From b8866426411c34489b0265bf720b4d917c8d4795 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 10 Mar 2023 15:53:43 +0100 Subject: ieee802154: Add support for user active scan requests In case a passive scan could not discover any PAN, a device may decide to perform an active scan to force coordinators to send a BEACON "immediately". Allow users to request to perform an active scan. Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230310145346.1397068-2-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- net/ieee802154/nl802154.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index d8f4379d4fa6..42e531aefe86 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -1426,6 +1426,7 @@ static int nl802154_trigger_scan(struct sk_buff *skb, struct genl_info *info) type = nla_get_u8(info->attrs[NL802154_ATTR_SCAN_TYPE]); switch (type) { + case NL802154_SCAN_ACTIVE: case NL802154_SCAN_PASSIVE: request->type = type; break; -- cgit v1.2.3 From e2c3e6f53a7a8a00ffeed127cfd1b397c3b016f8 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 10 Mar 2023 15:53:44 +0100 Subject: mac802154: Handle active scanning Active scan support is based on the current passive scan support, cheered up with beacon requests sent after every channel change. Co-developed-by: David Girault Signed-off-by: David Girault Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230310145346.1397068-3-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- include/net/ieee802154_netdev.h | 18 +++++++++++++- net/ieee802154/header_ops.c | 23 ++++++++++++++++++ net/mac802154/ieee802154_i.h | 1 + net/mac802154/scan.c | 53 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index da8a3e648c7a..257c9b2e9c9a 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -74,6 +74,10 @@ struct ieee802154_beacon_hdr { #endif } __packed; +struct ieee802154_mac_cmd_pl { + u8 cmd_id; +} __packed; + struct ieee802154_sechdr { #if defined(__LITTLE_ENDIAN_BITFIELD) u8 level:3, @@ -149,6 +153,16 @@ struct ieee802154_beacon_frame { struct ieee802154_beacon_hdr mac_pl; }; +struct ieee802154_mac_cmd_frame { + struct ieee802154_hdr mhr; + struct ieee802154_mac_cmd_pl mac_pl; +}; + +struct ieee802154_beacon_req_frame { + struct ieee802154_hdr mhr; + struct ieee802154_mac_cmd_pl mac_pl; +}; + /* pushes hdr onto the skb. fields of hdr->fc that can be calculated from * the contents of hdr will be, and the actual value of those bits in * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame @@ -174,9 +188,11 @@ int ieee802154_hdr_peek_addrs(const struct sk_buff *skb, */ int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr); -/* pushes a beacon frame into an skb */ +/* pushes/pulls various frame types into/from an skb */ int ieee802154_beacon_push(struct sk_buff *skb, struct ieee802154_beacon_frame *beacon); +int ieee802154_mac_cmd_push(struct sk_buff *skb, void *frame, + const void *pl, unsigned int pl_len); int ieee802154_max_payload(const struct ieee802154_hdr *hdr); diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c index 35d384dfe29d..a5ff1017a4b2 100644 --- a/net/ieee802154/header_ops.c +++ b/net/ieee802154/header_ops.c @@ -120,6 +120,29 @@ ieee802154_hdr_push(struct sk_buff *skb, struct ieee802154_hdr *hdr) } EXPORT_SYMBOL_GPL(ieee802154_hdr_push); +int ieee802154_mac_cmd_push(struct sk_buff *skb, void *f, + const void *pl, unsigned int pl_len) +{ + struct ieee802154_mac_cmd_frame *frame = f; + struct ieee802154_mac_cmd_pl *mac_pl = &frame->mac_pl; + struct ieee802154_hdr *mhr = &frame->mhr; + int ret; + + skb_reserve(skb, sizeof(*mhr)); + ret = ieee802154_hdr_push(skb, mhr); + if (ret < 0) + return ret; + + skb_reset_mac_header(skb); + skb->mac_len = ret; + + skb_put_data(skb, mac_pl, sizeof(*mac_pl)); + skb_put_data(skb, pl, pl_len); + + return 0; +} +EXPORT_SYMBOL_GPL(ieee802154_mac_cmd_push); + int ieee802154_beacon_push(struct sk_buff *skb, struct ieee802154_beacon_frame *beacon) { diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 63bab99ed368..7bfd5411a164 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -58,6 +58,7 @@ struct ieee802154_local { /* Scanning */ u8 scan_page; u8 scan_channel; + struct ieee802154_beacon_req_frame scan_beacon_req; struct cfg802154_scan_request __rcu *scan_req; struct delayed_work scan_work; diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c index 9b0933a185eb..201bfc567a43 100644 --- a/net/mac802154/scan.c +++ b/net/mac802154/scan.c @@ -18,8 +18,12 @@ #define IEEE802154_BEACON_MHR_SZ 13 #define IEEE802154_BEACON_PL_SZ 4 +#define IEEE802154_MAC_CMD_MHR_SZ 23 +#define IEEE802154_MAC_CMD_PL_SZ 1 #define IEEE802154_BEACON_SKB_SZ (IEEE802154_BEACON_MHR_SZ + \ IEEE802154_BEACON_PL_SZ) +#define IEEE802154_MAC_CMD_SKB_SZ (IEEE802154_MAC_CMD_MHR_SZ + \ + IEEE802154_MAC_CMD_PL_SZ) /* mac802154_scan_cleanup_locked() must be called upon scan completion or abort. * - Completions are asynchronous, not locked by the rtnl and decided by the @@ -131,6 +135,42 @@ static int mac802154_scan_find_next_chan(struct ieee802154_local *local, return 0; } +static int mac802154_scan_prepare_beacon_req(struct ieee802154_local *local) +{ + memset(&local->scan_beacon_req, 0, sizeof(local->scan_beacon_req)); + local->scan_beacon_req.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD; + local->scan_beacon_req.mhr.fc.dest_addr_mode = IEEE802154_SHORT_ADDRESSING; + local->scan_beacon_req.mhr.fc.version = IEEE802154_2003_STD; + local->scan_beacon_req.mhr.fc.source_addr_mode = IEEE802154_NO_ADDRESSING; + local->scan_beacon_req.mhr.dest.mode = IEEE802154_ADDR_SHORT; + local->scan_beacon_req.mhr.dest.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); + local->scan_beacon_req.mhr.dest.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); + local->scan_beacon_req.mac_pl.cmd_id = IEEE802154_CMD_BEACON_REQ; + + return 0; +} + +static int mac802154_transmit_beacon_req(struct ieee802154_local *local, + struct ieee802154_sub_if_data *sdata) +{ + struct sk_buff *skb; + int ret; + + skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ, GFP_KERNEL); + if (!skb) + return -ENOBUFS; + + skb->dev = sdata->dev; + + ret = ieee802154_mac_cmd_push(skb, &local->scan_beacon_req, NULL, 0); + if (ret) { + kfree_skb(skb); + return ret; + } + + return ieee802154_mlme_tx(local, sdata, skb); +} + void mac802154_scan_worker(struct work_struct *work) { struct ieee802154_local *local = @@ -206,6 +246,13 @@ void mac802154_scan_worker(struct work_struct *work) goto end_scan; } + if (scan_req->type == NL802154_SCAN_ACTIVE) { + ret = mac802154_transmit_beacon_req(local, sdata); + if (ret) + dev_err(&sdata->dev->dev, + "Error when transmitting beacon request (%d)\n", ret); + } + ieee802154_configure_durations(wpan_phy, page, channel); scan_duration = mac802154_scan_get_channel_time(scan_req_duration, wpan_phy->symbol_duration); @@ -231,8 +278,8 @@ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata, if (mac802154_is_scanning(local)) return -EBUSY; - /* TODO: support other scanning type */ - if (request->type != NL802154_SCAN_PASSIVE) + if (request->type != NL802154_SCAN_PASSIVE && + request->type != NL802154_SCAN_ACTIVE) return -EOPNOTSUPP; /* Store scanning parameters */ @@ -247,6 +294,8 @@ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata, local->scan_page = request->page; local->scan_channel = -1; set_bit(IEEE802154_IS_SCANNING, &local->ongoing); + if (request->type == NL802154_SCAN_ACTIVE) + mac802154_scan_prepare_beacon_req(local); nl802154_scan_started(request->wpan_phy, request->wpan_dev); -- cgit v1.2.3 From 26f88e4ebd4fbe96fb4326408e2af05644716d76 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 10 Mar 2023 15:53:45 +0100 Subject: ieee802154: Add support for allowing to answer BEACON_REQ Accept beaconing configurations from the user which involve answering beacon requests rather than only passively sending beacons. This may help devices to find the PAN more quickly. Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230310145346.1397068-4-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- net/ieee802154/nl802154.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 42e531aefe86..a20ac4bb48a4 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -233,7 +233,7 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { NLA_POLICY_RANGE(NLA_U8, NL802154_SCAN_DONE_REASON_FINISHED, NL802154_SCAN_DONE_REASON_ABORTED), [NL802154_ATTR_BEACON_INTERVAL] = - NLA_POLICY_MAX(NLA_U8, IEEE802154_MAX_SCAN_DURATION), + NLA_POLICY_MAX(NLA_U8, IEEE802154_ACTIVE_SCAN_DURATION), #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, -- cgit v1.2.3 From d021d218f6d924ff5417c64b2e41d184e4bb32d3 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 10 Mar 2023 15:53:46 +0100 Subject: mac802154: Handle received BEACON_REQ When performing an active scan, devices emit BEACON_REQ which must be answered by other PANs receiving the request, unless they are already passively sending beacons. Answering a beacon request becomes a duty when the user tells us to send beacons and the request provides an interval of 15. Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230310145346.1397068-5-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- include/net/ieee802154_netdev.h | 2 ++ net/ieee802154/header_ops.c | 13 ++++++++ net/mac802154/ieee802154_i.h | 20 ++++++++++++ net/mac802154/main.c | 2 ++ net/mac802154/rx.c | 70 ++++++++++++++++++++++++++++++++++++++++- net/mac802154/scan.c | 15 ++++++--- 6 files changed, 117 insertions(+), 5 deletions(-) diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 257c9b2e9c9a..063313df447d 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -193,6 +193,8 @@ int ieee802154_beacon_push(struct sk_buff *skb, struct ieee802154_beacon_frame *beacon); int ieee802154_mac_cmd_push(struct sk_buff *skb, void *frame, const void *pl, unsigned int pl_len); +int ieee802154_mac_cmd_pl_pull(struct sk_buff *skb, + struct ieee802154_mac_cmd_pl *mac_pl); int ieee802154_max_payload(const struct ieee802154_hdr *hdr); diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c index a5ff1017a4b2..41a556be1017 100644 --- a/net/ieee802154/header_ops.c +++ b/net/ieee802154/header_ops.c @@ -307,6 +307,19 @@ ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr) } EXPORT_SYMBOL_GPL(ieee802154_hdr_pull); +int ieee802154_mac_cmd_pl_pull(struct sk_buff *skb, + struct ieee802154_mac_cmd_pl *mac_pl) +{ + if (!pskb_may_pull(skb, sizeof(*mac_pl))) + return -EINVAL; + + memcpy(mac_pl, skb->data, sizeof(*mac_pl)); + skb_pull(skb, sizeof(*mac_pl)); + + return 0; +} +EXPORT_SYMBOL_GPL(ieee802154_mac_cmd_pl_pull); + int ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr) { diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 7bfd5411a164..c347ec9ff8c9 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -71,6 +71,8 @@ struct ieee802154_local { /* Asynchronous tasks */ struct list_head rx_beacon_list; struct work_struct rx_beacon_work; + struct list_head rx_mac_cmd_list; + struct work_struct rx_mac_cmd_work; bool started; bool suspended; @@ -155,6 +157,22 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata) return test_bit(SDATA_STATE_RUNNING, &sdata->state); } +static inline int ieee802154_get_mac_cmd(struct sk_buff *skb, u8 *mac_cmd) +{ + struct ieee802154_mac_cmd_pl mac_pl; + int ret; + + if (mac_cb(skb)->type != IEEE802154_FC_TYPE_MAC_CMD) + return -EINVAL; + + ret = ieee802154_mac_cmd_pl_pull(skb, &mac_pl); + if (ret) + return ret; + + *mac_cmd = mac_pl.cmd_id; + return 0; +} + extern struct ieee802154_mlme_ops mac802154_mlme_wpan; void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb); @@ -276,6 +294,8 @@ static inline bool mac802154_is_beaconing(struct ieee802154_local *local) return test_bit(IEEE802154_IS_BEACONING, &local->ongoing); } +void mac802154_rx_mac_cmd_worker(struct work_struct *work); + /* interface handling */ int ieee802154_iface_init(void); void ieee802154_iface_exit(void); diff --git a/net/mac802154/main.c b/net/mac802154/main.c index ee23e234b998..357ece67432b 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -90,6 +90,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) INIT_LIST_HEAD(&local->interfaces); INIT_LIST_HEAD(&local->rx_beacon_list); + INIT_LIST_HEAD(&local->rx_mac_cmd_list); mutex_init(&local->iflist_mtx); tasklet_setup(&local->tasklet, ieee802154_tasklet_handler); @@ -100,6 +101,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_worker); INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker); INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker); + INIT_WORK(&local->rx_mac_cmd_work, mac802154_rx_mac_cmd_worker); /* init supported flags with 802.15.4 default ranges */ phy->supported.max_minbe = 8; diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index da0628ee3c89..e2434b4fe514 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -47,6 +47,62 @@ void mac802154_rx_beacon_worker(struct work_struct *work) kfree(mac_pkt); } +static bool mac802154_should_answer_beacon_req(struct ieee802154_local *local) +{ + struct cfg802154_beacon_request *beacon_req; + unsigned int interval; + + rcu_read_lock(); + beacon_req = rcu_dereference(local->beacon_req); + if (!beacon_req) { + rcu_read_unlock(); + return false; + } + + interval = beacon_req->interval; + rcu_read_unlock(); + + if (!mac802154_is_beaconing(local)) + return false; + + return interval == IEEE802154_ACTIVE_SCAN_DURATION; +} + +void mac802154_rx_mac_cmd_worker(struct work_struct *work) +{ + struct ieee802154_local *local = + container_of(work, struct ieee802154_local, rx_mac_cmd_work); + struct cfg802154_mac_pkt *mac_pkt; + u8 mac_cmd; + int rc; + + mac_pkt = list_first_entry_or_null(&local->rx_mac_cmd_list, + struct cfg802154_mac_pkt, node); + if (!mac_pkt) + return; + + rc = ieee802154_get_mac_cmd(mac_pkt->skb, &mac_cmd); + if (rc) + goto out; + + switch (mac_cmd) { + case IEEE802154_CMD_BEACON_REQ: + dev_dbg(&mac_pkt->sdata->dev->dev, "processing BEACON REQ\n"); + if (!mac802154_should_answer_beacon_req(local)) + break; + + queue_delayed_work(local->mac_wq, &local->beacon_work, 0); + break; + default: + break; + } + +out: + list_del(&mac_pkt->node); + kfree_skb(mac_pkt->skb); + kfree(mac_pkt); +} + static int ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, struct sk_buff *skb, const struct ieee802154_hdr *hdr) @@ -140,8 +196,20 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, list_add_tail(&mac_pkt->node, &sdata->local->rx_beacon_list); queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work); return NET_RX_SUCCESS; - case IEEE802154_FC_TYPE_ACK: + case IEEE802154_FC_TYPE_MAC_CMD: + dev_dbg(&sdata->dev->dev, "MAC COMMAND received\n"); + mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC); + if (!mac_pkt) + goto fail; + + mac_pkt->skb = skb_get(skb); + mac_pkt->sdata = sdata; + list_add_tail(&mac_pkt->node, &sdata->local->rx_mac_cmd_list); + queue_work(sdata->local->mac_wq, &sdata->local->rx_mac_cmd_work); + return NET_RX_SUCCESS; + + case IEEE802154_FC_TYPE_ACK: goto fail; case IEEE802154_FC_TYPE_DATA: diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c index 201bfc567a43..618553a2e026 100644 --- a/net/mac802154/scan.c +++ b/net/mac802154/scan.c @@ -403,6 +403,7 @@ void mac802154_beacon_worker(struct work_struct *work) struct cfg802154_beacon_request *beacon_req; struct ieee802154_sub_if_data *sdata; struct wpan_dev *wpan_dev; + u8 interval; int ret; rcu_read_lock(); @@ -423,6 +424,7 @@ void mac802154_beacon_worker(struct work_struct *work) } wpan_dev = beacon_req->wpan_dev; + interval = beacon_req->interval; rcu_read_unlock(); @@ -432,8 +434,9 @@ void mac802154_beacon_worker(struct work_struct *work) dev_err(&sdata->dev->dev, "Beacon could not be transmitted (%d)\n", ret); - queue_delayed_work(local->mac_wq, &local->beacon_work, - local->beacon_interval); + if (interval < IEEE802154_ACTIVE_SCAN_DURATION) + queue_delayed_work(local->mac_wq, &local->beacon_work, + local->beacon_interval); } int mac802154_stop_beacons_locked(struct ieee802154_local *local, @@ -488,13 +491,17 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata, local->beacon.mhr.source.pan_id = request->wpan_dev->pan_id; local->beacon.mhr.source.extended_addr = request->wpan_dev->extended_addr; local->beacon.mac_pl.beacon_order = request->interval; - local->beacon.mac_pl.superframe_order = request->interval; + if (request->interval <= IEEE802154_MAX_SCAN_DURATION) + local->beacon.mac_pl.superframe_order = request->interval; local->beacon.mac_pl.final_cap_slot = 0xf; local->beacon.mac_pl.battery_life_ext = 0; - /* TODO: Fill this field depending on the coordinator capacity */ + /* TODO: Fill this field with the coordinator situation in the network */ local->beacon.mac_pl.pan_coordinator = 1; local->beacon.mac_pl.assoc_permit = 1; + if (request->interval == IEEE802154_ACTIVE_SCAN_DURATION) + return 0; + /* Start the beacon work */ local->beacon_interval = mac802154_scan_get_channel_time(request->interval, -- cgit v1.2.3 From 822452fb6c696bb2331649ce6fbb49e49261cc71 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 24 Mar 2023 12:05:57 +0100 Subject: net: ieee802154: Handle limited devices with only datagram support Some devices, like HardMAC ones can be a bit limited in the way they handle mac commands. In particular, they might just not support it at all and instead only be able to transmit and receive regular data packets. In this case, they cannot be used for any of the internal management commands that we have introduced so far and must be flagged accordingly. Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230324110558.90707-2-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- include/net/cfg802154.h | 3 +++ net/ieee802154/nl802154.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 0c2778a836db..e00057984489 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -178,12 +178,15 @@ wpan_phy_cca_cmp(const struct wpan_phy_cca *a, const struct wpan_phy_cca *b) * setting. * @WPAN_PHY_FLAG_STATE_QUEUE_STOPPED: Indicates that the transmit queue was * temporarily stopped. + * @WPAN_PHY_FLAG_DATAGRAMS_ONLY: Indicates that transceiver is only able to + * send/receive datagrams. */ enum wpan_phy_flags { WPAN_PHY_FLAG_TXPOWER = BIT(1), WPAN_PHY_FLAG_CCA_ED_LEVEL = BIT(2), WPAN_PHY_FLAG_CCA_MODE = BIT(3), WPAN_PHY_FLAG_STATE_QUEUE_STOPPED = BIT(4), + WPAN_PHY_FLAG_DATAGRAMS_ONLY = BIT(5), }; struct wpan_phy { diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index a20ac4bb48a4..cd688b51d977 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -1417,6 +1417,11 @@ static int nl802154_trigger_scan(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + if (wpan_phy->flags & WPAN_PHY_FLAG_DATAGRAMS_ONLY) { + NL_SET_ERR_MSG(info->extack, "PHY only supports datagrams"); + return -EOPNOTSUPP; + } + request = kzalloc(sizeof(*request), GFP_KERNEL); if (!request) return -ENOMEM; @@ -1584,6 +1589,11 @@ nl802154_send_beacons(struct sk_buff *skb, struct genl_info *info) return -EPERM; } + if (wpan_phy->flags & WPAN_PHY_FLAG_DATAGRAMS_ONLY) { + NL_SET_ERR_MSG(info->extack, "PHY only supports datagrams"); + return -EOPNOTSUPP; + } + request = kzalloc(sizeof(*request), GFP_KERNEL); if (!request) return -ENOMEM; -- cgit v1.2.3 From 1af3de62f03f651c5e50c0e00f8fed34d07b9df3 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 24 Mar 2023 12:05:58 +0100 Subject: ieee802154: ca8210: Flag the driver as being limited This is a hardMAC device wired to Linux 802154 softMAC implementation. It is a bit limited in the sense that it cannot handle anything else that datagrams. Let's flag it like this to prevent using unsupported features such as scan/beacons handling. Signed-off-by: Miquel Raynal Acked-by: Alexander Aring Link: https://lore.kernel.org/r/20230324110558.90707-3-miquel.raynal@bootlin.com Signed-off-by: Stefan Schmidt --- drivers/net/ieee802154/ca8210.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index 1eada1db8dcf..567e95f00001 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -2945,7 +2945,8 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw) ca8210_hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL | - WPAN_PHY_FLAG_CCA_MODE; + WPAN_PHY_FLAG_CCA_MODE | + WPAN_PHY_FLAG_DATAGRAMS_ONLY; } /** -- cgit v1.2.3 From 9981a3ac5887efaff8d2a9e3fb0d48612d8cf733 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Fri, 21 Apr 2023 12:44:56 +0300 Subject: wifi: ath12k: add qmi_cnss_feature_bitmap field to hardware parameters Currently the CNSS (Connectivity Subsystem) QMI feature is assigned to qmi_wlanfw_host_cap_req_msg_v01 request directly, this prevents chip-specific CNSS features from being added easily. Solve this by adding a new field qmi_cnss_feature_bitmap to hw_params so chip-specific CNSS features can be assigned to this field and later assigned to qmi_wlanfw_host_cap_req_msg_v01 request. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230404032057.3236122-2-quic_cjhuang@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 5 +++++ drivers/net/wireless/ath/ath12k/hw.h | 2 ++ drivers/net/wireless/ath/ath12k/qmi.c | 6 ++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 1ffac7e3deaa..cc47cbf93f6b 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -906,6 +906,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .hal_ops = &hal_qcn9274_ops, + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01), }, { .name = "wcn7850 hw2.0", @@ -960,6 +961,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .wmi_init = ath12k_wmi_init_wcn7850, .hal_ops = &hal_wcn7850_ops, + + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01), }, { .name = "qcn9274 hw2.0", @@ -1013,6 +1016,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .wmi_init = ath12k_wmi_init_qcn9274, .hal_ops = &hal_qcn9274_ops, + + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01), }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index e3461004188b..e6c4223c283c 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -184,6 +184,8 @@ struct ath12k_hw_params { struct ath12k_wmi_resource_config_arg *config); const struct hal_ops *hal_ops; + + u64 qmi_cnss_feature_bitmap; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 03ba245fbee9..4afba76b90fe 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -1942,8 +1942,10 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) req.cal_done_valid = 1; req.cal_done = ab->qmi.cal_done; - req.feature_list_valid = 1; - req.feature_list = BIT(CNSS_QDSS_CFG_MISS_V01); + if (ab->hw_params->qmi_cnss_feature_bitmap) { + req.feature_list_valid = 1; + req.feature_list = ab->hw_params->qmi_cnss_feature_bitmap; + } /* BRINGUP: here we are piggybacking a lot of stuff using * internal_sleep_clock, should it be split? -- cgit v1.2.3 From 34c5625a459a7dff745bcd862962688b5c795762 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Fri, 21 Apr 2023 12:44:57 +0300 Subject: wifi: ath12k: set PERST pin no pull request for WCN7850 The PCIe PERST pin is currently pulled down on WCN7850 and it causes some power leakage. Fix it by notifying firmware not to pull down PCIe PERST pin in QMI message for WCN7850. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230404032057.3236122-3-quic_cjhuang@quicinc.com --- drivers/net/wireless/ath/ath12k/hw.c | 3 ++- drivers/net/wireless/ath/ath12k/qmi.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index cc47cbf93f6b..5991cc91cd00 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -962,7 +962,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .hal_ops = &hal_wcn7850_ops, - .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01), + .qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) | + BIT(CNSS_PCIE_PERST_NO_PULL_V01), }, { .name = "qcn9274 hw2.0", diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index ad87f19903db..df76149c49f5 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -189,6 +189,7 @@ struct wlfw_host_mlo_chip_info_s_v01 { enum ath12k_qmi_cnss_feature { CNSS_FEATURE_MIN_ENUM_VAL_V01 = INT_MIN, CNSS_QDSS_CFG_MISS_V01 = 3, + CNSS_PCIE_PERST_NO_PULL_V01 = 4, CNSS_MAX_FEATURE_V01 = 64, CNSS_FEATURE_MAX_ENUM_VAL_V01 = INT_MAX, }; -- cgit v1.2.3 From e671fb86ecc03ce15a89cda8553621248ccf620c Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Fri, 21 Apr 2023 12:44:57 +0300 Subject: wifi: ath12k: send WMI_PEER_REORDER_QUEUE_SETUP_CMDID when ADDBA session starts Low receive throughput is seen on WCN7850 because ADDBA related parameters are not updated to firmware when receive ADDBA session starts. Fix it by sending WMI_PEER_REORDER_QUEUE_SETUP_CMDID again to firmware to update the ADDBA related parameters for chips which have false reoq_lut_support in hw_params. For chips which have true reoq_lut_support in hw_params don't need this command to send to firmware. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230404070158.3368530-1-quic_cjhuang@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index e78478a5b978..c7bf4f7fa99e 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -978,7 +978,19 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_ return ret; } - return ret; + if (!ab->hw_params->reoq_lut_support) { + ret = ath12k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, + peer_mac, + paddr, tid, 1, + ba_win_sz); + if (ret) { + ath12k_warn(ab, "failed to setup peer rx reorder queuefor tid %d: %d\n", + tid, ret); + return ret; + } + } + + return 0; } rx_tid->tid = tid; -- cgit v1.2.3 From 987d0242d189661f78b77cc4d77f843b15600fed Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 20 Apr 2023 00:14:10 -0700 Subject: bpf: Add bpf_dynptr_adjust Add a new kfunc int bpf_dynptr_adjust(struct bpf_dynptr_kern *ptr, u32 start, u32 end); which adjusts the dynptr to reflect the new [start, end) interval. In particular, it advances the offset of the dynptr by "start" bytes, and if end is less than the size of the dynptr, then this will trim the dynptr accordingly. Adjusting the dynptr interval may be useful in certain situations. For example, when hashing which takes in generic dynptrs, if the dynptr points to a struct but only a certain memory region inside the struct should be hashed, adjust can be used to narrow in on the specific region to hash. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230420071414.570108-2-joannelkoong@gmail.com --- kernel/bpf/helpers.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 8d368fa353f9..42e06d1b492d 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1448,6 +1448,13 @@ u32 bpf_dynptr_get_size(const struct bpf_dynptr_kern *ptr) return ptr->size & DYNPTR_SIZE_MASK; } +static void bpf_dynptr_set_size(struct bpf_dynptr_kern *ptr, u32 new_size) +{ + u32 metadata = ptr->size & ~DYNPTR_SIZE_MASK; + + ptr->size = new_size | metadata; +} + int bpf_dynptr_check_size(u32 size) { return size > DYNPTR_MAX_SIZE ? -E2BIG : 0; @@ -2297,6 +2304,24 @@ __bpf_kfunc void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr_kern *ptr, u32 o return bpf_dynptr_slice(ptr, offset, buffer, buffer__szk); } +__bpf_kfunc int bpf_dynptr_adjust(struct bpf_dynptr_kern *ptr, u32 start, u32 end) +{ + u32 size; + + if (!ptr->data || start > end) + return -EINVAL; + + size = bpf_dynptr_get_size(ptr); + + if (start > size || end > size) + return -ERANGE; + + ptr->offset += start; + bpf_dynptr_set_size(ptr, end - start); + + return 0; +} + __bpf_kfunc void *bpf_cast_to_kern_ctx(void *obj) { return obj; @@ -2369,6 +2394,7 @@ BTF_ID_FLAGS(func, bpf_dynptr_slice_rdwr, KF_RET_NULL) BTF_ID_FLAGS(func, bpf_iter_num_new, KF_ITER_NEW) BTF_ID_FLAGS(func, bpf_iter_num_next, KF_ITER_NEXT | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_iter_num_destroy, KF_ITER_DESTROY) +BTF_ID_FLAGS(func, bpf_dynptr_adjust) BTF_SET8_END(common_btf_ids) static const struct btf_kfunc_id_set common_kfunc_set = { -- cgit v1.2.3 From 540ccf96ddbc173474c32e595787d5622253be3d Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 20 Apr 2023 00:14:11 -0700 Subject: bpf: Add bpf_dynptr_is_null and bpf_dynptr_is_rdonly bpf_dynptr_is_null returns true if the dynptr is null / invalid (determined by whether ptr->data is NULL), else false if the dynptr is a valid dynptr. bpf_dynptr_is_rdonly returns true if the dynptr is read-only, else false if the dynptr is read-writable. If the dynptr is null / invalid, false is returned by default. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Andrii Nakryiko Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20230420071414.570108-3-joannelkoong@gmail.com --- kernel/bpf/helpers.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 42e06d1b492d..a683b3e71a28 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1423,7 +1423,7 @@ static const struct bpf_func_proto bpf_kptr_xchg_proto = { #define DYNPTR_SIZE_MASK 0xFFFFFF #define DYNPTR_RDONLY_BIT BIT(31) -static bool bpf_dynptr_is_rdonly(const struct bpf_dynptr_kern *ptr) +static bool __bpf_dynptr_is_rdonly(const struct bpf_dynptr_kern *ptr) { return ptr->size & DYNPTR_RDONLY_BIT; } @@ -1570,7 +1570,7 @@ BPF_CALL_5(bpf_dynptr_write, const struct bpf_dynptr_kern *, dst, u32, offset, v enum bpf_dynptr_type type; int err; - if (!dst->data || bpf_dynptr_is_rdonly(dst)) + if (!dst->data || __bpf_dynptr_is_rdonly(dst)) return -EINVAL; err = bpf_dynptr_check_off_len(dst, offset, len); @@ -1626,7 +1626,7 @@ BPF_CALL_3(bpf_dynptr_data, const struct bpf_dynptr_kern *, ptr, u32, offset, u3 if (err) return 0; - if (bpf_dynptr_is_rdonly(ptr)) + if (__bpf_dynptr_is_rdonly(ptr)) return 0; type = bpf_dynptr_get_type(ptr); @@ -2276,7 +2276,7 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset __bpf_kfunc void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr_kern *ptr, u32 offset, void *buffer, u32 buffer__szk) { - if (!ptr->data || bpf_dynptr_is_rdonly(ptr)) + if (!ptr->data || __bpf_dynptr_is_rdonly(ptr)) return NULL; /* bpf_dynptr_slice_rdwr is the same logic as bpf_dynptr_slice. @@ -2322,6 +2322,19 @@ __bpf_kfunc int bpf_dynptr_adjust(struct bpf_dynptr_kern *ptr, u32 start, u32 en return 0; } +__bpf_kfunc bool bpf_dynptr_is_null(struct bpf_dynptr_kern *ptr) +{ + return !ptr->data; +} + +__bpf_kfunc bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr) +{ + if (!ptr->data) + return false; + + return __bpf_dynptr_is_rdonly(ptr); +} + __bpf_kfunc void *bpf_cast_to_kern_ctx(void *obj) { return obj; @@ -2395,6 +2408,8 @@ BTF_ID_FLAGS(func, bpf_iter_num_new, KF_ITER_NEW) BTF_ID_FLAGS(func, bpf_iter_num_next, KF_ITER_NEXT | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_iter_num_destroy, KF_ITER_DESTROY) BTF_ID_FLAGS(func, bpf_dynptr_adjust) +BTF_ID_FLAGS(func, bpf_dynptr_is_null) +BTF_ID_FLAGS(func, bpf_dynptr_is_rdonly) BTF_SET8_END(common_btf_ids) static const struct btf_kfunc_id_set common_kfunc_set = { -- cgit v1.2.3 From 26662d7347a058ca497792c4b22ac91cc415cbf6 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 20 Apr 2023 00:14:12 -0700 Subject: bpf: Add bpf_dynptr_size bpf_dynptr_size returns the number of usable bytes in a dynptr. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20230420071414.570108-4-joannelkoong@gmail.com --- include/linux/bpf.h | 2 +- kernel/bpf/helpers.c | 15 ++++++++++++--- kernel/trace/bpf_trace.c | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index e53ceee1df37..456f33b9d205 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1197,7 +1197,7 @@ enum bpf_dynptr_type { }; int bpf_dynptr_check_size(u32 size); -u32 bpf_dynptr_get_size(const struct bpf_dynptr_kern *ptr); +u32 __bpf_dynptr_size(const struct bpf_dynptr_kern *ptr); #ifdef CONFIG_BPF_JIT int bpf_trampoline_link_prog(struct bpf_tramp_link *link, struct bpf_trampoline *tr); diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index a683b3e71a28..c465e97733b9 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1443,7 +1443,7 @@ static enum bpf_dynptr_type bpf_dynptr_get_type(const struct bpf_dynptr_kern *pt return (ptr->size & ~(DYNPTR_RDONLY_BIT)) >> DYNPTR_TYPE_SHIFT; } -u32 bpf_dynptr_get_size(const struct bpf_dynptr_kern *ptr) +u32 __bpf_dynptr_size(const struct bpf_dynptr_kern *ptr) { return ptr->size & DYNPTR_SIZE_MASK; } @@ -1476,7 +1476,7 @@ void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr) static int bpf_dynptr_check_off_len(const struct bpf_dynptr_kern *ptr, u32 offset, u32 len) { - u32 size = bpf_dynptr_get_size(ptr); + u32 size = __bpf_dynptr_size(ptr); if (len > size || offset > size - len) return -E2BIG; @@ -2311,7 +2311,7 @@ __bpf_kfunc int bpf_dynptr_adjust(struct bpf_dynptr_kern *ptr, u32 start, u32 en if (!ptr->data || start > end) return -EINVAL; - size = bpf_dynptr_get_size(ptr); + size = __bpf_dynptr_size(ptr); if (start > size || end > size) return -ERANGE; @@ -2335,6 +2335,14 @@ __bpf_kfunc bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr) return __bpf_dynptr_is_rdonly(ptr); } +__bpf_kfunc __u32 bpf_dynptr_size(const struct bpf_dynptr_kern *ptr) +{ + if (!ptr->data) + return -EINVAL; + + return __bpf_dynptr_size(ptr); +} + __bpf_kfunc void *bpf_cast_to_kern_ctx(void *obj) { return obj; @@ -2410,6 +2418,7 @@ BTF_ID_FLAGS(func, bpf_iter_num_destroy, KF_ITER_DESTROY) BTF_ID_FLAGS(func, bpf_dynptr_adjust) BTF_ID_FLAGS(func, bpf_dynptr_is_null) BTF_ID_FLAGS(func, bpf_dynptr_is_rdonly) +BTF_ID_FLAGS(func, bpf_dynptr_size) BTF_SET8_END(common_btf_ids) static const struct btf_kfunc_id_set common_kfunc_set = { diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index bcf91bc7bf71..8deb22a99abe 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1349,9 +1349,9 @@ __bpf_kfunc int bpf_verify_pkcs7_signature(struct bpf_dynptr_kern *data_ptr, } return verify_pkcs7_signature(data_ptr->data, - bpf_dynptr_get_size(data_ptr), + __bpf_dynptr_size(data_ptr), sig_ptr->data, - bpf_dynptr_get_size(sig_ptr), + __bpf_dynptr_size(sig_ptr), trusted_keyring->key, VERIFYING_UNSPECIFIED_SIGNATURE, NULL, NULL); -- cgit v1.2.3 From 361f129f3cc185af6667aca0bec0be9a020a8abc Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 20 Apr 2023 00:14:13 -0700 Subject: bpf: Add bpf_dynptr_clone The cloned dynptr will point to the same data as its parent dynptr, with the same type, offset, size and read-only properties. Any writes to a dynptr will be reflected across all instances (by 'instance', this means any dynptrs that point to the same underlying data). Please note that data slice and dynptr invalidations will affect all instances as well. For example, if bpf_dynptr_write() is called on an skb-type dynptr, all data slices of dynptr instances to that skb will be invalidated as well (eg data slices of any clones, parents, grandparents, ...). Another example is if a ringbuf dynptr is submitted, any instance of that dynptr will be invalidated. Changing the view of the dynptr (eg advancing the offset or trimming the size) will only affect that dynptr and not affect any other instances. One example use case where cloning may be helpful is for hashing or iterating through dynptr data. Cloning will allow the user to maintain the original view of the dynptr for future use, while also allowing views to smaller subsets of the data after the offset is advanced or the size is trimmed. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230420071414.570108-5-joannelkoong@gmail.com --- kernel/bpf/helpers.c | 14 +++++++ kernel/bpf/verifier.c | 103 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 97 insertions(+), 20 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index c465e97733b9..bb6b4637ebf2 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2343,6 +2343,19 @@ __bpf_kfunc __u32 bpf_dynptr_size(const struct bpf_dynptr_kern *ptr) return __bpf_dynptr_size(ptr); } +__bpf_kfunc int bpf_dynptr_clone(struct bpf_dynptr_kern *ptr, + struct bpf_dynptr_kern *clone__uninit) +{ + if (!ptr->data) { + bpf_dynptr_set_null(clone__uninit); + return -EINVAL; + } + + *clone__uninit = *ptr; + + return 0; +} + __bpf_kfunc void *bpf_cast_to_kern_ctx(void *obj) { return obj; @@ -2419,6 +2432,7 @@ BTF_ID_FLAGS(func, bpf_dynptr_adjust) BTF_ID_FLAGS(func, bpf_dynptr_is_null) BTF_ID_FLAGS(func, bpf_dynptr_is_rdonly) BTF_ID_FLAGS(func, bpf_dynptr_size) +BTF_ID_FLAGS(func, bpf_dynptr_clone) BTF_SET8_END(common_btf_ids) static const struct btf_kfunc_id_set common_kfunc_set = { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index fbcf5a4e2fcd..ff4a8ab99f08 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -309,6 +309,7 @@ struct bpf_kfunc_call_arg_meta { struct { enum bpf_dynptr_type type; u32 id; + u32 ref_obj_id; } initialized_dynptr; struct { u8 spi; @@ -847,11 +848,11 @@ static int destroy_if_dynptr_stack_slot(struct bpf_verifier_env *env, struct bpf_func_state *state, int spi); static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg, - enum bpf_arg_type arg_type, int insn_idx) + enum bpf_arg_type arg_type, int insn_idx, int clone_ref_obj_id) { struct bpf_func_state *state = func(env, reg); enum bpf_dynptr_type type; - int spi, i, id, err; + int spi, i, err; spi = dynptr_get_spi(env, reg); if (spi < 0) @@ -887,7 +888,13 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_ if (dynptr_type_refcounted(type)) { /* The id is used to track proper releasing */ - id = acquire_reference_state(env, insn_idx); + int id; + + if (clone_ref_obj_id) + id = clone_ref_obj_id; + else + id = acquire_reference_state(env, insn_idx); + if (id < 0) return id; @@ -901,24 +908,15 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_ return 0; } -static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +static void invalidate_dynptr(struct bpf_verifier_env *env, struct bpf_func_state *state, int spi) { - struct bpf_func_state *state = func(env, reg); - int spi, i; - - spi = dynptr_get_spi(env, reg); - if (spi < 0) - return spi; + int i; for (i = 0; i < BPF_REG_SIZE; i++) { state->stack[spi].slot_type[i] = STACK_INVALID; state->stack[spi - 1].slot_type[i] = STACK_INVALID; } - /* Invalidate any slices associated with this dynptr */ - if (dynptr_type_refcounted(state->stack[spi].spilled_ptr.dynptr.type)) - WARN_ON_ONCE(release_reference(env, state->stack[spi].spilled_ptr.ref_obj_id)); - __mark_reg_not_init(env, &state->stack[spi].spilled_ptr); __mark_reg_not_init(env, &state->stack[spi - 1].spilled_ptr); @@ -945,6 +943,50 @@ static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_re */ state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; state->stack[spi - 1].spilled_ptr.live |= REG_LIVE_WRITTEN; +} + +static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg) +{ + struct bpf_func_state *state = func(env, reg); + int spi, ref_obj_id, i; + + spi = dynptr_get_spi(env, reg); + if (spi < 0) + return spi; + + if (!dynptr_type_refcounted(state->stack[spi].spilled_ptr.dynptr.type)) { + invalidate_dynptr(env, state, spi); + return 0; + } + + ref_obj_id = state->stack[spi].spilled_ptr.ref_obj_id; + + /* If the dynptr has a ref_obj_id, then we need to invalidate + * two things: + * + * 1) Any dynptrs with a matching ref_obj_id (clones) + * 2) Any slices derived from this dynptr. + */ + + /* Invalidate any slices associated with this dynptr */ + WARN_ON_ONCE(release_reference(env, ref_obj_id)); + + /* Invalidate any dynptr clones */ + for (i = 1; i < state->allocated_stack / BPF_REG_SIZE; i++) { + if (state->stack[i].spilled_ptr.ref_obj_id != ref_obj_id) + continue; + + /* it should always be the case that if the ref obj id + * matches then the stack slot also belongs to a + * dynptr + */ + if (state->stack[i].slot_type[0] != STACK_DYNPTR) { + verbose(env, "verifier internal error: misconfigured ref_obj_id\n"); + return -EFAULT; + } + if (state->stack[i].spilled_ptr.dynptr.first_slot) + invalidate_dynptr(env, state, i); + } return 0; } @@ -6677,7 +6719,7 @@ static int process_kptr_func(struct bpf_verifier_env *env, int regno, * type, and declare it as 'const struct bpf_dynptr *' in their prototype. */ static int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn_idx, - enum bpf_arg_type arg_type) + enum bpf_arg_type arg_type, int clone_ref_obj_id) { struct bpf_reg_state *regs = cur_regs(env), *reg = ®s[regno]; int err; @@ -6721,7 +6763,7 @@ static int process_dynptr_func(struct bpf_verifier_env *env, int regno, int insn return err; } - err = mark_stack_slots_dynptr(env, reg, arg_type, insn_idx); + err = mark_stack_slots_dynptr(env, reg, arg_type, insn_idx, clone_ref_obj_id); } else /* MEM_RDONLY and None case from above */ { /* For the reg->type == PTR_TO_STACK case, bpf_dynptr is never const */ if (reg->type == CONST_PTR_TO_DYNPTR && !(arg_type & MEM_RDONLY)) { @@ -7631,7 +7673,7 @@ skip_type_check: err = check_mem_size_reg(env, reg, regno, true, meta); break; case ARG_PTR_TO_DYNPTR: - err = process_dynptr_func(env, regno, insn_idx, arg_type); + err = process_dynptr_func(env, regno, insn_idx, arg_type, 0); if (err) return err; break; @@ -9595,6 +9637,7 @@ enum special_kfunc_type { KF_bpf_dynptr_from_xdp, KF_bpf_dynptr_slice, KF_bpf_dynptr_slice_rdwr, + KF_bpf_dynptr_clone, }; BTF_SET_START(special_kfunc_set) @@ -9614,6 +9657,7 @@ BTF_ID(func, bpf_dynptr_from_skb) BTF_ID(func, bpf_dynptr_from_xdp) BTF_ID(func, bpf_dynptr_slice) BTF_ID(func, bpf_dynptr_slice_rdwr) +BTF_ID(func, bpf_dynptr_clone) BTF_SET_END(special_kfunc_set) BTF_ID_LIST(special_kfunc_list) @@ -9635,6 +9679,7 @@ BTF_ID(func, bpf_dynptr_from_skb) BTF_ID(func, bpf_dynptr_from_xdp) BTF_ID(func, bpf_dynptr_slice) BTF_ID(func, bpf_dynptr_slice_rdwr) +BTF_ID(func, bpf_dynptr_clone) static bool is_kfunc_bpf_rcu_read_lock(struct bpf_kfunc_call_arg_meta *meta) { @@ -10330,6 +10375,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ case KF_ARG_PTR_TO_DYNPTR: { enum bpf_arg_type dynptr_arg_type = ARG_PTR_TO_DYNPTR; + int clone_ref_obj_id = 0; if (reg->type != PTR_TO_STACK && reg->type != CONST_PTR_TO_DYNPTR) { @@ -10343,12 +10389,28 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ if (is_kfunc_arg_uninit(btf, &args[i])) dynptr_arg_type |= MEM_UNINIT; - if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) + if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) { dynptr_arg_type |= DYNPTR_TYPE_SKB; - else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) + } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_from_xdp]) { dynptr_arg_type |= DYNPTR_TYPE_XDP; + } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] && + (dynptr_arg_type & MEM_UNINIT)) { + enum bpf_dynptr_type parent_type = meta->initialized_dynptr.type; + + if (parent_type == BPF_DYNPTR_TYPE_INVALID) { + verbose(env, "verifier internal error: no dynptr type for parent of clone\n"); + return -EFAULT; + } + + dynptr_arg_type |= (unsigned int)get_dynptr_type_flag(parent_type); + clone_ref_obj_id = meta->initialized_dynptr.ref_obj_id; + if (dynptr_type_refcounted(parent_type) && !clone_ref_obj_id) { + verbose(env, "verifier internal error: missing ref obj id for parent of clone\n"); + return -EFAULT; + } + } - ret = process_dynptr_func(env, regno, insn_idx, dynptr_arg_type); + ret = process_dynptr_func(env, regno, insn_idx, dynptr_arg_type, clone_ref_obj_id); if (ret < 0) return ret; @@ -10361,6 +10423,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ } meta->initialized_dynptr.id = id; meta->initialized_dynptr.type = dynptr_get_type(env, reg); + meta->initialized_dynptr.ref_obj_id = dynptr_ref_obj_id(env, reg); } break; -- cgit v1.2.3 From d911ba7ceafd29606df4018bbd87a1642f9e6d88 Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Thu, 20 Apr 2023 00:14:14 -0700 Subject: selftests/bpf: Add tests for dynptr convenience helpers Add various tests for the added dynptr convenience helpers. Signed-off-by: Joanne Koong Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230420071414.570108-6-joannelkoong@gmail.com --- tools/testing/selftests/bpf/bpf_kfuncs.h | 6 + tools/testing/selftests/bpf/prog_tests/dynptr.c | 6 + tools/testing/selftests/bpf/progs/dynptr_fail.c | 287 ++++++++++++++++++++ tools/testing/selftests/bpf/progs/dynptr_success.c | 298 +++++++++++++++++++++ 4 files changed, 597 insertions(+) diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 8c993ec8ceea..f3c41f8902a0 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -35,4 +35,10 @@ extern void *bpf_dynptr_slice(const struct bpf_dynptr *ptr, __u32 offset, extern void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *ptr, __u32 offset, void *buffer, __u32 buffer__szk) __ksym; +extern int bpf_dynptr_adjust(const struct bpf_dynptr *ptr, __u32 start, __u32 end) __ksym; +extern int bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; +extern int bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; +extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym; +extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym; + #endif diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index d176c34a7d2e..0478916aff37 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -20,6 +20,12 @@ static struct { {"test_ringbuf", SETUP_SYSCALL_SLEEP}, {"test_skb_readonly", SETUP_SKB_PROG}, {"test_dynptr_skb_data", SETUP_SKB_PROG}, + {"test_adjust", SETUP_SYSCALL_SLEEP}, + {"test_adjust_err", SETUP_SYSCALL_SLEEP}, + {"test_zero_size_dynptr", SETUP_SYSCALL_SLEEP}, + {"test_dynptr_is_null", SETUP_SYSCALL_SLEEP}, + {"test_dynptr_is_rdonly", SETUP_SKB_PROG}, + {"test_dynptr_clone", SETUP_SKB_PROG}, }; static void verify_success(const char *prog_name, enum test_setup_type setup_type) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index 759eb5c245cd..efe4ce72d00e 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -1378,3 +1378,290 @@ int invalid_slice_rdwr_rdonly(struct __sk_buff *skb) return 0; } + +/* bpf_dynptr_adjust can only be called on initialized dynptrs */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int dynptr_adjust_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + + /* this should fail */ + bpf_dynptr_adjust(&ptr, 1, 2); + + return 0; +} + +/* bpf_dynptr_is_null can only be called on initialized dynptrs */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int dynptr_is_null_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + + /* this should fail */ + bpf_dynptr_is_null(&ptr); + + return 0; +} + +/* bpf_dynptr_is_rdonly can only be called on initialized dynptrs */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int dynptr_is_rdonly_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + + /* this should fail */ + bpf_dynptr_is_rdonly(&ptr); + + return 0; +} + +/* bpf_dynptr_size can only be called on initialized dynptrs */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int dynptr_size_invalid(void *ctx) +{ + struct bpf_dynptr ptr; + + /* this should fail */ + bpf_dynptr_size(&ptr); + + return 0; +} + +/* Only initialized dynptrs can be cloned */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #1") +int clone_invalid1(void *ctx) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr ptr2; + + /* this should fail */ + bpf_dynptr_clone(&ptr1, &ptr2); + + return 0; +} + +/* Can't overwrite an existing dynptr when cloning */ +SEC("?xdp") +__failure __msg("cannot overwrite referenced dynptr") +int clone_invalid2(struct xdp_md *xdp) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr clone; + + bpf_dynptr_from_xdp(xdp, 0, &ptr1); + + bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &clone); + + /* this should fail */ + bpf_dynptr_clone(&ptr1, &clone); + + bpf_ringbuf_submit_dynptr(&clone, 0); + + return 0; +} + +/* Invalidating a dynptr should invalidate its clones */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #3") +int clone_invalidate1(void *ctx) +{ + struct bpf_dynptr clone; + struct bpf_dynptr ptr; + char read_data[64]; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + + bpf_ringbuf_submit_dynptr(&ptr, 0); + + /* this should fail */ + bpf_dynptr_read(read_data, sizeof(read_data), &clone, 0, 0); + + return 0; +} + +/* Invalidating a dynptr should invalidate its parent */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #3") +int clone_invalidate2(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone; + char read_data[64]; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + + bpf_ringbuf_submit_dynptr(&clone, 0); + + /* this should fail */ + bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); + + return 0; +} + +/* Invalidating a dynptr should invalidate its siblings */ +SEC("?raw_tp") +__failure __msg("Expected an initialized dynptr as arg #3") +int clone_invalidate3(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone1; + struct bpf_dynptr clone2; + char read_data[64]; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone1); + + bpf_dynptr_clone(&ptr, &clone2); + + bpf_ringbuf_submit_dynptr(&clone2, 0); + + /* this should fail */ + bpf_dynptr_read(read_data, sizeof(read_data), &clone1, 0, 0); + + return 0; +} + +/* Invalidating a dynptr should invalidate any data slices + * of its clones + */ +SEC("?raw_tp") +__failure __msg("invalid mem access 'scalar'") +int clone_invalidate4(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone; + int *data; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + data = bpf_dynptr_data(&clone, 0, sizeof(val)); + if (!data) + return 0; + + bpf_ringbuf_submit_dynptr(&ptr, 0); + + /* this should fail */ + *data = 123; + + return 0; +} + +/* Invalidating a dynptr should invalidate any data slices + * of its parent + */ +SEC("?raw_tp") +__failure __msg("invalid mem access 'scalar'") +int clone_invalidate5(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone; + int *data; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + data = bpf_dynptr_data(&ptr, 0, sizeof(val)); + if (!data) + return 0; + + bpf_dynptr_clone(&ptr, &clone); + + bpf_ringbuf_submit_dynptr(&clone, 0); + + /* this should fail */ + *data = 123; + + return 0; +} + +/* Invalidating a dynptr should invalidate any data slices + * of its sibling + */ +SEC("?raw_tp") +__failure __msg("invalid mem access 'scalar'") +int clone_invalidate6(void *ctx) +{ + struct bpf_dynptr ptr; + struct bpf_dynptr clone1; + struct bpf_dynptr clone2; + int *data; + + bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone1); + + bpf_dynptr_clone(&ptr, &clone2); + + data = bpf_dynptr_data(&clone1, 0, sizeof(val)); + if (!data) + return 0; + + bpf_ringbuf_submit_dynptr(&clone2, 0); + + /* this should fail */ + *data = 123; + + return 0; +} + +/* A skb clone's data slices should be invalid anytime packet data changes */ +SEC("?tc") +__failure __msg("invalid mem access 'scalar'") +int clone_skb_packet_data(struct __sk_buff *skb) +{ + char buffer[sizeof(__u32)] = {}; + struct bpf_dynptr clone; + struct bpf_dynptr ptr; + __u32 *data; + + bpf_dynptr_from_skb(skb, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + data = bpf_dynptr_slice_rdwr(&clone, 0, buffer, sizeof(buffer)); + if (!data) + return XDP_DROP; + + if (bpf_skb_pull_data(skb, skb->len)) + return SK_DROP; + + /* this should fail */ + *data = 123; + + return 0; +} + +/* A xdp clone's data slices should be invalid anytime packet data changes */ +SEC("?xdp") +__failure __msg("invalid mem access 'scalar'") +int clone_xdp_packet_data(struct xdp_md *xdp) +{ + char buffer[sizeof(__u32)] = {}; + struct bpf_dynptr clone; + struct bpf_dynptr ptr; + struct ethhdr *hdr; + __u32 *data; + + bpf_dynptr_from_xdp(xdp, 0, &ptr); + + bpf_dynptr_clone(&ptr, &clone); + data = bpf_dynptr_slice_rdwr(&clone, 0, buffer, sizeof(buffer)); + if (!data) + return XDP_DROP; + + if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(*hdr))) + return XDP_DROP; + + /* this should fail */ + *data = 123; + + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index b2fa6c47ecc0..be7de62de045 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -207,3 +207,301 @@ int test_dynptr_skb_data(struct __sk_buff *skb) return 1; } + +SEC("tp/syscalls/sys_enter_nanosleep") +int test_adjust(void *ctx) +{ + struct bpf_dynptr ptr; + __u32 bytes = 64; + __u32 off = 10; + __u32 trim = 15; + + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + err = bpf_ringbuf_reserve_dynptr(&ringbuf, bytes, 0, &ptr); + if (err) { + err = 1; + goto done; + } + + if (bpf_dynptr_size(&ptr) != bytes) { + err = 2; + goto done; + } + + /* Advance the dynptr by off */ + err = bpf_dynptr_adjust(&ptr, off, bpf_dynptr_size(&ptr)); + if (err) { + err = 3; + goto done; + } + + if (bpf_dynptr_size(&ptr) != bytes - off) { + err = 4; + goto done; + } + + /* Trim the dynptr */ + err = bpf_dynptr_adjust(&ptr, off, 15); + if (err) { + err = 5; + goto done; + } + + /* Check that the size was adjusted correctly */ + if (bpf_dynptr_size(&ptr) != trim - off) { + err = 6; + goto done; + } + +done: + bpf_ringbuf_discard_dynptr(&ptr, 0); + return 0; +} + +SEC("tp/syscalls/sys_enter_nanosleep") +int test_adjust_err(void *ctx) +{ + char write_data[45] = "hello there, world!!"; + struct bpf_dynptr ptr; + __u32 size = 64; + __u32 off = 20; + + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) { + err = 1; + goto done; + } + + /* Check that start can't be greater than end */ + if (bpf_dynptr_adjust(&ptr, 5, 1) != -EINVAL) { + err = 2; + goto done; + } + + /* Check that start can't be greater than size */ + if (bpf_dynptr_adjust(&ptr, size + 1, size + 1) != -ERANGE) { + err = 3; + goto done; + } + + /* Check that end can't be greater than size */ + if (bpf_dynptr_adjust(&ptr, 0, size + 1) != -ERANGE) { + err = 4; + goto done; + } + + if (bpf_dynptr_adjust(&ptr, off, size)) { + err = 5; + goto done; + } + + /* Check that you can't write more bytes than available into the dynptr + * after you've adjusted it + */ + if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) { + err = 6; + goto done; + } + + /* Check that even after adjusting, submitting/discarding + * a ringbuf dynptr works + */ + bpf_ringbuf_submit_dynptr(&ptr, 0); + return 0; + +done: + bpf_ringbuf_discard_dynptr(&ptr, 0); + return 0; +} + +SEC("tp/syscalls/sys_enter_nanosleep") +int test_zero_size_dynptr(void *ctx) +{ + char write_data = 'x', read_data; + struct bpf_dynptr ptr; + __u32 size = 64; + + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) { + err = 1; + goto done; + } + + /* After this, the dynptr has a size of 0 */ + if (bpf_dynptr_adjust(&ptr, size, size)) { + err = 2; + goto done; + } + + /* Test that reading + writing non-zero bytes is not ok */ + if (bpf_dynptr_read(&read_data, sizeof(read_data), &ptr, 0, 0) != -E2BIG) { + err = 3; + goto done; + } + + if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) { + err = 4; + goto done; + } + + /* Test that reading + writing 0 bytes from a 0-size dynptr is ok */ + if (bpf_dynptr_read(&read_data, 0, &ptr, 0, 0)) { + err = 5; + goto done; + } + + if (bpf_dynptr_write(&ptr, 0, &write_data, 0, 0)) { + err = 6; + goto done; + } + + err = 0; + +done: + bpf_ringbuf_discard_dynptr(&ptr, 0); + return 0; +} + +SEC("tp/syscalls/sys_enter_nanosleep") +int test_dynptr_is_null(void *ctx) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr ptr2; + __u64 size = 4; + + if (bpf_get_current_pid_tgid() >> 32 != pid) + return 0; + + /* Pass in invalid flags, get back an invalid dynptr */ + if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 123, &ptr1) != -EINVAL) { + err = 1; + goto exit_early; + } + + /* Test that the invalid dynptr is null */ + if (!bpf_dynptr_is_null(&ptr1)) { + err = 2; + goto exit_early; + } + + /* Get a valid dynptr */ + if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr2)) { + err = 3; + goto exit; + } + + /* Test that the valid dynptr is not null */ + if (bpf_dynptr_is_null(&ptr2)) { + err = 4; + goto exit; + } + +exit: + bpf_ringbuf_discard_dynptr(&ptr2, 0); +exit_early: + bpf_ringbuf_discard_dynptr(&ptr1, 0); + return 0; +} + +SEC("cgroup_skb/egress") +int test_dynptr_is_rdonly(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr ptr2; + struct bpf_dynptr ptr3; + + /* Pass in invalid flags, get back an invalid dynptr */ + if (bpf_dynptr_from_skb(skb, 123, &ptr1) != -EINVAL) { + err = 1; + return 0; + } + + /* Test that an invalid dynptr is_rdonly returns false */ + if (bpf_dynptr_is_rdonly(&ptr1)) { + err = 2; + return 0; + } + + /* Get a read-only dynptr */ + if (bpf_dynptr_from_skb(skb, 0, &ptr2)) { + err = 3; + return 0; + } + + /* Test that the dynptr is read-only */ + if (!bpf_dynptr_is_rdonly(&ptr2)) { + err = 4; + return 0; + } + + /* Get a read-writeable dynptr */ + if (bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr3)) { + err = 5; + goto done; + } + + /* Test that the dynptr is read-only */ + if (bpf_dynptr_is_rdonly(&ptr3)) { + err = 6; + goto done; + } + +done: + bpf_ringbuf_discard_dynptr(&ptr3, 0); + return 0; +} + +SEC("cgroup_skb/egress") +int test_dynptr_clone(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr1; + struct bpf_dynptr ptr2; + __u32 off = 2, size; + + /* Get a dynptr */ + if (bpf_dynptr_from_skb(skb, 0, &ptr1)) { + err = 1; + return 0; + } + + if (bpf_dynptr_adjust(&ptr1, off, bpf_dynptr_size(&ptr1))) { + err = 2; + return 0; + } + + /* Clone the dynptr */ + if (bpf_dynptr_clone(&ptr1, &ptr2)) { + err = 3; + return 0; + } + + size = bpf_dynptr_size(&ptr1); + + /* Check that the clone has the same size and rd-only */ + if (bpf_dynptr_size(&ptr2) != size) { + err = 4; + return 0; + } + + if (bpf_dynptr_is_rdonly(&ptr2) != bpf_dynptr_is_rdonly(&ptr1)) { + err = 5; + return 0; + } + + /* Advance and trim the original dynptr */ + bpf_dynptr_adjust(&ptr1, 5, 5); + + /* Check that only original dynptr was affected, and the clone wasn't */ + if (bpf_dynptr_size(&ptr2) != size) { + err = 6; + return 0; + } + + return 0; +} -- cgit v1.2.3 From b3e8701dd1fa25fc59cffa68240326efccff0336 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 4 Apr 2023 14:05:58 +0000 Subject: selftests/bpf: Add test case to assert precise scalar path pruning Add a test case to check for precision marking of safe paths. Ensure that the verifier will not prematurely prune scalars contributing to registers needing precision. Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/verifier/precise.c | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 6c03a7d805f9..8f0340eed696 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -217,3 +217,39 @@ .errstr = "invalid access to memory, mem_size=1 off=42 size=8", .result = REJECT, }, +{ + "precise: program doesn't prematurely prune branches", + .insns = { + BPF_ALU64_IMM(BPF_MOV, BPF_REG_6, 0x400), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_7, 0), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_8, 0), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_9, 0x80000000), + BPF_ALU64_IMM(BPF_MOD, BPF_REG_6, 0x401), + BPF_JMP_IMM(BPF_JA, 0, 0, 0), + BPF_JMP_REG(BPF_JLE, BPF_REG_6, BPF_REG_9, 2), + BPF_ALU64_IMM(BPF_MOD, BPF_REG_6, 1), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_9, 0), + BPF_JMP_REG(BPF_JLE, BPF_REG_6, BPF_REG_9, 1), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_6, 0), + BPF_ALU64_IMM(BPF_MOV, BPF_REG_0, 0), + BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), + BPF_LD_MAP_FD(BPF_REG_4, 0), + BPF_ALU64_REG(BPF_MOV, BPF_REG_1, BPF_REG_4), + BPF_ALU64_REG(BPF_MOV, BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_RSH, BPF_REG_6, 10), + BPF_ALU64_IMM(BPF_MUL, BPF_REG_6, 8192), + BPF_ALU64_REG(BPF_MOV, BPF_REG_1, BPF_REG_0), + BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_6), + BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_0, 0), + BPF_STX_MEM(BPF_DW, BPF_REG_1, BPF_REG_3, 0), + BPF_EXIT_INSN(), + }, + .fixup_map_array_48b = { 13 }, + .prog_type = BPF_PROG_TYPE_XDP, + .result = REJECT, + .errstr = "register with unbounded min value is not allowed", +}, -- cgit v1.2.3 From af0335d2926e1c597c247956cd608b6e8c9d6463 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Sat, 22 Apr 2023 10:20:53 -0700 Subject: docs/bpf: Add table to describe LRU properties Depending on the map type and flags for LRU, different properties are global or percpu. Add a table to describe these. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20230422172054.3355436-1-joe@isovalent.com --- Documentation/bpf/map_hash.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/bpf/map_hash.rst b/Documentation/bpf/map_hash.rst index 8669426264c6..1314dfc5e7e1 100644 --- a/Documentation/bpf/map_hash.rst +++ b/Documentation/bpf/map_hash.rst @@ -29,7 +29,16 @@ will automatically evict the least recently used entries when the hash table reaches capacity. An LRU hash maintains an internal LRU list that is used to select elements for eviction. This internal LRU list is shared across CPUs but it is possible to request a per CPU LRU list with -the ``BPF_F_NO_COMMON_LRU`` flag when calling ``bpf_map_create``. +the ``BPF_F_NO_COMMON_LRU`` flag when calling ``bpf_map_create``. The +following table outlines the properties of LRU maps depending on the a +map type and the flags used to create the map. + +======================== ========================= ================================ +Flag ``BPF_MAP_TYPE_LRU_HASH`` ``BPF_MAP_TYPE_LRU_PERCPU_HASH`` +======================== ========================= ================================ +**BPF_F_NO_COMMON_LRU** Per-CPU LRU, global map Per-CPU LRU, per-cpu map +**!BPF_F_NO_COMMON_LRU** Global LRU, global map Global LRU, per-cpu map +======================== ========================= ================================ Usage ===== -- cgit v1.2.3 From 1a986518b8a517637f70cd6d7d494bd0cbbf6145 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Sat, 22 Apr 2023 10:20:54 -0700 Subject: docs/bpf: Add LRU internals description and graph Extend the bpf hashmap docs to include a brief description of the internals of the LRU map type (setting appropriate API expectations), including the original commit message from Martin and a variant on the graph that I had presented during my Linux Plumbers Conference 2022 talk on "Pressure feedback for LRU map types"[0]. The node names in the dot file correspond roughly to the functions where the logic for those decisions or steps is defined, to help curious developers to cross-reference and update this logic if the details of the LRU implementation ever differ from this description. [0] https://lpc.events/event/16/contributions/1368/ Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann Reviewed-by: Bagas Sanjaya Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20230422172054.3355436-2-joe@isovalent.com --- Documentation/bpf/map_hash.rst | 42 ++++++++ Documentation/bpf/map_lru_hash_update.dot | 172 ++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 Documentation/bpf/map_lru_hash_update.dot diff --git a/Documentation/bpf/map_hash.rst b/Documentation/bpf/map_hash.rst index 1314dfc5e7e1..d2343952f2cb 100644 --- a/Documentation/bpf/map_hash.rst +++ b/Documentation/bpf/map_hash.rst @@ -1,5 +1,6 @@ .. SPDX-License-Identifier: GPL-2.0-only .. Copyright (C) 2022 Red Hat, Inc. +.. Copyright (C) 2022-2023 Isovalent, Inc. =============================================== BPF_MAP_TYPE_HASH, with PERCPU and LRU Variants @@ -215,3 +216,44 @@ Userspace walking the map elements from the map declared above: cur_key = &next_key; } } + +Internals +========= + +This section of the document is targeted at Linux developers and describes +aspects of the map implementations that are not considered stable ABI. The +following details are subject to change in future versions of the kernel. + +``BPF_MAP_TYPE_LRU_HASH`` and variants +-------------------------------------- + +Updating elements in LRU maps may trigger eviction behaviour when the capacity +of the map is reached. There are various steps that the update algorithm +attempts in order to enforce the LRU property which have increasing impacts on +other CPUs involved in the following operation attempts: + +- Attempt to use CPU-local state to batch operations +- Attempt to fetch free nodes from global lists +- Attempt to pull any node from a global list and remove it from the hashmap +- Attempt to pull any node from any CPU's list and remove it from the hashmap + +This algorithm is described visually in the following diagram. See the +description in commit 3a08c2fd7634 ("bpf: LRU List") for a full explanation of +the corresponding operations: + +.. kernel-figure:: map_lru_hash_update.dot + :alt: Diagram outlining the LRU eviction steps taken during map update. + + LRU hash eviction during map update for ``BPF_MAP_TYPE_LRU_HASH`` and + variants. See the dot file source for kernel function name code references. + +Map updates start from the oval in the top right "begin ``bpf_map_update()``" +and progress through the graph towards the bottom where the result may be +either a successful update or a failure with various error codes. The key in +the top right provides indicators for which locks may be involved in specific +operations. This is intended as a visual hint for reasoning about how map +contention may impact update operations, though the map type and flags may +impact the actual contention on those locks, based on the logic described in +the table above. For instance, if the map is created with type +``BPF_MAP_TYPE_LRU_PERCPU_HASH`` and flags ``BPF_F_NO_COMMON_LRU`` then all map +properties would be per-cpu. diff --git a/Documentation/bpf/map_lru_hash_update.dot b/Documentation/bpf/map_lru_hash_update.dot new file mode 100644 index 000000000000..a0fee349d29c --- /dev/null +++ b/Documentation/bpf/map_lru_hash_update.dot @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2022-2023 Isovalent, Inc. +digraph { + node [colorscheme=accent4,style=filled] # Apply colorscheme to all nodes + graph [splines=ortho, nodesep=1] + + subgraph cluster_key { + label = "Key\n(locks held during operation)"; + rankdir = TB; + + remote_lock [shape=rectangle,fillcolor=4,label="remote CPU LRU lock"] + hash_lock [shape=rectangle,fillcolor=3,label="hashtab lock"] + lru_lock [shape=rectangle,fillcolor=2,label="LRU lock"] + local_lock [shape=rectangle,fillcolor=1,label="local CPU LRU lock"] + no_lock [shape=rectangle,label="no locks held"] + } + + begin [shape=oval,label="begin\nbpf_map_update()"] + + // Nodes below with an 'fn_' prefix are roughly labeled by the C function + // names that initiate the corresponding logic in kernel/bpf/bpf_lru_list.c. + // Number suffixes and errno suffixes handle subsections of the corresponding + // logic in the function as of the writing of this dot. + + // cf. __local_list_pop_free() / bpf_percpu_lru_pop_free() + local_freelist_check [shape=diamond,fillcolor=1, + label="Local freelist\nnode available?"]; + use_local_node [shape=rectangle, + label="Use node owned\nby this CPU"] + + // cf. bpf_lru_pop_free() + common_lru_check [shape=diamond, + label="Map created with\ncommon LRU?\n(!BPF_F_NO_COMMON_LRU)"]; + + fn_bpf_lru_list_pop_free_to_local [shape=rectangle,fillcolor=2, + label="Flush local pending, + Rotate Global list, move + LOCAL_FREE_TARGET + from global -> local"] + // Also corresponds to: + // fn__local_list_flush() + // fn_bpf_lru_list_rotate() + fn___bpf_lru_node_move_to_free[shape=diamond,fillcolor=2, + label="Able to free\nLOCAL_FREE_TARGET\nnodes?"] + + fn___bpf_lru_list_shrink_inactive [shape=rectangle,fillcolor=3, + label="Shrink inactive list + up to remaining + LOCAL_FREE_TARGET + (global LRU -> local)"] + fn___bpf_lru_list_shrink [shape=diamond,fillcolor=2, + label="> 0 entries in\nlocal free list?"] + fn___bpf_lru_list_shrink2 [shape=rectangle,fillcolor=2, + label="Steal one node from + inactive, or if empty, + from active global list"] + fn___bpf_lru_list_shrink3 [shape=rectangle,fillcolor=3, + label="Try to remove\nnode from hashtab"] + + local_freelist_check2 [shape=diamond,label="Htab removal\nsuccessful?"] + common_lru_check2 [shape=diamond, + label="Map created with\ncommon LRU?\n(!BPF_F_NO_COMMON_LRU)"]; + + subgraph cluster_remote_lock { + label = "Iterate through CPUs\n(start from current)"; + style = dashed; + rankdir=LR; + + local_freelist_check5 [shape=diamond,fillcolor=4, + label="Steal a node from\nper-cpu freelist?"] + local_freelist_check6 [shape=rectangle,fillcolor=4, + label="Steal a node from + (1) Unreferenced pending, or + (2) Any pending node"] + local_freelist_check7 [shape=rectangle,fillcolor=3, + label="Try to remove\nnode from hashtab"] + fn_htab_lru_map_update_elem [shape=diamond, + label="Stole node\nfrom remote\nCPU?"] + fn_htab_lru_map_update_elem2 [shape=diamond,label="Iterated\nall CPUs?"] + // Also corresponds to: + // use_local_node() + // fn__local_list_pop_pending() + } + + fn_bpf_lru_list_pop_free_to_local2 [shape=rectangle, + label="Use node that was\nnot recently referenced"] + local_freelist_check4 [shape=rectangle, + label="Use node that was\nactively referenced\nin global list"] + fn_htab_lru_map_update_elem_ENOMEM [shape=oval,label="return -ENOMEM"] + fn_htab_lru_map_update_elem3 [shape=rectangle, + label="Use node that was\nactively referenced\nin (another?) CPU's cache"] + fn_htab_lru_map_update_elem4 [shape=rectangle,fillcolor=3, + label="Update hashmap\nwith new element"] + fn_htab_lru_map_update_elem5 [shape=oval,label="return 0"] + fn_htab_lru_map_update_elem_EBUSY [shape=oval,label="return -EBUSY"] + fn_htab_lru_map_update_elem_EEXIST [shape=oval,label="return -EEXIST"] + fn_htab_lru_map_update_elem_ENOENT [shape=oval,label="return -ENOENT"] + + begin -> local_freelist_check + local_freelist_check -> use_local_node [xlabel="Y"] + local_freelist_check -> common_lru_check [xlabel="N"] + common_lru_check -> fn_bpf_lru_list_pop_free_to_local [xlabel="Y"] + common_lru_check -> fn___bpf_lru_list_shrink_inactive [xlabel="N"] + fn_bpf_lru_list_pop_free_to_local -> fn___bpf_lru_node_move_to_free + fn___bpf_lru_node_move_to_free -> + fn_bpf_lru_list_pop_free_to_local2 [xlabel="Y"] + fn___bpf_lru_node_move_to_free -> + fn___bpf_lru_list_shrink_inactive [xlabel="N"] + fn___bpf_lru_list_shrink_inactive -> fn___bpf_lru_list_shrink + fn___bpf_lru_list_shrink -> fn_bpf_lru_list_pop_free_to_local2 [xlabel = "Y"] + fn___bpf_lru_list_shrink -> fn___bpf_lru_list_shrink2 [xlabel="N"] + fn___bpf_lru_list_shrink2 -> fn___bpf_lru_list_shrink3 + fn___bpf_lru_list_shrink3 -> local_freelist_check2 + local_freelist_check2 -> local_freelist_check4 [xlabel = "Y"] + local_freelist_check2 -> common_lru_check2 [xlabel = "N"] + common_lru_check2 -> local_freelist_check5 [xlabel = "Y"] + common_lru_check2 -> fn_htab_lru_map_update_elem_ENOMEM [xlabel = "N"] + local_freelist_check5 -> fn_htab_lru_map_update_elem [xlabel = "Y"] + local_freelist_check5 -> local_freelist_check6 [xlabel = "N"] + local_freelist_check6 -> local_freelist_check7 + local_freelist_check7 -> fn_htab_lru_map_update_elem + + fn_htab_lru_map_update_elem -> fn_htab_lru_map_update_elem3 [xlabel = "Y"] + fn_htab_lru_map_update_elem -> fn_htab_lru_map_update_elem2 [xlabel = "N"] + fn_htab_lru_map_update_elem2 -> + fn_htab_lru_map_update_elem_ENOMEM [xlabel = "Y"] + fn_htab_lru_map_update_elem2 -> local_freelist_check5 [xlabel = "N"] + fn_htab_lru_map_update_elem3 -> fn_htab_lru_map_update_elem4 + + use_local_node -> fn_htab_lru_map_update_elem4 + fn_bpf_lru_list_pop_free_to_local2 -> fn_htab_lru_map_update_elem4 + local_freelist_check4 -> fn_htab_lru_map_update_elem4 + + fn_htab_lru_map_update_elem4 -> fn_htab_lru_map_update_elem5 [headlabel="Success"] + fn_htab_lru_map_update_elem4 -> + fn_htab_lru_map_update_elem_EBUSY [xlabel="Hashtab lock failed"] + fn_htab_lru_map_update_elem4 -> + fn_htab_lru_map_update_elem_EEXIST [xlabel="BPF_EXIST set and\nkey already exists"] + fn_htab_lru_map_update_elem4 -> + fn_htab_lru_map_update_elem_ENOENT [headlabel="BPF_NOEXIST set\nand no such entry"] + + // Create invisible pad nodes to line up various nodes + pad0 [style=invis] + pad1 [style=invis] + pad2 [style=invis] + pad3 [style=invis] + pad4 [style=invis] + + // Line up the key with the top of the graph + no_lock -> local_lock [style=invis] + local_lock -> lru_lock [style=invis] + lru_lock -> hash_lock [style=invis] + hash_lock -> remote_lock [style=invis] + remote_lock -> local_freelist_check5 [style=invis] + remote_lock -> fn___bpf_lru_list_shrink [style=invis] + + // Line up return code nodes at the bottom of the graph + fn_htab_lru_map_update_elem -> pad0 [style=invis] + pad0 -> pad1 [style=invis] + pad1 -> pad2 [style=invis] + //pad2-> fn_htab_lru_map_update_elem_ENOMEM [style=invis] + fn_htab_lru_map_update_elem4 -> pad3 [style=invis] + pad3 -> fn_htab_lru_map_update_elem5 [style=invis] + pad3 -> fn_htab_lru_map_update_elem_EBUSY [style=invis] + pad3 -> fn_htab_lru_map_update_elem_EEXIST [style=invis] + pad3 -> fn_htab_lru_map_update_elem_ENOENT [style=invis] + + // Reduce diagram width by forcing some nodes to appear above others + local_freelist_check4 -> fn_htab_lru_map_update_elem3 [style=invis] + common_lru_check2 -> pad4 [style=invis] + pad4 -> local_freelist_check5 [style=invis] +} -- cgit v1.2.3 From 74fc8801edc279fb5f778eb91df48e4d3cd951a2 Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Fri, 21 Apr 2023 14:41:31 -0700 Subject: bpftool: Show map IDs along with struct_ops links. A new link type, BPF_LINK_TYPE_STRUCT_OPS, was added to attach struct_ops to links. (226bc6ae6405) It would be helpful for users to know which map is associated with the link. The assumption was that every link is associated with a BPF program, but this does not hold true for struct_ops. It would be better to display map_id instead of prog_id for struct_ops links. However, some tools may rely on the old assumption and need a prog_id. The discussion on the mailing list suggests that tools should parse JSON format. We will maintain the existing JSON format by adding a map_id without removing prog_id. As for plain text format, we will remove prog_id from the header line and add a map_id for struct_ops links. Signed-off-by: Kui-Feng Lee Signed-off-by: Daniel Borkmann Reviewed-by: Quentin Monnet Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20230421214131.352662-1-kuifeng@meta.com --- tools/bpf/bpftool/link.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index d98dbc50cf4c..243b74e18e51 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -212,7 +212,10 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) case BPF_LINK_TYPE_NETFILTER: netfilter_dump_json(info, json_wtr); break; - + case BPF_LINK_TYPE_STRUCT_OPS: + jsonw_uint_field(json_wtr, "map_id", + info->struct_ops.map_id); + break; default: break; } @@ -245,7 +248,10 @@ static void show_link_header_plain(struct bpf_link_info *info) else printf("type %u ", info->type); - printf("prog %u ", info->prog_id); + if (info->type == BPF_LINK_TYPE_STRUCT_OPS) + printf("map %u ", info->struct_ops.map_id); + else + printf("prog %u ", info->prog_id); } static void show_link_attach_type_plain(__u32 attach_type) -- cgit v1.2.3 From 84214ab4689f962b4bfc47fc9a5838d25ac4274d Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 18 Apr 2023 15:30:42 +0200 Subject: igc: Enable and fix RX hash usage by netstack When function igc_rx_hash() was introduced in v4.20 via commit 0507ef8a0372 ("igc: Add transmit and receive fastpath and interrupt handlers"), the hardware wasn't configured to provide RSS hash, thus it made sense to not enable net_device NETIF_F_RXHASH feature bit. The NIC hardware was configured to enable RSS hash info in v5.2 via commit 2121c2712f82 ("igc: Add multiple receive queues control supporting"), but forgot to set the NETIF_F_RXHASH feature bit. The original implementation of igc_rx_hash() didn't extract the associated pkt_hash_type, but statically set PKT_HASH_TYPE_L3. The largest portions of this patch are about extracting the RSS Type from the hardware and mapping this to enum pkt_hash_types. This was based on Foxville i225 software user manual rev-1.3.1 and tested on Intel Ethernet Controller I225-LM (rev 03). For UDP it's worth noting that RSS (type) hashing have been disabled both for IPv4 and IPv6 (see IGC_MRQC_RSS_FIELD_IPV4_UDP + IGC_MRQC_RSS_FIELD_IPV6_UDP) because hardware RSS doesn't handle fragmented pkts well when enabled (can cause out-of-order). This results in PKT_HASH_TYPE_L3 for UDP packets, and hash value doesn't include UDP port numbers. Not being PKT_HASH_TYPE_L4, have the effect that netstack will do a software based hash calc calling into flow_dissect, but only when code calls skb_get_hash(), which doesn't necessary happen for local delivery. For QA verification testing I wrote a small bpftrace prog: [0] https://github.com/xdp-project/xdp-project/blob/master/areas/hints/monitor_skb_hash_on_dev.bt Fixes: 2121c2712f82 ("igc: Add multiple receive queues control supporting") Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Acked-by: Song Yoong Siang Link: https://lore.kernel.org/bpf/168182464270.616355.11391652654430626584.stgit@firesoul --- drivers/net/ethernet/intel/igc/igc.h | 28 ++++++++++++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_main.c | 31 +++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 34aebf00a512..f7f9e217e7b4 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "igc_hw.h" @@ -311,6 +312,33 @@ extern char igc_driver_name[]; #define IGC_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 #define IGC_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 +/* RX-desc Write-Back format RSS Type's */ +enum igc_rss_type_num { + IGC_RSS_TYPE_NO_HASH = 0, + IGC_RSS_TYPE_HASH_TCP_IPV4 = 1, + IGC_RSS_TYPE_HASH_IPV4 = 2, + IGC_RSS_TYPE_HASH_TCP_IPV6 = 3, + IGC_RSS_TYPE_HASH_IPV6_EX = 4, + IGC_RSS_TYPE_HASH_IPV6 = 5, + IGC_RSS_TYPE_HASH_TCP_IPV6_EX = 6, + IGC_RSS_TYPE_HASH_UDP_IPV4 = 7, + IGC_RSS_TYPE_HASH_UDP_IPV6 = 8, + IGC_RSS_TYPE_HASH_UDP_IPV6_EX = 9, + IGC_RSS_TYPE_MAX = 10, +}; +#define IGC_RSS_TYPE_MAX_TABLE 16 +#define IGC_RSS_TYPE_MASK GENMASK(3,0) /* 4-bits (3:0) = mask 0x0F */ + +/* igc_rss_type - Rx descriptor RSS type field */ +static inline u32 igc_rss_type(const union igc_adv_rx_desc *rx_desc) +{ + /* RSS Type 4-bits (3:0) number: 0-9 (above 9 is reserved) + * Accessing the same bits via u16 (wb.lower.lo_dword.hs_rss.pkt_info) + * is slightly slower than via u32 (wb.lower.lo_dword.data) + */ + return le32_get_bits(rx_desc->wb.lower.lo_dword.data, IGC_RSS_TYPE_MASK); +} + /* Interrupt defines */ #define IGC_START_ITR 648 /* ~6000 ints/sec */ #define IGC_4K_ITR 980 diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index ba49728be919..f6b03e0372e0 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -1687,14 +1687,36 @@ static void igc_rx_checksum(struct igc_ring *ring, le32_to_cpu(rx_desc->wb.upper.status_error)); } +/* Mapping HW RSS Type to enum pkt_hash_types */ +static const enum pkt_hash_types igc_rss_type_table[IGC_RSS_TYPE_MAX_TABLE] = { + [IGC_RSS_TYPE_NO_HASH] = PKT_HASH_TYPE_L2, + [IGC_RSS_TYPE_HASH_TCP_IPV4] = PKT_HASH_TYPE_L4, + [IGC_RSS_TYPE_HASH_IPV4] = PKT_HASH_TYPE_L3, + [IGC_RSS_TYPE_HASH_TCP_IPV6] = PKT_HASH_TYPE_L4, + [IGC_RSS_TYPE_HASH_IPV6_EX] = PKT_HASH_TYPE_L3, + [IGC_RSS_TYPE_HASH_IPV6] = PKT_HASH_TYPE_L3, + [IGC_RSS_TYPE_HASH_TCP_IPV6_EX] = PKT_HASH_TYPE_L4, + [IGC_RSS_TYPE_HASH_UDP_IPV4] = PKT_HASH_TYPE_L4, + [IGC_RSS_TYPE_HASH_UDP_IPV6] = PKT_HASH_TYPE_L4, + [IGC_RSS_TYPE_HASH_UDP_IPV6_EX] = PKT_HASH_TYPE_L4, + [10] = PKT_HASH_TYPE_NONE, /* RSS Type above 9 "Reserved" by HW */ + [11] = PKT_HASH_TYPE_NONE, /* keep array sized for SW bit-mask */ + [12] = PKT_HASH_TYPE_NONE, /* to handle future HW revisons */ + [13] = PKT_HASH_TYPE_NONE, + [14] = PKT_HASH_TYPE_NONE, + [15] = PKT_HASH_TYPE_NONE, +}; + static inline void igc_rx_hash(struct igc_ring *ring, union igc_adv_rx_desc *rx_desc, struct sk_buff *skb) { - if (ring->netdev->features & NETIF_F_RXHASH) - skb_set_hash(skb, - le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), - PKT_HASH_TYPE_L3); + if (ring->netdev->features & NETIF_F_RXHASH) { + u32 rss_hash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); + u32 rss_type = igc_rss_type(rx_desc); + + skb_set_hash(skb, rss_hash, igc_rss_type_table[rss_type]); + } } static void igc_rx_vlan(struct igc_ring *rx_ring, @@ -6551,6 +6573,7 @@ static int igc_probe(struct pci_dev *pdev, netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; netdev->features |= NETIF_F_TSO_ECN; + netdev->features |= NETIF_F_RXHASH; netdev->features |= NETIF_F_RXCSUM; netdev->features |= NETIF_F_HW_CSUM; netdev->features |= NETIF_F_SCTP_CRC; -- cgit v1.2.3 From 73b7123de0cfa4f6609677e927ab02cb05b593c2 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 18 Apr 2023 15:30:47 +0200 Subject: igc: Add igc_xdp_buff wrapper for xdp_buff in driver Driver specific metadata data for XDP-hints kfuncs are propagated via tail extending the struct xdp_buff with a locally scoped driver struct. Zero-Copy AF_XDP/XSK does similar tricks via struct xdp_buff_xsk. This xdp_buff_xsk struct contains a CB area (24 bytes) that can be used for extending the locally scoped driver into. The XSK_CHECK_PRIV_TYPE define catch size violations build time. The changes needed for AF_XDP zero-copy in igc_clean_rx_irq_zc() is done in next patch, because the member rx_desc isn't available at this point. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Acked-by: Song Yoong Siang Link: https://lore.kernel.org/bpf/168182464779.616355.3761989884165609387.stgit@firesoul --- drivers/net/ethernet/intel/igc/igc.h | 5 +++++ drivers/net/ethernet/intel/igc/igc_main.c | 16 +++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index f7f9e217e7b4..76a5115aefc8 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -499,6 +499,11 @@ struct igc_rx_buffer { }; }; +/* context wrapper around xdp_buff to provide access to descriptor metadata */ +struct igc_xdp_buff { + struct xdp_buff xdp; +}; + struct igc_q_vector { struct igc_adapter *adapter; /* backlink */ void __iomem *itr_register; diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index f6b03e0372e0..06bf8a7eec93 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2233,6 +2233,8 @@ static bool igc_alloc_rx_buffers_zc(struct igc_ring *ring, u16 count) if (!count) return ok; + XSK_CHECK_PRIV_TYPE(struct igc_xdp_buff); + desc = IGC_RX_DESC(ring, i); bi = &ring->rx_buffer_info[i]; i -= ring->count; @@ -2517,8 +2519,8 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) union igc_adv_rx_desc *rx_desc; struct igc_rx_buffer *rx_buffer; unsigned int size, truesize; + struct igc_xdp_buff ctx; ktime_t timestamp = 0; - struct xdp_buff xdp; int pkt_offset = 0; void *pktbuf; @@ -2552,13 +2554,13 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) } if (!skb) { - xdp_init_buff(&xdp, truesize, &rx_ring->xdp_rxq); - xdp_prepare_buff(&xdp, pktbuf - igc_rx_offset(rx_ring), + xdp_init_buff(&ctx.xdp, truesize, &rx_ring->xdp_rxq); + xdp_prepare_buff(&ctx.xdp, pktbuf - igc_rx_offset(rx_ring), igc_rx_offset(rx_ring) + pkt_offset, size, true); - xdp_buff_clear_frags_flag(&xdp); + xdp_buff_clear_frags_flag(&ctx.xdp); - skb = igc_xdp_run_prog(adapter, &xdp); + skb = igc_xdp_run_prog(adapter, &ctx.xdp); } if (IS_ERR(skb)) { @@ -2580,9 +2582,9 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) } else if (skb) igc_add_rx_frag(rx_ring, rx_buffer, skb, size); else if (ring_uses_build_skb(rx_ring)) - skb = igc_build_skb(rx_ring, rx_buffer, &xdp); + skb = igc_build_skb(rx_ring, rx_buffer, &ctx.xdp); else - skb = igc_construct_skb(rx_ring, rx_buffer, &xdp, + skb = igc_construct_skb(rx_ring, rx_buffer, &ctx.xdp, timestamp); /* exit if we failed to retrieve a buffer */ -- cgit v1.2.3 From 8416814fffa9cfa74c18da149f522dd9e1850987 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 18 Apr 2023 15:30:52 +0200 Subject: igc: Add XDP hints kfuncs for RX hash This implements XDP hints kfunc for RX-hash (xmo_rx_hash). The HW rss hash type is handled via mapping table. This igc driver (default config) does L3 hashing for UDP packets (excludes UDP src/dest ports in hash calc). Meaning RSS hash type is L3 based. Tested that the igc_rss_type_num for UDP is either IGC_RSS_TYPE_HASH_IPV4 or IGC_RSS_TYPE_HASH_IPV6. This patch also updates AF_XDP zero-copy function igc_clean_rx_irq_zc() to use the xdp_buff wrapper struct igc_xdp_buff. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Acked-by: Song Yoong Siang Link: https://lore.kernel.org/bpf/168182465285.616355.2701740913376314790.stgit@firesoul --- drivers/net/ethernet/intel/igc/igc.h | 1 + drivers/net/ethernet/intel/igc/igc_main.c | 53 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 76a5115aefc8..c609a2e648f8 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -502,6 +502,7 @@ struct igc_rx_buffer { /* context wrapper around xdp_buff to provide access to descriptor metadata */ struct igc_xdp_buff { struct xdp_buff xdp; + union igc_adv_rx_desc *rx_desc; }; struct igc_q_vector { diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 06bf8a7eec93..c18486f46085 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2559,6 +2559,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) igc_rx_offset(rx_ring) + pkt_offset, size, true); xdp_buff_clear_frags_flag(&ctx.xdp); + ctx.rx_desc = rx_desc; skb = igc_xdp_run_prog(adapter, &ctx.xdp); } @@ -2685,6 +2686,15 @@ static void igc_dispatch_skb_zc(struct igc_q_vector *q_vector, napi_gro_receive(&q_vector->napi, skb); } +static struct igc_xdp_buff *xsk_buff_to_igc_ctx(struct xdp_buff *xdp) +{ + /* xdp_buff pointer used by ZC code path is alloc as xdp_buff_xsk. The + * igc_xdp_buff shares its layout with xdp_buff_xsk and private + * igc_xdp_buff fields fall into xdp_buff_xsk->cb + */ + return (struct igc_xdp_buff *)xdp; +} + static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget) { struct igc_adapter *adapter = q_vector->adapter; @@ -2703,6 +2713,7 @@ static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget) while (likely(total_packets < budget)) { union igc_adv_rx_desc *desc; struct igc_rx_buffer *bi; + struct igc_xdp_buff *ctx; ktime_t timestamp = 0; unsigned int size; int res; @@ -2720,6 +2731,9 @@ static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget) bi = &ring->rx_buffer_info[ntc]; + ctx = xsk_buff_to_igc_ctx(bi->xdp); + ctx->rx_desc = desc; + if (igc_test_staterr(desc, IGC_RXDADV_STAT_TSIP)) { timestamp = igc_ptp_rx_pktstamp(q_vector->adapter, bi->xdp->data); @@ -6475,6 +6489,44 @@ u32 igc_rd32(struct igc_hw *hw, u32 reg) return value; } +/* Mapping HW RSS Type to enum xdp_rss_hash_type */ +static enum xdp_rss_hash_type igc_xdp_rss_type[IGC_RSS_TYPE_MAX_TABLE] = { + [IGC_RSS_TYPE_NO_HASH] = XDP_RSS_TYPE_L2, + [IGC_RSS_TYPE_HASH_TCP_IPV4] = XDP_RSS_TYPE_L4_IPV4_TCP, + [IGC_RSS_TYPE_HASH_IPV4] = XDP_RSS_TYPE_L3_IPV4, + [IGC_RSS_TYPE_HASH_TCP_IPV6] = XDP_RSS_TYPE_L4_IPV6_TCP, + [IGC_RSS_TYPE_HASH_IPV6_EX] = XDP_RSS_TYPE_L3_IPV6_EX, + [IGC_RSS_TYPE_HASH_IPV6] = XDP_RSS_TYPE_L3_IPV6, + [IGC_RSS_TYPE_HASH_TCP_IPV6_EX] = XDP_RSS_TYPE_L4_IPV6_TCP_EX, + [IGC_RSS_TYPE_HASH_UDP_IPV4] = XDP_RSS_TYPE_L4_IPV4_UDP, + [IGC_RSS_TYPE_HASH_UDP_IPV6] = XDP_RSS_TYPE_L4_IPV6_UDP, + [IGC_RSS_TYPE_HASH_UDP_IPV6_EX] = XDP_RSS_TYPE_L4_IPV6_UDP_EX, + [10] = XDP_RSS_TYPE_NONE, /* RSS Type above 9 "Reserved" by HW */ + [11] = XDP_RSS_TYPE_NONE, /* keep array sized for SW bit-mask */ + [12] = XDP_RSS_TYPE_NONE, /* to handle future HW revisons */ + [13] = XDP_RSS_TYPE_NONE, + [14] = XDP_RSS_TYPE_NONE, + [15] = XDP_RSS_TYPE_NONE, +}; + +static int igc_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash, + enum xdp_rss_hash_type *rss_type) +{ + const struct igc_xdp_buff *ctx = (void *)_ctx; + + if (!(ctx->xdp.rxq->dev->features & NETIF_F_RXHASH)) + return -ENODATA; + + *hash = le32_to_cpu(ctx->rx_desc->wb.lower.hi_dword.rss); + *rss_type = igc_xdp_rss_type[igc_rss_type(ctx->rx_desc)]; + + return 0; +} + +static const struct xdp_metadata_ops igc_xdp_metadata_ops = { + .xmo_rx_hash = igc_xdp_rx_hash, +}; + /** * igc_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -6548,6 +6600,7 @@ static int igc_probe(struct pci_dev *pdev, hw->hw_addr = adapter->io_addr; netdev->netdev_ops = &igc_netdev_ops; + netdev->xdp_metadata_ops = &igc_xdp_metadata_ops; igc_ethtool_set_ops(netdev); netdev->watchdog_timeo = 5 * HZ; -- cgit v1.2.3 From d677266755c6e55c43b6755673a1eeae3d452e87 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 18 Apr 2023 15:30:57 +0200 Subject: igc: Add XDP hints kfuncs for RX timestamp The NIC hardware RX timestamping mechanism adds an optional tailored header before the MAC header containing packet reception time. Optional depending on RX descriptor TSIP status bit (IGC_RXDADV_STAT_TSIP). In case this bit is set driver does offset adjustments to packet data start and extracts the timestamp. The timestamp need to be extracted before invoking the XDP bpf_prog, because this area just before the packet is also accessible by XDP via data_meta context pointer (and helper bpf_xdp_adjust_meta). Thus, an XDP bpf_prog can potentially overwrite this and corrupt data that we want to extract with the new kfunc for reading the timestamp. Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Acked-by: Song Yoong Siang Link: https://lore.kernel.org/bpf/168182465791.616355.2583922957423587914.stgit@firesoul --- drivers/net/ethernet/intel/igc/igc.h | 1 + drivers/net/ethernet/intel/igc/igc_main.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index c609a2e648f8..18d4af934d8c 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -503,6 +503,7 @@ struct igc_rx_buffer { struct igc_xdp_buff { struct xdp_buff xdp; union igc_adv_rx_desc *rx_desc; + ktime_t rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */ }; struct igc_q_vector { diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index c18486f46085..b78e0e6562c8 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2549,6 +2549,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget) if (igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP)) { timestamp = igc_ptp_rx_pktstamp(q_vector->adapter, pktbuf); + ctx.rx_ts = timestamp; pkt_offset = IGC_TS_HDR_LEN; size -= IGC_TS_HDR_LEN; } @@ -2737,6 +2738,7 @@ static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget) if (igc_test_staterr(desc, IGC_RXDADV_STAT_TSIP)) { timestamp = igc_ptp_rx_pktstamp(q_vector->adapter, bi->xdp->data); + ctx->rx_ts = timestamp; bi->xdp->data += IGC_TS_HDR_LEN; @@ -6523,8 +6525,22 @@ static int igc_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash, return 0; } +static int igc_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp) +{ + const struct igc_xdp_buff *ctx = (void *)_ctx; + + if (igc_test_staterr(ctx->rx_desc, IGC_RXDADV_STAT_TSIP)) { + *timestamp = ctx->rx_ts; + + return 0; + } + + return -ENODATA; +} + static const struct xdp_metadata_ops igc_xdp_metadata_ops = { .xmo_rx_hash = igc_xdp_rx_hash, + .xmo_rx_timestamp = igc_xdp_rx_timestamp, }; /** -- cgit v1.2.3 From bb323478767d4b4d78380bc9e2c0971ca33442af Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 18 Apr 2023 15:31:03 +0200 Subject: selftests/bpf: xdp_hw_metadata track more timestamps To correlate the hardware RX timestamp with something, add tracking of two software timestamps both clock source CLOCK_TAI (see description in man clock_gettime(2)). XDP metadata is extended with xdp_timestamp for capturing when XDP received the packet. Populated with BPF helper bpf_ktime_get_tai_ns(). I could not find a BPF helper for getting CLOCK_REALTIME, which would have been preferred. In userspace when AF_XDP sees the packet another software timestamp is recorded via clock_gettime() also clock source CLOCK_TAI. Example output shortly after loading igc driver: poll: 1 (0) skip=1 fail=0 redir=2 xsk_ring_cons__peek: 1 0x12557a8: rx_desc[1]->addr=100000000009000 addr=9100 comp_addr=9000 rx_hash: 0x82A96531 with RSS type:0x1 rx_timestamp: 1681740540304898909 (sec:1681740540.3049) XDP RX-time: 1681740577304958316 (sec:1681740577.3050) delta sec:37.0001 (37000059.407 usec) AF_XDP time: 1681740577305051315 (sec:1681740577.3051) delta sec:0.0001 (92.999 usec) 0x12557a8: complete idx=9 addr=9000 The first observation is that the 37 sec difference between RX HW vs XDP timestamps, which indicate hardware is likely clock source CLOCK_REALTIME, because (as of this writing) CLOCK_TAI is initialised with a 37 sec offset. The 93 usec (microsec) difference between XDP vs AF_XDP userspace is the userspace wakeup time. On this hardware it was caused by CPU idle sleep states, which can be reduced by tuning /dev/cpu_dma_latency. View current requested/allowed latency bound via: hexdump --format '"%d\n"' /dev/cpu_dma_latency More explanation of the output and how this can be used to identify clock drift for the HW clock can be seen here[1]: [1] https://github.com/xdp-project/xdp-project/blob/master/areas/hints/xdp_hints_kfuncs02_driver_igc.org Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Acked-by: Song Yoong Siang Link: https://lore.kernel.org/bpf/168182466298.616355.2544377890818617459.stgit@firesoul --- .../testing/selftests/bpf/progs/xdp_hw_metadata.c | 4 +- tools/testing/selftests/bpf/xdp_hw_metadata.c | 47 +++++++++++++++++++--- tools/testing/selftests/bpf/xdp_metadata.h | 1 + 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c b/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c index e1c787815e44..b2dfd7066c6e 100644 --- a/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/progs/xdp_hw_metadata.c @@ -77,7 +77,9 @@ int rx(struct xdp_md *ctx) } err = bpf_xdp_metadata_rx_timestamp(ctx, &meta->rx_timestamp); - if (err) + if (!err) + meta->xdp_timestamp = bpf_ktime_get_tai_ns(); + else meta->rx_timestamp = 0; /* Used by AF_XDP as not avail signal */ err = bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type); diff --git a/tools/testing/selftests/bpf/xdp_hw_metadata.c b/tools/testing/selftests/bpf/xdp_hw_metadata.c index 987cf0db5ebc..613321eb84c1 100644 --- a/tools/testing/selftests/bpf/xdp_hw_metadata.c +++ b/tools/testing/selftests/bpf/xdp_hw_metadata.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "xdp_metadata.h" @@ -134,18 +135,52 @@ static void refill_rx(struct xsk *xsk, __u64 addr) } } -static void verify_xdp_metadata(void *data) +#define NANOSEC_PER_SEC 1000000000 /* 10^9 */ +static __u64 gettime(clockid_t clock_id) +{ + struct timespec t; + int res; + + /* See man clock_gettime(2) for type of clock_id's */ + res = clock_gettime(clock_id, &t); + + if (res < 0) + error(res, errno, "Error with clock_gettime()"); + + return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec; +} + +static void verify_xdp_metadata(void *data, clockid_t clock_id) { struct xdp_meta *meta; meta = data - sizeof(*meta); - printf("rx_timestamp: %llu\n", meta->rx_timestamp); if (meta->rx_hash_err < 0) printf("No rx_hash err=%d\n", meta->rx_hash_err); else printf("rx_hash: 0x%X with RSS type:0x%X\n", meta->rx_hash, meta->rx_hash_type); + + printf("rx_timestamp: %llu (sec:%0.4f)\n", meta->rx_timestamp, + (double)meta->rx_timestamp / NANOSEC_PER_SEC); + if (meta->rx_timestamp) { + __u64 usr_clock = gettime(clock_id); + __u64 xdp_clock = meta->xdp_timestamp; + __s64 delta_X = xdp_clock - meta->rx_timestamp; + __s64 delta_X2U = usr_clock - xdp_clock; + + printf("XDP RX-time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n", + xdp_clock, (double)xdp_clock / NANOSEC_PER_SEC, + (double)delta_X / NANOSEC_PER_SEC, + (double)delta_X / 1000); + + printf("AF_XDP time: %llu (sec:%0.4f) delta sec:%0.4f (%0.3f usec)\n", + usr_clock, (double)usr_clock / NANOSEC_PER_SEC, + (double)delta_X2U / NANOSEC_PER_SEC, + (double)delta_X2U / 1000); + } + } static void verify_skb_metadata(int fd) @@ -193,7 +228,7 @@ static void verify_skb_metadata(int fd) printf("skb hwtstamp is not found!\n"); } -static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd) +static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t clock_id) { const struct xdp_desc *rx_desc; struct pollfd fds[rxq + 1]; @@ -243,7 +278,8 @@ static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd) addr = xsk_umem__add_offset_to_addr(rx_desc->addr); printf("%p: rx_desc[%u]->addr=%llx addr=%llx comp_addr=%llx\n", xsk, idx, rx_desc->addr, addr, comp_addr); - verify_xdp_metadata(xsk_umem__get_data(xsk->umem_area, addr)); + verify_xdp_metadata(xsk_umem__get_data(xsk->umem_area, addr), + clock_id); xsk_ring_cons__release(&xsk->rx, 1); refill_rx(xsk, comp_addr); } @@ -370,6 +406,7 @@ static void timestamping_enable(int fd, int val) int main(int argc, char *argv[]) { + clockid_t clock_id = CLOCK_TAI; int server_fd = -1; int ret; int i; @@ -443,7 +480,7 @@ int main(int argc, char *argv[]) error(1, -ret, "bpf_xdp_attach"); signal(SIGINT, handle_signal); - ret = verify_metadata(rx_xsk, rxq, server_fd); + ret = verify_metadata(rx_xsk, rxq, server_fd, clock_id); close(server_fd); cleanup(); if (ret) diff --git a/tools/testing/selftests/bpf/xdp_metadata.h b/tools/testing/selftests/bpf/xdp_metadata.h index 0c4624dc6f2f..938a729bd307 100644 --- a/tools/testing/selftests/bpf/xdp_metadata.h +++ b/tools/testing/selftests/bpf/xdp_metadata.h @@ -11,6 +11,7 @@ struct xdp_meta { __u64 rx_timestamp; + __u64 xdp_timestamp; __u32 rx_hash; union { __u32 rx_hash_type; -- cgit v1.2.3 From a4644119208444f84d9ffcd4d0af630046c2de98 Mon Sep 17 00:00:00 2001 From: Florent Revest Date: Thu, 27 Apr 2023 16:32:07 +0200 Subject: selftests/bpf: Update the aarch64 tests deny list Now that ftrace supports direct call on arm64, BPF tracing programs work on that architecture. This fixes the vast majority of BPF selftests except for: - multi_kprobe programs which require fprobe, not available on arm64 yet - tracing_struct which requires trampoline support to access struct args This patch updates the list of BPF selftests which are known to fail so the BPF CI can validate the tests which pass now. Signed-off-by: Florent Revest Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230427143207.635263-1-revest@chromium.org --- tools/testing/selftests/bpf/DENYLIST.aarch64 | 81 ++-------------------------- 1 file changed, 4 insertions(+), 77 deletions(-) diff --git a/tools/testing/selftests/bpf/DENYLIST.aarch64 b/tools/testing/selftests/bpf/DENYLIST.aarch64 index 0a6837f97c32..4b6b18424140 100644 --- a/tools/testing/selftests/bpf/DENYLIST.aarch64 +++ b/tools/testing/selftests/bpf/DENYLIST.aarch64 @@ -1,33 +1,5 @@ -bloom_filter_map # libbpf: prog 'check_bloom': failed to attach: ERROR: strerror_r(-524)=22 -bpf_cookie/lsm -bpf_cookie/multi_kprobe_attach_api -bpf_cookie/multi_kprobe_link_api -bpf_cookie/trampoline -bpf_loop/check_callback_fn_stop # link unexpected error: -524 -bpf_loop/check_invalid_flags -bpf_loop/check_nested_calls -bpf_loop/check_non_constant_callback -bpf_loop/check_nr_loops -bpf_loop/check_null_callback_ctx -bpf_loop/check_stack -bpf_mod_race # bpf_mod_kfunc_race__attach unexpected error: -524 (errno 524) -bpf_tcp_ca/dctcp_fallback -btf_dump/btf_dump: var_data # find type id unexpected find type id: actual -2 < expected 0 -cgroup_hierarchical_stats # attach unexpected error: -524 (errno 524) -d_path/basic # setup attach failed: -524 -deny_namespace # attach unexpected error: -524 (errno 524) -fentry_fexit # fentry_attach unexpected error: -1 (errno 524) -fentry_test # fentry_attach unexpected error: -1 (errno 524) -fexit_sleep # fexit_attach fexit attach failed: -1 -fexit_stress # fexit attach unexpected fexit attach: actual -524 < expected 0 -fexit_test # fexit_attach unexpected error: -1 (errno 524) -get_func_args_test # get_func_args_test__attach unexpected error: -524 (errno 524) (trampoline) -get_func_ip_test # get_func_ip_test__attach unexpected error: -524 (errno 524) (trampoline) -htab_update/reenter_update -kfree_skb # attach fentry unexpected error: -524 (trampoline) -kfunc_call/subprog # extern (var ksym) 'bpf_prog_active': not found in kernel BTF -kfunc_call/subprog_lskel # skel unexpected error: -2 -kfunc_dynptr_param/dynptr_data_null # libbpf: prog 'dynptr_data_null': failed to attach: ERROR: strerror_r(-524)=22 +bpf_cookie/multi_kprobe_attach_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 +bpf_cookie/multi_kprobe_link_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 kprobe_multi_bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/attach_api_addrs # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/attach_api_pattern # bpf_program__attach_kprobe_multi_opts unexpected error: -95 @@ -35,51 +7,6 @@ kprobe_multi_test/attach_api_syms # bpf_program__attach_kprobe_mu kprobe_multi_test/bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/link_api_addrs # link_fd unexpected link_fd: actual -95 < expected 0 kprobe_multi_test/link_api_syms # link_fd unexpected link_fd: actual -95 < expected 0 -kprobe_multi_test/skel_api # kprobe_multi__attach unexpected error: -524 (errno 524) -ksyms_module/libbpf # 'bpf_testmod_ksym_percpu': not found in kernel BTF -ksyms_module/lskel # test_ksyms_module_lskel__open_and_load unexpected error: -2 -libbpf_get_fd_by_id_opts # test_libbpf_get_fd_by_id_opts__attach unexpected error: -524 (errno 524) -linked_list -lookup_key # test_lookup_key__attach unexpected error: -524 (errno 524) -lru_bug # lru_bug__attach unexpected error: -524 (errno 524) -modify_return # modify_return__attach failed unexpected error: -524 (errno 524) -module_attach # skel_attach skeleton attach failed: -524 -module_fentry_shadow # bpf_link_create unexpected bpf_link_create: actual -524 < expected 0 -mptcp/base # run_test mptcp unexpected error: -524 (errno 524) -netcnt # packets unexpected packets: actual 10001 != expected 10000 -rcu_read_lock # failed to attach: ERROR: strerror_r(-524)=22 -recursion # skel_attach unexpected error: -524 (errno 524) -ringbuf # skel_attach skeleton attachment failed: -1 -setget_sockopt # attach_cgroup unexpected error: -524 -sk_storage_tracing # test_sk_storage_tracing__attach unexpected error: -524 (errno 524) -skc_to_unix_sock # could not attach BPF object unexpected error: -524 (errno 524) -socket_cookie # prog_attach unexpected error: -524 -stacktrace_build_id # compare_stack_ips stackmap vs. stack_amap err -1 errno 2 -task_local_storage/exit_creds # skel_attach unexpected error: -524 (errno 524) -task_local_storage/recursion # skel_attach unexpected error: -524 (errno 524) -test_bprm_opts # attach attach failed: -524 -test_ima # attach attach failed: -524 -test_local_storage # attach lsm attach failed: -524 -test_lsm # test_lsm_first_attach unexpected error: -524 (errno 524) -test_overhead # attach_fentry unexpected error: -524 -timer # timer unexpected error: -524 (errno 524) -timer_crash # timer_crash__attach unexpected error: -524 (errno 524) -timer_mim # timer_mim unexpected error: -524 (errno 524) -trace_printk # trace_printk__attach unexpected error: -1 (errno 524) -trace_vprintk # trace_vprintk__attach unexpected error: -1 (errno 524) +kprobe_multi_test/skel_api # libbpf: failed to load BPF skeleton 'kprobe_multi': -3 +module_attach # prog 'kprobe_multi': failed to auto-attach: -95 tracing_struct # tracing_struct__attach unexpected error: -524 (errno 524) -trampoline_count # attach_prog unexpected error: -524 -unpriv_bpf_disabled # skel_attach unexpected error: -524 (errno 524) -user_ringbuf/test_user_ringbuf_post_misaligned # misaligned_skel unexpected error: -524 (errno 524) -user_ringbuf/test_user_ringbuf_post_producer_wrong_offset -user_ringbuf/test_user_ringbuf_post_larger_than_ringbuf_sz -user_ringbuf/test_user_ringbuf_basic # ringbuf_basic_skel unexpected error: -524 (errno 524) -user_ringbuf/test_user_ringbuf_sample_full_ring_buffer -user_ringbuf/test_user_ringbuf_post_alignment_autoadjust -user_ringbuf/test_user_ringbuf_overfill -user_ringbuf/test_user_ringbuf_discards_properly_ignored -user_ringbuf/test_user_ringbuf_loop -user_ringbuf/test_user_ringbuf_msg_protocol -user_ringbuf/test_user_ringbuf_blocking_reserve -verify_pkcs7_sig # test_verify_pkcs7_sig__attach unexpected error: -524 (errno 524) -vmlinux # skel_attach skeleton attach failed: -524 -- cgit v1.2.3 From 6ec7be9a2d2b09815f69fc2183ec31857eaa6e27 Mon Sep 17 00:00:00 2001 From: Kal Conley Date: Sun, 23 Apr 2023 20:01:56 +0200 Subject: xsk: Use pool->dma_pages to check for DMA Compare pool->dma_pages instead of pool->dma_pages_cnt to check for an active DMA mapping. pool->dma_pages needs to be read anyway to access the map so this compiles to more efficient code. Signed-off-by: Kal Conley Signed-off-by: Daniel Borkmann Reviewed-by: Xuan Zhuo Acked-by: Magnus Karlsson Link: https://lore.kernel.org/bpf/20230423180157.93559-1-kal.conley@dectris.com --- include/net/xsk_buff_pool.h | 2 +- net/xdp/xsk_buff_pool.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h index d318c769b445..a8d7b8a3688a 100644 --- a/include/net/xsk_buff_pool.h +++ b/include/net/xsk_buff_pool.h @@ -180,7 +180,7 @@ static inline bool xp_desc_crosses_non_contig_pg(struct xsk_buff_pool *pool, if (likely(!cross_pg)) return false; - return pool->dma_pages_cnt && + return pool->dma_pages && !(pool->dma_pages[addr >> PAGE_SHIFT] & XSK_NEXT_PG_CONTIG_MASK); } diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c index b2df1e0f8153..26f6d304451e 100644 --- a/net/xdp/xsk_buff_pool.c +++ b/net/xdp/xsk_buff_pool.c @@ -350,7 +350,7 @@ void xp_dma_unmap(struct xsk_buff_pool *pool, unsigned long attrs) { struct xsk_dma_map *dma_map; - if (pool->dma_pages_cnt == 0) + if (!pool->dma_pages) return; dma_map = xp_find_dma_map(pool); @@ -364,6 +364,7 @@ void xp_dma_unmap(struct xsk_buff_pool *pool, unsigned long attrs) __xp_dma_unmap(dma_map, attrs); kvfree(pool->dma_pages); + pool->dma_pages = NULL; pool->dma_pages_cnt = 0; pool->dev = NULL; } @@ -503,7 +504,7 @@ static struct xdp_buff_xsk *__xp_alloc(struct xsk_buff_pool *pool) if (pool->unaligned) { xskb = pool->free_heads[--pool->free_heads_cnt]; xp_init_xskb_addr(xskb, pool, addr); - if (pool->dma_pages_cnt) + if (pool->dma_pages) xp_init_xskb_dma(xskb, pool, pool->dma_pages, addr); } else { xskb = &pool->heads[xp_aligned_extract_idx(pool, addr)]; @@ -569,7 +570,7 @@ static u32 xp_alloc_new_from_fq(struct xsk_buff_pool *pool, struct xdp_buff **xd if (pool->unaligned) { xskb = pool->free_heads[--pool->free_heads_cnt]; xp_init_xskb_addr(xskb, pool, addr); - if (pool->dma_pages_cnt) + if (pool->dma_pages) xp_init_xskb_dma(xskb, pool, pool->dma_pages, addr); } else { xskb = &pool->heads[xp_aligned_extract_idx(pool, addr)]; -- cgit v1.2.3 From bf06c9393493a2862d4670beda2928423c774ff3 Mon Sep 17 00:00:00 2001 From: Xueming Feng Date: Thu, 27 Apr 2023 20:03:13 +0800 Subject: bpftool: Dump map id instead of value for map_of_maps types When using `bpftool map dump` with map_of_maps, it is usually more convenient to show the inner map id instead of raw value. We are changing the plain print behavior to show inner_map_id instead of hex value, this would help with quick look up of inner map with `bpftool map dump id `. To avoid disrupting scripted behavior, we will add a new `inner_map_id` field to json output instead of replacing value. plain print: ``` $ bpftool map dump id 138 Without Patch: key: fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 27 16 06 00 value: 8b 00 00 00 Found 1 element With Patch: key: fc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 05 27 16 06 00 inner_map_id: 139 Found 1 element ``` json print: ``` $ bpftool -p map dump id 567 Without Patch: [{ "key": ["0xc0","0x00","0x02","0x05","0x27","0x16","0x06","0x00" ], "value": ["0x38","0x02","0x00","0x00" ] } ] With Patch: [{ "key": ["0xc0","0x00","0x02","0x05","0x27","0x16","0x06","0x00" ], "value": ["0x38","0x02","0x00","0x00" ], "inner_map_id": 568 } ] ``` Signed-off-by: Xueming Feng Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230427120313.43574-1-kuro@kuroa.me Signed-off-by: Martin KaFai Lau --- tools/bpf/bpftool/map.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index aaeb8939e137..ae9e822aa3fe 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -139,6 +139,9 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key, print_hex_data_json(key, info->key_size); jsonw_name(json_wtr, "value"); print_hex_data_json(value, info->value_size); + if (map_is_map_of_maps(info->type)) + jsonw_uint_field(json_wtr, "inner_map_id", + *(unsigned int *)value); if (btf) { struct btf_dumper d = { .btf = btf, @@ -259,8 +262,13 @@ static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, } if (info->value_size) { - printf("value:%c", break_names ? '\n' : ' '); - fprint_hex(stdout, value, info->value_size, " "); + if (map_is_map_of_maps(info->type)) { + printf("inner_map_id:%c", break_names ? '\n' : ' '); + printf("%u ", *(unsigned int *)value); + } else { + printf("value:%c", break_names ? '\n' : ' '); + fprint_hex(stdout, value, info->value_size, " "); + } } printf("\n"); -- cgit v1.2.3 From f1f5553d91a11663a5761b78e61f70c1db0bbd2f Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 25 Apr 2023 10:47:44 -0700 Subject: selftests/bpf: Fix selftest test_global_funcs/global_func1 failure with latest clang The selftest test_global_funcs/global_func1 failed with the latest clang17. The reason is due to upstream ArgumentPromotionPass ([1]), which may manipulate static function parameters and cause inlining although the funciton is marked as noinline. The original code: static __attribute__ ((noinline)) int f0(int var, struct __sk_buff *skb) { return skb->len; } __attribute__ ((noinline)) int f1(struct __sk_buff *skb) { ... return f0(0, skb) + skb->len; } ... SEC("tc") __failure __msg("combined stack size of 4 calls is 544") int global_func1(struct __sk_buff *skb) { return f0(1, skb) + f1(skb) + f2(2, skb) + f3(3, skb, 4); } After ArgumentPromotionPass, the code is translated to static __attribute__ ((noinline)) int f0(int var, int skb_len) { return skb_len; } __attribute__ ((noinline)) int f1(struct __sk_buff *skb) { ... return f0(0, skb->len) + skb->len; } ... SEC("tc") __failure __msg("combined stack size of 4 calls is 544") int global_func1(struct __sk_buff *skb) { return f0(1, skb->len) + f1(skb) + f2(2, skb) + f3(3, skb, 4); } And later llvm InstCombine phase recognized that f0() simplify returns the value of the second argument and removed f0() completely and the final code looks like: __attribute__ ((noinline)) int f1(struct __sk_buff *skb) { ... return skb->len + skb->len; } ... SEC("tc") __failure __msg("combined stack size of 4 calls is 544") int global_func1(struct __sk_buff *skb) { return skb->len + f1(skb) + f2(2, skb) + f3(3, skb, 4); } If f0() is not inlined, the verification will fail with stack size 544 for a particular callchain. With f0() inlined, the maximum stack size is 512 which is in the limit. Let us add a `asm volatile ("")` in f0() to prevent ArgumentPromotionPass from hoisting the code to its caller, and this fixed the test failure. [1] https://reviews.llvm.org/D148269 Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230425174744.1758515-1-yhs@fb.com --- tools/testing/selftests/bpf/progs/test_global_func1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/test_global_func1.c b/tools/testing/selftests/bpf/progs/test_global_func1.c index b85fc8c423ba..17a9f59bf5f3 100644 --- a/tools/testing/selftests/bpf/progs/test_global_func1.c +++ b/tools/testing/selftests/bpf/progs/test_global_func1.c @@ -10,6 +10,8 @@ static __attribute__ ((noinline)) int f0(int var, struct __sk_buff *skb) { + asm volatile (""); + return skb->len; } -- cgit v1.2.3 From 31f4f810d533e7ed9a835c5f946eceaec015ce10 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 27 Apr 2023 20:37:44 -0700 Subject: selftests/bpf: Add fexit_sleep to DENYLIST.aarch64 It is reported that the fexit_sleep never returns in aarch64. The remaining tests cannot start. Put this test into DENYLIST.aarch64 for now so that other tests can continue to run in the CI. Acked-by: Manu Bretelle Reported-by: Manu Bretelle Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/DENYLIST.aarch64 | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/bpf/DENYLIST.aarch64 b/tools/testing/selftests/bpf/DENYLIST.aarch64 index 4b6b18424140..cd42e2825bd2 100644 --- a/tools/testing/selftests/bpf/DENYLIST.aarch64 +++ b/tools/testing/selftests/bpf/DENYLIST.aarch64 @@ -1,5 +1,6 @@ bpf_cookie/multi_kprobe_attach_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 bpf_cookie/multi_kprobe_link_api # kprobe_multi_link_api_subtest:FAIL:fentry_raw_skel_load unexpected error: -3 +fexit_sleep # The test never returns. The remaining tests cannot start. kprobe_multi_bench_attach # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/attach_api_addrs # bpf_program__attach_kprobe_multi_opts unexpected error: -95 kprobe_multi_test/attach_api_pattern # bpf_program__attach_kprobe_multi_opts unexpected error: -95 -- cgit v1.2.3 From 3e56c80931c7615250fe4bf83f93b57881969266 Mon Sep 17 00:00:00 2001 From: Peter Seiderer Date: Wed, 26 Apr 2023 17:35:00 +0300 Subject: wifi: ath9k: fix AR9003 mac hardware hang check register offset calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix ath9k_hw_verify_hang()/ar9003_hw_detect_mac_hang() register offset calculation (do not overflow the shift for the second register/queues above five, use the register layout described in the comments above ath9k_hw_verify_hang() instead). Fixes: 222e04830ff0 ("ath9k: Fix MAC HW hang check for AR9003") Reported-by: Gregg Wonderly Link: https://lore.kernel.org/linux-wireless/E3A9C354-0CB7-420C-ADEF-F0177FB722F4@seqtechllc.com/ Signed-off-by: Peter Seiderer Acked-by: Toke Høiland-Jørgensen Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230422212423.26065-1-ps.report@gmx.net --- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 4f27a9fb1482..e9bd13eeee92 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -1099,17 +1099,22 @@ static bool ath9k_hw_verify_hang(struct ath_hw *ah, unsigned int queue) { u32 dma_dbg_chain, dma_dbg_complete; u8 dcu_chain_state, dcu_complete_state; + unsigned int dbg_reg, reg_offset; int i; - for (i = 0; i < NUM_STATUS_READS; i++) { - if (queue < 6) - dma_dbg_chain = REG_READ(ah, AR_DMADBG_4); - else - dma_dbg_chain = REG_READ(ah, AR_DMADBG_5); + if (queue < 6) { + dbg_reg = AR_DMADBG_4; + reg_offset = queue * 5; + } else { + dbg_reg = AR_DMADBG_5; + reg_offset = (queue - 6) * 5; + } + for (i = 0; i < NUM_STATUS_READS; i++) { + dma_dbg_chain = REG_READ(ah, dbg_reg); dma_dbg_complete = REG_READ(ah, AR_DMADBG_6); - dcu_chain_state = (dma_dbg_chain >> (5 * queue)) & 0x1f; + dcu_chain_state = (dma_dbg_chain >> reg_offset) & 0x1f; dcu_complete_state = dma_dbg_complete & 0x3; if ((dcu_chain_state != 0x6) || (dcu_complete_state != 0x1)) @@ -1128,6 +1133,7 @@ static bool ar9003_hw_detect_mac_hang(struct ath_hw *ah) u8 dcu_chain_state, dcu_complete_state; bool dcu_wait_frdone = false; unsigned long chk_dcu = 0; + unsigned int reg_offset; unsigned int i = 0; dma_dbg_4 = REG_READ(ah, AR_DMADBG_4); @@ -1139,12 +1145,15 @@ static bool ar9003_hw_detect_mac_hang(struct ath_hw *ah) goto exit; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (i < 6) + if (i < 6) { chk_dbg = dma_dbg_4; - else + reg_offset = i * 5; + } else { chk_dbg = dma_dbg_5; + reg_offset = (i - 6) * 5; + } - dcu_chain_state = (chk_dbg >> (5 * i)) & 0x1f; + dcu_chain_state = (chk_dbg >> reg_offset) & 0x1f; if (dcu_chain_state == 0x6) { dcu_wait_frdone = true; chk_dcu |= BIT(i); -- cgit v1.2.3 From f24292e827088bba8de7158501ac25a59b064953 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Wed, 26 Apr 2023 17:35:01 +0300 Subject: wifi: ath9k: avoid referencing uninit memory in ath9k_wmi_ctrl_rx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the reasons also described in commit b383e8abed41 ("wifi: ath9k: avoid uninit memory read in ath9k_htc_rx_msg()"), ath9k_htc_rx_msg() should validate pkt_len before accessing the SKB. For example, the obtained SKB may have been badly constructed with pkt_len = 8. In this case, the SKB can only contain a valid htc_frame_hdr but after being processed in ath9k_htc_rx_msg() and passed to ath9k_wmi_ctrl_rx() endpoint RX handler, it is expected to have a WMI command header which should be located inside its data payload. Implement sanity checking inside ath9k_wmi_ctrl_rx(). Otherwise, uninit memory can be referenced. Tested on Qualcomm Atheros Communications AR9271 802.11n . Found by Linux Verification Center (linuxtesting.org) with Syzkaller. Fixes: fb9987d0f748 ("ath9k_htc: Support for AR9271 chipset.") Reported-and-tested-by: syzbot+f2cb6e0ffdb961921e4d@syzkaller.appspotmail.com Signed-off-by: Fedor Pchelkin Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230424183348.111355-1-pchelkin@ispras.ru --- drivers/net/wireless/ath/ath9k/wmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 19345b8f7bfd..d652c647d56b 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -221,6 +221,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb, if (unlikely(wmi->stopped)) goto free_skb; + /* Validate the obtained SKB. */ + if (unlikely(skb->len < sizeof(struct wmi_cmd_hdr))) + goto free_skb; + hdr = (struct wmi_cmd_hdr *) skb->data; cmd_id = be16_to_cpu(hdr->command_id); -- cgit v1.2.3 From 33f83a23f4cccc3a30cc41aa0e01b66900001052 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 25 Apr 2023 13:57:19 +0200 Subject: wifi: ath12k: Remove some dead code ATH12K_HE_MCS_MAX = 11, so this test and the following one are the same. Remove the one with the hard coded 11 value. Signed-off-by: Christophe JAILLET Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/c17edf0811156a33bae6c5cf1906d751cc87edd4.1682423828.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/ath/ath12k/dp_rx.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index c7bf4f7fa99e..8c8162fbe5c6 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -1374,11 +1374,6 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, * Firmware rate's control to be skipped for this? */ - if (flags == WMI_RATE_PREAMBLE_HE && mcs > 11) { - ath12k_warn(ab, "Invalid HE mcs %d peer stats", mcs); - return; - } - if (flags == WMI_RATE_PREAMBLE_HE && mcs > ATH12K_HE_MCS_MAX) { ath12k_warn(ab, "Invalid HE mcs %d peer stats", mcs); return; -- cgit v1.2.3 From e2ceb1de2f83aafd8003f0b72dfd4b7441e97d14 Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Fri, 21 Apr 2023 16:54:45 +0200 Subject: wifi: ath11k: fix registration of 6Ghz-only phy without the full channel range Because of what seems to be a typo, a 6Ghz-only phy for which the BDF does not allow the 7115Mhz channel will fail to register: WARNING: CPU: 2 PID: 106 at net/wireless/core.c:907 wiphy_register+0x914/0x954 Modules linked in: ath11k_pci sbsa_gwdt CPU: 2 PID: 106 Comm: kworker/u8:5 Not tainted 6.3.0-rc7-next-20230418-00549-g1e096a17625a-dirty #9 Hardware name: Freebox V7R Board (DT) Workqueue: ath11k_qmi_driver_event ath11k_qmi_driver_event_work pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : wiphy_register+0x914/0x954 lr : ieee80211_register_hw+0x67c/0xc10 sp : ffffff800b123aa0 x29: ffffff800b123aa0 x28: 0000000000000000 x27: 0000000000000000 x26: 0000000000000000 x25: 0000000000000006 x24: ffffffc008d51418 x23: ffffffc008cb0838 x22: ffffff80176c2460 x21: 0000000000000168 x20: ffffff80176c0000 x19: ffffff80176c03e0 x18: 0000000000000014 x17: 00000000cbef338c x16: 00000000d2a26f21 x15: 00000000ad6bb85f x14: 0000000000000020 x13: 0000000000000020 x12: 00000000ffffffbd x11: 0000000000000208 x10: 00000000fffffdf7 x9 : ffffffc009394718 x8 : ffffff80176c0528 x7 : 000000007fffffff x6 : 0000000000000006 x5 : 0000000000000005 x4 : ffffff800b304284 x3 : ffffff800b304284 x2 : ffffff800b304d98 x1 : 0000000000000000 x0 : 0000000000000000 Call trace: wiphy_register+0x914/0x954 ieee80211_register_hw+0x67c/0xc10 ath11k_mac_register+0x7c4/0xe10 ath11k_core_qmi_firmware_ready+0x1f4/0x570 ath11k_qmi_driver_event_work+0x198/0x590 process_one_work+0x1b8/0x328 worker_thread+0x6c/0x414 kthread+0x100/0x104 ret_from_fork+0x10/0x20 ---[ end trace 0000000000000000 ]--- ath11k_pci 0002:01:00.0: ieee80211 registration failed: -22 ath11k_pci 0002:01:00.0: failed register the radio with mac80211: -22 ath11k_pci 0002:01:00.0: failed to create pdev core: -22 Signed-off-by: Maxime Bizon Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421145445.2612280-1-mbizon@freebox.fr --- drivers/net/wireless/ath/ath11k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 1c93f1afccc5..05920ad413c5 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -8892,7 +8892,7 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, } if (supported_bands & WMI_HOST_WLAN_5G_CAP) { - if (reg_cap->high_5ghz_chan >= ATH11K_MAX_6G_FREQ) { + if (reg_cap->high_5ghz_chan >= ATH11K_MIN_6G_FREQ) { channels = kmemdup(ath11k_6ghz_channels, sizeof(ath11k_6ghz_channels), GFP_KERNEL); if (!channels) { -- cgit v1.2.3 From c39028b333f3a3a765c5c0b9726b8e38aedf0ba1 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 27 Apr 2023 18:36:38 -0700 Subject: libbpf: btf_dump_type_data_check_overflow needs to consider BTF_MEMBER_BITFIELD_SIZE The btf_dump/struct_data selftest is failing with: [...] test_btf_dump_struct_data:FAIL:unexpected return value dumping fs_context unexpected unexpected return value dumping fs_context: actual -7 != expected 264 [...] The reason is in btf_dump_type_data_check_overflow(). It does not use BTF_MEMBER_BITFIELD_SIZE from the struct's member (btf_member). Instead, it is using the enum size which is 4. It had been working till the recent commit 4e04143c869c ("fs_context: drop the unused lsm_flags member") removed an integer member which also removed the 4 bytes padding at the end of the fs_context. Missing this 4 bytes padding exposed this bug. In particular, when btf_dump_type_data_check_overflow() reaches the member 'phase', -E2BIG is returned. The fix is to pass bit_sz to btf_dump_type_data_check_overflow(). In btf_dump_type_data_check_overflow(), it does a different size check when bit_sz is not zero. The current fs_context: [3600] ENUM 'fs_context_purpose' encoding=UNSIGNED size=4 vlen=3 'FS_CONTEXT_FOR_MOUNT' val=0 'FS_CONTEXT_FOR_SUBMOUNT' val=1 'FS_CONTEXT_FOR_RECONFIGURE' val=2 [3601] ENUM 'fs_context_phase' encoding=UNSIGNED size=4 vlen=7 'FS_CONTEXT_CREATE_PARAMS' val=0 'FS_CONTEXT_CREATING' val=1 'FS_CONTEXT_AWAITING_MOUNT' val=2 'FS_CONTEXT_AWAITING_RECONF' val=3 'FS_CONTEXT_RECONF_PARAMS' val=4 'FS_CONTEXT_RECONFIGURING' val=5 'FS_CONTEXT_FAILED' val=6 [3602] STRUCT 'fs_context' size=264 vlen=21 'ops' type_id=3603 bits_offset=0 'uapi_mutex' type_id=235 bits_offset=64 'fs_type' type_id=872 bits_offset=1216 'fs_private' type_id=21 bits_offset=1280 'sget_key' type_id=21 bits_offset=1344 'root' type_id=781 bits_offset=1408 'user_ns' type_id=251 bits_offset=1472 'net_ns' type_id=984 bits_offset=1536 'cred' type_id=1785 bits_offset=1600 'log' type_id=3621 bits_offset=1664 'source' type_id=42 bits_offset=1792 'security' type_id=21 bits_offset=1856 's_fs_info' type_id=21 bits_offset=1920 'sb_flags' type_id=20 bits_offset=1984 'sb_flags_mask' type_id=20 bits_offset=2016 's_iflags' type_id=20 bits_offset=2048 'purpose' type_id=3600 bits_offset=2080 bitfield_size=8 'phase' type_id=3601 bits_offset=2088 bitfield_size=8 'need_free' type_id=67 bits_offset=2096 bitfield_size=1 'global' type_id=67 bits_offset=2097 bitfield_size=1 'oldapi' type_id=67 bits_offset=2098 bitfield_size=1 Fixes: 920d16af9b42 ("libbpf: BTF dumper support for typed data") Signed-off-by: Martin KaFai Lau Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230428013638.1581263-1-martin.lau@linux.dev --- tools/lib/bpf/btf_dump.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index 580985ee5545..4d9f30bf7f01 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -2250,9 +2250,25 @@ static int btf_dump_type_data_check_overflow(struct btf_dump *d, const struct btf_type *t, __u32 id, const void *data, - __u8 bits_offset) + __u8 bits_offset, + __u8 bit_sz) { - __s64 size = btf__resolve_size(d->btf, id); + __s64 size; + + if (bit_sz) { + /* bits_offset is at most 7. bit_sz is at most 128. */ + __u8 nr_bytes = (bits_offset + bit_sz + 7) / 8; + + /* When bit_sz is non zero, it is called from + * btf_dump_struct_data() where it only cares about + * negative error value. + * Return nr_bytes in success case to make it + * consistent as the regular integer case below. + */ + return data + nr_bytes > d->typed_dump->data_end ? -E2BIG : nr_bytes; + } + + size = btf__resolve_size(d->btf, id); if (size < 0 || size >= INT_MAX) { pr_warn("unexpected size [%zu] for id [%u]\n", @@ -2407,7 +2423,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d, { int size, err = 0; - size = btf_dump_type_data_check_overflow(d, t, id, data, bits_offset); + size = btf_dump_type_data_check_overflow(d, t, id, data, bits_offset, bit_sz); if (size < 0) return size; err = btf_dump_type_data_check_zero(d, t, id, data, bits_offset, bit_sz); -- cgit v1.2.3 From 0a5c0de8b66f9789422f04de7304e374a2ea8df5 Mon Sep 17 00:00:00 2001 From: Stephen Veiss Date: Thu, 27 Apr 2023 15:53:32 -0700 Subject: selftests/bpf: Extract insert_test from parse_test_list Split the logic to insert new tests into test filter sets out from parse_test_list. Fix the subtest insertion logic to reuse an existing top-level test filter, which prevents the creation of duplicate top-level test filters each with a single subtest. Signed-off-by: Stephen Veiss Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230427225333.3506052-2-sveiss@meta.com --- .../testing/selftests/bpf/prog_tests/arg_parsing.c | 13 ++ tools/testing/selftests/bpf/testing_helpers.c | 160 ++++++++++++--------- 2 files changed, 108 insertions(+), 65 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c index b17bfa0e0aac..3754cd5f8c0a 100644 --- a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c +++ b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c @@ -96,6 +96,19 @@ static void test_parse_test_list(void) goto error; ASSERT_OK(strcmp("*bpf_cookie*", set.tests[0].name), "test name"); ASSERT_OK(strcmp("*trace*", set.tests[0].subtests[0]), "subtest name"); + free_test_filter_set(&set); + + ASSERT_OK(parse_test_list("t/subtest1,t/subtest2", &set, true), + "parsing"); + if (!ASSERT_EQ(set.cnt, 1, "count of test filters")) + goto error; + if (!ASSERT_OK_PTR(set.tests, "test filters initialized")) + goto error; + if (!ASSERT_EQ(set.tests[0].subtest_cnt, 2, "subtest filters count")) + goto error; + ASSERT_OK(strcmp("t", set.tests[0].name), "test name"); + ASSERT_OK(strcmp("subtest1", set.tests[0].subtests[0]), "subtest name"); + ASSERT_OK(strcmp("subtest2", set.tests[0].subtests[1]), "subtest name"); error: free_test_filter_set(&set); } diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 0b5e0829e5be..fca617e87710 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -70,92 +70,122 @@ int parse_num_list(const char *s, bool **num_set, int *num_set_len) return 0; } -int parse_test_list(const char *s, - struct test_filter_set *set, - bool is_glob_pattern) +static int do_insert_test(struct test_filter_set *set, + char *test_str, + char *subtest_str) { - char *input, *state = NULL, *next; - struct test_filter *tmp, *tests = NULL; - int i, j, cnt = 0; + struct test_filter *tmp, *test; + char **ctmp; + int i; - input = strdup(s); - if (!input) + for (i = 0; i < set->cnt; i++) { + test = &set->tests[i]; + + if (strcmp(test_str, test->name) == 0) { + free(test_str); + goto subtest; + } + } + + tmp = realloc(set->tests, sizeof(*test) * (set->cnt + 1)); + if (!tmp) return -ENOMEM; - while ((next = strtok_r(state ? NULL : input, ",", &state))) { - char *subtest_str = strchr(next, '/'); - char *pattern = NULL; - int glob_chars = 0; + set->tests = tmp; + test = &set->tests[set->cnt]; - tmp = realloc(tests, sizeof(*tests) * (cnt + 1)); - if (!tmp) - goto err; - tests = tmp; + test->name = test_str; + test->subtests = NULL; + test->subtest_cnt = 0; - tests[cnt].subtest_cnt = 0; - tests[cnt].subtests = NULL; + set->cnt++; - if (is_glob_pattern) { - pattern = "%s"; - } else { - pattern = "*%s*"; - glob_chars = 2; - } +subtest: + if (!subtest_str) + return 0; - if (subtest_str) { - char **tmp_subtests = NULL; - int subtest_cnt = tests[cnt].subtest_cnt; - - *subtest_str = '\0'; - subtest_str += 1; - tmp_subtests = realloc(tests[cnt].subtests, - sizeof(*tmp_subtests) * - (subtest_cnt + 1)); - if (!tmp_subtests) - goto err; - tests[cnt].subtests = tmp_subtests; - - tests[cnt].subtests[subtest_cnt] = - malloc(strlen(subtest_str) + glob_chars + 1); - if (!tests[cnt].subtests[subtest_cnt]) - goto err; - sprintf(tests[cnt].subtests[subtest_cnt], - pattern, - subtest_str); - - tests[cnt].subtest_cnt++; + for (i = 0; i < test->subtest_cnt; i++) { + if (strcmp(subtest_str, test->subtests[i]) == 0) { + free(subtest_str); + return 0; } + } - tests[cnt].name = malloc(strlen(next) + glob_chars + 1); - if (!tests[cnt].name) - goto err; - sprintf(tests[cnt].name, pattern, next); + ctmp = realloc(test->subtests, + sizeof(*test->subtests) * (test->subtest_cnt + 1)); + if (!ctmp) + return -ENOMEM; + + test->subtests = ctmp; + test->subtests[test->subtest_cnt] = subtest_str; - cnt++; + test->subtest_cnt++; + + return 0; +} + +static int insert_test(struct test_filter_set *set, + char *test_spec, + bool is_glob_pattern) +{ + char *pattern, *subtest_str, *ext_test_str, *ext_subtest_str = NULL; + int glob_chars = 0; + + if (is_glob_pattern) { + pattern = "%s"; + } else { + pattern = "*%s*"; + glob_chars = 2; } - tmp = realloc(set->tests, sizeof(*tests) * (cnt + set->cnt)); - if (!tmp) + subtest_str = strchr(test_spec, '/'); + if (subtest_str) { + *subtest_str = '\0'; + subtest_str += 1; + } + + ext_test_str = malloc(strlen(test_spec) + glob_chars + 1); + if (!ext_test_str) goto err; - memcpy(tmp + set->cnt, tests, sizeof(*tests) * cnt); - set->tests = tmp; - set->cnt += cnt; + sprintf(ext_test_str, pattern, test_spec); - free(tests); - free(input); - return 0; + if (subtest_str) { + ext_subtest_str = malloc(strlen(subtest_str) + glob_chars + 1); + if (!ext_subtest_str) + goto err; + + sprintf(ext_subtest_str, pattern, subtest_str); + } + + return do_insert_test(set, ext_test_str, ext_subtest_str); err: - for (i = 0; i < cnt; i++) { - for (j = 0; j < tests[i].subtest_cnt; j++) - free(tests[i].subtests[j]); + free(ext_test_str); + free(ext_subtest_str); + + return -ENOMEM; +} - free(tests[i].name); +int parse_test_list(const char *s, + struct test_filter_set *set, + bool is_glob_pattern) +{ + char *input, *state = NULL, *test_spec; + int err = 0; + + input = strdup(s); + if (!input) + return -ENOMEM; + + while ((test_spec = strtok_r(state ? NULL : input, ",", &state))) { + err = insert_test(set, test_spec, is_glob_pattern); + if (err) + break; } - free(tests); + free(input); - return -ENOMEM; + return err; } __u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info) -- cgit v1.2.3 From 64276f01dce85f72853617e513622b5645497d81 Mon Sep 17 00:00:00 2001 From: Stephen Veiss Date: Thu, 27 Apr 2023 15:53:33 -0700 Subject: selftests/bpf: Test_progs can read test lists from file Improve test selection logic when using -a/-b/-d/-t options. The list of tests to include or exclude can now be read from a file, specified as @. The file contains one name (or wildcard pattern) per line, and comments beginning with # are ignored. These options can be passed multiple times to read more than one file. Signed-off-by: Stephen Veiss Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230427225333.3506052-3-sveiss@meta.com --- .../testing/selftests/bpf/prog_tests/arg_parsing.c | 55 ++++++++++++++++++++++ tools/testing/selftests/bpf/test_progs.c | 37 +++++++++++---- tools/testing/selftests/bpf/testing_helpers.c | 47 ++++++++++++++++++ tools/testing/selftests/bpf/testing_helpers.h | 3 ++ 4 files changed, 132 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c index 3754cd5f8c0a..bb143de68875 100644 --- a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c +++ b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c @@ -113,8 +113,63 @@ error: free_test_filter_set(&set); } +static void test_parse_test_list_file(void) +{ + struct test_filter_set set; + char tmpfile[80]; + FILE *fp; + int fd; + + snprintf(tmpfile, sizeof(tmpfile), "/tmp/bpf_arg_parsing_test.XXXXXX"); + fd = mkstemp(tmpfile); + if (!ASSERT_GE(fd, 0, "create tmp")) + return; + + fp = fdopen(fd, "w"); + if (!ASSERT_NEQ(fp, NULL, "fdopen tmp")) { + close(fd); + goto out_remove; + } + + fprintf(fp, "# comment\n"); + fprintf(fp, " test_with_spaces \n"); + fprintf(fp, "testA/subtest # comment\n"); + fprintf(fp, "testB#comment with no space\n"); + fprintf(fp, "testB # duplicate\n"); + fprintf(fp, "testA/subtest # subtest duplicate\n"); + fprintf(fp, "testA/subtest2\n"); + fprintf(fp, "testC_no_eof_newline"); + fflush(fp); + + if (!ASSERT_OK(ferror(fp), "prepare tmp")) + goto out_fclose; + + init_test_filter_set(&set); + + ASSERT_OK(parse_test_list_file(tmpfile, &set, true), "parse file"); + + ASSERT_EQ(set.cnt, 4, "test count"); + ASSERT_OK(strcmp("test_with_spaces", set.tests[0].name), "test 0 name"); + ASSERT_EQ(set.tests[0].subtest_cnt, 0, "test 0 subtest count"); + ASSERT_OK(strcmp("testA", set.tests[1].name), "test 1 name"); + ASSERT_EQ(set.tests[1].subtest_cnt, 2, "test 1 subtest count"); + ASSERT_OK(strcmp("subtest", set.tests[1].subtests[0]), "test 1 subtest 0"); + ASSERT_OK(strcmp("subtest2", set.tests[1].subtests[1]), "test 1 subtest 1"); + ASSERT_OK(strcmp("testB", set.tests[2].name), "test 2 name"); + ASSERT_OK(strcmp("testC_no_eof_newline", set.tests[3].name), "test 3 name"); + + free_test_filter_set(&set); + +out_fclose: + fclose(fp); +out_remove: + remove(tmpfile); +} + void test_arg_parsing(void) { if (test__start_subtest("test_parse_test_list")) test_parse_test_list(); + if (test__start_subtest("test_parse_test_list_file")) + test_parse_test_list_file(); } diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index ea82921110da..793689dcc170 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -714,7 +714,13 @@ static struct test_state test_states[ARRAY_SIZE(prog_test_defs)]; const char *argp_program_version = "test_progs 0.1"; const char *argp_program_bug_address = ""; -static const char argp_program_doc[] = "BPF selftests test runner"; +static const char argp_program_doc[] = +"BPF selftests test runner\v" +"Options accepting the NAMES parameter take either a comma-separated list\n" +"of test names, or a filename prefixed with @. The file contains one name\n" +"(or wildcard pattern) per line, and comments beginning with # are ignored.\n" +"\n" +"These options can be passed repeatedly to read multiple files.\n"; enum ARG_KEYS { ARG_TEST_NUM = 'n', @@ -797,6 +803,7 @@ extern int extra_prog_load_log_flags; static error_t parse_arg(int key, char *arg, struct argp_state *state) { struct test_env *env = state->input; + int err = 0; switch (key) { case ARG_TEST_NUM: { @@ -821,18 +828,28 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) } case ARG_TEST_NAME_GLOB_ALLOWLIST: case ARG_TEST_NAME: { - if (parse_test_list(arg, - &env->test_selector.whitelist, - key == ARG_TEST_NAME_GLOB_ALLOWLIST)) - return -ENOMEM; + if (arg[0] == '@') + err = parse_test_list_file(arg + 1, + &env->test_selector.whitelist, + key == ARG_TEST_NAME_GLOB_ALLOWLIST); + else + err = parse_test_list(arg, + &env->test_selector.whitelist, + key == ARG_TEST_NAME_GLOB_ALLOWLIST); + break; } case ARG_TEST_NAME_GLOB_DENYLIST: case ARG_TEST_NAME_BLACKLIST: { - if (parse_test_list(arg, - &env->test_selector.blacklist, - key == ARG_TEST_NAME_GLOB_DENYLIST)) - return -ENOMEM; + if (arg[0] == '@') + err = parse_test_list_file(arg + 1, + &env->test_selector.blacklist, + key == ARG_TEST_NAME_GLOB_DENYLIST); + else + err = parse_test_list(arg, + &env->test_selector.blacklist, + key == ARG_TEST_NAME_GLOB_DENYLIST); + break; } case ARG_VERIFIER_STATS: @@ -900,7 +917,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) default: return ARGP_ERR_UNKNOWN; } - return 0; + return err; } /* diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index fca617e87710..dc9595ade8de 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* Copyright (C) 2019 Netronome Systems, Inc. */ /* Copyright (C) 2020 Facebook, Inc. */ +#include #include #include #include @@ -167,6 +168,52 @@ err: return -ENOMEM; } +int parse_test_list_file(const char *path, + struct test_filter_set *set, + bool is_glob_pattern) +{ + char *buf = NULL, *capture_start, *capture_end, *scan_end; + size_t buflen = 0; + int err = 0; + FILE *f; + + f = fopen(path, "r"); + if (!f) { + err = -errno; + fprintf(stderr, "Failed to open '%s': %d\n", path, err); + return err; + } + + while (getline(&buf, &buflen, f) != -1) { + capture_start = buf; + + while (isspace(*capture_start)) + ++capture_start; + + capture_end = capture_start; + scan_end = capture_start; + + while (*scan_end && *scan_end != '#') { + if (!isspace(*scan_end)) + capture_end = scan_end; + + ++scan_end; + } + + if (capture_end == capture_start) + continue; + + *(++capture_end) = '\0'; + + err = insert_test(set, capture_start, is_glob_pattern); + if (err) + break; + } + + fclose(f); + return err; +} + int parse_test_list(const char *s, struct test_filter_set *set, bool is_glob_pattern) diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index eb8790f928e4..98f09bbae86f 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -20,5 +20,8 @@ struct test_filter_set; int parse_test_list(const char *s, struct test_filter_set *test_set, bool is_glob_pattern); +int parse_test_list_file(const char *path, + struct test_filter_set *test_set, + bool is_glob_pattern); __u64 read_perf_max_sample_freq(void); -- cgit v1.2.3 From bf6882aebd0ea67558764d44ddeffc7d253c6eb8 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 2 May 2023 11:05:43 -0700 Subject: bpf: Emit struct bpf_tcp_sock type in vmlinux BTF In one of our internal testing, we found a case where - uapi struct bpf_tcp_sock is in vmlinux.h where vmlinux.h is not generated from the testing kernel - struct bpf_tcp_sock is not in vmlinux BTF The above combination caused bpf load failure as the following memory access struct bpf_tcp_sock *tcp_sock = ...; ... tcp_sock->snd_cwnd ... needs CORE relocation but the relocation cannot be resolved since the kernel BTF does not have corresponding type. Similar to other previous cases (nf_conn___init, tcp6_sock, mctcp_sock, etc.), add the type to vmlinux BTF with BTF_EMIT_TYPE macro. Signed-off-by: Yonghong Song Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230502180543.1832140-1-yhs@fb.com --- net/core/filter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/filter.c b/net/core/filter.c index d9ce04ca22ce..451b0ec7f242 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -6916,6 +6916,8 @@ u32 bpf_tcp_sock_convert_ctx_access(enum bpf_access_type type, FIELD)); \ } while (0) + BTF_TYPE_EMIT(struct bpf_tcp_sock); + switch (si->off) { case offsetof(struct bpf_tcp_sock, rtt_min): BUILD_BUG_ON(sizeof_field(struct tcp_sock, rtt_min) != -- cgit v1.2.3 From fedf99200ab086c42a572fca1d7266b06cdc3e3f Mon Sep 17 00:00:00 2001 From: Kui-Feng Lee Date: Tue, 2 May 2023 11:14:18 -0700 Subject: bpf: Print a warning only if writing to unprivileged_bpf_disabled. Only print the warning message if you are writing to "/proc/sys/kernel/unprivileged_bpf_disabled". The kernel may print an annoying warning when you read "/proc/sys/kernel/unprivileged_bpf_disabled" saying WARNING: Unprivileged eBPF is enabled with eIBRS on, data leaks possible via Spectre v2 BHB attacks! However, this message is only meaningful when the feature is disabled or enabled. Signed-off-by: Kui-Feng Lee Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230502181418.308479-1-kuifeng@meta.com --- kernel/bpf/syscall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 14f39c1e573e..909c112ef537 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -5380,7 +5380,8 @@ static int bpf_unpriv_handler(struct ctl_table *table, int write, *(int *)table->data = unpriv_enable; } - unpriv_ebpf_notify(unpriv_enable); + if (write) + unpriv_ebpf_notify(unpriv_enable); return ret; } -- cgit v1.2.3 From 7866fc6aa0deb2294eb781fc3ac94b7d4c6eb242 Mon Sep 17 00:00:00 2001 From: Kenjiro Nakayama Date: Thu, 4 May 2023 12:54:43 +0900 Subject: libbpf: Fix comment about arc and riscv arch in bpf_tracing.h To make comments about arc and riscv arch in bpf_tracing.h accurate, this patch fixes the comment about arc and adds the comment for riscv. Signed-off-by: Kenjiro Nakayama Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230504035443.427927-1-nakayamakenjiro@gmail.com --- tools/lib/bpf/bpf_tracing.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/bpf_tracing.h b/tools/lib/bpf/bpf_tracing.h index 6fb3d0f9af17..be076a4041ab 100644 --- a/tools/lib/bpf/bpf_tracing.h +++ b/tools/lib/bpf/bpf_tracing.h @@ -351,6 +351,7 @@ struct pt_regs___arm64 { * https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#risc-v-calling-conventions */ +/* riscv provides struct user_regs_struct instead of struct pt_regs to userspace */ #define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x)) #define __PT_PARM1_REG a0 #define __PT_PARM2_REG a1 @@ -383,7 +384,7 @@ struct pt_regs___arm64 { * https://raw.githubusercontent.com/wiki/foss-for-synopsys-dwc-arc-processors/toolchain/files/ARCv2_ABI.pdf */ -/* arc provides struct user_pt_regs instead of struct pt_regs to userspace */ +/* arc provides struct user_regs_struct instead of struct pt_regs to userspace */ #define __PT_REGS_CAST(x) ((const struct user_regs_struct *)(x)) #define __PT_PARM1_REG scratch.r0 #define __PT_PARM2_REG scratch.r1 -- cgit v1.2.3 From 5956f3011604f03be073cba0fbe5f399b4d779ec Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:08 -0700 Subject: veristat: add -t flag for adding BPF_F_TEST_STATE_FREQ program flag Sometimes during debugging it's important that BPF program is loaded with BPF_F_TEST_STATE_FREQ flag set to force verifier to do frequent state checkpointing. Teach veristat to do this when -t ("test state") flag is specified. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/veristat.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/testing/selftests/bpf/veristat.c b/tools/testing/selftests/bpf/veristat.c index 1db7185181da..655095810d4a 100644 --- a/tools/testing/selftests/bpf/veristat.c +++ b/tools/testing/selftests/bpf/veristat.c @@ -141,6 +141,7 @@ static struct env { bool verbose; bool debug; bool quiet; + bool force_checkpoints; enum resfmt out_fmt; bool show_version; bool comparison_mode; @@ -209,6 +210,8 @@ static const struct argp_option opts[] = { { "log-level", 'l', "LEVEL", 0, "Verifier log level (default 0 for normal mode, 1 for verbose mode)" }, { "log-fixed", OPT_LOG_FIXED, NULL, 0, "Disable verifier log rotation" }, { "log-size", OPT_LOG_SIZE, "BYTES", 0, "Customize verifier log size (default to 16MB)" }, + { "test-states", 't', NULL, 0, + "Force frequent BPF verifier state checkpointing (set BPF_F_TEST_STATE_FREQ program flag)" }, { "quiet", 'q', NULL, 0, "Quiet mode" }, { "emit", 'e', "SPEC", 0, "Specify stats to be emitted" }, { "sort", 's', "SPEC", 0, "Specify sort order" }, @@ -284,6 +287,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) argp_usage(state); } break; + case 't': + env.force_checkpoints = true; + break; case 'C': env.comparison_mode = true; break; @@ -989,6 +995,9 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf /* increase chances of successful BPF object loading */ fixup_obj(obj, prog, base_filename); + if (env.force_checkpoints) + bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_STATE_FREQ); + err = bpf_object__load(obj); env.progs_processed++; -- cgit v1.2.3 From e0bf462276b6ee23203365eacb5c599f42a5a084 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:09 -0700 Subject: bpf: mark relevant stack slots scratched for register read instructions When handling instructions that read register slots, mark relevant stack slots as scratched so that verifier log would contain those slots' states, in addition to currently emitted registers with stack slot offsets. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-3-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ff4a8ab99f08..da8a5834f2ca 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4109,6 +4109,7 @@ static void mark_reg_stack_read(struct bpf_verifier_env *env, for (i = min_off; i < max_off; i++) { slot = -i - 1; spi = slot / BPF_REG_SIZE; + mark_stack_slot_scratched(env, spi); stype = ptr_state->stack[spi].slot_type; if (stype[slot % BPF_REG_SIZE] != STACK_ZERO) break; @@ -4160,6 +4161,8 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env, stype = reg_state->stack[spi].slot_type; reg = ®_state->stack[spi].spilled_ptr; + mark_stack_slot_scratched(env, spi); + if (is_spilled_reg(®_state->stack[spi])) { u8 spill_size = 1; -- cgit v1.2.3 From 407958a0e980b9e1842ab87b5a1040521e1e24e9 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:10 -0700 Subject: bpf: encapsulate precision backtracking bookkeeping Add struct backtrack_state and straightforward API around it to keep track of register and stack masks used and maintained during precision backtracking process. Having this logic separately allow to keep high-level backtracking algorithm cleaner, but also it sets us up to cleanly keep track of register and stack masks per frame, allowing (with some further logic adjustments) to perform precision backpropagation across multiple frames (i.e., subprog calls). Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-4-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 14 +++ kernel/bpf/verifier.c | 249 +++++++++++++++++++++++++++++++------------ 2 files changed, 196 insertions(+), 67 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 3dd29a53b711..33f541366f4e 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -238,6 +238,10 @@ enum bpf_stack_slot_type { #define BPF_REG_SIZE 8 /* size of eBPF register in bytes */ +#define BPF_REGMASK_ARGS ((1 << BPF_REG_1) | (1 << BPF_REG_2) | \ + (1 << BPF_REG_3) | (1 << BPF_REG_4) | \ + (1 << BPF_REG_5)) + #define BPF_DYNPTR_SIZE sizeof(struct bpf_dynptr_kern) #define BPF_DYNPTR_NR_SLOTS (BPF_DYNPTR_SIZE / BPF_REG_SIZE) @@ -541,6 +545,15 @@ struct bpf_subprog_info { bool is_async_cb; }; +struct bpf_verifier_env; + +struct backtrack_state { + struct bpf_verifier_env *env; + u32 frame; + u32 reg_masks[MAX_CALL_FRAMES]; + u64 stack_masks[MAX_CALL_FRAMES]; +}; + /* single container for all structs * one verifier_env per bpf_check() call */ @@ -578,6 +591,7 @@ struct bpf_verifier_env { int *insn_stack; int cur_stack; } cfg; + struct backtrack_state bt; u32 pass_cnt; /* number of times do_check() was called */ u32 subprog_cnt; /* number of instructions analyzed by the verifier */ diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index da8a5834f2ca..9b2e571250e1 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1296,6 +1296,12 @@ static bool is_spilled_reg(const struct bpf_stack_state *stack) return stack->slot_type[BPF_REG_SIZE - 1] == STACK_SPILL; } +static bool is_spilled_scalar_reg(const struct bpf_stack_state *stack) +{ + return stack->slot_type[BPF_REG_SIZE - 1] == STACK_SPILL && + stack->spilled_ptr.type == SCALAR_VALUE; +} + static void scrub_spilled_slot(u8 *stype) { if (*stype != STACK_INVALID) @@ -3186,12 +3192,128 @@ static const char *disasm_kfunc_name(void *data, const struct bpf_insn *insn) return btf_name_by_offset(desc_btf, func->name_off); } +static inline void bt_init(struct backtrack_state *bt, u32 frame) +{ + bt->frame = frame; +} + +static inline void bt_reset(struct backtrack_state *bt) +{ + struct bpf_verifier_env *env = bt->env; + + memset(bt, 0, sizeof(*bt)); + bt->env = env; +} + +static inline u32 bt_empty(struct backtrack_state *bt) +{ + u64 mask = 0; + int i; + + for (i = 0; i <= bt->frame; i++) + mask |= bt->reg_masks[i] | bt->stack_masks[i]; + + return mask == 0; +} + +static inline int bt_subprog_enter(struct backtrack_state *bt) +{ + if (bt->frame == MAX_CALL_FRAMES - 1) { + verbose(bt->env, "BUG subprog enter from frame %d\n", bt->frame); + WARN_ONCE(1, "verifier backtracking bug"); + return -EFAULT; + } + bt->frame++; + return 0; +} + +static inline int bt_subprog_exit(struct backtrack_state *bt) +{ + if (bt->frame == 0) { + verbose(bt->env, "BUG subprog exit from frame 0\n"); + WARN_ONCE(1, "verifier backtracking bug"); + return -EFAULT; + } + bt->frame--; + return 0; +} + +static inline void bt_set_frame_reg(struct backtrack_state *bt, u32 frame, u32 reg) +{ + bt->reg_masks[frame] |= 1 << reg; +} + +static inline void bt_clear_frame_reg(struct backtrack_state *bt, u32 frame, u32 reg) +{ + bt->reg_masks[frame] &= ~(1 << reg); +} + +static inline void bt_set_reg(struct backtrack_state *bt, u32 reg) +{ + bt_set_frame_reg(bt, bt->frame, reg); +} + +static inline void bt_clear_reg(struct backtrack_state *bt, u32 reg) +{ + bt_clear_frame_reg(bt, bt->frame, reg); +} + +static inline void bt_set_frame_slot(struct backtrack_state *bt, u32 frame, u32 slot) +{ + bt->stack_masks[frame] |= 1ull << slot; +} + +static inline void bt_clear_frame_slot(struct backtrack_state *bt, u32 frame, u32 slot) +{ + bt->stack_masks[frame] &= ~(1ull << slot); +} + +static inline void bt_set_slot(struct backtrack_state *bt, u32 slot) +{ + bt_set_frame_slot(bt, bt->frame, slot); +} + +static inline void bt_clear_slot(struct backtrack_state *bt, u32 slot) +{ + bt_clear_frame_slot(bt, bt->frame, slot); +} + +static inline u32 bt_frame_reg_mask(struct backtrack_state *bt, u32 frame) +{ + return bt->reg_masks[frame]; +} + +static inline u32 bt_reg_mask(struct backtrack_state *bt) +{ + return bt->reg_masks[bt->frame]; +} + +static inline u64 bt_frame_stack_mask(struct backtrack_state *bt, u32 frame) +{ + return bt->stack_masks[frame]; +} + +static inline u64 bt_stack_mask(struct backtrack_state *bt) +{ + return bt->stack_masks[bt->frame]; +} + +static inline bool bt_is_reg_set(struct backtrack_state *bt, u32 reg) +{ + return bt->reg_masks[bt->frame] & (1 << reg); +} + +static inline bool bt_is_slot_set(struct backtrack_state *bt, u32 slot) +{ + return bt->stack_masks[bt->frame] & (1ull << slot); +} + /* For given verifier state backtrack_insn() is called from the last insn to * the first insn. Its purpose is to compute a bitmask of registers and * stack slots that needs precision in the parent verifier state. */ static int backtrack_insn(struct bpf_verifier_env *env, int idx, - u32 *reg_mask, u64 *stack_mask) + struct backtrack_state *bt) { const struct bpf_insn_cbs cbs = { .cb_call = disasm_kfunc_name, @@ -3202,20 +3324,20 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, u8 class = BPF_CLASS(insn->code); u8 opcode = BPF_OP(insn->code); u8 mode = BPF_MODE(insn->code); - u32 dreg = 1u << insn->dst_reg; - u32 sreg = 1u << insn->src_reg; + u32 dreg = insn->dst_reg; + u32 sreg = insn->src_reg; u32 spi; if (insn->code == 0) return 0; if (env->log.level & BPF_LOG_LEVEL2) { - verbose(env, "regs=%x stack=%llx before ", *reg_mask, *stack_mask); + verbose(env, "regs=%x stack=%llx before ", bt_reg_mask(bt), bt_stack_mask(bt)); verbose(env, "%d: ", idx); print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); } if (class == BPF_ALU || class == BPF_ALU64) { - if (!(*reg_mask & dreg)) + if (!bt_is_reg_set(bt, dreg)) return 0; if (opcode == BPF_MOV) { if (BPF_SRC(insn->code) == BPF_X) { @@ -3223,8 +3345,8 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, * dreg needs precision after this insn * sreg needs precision before this insn */ - *reg_mask &= ~dreg; - *reg_mask |= sreg; + bt_clear_reg(bt, dreg); + bt_set_reg(bt, sreg); } else { /* dreg = K * dreg needs precision after this insn. @@ -3232,7 +3354,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, * as precise=true in this verifier state. * No further markings in parent are necessary */ - *reg_mask &= ~dreg; + bt_clear_reg(bt, dreg); } } else { if (BPF_SRC(insn->code) == BPF_X) { @@ -3240,15 +3362,15 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, * both dreg and sreg need precision * before this insn */ - *reg_mask |= sreg; + bt_set_reg(bt, sreg); } /* else dreg += K * dreg still needs precision before this insn */ } } else if (class == BPF_LDX) { - if (!(*reg_mask & dreg)) + if (!bt_is_reg_set(bt, dreg)) return 0; - *reg_mask &= ~dreg; + bt_clear_reg(bt, dreg); /* scalars can only be spilled into stack w/o losing precision. * Load from any other memory can be zero extended. @@ -3269,9 +3391,9 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, WARN_ONCE(1, "verifier backtracking bug"); return -EFAULT; } - *stack_mask |= 1ull << spi; + bt_set_slot(bt, spi); } else if (class == BPF_STX || class == BPF_ST) { - if (*reg_mask & dreg) + if (bt_is_reg_set(bt, dreg)) /* stx & st shouldn't be using _scalar_ dst_reg * to access memory. It means backtracking * encountered a case of pointer subtraction. @@ -3286,11 +3408,11 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, WARN_ONCE(1, "verifier backtracking bug"); return -EFAULT; } - if (!(*stack_mask & (1ull << spi))) + if (!bt_is_slot_set(bt, spi)) return 0; - *stack_mask &= ~(1ull << spi); + bt_clear_slot(bt, spi); if (class == BPF_STX) - *reg_mask |= sreg; + bt_set_reg(bt, sreg); } else if (class == BPF_JMP || class == BPF_JMP32) { if (opcode == BPF_CALL) { if (insn->src_reg == BPF_PSEUDO_CALL) @@ -3307,19 +3429,19 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL && insn->imm == 0) return -ENOTSUPP; /* regular helper call sets R0 */ - *reg_mask &= ~1; - if (*reg_mask & 0x3f) { + bt_clear_reg(bt, BPF_REG_0); + if (bt_reg_mask(bt) & BPF_REGMASK_ARGS) { /* if backtracing was looking for registers R1-R5 * they should have been found already. */ - verbose(env, "BUG regs %x\n", *reg_mask); + verbose(env, "BUG regs %x\n", bt_reg_mask(bt)); WARN_ONCE(1, "verifier backtracking bug"); return -EFAULT; } } else if (opcode == BPF_EXIT) { return -ENOTSUPP; } else if (BPF_SRC(insn->code) == BPF_X) { - if (!(*reg_mask & (dreg | sreg))) + if (!bt_is_reg_set(bt, dreg) && !bt_is_reg_set(bt, sreg)) return 0; /* dreg sreg * Both dreg and sreg need precision before @@ -3327,7 +3449,8 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, * before it would be equally necessary to * propagate it to dreg. */ - *reg_mask |= (sreg | dreg); + bt_set_reg(bt, dreg); + bt_set_reg(bt, sreg); /* else dreg K * Only dreg still needs precision before * this insn, so for the K-based conditional @@ -3335,9 +3458,9 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, */ } } else if (class == BPF_LD) { - if (!(*reg_mask & dreg)) + if (!bt_is_reg_set(bt, dreg)) return 0; - *reg_mask &= ~dreg; + bt_clear_reg(bt, dreg); /* It's ld_imm64 or ld_abs or ld_ind. * For ld_imm64 no further tracking of precision * into parent is necessary @@ -3550,20 +3673,21 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int regno, int spi) { + struct backtrack_state *bt = &env->bt; struct bpf_verifier_state *st = env->cur_state; int first_idx = st->first_insn_idx; int last_idx = env->insn_idx; struct bpf_func_state *func; struct bpf_reg_state *reg; - u32 reg_mask = regno >= 0 ? 1u << regno : 0; - u64 stack_mask = spi >= 0 ? 1ull << spi : 0; bool skip_first = true; - bool new_marks = false; int i, err; if (!env->bpf_capable) return 0; + /* set frame number from which we are starting to backtrack */ + bt_init(bt, frame); + /* Do sanity checks against current state of register and/or stack * slot, but don't set precise flag in current state, as precision * tracking in the current state is unnecessary. @@ -3575,26 +3699,17 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r WARN_ONCE(1, "backtracing misuse"); return -EFAULT; } - new_marks = true; + bt_set_reg(bt, regno); } while (spi >= 0) { - if (!is_spilled_reg(&func->stack[spi])) { - stack_mask = 0; + if (!is_spilled_scalar_reg(&func->stack[spi])) break; - } - reg = &func->stack[spi].spilled_ptr; - if (reg->type != SCALAR_VALUE) { - stack_mask = 0; - break; - } - new_marks = true; + bt_set_slot(bt, spi); break; } - if (!new_marks) - return 0; - if (!reg_mask && !stack_mask) + if (bt_empty(bt)) return 0; for (;;) { @@ -3613,12 +3728,13 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r if (st->curframe == 0 && st->frame[0]->subprogno > 0 && st->frame[0]->callsite == BPF_MAIN_FUNC && - stack_mask == 0 && (reg_mask & ~0x3e) == 0) { - bitmap_from_u64(mask, reg_mask); + bt_stack_mask(bt) == 0 && + (bt_reg_mask(bt) & ~BPF_REGMASK_ARGS) == 0) { + bitmap_from_u64(mask, bt_reg_mask(bt)); for_each_set_bit(i, mask, 32) { reg = &st->frame[0]->regs[i]; if (reg->type != SCALAR_VALUE) { - reg_mask &= ~(1u << i); + bt_clear_reg(bt, i); continue; } reg->precise = true; @@ -3626,8 +3742,8 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r return 0; } - verbose(env, "BUG backtracing func entry subprog %d reg_mask %x stack_mask %llx\n", - st->frame[0]->subprogno, reg_mask, stack_mask); + verbose(env, "BUG backtracking func entry subprog %d reg_mask %x stack_mask %llx\n", + st->frame[0]->subprogno, bt_reg_mask(bt), bt_stack_mask(bt)); WARN_ONCE(1, "verifier backtracking bug"); return -EFAULT; } @@ -3637,15 +3753,16 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r err = 0; skip_first = false; } else { - err = backtrack_insn(env, i, ®_mask, &stack_mask); + err = backtrack_insn(env, i, bt); } if (err == -ENOTSUPP) { mark_all_scalars_precise(env, st); + bt_reset(bt); return 0; } else if (err) { return err; } - if (!reg_mask && !stack_mask) + if (bt_empty(bt)) /* Found assignment(s) into tracked register in this state. * Since this state is already marked, just return. * Nothing to be tracked further in the parent state. @@ -3670,21 +3787,21 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r if (!st) break; - new_marks = false; func = st->frame[frame]; - bitmap_from_u64(mask, reg_mask); + bitmap_from_u64(mask, bt_reg_mask(bt)); for_each_set_bit(i, mask, 32) { reg = &func->regs[i]; if (reg->type != SCALAR_VALUE) { - reg_mask &= ~(1u << i); + bt_clear_reg(bt, i); continue; } - if (!reg->precise) - new_marks = true; - reg->precise = true; + if (reg->precise) + bt_clear_reg(bt, i); + else + reg->precise = true; } - bitmap_from_u64(mask, stack_mask); + bitmap_from_u64(mask, bt_stack_mask(bt)); for_each_set_bit(i, mask, 64) { if (i >= func->allocated_stack / BPF_REG_SIZE) { /* the sequence of instructions: @@ -3701,32 +3818,28 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r * In such case fallback to conservative. */ mark_all_scalars_precise(env, st); + bt_reset(bt); return 0; } - if (!is_spilled_reg(&func->stack[i])) { - stack_mask &= ~(1ull << i); + if (!is_spilled_scalar_reg(&func->stack[i])) { + bt_clear_slot(bt, i); continue; } reg = &func->stack[i].spilled_ptr; - if (reg->type != SCALAR_VALUE) { - stack_mask &= ~(1ull << i); - continue; - } - if (!reg->precise) - new_marks = true; - reg->precise = true; + if (reg->precise) + bt_clear_slot(bt, i); + else + reg->precise = true; } if (env->log.level & BPF_LOG_LEVEL2) { verbose(env, "parent %s regs=%x stack=%llx marks:", - new_marks ? "didn't have" : "already had", - reg_mask, stack_mask); + !bt_empty(bt) ? "didn't have" : "already had", + bt_reg_mask(bt), bt_stack_mask(bt)); print_verifier_state(env, func, true); } - if (!reg_mask && !stack_mask) - break; - if (!new_marks) + if (bt_empty(bt)) break; last_idx = st->last_insn_idx; @@ -18872,6 +18985,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3 if (!env) return -ENOMEM; + env->bt.env = env; + len = (*prog)->len; env->insn_aux_data = vzalloc(array_size(sizeof(struct bpf_insn_aux_data), len)); -- cgit v1.2.3 From d9439c21a9e4769bfd83a03ab39056164d44ac31 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:11 -0700 Subject: bpf: improve precision backtrack logging Add helper to format register and stack masks in more human-readable format. Adjust logging a bit during backtrack propagation and especially during forcing precision fallback logic to make it clearer what's going on (with log_level=2, of course), and also start reporting affected frame depth. This is in preparation for having more than one active frame later when precision propagation between subprog calls is added. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-5-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- include/linux/bpf_verifier.h | 13 ++- kernel/bpf/verifier.c | 72 +++++++++++++++-- tools/testing/selftests/bpf/verifier/precise.c | 106 +++++++++++++------------ 3 files changed, 128 insertions(+), 63 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 33f541366f4e..5b11a3b0fec0 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -18,8 +18,11 @@ * that converting umax_value to int cannot overflow. */ #define BPF_MAX_VAR_SIZ (1 << 29) -/* size of type_str_buf in bpf_verifier. */ -#define TYPE_STR_BUF_LEN 128 +/* size of tmp_str_buf in bpf_verifier. + * we need at least 306 bytes to fit full stack mask representation + * (in the "-8,-16,...,-512" form) + */ +#define TMP_STR_BUF_LEN 320 /* Liveness marks, used for registers and spilled-regs (in stack slots). * Read marks propagate upwards until they find a write mark; they record that @@ -620,8 +623,10 @@ struct bpf_verifier_env { /* Same as scratched_regs but for stack slots */ u64 scratched_stack_slots; u64 prev_log_pos, prev_insn_print_pos; - /* buffer used in reg_type_str() to generate reg_type string */ - char type_str_buf[TYPE_STR_BUF_LEN]; + /* buffer used to generate temporary string representations, + * e.g., in reg_type_str() to generate reg_type string + */ + char tmp_str_buf[TMP_STR_BUF_LEN]; }; __printf(2, 0) void bpf_verifier_vlog(struct bpf_verifier_log *log, diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 9b2e571250e1..5412c8c8511d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -605,9 +605,9 @@ static const char *reg_type_str(struct bpf_verifier_env *env, type & PTR_TRUSTED ? "trusted_" : "" ); - snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s", + snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s%s%s", prefix, str[base_type(type)], postfix); - return env->type_str_buf; + return env->tmp_str_buf; } static char slot_type_char[] = { @@ -3308,6 +3308,45 @@ static inline bool bt_is_slot_set(struct backtrack_state *bt, u32 slot) return bt->stack_masks[bt->frame] & (1ull << slot); } +/* format registers bitmask, e.g., "r0,r2,r4" for 0x15 mask */ +static void fmt_reg_mask(char *buf, ssize_t buf_sz, u32 reg_mask) +{ + DECLARE_BITMAP(mask, 64); + bool first = true; + int i, n; + + buf[0] = '\0'; + + bitmap_from_u64(mask, reg_mask); + for_each_set_bit(i, mask, 32) { + n = snprintf(buf, buf_sz, "%sr%d", first ? "" : ",", i); + first = false; + buf += n; + buf_sz -= n; + if (buf_sz < 0) + break; + } +} +/* format stack slots bitmask, e.g., "-8,-24,-40" for 0x15 mask */ +static void fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask) +{ + DECLARE_BITMAP(mask, 64); + bool first = true; + int i, n; + + buf[0] = '\0'; + + bitmap_from_u64(mask, stack_mask); + for_each_set_bit(i, mask, 64) { + n = snprintf(buf, buf_sz, "%s%d", first ? "" : ",", -(i + 1) * 8); + first = false; + buf += n; + buf_sz -= n; + if (buf_sz < 0) + break; + } +} + /* For given verifier state backtrack_insn() is called from the last insn to * the first insn. Its purpose is to compute a bitmask of registers and * stack slots that needs precision in the parent verifier state. @@ -3331,7 +3370,11 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, if (insn->code == 0) return 0; if (env->log.level & BPF_LOG_LEVEL2) { - verbose(env, "regs=%x stack=%llx before ", bt_reg_mask(bt), bt_stack_mask(bt)); + fmt_reg_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, bt_reg_mask(bt)); + verbose(env, "mark_precise: frame%d: regs=%s ", + bt->frame, env->tmp_str_buf); + fmt_stack_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, bt_stack_mask(bt)); + verbose(env, "stack=%s before ", env->tmp_str_buf); verbose(env, "%d: ", idx); print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); } @@ -3531,6 +3574,11 @@ static void mark_all_scalars_precise(struct bpf_verifier_env *env, struct bpf_reg_state *reg; int i, j; + if (env->log.level & BPF_LOG_LEVEL2) { + verbose(env, "mark_precise: frame%d: falling back to forcing all scalars precise\n", + st->curframe); + } + /* big hammer: mark all scalars precise in this path. * pop_stack may still get !precise scalars. * We also skip current state and go straight to first parent state, @@ -3542,17 +3590,25 @@ static void mark_all_scalars_precise(struct bpf_verifier_env *env, func = st->frame[i]; for (j = 0; j < BPF_REG_FP; j++) { reg = &func->regs[j]; - if (reg->type != SCALAR_VALUE) + if (reg->type != SCALAR_VALUE || reg->precise) continue; reg->precise = true; + if (env->log.level & BPF_LOG_LEVEL2) { + verbose(env, "force_precise: frame%d: forcing r%d to be precise\n", + i, j); + } } for (j = 0; j < func->allocated_stack / BPF_REG_SIZE; j++) { if (!is_spilled_reg(&func->stack[j])) continue; reg = &func->stack[j].spilled_ptr; - if (reg->type != SCALAR_VALUE) + if (reg->type != SCALAR_VALUE || reg->precise) continue; reg->precise = true; + if (env->log.level & BPF_LOG_LEVEL2) { + verbose(env, "force_precise: frame%d: forcing fp%d to be precise\n", + i, -(j + 1) * 8); + } } } } @@ -3716,8 +3772,10 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r DECLARE_BITMAP(mask, 64); u32 history = st->jmp_history_cnt; - if (env->log.level & BPF_LOG_LEVEL2) - verbose(env, "last_idx %d first_idx %d\n", last_idx, first_idx); + if (env->log.level & BPF_LOG_LEVEL2) { + verbose(env, "mark_precise: frame%d: last_idx %d first_idx %d\n", + bt->frame, last_idx, first_idx); + } if (last_idx < 0) { /* we are at the entry into subprog, which diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 8f0340eed696..a22fabd404ed 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -38,25 +38,24 @@ .fixup_map_array_48b = { 1 }, .result = VERBOSE_ACCEPT, .errstr = - "26: (85) call bpf_probe_read_kernel#113\ - last_idx 26 first_idx 20\ - regs=4 stack=0 before 25\ - regs=4 stack=0 before 24\ - regs=4 stack=0 before 23\ - regs=4 stack=0 before 22\ - regs=4 stack=0 before 20\ - parent didn't have regs=4 stack=0 marks\ - last_idx 19 first_idx 10\ - regs=4 stack=0 before 19\ - regs=200 stack=0 before 18\ - regs=300 stack=0 before 17\ - regs=201 stack=0 before 15\ - regs=201 stack=0 before 14\ - regs=200 stack=0 before 13\ - regs=200 stack=0 before 12\ - regs=200 stack=0 before 11\ - regs=200 stack=0 before 10\ - parent already had regs=0 stack=0 marks", + "mark_precise: frame0: last_idx 26 first_idx 20\ + mark_precise: frame0: regs=r2 stack= before 25\ + mark_precise: frame0: regs=r2 stack= before 24\ + mark_precise: frame0: regs=r2 stack= before 23\ + mark_precise: frame0: regs=r2 stack= before 22\ + mark_precise: frame0: regs=r2 stack= before 20\ + parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: last_idx 19 first_idx 10\ + mark_precise: frame0: regs=r2 stack= before 19\ + mark_precise: frame0: regs=r9 stack= before 18\ + mark_precise: frame0: regs=r8,r9 stack= before 17\ + mark_precise: frame0: regs=r0,r9 stack= before 15\ + mark_precise: frame0: regs=r0,r9 stack= before 14\ + mark_precise: frame0: regs=r9 stack= before 13\ + mark_precise: frame0: regs=r9 stack= before 12\ + mark_precise: frame0: regs=r9 stack= before 11\ + mark_precise: frame0: regs=r9 stack= before 10\ + parent already had regs=0 stack=0 marks:", }, { "precise: test 2", @@ -100,20 +99,20 @@ .flags = BPF_F_TEST_STATE_FREQ, .errstr = "26: (85) call bpf_probe_read_kernel#113\ - last_idx 26 first_idx 22\ - regs=4 stack=0 before 25\ - regs=4 stack=0 before 24\ - regs=4 stack=0 before 23\ - regs=4 stack=0 before 22\ - parent didn't have regs=4 stack=0 marks\ - last_idx 20 first_idx 20\ - regs=4 stack=0 before 20\ - parent didn't have regs=4 stack=0 marks\ - last_idx 19 first_idx 17\ - regs=4 stack=0 before 19\ - regs=200 stack=0 before 18\ - regs=300 stack=0 before 17\ - parent already had regs=0 stack=0 marks", + mark_precise: frame0: last_idx 26 first_idx 22\ + mark_precise: frame0: regs=r2 stack= before 25\ + mark_precise: frame0: regs=r2 stack= before 24\ + mark_precise: frame0: regs=r2 stack= before 23\ + mark_precise: frame0: regs=r2 stack= before 22\ + parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: last_idx 20 first_idx 20\ + mark_precise: frame0: regs=r2 stack= before 20\ + parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: last_idx 19 first_idx 17\ + mark_precise: frame0: regs=r2 stack= before 19\ + mark_precise: frame0: regs=r9 stack= before 18\ + mark_precise: frame0: regs=r8,r9 stack= before 17\ + parent already had regs=0 stack=0 marks:", }, { "precise: cross frame pruning", @@ -153,15 +152,15 @@ }, .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, - .errstr = "5: (2d) if r4 > r0 goto pc+0\ - last_idx 5 first_idx 5\ - parent didn't have regs=10 stack=0 marks\ - last_idx 4 first_idx 2\ - regs=10 stack=0 before 4\ - regs=10 stack=0 before 3\ - regs=0 stack=1 before 2\ - last_idx 5 first_idx 5\ - parent didn't have regs=1 stack=0 marks", + .errstr = "mark_precise: frame0: last_idx 5 first_idx 5\ + parent didn't have regs=10 stack=0 marks:\ + mark_precise: frame0: last_idx 4 first_idx 2\ + mark_precise: frame0: regs=r4 stack= before 4\ + mark_precise: frame0: regs=r4 stack= before 3\ + mark_precise: frame0: regs= stack=-8 before 2\ + mark_precise: frame0: falling back to forcing all scalars precise\ + mark_precise: frame0: last_idx 5 first_idx 5\ + parent didn't have regs=1 stack=0 marks:", .result = VERBOSE_ACCEPT, .retval = -1, }, @@ -179,16 +178,19 @@ }, .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, - .errstr = "last_idx 6 first_idx 6\ - parent didn't have regs=10 stack=0 marks\ - last_idx 5 first_idx 3\ - regs=10 stack=0 before 5\ - regs=10 stack=0 before 4\ - regs=0 stack=1 before 3\ - last_idx 6 first_idx 6\ - parent didn't have regs=1 stack=0 marks\ - last_idx 5 first_idx 3\ - regs=1 stack=0 before 5", + .errstr = "mark_precise: frame0: last_idx 6 first_idx 6\ + parent didn't have regs=10 stack=0 marks:\ + mark_precise: frame0: last_idx 5 first_idx 3\ + mark_precise: frame0: regs=r4 stack= before 5\ + mark_precise: frame0: regs=r4 stack= before 4\ + mark_precise: frame0: regs= stack=-8 before 3\ + mark_precise: frame0: falling back to forcing all scalars precise\ + force_precise: frame0: forcing r0 to be precise\ + force_precise: frame0: forcing r0 to be precise\ + mark_precise: frame0: last_idx 6 first_idx 6\ + parent didn't have regs=1 stack=0 marks:\ + mark_precise: frame0: last_idx 5 first_idx 3\ + mark_precise: frame0: regs=r0 stack= before 5", .result = VERBOSE_ACCEPT, .retval = -1, }, -- cgit v1.2.3 From 1ef22b6865a73a8aed36d43375fe8c7b30869326 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:12 -0700 Subject: bpf: maintain bitmasks across all active frames in __mark_chain_precision Teach __mark_chain_precision logic to maintain register/stack masks across all active frames when going from child state to parent state. Currently this should be mostly no-op, as precision backtracking usually bails out when encountering subprog entry/exit. It's not very apparent from the diff due to increased indentation, but the logic remains the same, except everything is done on specific `fr` frame index. Calls to bt_clear_reg() and bt_clear_slot() are replaced with frame-specific bt_clear_frame_reg() and bt_clear_frame_slot(), where frame index is passed explicitly, instead of using current frame number. We also adjust logging to emit affected frame number. And we also add better logging of human-readable register and stack slot masks, similar to previous patch. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-6-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 100 +++++++++++++------------ tools/testing/selftests/bpf/verifier/precise.c | 18 ++--- 2 files changed, 62 insertions(+), 56 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5412c8c8511d..5a7997bc96f5 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3736,7 +3736,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r struct bpf_func_state *func; struct bpf_reg_state *reg; bool skip_first = true; - int i, err; + int i, fr, err; if (!env->bpf_capable) return 0; @@ -3845,56 +3845,62 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r if (!st) break; - func = st->frame[frame]; - bitmap_from_u64(mask, bt_reg_mask(bt)); - for_each_set_bit(i, mask, 32) { - reg = &func->regs[i]; - if (reg->type != SCALAR_VALUE) { - bt_clear_reg(bt, i); - continue; + for (fr = bt->frame; fr >= 0; fr--) { + func = st->frame[fr]; + bitmap_from_u64(mask, bt_frame_reg_mask(bt, fr)); + for_each_set_bit(i, mask, 32) { + reg = &func->regs[i]; + if (reg->type != SCALAR_VALUE) { + bt_clear_frame_reg(bt, fr, i); + continue; + } + if (reg->precise) + bt_clear_frame_reg(bt, fr, i); + else + reg->precise = true; } - if (reg->precise) - bt_clear_reg(bt, i); - else - reg->precise = true; - } - bitmap_from_u64(mask, bt_stack_mask(bt)); - for_each_set_bit(i, mask, 64) { - if (i >= func->allocated_stack / BPF_REG_SIZE) { - /* the sequence of instructions: - * 2: (bf) r3 = r10 - * 3: (7b) *(u64 *)(r3 -8) = r0 - * 4: (79) r4 = *(u64 *)(r10 -8) - * doesn't contain jmps. It's backtracked - * as a single block. - * During backtracking insn 3 is not recognized as - * stack access, so at the end of backtracking - * stack slot fp-8 is still marked in stack_mask. - * However the parent state may not have accessed - * fp-8 and it's "unallocated" stack space. - * In such case fallback to conservative. - */ - mark_all_scalars_precise(env, st); - bt_reset(bt); - return 0; - } + bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr)); + for_each_set_bit(i, mask, 64) { + if (i >= func->allocated_stack / BPF_REG_SIZE) { + /* the sequence of instructions: + * 2: (bf) r3 = r10 + * 3: (7b) *(u64 *)(r3 -8) = r0 + * 4: (79) r4 = *(u64 *)(r10 -8) + * doesn't contain jmps. It's backtracked + * as a single block. + * During backtracking insn 3 is not recognized as + * stack access, so at the end of backtracking + * stack slot fp-8 is still marked in stack_mask. + * However the parent state may not have accessed + * fp-8 and it's "unallocated" stack space. + * In such case fallback to conservative. + */ + mark_all_scalars_precise(env, st); + bt_reset(bt); + return 0; + } - if (!is_spilled_scalar_reg(&func->stack[i])) { - bt_clear_slot(bt, i); - continue; + if (!is_spilled_scalar_reg(&func->stack[i])) { + bt_clear_frame_slot(bt, fr, i); + continue; + } + reg = &func->stack[i].spilled_ptr; + if (reg->precise) + bt_clear_frame_slot(bt, fr, i); + else + reg->precise = true; + } + if (env->log.level & BPF_LOG_LEVEL2) { + fmt_reg_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, + bt_frame_reg_mask(bt, fr)); + verbose(env, "mark_precise: frame%d: parent state regs=%s ", + fr, env->tmp_str_buf); + fmt_stack_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, + bt_frame_stack_mask(bt, fr)); + verbose(env, "stack=%s: ", env->tmp_str_buf); + print_verifier_state(env, func, true); } - reg = &func->stack[i].spilled_ptr; - if (reg->precise) - bt_clear_slot(bt, i); - else - reg->precise = true; - } - if (env->log.level & BPF_LOG_LEVEL2) { - verbose(env, "parent %s regs=%x stack=%llx marks:", - !bt_empty(bt) ? "didn't have" : "already had", - bt_reg_mask(bt), bt_stack_mask(bt)); - print_verifier_state(env, func, true); } if (bt_empty(bt)) diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index a22fabd404ed..77ea018582c5 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -44,7 +44,7 @@ mark_precise: frame0: regs=r2 stack= before 23\ mark_precise: frame0: regs=r2 stack= before 22\ mark_precise: frame0: regs=r2 stack= before 20\ - parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 19 first_idx 10\ mark_precise: frame0: regs=r2 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\ @@ -55,7 +55,7 @@ mark_precise: frame0: regs=r9 stack= before 12\ mark_precise: frame0: regs=r9 stack= before 11\ mark_precise: frame0: regs=r9 stack= before 10\ - parent already had regs=0 stack=0 marks:", + mark_precise: frame0: parent state regs= stack=:", }, { "precise: test 2", @@ -104,15 +104,15 @@ mark_precise: frame0: regs=r2 stack= before 24\ mark_precise: frame0: regs=r2 stack= before 23\ mark_precise: frame0: regs=r2 stack= before 22\ - parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 20 first_idx 20\ mark_precise: frame0: regs=r2 stack= before 20\ - parent didn't have regs=4 stack=0 marks:\ + mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 19 first_idx 17\ mark_precise: frame0: regs=r2 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\ mark_precise: frame0: regs=r8,r9 stack= before 17\ - parent already had regs=0 stack=0 marks:", + mark_precise: frame0: parent state regs= stack=:", }, { "precise: cross frame pruning", @@ -153,14 +153,14 @@ .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, .errstr = "mark_precise: frame0: last_idx 5 first_idx 5\ - parent didn't have regs=10 stack=0 marks:\ + mark_precise: frame0: parent state regs=r4 stack=:\ mark_precise: frame0: last_idx 4 first_idx 2\ mark_precise: frame0: regs=r4 stack= before 4\ mark_precise: frame0: regs=r4 stack= before 3\ mark_precise: frame0: regs= stack=-8 before 2\ mark_precise: frame0: falling back to forcing all scalars precise\ mark_precise: frame0: last_idx 5 first_idx 5\ - parent didn't have regs=1 stack=0 marks:", + mark_precise: frame0: parent state regs=r0 stack=:", .result = VERBOSE_ACCEPT, .retval = -1, }, @@ -179,7 +179,7 @@ .prog_type = BPF_PROG_TYPE_XDP, .flags = BPF_F_TEST_STATE_FREQ, .errstr = "mark_precise: frame0: last_idx 6 first_idx 6\ - parent didn't have regs=10 stack=0 marks:\ + mark_precise: frame0: parent state regs=r4 stack=:\ mark_precise: frame0: last_idx 5 first_idx 3\ mark_precise: frame0: regs=r4 stack= before 5\ mark_precise: frame0: regs=r4 stack= before 4\ @@ -188,7 +188,7 @@ force_precise: frame0: forcing r0 to be precise\ force_precise: frame0: forcing r0 to be precise\ mark_precise: frame0: last_idx 6 first_idx 6\ - parent didn't have regs=1 stack=0 marks:\ + mark_precise: frame0: parent state regs=r0 stack=:\ mark_precise: frame0: last_idx 5 first_idx 3\ mark_precise: frame0: regs=r0 stack= before 5", .result = VERBOSE_ACCEPT, -- cgit v1.2.3 From f655badf2a8fc028433d9583bf86a6b473721f09 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:13 -0700 Subject: bpf: fix propagate_precision() logic for inner frames Fix propagate_precision() logic to perform propagation of all necessary registers and stack slots across all active frames *in one batch step*. Doing this for each register/slot in each individual frame is wasteful, but the main problem is that backtracking of instruction in any frame except the deepest one just doesn't work. This is due to backtracking logic relying on jump history, and available jump history always starts (or ends, depending how you view it) in current frame. So, if prog A (frame #0) called subprog B (frame #1) and we need to propagate precision of, say, register R6 (callee-saved) within frame #0, we actually don't even know where jump history that corresponds to prog A even starts. We'd need to skip subprog part of jump history first to be able to do this. Luckily, with struct backtrack_state and __mark_chain_precision() handling bitmasks tracking/propagation across all active frames at the same time (added in previous patch), propagate_precision() can be both fixed and sped up by setting all the necessary bits across all frames and then performing one __mark_chain_precision() pass. This makes it unnecessary to skip subprog parts of jump history. We also improve logging along the way, to clearly specify which registers' and slots' precision markings are propagated within which frame. Each frame will have dedicated line and all registers and stack slots from that frame will be reported in format similar to precision backtrack regs/stack logging. E.g.: frame 1: propagating r1,r2,r3,fp-8,fp-16 frame 0: propagating r3,r9,fp-120 Fixes: 529409ea92d5 ("bpf: propagate precision across all frames, not just the last one") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-7-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 65 +++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5a7997bc96f5..13bbaa2485fc 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3726,8 +3726,7 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_ * mark_all_scalars_imprecise() to hopefully get more permissive and generic * finalized states which help in short circuiting more future states. */ -static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int regno, - int spi) +static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) { struct backtrack_state *bt = &env->bt; struct bpf_verifier_state *st = env->cur_state; @@ -3742,13 +3741,13 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r return 0; /* set frame number from which we are starting to backtrack */ - bt_init(bt, frame); + bt_init(bt, env->cur_state->curframe); /* Do sanity checks against current state of register and/or stack * slot, but don't set precise flag in current state, as precision * tracking in the current state is unnecessary. */ - func = st->frame[frame]; + func = st->frame[bt->frame]; if (regno >= 0) { reg = &func->regs[regno]; if (reg->type != SCALAR_VALUE) { @@ -3758,13 +3757,6 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r bt_set_reg(bt, regno); } - while (spi >= 0) { - if (!is_spilled_scalar_reg(&func->stack[spi])) - break; - bt_set_slot(bt, spi); - break; - } - if (bt_empty(bt)) return 0; @@ -3914,17 +3906,15 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int r int mark_chain_precision(struct bpf_verifier_env *env, int regno) { - return __mark_chain_precision(env, env->cur_state->curframe, regno, -1); -} - -static int mark_chain_precision_frame(struct bpf_verifier_env *env, int frame, int regno) -{ - return __mark_chain_precision(env, frame, regno, -1); + return __mark_chain_precision(env, regno); } -static int mark_chain_precision_stack_frame(struct bpf_verifier_env *env, int frame, int spi) +/* mark_chain_precision_batch() assumes that env->bt is set in the caller to + * desired reg and stack masks across all relevant frames + */ +static int mark_chain_precision_batch(struct bpf_verifier_env *env) { - return __mark_chain_precision(env, frame, -1, spi); + return __mark_chain_precision(env, -1); } static bool is_spillable_regtype(enum bpf_reg_type type) @@ -15361,20 +15351,25 @@ static int propagate_precision(struct bpf_verifier_env *env, struct bpf_reg_state *state_reg; struct bpf_func_state *state; int i, err = 0, fr; + bool first; for (fr = old->curframe; fr >= 0; fr--) { state = old->frame[fr]; state_reg = state->regs; + first = true; for (i = 0; i < BPF_REG_FP; i++, state_reg++) { if (state_reg->type != SCALAR_VALUE || !state_reg->precise || !(state_reg->live & REG_LIVE_READ)) continue; - if (env->log.level & BPF_LOG_LEVEL2) - verbose(env, "frame %d: propagating r%d\n", fr, i); - err = mark_chain_precision_frame(env, fr, i); - if (err < 0) - return err; + if (env->log.level & BPF_LOG_LEVEL2) { + if (first) + verbose(env, "frame %d: propagating r%d", fr, i); + else + verbose(env, ",r%d", i); + } + bt_set_frame_reg(&env->bt, fr, i); + first = false; } for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) { @@ -15385,14 +15380,24 @@ static int propagate_precision(struct bpf_verifier_env *env, !state_reg->precise || !(state_reg->live & REG_LIVE_READ)) continue; - if (env->log.level & BPF_LOG_LEVEL2) - verbose(env, "frame %d: propagating fp%d\n", - fr, (-i - 1) * BPF_REG_SIZE); - err = mark_chain_precision_stack_frame(env, fr, i); - if (err < 0) - return err; + if (env->log.level & BPF_LOG_LEVEL2) { + if (first) + verbose(env, "frame %d: propagating fp%d", + fr, (-i - 1) * BPF_REG_SIZE); + else + verbose(env, ",fp%d", (-i - 1) * BPF_REG_SIZE); + } + bt_set_frame_slot(&env->bt, fr, i); + first = false; } + if (!first) + verbose(env, "\n"); } + + err = mark_chain_precision_batch(env); + if (err < 0) + return err; + return 0; } -- cgit v1.2.3 From c50c0b57a515826b5d2e1ce85cd85f24f0da10c2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:14 -0700 Subject: bpf: fix mark_all_scalars_precise use in mark_chain_precision When precision backtracking bails out due to some unsupported sequence of instructions (e.g., stack access through register other than r10), we need to mark all SCALAR registers as precise to be safe. Currently, though, we mark SCALARs precise only starting from the state we detected unsupported condition, which could be one of the parent states of the actual current state. This will leave some registers potentially not marked as precise, even though they should. So make sure we start marking scalars as precise from current state (env->cur_state). Further, we don't currently detect a situation when we end up with some stack slots marked as needing precision, but we ran out of available states to find the instructions that populate those stack slots. This is akin the `i >= func->allocated_stack / BPF_REG_SIZE` check and should be handled similarly by falling back to marking all SCALARs precise. Add this check when we run out of states. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-8-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 16 +++++++++++++--- tools/testing/selftests/bpf/verifier/precise.c | 9 +++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 13bbaa2485fc..899122832d8e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3806,7 +3806,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) err = backtrack_insn(env, i, bt); } if (err == -ENOTSUPP) { - mark_all_scalars_precise(env, st); + mark_all_scalars_precise(env, env->cur_state); bt_reset(bt); return 0; } else if (err) { @@ -3868,7 +3868,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) * fp-8 and it's "unallocated" stack space. * In such case fallback to conservative. */ - mark_all_scalars_precise(env, st); + mark_all_scalars_precise(env, env->cur_state); bt_reset(bt); return 0; } @@ -3896,11 +3896,21 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) } if (bt_empty(bt)) - break; + return 0; last_idx = st->last_insn_idx; first_idx = st->first_insn_idx; } + + /* if we still have requested precise regs or slots, we missed + * something (e.g., stack access through non-r10 register), so + * fallback to marking all precise + */ + if (!bt_empty(bt)) { + mark_all_scalars_precise(env, env->cur_state); + bt_reset(bt); + } + return 0; } diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index 77ea018582c5..b8c0aae8e7ec 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -159,8 +159,9 @@ mark_precise: frame0: regs=r4 stack= before 3\ mark_precise: frame0: regs= stack=-8 before 2\ mark_precise: frame0: falling back to forcing all scalars precise\ + force_precise: frame0: forcing r0 to be precise\ mark_precise: frame0: last_idx 5 first_idx 5\ - mark_precise: frame0: parent state regs=r0 stack=:", + mark_precise: frame0: parent state regs= stack=:", .result = VERBOSE_ACCEPT, .retval = -1, }, @@ -187,10 +188,10 @@ mark_precise: frame0: falling back to forcing all scalars precise\ force_precise: frame0: forcing r0 to be precise\ force_precise: frame0: forcing r0 to be precise\ + force_precise: frame0: forcing r0 to be precise\ + force_precise: frame0: forcing r0 to be precise\ mark_precise: frame0: last_idx 6 first_idx 6\ - mark_precise: frame0: parent state regs=r0 stack=:\ - mark_precise: frame0: last_idx 5 first_idx 3\ - mark_precise: frame0: regs=r0 stack= before 5", + mark_precise: frame0: parent state regs= stack=:", .result = VERBOSE_ACCEPT, .retval = -1, }, -- cgit v1.2.3 From fde2a3882bd07876c144f2e00f7ae6893c378180 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:15 -0700 Subject: bpf: support precision propagation in the presence of subprogs Add support precision backtracking in the presence of subprogram frames in jump history. This means supporting a few different kinds of subprogram invocation situations, all requiring a slightly different handling in precision backtracking handling logic: - static subprogram calls; - global subprogram calls; - callback-calling helpers/kfuncs. For each of those we need to handle a few precision propagation cases: - what to do with precision of subprog returns (r0); - what to do with precision of input arguments; - for all of them callee-saved registers in caller function should be propagated ignoring subprog/callback part of jump history. N.B. Async callback-calling helpers (currently only bpf_timer_set_callback()) are transparent to all this because they set a separate async callback environment and thus callback's history is not shared with main program's history. So as far as all the changes in this commit goes, such helper is just a regular helper. Let's look at all these situation in more details. Let's start with static subprogram being called, using an exxerpt of a simple main program and its static subprog, indenting subprog's frame slightly to make everything clear. frame 0 frame 1 precision set ======= ======= ============= 9: r6 = 456; 10: r1 = 123; fr0: r6 11: call pc+10; fr0: r1, r6 22: r0 = r1; fr0: r6; fr1: r1 23: exit fr0: r6; fr1: r0 12: r1 = fr0: r0, r6 13: r1 += r0; fr0: r0, r6 14: r1 += r6; fr0: r6 15: exit As can be seen above main function is passing 123 as single argument to an identity (`return x;`) subprog. Returned value is used to adjust map pointer offset, which forces r0 to be marked as precise. Then instruction #14 does the same for callee-saved r6, which will have to be backtracked all the way to instruction #9. For brevity, precision sets for instruction #13 and #14 are combined in the diagram above. First, for subprog calls, r0 returned from subprog (in frame 0) has to go into subprog's frame 1, and should be cleared from frame 0. So we go back into subprog's frame knowing we need to mark r0 precise. We then see that insn #22 sets r0 from r1, so now we care about marking r1 precise. When we pop up from subprog's frame back into caller at insn #11 we keep r1, as it's an argument-passing register, so we eventually find `10: r1 = 123;` and satify precision propagation chain for insn #13. This example demonstrates two sets of rules: - r0 returned after subprog call has to be moved into subprog's r0 set; - *static* subprog arguments (r1-r5) are moved back to caller precision set. Let's look at what happens with callee-saved precision propagation. Insn #14 mark r6 as precise. When we get into subprog's frame, we keep r6 in frame 0's precision set *only*. Subprog itself has its own set of independent r6-r10 registers and is not affected. When we eventually made our way out of subprog frame we keep r6 in precision set until we reach `9: r6 = 456;`, satisfying propagation. r6-r10 propagation is perhaps the simplest aspect, it always stays in its original frame. That's pretty much all we have to do to support precision propagation across *static subprog* invocation. Let's look at what happens when we have global subprog invocation. frame 0 frame 1 precision set ======= ======= ============= 9: r6 = 456; 10: r1 = 123; fr0: r6 11: call pc+10; # global subprog fr0: r6 12: r1 = fr0: r0, r6 13: r1 += r0; fr0: r0, r6 14: r1 += r6; fr0: r6; 15: exit Starting from insn #13, r0 has to be precise. We backtrack all the way to insn #11 (call pc+10) and see that subprog is global, so was already validated in isolation. As opposed to static subprog, global subprog always returns unknown scalar r0, so that satisfies precision propagation and we drop r0 from precision set. We are done for insns #13. Now for insn #14. r6 is in precision set, we backtrack to `call pc+10;`. Here we need to recognize that this is effectively both exit and entry to global subprog, which means we stay in caller's frame. So we carry on with r6 still in precision set, until we satisfy it at insn #9. The only hard part with global subprogs is just knowing when it's a global func. Lastly, callback-calling helpers and kfuncs do simulate subprog calls, so jump history will have subprog instructions in between caller program's instructions, but the rules of propagating r0 and r1-r5 differ, because we don't actually directly call callback. We actually call helper/kfunc, which at runtime will call subprog, so the only difference between normal helper/kfunc handling is that we need to make sure to skip callback simulatinog part of jump history. Let's look at an example to make this clearer. frame 0 frame 1 precision set ======= ======= ============= 8: r6 = 456; 9: r1 = 123; fr0: r6 10: r2 = &callback; fr0: r6 11: call bpf_loop; fr0: r6 22: r0 = r1; fr0: r6 fr1: 23: exit fr0: r6 fr1: 12: r1 = fr0: r0, r6 13: r1 += r0; fr0: r0, r6 14: r1 += r6; fr0: r6; 15: exit Again, insn #13 forces r0 to be precise. As soon as we get to `23: exit` we see that this isn't actually a static subprog call (it's `call bpf_loop;` helper call instead). So we clear r0 from precision set. For callee-saved register, there is no difference: it stays in frame 0's precision set, we go through insn #22 and #23, ignoring them until we get back to caller frame 0, eventually satisfying precision backtrack logic at insn #8 (`r6 = 456;`). Assuming callback needed to set r0 as precise at insn #23, we'd backtrack to insn #22, switching from r0 to r1, and then at the point when we pop back to frame 0 at insn #11, we'll clear r1-r5 from precision set, as we don't really do a subprog call directly, so there is no input argument precision propagation. That's pretty much it. With these changes, it seems like the only still unsupported situation for precision backpropagation is the case when program is accessing stack through registers other than r10. This is still left as unsupported (though rare) case for now. As for results. For selftests, few positive changes for bigger programs, cls_redirect in dynptr variant benefitting the most: [vmuser@archvm bpf]$ ./veristat -C ~/subprog-precise-before-results.csv ~/subprog-precise-after-results.csv -f @veristat.cfg -e file,prog,insns -f 'insns_diff!=0' File Program Insns (A) Insns (B) Insns (DIFF) ---------------------------------------- ------------- --------- --------- ---------------- pyperf600_bpf_loop.bpf.linked1.o on_event 2060 2002 -58 (-2.82%) test_cls_redirect_dynptr.bpf.linked1.o cls_redirect 15660 2914 -12746 (-81.39%) test_cls_redirect_subprogs.bpf.linked1.o cls_redirect 61620 59088 -2532 (-4.11%) xdp_synproxy_kern.bpf.linked1.o syncookie_tc 109980 86278 -23702 (-21.55%) xdp_synproxy_kern.bpf.linked1.o syncookie_xdp 97716 85147 -12569 (-12.86%) Cilium progress don't really regress. They don't use subprogs and are mostly unaffected, but some other fixes and improvements could have changed something. This doesn't appear to be the case: [vmuser@archvm bpf]$ ./veristat -C ~/subprog-precise-before-results-cilium.csv ~/subprog-precise-after-results-cilium.csv -e file,prog,insns -f 'insns_diff!=0' File Program Insns (A) Insns (B) Insns (DIFF) ------------- ------------------------------ --------- --------- ------------ bpf_host.o tail_nodeport_nat_ingress_ipv6 4983 5003 +20 (+0.40%) bpf_lxc.o tail_nodeport_nat_ingress_ipv6 4983 5003 +20 (+0.40%) bpf_overlay.o tail_nodeport_nat_ingress_ipv6 4983 5003 +20 (+0.40%) bpf_xdp.o tail_handle_nat_fwd_ipv6 12475 12504 +29 (+0.23%) bpf_xdp.o tail_nodeport_nat_ingress_ipv6 6363 6371 +8 (+0.13%) Looking at (somewhat anonymized) Meta production programs, we see mostly insignificant variation in number of instructions, with one program (syar_bind6_protect6) benefitting the most at -17%. [vmuser@archvm bpf]$ ./veristat -C ~/subprog-precise-before-results-fbcode.csv ~/subprog-precise-after-results-fbcode.csv -e prog,insns -f 'insns_diff!=0' Program Insns (A) Insns (B) Insns (DIFF) ------------------------ --------- --------- ---------------- on_request_context_event 597 585 -12 (-2.01%) read_async_py_stack 43789 43657 -132 (-0.30%) read_sync_py_stack 35041 37599 +2558 (+7.30%) rrm_usdt 946 940 -6 (-0.63%) sysarmor_inet6_bind 28863 28249 -614 (-2.13%) sysarmor_inet_bind 28845 28240 -605 (-2.10%) syar_bind4_protect4 154145 147640 -6505 (-4.22%) syar_bind6_protect6 165242 137088 -28154 (-17.04%) syar_task_exit_setgid 21289 19720 -1569 (-7.37%) syar_task_exit_setuid 21290 19721 -1569 (-7.37%) do_uprobe 19967 19413 -554 (-2.77%) tw_twfw_ingress 215877 204833 -11044 (-5.12%) tw_twfw_tc_in 215877 204833 -11044 (-5.12%) But checking duration (wall clock) differences, that is the actual time taken by verifier to validate programs, we see a sometimes dramatic improvements, all the way to about 16x improvements: [vmuser@archvm bpf]$ ./veristat -C ~/subprog-precise-before-results-meta.csv ~/subprog-precise-after-results-meta.csv -e prog,duration -s duration_diff^ | head -n20 Program Duration (us) (A) Duration (us) (B) Duration (us) (DIFF) ---------------------------------------- ----------------- ----------------- -------------------- tw_twfw_ingress 4488374 272836 -4215538 (-93.92%) tw_twfw_tc_in 4339111 268175 -4070936 (-93.82%) tw_twfw_egress 3521816 270751 -3251065 (-92.31%) tw_twfw_tc_eg 3472878 284294 -3188584 (-91.81%) balancer_ingress 343119 291391 -51728 (-15.08%) syar_bind6_protect6 78992 64782 -14210 (-17.99%) ttls_tc_ingress 11739 8176 -3563 (-30.35%) kprobe__security_inode_link 13864 11341 -2523 (-18.20%) read_sync_py_stack 21927 19442 -2485 (-11.33%) read_async_py_stack 30444 28136 -2308 (-7.58%) syar_task_exit_setuid 10256 8440 -1816 (-17.71%) Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-9-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 163 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 143 insertions(+), 20 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 899122832d8e..0fa96581eb77 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -240,6 +240,12 @@ static void bpf_map_key_store(struct bpf_insn_aux_data *aux, u64 state) (poisoned ? BPF_MAP_KEY_POISON : 0ULL); } +static bool bpf_helper_call(const struct bpf_insn *insn) +{ + return insn->code == (BPF_JMP | BPF_CALL) && + insn->src_reg == 0; +} + static bool bpf_pseudo_call(const struct bpf_insn *insn) { return insn->code == (BPF_JMP | BPF_CALL) && @@ -469,6 +475,13 @@ static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg) return rec; } +static bool subprog_is_global(const struct bpf_verifier_env *env, int subprog) +{ + struct bpf_func_info_aux *aux = env->prog->aux->func_info_aux; + + return aux && aux[subprog].linkage == BTF_FUNC_GLOBAL; +} + static bool reg_may_point_to_spin_lock(const struct bpf_reg_state *reg) { return btf_record_has_field(reg_btf_record(reg), BPF_SPIN_LOCK); @@ -516,6 +529,8 @@ static bool is_dynptr_ref_function(enum bpf_func_id func_id) return func_id == BPF_FUNC_dynptr_data; } +static bool is_callback_calling_kfunc(u32 btf_id); + static bool is_callback_calling_function(enum bpf_func_id func_id) { return func_id == BPF_FUNC_for_each_map_elem || @@ -525,6 +540,11 @@ static bool is_callback_calling_function(enum bpf_func_id func_id) func_id == BPF_FUNC_user_ringbuf_drain; } +static bool is_async_callback_calling_function(enum bpf_func_id func_id) +{ + return func_id == BPF_FUNC_timer_set_callback; +} + static bool is_storage_get_function(enum bpf_func_id func_id) { return func_id == BPF_FUNC_sk_storage_get || @@ -3350,8 +3370,13 @@ static void fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask) /* For given verifier state backtrack_insn() is called from the last insn to * the first insn. Its purpose is to compute a bitmask of registers and * stack slots that needs precision in the parent verifier state. + * + * @idx is an index of the instruction we are currently processing; + * @subseq_idx is an index of the subsequent instruction that: + * - *would be* executed next, if jump history is viewed in forward order; + * - *was* processed previously during backtracking. */ -static int backtrack_insn(struct bpf_verifier_env *env, int idx, +static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx, struct backtrack_state *bt) { const struct bpf_insn_cbs cbs = { @@ -3365,7 +3390,7 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, u8 mode = BPF_MODE(insn->code); u32 dreg = insn->dst_reg; u32 sreg = insn->src_reg; - u32 spi; + u32 spi, i; if (insn->code == 0) return 0; @@ -3457,14 +3482,86 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, if (class == BPF_STX) bt_set_reg(bt, sreg); } else if (class == BPF_JMP || class == BPF_JMP32) { - if (opcode == BPF_CALL) { - if (insn->src_reg == BPF_PSEUDO_CALL) - return -ENOTSUPP; - /* BPF helpers that invoke callback subprogs are - * equivalent to BPF_PSEUDO_CALL above + if (bpf_pseudo_call(insn)) { + int subprog_insn_idx, subprog; + + subprog_insn_idx = idx + insn->imm + 1; + subprog = find_subprog(env, subprog_insn_idx); + if (subprog < 0) + return -EFAULT; + + if (subprog_is_global(env, subprog)) { + /* check that jump history doesn't have any + * extra instructions from subprog; the next + * instruction after call to global subprog + * should be literally next instruction in + * caller program + */ + WARN_ONCE(idx + 1 != subseq_idx, "verifier backtracking bug"); + /* r1-r5 are invalidated after subprog call, + * so for global func call it shouldn't be set + * anymore + */ + if (bt_reg_mask(bt) & BPF_REGMASK_ARGS) { + verbose(env, "BUG regs %x\n", bt_reg_mask(bt)); + WARN_ONCE(1, "verifier backtracking bug"); + return -EFAULT; + } + /* global subprog always sets R0 */ + bt_clear_reg(bt, BPF_REG_0); + return 0; + } else { + /* static subprog call instruction, which + * means that we are exiting current subprog, + * so only r1-r5 could be still requested as + * precise, r0 and r6-r10 or any stack slot in + * the current frame should be zero by now + */ + if (bt_reg_mask(bt) & ~BPF_REGMASK_ARGS) { + verbose(env, "BUG regs %x\n", bt_reg_mask(bt)); + WARN_ONCE(1, "verifier backtracking bug"); + return -EFAULT; + } + /* we don't track register spills perfectly, + * so fallback to force-precise instead of failing */ + if (bt_stack_mask(bt) != 0) + return -ENOTSUPP; + /* propagate r1-r5 to the caller */ + for (i = BPF_REG_1; i <= BPF_REG_5; i++) { + if (bt_is_reg_set(bt, i)) { + bt_clear_reg(bt, i); + bt_set_frame_reg(bt, bt->frame - 1, i); + } + } + if (bt_subprog_exit(bt)) + return -EFAULT; + return 0; + } + } else if ((bpf_helper_call(insn) && + is_callback_calling_function(insn->imm) && + !is_async_callback_calling_function(insn->imm)) || + (bpf_pseudo_kfunc_call(insn) && is_callback_calling_kfunc(insn->imm))) { + /* callback-calling helper or kfunc call, which means + * we are exiting from subprog, but unlike the subprog + * call handling above, we shouldn't propagate + * precision of r1-r5 (if any requested), as they are + * not actually arguments passed directly to callback + * subprogs */ - if (insn->src_reg == 0 && is_callback_calling_function(insn->imm)) + if (bt_reg_mask(bt) & ~BPF_REGMASK_ARGS) { + verbose(env, "BUG regs %x\n", bt_reg_mask(bt)); + WARN_ONCE(1, "verifier backtracking bug"); + return -EFAULT; + } + if (bt_stack_mask(bt) != 0) return -ENOTSUPP; + /* clear r1-r5 in callback subprog's mask */ + for (i = BPF_REG_1; i <= BPF_REG_5; i++) + bt_clear_reg(bt, i); + if (bt_subprog_exit(bt)) + return -EFAULT; + return 0; + } else if (opcode == BPF_CALL) { /* kfunc with imm==0 is invalid and fixup_kfunc_call will * catch this error later. Make backtracking conservative * with ENOTSUPP. @@ -3482,7 +3579,39 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, return -EFAULT; } } else if (opcode == BPF_EXIT) { - return -ENOTSUPP; + bool r0_precise; + + if (bt_reg_mask(bt) & BPF_REGMASK_ARGS) { + /* if backtracing was looking for registers R1-R5 + * they should have been found already. + */ + verbose(env, "BUG regs %x\n", bt_reg_mask(bt)); + WARN_ONCE(1, "verifier backtracking bug"); + return -EFAULT; + } + + /* BPF_EXIT in subprog or callback always returns + * right after the call instruction, so by checking + * whether the instruction at subseq_idx-1 is subprog + * call or not we can distinguish actual exit from + * *subprog* from exit from *callback*. In the former + * case, we need to propagate r0 precision, if + * necessary. In the former we never do that. + */ + r0_precise = subseq_idx - 1 >= 0 && + bpf_pseudo_call(&env->prog->insnsi[subseq_idx - 1]) && + bt_is_reg_set(bt, BPF_REG_0); + + bt_clear_reg(bt, BPF_REG_0); + if (bt_subprog_enter(bt)) + return -EFAULT; + + if (r0_precise) + bt_set_reg(bt, BPF_REG_0); + /* r6-r9 and stack slots will stay set in caller frame + * bitmasks until we return back from callee(s) + */ + return 0; } else if (BPF_SRC(insn->code) == BPF_X) { if (!bt_is_reg_set(bt, dreg) && !bt_is_reg_set(bt, sreg)) return 0; @@ -3735,7 +3864,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) struct bpf_func_state *func; struct bpf_reg_state *reg; bool skip_first = true; - int i, fr, err; + int i, prev_i, fr, err; if (!env->bpf_capable) return 0; @@ -3798,12 +3927,12 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) return -EFAULT; } - for (i = last_idx;;) { + for (i = last_idx, prev_i = -1;;) { if (skip_first) { err = 0; skip_first = false; } else { - err = backtrack_insn(env, i, bt); + err = backtrack_insn(env, i, prev_i, bt); } if (err == -ENOTSUPP) { mark_all_scalars_precise(env, env->cur_state); @@ -3820,6 +3949,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) return 0; if (i == first_idx) break; + prev_i = i; i = get_prev_insn_idx(st, i, &history); if (i >= env->prog->len) { /* This can happen if backtracking reached insn 0 @@ -8400,17 +8530,13 @@ static int set_callee_state(struct bpf_verifier_env *env, struct bpf_func_state *caller, struct bpf_func_state *callee, int insn_idx); -static bool is_callback_calling_kfunc(u32 btf_id); - static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn, int *insn_idx, int subprog, set_callee_state_fn set_callee_state_cb) { struct bpf_verifier_state *state = env->cur_state; - struct bpf_func_info_aux *func_info_aux; struct bpf_func_state *caller, *callee; int err; - bool is_global = false; if (state->curframe + 1 >= MAX_CALL_FRAMES) { verbose(env, "the call stack of %d frames is too deep\n", @@ -8425,13 +8551,10 @@ static int __check_func_call(struct bpf_verifier_env *env, struct bpf_insn *insn return -EFAULT; } - func_info_aux = env->prog->aux->func_info_aux; - if (func_info_aux) - is_global = func_info_aux[subprog].linkage == BTF_FUNC_GLOBAL; err = btf_check_subprog_call(env, subprog, caller->regs); if (err == -EFAULT) return err; - if (is_global) { + if (subprog_is_global(env, subprog)) { if (err) { verbose(env, "Caller passes invalid args into func#%d\n", subprog); -- cgit v1.2.3 From 3ef3d2177b1a5484908c53d19269b964c488c20f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:16 -0700 Subject: selftests/bpf: add precision propagation tests in the presence of subprogs Add a bunch of tests validating verifier's precision backpropagation logic in the presence of subprog calls and/or callback-calling helpers/kfuncs. We validate the following conditions: - subprog_result_precise: static subprog r0 result precision handling; - global_subprog_result_precise: global subprog r0 precision shortcutting, similar to BPF helper handling; - callback_result_precise: similarly r0 marking precise for callback-calling helpers; - parent_callee_saved_reg_precise, parent_callee_saved_reg_precise_global: propagation of precision for callee-saved registers bypassing static/global subprogs; - parent_callee_saved_reg_precise_with_callback: same as above, but in the presence of callback-calling helper; - parent_stack_slot_precise, parent_stack_slot_precise_global: similar to above, but instead propagating precision of stack slot (spilled SCALAR reg); - parent_stack_slot_precise_with_callback: same as above, but in the presence of callback-calling helper; - subprog_arg_precise: propagation of precision of static subprog's input argument back to caller; - subprog_spill_into_parent_stack_slot_precise: negative test validating that verifier currently can't support backtracking of stack access with non-r10 register, we validate that we fallback to forcing precision for all SCALARs. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-10-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/verifier.c | 2 + tools/testing/selftests/bpf/progs/bpf_misc.h | 4 + .../bpf/progs/verifier_subprog_precision.c | 536 +++++++++++++++++++++ 3 files changed, 542 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/verifier_subprog_precision.c diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index 2497716ee379..531621adef42 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -55,6 +55,7 @@ #include "verifier_spill_fill.skel.h" #include "verifier_spin_lock.skel.h" #include "verifier_stack_ptr.skel.h" +#include "verifier_subprog_precision.skel.h" #include "verifier_subreg.skel.h" #include "verifier_uninit.skel.h" #include "verifier_unpriv.skel.h" @@ -154,6 +155,7 @@ void test_verifier_sock(void) { RUN(verifier_sock); } void test_verifier_spill_fill(void) { RUN(verifier_spill_fill); } void test_verifier_spin_lock(void) { RUN(verifier_spin_lock); } void test_verifier_stack_ptr(void) { RUN(verifier_stack_ptr); } +void test_verifier_subprog_precision(void) { RUN(verifier_subprog_precision); } void test_verifier_subreg(void) { RUN(verifier_subreg); } void test_verifier_uninit(void) { RUN(verifier_uninit); } void test_verifier_unpriv(void) { RUN(verifier_unpriv); } diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h index d3c1217ba79a..38a57a2e70db 100644 --- a/tools/testing/selftests/bpf/progs/bpf_misc.h +++ b/tools/testing/selftests/bpf/progs/bpf_misc.h @@ -86,6 +86,10 @@ #define POINTER_VALUE 0xcafe4all #define TEST_DATA_LEN 64 +#ifndef __used +#define __used __attribute__((used)) +#endif + #if defined(__TARGET_ARCH_x86) #define SYSCALL_WRAPPER 1 #define SYS_PREFIX "__x64_" diff --git a/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c new file mode 100644 index 000000000000..db6b3143338b --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_subprog_precision.c @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include +#include +#include +#include +#include "bpf_misc.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + +int vals[] SEC(".data.vals") = {1, 2, 3, 4}; + +__naked __noinline __used +static unsigned long identity_subprog() +{ + /* the simplest *static* 64-bit identity function */ + asm volatile ( + "r0 = r1;" + "exit;" + ); +} + +__noinline __used +unsigned long global_identity_subprog(__u64 x) +{ + /* the simplest *global* 64-bit identity function */ + return x; +} + +__naked __noinline __used +static unsigned long callback_subprog() +{ + /* the simplest callback function */ + asm volatile ( + "r0 = 0;" + "exit;" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("7: (0f) r1 += r0") +__msg("mark_precise: frame0: regs=r0 stack= before 6: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r0 stack= before 5: (27) r0 *= 4") +__msg("mark_precise: frame0: regs=r0 stack= before 11: (95) exit") +__msg("mark_precise: frame1: regs=r0 stack= before 10: (bf) r0 = r1") +__msg("mark_precise: frame1: regs=r1 stack= before 4: (85) call pc+5") +__msg("mark_precise: frame0: regs=r1 stack= before 3: (bf) r1 = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int subprog_result_precise(void) +{ + asm volatile ( + "r6 = 3;" + /* pass r6 through r1 into subprog to get it back as r0; + * this whole chain will have to be marked as precise later + */ + "r1 = r6;" + "call identity_subprog;" + /* now use subprog's returned value (which is a + * r6 -> r1 -> r0 chain), as index into vals array, forcing + * all of that to be known precisely + */ + "r0 *= 4;" + "r1 = %[vals];" + /* here r0->r1->r6 chain is forced to be precise and has to be + * propagated back to the beginning, including through the + * subprog call + */ + "r1 += r0;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("9: (0f) r1 += r0") +__msg("mark_precise: frame0: last_idx 9 first_idx 0") +__msg("mark_precise: frame0: regs=r0 stack= before 8: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r0 stack= before 7: (27) r0 *= 4") +__msg("mark_precise: frame0: regs=r0 stack= before 5: (a5) if r0 < 0x4 goto pc+1") +__msg("mark_precise: frame0: regs=r0 stack= before 4: (85) call pc+7") +__naked int global_subprog_result_precise(void) +{ + asm volatile ( + "r6 = 3;" + /* pass r6 through r1 into subprog to get it back as r0; + * given global_identity_subprog is global, precision won't + * propagate all the way back to r6 + */ + "r1 = r6;" + "call global_identity_subprog;" + /* now use subprog's returned value (which is unknown now, so + * we need to clamp it), as index into vals array, forcing r0 + * to be marked precise (with no effect on r6, though) + */ + "if r0 < %[vals_arr_sz] goto 1f;" + "r0 = %[vals_arr_sz] - 1;" + "1:" + "r0 *= 4;" + "r1 = %[vals];" + /* here r0 is forced to be precise and has to be + * propagated back to the global subprog call, but it + * shouldn't go all the way to mark r6 as precise + */ + "r1 += r0;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals), + __imm_const(vals_arr_sz, ARRAY_SIZE(vals)) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("14: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 14 first_idx 10") +__msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4") +__msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0") +__msg("mark_precise: frame0: parent state regs=r0 stack=:") +__msg("mark_precise: frame0: last_idx 18 first_idx 0") +__msg("mark_precise: frame0: regs=r0 stack= before 18: (95) exit") +__naked int callback_result_precise(void) +{ + asm volatile ( + "r6 = 3;" + + /* call subprog and use result; r0 shouldn't propagate back to + * callback_subprog + */ + "r1 = r6;" /* nr_loops */ + "r2 = %[callback_subprog];" /* callback_fn */ + "r3 = 0;" /* callback_ctx */ + "r4 = 0;" /* flags */ + "call %[bpf_loop];" + + "r6 = r0;" + "if r6 > 3 goto 1f;" + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the bpf_loop() call, but not beyond + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "1:" + "exit;" + : + : __imm_ptr(vals), + __imm_ptr(callback_subprog), + __imm(bpf_loop) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("7: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 7 first_idx 0") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 5: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 11: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 10: (bf) r0 = r1") +__msg("mark_precise: frame1: regs= stack= before 4: (85) call pc+5") +__msg("mark_precise: frame0: regs=r6 stack= before 3: (b7) r1 = 0") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int parent_callee_saved_reg_precise(void) +{ + asm volatile ( + "r6 = 3;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 0;" + "call identity_subprog;" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("7: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 7 first_idx 0") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 5: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 4: (85) call pc+5") +__msg("mark_precise: frame0: regs=r6 stack= before 3: (b7) r1 = 0") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int parent_callee_saved_reg_precise_global(void) +{ + asm volatile ( + "r6 = 3;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 0;" + "call global_identity_subprog;" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("12: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 12 first_idx 10") +__msg("mark_precise: frame0: regs=r6 stack= before 11: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 10: (27) r6 *= 4") +__msg("mark_precise: frame0: parent state regs=r6 stack=:") +__msg("mark_precise: frame0: last_idx 16 first_idx 0") +__msg("mark_precise: frame0: regs=r6 stack= before 16: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 15: (b7) r0 = 0") +__msg("mark_precise: frame1: regs= stack= before 9: (85) call bpf_loop#181") +__msg("mark_precise: frame0: regs=r6 stack= before 8: (b7) r4 = 0") +__msg("mark_precise: frame0: regs=r6 stack= before 7: (b7) r3 = 0") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r2 = r8") +__msg("mark_precise: frame0: regs=r6 stack= before 5: (b7) r1 = 1") +__msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3") +__naked int parent_callee_saved_reg_precise_with_callback(void) +{ + asm volatile ( + "r6 = 3;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 1;" /* nr_loops */ + "r2 = %[callback_subprog];" /* callback_fn */ + "r3 = 0;" /* callback_ctx */ + "r4 = 0;" /* flags */ + "call %[bpf_loop];" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) callback call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals), + __imm_ptr(callback_subprog), + __imm(bpf_loop) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("9: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 9 first_idx 6") +__msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: parent state regs= stack=-8:") +__msg("mark_precise: frame0: last_idx 13 first_idx 0") +__msg("mark_precise: frame0: regs= stack=-8 before 13: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 12: (bf) r0 = r1") +__msg("mark_precise: frame1: regs= stack= before 5: (85) call pc+6") +__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0") +__msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int parent_stack_slot_precise(void) +{ + asm volatile ( + /* spill reg */ + "r6 = 3;" + "*(u64 *)(r10 - 8) = r6;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 0;" + "call identity_subprog;" + + /* restore reg from stack; in this case we'll be carrying + * stack mask when going back into subprog through jump + * history + */ + "r6 = *(u64 *)(r10 - 8);" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("9: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 9 first_idx 6") +__msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: parent state regs= stack=-8:") +__msg("mark_precise: frame0: last_idx 5 first_idx 0") +__msg("mark_precise: frame0: regs= stack=-8 before 5: (85) call pc+6") +__msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0") +__msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3") +__naked int parent_stack_slot_precise_global(void) +{ + asm volatile ( + /* spill reg */ + "r6 = 3;" + "*(u64 *)(r10 - 8) = r6;" + + /* call subprog and ignore result; we need this call only to + * complicate jump history + */ + "r1 = 0;" + "call global_identity_subprog;" + + /* restore reg from stack; in this case we'll be carrying + * stack mask when going back into subprog through jump + * history + */ + "r6 = *(u64 *)(r10 - 8);" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("14: (0f) r1 += r6") +__msg("mark_precise: frame0: last_idx 14 first_idx 11") +__msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7") +__msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4") +__msg("mark_precise: frame0: regs=r6 stack= before 11: (79) r6 = *(u64 *)(r10 -8)") +__msg("mark_precise: frame0: parent state regs= stack=-8:") +__msg("mark_precise: frame0: last_idx 18 first_idx 0") +__msg("mark_precise: frame0: regs= stack=-8 before 18: (95) exit") +__msg("mark_precise: frame1: regs= stack= before 17: (b7) r0 = 0") +__msg("mark_precise: frame1: regs= stack= before 10: (85) call bpf_loop#181") +__msg("mark_precise: frame0: regs= stack=-8 before 9: (b7) r4 = 0") +__msg("mark_precise: frame0: regs= stack=-8 before 8: (b7) r3 = 0") +__msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r2 = r8") +__msg("mark_precise: frame0: regs= stack=-8 before 6: (bf) r1 = r6") +__msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -8) = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3") +__naked int parent_stack_slot_precise_with_callback(void) +{ + asm volatile ( + /* spill reg */ + "r6 = 3;" + "*(u64 *)(r10 - 8) = r6;" + + /* ensure we have callback frame in jump history */ + "r1 = r6;" /* nr_loops */ + "r2 = %[callback_subprog];" /* callback_fn */ + "r3 = 0;" /* callback_ctx */ + "r4 = 0;" /* flags */ + "call %[bpf_loop];" + + /* restore reg from stack; in this case we'll be carrying + * stack mask when going back into subprog through jump + * history + */ + "r6 = *(u64 *)(r10 - 8);" + + "r6 *= 4;" + "r1 = %[vals];" + /* here r6 is forced to be precise and has to be propagated + * back to the beginning, handling (and ignoring) subprog call + */ + "r1 += r6;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals), + __imm_ptr(callback_subprog), + __imm(bpf_loop) + : __clobber_common, "r6" + ); +} + +__noinline __used +static __u64 subprog_with_precise_arg(__u64 x) +{ + return vals[x]; /* x is forced to be precise */ +} + +SEC("?raw_tp") +__success __log_level(2) +__msg("8: (0f) r2 += r1") +__msg("mark_precise: frame1: last_idx 8 first_idx 0") +__msg("mark_precise: frame1: regs=r1 stack= before 6: (18) r2 = ") +__msg("mark_precise: frame1: regs=r1 stack= before 5: (67) r1 <<= 2") +__msg("mark_precise: frame1: regs=r1 stack= before 2: (85) call pc+2") +__msg("mark_precise: frame0: regs=r1 stack= before 1: (bf) r1 = r6") +__msg("mark_precise: frame0: regs=r6 stack= before 0: (b7) r6 = 3") +__naked int subprog_arg_precise(void) +{ + asm volatile ( + "r6 = 3;" + "r1 = r6;" + /* subprog_with_precise_arg expects its argument to be + * precise, so r1->r6 will be marked precise from inside the + * subprog + */ + "call subprog_with_precise_arg;" + "r0 += r6;" + "exit;" + : + : + : __clobber_common, "r6" + ); +} + +/* r1 is pointer to stack slot; + * r2 is a register to spill into that slot + * subprog also spills r2 into its own stack slot + */ +__naked __noinline __used +static __u64 subprog_spill_reg_precise(void) +{ + asm volatile ( + /* spill to parent stack */ + "*(u64 *)(r1 + 0) = r2;" + /* spill to subprog stack (we use -16 offset to avoid + * accidental confusion with parent's -8 stack slot in + * verifier log output) + */ + "*(u64 *)(r10 - 16) = r2;" + /* use both spills as return result to propagete precision everywhere */ + "r0 = *(u64 *)(r10 - 16);" + "r2 = *(u64 *)(r1 + 0);" + "r0 += r2;" + "exit;" + ); +} + +SEC("?raw_tp") +__success __log_level(2) +/* precision backtracking can't currently handle stack access not through r10, + * so we won't be able to mark stack slot fp-8 as precise, and so will + * fallback to forcing all as precise + */ +__msg("mark_precise: frame0: falling back to forcing all scalars precise") +__naked int subprog_spill_into_parent_stack_slot_precise(void) +{ + asm volatile ( + "r6 = 1;" + + /* pass pointer to stack slot and r6 to subprog; + * r6 will be marked precise and spilled into fp-8 slot, which + * also should be marked precise + */ + "r1 = r10;" + "r1 += -8;" + "r2 = r6;" + "call subprog_spill_reg_precise;" + + /* restore reg from stack; in this case we'll be carrying + * stack mask when going back into subprog through jump + * history + */ + "r7 = *(u64 *)(r10 - 8);" + + "r7 *= 4;" + "r1 = %[vals];" + /* here r7 is forced to be precise and has to be propagated + * back to the beginning, handling subprog call and logic + */ + "r1 += r7;" + "r0 = *(u32 *)(r1 + 0);" + "exit;" + : + : __imm_ptr(vals) + : __clobber_common, "r6", "r7" + ); +} + +__naked __noinline __used +static __u64 subprog_with_checkpoint(void) +{ + asm volatile ( + "r0 = 0;" + /* guaranteed checkpoint if BPF_F_TEST_STATE_FREQ is used */ + "goto +0;" + "exit;" + ); +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From c91ab90cea7ae61334c7026daf310f5875dfdee7 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 4 May 2023 21:33:17 -0700 Subject: selftests/bpf: revert iter test subprog precision workaround Now that precision propagation is supported fully in the presence of subprogs, there is no need to work around iter test. Revert original workaround. This reverts be7dbd275dc6 ("selftests/bpf: avoid mark_all_scalars_precise() trigger in one of iter tests"). Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230505043317.3629845-11-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/iters.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c index be16143ae292..6b9b3c56f009 100644 --- a/tools/testing/selftests/bpf/progs/iters.c +++ b/tools/testing/selftests/bpf/progs/iters.c @@ -651,29 +651,25 @@ int iter_stack_array_loop(const void *ctx) return sum; } -#define ARR_SZ 16 - -static __noinline void fill(struct bpf_iter_num *it, int *arr, int mul) +static __noinline void fill(struct bpf_iter_num *it, int *arr, __u32 n, int mul) { - int *t; - __u64 i; + int *t, i; while ((t = bpf_iter_num_next(it))) { i = *t; - if (i >= ARR_SZ) + if (i >= n) break; arr[i] = i * mul; } } -static __noinline int sum(struct bpf_iter_num *it, int *arr) +static __noinline int sum(struct bpf_iter_num *it, int *arr, __u32 n) { - int *t, sum = 0;; - __u64 i; + int *t, i, sum = 0;; while ((t = bpf_iter_num_next(it))) { i = *t; - if (i >= ARR_SZ) + if (i >= n) break; sum += arr[i]; } @@ -685,7 +681,7 @@ SEC("raw_tp") __success int iter_pass_iter_ptr_to_subprog(const void *ctx) { - int arr1[ARR_SZ], arr2[ARR_SZ]; + int arr1[16], arr2[32]; struct bpf_iter_num it; int n, sum1, sum2; @@ -694,25 +690,25 @@ int iter_pass_iter_ptr_to_subprog(const void *ctx) /* fill arr1 */ n = ARRAY_SIZE(arr1); bpf_iter_num_new(&it, 0, n); - fill(&it, arr1, 2); + fill(&it, arr1, n, 2); bpf_iter_num_destroy(&it); /* fill arr2 */ n = ARRAY_SIZE(arr2); bpf_iter_num_new(&it, 0, n); - fill(&it, arr2, 10); + fill(&it, arr2, n, 10); bpf_iter_num_destroy(&it); /* sum arr1 */ n = ARRAY_SIZE(arr1); bpf_iter_num_new(&it, 0, n); - sum1 = sum(&it, arr1); + sum1 = sum(&it, arr1, n); bpf_iter_num_destroy(&it); /* sum arr2 */ n = ARRAY_SIZE(arr2); bpf_iter_num_new(&it, 0, n); - sum2 = sum(&it, arr2); + sum2 = sum(&it, arr2, n); bpf_iter_num_destroy(&it); bpf_printk("sum1=%d, sum2=%d", sum1, sum2); -- cgit v1.2.3 From ac48499e2bf5b06e09e256039e56e695e9c2c667 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:16 +0200 Subject: wifi: rtl8xxxu: Add start_ap() callback This gets called at the start of AP mode operation. Set bssid, beacon interval and send a connect report to the HW. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-2-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 8eafbf1cee71..9cd6d171e993 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1727,6 +1727,7 @@ struct rtl8xxxu_cfo_tracking { }; #define RTL8XXXU_HW_LED_CONTROL 2 +#define RTL8XXXU_BC_MC_MACID 0 struct rtl8xxxu_priv { struct ieee80211_hw *hw; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index fd8c8c6d53d6..b8fcf911c072 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4968,6 +4968,20 @@ error: return; } +static int rtl8xxxu_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct device *dev = &priv->udev->dev; + + dev_dbg(dev, "Start AP mode\n"); + rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid); + rtl8xxxu_write16(priv, REG_BCN_INTERVAL, vif->bss_conf.beacon_int); + priv->fops->report_connect(priv, RTL8XXXU_BC_MC_MACID, true); + + return 0; +} + static u32 rtl8xxxu_80211_to_rtl_queue(u32 queue) { u32 rtlqueue; @@ -7093,6 +7107,7 @@ static const struct ieee80211_ops rtl8xxxu_ops = { .config = rtl8xxxu_config, .conf_tx = rtl8xxxu_conf_tx, .bss_info_changed = rtl8xxxu_bss_info_changed, + .start_ap = rtl8xxxu_start_ap, .configure_filter = rtl8xxxu_configure_filter, .set_rts_threshold = rtl8xxxu_set_rts_threshold, .start = rtl8xxxu_start, -- cgit v1.2.3 From 25ed009cc0aafd946008e323da5da43311ed4ac7 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:17 +0200 Subject: wifi: rtl8xxxu: Select correct queue for beacon frames Use the special beacon queue for beacon frames instead of the management frame queue. They will be put in a special area called reserved page and send out periodically when in AP mode. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-3-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index b8fcf911c072..9dc6f3ec7a30 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5010,7 +5010,9 @@ static u32 rtl8xxxu_queue_select(struct ieee80211_hdr *hdr, struct sk_buff *skb) { u32 queue; - if (ieee80211_is_mgmt(hdr->frame_control)) + if (unlikely(ieee80211_is_beacon(hdr->frame_control))) + queue = TXDESC_QUEUE_BEACON; + else if (ieee80211_is_mgmt(hdr->frame_control)) queue = TXDESC_QUEUE_MGNT; else queue = rtl8xxxu_80211_to_rtl_queue(skb_get_queue_mapping(skb)); -- cgit v1.2.3 From cde8848cad0bb4f03388f07d65e5fa0e8d35861b Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:18 +0200 Subject: wifi: rtl8xxxu: Add beacon functions Add a workqueue to update the beacon contents asynchronously and implement downloading the beacon to the HW and starting beacon tx like the vendor driver. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-4-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 75 ++++++++++++++++++++++ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 3 + 3 files changed, 79 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 9cd6d171e993..971f1cc38d32 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1851,6 +1851,7 @@ struct rtl8xxxu_priv { struct delayed_work ra_watchdog; struct work_struct c2hcmd_work; struct sk_buff_head c2hcmd_queue; + struct work_struct update_beacon_work; struct rtl8xxxu_btcoex bt_coex; struct rtl8xxxu_ra_report ra_report; struct rtl8xxxu_cfo_tracking cfo_tracking; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 9dc6f3ec7a30..a152e5c9ea69 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -1185,6 +1185,20 @@ static void rtl8xxxu_stop_tx_beacon(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 2, val8); } +static void rtl8xxxu_start_tx_beacon(struct rtl8xxxu_priv *priv) +{ + u8 val8; + + val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2); + val8 |= EN_BCNQ_DL >> 16; + rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8); + + rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 1, 0x80); + val8 = rtl8xxxu_read8(priv, REG_TBTT_PROHIBIT + 2); + val8 &= 0xF0; + rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 2, val8); +} + /* * The rtl8723a has 3 channel groups for it's efuse settings. It only @@ -4964,6 +4978,17 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, dev_dbg(dev, "Changed BASIC_RATES!\n"); rtl8xxxu_set_basic_rates(priv, bss_conf->basic_rates); } + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (bss_conf->enable_beacon) + rtl8xxxu_start_tx_beacon(priv); + else + rtl8xxxu_stop_tx_beacon(priv); + } + + if (changed & BSS_CHANGED_BEACON) + schedule_work(&priv->update_beacon_work); + error: return; } @@ -5545,6 +5570,55 @@ error: dev_kfree_skb(skb); } +static void rtl8xxxu_send_beacon_frame(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtl8xxxu_priv *priv = hw->priv; + struct sk_buff *skb = ieee80211_beacon_get(hw, vif, 0); + struct device *dev = &priv->udev->dev; + int retry; + u8 val8; + + /* BCN_VALID, write 1 to clear, cleared by SW */ + val8 = rtl8xxxu_read8(priv, REG_TDECTRL + 2); + val8 |= BIT_BCN_VALID >> 16; + rtl8xxxu_write8(priv, REG_TDECTRL + 2, val8); + + /* SW_BCN_SEL - Port0 */ + val8 = rtl8xxxu_read8(priv, REG_DWBCN1_CTRL_8723B + 2); + val8 &= ~(BIT_SW_BCN_SEL >> 16); + rtl8xxxu_write8(priv, REG_DWBCN1_CTRL_8723B + 2, val8); + + if (skb) + rtl8xxxu_tx(hw, NULL, skb); + + retry = 100; + do { + val8 = rtl8xxxu_read8(priv, REG_TDECTRL + 2); + if (val8 & (BIT_BCN_VALID >> 16)) + break; + usleep_range(10, 20); + } while (--retry); + + if (!retry) + dev_err(dev, "%s: Failed to read beacon valid bit\n", __func__); +} + +static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work) +{ + struct rtl8xxxu_priv *priv = + container_of(work, struct rtl8xxxu_priv, update_beacon_work); + struct ieee80211_hw *hw = priv->hw; + struct ieee80211_vif *vif = priv->vif; + + if (!vif) { + WARN_ONCE(true, "no vif to update beacon\n"); + return; + } + + rtl8xxxu_send_beacon_frame(hw, vif); +} + void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv, struct ieee80211_rx_status *rx_status, struct rtl8723au_phy_stats *phy_stats, @@ -7311,6 +7385,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, spin_lock_init(&priv->rx_urb_lock); INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback); + INIT_WORK(&priv->update_beacon_work, rtl8xxxu_update_beacon_work_callback); skb_queue_head_init(&priv->c2hcmd_queue); usb_set_intfdata(interface, hw); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 4dffbab494c3..ad285e4ac0ec 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -456,6 +456,7 @@ #define REG_FIFOPAGE 0x0204 #define REG_TDECTRL 0x0208 +#define BIT_BCN_VALID BIT(16) #define REG_DWBCN0_CTRL_8188F REG_TDECTRL @@ -470,6 +471,7 @@ #define AUTO_LLT_INIT_LLT BIT(16) #define REG_DWBCN1_CTRL_8723B 0x0228 +#define BIT_SW_BCN_SEL BIT(20) /* 0x0280 ~ 0x02FF RXDMA Configuration */ #define REG_RXDMA_AGG_PG_TH 0x0280 /* 0-7 : USB DMA size bits @@ -516,6 +518,7 @@ #define REG_FWHW_TXQ_CTRL 0x0420 #define FWHW_TXQ_CTRL_AMPDU_RETRY BIT(7) #define FWHW_TXQ_CTRL_XMIT_MGMT_ACK BIT(12) +#define EN_BCNQ_DL BIT(22) #define REG_HWSEQ_CTRL 0x0423 #define REG_TXPKTBUF_BCNQ_BDNY 0x0424 -- cgit v1.2.3 From f5db4d11fda182eea4e639e80b0404f7b8a43c01 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:19 +0200 Subject: wifi: rtl8xxxu: Add set_tim() callback Update beacon content if TIM bitmap maintained by mac80211 is changed. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-5-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index a152e5c9ea69..37794739c71c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4503,6 +4503,16 @@ int rtl8xxxu_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } +static int rtl8xxxu_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + bool set) +{ + struct rtl8xxxu_priv *priv = hw->priv; + + schedule_work(&priv->update_beacon_work); + + return 0; +} + static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac) { @@ -7194,6 +7204,7 @@ static const struct ieee80211_ops rtl8xxxu_ops = { .ampdu_action = rtl8xxxu_ampdu_action, .sta_statistics = rtl8xxxu_sta_statistics, .get_antenna = rtl8xxxu_get_antenna, + .set_tim = rtl8xxxu_set_tim, }; static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv, -- cgit v1.2.3 From 20d59515489442e8899158514f9997662cb47ce5 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:20 +0200 Subject: wifi: rtl8xxxu: Allow setting rts threshold to -1 The default setting in hostapd.conf for rts threshold is -1, which means disabled. Allow to set it. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-6-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 37794739c71c..9d08a1c8c3b3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6655,7 +6655,7 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts) { - if (rts > 2347) + if (rts > 2347 && rts != (u32)-1) return -EINVAL; return 0; -- cgit v1.2.3 From fd5440f9311fa8ebeded0551be90a972118b1598 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:21 +0200 Subject: wifi: rtl8xxxu: Allow creating interface in AP mode Use the sequence from the vendor driver for setting up the beacon related registers. Also set the MAC address register here, in case the MAC address for the new interface should be different from what was set in rtl8xxxu_init_device(). This happens for example with the hostapd config option "bssid". Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-7-martin.kaistra@linutronix.de --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 31 +++++++++++++++++++--- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 ++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 9d08a1c8c3b3..ab4a1f83c760 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6471,18 +6471,39 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, int ret; u8 val8; + if (!priv->vif) + priv->vif = vif; + else + return -EOPNOTSUPP; + switch (vif->type) { case NL80211_IFTYPE_STATION: - if (!priv->vif) - priv->vif = vif; - else - return -EOPNOTSUPP; rtl8xxxu_stop_tx_beacon(priv); val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE | BEACON_DISABLE_TSF_UPDATE; rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); + ret = 0; + break; + case NL80211_IFTYPE_AP: + rtl8xxxu_write8(priv, REG_BEACON_CTRL, + BEACON_DISABLE_TSF_UPDATE | BEACON_CTRL_MBSSID); + rtl8xxxu_write8(priv, REG_ATIMWND, 0x0c); /* 12ms */ + rtl8xxxu_write16(priv, REG_TSFTR_SYN_OFFSET, 0x7fff); /* ~32ms */ + rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, DUAL_TSF_RESET_TSF0); + + /* enable BCN0 function */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, + BEACON_DISABLE_TSF_UPDATE | + BEACON_FUNCTION_ENABLE | BEACON_CTRL_MBSSID | + BEACON_CTRL_TX_BEACON_RPT); + + /* select BCN on port 0 */ + val8 = rtl8xxxu_read8(priv, REG_CCK_CHECK); + val8 &= ~BIT_BCN_PORT_SEL; + rtl8xxxu_write8(priv, REG_CCK_CHECK, val8); + ret = 0; break; default: @@ -6490,6 +6511,8 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, } rtl8xxxu_set_linktype(priv, vif->type); + ether_addr_copy(priv->mac_addr, vif->addr); + rtl8xxxu_set_mac(priv); return ret; } diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index ad285e4ac0ec..8571d5129f32 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -575,6 +575,8 @@ #define REG_ARFR1 0x0448 #define REG_ARFR2 0x044c #define REG_ARFR3 0x0450 +#define REG_CCK_CHECK 0x0454 +#define BIT_BCN_PORT_SEL BIT(5) #define REG_AMPDU_MAX_TIME_8723B 0x0456 #define REG_AGGLEN_LMT 0x0458 #define REG_AMPDU_MIN_SPACE 0x045c -- cgit v1.2.3 From d59a105acc03e1f36b522017e57cccae2243abe2 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:22 +0200 Subject: wifi: rtl8xxxu: Actually use macid in rtl8xxxu_gen2_report_connect The report_connect function has had a macid parameter from the beginning, but it has not been used, because in STA mode, the value was always zero. As it can now have different values in AP mode, actually wire it up to the H2C command. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-8-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index ab4a1f83c760..66e196f7416e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4619,6 +4619,8 @@ void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, else h2c.media_status_rpt.parm &= ~BIT(0); + h2c.media_status_rpt.macid = macid; + rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt)); } -- cgit v1.2.3 From 2be2eed4c39b962df15c33813f741e0f8f68fd65 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:23 +0200 Subject: wifi: rtl8xxxu: Add parameter role to report_connect This allows to tell the HW if a connection is made to a STA or an AP. Add the implementation for the gen2 version. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-9-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 9 ++++++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 11 ++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 971f1cc38d32..2dc9b205f08c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1280,6 +1280,9 @@ struct rtl8xxxu_rfregs { #define H2C_JOIN_BSS_DISCONNECT 0 #define H2C_JOIN_BSS_CONNECT 1 +#define H2C_MACID_ROLE_STA 1 +#define H2C_MACID_ROLE_AP 2 + /* * H2C (firmware) commands differ between the older generation chips * 8188[cr]u, 819[12]cu, and 8723au, and the more recent chips 8723bu, @@ -1906,7 +1909,7 @@ struct rtl8xxxu_fileops { void (*update_rate_mask) (struct rtl8xxxu_priv *priv, u32 ramask, u8 rateid, int sgi, int txbw_40mhz); void (*report_connect) (struct rtl8xxxu_priv *priv, - u8 macid, bool connect); + u8 macid, u8 role, bool connect); void (*report_rssi) (struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, @@ -2027,9 +2030,9 @@ void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, u32 ramask, u8 rateid, int sgi, int txbw_40mhz); void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, - u8 macid, bool connect); + u8 macid, u8 role, bool connect); void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, - u8 macid, bool connect); + u8 macid, u8 role, bool connect); void rtl8xxxu_gen1_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); void rtl8xxxu_gen2_report_rssi(struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 66e196f7416e..0e951dee127e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4586,7 +4586,7 @@ void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, } void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, - u8 macid, bool connect) + u8 macid, u8 role, bool connect) { struct h2c_cmd h2c; @@ -4603,7 +4603,7 @@ void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, } void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, - u8 macid, bool connect) + u8 macid, u8 role, bool connect) { /* * The firmware turns on the rate control when it knows it's @@ -4619,6 +4619,7 @@ void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, else h2c.media_status_rpt.parm &= ~BIT(0); + h2c.media_status_rpt.parm |= ((role << 4) & 0xf0); h2c.media_status_rpt.macid = macid; rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt)); @@ -4947,13 +4948,13 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_write16(priv, REG_BCN_PSR_RPT, 0xc000 | vif->cfg.aid); - priv->fops->report_connect(priv, 0, true); + priv->fops->report_connect(priv, 0, H2C_MACID_ROLE_AP, true); } else { val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); val8 |= BEACON_DISABLE_TSF_UPDATE; rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); - priv->fops->report_connect(priv, 0, false); + priv->fops->report_connect(priv, 0, H2C_MACID_ROLE_AP, false); } } @@ -5014,7 +5015,7 @@ static int rtl8xxxu_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, dev_dbg(dev, "Start AP mode\n"); rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid); rtl8xxxu_write16(priv, REG_BCN_INTERVAL, vif->bss_conf.beacon_int); - priv->fops->report_connect(priv, RTL8XXXU_BC_MC_MACID, true); + priv->fops->report_connect(priv, RTL8XXXU_BC_MC_MACID, 0, true); return 0; } -- cgit v1.2.3 From 40d02ff2b1868dbf3c3f33aadfe4200b6614f52b Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:24 +0200 Subject: wifi: rtl8xxxu: Add parameter force to rtl8xxxu_refresh_rate_mask In AP mode, when multiple STAs connect to us, we need to set an initial rate mask for each of them. This initialisation should happen regardless of the rssi_level saved in the priv struct. Add a parameter called force to rtl8xxxu_refresh_rate_mask() which will be used for this initialisation. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-10-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 0e951dee127e..a3ca6ea9b2d6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6830,7 +6830,8 @@ static u8 rtl8xxxu_signal_to_snr(int signal) } static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, - int signal, struct ieee80211_sta *sta) + int signal, struct ieee80211_sta *sta, + bool force) { struct ieee80211_hw *hw = priv->hw; u16 wireless_mode; @@ -6864,7 +6865,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, else rssi_level = RTL8XXXU_RATR_STA_LOW; - if (rssi_level != priv->rssi_level) { + if (rssi_level != priv->rssi_level || force) { int sgi = 0; u32 rate_bitmap = 0; @@ -7080,7 +7081,7 @@ static void rtl8xxxu_watchdog_callback(struct work_struct *work) if (priv->fops->set_crystal_cap) rtl8xxxu_track_cfo(priv); - rtl8xxxu_refresh_rate_mask(priv, signal, sta); + rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); } out: -- cgit v1.2.3 From 726e478ce1b3f8738c4e6f6a9683b64dcfb5b219 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:25 +0200 Subject: wifi: rtl8xxxu: Add sta_add() and sta_remove() callbacks In AP mode, sta_add() gets called when a new STA gets associated to us. Call rtl8xxxu_refresh_rate_mask() to set a rate mask for the newly connected STA (referenced by the macid) and then send a media connnect report. Ignore the call to sta_add() in station mode. Reserve one macid for broadcast/multicast packets in init. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-11-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 9 ++++ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 52 ++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 2dc9b205f08c..a918d1283d1e 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1730,6 +1730,7 @@ struct rtl8xxxu_cfo_tracking { }; #define RTL8XXXU_HW_LED_CONTROL 2 +#define RTL8XXXU_MAX_MAC_ID_NUM 128 #define RTL8XXXU_BC_MC_MACID 0 struct rtl8xxxu_priv { @@ -1863,6 +1864,14 @@ struct rtl8xxxu_priv { bool led_registered; char led_name[32]; struct led_classdev led_cdev; + DECLARE_BITMAP(mac_id_map, RTL8XXXU_MAX_MAC_ID_NUM); +}; + +struct rtl8xxxu_sta_info { + struct ieee80211_sta *sta; + struct ieee80211_vif *vif; + + u8 macid; }; struct rtl8xxxu_rx_urb { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index a3ca6ea9b2d6..dd678f280389 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3977,6 +3977,22 @@ void rtl8xxxu_init_burst(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_RSV_CTRL, val8); } +static u8 rtl8xxxu_acquire_macid(struct rtl8xxxu_priv *priv) +{ + u8 macid; + + macid = find_first_zero_bit(priv->mac_id_map, RTL8XXXU_MAX_MAC_ID_NUM); + if (macid < RTL8XXXU_MAX_MAC_ID_NUM) + set_bit(macid, priv->mac_id_map); + + return macid; +} + +static void rtl8xxxu_release_macid(struct rtl8xxxu_priv *priv, u8 macid) +{ + clear_bit(macid, priv->mac_id_map); +} + static int rtl8xxxu_init_device(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -4446,6 +4462,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (priv->rtl_chip == RTL8188E) rtl8188e_ra_info_init_all(&priv->ra_info); + set_bit(RTL8XXXU_BC_MC_MACID, priv->mac_id_map); + exit: return ret; } @@ -7212,6 +7230,38 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) rtl8xxxu_free_tx_resources(priv); } +static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + struct rtl8xxxu_priv *priv = hw->priv; + + if (vif->type == NL80211_IFTYPE_AP) { + sta_info->macid = rtl8xxxu_acquire_macid(priv); + if (sta_info->macid >= RTL8XXXU_MAX_MAC_ID_NUM) + return -ENOSPC; + + rtl8xxxu_refresh_rate_mask(priv, 0, sta, true); + priv->fops->report_connect(priv, sta_info->macid, H2C_MACID_ROLE_STA, true); + } + + return 0; +} + +static int rtl8xxxu_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + struct rtl8xxxu_priv *priv = hw->priv; + + if (vif->type == NL80211_IFTYPE_AP) + rtl8xxxu_release_macid(priv, sta_info->macid); + + return 0; +} + static const struct ieee80211_ops rtl8xxxu_ops = { .tx = rtl8xxxu_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, @@ -7232,6 +7282,8 @@ static const struct ieee80211_ops rtl8xxxu_ops = { .sta_statistics = rtl8xxxu_sta_statistics, .get_antenna = rtl8xxxu_get_antenna, .set_tim = rtl8xxxu_set_tim, + .sta_add = rtl8xxxu_sta_add, + .sta_remove = rtl8xxxu_sta_remove, }; static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv, -- cgit v1.2.3 From 9aa45598d0540b7797673bb29d458ec16e42513d Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:26 +0200 Subject: wifi: rtl8xxxu: Put the macid in txdesc Add a parameter macid to fill_txdesc(), implement setting it for the gen2 version. This is used to tell the HW who the recipient of the packet is, so that the appropriate data rate can be selected. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-12-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 8 +++---- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 28 ++++++++++++++++++---- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index a918d1283d1e..688168e0723c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1924,7 +1924,7 @@ struct rtl8xxxu_fileops { struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, bool short_preamble, bool ampdu_enable, - u32 rts_rate); + u32 rts_rate, u8 macid); void (*set_crystal_cap) (struct rtl8xxxu_priv *priv, u8 crystal_cap); s8 (*cck_rssi) (struct rtl8xxxu_priv *priv, struct rtl8723au_phy_stats *phy_stats); int (*led_classdev_brightness_set) (struct led_classdev *led_cdev, @@ -2070,17 +2070,17 @@ void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, bool short_preamble, bool ampdu_enable, - u32 rts_rate); + u32 rts_rate, u8 macid); void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, bool short_preamble, bool ampdu_enable, - u32 rts_rate); + u32 rts_rate, u8 macid); void rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, bool short_preamble, bool ampdu_enable, - u32 rts_rate); + u32 rts_rate, u8 macid); void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5); void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index dd678f280389..dfb24de81197 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3993,6 +3993,18 @@ static void rtl8xxxu_release_macid(struct rtl8xxxu_priv *priv, u8 macid) clear_bit(macid, priv->mac_id_map); } +static inline u8 rtl8xxxu_get_macid(struct rtl8xxxu_priv *priv, + struct ieee80211_sta *sta) +{ + struct rtl8xxxu_sta_info *sta_info; + + if (!priv->vif || priv->vif->type == NL80211_IFTYPE_STATION || !sta) + return 0; + + sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + return sta_info->macid; +} + static int rtl8xxxu_init_device(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -5231,7 +5243,8 @@ void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, - bool short_preamble, bool ampdu_enable, u32 rts_rate) + bool short_preamble, bool ampdu_enable, u32 rts_rate, + u8 macid) { struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; @@ -5303,7 +5316,8 @@ void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, - bool short_preamble, bool ampdu_enable, u32 rts_rate) + bool short_preamble, bool ampdu_enable, u32 rts_rate, + u8 macid) { struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; @@ -5327,6 +5341,8 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, dev_info(dev, "%s: TX rate: %d, pkt size %u\n", __func__, rate, le16_to_cpu(tx_desc40->pkt_size)); + tx_desc40->txdw1 |= cpu_to_le32(macid << TXDESC40_MACID_SHIFT); + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); tx_desc40->txdw4 = cpu_to_le32(rate); @@ -5378,7 +5394,8 @@ void rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct ieee80211_tx_info *tx_info, struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, - bool short_preamble, bool ampdu_enable, u32 rts_rate) + bool short_preamble, bool ampdu_enable, u32 rts_rate, + u8 macid) { struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; @@ -5477,6 +5494,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, u16 pktlen = skb->len; u16 rate_flag = tx_info->control.rates[0].flags; int tx_desc_size = priv->fops->tx_desc_size; + u8 macid; int ret; bool ampdu_enable, sgi = false, short_preamble = false; @@ -5576,9 +5594,9 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, else rts_rate = 0; - + macid = rtl8xxxu_get_macid(priv, sta); priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble, - ampdu_enable, rts_rate); + ampdu_enable, rts_rate, macid); rtl8xxxu_calc_tx_desc_csum(tx_desc); -- cgit v1.2.3 From 769f326322e7328eeedc94fd33979683347fa7c7 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:27 +0200 Subject: wifi: rtl8xxxu: Add parameter macid to update_rate_mask The HW maintains a rate_mask for each connection, referenced by the macid. Add a parameter to update_rate_mask and add the macid to the h2c call in the gen2 implementation. Also extend refresh_rate_mask to get the macid from sta_info. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-13-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 7 ++++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c | 3 ++- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 13 +++++++++---- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 688168e0723c..1cf2ea4b0265 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1916,7 +1916,8 @@ struct rtl8xxxu_fileops { void (*set_tx_power) (struct rtl8xxxu_priv *priv, int channel, bool ht40); void (*update_rate_mask) (struct rtl8xxxu_priv *priv, - u32 ramask, u8 rateid, int sgi, int txbw_40mhz); + u32 ramask, u8 rateid, int sgi, int txbw_40mhz, + u8 macid); void (*report_connect) (struct rtl8xxxu_priv *priv, u8 macid, u8 role, bool connect); void (*report_rssi) (struct rtl8xxxu_priv *priv, u8 macid, u8 rssi); @@ -2035,9 +2036,9 @@ void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw); void rtl8xxxu_gen1_usb_quirks(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen2_usb_quirks(struct rtl8xxxu_priv *priv); void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, u8 rateid, int sgi, int txbw_40mhz); + u32 ramask, u8 rateid, int sgi, int txbw_40mhz, u8 macid); void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, u8 rateid, int sgi, int txbw_40mhz); + u32 ramask, u8 rateid, int sgi, int txbw_40mhz, u8 macid); void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, u8 macid, u8 role, bool connect); void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c index 8986783ae8fa..6d0f975f891b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c @@ -1794,7 +1794,8 @@ static void rtl8188e_arfb_refresh(struct rtl8xxxu_ra_info *ra) static void rtl8188e_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, u8 rateid, int sgi, int txbw_40mhz) + u32 ramask, u8 rateid, int sgi, int txbw_40mhz, + u8 macid) { struct rtl8xxxu_ra_info *ra = &priv->ra_info; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index dfb24de81197..61231be81665 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4566,7 +4566,8 @@ static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw, } void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, u8 rateid, int sgi, int txbw_40mhz) + u32 ramask, u8 rateid, int sgi, int txbw_40mhz, + u8 macid) { struct h2c_cmd h2c; @@ -4586,7 +4587,8 @@ void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, } void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, u8 rateid, int sgi, int txbw_40mhz) + u32 ramask, u8 rateid, int sgi, int txbw_40mhz, + u8 macid) { struct h2c_cmd h2c; u8 bw; @@ -4603,6 +4605,7 @@ void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, h2c.b_macid_cfg.ramask1 = (ramask >> 8) & 0xff; h2c.b_macid_cfg.ramask2 = (ramask >> 16) & 0xff; h2c.b_macid_cfg.ramask3 = (ramask >> 24) & 0xff; + h2c.b_macid_cfg.macid = macid; h2c.b_macid_cfg.data1 = rateid; if (sgi) @@ -4968,7 +4971,8 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, priv->vif = vif; priv->rssi_level = RTL8XXXU_RATR_STA_INIT; - priv->fops->update_rate_mask(priv, ramask, 0, sgi, bw == RATE_INFO_BW_40); + priv->fops->update_rate_mask(priv, ramask, 0, sgi, + bw == RATE_INFO_BW_40, 0); rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); @@ -6875,6 +6879,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, u8 txbw_40mhz; u8 snr, snr_thresh_high, snr_thresh_low; u8 go_up_gap = 5; + u8 macid = rtl8xxxu_get_macid(priv, sta); rssi_level = priv->rssi_level; snr = rtl8xxxu_signal_to_snr(signal); @@ -6994,7 +6999,7 @@ static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, } priv->rssi_level = rssi_level; - priv->fops->update_rate_mask(priv, rate_bitmap, ratr_idx, sgi, txbw_40mhz); + priv->fops->update_rate_mask(priv, rate_bitmap, ratr_idx, sgi, txbw_40mhz, macid); } } -- cgit v1.2.3 From 89819a6511441bac45f2f04f10880895e01a6ce7 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:28 +0200 Subject: wifi: rtl8xxxu: Enable hw seq for mgmt/non-QoS data frames Beacon frames are generated by the HW and therefore contain a HW generated seq number. Enable HW sequence number for other frames to match that. mac80211 will tell us via IEEE80211_TX_CTL_ASSIGN_SEQ when that is necessary. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-14-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 61231be81665..2e075094a37a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5370,6 +5370,9 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, tx_desc40->txdw4 |= cpu_to_le32(TXDESC40_RETRY_LIMIT_ENABLE); } + if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + tx_desc40->txdw8 |= cpu_to_le32(TXDESC40_HW_SEQ_ENABLE); + if (short_preamble) tx_desc40->txdw5 |= cpu_to_le32(TXDESC40_SHORT_PREAMBLE); -- cgit v1.2.3 From 66dcb574418eac0b09121d37ea0b52dede021887 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:29 +0200 Subject: wifi: rtl8xxxu: Clean up filter configuration When RCR_CHECK_BSSID_MATCH is set in AP mode, we don't receive any data frames. Rearrange RCR bits to filter flags to match other realtek drivers and remove RCR_CHECK_BSSID_MATCH in AP mode. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-15-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 2e075094a37a..9e9d172a37f1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6689,22 +6689,22 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, */ if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - rcr &= ~RCR_CHECK_BSSID_BEACON; + rcr &= ~(RCR_CHECK_BSSID_BEACON | RCR_CHECK_BSSID_MATCH); else - rcr |= RCR_CHECK_BSSID_BEACON; + rcr |= RCR_CHECK_BSSID_BEACON | RCR_CHECK_BSSID_MATCH; + + if (priv->vif && priv->vif->type == NL80211_IFTYPE_AP) + rcr &= ~RCR_CHECK_BSSID_MATCH; if (*total_flags & FIF_CONTROL) rcr |= RCR_ACCEPT_CTRL_FRAME; else rcr &= ~RCR_ACCEPT_CTRL_FRAME; - if (*total_flags & FIF_OTHER_BSS) { + if (*total_flags & FIF_OTHER_BSS) rcr |= RCR_ACCEPT_AP; - rcr &= ~RCR_CHECK_BSSID_MATCH; - } else { + else rcr &= ~RCR_ACCEPT_AP; - rcr |= RCR_CHECK_BSSID_MATCH; - } if (*total_flags & FIF_PSPOLL) rcr |= RCR_ACCEPT_PM; -- cgit v1.2.3 From 07342528f7c8b7ca156ee6d8c132e42579b37bb9 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:30 +0200 Subject: wifi: rtl8xxxu: Remove usage of ieee80211_get_tx_rate() As this driver uses HAS_RATE_CONTROL, tx_rates will not be provided by mac80211. For some frames c->control.rates[0].idx is negative, which means ieee80211_get_tx_rate() will print a warning and return NULL. Only management frames have USE_DRIVER_RATE set, so for all others the rate info of txdesc is ignored anyway. Remove call to ieee80211_get_tx_rate() and send management frames with 1M (rate info = 0). Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-16-martin.kaistra@linutronix.de --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 27 +++------------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 9e9d172a37f1..a2cc9177fba4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5250,21 +5250,14 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, bool short_preamble, bool ampdu_enable, u32 rts_rate, u8 macid) { - struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - u32 rate; + u32 rate = 0; u16 rate_flags = tx_info->control.rates[0].flags; u16 seq_number; - if (rate_flags & IEEE80211_TX_RC_MCS && - !ieee80211_is_mgmt(hdr->frame_control)) - rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; - else - rate = tx_rate->hw_value; - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) dev_info(dev, "%s: TX rate: %d, pkt size %u\n", __func__, rate, le16_to_cpu(tx_desc->pkt_size)); @@ -5323,24 +5316,17 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, bool short_preamble, bool ampdu_enable, u32 rts_rate, u8 macid) { - struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; struct rtl8xxxu_txdesc40 *tx_desc40; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - u32 rate; + u32 rate = 0; u16 rate_flags = tx_info->control.rates[0].flags; u16 seq_number; tx_desc40 = (struct rtl8xxxu_txdesc40 *)tx_desc32; - if (rate_flags & IEEE80211_TX_RC_MCS && - !ieee80211_is_mgmt(hdr->frame_control)) - rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; - else - rate = tx_rate->hw_value; - if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) dev_info(dev, "%s: TX rate: %d, pkt size %u\n", __func__, rate, le16_to_cpu(tx_desc40->pkt_size)); @@ -5404,22 +5390,15 @@ rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, bool short_preamble, bool ampdu_enable, u32 rts_rate, u8 macid) { - struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; struct rtl8xxxu_ra_info *ra = &priv->ra_info; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - u32 rate; + u32 rate = 0; u16 rate_flags = tx_info->control.rates[0].flags; u16 seq_number; - if (rate_flags & IEEE80211_TX_RC_MCS && - !ieee80211_is_mgmt(hdr->frame_control)) - rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; - else - rate = tx_rate->hw_value; - seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); if (ieee80211_is_data(hdr->frame_control)) { -- cgit v1.2.3 From 19b396c241cfdcb4431491d07ff586f78436754a Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:31 +0200 Subject: wifi: rtl8xxxu: Remove usage of tx_info->control.rates[0].flags As this driver uses HAS_RATE_CONTROL, rate_flags will not be provided by mac80211. Stop using tx_info->control.rates[0].flags and ieee80211_get_rts_cts_rate() and use rts_threshold and bss_conf.use_cts_prot instead to determine when to use RTS and CTS. Send RTS with 24M rate like the vendor drivers. Also set this RTS rate for ampdu_enable = true, because we also enable RTS for these frames. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-17-martin.kaistra@linutronix.de --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index a2cc9177fba4..aa430a912d82 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5255,7 +5255,6 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u32 rate = 0; - u16 rate_flags = tx_info->control.rates[0].flags; u16 seq_number; if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) @@ -5296,10 +5295,10 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled */ tx_desc->txdw4 |= cpu_to_le32(rts_rate << TXDESC32_RTS_RATE_SHIFT); - if (ampdu_enable || (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS)) { + if (ampdu_enable || tx_info->control.use_rts) { tx_desc->txdw4 |= cpu_to_le32(TXDESC32_RTS_CTS_ENABLE); tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); - } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + } else if (tx_info->control.use_cts_prot) { tx_desc->txdw4 |= cpu_to_le32(TXDESC32_CTS_SELF_ENABLE); tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); } @@ -5322,7 +5321,6 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u32 rate = 0; - u16 rate_flags = tx_info->control.rates[0].flags; u16 seq_number; tx_desc40 = (struct rtl8xxxu_txdesc40 *)tx_desc32; @@ -5363,13 +5361,14 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, tx_desc40->txdw5 |= cpu_to_le32(TXDESC40_SHORT_PREAMBLE); tx_desc40->txdw4 |= cpu_to_le32(rts_rate << TXDESC40_RTS_RATE_SHIFT); + /* * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled */ - if (ampdu_enable || (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS)) { + if (ampdu_enable || tx_info->control.use_rts) { tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_RTS_CTS_ENABLE); tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_HW_RTS_ENABLE); - } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + } else if (tx_info->control.use_cts_prot) { /* * For some reason the vendor driver doesn't set * TXDESC40_HW_RTS_ENABLE for CTS to SELF @@ -5396,7 +5395,6 @@ rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u32 rate = 0; - u16 rate_flags = tx_info->control.rates[0].flags; u16 seq_number; seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); @@ -5451,10 +5449,10 @@ rtl8xxxu_fill_txdesc_v3(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled */ tx_desc->txdw4 |= cpu_to_le32(rts_rate << TXDESC32_RTS_RATE_SHIFT); - if (ampdu_enable || (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS)) { + if (ampdu_enable || tx_info->control.use_rts) { tx_desc->txdw4 |= cpu_to_le32(TXDESC32_RTS_CTS_ENABLE); tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); - } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + } else if (tx_info->control.use_cts_prot) { tx_desc->txdw4 |= cpu_to_le32(TXDESC32_CTS_SELF_ENABLE); tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); } @@ -5478,7 +5476,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct device *dev = &priv->udev->dev; u32 queue, rts_rate; u16 pktlen = skb->len; - u16 rate_flag = tx_info->control.rates[0].flags; int tx_desc_size = priv->fops->tx_desc_size; u8 macid; int ret; @@ -5563,20 +5560,23 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, } } - if (rate_flag & IEEE80211_TX_RC_SHORT_GI || - (ieee80211_is_data_qos(hdr->frame_control) && - sta && sta->deflink.ht_cap.cap & - (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))) + if (ieee80211_is_data_qos(hdr->frame_control) && + sta && sta->deflink.ht_cap.cap & + (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20)) sgi = true; - if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE || - (sta && vif && vif->bss_conf.use_short_preamble)) + if (sta && vif && vif->bss_conf.use_short_preamble) short_preamble = true; - if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) - rts_rate = ieee80211_get_rts_cts_rate(hw, tx_info)->hw_value; - else if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) - rts_rate = ieee80211_get_rts_cts_rate(hw, tx_info)->hw_value; + if (skb->len > hw->wiphy->rts_threshold) + tx_info->control.use_rts = true; + + if (sta && vif && vif->bss_conf.use_cts_prot) + tx_info->control.use_cts_prot = true; + + if (ampdu_enable || tx_info->control.use_rts || + tx_info->control.use_cts_prot) + rts_rate = DESC_RATE_24M; else rts_rate = 0; -- cgit v1.2.3 From b468481c9ad39449695376efd381ce3737e32aab Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:32 +0200 Subject: wifi: rtl8xxxu: Declare AP mode support for 8188f Everything is in place now for AP mode, we can tell the system that we support it. Put the feature behind a flag in priv->fops, because it is not (yet) implemented for all chips. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-18-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 1cf2ea4b0265..296f34578468 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1943,6 +1943,7 @@ struct rtl8xxxu_fileops { u8 init_reg_hmtfr:1; u8 ampdu_max_time; u8 ustime_tsf_edca; + u8 supports_ap:1; u32 adda_1t_init; u32 adda_1t_path_on; u32 adda_2t_path_on_a; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index dbdfd7787465..7fd258bf65e3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -1748,6 +1748,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .init_reg_hmtfr = 1, .ampdu_max_time = 0x70, .ustime_tsf_edca = 0x28, + .supports_ap = 1, .adda_1t_init = 0x03c00014, .adda_1t_path_on = 0x03c00014, .trxff_boundary = 0x3f7f, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index aa430a912d82..71c715ec5608 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -7533,6 +7533,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->wiphy->max_scan_ssids = 1; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + if (priv->fops->supports_ap) + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); hw->queues = 4; sband = &rtl8xxxu_supported_band; -- cgit v1.2.3 From b9a07c443a82432c4679a5a026b53e1e454d9a40 Mon Sep 17 00:00:00 2001 From: Martin Kaistra Date: Fri, 28 Apr 2023 17:08:33 +0200 Subject: wifi: rtl8xxxu: Set maximum number of supported stations Set maximum number of associated stations supported in AP mode. For 8188f, the maximum number of supported macids is 16, reserve one for broadcast/multicast frames. Signed-off-by: Martin Kaistra Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428150833.218605-19-martin.kaistra@linutronix.de --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 296f34578468..2c756640f59d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1944,6 +1944,7 @@ struct rtl8xxxu_fileops { u8 ampdu_max_time; u8 ustime_tsf_edca; u8 supports_ap:1; + u16 max_macid_num; u32 adda_1t_init; u32 adda_1t_path_on; u32 adda_2t_path_on_a; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index 7fd258bf65e3..71b7f0d31bf4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -1749,6 +1749,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .ampdu_max_time = 0x70, .ustime_tsf_edca = 0x28, .supports_ap = 1, + .max_macid_num = 16, .adda_1t_init = 0x03c00014, .adda_1t_path_on = 0x03c00014, .trxff_boundary = 0x3f7f, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 71c715ec5608..67901b3ee896 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -7532,6 +7532,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->wiphy->max_scan_ssids = 1; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + if (priv->fops->max_macid_num) + hw->wiphy->max_ap_assoc_sta = priv->fops->max_macid_num - 1; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); if (priv->fops->supports_ap) hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); -- cgit v1.2.3 From 6dc28456aa172b6e4dcc8e0914026b4026ae0a05 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Tue, 25 Apr 2023 16:01:00 +0300 Subject: wifi: rtl8xxxu: Support USB RX aggregation for the newer chips The driver can receive several frames in the same USB transfer. Add the code to handle this in rtl8xxxu_parse_rxdesc24(), even though currently all the relevant chips send only one frame per USB transfer (RTL8723BU, RTL8192EU, RTL8188FU, RTL8710BU). This was tested with RTL8188FU, RTL8192EU, RTL8710BU, and RTL8192FU. Signed-off-by: Bitterblue Smith Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/16d2d1ff-6438-10c9-347f-6e14dd358ccf@gmail.com --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 119 ++++++++++++++------- 1 file changed, 78 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 67901b3ee896..b2b2f68e7273 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6322,61 +6322,98 @@ int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { struct ieee80211_hw *hw = priv->hw; - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct rtl8xxxu_rxdesc24 *rx_desc = - (struct rtl8xxxu_rxdesc24 *)skb->data; + struct ieee80211_rx_status *rx_status; + struct rtl8xxxu_rxdesc24 *rx_desc; struct rtl8723au_phy_stats *phy_stats; - __le32 *_rx_desc_le = (__le32 *)skb->data; - u32 *_rx_desc = (u32 *)skb->data; + struct sk_buff *next_skb = NULL; + __le32 *_rx_desc_le; + u32 *_rx_desc; int drvinfo_sz, desc_shift; - int i; + int i, pkt_len, urb_len, pkt_offset; - for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc24) / sizeof(u32)); i++) - _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); + urb_len = skb->len; - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); + if (urb_len < sizeof(struct rtl8xxxu_rxdesc24)) { + kfree_skb(skb); + return RX_TYPE_ERROR; + } - skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc24)); + do { + rx_desc = (struct rtl8xxxu_rxdesc24 *)skb->data; + _rx_desc_le = (__le32 *)skb->data; + _rx_desc = (u32 *)skb->data; - phy_stats = (struct rtl8723au_phy_stats *)skb->data; + for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc24) / sizeof(u32)); i++) + _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]); - drvinfo_sz = rx_desc->drvinfo_sz * 8; - desc_shift = rx_desc->shift; - skb_pull(skb, drvinfo_sz + desc_shift); + pkt_len = rx_desc->pktlen; - if (rx_desc->rpt_sel) { - struct device *dev = &priv->udev->dev; - dev_dbg(dev, "%s: C2H packet\n", __func__); - rtl8723bu_handle_c2h(priv, skb); - return RX_TYPE_C2H; - } + drvinfo_sz = rx_desc->drvinfo_sz * 8; + desc_shift = rx_desc->shift; + pkt_offset = roundup(pkt_len + drvinfo_sz + desc_shift + + sizeof(struct rtl8xxxu_rxdesc24), 8); + + /* + * Only clone the skb if there's enough data at the end to + * at least cover the rx descriptor + */ + if (urb_len >= (pkt_offset + sizeof(struct rtl8xxxu_rxdesc24))) + next_skb = skb_clone(skb, GFP_ATOMIC); - if (rx_desc->phy_stats) - priv->fops->parse_phystats(priv, rx_status, phy_stats, - rx_desc->rxmcs, (struct ieee80211_hdr *)skb->data, - rx_desc->crc32 || rx_desc->icverr); + rx_status = IEEE80211_SKB_RXCB(skb); + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - rx_status->mactime = rx_desc->tsfl; - rx_status->flag |= RX_FLAG_MACTIME_START; + skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc24)); - if (!rx_desc->swdec) - rx_status->flag |= RX_FLAG_DECRYPTED; - if (rx_desc->crc32) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (rx_desc->bw) - rx_status->bw = RATE_INFO_BW_40; + phy_stats = (struct rtl8723au_phy_stats *)skb->data; - if (rx_desc->rxmcs >= DESC_RATE_MCS0) { - rx_status->encoding = RX_ENC_HT; - rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; - } else { - rx_status->rate_idx = rx_desc->rxmcs; - } + skb_pull(skb, drvinfo_sz + desc_shift); - rx_status->freq = hw->conf.chandef.chan->center_freq; - rx_status->band = hw->conf.chandef.chan->band; + skb_trim(skb, pkt_len); + + if (rx_desc->rpt_sel) { + struct device *dev = &priv->udev->dev; + dev_dbg(dev, "%s: C2H packet\n", __func__); + rtl8723bu_handle_c2h(priv, skb); + } else { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (rx_desc->phy_stats) + priv->fops->parse_phystats(priv, rx_status, phy_stats, + rx_desc->rxmcs, hdr, + rx_desc->crc32 || rx_desc->icverr); + + rx_status->mactime = rx_desc->tsfl; + rx_status->flag |= RX_FLAG_MACTIME_START; + + if (!rx_desc->swdec) + rx_status->flag |= RX_FLAG_DECRYPTED; + if (rx_desc->crc32) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rx_desc->bw) + rx_status->bw = RATE_INFO_BW_40; + + if (rx_desc->rxmcs >= DESC_RATE_MCS0) { + rx_status->encoding = RX_ENC_HT; + rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0; + } else { + rx_status->rate_idx = rx_desc->rxmcs; + } + + rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = hw->conf.chandef.chan->band; + + ieee80211_rx_irqsafe(hw, skb); + } + + skb = next_skb; + if (skb) + skb_pull(next_skb, pkt_offset); + + urb_len -= pkt_offset; + next_skb = NULL; + } while (skb && urb_len >= sizeof(struct rtl8xxxu_rxdesc24)); - ieee80211_rx_irqsafe(hw, skb); return RX_TYPE_DATA_PKT; } -- cgit v1.2.3 From 271a588d34ed1dd771bc85a224b05ccdacce1de8 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 27 Apr 2023 20:59:36 +0200 Subject: wifi: rtl8xxxu: rtl8xxxu_rx_complete(): remove unnecessary return Remove a return statement at the end of a void function. This fixes a checkpatch warning. WARNING: void function return statements are not generally useful 6206: FILE: ./drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:6206: + return; +} Signed-off-by: Martin Kaiser Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230427185936.923777-1-martin@kaiser.cx --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index b2b2f68e7273..37df47c27a69 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6443,7 +6443,6 @@ static void rtl8xxxu_rx_complete(struct urb *urb) cleanup: usb_free_urb(urb); dev_kfree_skb(skb); - return; } static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv, -- cgit v1.2.3 From 225622256b1b7156624e281e1c0251c292ea24cd Mon Sep 17 00:00:00 2001 From: Zhang Shurong Date: Thu, 27 Apr 2023 01:02:20 +0800 Subject: wifi: rtw88: fix incorrect error codes in rtw_debugfs_copy_from_user If there is a failure during copy_from_user or user-provided data buffer is invalid, rtw_debugfs_copy_from_user should return negative error code instead of a positive value count. Fix this bug by returning correct error code. Moreover, the check of buffer against null is removed since it will be handled by copy_from_user. Signed-off-by: Zhang Shurong Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/tencent_D2EB102CC7435C0110154E62ECA6A7D67505@qq.com --- drivers/net/wireless/realtek/rtw88/debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index fa3d73b333ba..3da477e1ebd3 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -183,8 +183,8 @@ static int rtw_debugfs_copy_from_user(char tmp[], int size, tmp_len = (count > size - 1 ? size - 1 : count); - if (!buffer || copy_from_user(tmp, buffer, tmp_len)) - return count; + if (copy_from_user(tmp, buffer, tmp_len)) + return -EFAULT; tmp[tmp_len] = '\0'; -- cgit v1.2.3 From 77005533777267736fca64fa376b8a835cb8806b Mon Sep 17 00:00:00 2001 From: Zhang Shurong Date: Thu, 27 Apr 2023 01:02:21 +0800 Subject: wifi: rtw88: fix incorrect error codes in rtw_debugfs_set_* If there is a failure during copy_from_user or user-provided data buffer is invalid, rtw_debugfs_set_* should return negative error code instead of a positive value count. Fix this bug by returning correct error code. Signed-off-by: Zhang Shurong Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/tencent_53140CC2A3468101955F02EB66AA96780B05@qq.com --- drivers/net/wireless/realtek/rtw88/debug.c | 55 ++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 3da477e1ebd3..f8ba133baff0 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -201,13 +201,16 @@ static ssize_t rtw_debugfs_set_read_reg(struct file *filp, char tmp[32 + 1]; u32 addr, len; int num; + int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 2); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 2); + if (ret) + return ret; num = sscanf(tmp, "%x %x", &addr, &len); if (num != 2) - return count; + return -EINVAL; if (len != 1 && len != 2 && len != 4) { rtw_warn(rtwdev, "read reg setting wrong len\n"); @@ -288,8 +291,11 @@ static ssize_t rtw_debugfs_set_rsvd_page(struct file *filp, char tmp[32 + 1]; u32 offset, page_num; int num; + int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 2); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 2); + if (ret) + return ret; num = sscanf(tmp, "%d %d", &offset, &page_num); @@ -314,8 +320,11 @@ static ssize_t rtw_debugfs_set_single_input(struct file *filp, char tmp[32 + 1]; u32 input; int num; + int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + if (ret) + return ret; num = kstrtoint(tmp, 0, &input); @@ -338,14 +347,17 @@ static ssize_t rtw_debugfs_set_write_reg(struct file *filp, char tmp[32 + 1]; u32 addr, val, len; int num; + int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); + if (ret) + return ret; /* write BB/MAC register */ num = sscanf(tmp, "%x %x %x", &addr, &val, &len); if (num != 3) - return count; + return -EINVAL; switch (len) { case 1: @@ -381,8 +393,11 @@ static ssize_t rtw_debugfs_set_h2c(struct file *filp, char tmp[32 + 1]; u8 param[8]; int num; + int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); + if (ret) + return ret; num = sscanf(tmp, "%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx", ¶m[0], ¶m[1], ¶m[2], ¶m[3], @@ -408,14 +423,17 @@ static ssize_t rtw_debugfs_set_rf_write(struct file *filp, char tmp[32 + 1]; u32 path, addr, mask, val; int num; + int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 4); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 4); + if (ret) + return ret; num = sscanf(tmp, "%x %x %x %x", &path, &addr, &mask, &val); if (num != 4) { rtw_warn(rtwdev, "invalid args, [path] [addr] [mask] [val]\n"); - return count; + return -EINVAL; } mutex_lock(&rtwdev->mutex); @@ -438,14 +456,17 @@ static ssize_t rtw_debugfs_set_rf_read(struct file *filp, char tmp[32 + 1]; u32 path, addr, mask; int num; + int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); + if (ret) + return ret; num = sscanf(tmp, "%x %x %x", &path, &addr, &mask); if (num != 3) { rtw_warn(rtwdev, "invalid args, [path] [addr] [mask] [val]\n"); - return count; + return -EINVAL; } debugfs_priv->rf_path = path; @@ -467,7 +488,9 @@ static ssize_t rtw_debugfs_set_fix_rate(struct file *filp, char tmp[32 + 1]; int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + if (ret) + return ret; ret = kstrtou8(tmp, 0, &fix_rate); if (ret) { @@ -860,7 +883,9 @@ static ssize_t rtw_debugfs_set_coex_enable(struct file *filp, bool enable; int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + if (ret) + return ret; ret = kstrtobool(tmp, &enable); if (ret) { @@ -930,7 +955,9 @@ static ssize_t rtw_debugfs_set_fw_crash(struct file *filp, bool input; int ret; - rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + if (ret) + return ret; ret = kstrtobool(tmp, &input); if (ret) -- cgit v1.2.3 From 9805500606c256cf61ef73a767d7e797fe5ba18e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 18 Apr 2023 09:28:14 +0800 Subject: wifi: rtw89: use struct rtw89_phy_sts_ie0 instead of macro to access PHY IE0 status To be more clear to know where it gets information from PHY IE0 data, change to use struct and standard le32_get_bits() to access. This doesn't change logic at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230418012820.5139-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 15 ++++++++++----- drivers/net/wireless/realtek/rtw89/txrx.h | 16 ++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 7fc0a26a4d73..09b4f7486e10 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1277,9 +1277,11 @@ static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, u8 *addr) static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev, u8 *addr, struct rtw89_rx_phy_ppdu *phy_ppdu) { + const struct rtw89_phy_sts_ie0 *ie = (const struct rtw89_phy_sts_ie0 *)addr; s16 cfo; + u32 t; - phy_ppdu->chan_idx = RTW89_GET_PHY_STS_IE01_CH_IDX(addr); + phy_ppdu->chan_idx = le32_get_bits(ie->w0, RTW89_PHY_STS_IE01_W0_CH_IDX); if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6) return; @@ -1287,10 +1289,13 @@ static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev, u8 *addr, return; /* sign conversion for S(12,2) */ - if (rtwdev->chip->cfo_src_fd) - cfo = sign_extend32(RTW89_GET_PHY_STS_IE01_FD_CFO(addr), 11); - else - cfo = sign_extend32(RTW89_GET_PHY_STS_IE01_PREMB_CFO(addr), 11); + if (rtwdev->chip->cfo_src_fd) { + t = le32_get_bits(ie->w1, RTW89_PHY_STS_IE01_W1_FD_CFO); + cfo = sign_extend32(t, 11); + } else { + t = le32_get_bits(ie->w1, RTW89_PHY_STS_IE01_W1_PREMB_CFO); + cfo = sign_extend32(t, 11); + } rtw89_phy_cfo_parse(rtwdev, cfo, phy_ppdu); } diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 98eb9607cd21..5c050278fd46 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -298,12 +298,16 @@ le32_get_bits(*((const __le32 *)ie), GENMASK(4, 0)) #define RTW89_GET_PHY_STS_IE_LEN(ie) \ le32_get_bits(*((const __le32 *)ie), GENMASK(11, 5)) -#define RTW89_GET_PHY_STS_IE01_CH_IDX(ie) \ - le32_get_bits(*((const __le32 *)ie), GENMASK(23, 16)) -#define RTW89_GET_PHY_STS_IE01_FD_CFO(ie) \ - le32_get_bits(*((const __le32 *)(ie) + 1), GENMASK(19, 8)) -#define RTW89_GET_PHY_STS_IE01_PREMB_CFO(ie) \ - le32_get_bits(*((const __le32 *)(ie) + 1), GENMASK(31, 20)) + +struct rtw89_phy_sts_ie0 { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; + +#define RTW89_PHY_STS_IE01_W0_CH_IDX GENMASK(23, 16) +#define RTW89_PHY_STS_IE01_W1_FD_CFO GENMASK(19, 8) +#define RTW89_PHY_STS_IE01_W1_PREMB_CFO GENMASK(31, 20) enum rtw89_tx_channel { RTW89_TXCH_ACH0 = 0, -- cgit v1.2.3 From f48453e058d763e895bde7b072f25b7b519a3500 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 18 Apr 2023 09:28:15 +0800 Subject: wifi: rtw89: set capability of TX antenna diversity TX antenna diversity is a mechanism to select a proper antenna from two antenna for single one hardware PHY chip. It chooses antenna with better EVM or RSSI, and use GPIO to control SPDT to switch selected antenna. RFE type from efuse is used to define if a module can support TX antenna diversity when (type % 3) is 2. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230418012820.5139-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 10 ++++++++-- drivers/net/wireless/realtek/rtw89/core.h | 2 ++ drivers/net/wireless/realtek/rtw89/mac.c | 9 +++++++++ drivers/net/wireless/realtek/rtw89/mac80211.c | 7 ++++++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 09b4f7486e10..42e68ec15075 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3701,6 +3701,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) { struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_efuse *efuse = &rtwdev->efuse; + struct rtw89_hal *hal = &rtwdev->hal; int ret; int tx_headroom = IEEE80211_HT_CTL_LEN; @@ -3739,8 +3740,13 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); - hw->wiphy->available_antennas_tx = BIT(rtwdev->chip->rf_path_num) - 1; - hw->wiphy->available_antennas_rx = BIT(rtwdev->chip->rf_path_num) - 1; + if (hal->ant_diversity) { + hw->wiphy->available_antennas_tx = 0x3; + hw->wiphy->available_antennas_rx = 0x3; + } else { + hw->wiphy->available_antennas_tx = BIT(rtwdev->chip->rf_path_num) - 1; + hw->wiphy->available_antennas_rx = BIT(rtwdev->chip->rf_path_num) - 1; + } hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP | diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 6df386a38fb4..38c361ddde38 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3423,6 +3423,8 @@ struct rtw89_hal { u8 tx_nss; u8 rx_nss; bool tx_path_diversity; + bool ant_diversity; + bool ant_diversity_fixed; bool support_cckpd; bool support_igi; atomic_t roc_entity_idx; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index b8019cfc11b2..50ea4bf67275 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -2598,6 +2598,7 @@ static int rtw89_mac_read_phycap(struct rtw89_dev *rtwdev, int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) { + struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_hal *hal = &rtwdev->hal; const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_mac_c2h_info c2h_info = {0}; @@ -2629,6 +2630,13 @@ int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) hal->tx_path_diversity = true; } + if (chip->rf_path_num == 1) { + hal->antenna_tx = RF_A; + hal->antenna_rx = RF_A; + if ((efuse->rfe_type % 3) == 2) + hal->ant_diversity = true; + } + rtw89_debug(rtwdev, RTW89_DBG_FW, "phycap hal/phy/chip: tx_nss=0x%x/0x%x/0x%x rx_nss=0x%x/0x%x/0x%x\n", hal->tx_nss, tx_nss, chip->tx_nss, @@ -2637,6 +2645,7 @@ int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) "ant num/bitmap: tx=%d/0x%x rx=%d/0x%x\n", tx_ant, hal->antenna_tx, rx_ant, hal->antenna_rx); rtw89_debug(rtwdev, RTW89_DBG_FW, "TX path diversity=%d\n", hal->tx_path_diversity); + rtw89_debug(rtwdev, RTW89_DBG_FW, "Antenna diversity=%d\n", hal->ant_diversity); return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index ee4588b61b8f..f40d70f016e4 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -762,13 +762,18 @@ int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) struct rtw89_dev *rtwdev = hw->priv; struct rtw89_hal *hal = &rtwdev->hal; - if (rx_ant != hw->wiphy->available_antennas_rx && rx_ant != hal->antenna_rx) + if (hal->ant_diversity) { + if (tx_ant != rx_ant || hweight32(tx_ant) != 1) + return -EINVAL; + } else if (rx_ant != hw->wiphy->available_antennas_rx && rx_ant != hal->antenna_rx) { return -EINVAL; + } mutex_lock(&rtwdev->mutex); hal->antenna_tx = tx_ant; hal->antenna_rx = rx_ant; hal->tx_path_diversity = false; + hal->ant_diversity_fixed = true; mutex_unlock(&rtwdev->mutex); return 0; -- cgit v1.2.3 From f6b24241cbec5236c061f90d52acb3d9430f2d43 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 18 Apr 2023 09:28:16 +0800 Subject: wifi: rtw89: add RSSI statistics for the case of antenna diversity to debugfs RSSI strength is only from PHY path A, but there are two antenna for the module which supports antenna diversity. So, set RSSI value to index 1 of RSSI array if current antenna is on antenna B. Then, debugfs can show two RSSI values with a asterisk mark on selected antenna. RSSI: -23 dBm (raw=174, prev=173) [-26, -23*] Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230418012820.5139-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 20 +++++++++++++++++--- drivers/net/wireless/realtek/rtw89/debug.c | 8 +++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 42e68ec15075..5271d596b04d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1244,10 +1244,22 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; struct rtw89_rx_phy_ppdu *phy_ppdu = (struct rtw89_rx_phy_ppdu *)data; struct rtw89_dev *rtwdev = rtwsta->rtwdev; + struct rtw89_hal *hal = &rtwdev->hal; + u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; + u8 ant_pos = U8_MAX; int i; - if (rtwsta->mac_id == phy_ppdu->mac_id && phy_ppdu->to_self) { - ewma_rssi_add(&rtwsta->avg_rssi, phy_ppdu->rssi_avg); + if (rtwsta->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self) + return; + + if (hal->ant_diversity && hal->antenna_rx) + ant_pos = __ffs(hal->antenna_rx); + + ewma_rssi_add(&rtwsta->avg_rssi, phy_ppdu->rssi_avg); + + if (ant_pos < ant_num) { + ewma_rssi_add(&rtwsta->rssi[ant_pos], phy_ppdu->rssi[0]); + } else { for (i = 0; i < rtwdev->chip->rf_path_num; i++) ewma_rssi_add(&rtwsta->rssi[i], phy_ppdu->rssi[i]); } @@ -2764,6 +2776,8 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, { struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_hal *hal = &rtwdev->hal; + u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; int i; int ret; @@ -2777,7 +2791,7 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, rtw89_core_txq_init(rtwdev, sta->txq[i]); ewma_rssi_init(&rtwsta->avg_rssi); - for (i = 0; i < rtwdev->chip->rf_path_num; i++) + for (i = 0; i < ant_num; i++) ewma_rssi_init(&rtwsta->rssi[i]); if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 1e5b7a998716..bc5ea9735866 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3206,6 +3206,8 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) struct seq_file *m = (struct seq_file *)data; struct rtw89_dev *rtwdev = rtwsta->rtwdev; struct rtw89_hal *hal = &rtwdev->hal; + u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; + bool ant_asterisk = hal->tx_path_diversity || hal->ant_diversity; u8 rssi; int i; @@ -3256,11 +3258,11 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) rssi = ewma_rssi_read(&rtwsta->avg_rssi); seq_printf(m, "RSSI: %d dBm (raw=%d, prev=%d) [", RTW89_RSSI_RAW_TO_DBM(rssi), rssi, rtwsta->prev_rssi); - for (i = 0; i < rtwdev->chip->rf_path_num; i++) { + for (i = 0; i < ant_num; i++) { rssi = ewma_rssi_read(&rtwsta->rssi[i]); seq_printf(m, "%d%s%s", RTW89_RSSI_RAW_TO_DBM(rssi), - hal->tx_path_diversity && (hal->antenna_tx & BIT(i)) ? "*" : "", - i + 1 == rtwdev->chip->rf_path_num ? "" : ", "); + ant_asterisk && (hal->antenna_tx & BIT(i)) ? "*" : "", + i + 1 == ant_num ? "" : ", "); } seq_puts(m, "]\n"); } -- cgit v1.2.3 From 4bb223a19f9b8c226b357ceedad47a00d88fef3a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 18 Apr 2023 09:28:17 +0800 Subject: wifi: rtw89: add EVM and SNR statistics to debugfs To help debug performance problem, add EVM and SNR statistics to debugfs that shows EVM: [(26.75, 26.75) (25.75, 25.75)] SNR: 40 Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230418012820.5139-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 29 ++++++++++++++++++++++++----- drivers/net/wireless/realtek/rtw89/core.h | 11 +++++++++++ drivers/net/wireless/realtek/rtw89/debug.c | 16 ++++++++++++++++ drivers/net/wireless/realtek/rtw89/txrx.h | 3 +++ 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 5271d596b04d..9b1ed52e53ba 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1247,13 +1247,16 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, struct rtw89_hal *hal = &rtwdev->hal; u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; u8 ant_pos = U8_MAX; + u8 evm_pos = 0; int i; if (rtwsta->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self) return; - if (hal->ant_diversity && hal->antenna_rx) + if (hal->ant_diversity && hal->antenna_rx) { ant_pos = __ffs(hal->antenna_rx); + evm_pos = ant_pos; + } ewma_rssi_add(&rtwsta->avg_rssi, phy_ppdu->rssi_avg); @@ -1263,6 +1266,12 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, for (i = 0; i < rtwdev->chip->rf_path_num; i++) ewma_rssi_add(&rtwsta->rssi[i], phy_ppdu->rssi[i]); } + + if (phy_ppdu->ofdm.has) { + ewma_snr_add(&rtwsta->avg_snr, phy_ppdu->ofdm.avg_snr); + ewma_evm_add(&rtwsta->evm_min[evm_pos], phy_ppdu->ofdm.evm_min); + ewma_evm_add(&rtwsta->evm_max[evm_pos], phy_ppdu->ofdm.evm_max); + } } #define VAR_LEN 0xff @@ -1300,6 +1309,11 @@ static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev, u8 *addr, if (!phy_ppdu->to_self) return; + phy_ppdu->ofdm.avg_snr = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_AVG_SNR); + phy_ppdu->ofdm.evm_max = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_EVM_MAX); + phy_ppdu->ofdm.evm_min = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_EVM_MIN); + phy_ppdu->ofdm.has = true; + /* sign conversion for S(12,2) */ if (rtwdev->chip->cfo_src_fd) { t = le32_get_bits(ie->w1, RTW89_PHY_STS_IE01_W1_FD_CFO); @@ -1350,9 +1364,6 @@ static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev, return -EINVAL; } rtw89_core_update_phy_ppdu(phy_ppdu); - ieee80211_iterate_stations_atomic(rtwdev->hw, - rtw89_core_rx_process_phy_ppdu_iter, - phy_ppdu); return 0; } @@ -1393,6 +1404,10 @@ static void rtw89_core_rx_process_phy_sts(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_TXRX, "parse phy sts failed\n"); else phy_ppdu->valid = true; + + ieee80211_iterate_stations_atomic(rtwdev->hw, + rtw89_core_rx_process_phy_ppdu_iter, + phy_ppdu); } static u8 rtw89_rxdesc_to_nl_he_gi(struct rtw89_dev *rtwdev, @@ -2791,8 +2806,12 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, rtw89_core_txq_init(rtwdev, sta->txq[i]); ewma_rssi_init(&rtwsta->avg_rssi); - for (i = 0; i < ant_num; i++) + ewma_snr_init(&rtwsta->avg_snr); + for (i = 0; i < ant_num; i++) { ewma_rssi_init(&rtwsta->rssi[i]); + ewma_evm_init(&rtwsta->evm_min[i]); + ewma_evm_init(&rtwsta->evm_max[i]); + } if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { /* for station mode, assign the mac_id from itself */ diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 38c361ddde38..7e7bece1fd54 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -551,6 +551,12 @@ struct rtw89_rx_phy_ppdu { u8 chan_idx; u8 ie; u16 rate; + struct { + bool has; + u8 avg_snr; + u8 evm_max; + u8 evm_min; + } ofdm; bool to_self; bool valid; }; @@ -2533,6 +2539,8 @@ struct rtw89_ra_report { }; DECLARE_EWMA(rssi, 10, 16); +DECLARE_EWMA(evm, 10, 16); +DECLARE_EWMA(snr, 10, 16); struct rtw89_ba_cam_entry { struct list_head list; @@ -2595,6 +2603,9 @@ struct rtw89_sta { u8 prev_rssi; struct ewma_rssi avg_rssi; struct ewma_rssi rssi[RF_PATH_MAX]; + struct ewma_snr avg_snr; + struct ewma_evm evm_min[RF_PATH_MAX]; + struct ewma_evm evm_max[RF_PATH_MAX]; struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS]; struct ieee80211_rx_status rx_status; u16 rx_hw_rate; diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index bc5ea9735866..6f418f14ec3f 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -3208,7 +3208,9 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) struct rtw89_hal *hal = &rtwdev->hal; u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num; bool ant_asterisk = hal->tx_path_diversity || hal->ant_diversity; + u8 evm_min, evm_max; u8 rssi; + u8 snr; int i; seq_printf(m, "TX rate [%d]: ", rtwsta->mac_id); @@ -3265,6 +3267,20 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta) i + 1 == ant_num ? "" : ", "); } seq_puts(m, "]\n"); + + seq_puts(m, "EVM: ["); + for (i = 0; i < (hal->ant_diversity ? 2 : 1); i++) { + evm_min = ewma_evm_read(&rtwsta->evm_min[i]); + evm_max = ewma_evm_read(&rtwsta->evm_max[i]); + + seq_printf(m, "%s(%2u.%02u, %2u.%02u)", i == 0 ? "" : " ", + evm_min >> 2, (evm_min & 0x3) * 25, + evm_max >> 2, (evm_max & 0x3) * 25); + } + seq_puts(m, "]\t"); + + snr = ewma_snr_read(&rtwsta->avg_snr); + seq_printf(m, "SNR: %u\n", snr); } static void diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 5c050278fd46..d880ecb879ca 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -308,6 +308,9 @@ struct rtw89_phy_sts_ie0 { #define RTW89_PHY_STS_IE01_W0_CH_IDX GENMASK(23, 16) #define RTW89_PHY_STS_IE01_W1_FD_CFO GENMASK(19, 8) #define RTW89_PHY_STS_IE01_W1_PREMB_CFO GENMASK(31, 20) +#define RTW89_PHY_STS_IE01_W2_AVG_SNR GENMASK(5, 0) +#define RTW89_PHY_STS_IE01_W2_EVM_MAX GENMASK(15, 8) +#define RTW89_PHY_STS_IE01_W2_EVM_MIN GENMASK(23, 16) enum rtw89_tx_channel { RTW89_TXCH_ACH0 = 0, -- cgit v1.2.3 From a90c613d099ff63587b60bfcfb0f4f1a7bb83252 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Tue, 18 Apr 2023 09:28:18 +0800 Subject: wifi: rtw89: initialize antenna for antenna diversity Initialize basic antenna switch settings according to hardware module design, and set to default antenna A. The set antenna function will be called dynamically to switch antenna according to EVM and RSSI. Signed-off-by: Eric Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230418012820.5139-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/phy.c | 69 ++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/reg.h | 21 +++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index c7e906123416..3f9755c58e6c 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2946,6 +2946,44 @@ static void rtw89_phy_ul_tb_info_init(struct rtw89_dev *rtwdev) rtw89_phy_read32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN); } +static void rtw89_phy_antdiv_reg_init(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_ANT_TRAIN_EN, + 0x0, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_TX_ANT_SEL, + 0x0, RTW89_PHY_0); + + rtw89_phy_write32_idx(rtwdev, R_P0_ANT_SW, B_P0_TRSW_TX_EXTEND, + 0x0, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANT_SW, B_P0_HW_ANTSW_DIS_BY_GNT_BT, + 0x0, RTW89_PHY_0); + + rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_BT_FORCE_ANTIDX_EN, + 0x0, RTW89_PHY_0); + + rtw89_phy_write32_idx(rtwdev, R_RFSW_CTRL_ANT0_BASE, B_RFSW_CTRL_ANT_MAPPING, + 0x0100, RTW89_PHY_0); + + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_BTG_TRX, + 0x1, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_HW_CTRL, + 0x0, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_SW_2G, + 0x0, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_SW_5G, + 0x0, RTW89_PHY_0); +} + +static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + + if (!hal->ant_diversity) + return; + + rtw89_phy_antdiv_reg_init(rtwdev); +} + static void rtw89_phy_stat_thermal_update(struct rtw89_dev *rtwdev) { struct rtw89_phy_stat *phystat = &rtwdev->phystat; @@ -4114,6 +4152,35 @@ void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev) &done); } +#define ANTDIV_MAIN 0 +#define ANTDIV_AUX 1 + +static void rtw89_phy_antdiv_set_ant(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + u8 default_ant, optional_ant; + + if (!hal->ant_diversity || hal->antenna_tx == 0) + return; + + if (hal->antenna_tx == RF_B) { + default_ant = ANTDIV_AUX; + optional_ant = ANTDIV_MAIN; + } else { + default_ant = ANTDIV_MAIN; + optional_ant = ANTDIV_AUX; + } + + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_CGCS_CTRL, + default_ant, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_RX_ORI, + default_ant, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_RX_ALT, + optional_ant, RTW89_PHY_0); + rtw89_phy_write32_idx(rtwdev, R_P0_ANTSEL, B_P0_ANTSEL_TX_ORI, + default_ant, RTW89_PHY_0); +} + static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev) { rtw89_phy_ccx_top_setting_init(rtwdev); @@ -4133,6 +4200,8 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_phy_dig_init(rtwdev); rtw89_phy_cfo_init(rtwdev); rtw89_phy_ul_tb_info_init(rtwdev); + rtw89_phy_antdiv_init(rtwdev); + rtw89_phy_antdiv_set_ant(rtwdev); rtw89_phy_init_rf_nctl(rtwdev); rtw89_chip_rfk_init(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 266e4231b5f3..50da3a3c289a 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3852,6 +3852,9 @@ #define B_ENABLE_CCK BIT(5) #define R_RSTB_ASYNC 0x0704 #define B_RSTB_ASYNC_ALL BIT(1) +#define R_P0_ANT_SW 0x0728 +#define B_P0_HW_ANTSW_DIS_BY_GNT_BT BIT(12) +#define B_P0_TRSW_TX_EXTEND GENMASK(3, 0) #define R_MAC_PIN_SEL 0x0734 #define B_CH_IDX_SEG0 GENMASK(23, 16) #define R_PLCP_HISTOGRAM 0x0738 @@ -4455,10 +4458,24 @@ #define B_P0_RFCTM_VAL GENMASK(25, 20) #define R_P0_RFCTM_RDY BIT(26) #define R_P0_TRSW 0x5868 -#define B_P0_TRSW_B BIT(0) -#define B_P0_TRSW_A BIT(1) +#define B_P0_BT_FORCE_ANTIDX_EN BIT(12) #define B_P0_TRSW_X BIT(2) +#define B_P0_TRSW_A BIT(1) +#define B_P0_TX_ANT_SEL BIT(1) +#define B_P0_TRSW_B BIT(0) +#define B_P0_ANT_TRAIN_EN BIT(0) #define B_P0_TRSW_SO_A2 GENMASK(7, 5) +#define R_P0_ANTSEL 0x586C +#define B_P0_ANTSEL_SW_5G BIT(25) +#define B_P0_ANTSEL_SW_2G BIT(23) +#define B_P0_ANTSEL_BTG_TRX BIT(21) +#define B_P0_ANTSEL_CGCS_CTRL BIT(17) +#define B_P0_ANTSEL_HW_CTRL BIT(16) +#define B_P0_ANTSEL_TX_ORI GENMASK(15, 12) +#define B_P0_ANTSEL_RX_ALT GENMASK(11, 8) +#define B_P0_ANTSEL_RX_ORI GENMASK(7, 4) +#define R_RFSW_CTRL_ANT0_BASE 0x5870 +#define B_RFSW_CTRL_ANT_MAPPING GENMASK(15, 0) #define R_P0_RFM 0x5894 #define B_P0_RFM_DIS_WL BIT(7) #define B_P0_RFM_TX_OPT BIT(6) -- cgit v1.2.3 From e3715859c75322fae560c46384f944006f367515 Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Tue, 18 Apr 2023 09:28:19 +0800 Subject: wifi: rtw89: add RSSI based antenna diversity RSSI statistics are grouped by CCK, OFDM or non-legacy rate. These statistics will be collected in training state for both (main/aux) antenna. There is a time period (ANTDIV_DELAY) for rate adaptive settle down before start collect statistics when switch antenna. Antenna diversity checks packet count from training state for each group and use the most one as the final RSSI for comparison, and then choose the better one as target antenna. Signed-off-by: Eric Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230418012820.5139-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 5 + drivers/net/wireless/realtek/rtw89/core.h | 20 ++++ drivers/net/wireless/realtek/rtw89/phy.c | 177 ++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/phy.h | 12 ++ 4 files changed, 214 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 9b1ed52e53ba..0d0b99343f55 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1391,6 +1391,8 @@ static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev, } } + rtw89_phy_antdiv_parse(rtwdev, phy_ppdu); + return 0; } @@ -2628,6 +2630,7 @@ static void rtw89_track_work(struct work_struct *work) rtw89_phy_ra_update(rtwdev); rtw89_phy_cfo_track(rtwdev); rtw89_phy_tx_path_div_track(rtwdev); + rtw89_phy_antdiv_track(rtwdev); rtw89_phy_ul_tb_ctrl_track(rtwdev); if (rtwdev->lps_enabled && !rtwdev->btc.lps) @@ -3482,6 +3485,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) cancel_delayed_work_sync(&rtwdev->coex_rfk_chk_work); cancel_delayed_work_sync(&rtwdev->cfo_track_work); cancel_delayed_work_sync(&rtwdev->forbid_ba_work); + cancel_delayed_work_sync(&rtwdev->antdiv_work); mutex_lock(&rtwdev->mutex); @@ -3517,6 +3521,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_DELAYED_WORK(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_work); INIT_DELAYED_WORK(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work); INIT_DELAYED_WORK(&rtwdev->forbid_ba_work, rtw89_forbid_ba_work); + INIT_DELAYED_WORK(&rtwdev->antdiv_work, rtw89_phy_antdiv_work); rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); if (!rtwdev->txq_wq) return -ENOMEM; diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7e7bece1fd54..ca9d6e9258ff 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3127,6 +3127,24 @@ struct rtw89_phy_ul_tb_info { u8 def_if_bandedge; }; +struct rtw89_antdiv_stats { + struct ewma_rssi cck_rssi_avg; + struct ewma_rssi ofdm_rssi_avg; + struct ewma_rssi non_legacy_rssi_avg; + u16 pkt_cnt_cck; + u16 pkt_cnt_ofdm; + u16 pkt_cnt_non_legacy; +}; + +struct rtw89_antdiv_info { + struct rtw89_antdiv_stats target_stats; + struct rtw89_antdiv_stats main_stats; + struct rtw89_antdiv_stats aux_stats; + u8 training_count; + u8 rssi_pre; + bool get_stats; +}; + struct rtw89_chip_info { enum rtw89_core_chip_id chip_id; const struct rtw89_chip_ops *ops; @@ -4099,6 +4117,7 @@ struct rtw89_dev { struct rtw89_phy_bb_gain_info bb_gain; struct rtw89_phy_efuse_gain efuse_gain; struct rtw89_phy_ul_tb_info ul_tb_info; + struct rtw89_antdiv_info antdiv; struct delayed_work track_work; struct delayed_work coex_act1_work; @@ -4107,6 +4126,7 @@ struct rtw89_dev { struct delayed_work cfo_track_work; struct delayed_work forbid_ba_work; struct delayed_work roc_work; + struct delayed_work antdiv_work; struct rtw89_ppdu_sts_info ppdu_sts; u8 total_sta_assoc; bool scanning; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 3f9755c58e6c..b9a3ebc2e790 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -10,6 +10,7 @@ #include "ps.h" #include "reg.h" #include "sar.h" +#include "txrx.h" #include "util.h" static u16 get_max_amsdu_len(struct rtw89_dev *rtwdev, @@ -2946,6 +2947,67 @@ static void rtw89_phy_ul_tb_info_init(struct rtw89_dev *rtwdev) rtw89_phy_read32_mask(rtwdev, R_BANDEDGE, B_BANDEDGE_EN); } +static +void rtw89_phy_antdiv_sts_instance_reset(struct rtw89_antdiv_stats *antdiv_sts) +{ + ewma_rssi_init(&antdiv_sts->cck_rssi_avg); + ewma_rssi_init(&antdiv_sts->ofdm_rssi_avg); + ewma_rssi_init(&antdiv_sts->non_legacy_rssi_avg); + antdiv_sts->pkt_cnt_cck = 0; + antdiv_sts->pkt_cnt_ofdm = 0; + antdiv_sts->pkt_cnt_non_legacy = 0; +} + +static void rtw89_phy_antdiv_sts_instance_add(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct rtw89_antdiv_stats *stats) +{ + if (GET_DATA_RATE_MODE(phy_ppdu->rate) == DATA_RATE_MODE_NON_HT) { + if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6) { + ewma_rssi_add(&stats->cck_rssi_avg, phy_ppdu->rssi_avg); + stats->pkt_cnt_cck++; + } else { + ewma_rssi_add(&stats->ofdm_rssi_avg, phy_ppdu->rssi_avg); + stats->pkt_cnt_ofdm++; + } + } else { + ewma_rssi_add(&stats->non_legacy_rssi_avg, phy_ppdu->rssi_avg); + stats->pkt_cnt_non_legacy++; + } +} + +static u8 rtw89_phy_antdiv_sts_instance_get_rssi(struct rtw89_antdiv_stats *stats) +{ + if (stats->pkt_cnt_non_legacy >= stats->pkt_cnt_cck && + stats->pkt_cnt_non_legacy >= stats->pkt_cnt_ofdm) + return ewma_rssi_read(&stats->non_legacy_rssi_avg); + else if (stats->pkt_cnt_ofdm >= stats->pkt_cnt_cck && + stats->pkt_cnt_ofdm >= stats->pkt_cnt_non_legacy) + return ewma_rssi_read(&stats->ofdm_rssi_avg); + else + return ewma_rssi_read(&stats->cck_rssi_avg); +} + +void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + struct rtw89_hal *hal = &rtwdev->hal; + + if (!hal->ant_diversity || hal->ant_diversity_fixed) + return; + + rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->target_stats); + + if (!antdiv->get_stats) + return; + + if (hal->antenna_rx == RF_A) + rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->main_stats); + else if (hal->antenna_rx == RF_B) + rtw89_phy_antdiv_sts_instance_add(rtwdev, phy_ppdu, &antdiv->aux_stats); +} + static void rtw89_phy_antdiv_reg_init(struct rtw89_dev *rtwdev) { rtw89_phy_write32_idx(rtwdev, R_P0_TRSW, B_P0_ANT_TRAIN_EN, @@ -2974,13 +3036,26 @@ static void rtw89_phy_antdiv_reg_init(struct rtw89_dev *rtwdev) 0x0, RTW89_PHY_0); } +static void rtw89_phy_antdiv_sts_reset(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + + rtw89_phy_antdiv_sts_instance_reset(&antdiv->target_stats); + rtw89_phy_antdiv_sts_instance_reset(&antdiv->main_stats); + rtw89_phy_antdiv_sts_instance_reset(&antdiv->aux_stats); +} + static void rtw89_phy_antdiv_init(struct rtw89_dev *rtwdev) { + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; struct rtw89_hal *hal = &rtwdev->hal; if (!hal->ant_diversity) return; + antdiv->get_stats = false; + antdiv->rssi_pre = 0; + rtw89_phy_antdiv_sts_reset(rtwdev); rtw89_phy_antdiv_reg_init(rtwdev); } @@ -4181,6 +4256,108 @@ static void rtw89_phy_antdiv_set_ant(struct rtw89_dev *rtwdev) default_ant, RTW89_PHY_0); } +static void rtw89_phy_swap_hal_antenna(struct rtw89_dev *rtwdev) +{ + struct rtw89_hal *hal = &rtwdev->hal; + + hal->antenna_rx = hal->antenna_rx == RF_A ? RF_B : RF_A; + hal->antenna_tx = hal->antenna_rx; +} + +static void rtw89_phy_antdiv_decision_state(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + struct rtw89_hal *hal = &rtwdev->hal; + bool no_change = false; + u8 main_rssi, aux_rssi; + u32 candidate; + + antdiv->get_stats = false; + antdiv->training_count = 0; + + main_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->main_stats); + aux_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->aux_stats); + + if (main_rssi > aux_rssi + RTW89_TX_DIV_RSSI_RAW_TH) + candidate = RF_A; + else if (aux_rssi > main_rssi + RTW89_TX_DIV_RSSI_RAW_TH) + candidate = RF_B; + else + no_change = true; + + if (no_change) { + /* swap back from training antenna to original */ + rtw89_phy_swap_hal_antenna(rtwdev); + return; + } + + hal->antenna_tx = candidate; + hal->antenna_rx = candidate; +} + +static void rtw89_phy_antdiv_training_state(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + u64 state_period; + + if (antdiv->training_count % 2 == 0) { + if (antdiv->training_count == 0) + rtw89_phy_antdiv_sts_reset(rtwdev); + + antdiv->get_stats = true; + state_period = msecs_to_jiffies(ANTDIV_TRAINNING_INTVL); + } else { + antdiv->get_stats = false; + state_period = msecs_to_jiffies(ANTDIV_DELAY); + + rtw89_phy_swap_hal_antenna(rtwdev); + rtw89_phy_antdiv_set_ant(rtwdev); + } + + antdiv->training_count++; + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->antdiv_work, + state_period); +} + +void rtw89_phy_antdiv_work(struct work_struct *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + antdiv_work.work); + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + + mutex_lock(&rtwdev->mutex); + + if (antdiv->training_count <= ANTDIV_TRAINNING_CNT) { + rtw89_phy_antdiv_training_state(rtwdev); + } else { + rtw89_phy_antdiv_decision_state(rtwdev); + rtw89_phy_antdiv_set_ant(rtwdev); + } + + mutex_unlock(&rtwdev->mutex); +} + +void rtw89_phy_antdiv_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_antdiv_info *antdiv = &rtwdev->antdiv; + struct rtw89_hal *hal = &rtwdev->hal; + u8 rssi, rssi_pre; + + if (!hal->ant_diversity || hal->ant_diversity_fixed) + return; + + rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->target_stats); + rssi_pre = antdiv->rssi_pre; + antdiv->rssi_pre = rssi; + rtw89_phy_antdiv_sts_instance_reset(&antdiv->target_stats); + + if (abs((int)rssi - (int)rssi_pre) < ANTDIV_RSSI_DIFF_TH) + return; + + antdiv->training_count = 0; + ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->antdiv_work, 0); +} + static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev) { rtw89_phy_ccx_top_setting_init(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 7535867d0f48..ab174a0ba488 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -67,6 +67,14 @@ #define UL_TB_TF_CNT_L2H_TH 100 #define UL_TB_TF_CNT_H2L_TH 70 +#define ANTDIV_TRAINNING_CNT 2 +#define ANTDIV_TRAINNING_INTVL 30 +#define ANTDIV_DELAY 110 +#define ANTDIV_TP_DIFF_TH_HIGH 100 +#define ANTDIV_TP_DIFF_TH_LOW 5 +#define ANTDIV_EVM_DIFF_TH 8 +#define ANTDIV_RSSI_DIFF_TH 3 + #define CCX_MAX_PERIOD 2097 #define CCX_MAX_PERIOD_UNIT 32 #define MS_TO_4US_RATIO 250 @@ -549,6 +557,10 @@ void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask, void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev); void rtw89_phy_dig(struct rtw89_dev *rtwdev); void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev); +void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu); +void rtw89_phy_antdiv_track(struct rtw89_dev *rtwdev); +void rtw89_phy_antdiv_work(struct work_struct *work); void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); void rtw89_phy_tssi_ctrl_set_bandedge_cfg(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx, -- cgit v1.2.3 From 5feecb40e735b7cb4173328fabfc49ddc2b3b1bc Mon Sep 17 00:00:00 2001 From: Eric Huang Date: Tue, 18 Apr 2023 09:28:20 +0800 Subject: wifi: rtw89: add EVM for antenna diversity Take EVM into consideration when doing antenna diversity, and the priority is higher than RSSI. Since EVM is more relevant to performance than RSSI, especially in OTA environment. Signed-off-by: Eric Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230418012820.5139-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/phy.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ca9d6e9258ff..40406ecce5bd 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3134,6 +3134,7 @@ struct rtw89_antdiv_stats { u16 pkt_cnt_cck; u16 pkt_cnt_ofdm; u16 pkt_cnt_non_legacy; + u32 evm; }; struct rtw89_antdiv_info { diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index b9a3ebc2e790..5eac00cd5188 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2956,6 +2956,7 @@ void rtw89_phy_antdiv_sts_instance_reset(struct rtw89_antdiv_stats *antdiv_sts) antdiv_sts->pkt_cnt_cck = 0; antdiv_sts->pkt_cnt_ofdm = 0; antdiv_sts->pkt_cnt_non_legacy = 0; + antdiv_sts->evm = 0; } static void rtw89_phy_antdiv_sts_instance_add(struct rtw89_dev *rtwdev, @@ -2969,10 +2970,12 @@ static void rtw89_phy_antdiv_sts_instance_add(struct rtw89_dev *rtwdev, } else { ewma_rssi_add(&stats->ofdm_rssi_avg, phy_ppdu->rssi_avg); stats->pkt_cnt_ofdm++; + stats->evm += phy_ppdu->ofdm.evm_min; } } else { ewma_rssi_add(&stats->non_legacy_rssi_avg, phy_ppdu->rssi_avg); stats->pkt_cnt_non_legacy++; + stats->evm += phy_ppdu->ofdm.evm_min; } } @@ -2988,6 +2991,11 @@ static u8 rtw89_phy_antdiv_sts_instance_get_rssi(struct rtw89_antdiv_stats *stat return ewma_rssi_read(&stats->cck_rssi_avg); } +static u8 rtw89_phy_antdiv_sts_instance_get_evm(struct rtw89_antdiv_stats *stats) +{ + return phy_div(stats->evm, stats->pkt_cnt_non_legacy + stats->pkt_cnt_ofdm); +} + void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu) { @@ -4270,15 +4278,22 @@ static void rtw89_phy_antdiv_decision_state(struct rtw89_dev *rtwdev) struct rtw89_hal *hal = &rtwdev->hal; bool no_change = false; u8 main_rssi, aux_rssi; + u8 main_evm, aux_evm; u32 candidate; antdiv->get_stats = false; antdiv->training_count = 0; main_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->main_stats); + main_evm = rtw89_phy_antdiv_sts_instance_get_evm(&antdiv->main_stats); aux_rssi = rtw89_phy_antdiv_sts_instance_get_rssi(&antdiv->aux_stats); + aux_evm = rtw89_phy_antdiv_sts_instance_get_evm(&antdiv->aux_stats); - if (main_rssi > aux_rssi + RTW89_TX_DIV_RSSI_RAW_TH) + if (main_evm > aux_evm + ANTDIV_EVM_DIFF_TH) + candidate = RF_A; + else if (aux_evm > main_evm + ANTDIV_EVM_DIFF_TH) + candidate = RF_B; + else if (main_rssi > aux_rssi + RTW89_TX_DIV_RSSI_RAW_TH) candidate = RF_A; else if (aux_rssi > main_rssi + RTW89_TX_DIV_RSSI_RAW_TH) candidate = RF_B; -- cgit v1.2.3 From 25a7e5072ef1901e671e6f39df40b5028b241804 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 19 Apr 2023 11:45:51 +0000 Subject: wifi: rtw89: release bit in rtw89_fw_h2c_del_pkt_offload() We have a pair of FW functions, rtw89_fw_h2c_add_pkt_offload() and rtw89_fw_h2c_del_pkt_offload(). The rtw89_fw_h2c_add_pkt_offload() acquires the bit itself, but the bit needs to be released by the caller of rtw89_fw_h2c_del_pkt_offload(). This looks asymmetrical and is not friendly to callers. Second, if callers always releases the bits, it might make driver unaligned to bitmap status of FW after some failures of calling rtw89_fw_h2c_del_pkt_offload(). So, this commit move bit release into rtw89_fw_h2c_del_pkt_offload(). In general, driver will call rtw89_fw_h2c_add_pkt_offload() and rtw89_fw_h2c_del_pkt_offload(), and then, SW bitmap can align with FW one. There is one exception when notify_fw is false. It happens when driver detects FW problems and is going to reset FW. Only in this case, driver needs to release bits outside rtw89_fw_h2c_del_pkt_offload(). Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/8cf5d45c5b04e7b680d4eb9dda62056cdce14cec.camel@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index b9b675bf9d05..4051d337ef4e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -997,8 +997,8 @@ void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, list_for_each_entry_safe(info, tmp, pkt_list, list) { if (notify_fw) rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); - rtw89_core_release_bit_map(rtwdev->pkt_offload, - info->id); + else + rtw89_core_release_bit_map(rtwdev->pkt_offload, info->id); list_del(&info->list); kfree(info); } @@ -2466,6 +2466,7 @@ int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id) goto fail; } + rtw89_core_release_bit_map(rtwdev->pkt_offload, id); return 0; fail: dev_kfree_skb_any(skb); @@ -3020,8 +3021,6 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev) list_for_each_entry_safe(info, tmp, &pkt_list[idx], list) { rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); - rtw89_core_release_bit_map(rtwdev->pkt_offload, - info->id); list_del(&info->list); kfree(info); } -- cgit v1.2.3 From 3ea1cd8d027f189c044de142d58c4b0162396db3 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 19 Apr 2023 11:45:55 +0000 Subject: wifi: rtw89: refine packet offload delete flow of 6 GHz probe There are two places where offload packets of 6 GHz probe would be deleted from FW, i.e. calling rtw89_fw_h2c_del_pkt_offload(). * rtw89_core_cancel_6ghz_probe_tx() * rtw89_release_pkt_list() It is possible that we try to delete the same one from FW twice. Although it might not be a big problem for now, it will depend on the runtime chip firmware. So, we add a check to avoid it. In case things becomes complex due to racing problem, we don't choose to do list_del(info->list) and kfree(info) in both sides. Besides, rtw89_fw_h2c_del_pkt_offload() will needs to wait for completion after the follow-up commit. However, rtw89_core_cancel_6ghz_probe_tx() was called in interrupt context. So, we move the stuffs of calling rtw89_fw_h2c_del_pkt_offload() from rtw89_core_cancel_6ghz_probe_tx() into a work. Then, we also need a check there before we call it. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/091966e5709cd7caecf9b81f7fd6388ae2b70a7e.camel@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 43 ++++++++++++++++++++++++++++--- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 3 ++- drivers/net/wireless/realtek/rtw89/fw.h | 1 + 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 0d0b99343f55..b1bd84f67910 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1515,6 +1515,34 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev, } } +static void rtw89_cancel_6ghz_probe_work(struct work_struct *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + cancel_6ghz_probe_work); + struct list_head *pkt_list = rtwdev->scan_info.pkt_list; + struct rtw89_pktofld_info *info; + + mutex_lock(&rtwdev->mutex); + + if (!rtwdev->scanning) + goto out; + + list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) { + if (!info->cancel || !test_bit(info->id, rtwdev->pkt_offload)) + continue; + + rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); + + /* Don't delete/free info from pkt_list at this moment. Let it + * be deleted/freed in rtw89_release_pkt_list() after scanning, + * since if during scanning, pkt_list is accessed in bottom half. + */ + } + +out: + mutex_unlock(&rtwdev->mutex); +} + static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev, struct sk_buff *skb) { @@ -1523,6 +1551,7 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev, struct list_head *pkt_list = rtwdev->scan_info.pkt_list; struct rtw89_pktofld_info *info; const u8 *ies = mgmt->u.beacon.variable, *ssid_ie; + bool queue_work = false; if (rx_status->band != NL80211_BAND_6GHZ) return; @@ -1531,16 +1560,22 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev, list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) { if (ether_addr_equal(info->bssid, mgmt->bssid)) { - rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); + info->cancel = true; + queue_work = true; continue; } if (!ssid_ie || ssid_ie[1] != info->ssid_len || info->ssid_len == 0) continue; - if (memcmp(&ssid_ie[2], info->ssid, info->ssid_len) == 0) - rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); + if (memcmp(&ssid_ie[2], info->ssid, info->ssid_len) == 0) { + info->cancel = true; + queue_work = true; + } } + + if (queue_work) + ieee80211_queue_work(rtwdev->hw, &rtwdev->cancel_6ghz_probe_work); } static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, @@ -3474,6 +3509,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) mutex_unlock(&rtwdev->mutex); cancel_work_sync(&rtwdev->c2h_work); + cancel_work_sync(&rtwdev->cancel_6ghz_probe_work); cancel_work_sync(&btc->eapol_notify_work); cancel_work_sync(&btc->arp_notify_work); cancel_work_sync(&btc->dhcp_notify_work); @@ -3536,6 +3572,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_WORK(&rtwdev->c2h_work, rtw89_fw_c2h_work); INIT_WORK(&rtwdev->ips_work, rtw89_ips_work); INIT_WORK(&rtwdev->load_firmware_work, rtw89_load_firmware_work); + INIT_WORK(&rtwdev->cancel_6ghz_probe_work, rtw89_cancel_6ghz_probe_work); skb_queue_head_init(&rtwdev->c2h_queue); rtw89_core_ppdu_sts_init(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 40406ecce5bd..4acf84850f0d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -4086,6 +4086,7 @@ struct rtw89_dev { struct work_struct c2h_work; struct work_struct ips_work; struct work_struct load_firmware_work; + struct work_struct cancel_6ghz_probe_work; struct list_head early_h2c_list; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 4051d337ef4e..2390bcb3b46a 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3020,7 +3020,8 @@ static void rtw89_release_pkt_list(struct rtw89_dev *rtwdev) continue; list_for_each_entry_safe(info, tmp, &pkt_list[idx], list) { - rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); + if (test_bit(info->id, rtwdev->pkt_offload)) + rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id); list_del(&info->list); kfree(info); } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 675f85c41471..74a691e35287 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -277,6 +277,7 @@ struct rtw89_pktofld_info { u8 ssid_len; u8 bssid[ETH_ALEN]; u16 channel_6ghz; + bool cancel; }; static inline void RTW89_SET_FWCMD_RA_IS_DIS(void *cmd, u32 val) -- cgit v1.2.3 From 8febd68be526c9f256c5490dd4b094a70e1b91ba Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 19 Apr 2023 11:45:58 +0000 Subject: wifi: rtw89: packet offload wait for FW response The H2Cs (host to chip packets) related to packet offload functions need to wait for FW responses in case FW state machine gets wrong and makes driver status no longer able to align FW one. In flow, driver may continuously send multiple H2Cs of packet offload series. If somehow FW doesn't deal with the former yet but the latter has gotten in, it might cause the problem mentioned above. So, we block these H2Cs by rtw89_wait_for_cond(). And then, when the corresponding C2Hs (chip to host packets) is received, we call rtw89_complete_cond(). Besides, RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP's C2H handler should be executed in interrupt context to make our wait/complete process work as expected. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/9ae8c1f105901c65e3171276a9fd6c99ae51803f.camel@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 1 + drivers/net/wireless/realtek/rtw89/core.h | 19 ++++++------ drivers/net/wireless/realtek/rtw89/fw.c | 34 +++++++++++++--------- drivers/net/wireless/realtek/rtw89/fw.h | 48 ++++++++++++++++++++++++------- drivers/net/wireless/realtek/rtw89/mac.c | 22 +++++++++++++- 5 files changed, 90 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index b1bd84f67910..c376dae916e7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3568,6 +3568,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) rtwdev->total_sta_assoc = 0; rtw89_init_wait(&rtwdev->mcc.wait); + rtw89_init_wait(&rtwdev->mac.fw_ofld_wait); INIT_WORK(&rtwdev->c2h_work, rtw89_fw_c2h_work); INIT_WORK(&rtwdev->ips_work, rtw89_ips_work); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 4acf84850f0d..46cb38c5a64f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3278,14 +3278,6 @@ enum rtw89_host_rpr_mode { RTW89_RPR_MODE_STF }; -struct rtw89_mac_info { - struct rtw89_dle_info dle_info; - struct rtw89_hfc_param hfc_param; - enum rtw89_qta_mode qta_mode; - u8 rpwm_seq_num; - u8 cpwm_seq_num; -}; - #define RTW89_COMPLETION_BUF_SIZE 24 #define RTW89_WAIT_COND_IDLE UINT_MAX @@ -3308,6 +3300,17 @@ static inline void rtw89_init_wait(struct rtw89_wait_info *wait) atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE); } +struct rtw89_mac_info { + struct rtw89_dle_info dle_info; + struct rtw89_hfc_param hfc_param; + enum rtw89_qta_mode qta_mode; + u8 rpwm_seq_num; + u8 cpwm_seq_num; + + /* see RTW89_FW_OFLD_WAIT_COND series for wait condition */ + struct rtw89_wait_info fw_ofld_wait; +}; + enum rtw89_fw_type { RTW89_FW_NORMAL = 1, RTW89_FW_WOWLAN = 3, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 2390bcb3b46a..84e04b5a5f00 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -14,6 +14,8 @@ static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb); +static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, + struct rtw89_wait_info *wait, unsigned int cond); static struct sk_buff *rtw89_fw_h2c_alloc_skb(struct rtw89_dev *rtwdev, u32 len, bool header) @@ -2440,7 +2442,9 @@ fail: #define H2C_LEN_PKT_OFLD 4 int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id) { + struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct sk_buff *skb; + unsigned int cond; u8 *cmd; int ret; @@ -2460,24 +2464,26 @@ int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id) H2C_FUNC_PACKET_OFLD, 1, 1, H2C_LEN_PKT_OFLD); - ret = rtw89_h2c_tx(rtwdev, skb, false); + cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(id, RTW89_PKT_OFLD_OP_DEL); + + ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); if (ret) { - rtw89_err(rtwdev, "failed to send h2c\n"); - goto fail; + rtw89_debug(rtwdev, RTW89_DBG_FW, + "failed to del pkt ofld: id %d, ret %d\n", + id, ret); + return ret; } rtw89_core_release_bit_map(rtwdev->pkt_offload, id); return 0; -fail: - dev_kfree_skb_any(skb); - - return ret; } int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, struct sk_buff *skb_ofld) { + struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct sk_buff *skb; + unsigned int cond; u8 *cmd; u8 alloc_id; int ret; @@ -2508,18 +2514,18 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, H2C_FUNC_PACKET_OFLD, 1, 1, H2C_LEN_PKT_OFLD + skb_ofld->len); - ret = rtw89_h2c_tx(rtwdev, skb, false); + cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(alloc_id, RTW89_PKT_OFLD_OP_ADD); + + ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); if (ret) { - rtw89_err(rtwdev, "failed to send h2c\n"); + rtw89_debug(rtwdev, RTW89_DBG_FW, + "failed to add pkt ofld: id %d, ret %d\n", + alloc_id, ret); rtw89_core_release_bit_map(rtwdev->pkt_offload, alloc_id); - goto fail; + return ret; } return 0; -fail: - dev_kfree_skb_any(skb); - - return ret; } #define H2C_LEN_SCAN_LIST_OFFLOAD 4 diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 74a691e35287..b7c8f6f0506d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -138,8 +138,13 @@ enum rtw89_pkt_offload_op { RTW89_PKT_OFLD_OP_ADD, RTW89_PKT_OFLD_OP_DEL, RTW89_PKT_OFLD_OP_READ, + + NUM_OF_RTW89_PKT_OFFLOAD_OP, }; +#define RTW89_PKT_OFLD_WAIT_TAG(pkt_id, pkt_op) \ + ((pkt_id) * NUM_OF_RTW89_PKT_OFFLOAD_OP + (pkt_op)) + enum rtw89_scanofld_notify_reason { RTW89_SCAN_DWELL_NOTIFY, RTW89_SCAN_PRE_TX_NOTIFY, @@ -3340,6 +3345,16 @@ static_assert(sizeof(struct rtw89_mac_mcc_tsf_rpt) <= RTW89_COMPLETION_BUF_SIZE) #define RTW89_GET_MAC_C2H_MCC_STATUS_RPT_TSF_HIGH(c2h) \ le32_get_bits(*((const __le32 *)(c2h) + 4), GENMASK(31, 0)) +struct rtw89_c2h_pkt_ofld_rsp { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; + +#define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_ID GENMASK(7, 0) +#define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_OP GENMASK(10, 8) +#define RTW89_C2H_PKT_OFLD_RSP_W2_PTK_LEN GENMASK(31, 16) + struct rtw89_h2c_bcnfltr { __le32 w0; } __packed; @@ -3498,17 +3513,28 @@ struct rtw89_fw_h2c_rf_reg_info { /* CLASS 9 - FW offload */ #define H2C_CL_MAC_FW_OFLD 0x9 -#define H2C_FUNC_PACKET_OFLD 0x1 -#define H2C_FUNC_MAC_MACID_PAUSE 0x8 -#define H2C_FUNC_USR_EDCA 0xF -#define H2C_FUNC_TSF32_TOGL 0x10 -#define H2C_FUNC_OFLD_CFG 0x14 -#define H2C_FUNC_ADD_SCANOFLD_CH 0x16 -#define H2C_FUNC_SCANOFLD 0x17 -#define H2C_FUNC_PKT_DROP 0x1b -#define H2C_FUNC_CFG_BCNFLTR 0x1e -#define H2C_FUNC_OFLD_RSSI 0x1f -#define H2C_FUNC_OFLD_TP 0x20 +enum rtw89_fw_ofld_h2c_func { + H2C_FUNC_PACKET_OFLD = 0x1, + H2C_FUNC_MAC_MACID_PAUSE = 0x8, + H2C_FUNC_USR_EDCA = 0xF, + H2C_FUNC_TSF32_TOGL = 0x10, + H2C_FUNC_OFLD_CFG = 0x14, + H2C_FUNC_ADD_SCANOFLD_CH = 0x16, + H2C_FUNC_SCANOFLD = 0x17, + H2C_FUNC_PKT_DROP = 0x1b, + H2C_FUNC_CFG_BCNFLTR = 0x1e, + H2C_FUNC_OFLD_RSSI = 0x1f, + H2C_FUNC_OFLD_TP = 0x20, + + NUM_OF_RTW89_FW_OFLD_H2C_FUNC, +}; + +#define RTW89_FW_OFLD_WAIT_COND(tag, func) \ + ((tag) * NUM_OF_RTW89_FW_OFLD_H2C_FUNC + (func)) + +#define RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(pkt_id, pkt_op) \ + RTW89_FW_OFLD_WAIT_COND(RTW89_PKT_OFLD_WAIT_TAG(pkt_id, pkt_op), \ + H2C_FUNC_PACKET_OFLD) /* CLASS 10 - Security CAM */ #define H2C_CL_MAC_SEC_CAM 0xa diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 50ea4bf67275..695c80865872 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4369,9 +4369,22 @@ rtw89_mac_c2h_bcn_cnt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) } static void -rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, +rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len) { + struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; + const struct rtw89_c2h_pkt_ofld_rsp *c2h = + (const struct rtw89_c2h_pkt_ofld_rsp *)skb_c2h->data; + u16 pkt_len = le32_get_bits(c2h->w2, RTW89_C2H_PKT_OFLD_RSP_W2_PTK_LEN); + u8 pkt_id = le32_get_bits(c2h->w2, RTW89_C2H_PKT_OFLD_RSP_W2_PTK_ID); + u8 pkt_op = le32_get_bits(c2h->w2, RTW89_C2H_PKT_OFLD_RSP_W2_PTK_OP); + struct rtw89_completion_data data = {}; + unsigned int cond; + + data.err = !pkt_len; + cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(pkt_id, pkt_op); + + rtw89_complete_cond(wait, cond, &data); } static void @@ -4579,6 +4592,13 @@ bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) switch (class) { default: return false; + case RTW89_MAC_C2H_CLASS_OFLD: + switch (func) { + default: + return false; + case RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP: + return true; + } case RTW89_MAC_C2H_CLASS_MCC: return true; } -- cgit v1.2.3 From 32bb12eb73dceeb78c04a46c333f6f319cf1cebd Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 19 Apr 2023 11:46:01 +0000 Subject: wifi: rtw89: mac: handle C2H receive/done ACK in interrupt context We have some MAC H2Cs (host to chip packets), which have no clear individual C2Hs (chip to host packets) to indicate FW execution response, but they are going to require to wait for FW completion. So, we have to deal with this via common MAC C2H receive/done ACKs. This commit changes the context, where common MAC C2H receive/done ACK handlers are executed, to interrupt context. And, code comments are added to prevent future commits from using it incorrectly. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/c4d766885e00b9f9dcf7954a80096c8b9d21149b.camel@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 695c80865872..97b1deaddaa0 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4336,6 +4336,8 @@ rtw89_mac_c2h_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, static void rtw89_mac_c2h_rec_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { + /* N.B. This will run in interrupt context. */ + rtw89_debug(rtwdev, RTW89_DBG_FW, "C2H rev ack recv, cat: %d, class: %d, func: %d, seq : %d\n", RTW89_GET_MAC_C2H_REV_ACK_CAT(c2h->data), @@ -4347,6 +4349,8 @@ rtw89_mac_c2h_rec_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) static void rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { + /* N.B. This will run in interrupt context. */ + rtw89_debug(rtwdev, RTW89_DBG_FW, "C2H done ack recv, cat: %d, class: %d, func: %d, ret: %d, seq : %d\n", RTW89_GET_MAC_C2H_DONE_ACK_CAT(c2h->data), @@ -4592,6 +4596,14 @@ bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) switch (class) { default: return false; + case RTW89_MAC_C2H_CLASS_INFO: + switch (func) { + default: + return false; + case RTW89_MAC_C2H_FUNC_REC_ACK: + case RTW89_MAC_C2H_FUNC_DONE_ACK: + return true; + } case RTW89_MAC_C2H_CLASS_OFLD: switch (func) { default: -- cgit v1.2.3 From b9b632f43f1c8b59ea3d23f7ea941616322dab5a Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 19 Apr 2023 11:46:03 +0000 Subject: wifi: rtw89: scan offload wait for FW done ACK The following are scan offload related H2C (host to chip) function types. * H2C_FUNC_ADD_SCANOFLD_CH * H2C_FUNC_SCANOFLD Before doing FW scan, we will continuously send multiple H2Cs with above types which are used to tell FW the scan configuration of this time. But, if FW doesn't handle one of these H2Cs well, the FW scan process might not run as expected and driver should notice it early. So, this commits makes scan offload related H2Cs wait for FW done ACK via rtw89_wait_for_cond() and rtw89_complete_cond(). And, we check the return code of these H2Cs from FW. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/a15f4bd594f71d7602ea67698b035805143700c9.camel@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 28 +++++++++++------------ drivers/net/wireless/realtek/rtw89/fw.h | 21 +++++++++-------- drivers/net/wireless/realtek/rtw89/mac.c | 39 +++++++++++++++++++++++++++----- 3 files changed, 58 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 84e04b5a5f00..f85f9ce2a7c1 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2532,9 +2532,11 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len, struct list_head *chan_list) { + struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_mac_chinfo *ch_info; struct sk_buff *skb; int skb_len = H2C_LEN_SCAN_LIST_OFFLOAD + len * RTW89_MAC_CHINFO_SIZE; + unsigned int cond; u8 *cmd; int ret; @@ -2581,27 +2583,27 @@ int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len); - ret = rtw89_h2c_tx(rtwdev, skb, false); + cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH); + + ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); if (ret) { - rtw89_err(rtwdev, "failed to send h2c\n"); - goto fail; + rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to add scan ofld ch\n"); + return ret; } return 0; -fail: - dev_kfree_skb_any(skb); - - return ret; } int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, struct rtw89_vif *rtwvif) { + struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_chan *op = &rtwdev->scan_info.op_chan; struct rtw89_h2c_scanofld *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; + unsigned int cond; int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); @@ -2640,17 +2642,15 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, H2C_FUNC_SCANOFLD, 1, 1, len); - ret = rtw89_h2c_tx(rtwdev, skb, false); + cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD); + + ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); if (ret) { - rtw89_err(rtwdev, "failed to send h2c\n"); - goto fail; + rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to scan ofld\n"); + return ret; } return 0; -fail: - dev_kfree_skb_any(skb); - - return ret; } int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index b7c8f6f0506d..22a187e41965 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3221,16 +3221,17 @@ static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb) #define RTW89_GET_C2H_LOG_SRT_PRT(c2h) (char *)((__le32 *)(c2h) + 2) #define RTW89_GET_C2H_LOG_LEN(len) ((len) - RTW89_C2H_HEADER_LEN) -#define RTW89_GET_MAC_C2H_DONE_ACK_CAT(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(1, 0)) -#define RTW89_GET_MAC_C2H_DONE_ACK_CLASS(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 2)) -#define RTW89_GET_MAC_C2H_DONE_ACK_FUNC(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(15, 8)) -#define RTW89_GET_MAC_C2H_DONE_ACK_H2C_RETURN(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 16)) -#define RTW89_GET_MAC_C2H_DONE_ACK_H2C_SEQ(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 24)) +struct rtw89_c2h_done_ack { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; + +#define RTW89_C2H_DONE_ACK_W2_CAT GENMASK(1, 0) +#define RTW89_C2H_DONE_ACK_W2_CLASS GENMASK(7, 2) +#define RTW89_C2H_DONE_ACK_W2_FUNC GENMASK(15, 8) +#define RTW89_C2H_DONE_ACK_W2_H2C_RETURN GENMASK(23, 16) +#define RTW89_C2H_DONE_ACK_W2_H2C_SEQ GENMASK(31, 24) #define RTW89_GET_MAC_C2H_REV_ACK_CAT(c2h) \ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(1, 0)) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 97b1deaddaa0..0c3a1153c871 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4347,17 +4347,44 @@ rtw89_mac_c2h_rec_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) } static void -rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len) { /* N.B. This will run in interrupt context. */ + struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + const struct rtw89_c2h_done_ack *c2h = + (const struct rtw89_c2h_done_ack *)skb_c2h->data; + u8 h2c_cat = le32_get_bits(c2h->w2, RTW89_C2H_DONE_ACK_W2_CAT); + u8 h2c_class = le32_get_bits(c2h->w2, RTW89_C2H_DONE_ACK_W2_CLASS); + u8 h2c_func = le32_get_bits(c2h->w2, RTW89_C2H_DONE_ACK_W2_FUNC); + u8 h2c_return = le32_get_bits(c2h->w2, RTW89_C2H_DONE_ACK_W2_H2C_RETURN); + u8 h2c_seq = le32_get_bits(c2h->w2, RTW89_C2H_DONE_ACK_W2_H2C_SEQ); + struct rtw89_completion_data data = {}; + unsigned int cond; rtw89_debug(rtwdev, RTW89_DBG_FW, "C2H done ack recv, cat: %d, class: %d, func: %d, ret: %d, seq : %d\n", - RTW89_GET_MAC_C2H_DONE_ACK_CAT(c2h->data), - RTW89_GET_MAC_C2H_DONE_ACK_CLASS(c2h->data), - RTW89_GET_MAC_C2H_DONE_ACK_FUNC(c2h->data), - RTW89_GET_MAC_C2H_DONE_ACK_H2C_RETURN(c2h->data), - RTW89_GET_MAC_C2H_DONE_ACK_H2C_SEQ(c2h->data)); + h2c_cat, h2c_class, h2c_func, h2c_return, h2c_seq); + + if (h2c_cat != H2C_CAT_MAC) + return; + + switch (h2c_class) { + default: + return; + case H2C_CL_MAC_FW_OFLD: + switch (h2c_func) { + default: + return; + case H2C_FUNC_ADD_SCANOFLD_CH: + case H2C_FUNC_SCANOFLD: + cond = RTW89_FW_OFLD_WAIT_COND(0, h2c_func); + break; + } + + data.err = !!h2c_return; + rtw89_complete_cond(fw_ofld_wait, cond, &data); + return; + } } static void -- cgit v1.2.3 From c8d89bf6b82f421dda16526233aba264d1331332 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Apr 2023 10:45:44 +0800 Subject: wifi: rtw89: 8851b: add 8851B basic chip_info 8851B is a 1x1 80 MHz bandwidth chip working on 2/5 GHz. Add these basic information, and more settings will be added by functions. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421024551.29994-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 101 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.h | 15 ++++ 2 files changed, 116 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8851b.c create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8851b.h diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c new file mode 100644 index 000000000000..a0aaac74b0ec --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2022-2023 Realtek Corporation + */ + +#include "coex.h" +#include "fw.h" +#include "mac.h" +#include "phy.h" +#include "reg.h" +#include "rtw8851b.h" +#include "rtw8851b_table.h" +#include "txrx.h" +#include "util.h" + +#define RTW8851B_FW_FORMAT_MAX 0 +#define RTW8851B_FW_BASENAME "rtw89/rtw8851b_fw" +#define RTW8851B_MODULE_FIRMWARE \ + RTW8851B_FW_BASENAME ".bin" + +static const struct rtw89_chip_ops rtw8851b_chip_ops = { + .fem_setup = NULL, + .fill_txdesc = rtw89_core_fill_txdesc, + .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, + .h2c_dctl_sec_cam = NULL, +}; + +const struct rtw89_chip_info rtw8851b_chip_info = { + .chip_id = RTL8851B, + .ops = &rtw8851b_chip_ops, + .fw_basename = RTW8851B_FW_BASENAME, + .fw_format_max = RTW8851B_FW_FORMAT_MAX, + .try_ce_fw = true, + .fifo_size = 196608, + .dle_scc_rsvd_size = 98304, + .max_amsdu_limit = 3500, + .dis_2g_40m_ul_ofdma = true, + .rsvd_ple_ofst = 0x2f800, + .wde_qempty_acq_num = 4, + .wde_qempty_mgq_sel = 4, + .rf_base_addr = {0xe000}, + .pwr_on_seq = NULL, + .pwr_off_seq = NULL, + .bb_table = &rtw89_8851b_phy_bb_table, + .bb_gain_table = &rtw89_8851b_phy_bb_gain_table, + .rf_table = {&rtw89_8851b_phy_radioa_table,}, + .nctl_table = &rtw89_8851b_phy_nctl_table, + .byr_table = &rtw89_8851b_byr_table, + .dflt_parms = &rtw89_8851b_dflt_parms, + .rfe_parms_conf = rtw89_8851b_rfe_parms_conf, + .txpwr_factor_rf = 2, + .txpwr_factor_mac = 1, + .dig_table = NULL, + .tssi_dbw_table = NULL, + .support_chanctx_num = 0, + .support_bands = BIT(NL80211_BAND_2GHZ) | + BIT(NL80211_BAND_5GHZ), + .support_bw160 = false, + .support_ul_tb_ctrl = true, + .hw_sec_hdr = false, + .rf_path_num = 1, + .tx_nss = 1, + .rx_nss = 1, + .acam_num = 32, + .bcam_num = 20, + .scam_num = 128, + .bacam_num = 2, + .bacam_dynamic_num = 4, + .bacam_v1 = false, + .sec_ctrl_efuse_size = 4, + .physical_efuse_size = 1216, + .logical_efuse_size = 2048, + .limit_efuse_size = 1280, + .dav_phy_efuse_size = 0, + .dav_log_efuse_size = 0, + .phycap_addr = 0x580, + .phycap_size = 128, + .para_ver = 0, + .wlcx_desired = 0x06000000, + .btcx_desired = 0x7, + .scbd = 0x1, + .mailbox = 0x1, + + .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) | + BIT(RTW89_PS_MODE_CLK_GATED), + .low_power_hci_modes = 0, + .h2c_cctl_func_id = H2C_FUNC_MAC_CCTLINFO_UD, + .hci_func_en_addr = R_AX_HCI_FUNC_EN, + .h2c_desc_size = sizeof(struct rtw89_txwd_body), + .txwd_body_size = sizeof(struct rtw89_txwd_body), + .bss_clr_map_reg = R_BSS_CLR_MAP_V1, + .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | + BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | + BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), + .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1, +}; +EXPORT_SYMBOL(rtw8851b_chip_info); + +MODULE_FIRMWARE(RTW8851B_MODULE_FIRMWARE); +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8851B driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.h b/drivers/net/wireless/realtek/rtw89/rtw8851b.h new file mode 100644 index 000000000000..e34b7d09ad6d --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2022-2023 Realtek Corporation + */ + +#ifndef __RTW89_8851B_H__ +#define __RTW89_8851B_H__ + +#include "core.h" + +#define RF_PATH_NUM_8851B 1 +#define BB_PATH_NUM_8851B 1 + +extern const struct rtw89_chip_info rtw8851b_chip_info; + +#endif -- cgit v1.2.3 From 99ff8da56322cda9eb9b37021e27b127c2d1cad8 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Apr 2023 10:45:45 +0800 Subject: wifi: rtw89: 8851be: add 8851BE PCI entry and fill PCI capabilities Add PCI entry to 8851BE with its device ID 10ec:b851, also fill PCI info according to its capabilities. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421024551.29994-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851be.c | 86 ++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8851be.c diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c new file mode 100644 index 000000000000..0f7711c50bd1 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2022-2023 Realtek Corporation + */ + +#include +#include + +#include "pci.h" +#include "reg.h" +#include "rtw8851b.h" + +static const struct rtw89_pci_info rtw8851b_pci_info = { + .txbd_trunc_mode = MAC_AX_BD_TRUNC, + .rxbd_trunc_mode = MAC_AX_BD_TRUNC, + .rxbd_mode = MAC_AX_RXBD_PKT, + .tag_mode = MAC_AX_TAG_MULTI, + .tx_burst = MAC_AX_TX_BURST_2048B, + .rx_burst = MAC_AX_RX_BURST_128B, + .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS, + .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS, + .multi_tag_num = MAC_AX_TAG_NUM_8, + .lbc_en = MAC_AX_PCIE_ENABLE, + .lbc_tmr = MAC_AX_LBC_TMR_2MS, + .autok_en = MAC_AX_PCIE_DISABLE, + .io_rcy_en = MAC_AX_PCIE_DISABLE, + .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS, + + .init_cfg_reg = R_AX_PCIE_INIT_CFG1, + .txhci_en_bit = B_AX_TXHCI_EN, + .rxhci_en_bit = B_AX_RXHCI_EN, + .rxbd_mode_bit = B_AX_RXBD_MODE, + .exp_ctrl_reg = R_AX_PCIE_EXP_CTRL, + .max_tag_num_mask = B_AX_MAX_TAG_NUM, + .rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR, + .txbd_rwptr_clr2_reg = 0, + .dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1}, + .dma_stop2 = {0}, + .dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1}, + .dma_busy2_reg = 0, + .dma_busy3_reg = R_AX_PCIE_DMA_BUSY1, + + .rpwm_addr = R_AX_PCIE_HRPWM, + .cpwm_addr = R_AX_CPWM, + .tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) | + BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) | + BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11), + .bd_idx_addr_low_power = NULL, + .dma_addr_set = &rtw89_pci_ch_dma_addr_set, + .bd_ram_table = &rtw89_bd_ram_table_single, + + .ltr_set = rtw89_pci_ltr_set, + .fill_txaddr_info = rtw89_pci_fill_txaddr_info, + .config_intr_mask = rtw89_pci_config_intr_mask, + .enable_intr = rtw89_pci_enable_intr, + .disable_intr = rtw89_pci_disable_intr, + .recognize_intrs = rtw89_pci_recognize_intrs, +}; + +static const struct rtw89_driver_info rtw89_8851be_info = { + .chip = &rtw8851b_chip_info, + .bus = { + .pci = &rtw8851b_pci_info, + }, +}; + +static const struct pci_device_id rtw89_8851be_id_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xb851), + .driver_data = (kernel_ulong_t)&rtw89_8851be_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(pci, rtw89_8851be_id_table); + +static struct pci_driver rtw89_8851be_driver = { + .name = "rtw89_8851be", + .id_table = rtw89_8851be_id_table, + .probe = rtw89_pci_probe, + .remove = rtw89_pci_remove, + .driver.pm = &rtw89_pm_ops, +}; +module_pci_driver(rtw89_8851be_driver); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8851BE driver"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From a24be8bbcbd22cfa53134f6dd399f026874aaa72 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Apr 2023 10:45:46 +0800 Subject: wifi: rtw89: 8851b: add NCTL post table NCTL (nano-controller) is used to assist RF calibration that sends commands to NCTL so it can reduce IO from driver. 8851B needs additional settings, so add a table to do things. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421024551.29994-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/phy.c | 6 +++++- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 ++ drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 46cb38c5a64f..26997b7fccaf 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3192,6 +3192,7 @@ struct rtw89_chip_info { const struct rtw89_phy_table *bb_gain_table; const struct rtw89_phy_table *rf_table[RF_PATH_MAX]; const struct rtw89_phy_table *nctl_table; + const struct rtw89_rfk_tbl *nctl_post_table; const struct rtw89_txpwr_table *byr_table; const struct rtw89_phy_dig_gain_table *dig_table; const struct rtw89_dig_regs *dig_regs; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 5eac00cd5188..47454cfad031 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1401,7 +1401,8 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x3); rtw89_phy_write32_set(rtwdev, R_GNT_BT_WGT_EN, 0x1); rtw89_phy_write32_set(rtwdev, R_P0_PATH_RST, 0x8000000); - rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000); + if (chip->chip_id != RTL8851B) + rtw89_phy_write32_set(rtwdev, R_P1_PATH_RST, 0x8000000); if (chip->chip_id == RTL8852B) rtw89_phy_write32_set(rtwdev, R_IOQ_IQK_DPK, 0x2); @@ -1415,6 +1416,9 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) nctl_table = chip->nctl_table; rtw89_phy_init_reg(rtwdev, nctl_table, rtw89_phy_config_bb_reg, NULL); + + if (chip->nctl_post_table) + rtw89_rfk_parser(rtwdev, chip->nctl_post_table); } static u32 rtw89_phy0_phy1_offset(struct rtw89_dev *rtwdev, u32 addr) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index a0aaac74b0ec..a67a43303592 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -8,6 +8,7 @@ #include "phy.h" #include "reg.h" #include "rtw8851b.h" +#include "rtw8851b_rfk_table.h" #include "rtw8851b_table.h" #include "txrx.h" #include "util.h" @@ -44,6 +45,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .bb_gain_table = &rtw89_8851b_phy_bb_gain_table, .rf_table = {&rtw89_8851b_phy_radioa_table,}, .nctl_table = &rtw89_8851b_phy_nctl_table, + .nctl_post_table = &rtw8851b_nctl_post_defs_tbl, .byr_table = &rtw89_8851b_byr_table, .dflt_parms = &rtw89_8851b_dflt_parms, .rfe_parms_conf = rtw89_8851b_rfe_parms_conf, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index d7930efd89b7..1e1e6d0af551 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2085,6 +2085,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .rf_table = {&rtw89_8852a_phy_radioa_table, &rtw89_8852a_phy_radiob_table,}, .nctl_table = &rtw89_8852a_phy_nctl_table, + .nctl_post_table = NULL, .byr_table = &rtw89_8852a_byr_table, .dflt_parms = &rtw89_8852a_dflt_parms, .rfe_parms_conf = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index eaa2ea0586bc..f12d250f0312 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2522,6 +2522,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .rf_table = {&rtw89_8852b_phy_radioa_table, &rtw89_8852b_phy_radiob_table,}, .nctl_table = &rtw89_8852b_phy_nctl_table, + .nctl_post_table = NULL, .byr_table = &rtw89_8852b_byr_table, .dflt_parms = &rtw89_8852b_dflt_parms, .rfe_parms_conf = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index ceb819a62efc..347a19b8eaa0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2821,6 +2821,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .rf_table = {&rtw89_8852c_phy_radiob_table, &rtw89_8852c_phy_radioa_table,}, .nctl_table = &rtw89_8852c_phy_nctl_table, + .nctl_post_table = NULL, .byr_table = &rtw89_8852c_byr_table, .dflt_parms = &rtw89_8852c_dflt_parms, .rfe_parms_conf = NULL, -- cgit v1.2.3 From 0789881aa3703b2ceb4c0f9a9c7d69f3fb7efd8d Mon Sep 17 00:00:00 2001 From: Chia-Yuan Li Date: Fri, 21 Apr 2023 10:45:47 +0800 Subject: wifi: rtw89: add CFO XTAL registers field to support 8851B Since CFO XTAL registers of 8851B is different from 8852A, add a chip_info field to define their difference. Other chips use another interface, so fill NULL to this field. Signed-off-by: Chia-Yuan Li Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421024551.29994-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 7 +++++++ drivers/net/wireless/realtek/rtw89/phy.c | 16 +++++++++------- drivers/net/wireless/realtek/rtw89/reg.h | 6 ++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 7 +++++++ drivers/net/wireless/realtek/rtw89/rtw8852a.c | 7 +++++++ drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + 7 files changed, 38 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 26997b7fccaf..fa5b2038cee7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3101,6 +3101,12 @@ struct rtw89_imr_info { u32 tmac_imr_set; }; +struct rtw89_xtal_info { + u32 xcap_reg; + u32 sc_xo_mask; + u32 sc_xi_mask; +}; + struct rtw89_rrsr_cfgs { struct rtw89_reg3_def ref_rate; struct rtw89_reg3_def rsc; @@ -3246,6 +3252,7 @@ struct rtw89_chip_info { u32 dma_ch_mask; u32 edcca_lvl_reg; const struct wiphy_wowlan_support *wowlan_stub; + const struct rtw89_xtal_info *xtal_info; }; union rtw89_bus_info { diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 47454cfad031..568488da3ff1 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -2343,27 +2343,29 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, static u8 rtw89_phy_cfo_get_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo) { + const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info; u32 reg_mask; if (sc_xo) - reg_mask = B_AX_XTAL_SC_XO_MASK; + reg_mask = xtal->sc_xo_mask; else - reg_mask = B_AX_XTAL_SC_XI_MASK; + reg_mask = xtal->sc_xi_mask; - return (u8)rtw89_read32_mask(rtwdev, R_AX_XTAL_ON_CTRL0, reg_mask); + return (u8)rtw89_read32_mask(rtwdev, xtal->xcap_reg, reg_mask); } static void rtw89_phy_cfo_set_xcap_reg(struct rtw89_dev *rtwdev, bool sc_xo, u8 val) { + const struct rtw89_xtal_info *xtal = rtwdev->chip->xtal_info; u32 reg_mask; if (sc_xo) - reg_mask = B_AX_XTAL_SC_XO_MASK; + reg_mask = xtal->sc_xo_mask; else - reg_mask = B_AX_XTAL_SC_XI_MASK; + reg_mask = xtal->sc_xi_mask; - rtw89_write32_mask(rtwdev, R_AX_XTAL_ON_CTRL0, reg_mask, val); + rtw89_write32_mask(rtwdev, xtal->xcap_reg, reg_mask, val); } static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, @@ -2376,7 +2378,7 @@ static void rtw89_phy_cfo_set_crystal_cap(struct rtw89_dev *rtwdev, if (!force && cfo->crystal_cap == crystal_cap) return; crystal_cap = clamp_t(u8, crystal_cap, 0, 127); - if (chip->chip_id == RTL8852A) { + if (chip->chip_id == RTL8852A || chip->chip_id == RTL8851B) { rtw89_phy_cfo_set_xcap_reg(rtwdev, true, crystal_cap); rtw89_phy_cfo_set_xcap_reg(rtwdev, false, crystal_cap); sc_xo_val = rtw89_phy_cfo_get_xcap_reg(rtwdev, true); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 50da3a3c289a..c396773a9b8c 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -243,6 +243,12 @@ #define B_AX_XTAL_SC_XI_MASK GENMASK(16, 10) #define B_AX_XTAL_SC_MASK GENMASK(6, 0) +#define R_AX_XTAL_ON_CTRL3 0x028C +#define B_AX_XTAL_SC_INIT_A_BLOCK_MASK GENMASK(30, 24) +#define B_AX_XTAL_SC_LPS_A_BLOCK_MASK GENMASK(22, 16) +#define B_AX_XTAL_SC_XO_A_BLOCK_MASK GENMASK(14, 8) +#define B_AX_XTAL_SC_XI_A_BLOCK_MASK GENMASK(6, 0) + #define R_AX_GPIO0_7_FUNC_SEL 0x02D0 #define R_AX_EECS_EESK_FUNC_SEL 0x02D8 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index a67a43303592..cc47bcbabfc9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -18,6 +18,12 @@ #define RTW8851B_MODULE_FIRMWARE \ RTW8851B_FW_BASENAME ".bin" +static const struct rtw89_xtal_info rtw8851b_xtal_info = { + .xcap_reg = R_AX_XTAL_ON_CTRL3, + .sc_xo_mask = B_AX_XTAL_SC_XO_A_BLOCK_MASK, + .sc_xi_mask = B_AX_XTAL_SC_XI_A_BLOCK_MASK, +}; + static const struct rtw89_chip_ops rtw8851b_chip_ops = { .fem_setup = NULL, .fill_txdesc = rtw89_core_fill_txdesc, @@ -94,6 +100,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1, + .xtal_info = &rtw8851b_xtal_info, }; EXPORT_SYMBOL(rtw8851b_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 1e1e6d0af551..bd417c60171a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -463,6 +463,12 @@ static const struct rtw89_imr_info rtw8852a_imr_info = { .tmac_imr_set = B_AX_TMAC_IMR_SET, }; +static const struct rtw89_xtal_info rtw8852a_xtal_info = { + .xcap_reg = R_AX_XTAL_ON_CTRL0, + .sc_xo_mask = B_AX_XTAL_SC_XO_MASK, + .sc_xi_mask = B_AX_XTAL_SC_XI_MASK, +}; + static const struct rtw89_rrsr_cfgs rtw8852a_rrsr_cfgs = { .ref_rate = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_REF_RATE_SEL, 0}, .rsc = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_RSC_MASK, 2}, @@ -2160,6 +2166,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852a, #endif + .xtal_info = &rtw8852a_xtal_info, }; EXPORT_SYMBOL(rtw8852a_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index f12d250f0312..af74d0feeccb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2599,6 +2599,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852b, #endif + .xtal_info = NULL, }; EXPORT_SYMBOL(rtw8852b_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 347a19b8eaa0..3268be8fea6c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2898,6 +2898,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8852c, #endif + .xtal_info = NULL, }; EXPORT_SYMBOL(rtw8852c_chip_info); -- cgit v1.2.3 From ce816ab54bc927f893e17e7e6b9b68e30dd4b4a1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Apr 2023 10:45:48 +0800 Subject: wifi: rtw89: use chip_info::small_fifo_size to choose debug_mask Previously, 8852B has smaller FIFO size than others, so I use chip_id to choose debug_mask before. 8851B has similar design, so add a field to chip_info as a general expression. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421024551.29994-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/pci.c | 4 ++-- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + 6 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index fa5b2038cee7..2347906dd050 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3159,6 +3159,7 @@ struct rtw89_chip_info { u8 fw_format_max; bool try_ce_fw; u32 fifo_size; + bool small_fifo_size; u32 dle_scc_rsvd_size; u16 max_amsdu_limit; bool dis_2g_40m_ul_ofdma; diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 70b4754667c9..b53f346fef97 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1003,10 +1003,10 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, min_cnt = min(bd_cnt, wd_cnt); if (min_cnt == 0) { /* This message can be frequently shown in low power mode or - * high traffic with 8852B, and we have recognized it as normal + * high traffic with small FIFO chips, and we have recognized it as normal * behavior, so print with mask RTW89_DBG_TXRX in these situations. */ - if (rtwpci->low_power || chip->chip_id == RTL8852B) + if (rtwpci->low_power || chip->small_fifo_size) debug_mask = RTW89_DBG_TXRX; else debug_mask = RTW89_DBG_UNEXP; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index cc47bcbabfc9..2c3db08b6831 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -38,6 +38,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .fw_format_max = RTW8851B_FW_FORMAT_MAX, .try_ce_fw = true, .fifo_size = 196608, + .small_fifo_size = true, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index bd417c60171a..58cb99003be9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2075,6 +2075,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .fw_format_max = RTW8852A_FW_FORMAT_MAX, .try_ce_fw = false, .fifo_size = 458752, + .small_fifo_size = false, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index af74d0feeccb..5a67f02557ee 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2506,6 +2506,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .fw_format_max = RTW8852B_FW_FORMAT_MAX, .try_ce_fw = true, .fifo_size = 196608, + .small_fifo_size = true, .dle_scc_rsvd_size = 98304, .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 3268be8fea6c..35ba30f040c7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2805,6 +2805,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .fw_format_max = RTW8852C_FW_FORMAT_MAX, .try_ce_fw = false, .fifo_size = 458752, + .small_fifo_size = false, .dle_scc_rsvd_size = 0, .max_amsdu_limit = 8000, .dis_2g_40m_ul_ofdma = false, -- cgit v1.2.3 From b6335d91607d6297d3f586e8a4dc6ce8f90652e7 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Apr 2023 10:45:49 +0800 Subject: wifi: rtw89: change naming of BA CAM from V1 to V0_EXT BA CAM of 8852C has more entries and more fields of H2C, and needs initialization before using. Due to differences from 8852A/8852B, we name it as V1 before. However, real V1 of BA CAM is introduced now, so change it to V0_EXT to avoid confusing with firmware design. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421024551.29994-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 9 ++++++++- drivers/net/wireless/realtek/rtw89/fw.c | 12 ++++++------ drivers/net/wireless/realtek/rtw89/fw.h | 6 +++--- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852b.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852c.c | 2 +- 7 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 2347906dd050..f697902706ac 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -122,6 +122,13 @@ enum rtw89_cv { CHIP_CV_INVALID = CHIP_CV_MAX, }; +enum rtw89_bacam_ver { + RTW89_BACAM_V0, + RTW89_BACAM_V1, + + RTW89_BACAM_V0_EXT = 99, +}; + enum rtw89_core_tx_type { RTW89_CORE_TX_TYPE_DATA, RTW89_CORE_TX_TYPE_MGMT, @@ -3182,7 +3189,7 @@ struct rtw89_chip_info { u8 scam_num; u8 bacam_num; u8 bacam_dynamic_num; - bool bacam_v1; + enum rtw89_bacam_ver bacam_ver; u8 sec_ctrl_efuse_size; u32 physical_efuse_size; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index f85f9ce2a7c1..ad277f22b197 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -809,7 +809,7 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, } skb_put(skb, H2C_BA_CAM_LEN); SET_BA_CAM_MACID(skb->data, macid); - if (chip->bacam_v1) + if (chip->bacam_ver == RTW89_BACAM_V0_EXT) SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx); else SET_BA_CAM_ENTRY_IDX(skb->data, entry_idx); @@ -825,7 +825,7 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, SET_BA_CAM_INIT_REQ(skb->data, 1); SET_BA_CAM_SSN(skb->data, params->ssn); - if (chip->bacam_v1) { + if (chip->bacam_ver == RTW89_BACAM_V0_EXT) { SET_BA_CAM_STD_EN(skb->data, 1); SET_BA_CAM_BAND(skb->data, rtwvif->mac_idx); } @@ -850,8 +850,8 @@ fail: return ret; } -static int rtw89_fw_h2c_init_dynamic_ba_cam_v1(struct rtw89_dev *rtwdev, - u8 entry_idx, u8 uid) +static int rtw89_fw_h2c_init_ba_cam_v0_ext(struct rtw89_dev *rtwdev, + u8 entry_idx, u8 uid) { struct sk_buff *skb; int ret; @@ -888,7 +888,7 @@ fail: return ret; } -void rtw89_fw_h2c_init_ba_cam_v1(struct rtw89_dev *rtwdev) +void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; u8 entry_idx = chip->bacam_num; @@ -896,7 +896,7 @@ void rtw89_fw_h2c_init_ba_cam_v1(struct rtw89_dev *rtwdev) int i; for (i = 0; i < chip->bacam_dynamic_num; i++) { - rtw89_fw_h2c_init_dynamic_ba_cam_v1(rtwdev, entry_idx, uid); + rtw89_fw_h2c_init_ba_cam_v0_ext(rtwdev, entry_idx, uid); entry_idx++; uid++; } diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 22a187e41965..048283750a2d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -3676,7 +3676,7 @@ void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw); int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params); -void rtw89_fw_h2c_init_ba_cam_v1(struct rtw89_dev *rtwdev); +void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param); @@ -3739,8 +3739,8 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; - if (chip->bacam_v1) - rtw89_fw_h2c_init_ba_cam_v1(rtwdev); + if (chip->bacam_ver == RTW89_BACAM_V0_EXT) + rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(rtwdev); } #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 2c3db08b6831..5ed699ab75a4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -74,7 +74,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .scam_num = 128, .bacam_num = 2, .bacam_dynamic_num = 4, - .bacam_v1 = false, + .bacam_ver = RTW89_BACAM_V0, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 58cb99003be9..a8a58ff36e95 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2115,7 +2115,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .scam_num = 128, .bacam_num = 2, .bacam_dynamic_num = 4, - .bacam_v1 = false, + .bacam_ver = RTW89_BACAM_V0, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 1536, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 5a67f02557ee..fa12d4a7f79f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2546,7 +2546,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .scam_num = 128, .bacam_num = 2, .bacam_dynamic_num = 4, - .bacam_v1 = false, + .bacam_ver = RTW89_BACAM_V0, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 35ba30f040c7..d9272bce0325 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2846,7 +2846,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .scam_num = 128, .bacam_num = 8, .bacam_dynamic_num = 8, - .bacam_v1 = true, + .bacam_ver = RTW89_BACAM_V0_EXT, .sec_ctrl_efuse_size = 4, .physical_efuse_size = 1216, .logical_efuse_size = 2048, -- cgit v1.2.3 From 2273dd724a6c6083e126828e56ff9a0a78913449 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Fri, 21 Apr 2023 10:45:50 +0800 Subject: wifi: rtw89: 8851b: add support WoWLAN to 8851B Add WoWLAN stub to 8851B, and decalre this chip can support magic packet and disconnect wakeup. Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421024551.29994-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 12 ++++++++++++ drivers/net/wireless/realtek/rtw89/wow.c | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 5ed699ab75a4..ce5c7a8644c3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -31,6 +31,15 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .h2c_dctl_sec_cam = NULL, }; +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support rtw_wowlan_stub_8851b = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, + .n_patterns = RTW89_MAX_PATTERN_NUM, + .pattern_max_len = RTW89_MAX_PATTERN_SIZE, + .pattern_min_len = 1, +}; +#endif + const struct rtw89_chip_info rtw8851b_chip_info = { .chip_id = RTL8851B, .ops = &rtw8851b_chip_ops, @@ -101,6 +110,9 @@ const struct rtw89_chip_info rtw8851b_chip_info = { BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI), .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1, +#ifdef CONFIG_PM + .wowlan_stub = &rtw_wowlan_stub_8851b, +#endif .xtal_info = &rtw8851b_xtal_info, }; EXPORT_SYMBOL(rtw8851b_chip_info); diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 2ca8abb70f11..364e54622150 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -91,7 +91,7 @@ static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev) u32 wow_reason_reg; u8 reason; - if (chip_id == RTL8852A || chip_id == RTL8852B) + if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) wow_reason_reg = R_AX_C2HREG_DATA3 + 3; else wow_reason_reg = R_AX_C2HREG_DATA3_V1 + 3; -- cgit v1.2.3 From 85d1539c0273402911cee89cde1190cd4aec731f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 21 Apr 2023 10:45:51 +0800 Subject: wifi: rtw89: 8851b: add DLE mem and HFC quota Configure DLE (data link engine) memory size for operating modes. Similarly, HFC standing for HCI flow control is used to set quota according to operating modes, which are SCC or download firmware. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421024551.29994-9-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.c | 2 ++ drivers/net/wireless/realtek/rtw89/mac.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 50 +++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 0c3a1153c871..64dc36470840 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -1475,6 +1475,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_qt_52a_wow = {264, 0, 32, 20, 64, 13, 1005, 0, 64, 128, 120,}, /* 8852B PCIE WOW */ .ple_qt_52b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, + /* 8851B PCIE WOW */ + .ple_qt_51b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,}, }; EXPORT_SYMBOL(rtw89_mac_size); diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index a8d9847ef0b4..d3922d4fe288 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -817,6 +817,7 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt58; const struct rtw89_ple_quota ple_qt_52a_wow; const struct rtw89_ple_quota ple_qt_52b_wow; + const struct rtw89_ple_quota ple_qt_51b_wow; }; extern const struct rtw89_mac_size_set rtw89_mac_size; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index ce5c7a8644c3..b68ebe950c4e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -18,6 +18,54 @@ #define RTW8851B_MODULE_FIRMWARE \ RTW8851B_FW_BASENAME ".bin" +static const struct rtw89_hfc_ch_cfg rtw8851b_hfc_chcfg_pcie[] = { + {5, 343, grp_0}, /* ACH 0 */ + {5, 343, grp_0}, /* ACH 1 */ + {5, 343, grp_0}, /* ACH 2 */ + {5, 343, grp_0}, /* ACH 3 */ + {0, 0, grp_0}, /* ACH 4 */ + {0, 0, grp_0}, /* ACH 5 */ + {0, 0, grp_0}, /* ACH 6 */ + {0, 0, grp_0}, /* ACH 7 */ + {4, 344, grp_0}, /* B0MGQ */ + {4, 344, grp_0}, /* B0HIQ */ + {0, 0, grp_0}, /* B1MGQ */ + {0, 0, grp_0}, /* B1HIQ */ + {40, 0, 0} /* FWCMDQ */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8851b_hfc_pubcfg_pcie = { + 448, /* Group 0 */ + 0, /* Group 1 */ + 448, /* Public Max */ + 0 /* WP threshold */ +}; + +static const struct rtw89_hfc_param_ini rtw8851b_hfc_param_ini_pcie[] = { + [RTW89_QTA_SCC] = {rtw8851b_hfc_chcfg_pcie, &rtw8851b_hfc_pubcfg_pcie, + &rtw89_mac_size.hfc_preccfg_pcie, RTW89_HCIFC_POH}, + [RTW89_QTA_DLFW] = {NULL, NULL, &rtw89_mac_size.hfc_preccfg_pcie, + RTW89_HCIFC_POH}, + [RTW89_QTA_INVALID] = {NULL}, +}; + +static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size6, + &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6, + &rtw89_mac_size.wde_qt6, &rtw89_mac_size.ple_qt18, + &rtw89_mac_size.ple_qt58}, + [RTW89_QTA_WOW] = {RTW89_QTA_WOW, &rtw89_mac_size.wde_size6, + &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6, + &rtw89_mac_size.wde_qt6, &rtw89_mac_size.ple_qt18, + &rtw89_mac_size.ple_qt_51b_wow}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + static const struct rtw89_xtal_info rtw8851b_xtal_info = { .xcap_reg = R_AX_XTAL_ON_CTRL3, .sc_xo_mask = B_AX_XTAL_SC_XO_A_BLOCK_MASK, @@ -52,6 +100,8 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, + .hfc_param_ini = rtw8851b_hfc_param_ini_pcie, + .dle_mem = rtw8851b_dle_mem_pcie, .wde_qempty_acq_num = 4, .wde_qempty_mgq_sel = 4, .rf_base_addr = {0xe000}, -- cgit v1.2.3 From 2a59fe291fb3f1cbe6f08b96b47af84b9fd5b207 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 24 Apr 2023 14:52:38 +0800 Subject: wifi: rtw89: 8851b: add set_channel_rf() Add to set RF registers according to the channel we want to switch. The callers will be added afterward. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230424065242.17477-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 239 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 14 ++ 2 files changed, 253 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c new file mode 100644 index 000000000000..9276e852bb05 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2022-2023 Realtek Corporation + */ + +#include "coex.h" +#include "debug.h" +#include "mac.h" +#include "phy.h" +#include "reg.h" +#include "rtw8851b.h" +#include "rtw8851b_rfk.h" +#include "rtw8851b_rfk_table.h" +#include "rtw8851b_table.h" + +static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + return RF_A; +} + +static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + enum rtw89_bandwidth bw, bool dav) +{ + u32 reg18_addr = dav ? RR_CFGCH : RR_CFGCH_V1; + u32 rf_reg18; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]===> %s\n", __func__); + + rf_reg18 = rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK); + if (rf_reg18 == INV_RF_DATA) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]Invalid RF_0x18 for Path-%d\n", path); + return; + } + rf_reg18 &= ~RR_CFGCH_BW; + + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + case RTW89_CHANNEL_WIDTH_10: + case RTW89_CHANNEL_WIDTH_20: + rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_20M); + break; + case RTW89_CHANNEL_WIDTH_40: + rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_40M); + break; + case RTW89_CHANNEL_WIDTH_80: + rf_reg18 |= FIELD_PREP(RR_CFGCH_BW, CFGCH_BW_80M); + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]Fail to set CH\n"); + } + + rf_reg18 &= ~(RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH | RR_CFGCH_BCN | + RR_CFGCH_BW2) & RFREG_MASK; + rf_reg18 |= RR_CFGCH_BW2; + rtw89_write_rf(rtwdev, path, reg18_addr, RFREG_MASK, rf_reg18); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK] set %x at path%d, %x =0x%x\n", + bw, path, reg18_addr, + rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK)); +} + +static void _ctrl_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_bandwidth bw) +{ + _bw_setting(rtwdev, RF_PATH_A, bw, true); + _bw_setting(rtwdev, RF_PATH_A, bw, false); +} + +static bool _set_s0_arfc18(struct rtw89_dev *rtwdev, u32 val) +{ + u32 bak; + u32 tmp; + int ret; + + bak = rtw89_read_rf(rtwdev, RF_PATH_A, RR_LDO, RFREG_MASK); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LDO, RR_LDO_SEL, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK, val); + + ret = read_poll_timeout_atomic(rtw89_read_rf, tmp, tmp == 0, 1, 1000, + false, rtwdev, RF_PATH_A, RR_LPF, RR_LPF_BUSY); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]LCK timeout\n"); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LDO, RFREG_MASK, bak); + + return !!ret; +} + +static void _lck_check(struct rtw89_dev *rtwdev) +{ + u32 tmp; + + if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]SYN MMD reset\n"); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_EN, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_SYN, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_SYN, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MMD, RR_MMD_RST_EN, 0x0); + } + + udelay(10); + + if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]re-set RF 0x18\n"); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1); + tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK); + _set_s0_arfc18(rtwdev, tmp); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0); + } + + if (rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RR_SYNFB_LK) == 0) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]SYN off/on\n"); + + tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_POW, RFREG_MASK); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RFREG_MASK, tmp); + tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_SX, RFREG_MASK); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_SX, RFREG_MASK, tmp); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_SYNLUT, RR_SYNLUT_MOD, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_POW, RR_POW_SYN, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_SYNLUT, RR_SYNLUT_MOD, 0x0); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1); + tmp = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK); + _set_s0_arfc18(rtwdev, tmp); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]0xb2=%x, 0xc5=%x\n", + rtw89_read_rf(rtwdev, RF_PATH_A, RR_VCO, RFREG_MASK), + rtw89_read_rf(rtwdev, RF_PATH_A, RR_SYNFB, RFREG_MASK)); + } +} + +static void _set_ch(struct rtw89_dev *rtwdev, u32 val) +{ + bool timeout; + + timeout = _set_s0_arfc18(rtwdev, val); + if (!timeout) + _lck_check(rtwdev); +} + +static void _ch_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + u8 central_ch, bool dav) +{ + u32 reg18_addr = dav ? RR_CFGCH : RR_CFGCH_V1; + bool is_2g_ch = central_ch <= 14; + u32 rf_reg18; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK]===> %s\n", __func__); + + rf_reg18 = rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK); + rf_reg18 &= ~(RR_CFGCH_BAND1 | RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH | + RR_CFGCH_BCN | RR_CFGCH_BAND0 | RR_CFGCH_CH); + rf_reg18 |= FIELD_PREP(RR_CFGCH_CH, central_ch); + + if (!is_2g_ch) + rf_reg18 |= FIELD_PREP(RR_CFGCH_BAND1, CFGCH_BAND1_5G) | + FIELD_PREP(RR_CFGCH_BAND0, CFGCH_BAND0_5G); + + rf_reg18 &= ~(RR_CFGCH_POW_LCK | RR_CFGCH_TRX_AH | RR_CFGCH_BCN | + RR_CFGCH_BW2) & RFREG_MASK; + rf_reg18 |= RR_CFGCH_BW2; + + if (path == RF_PATH_A && dav) + _set_ch(rtwdev, rf_reg18); + else + rtw89_write_rf(rtwdev, path, reg18_addr, RFREG_MASK, rf_reg18); + + rtw89_write_rf(rtwdev, path, RR_LCKST, RR_LCKST_BIN, 0); + rtw89_write_rf(rtwdev, path, RR_LCKST, RR_LCKST_BIN, 1); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]CH: %d for Path-%d, reg0x%x = 0x%x\n", + central_ch, path, reg18_addr, + rtw89_read_rf(rtwdev, path, reg18_addr, RFREG_MASK)); +} + +static void _ctrl_ch(struct rtw89_dev *rtwdev, u8 central_ch) +{ + _ch_setting(rtwdev, RF_PATH_A, central_ch, true); + _ch_setting(rtwdev, RF_PATH_A, central_ch, false); +} + +static void _set_rxbb_bw(struct rtw89_dev *rtwdev, enum rtw89_bandwidth bw, + enum rtw89_rf_path path) +{ + rtw89_write_rf(rtwdev, path, RR_LUTWE2, RR_LUTWE2_RTXBW, 0x1); + rtw89_write_rf(rtwdev, path, RR_LUTWA, RR_LUTWA_M2, 0x12); + + if (bw == RTW89_CHANNEL_WIDTH_20) + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x1b); + else if (bw == RTW89_CHANNEL_WIDTH_40) + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x13); + else if (bw == RTW89_CHANNEL_WIDTH_80) + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0xb); + else + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB, 0x3); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RFK] set S%d RXBB BW 0x3F = 0x%x\n", path, + rtw89_read_rf(rtwdev, path, RR_LUTWD0, RR_LUTWD0_LB)); + + rtw89_write_rf(rtwdev, path, RR_LUTWE2, RR_LUTWE2_RTXBW, 0x0); +} + +static void _rxbb_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_bandwidth bw) +{ + u8 kpath, path; + + kpath = _kpath(rtwdev, phy); + + for (path = 0; path < RF_PATH_NUM_8851B; path++) { + if (!(kpath & BIT(path))) + continue; + + _set_rxbb_bw(rtwdev, bw, path); + } +} + +static void rtw8851b_ctrl_bw_ch(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, u8 central_ch, + enum rtw89_band band, enum rtw89_bandwidth bw) +{ + _ctrl_ch(rtwdev, central_ch); + _ctrl_bw(rtwdev, phy, bw); + _rxbb_bw(rtwdev, phy, bw); +} + +void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8851b_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type, + chan->band_width); +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h new file mode 100644 index 000000000000..c81eb98dcf92 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2022-2023 Realtek Corporation + */ + +#ifndef __RTW89_8851B_RFK_H__ +#define __RTW89_8851B_RFK_H__ + +#include "core.h" + +void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx); + +#endif -- cgit v1.2.3 From 27d5559fd169676496c65a1d07678115c90dfd34 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 24 Apr 2023 14:52:39 +0800 Subject: wifi: rtw89: 8851b: rfk: add AACK Automatic amplitude control calibration (AACK) is the calibration to ensure the oscillator is biased for a constant output amplitude. We do this calibration if card does power on. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230424065242.17477-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 6 ++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 42 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 1 + 3 files changed, 49 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index c396773a9b8c..ee1b985e03d9 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3782,15 +3782,21 @@ #define RR_LOGEN 0xa3 #define RR_LOGEN_RPT GENMASK(19, 16) #define RR_SX 0xaf +#define RR_IBD 0xc9 +#define RR_IBD_VAL GENMASK(4, 0) #define RR_LDO 0xb1 #define RR_LDO_SEL GENMASK(8, 6) #define RR_VCO 0xb2 +#define RR_VCO_SEL GENMASK(9, 8) +#define RR_VCI 0xb3 +#define RR_VCI_ON BIT(7) #define RR_LPF 0xb7 #define RR_LPF_BUSY BIT(8) #define RR_XTALX2 0xb8 #define RR_MALSEL 0xbe #define RR_SYNFB 0xc5 #define RR_SYNFB_LK BIT(15) +#define RR_AACK 0xca #define RR_LCKST 0xcf #define RR_LCKST_BIN BIT(0) #define RR_LCK_TRG 0xd3 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 9276e852bb05..471ed1a63476 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -17,6 +17,48 @@ static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) return RF_A; } +void rtw8851b_aack(struct rtw89_dev *rtwdev) +{ + u32 tmp05, ib[4]; + u32 tmp; + int ret; + int rek; + int i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]DO AACK\n"); + + tmp05 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_MASK, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, 0x0); + + for (rek = 0; rek < 4; rek++) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_AACK, RFREG_MASK, 0x8201e); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_AACK, RFREG_MASK, 0x8201f); + fsleep(100); + + ret = read_poll_timeout_atomic(rtw89_read_rf, tmp, tmp, + 1, 1000, false, + rtwdev, RF_PATH_A, 0xd0, BIT(16)); + if (ret) + rtw89_warn(rtwdev, "[LCK]AACK timeout\n"); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_VCI, RR_VCI_ON, 0x1); + for (i = 0; i < 4; i++) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_VCO, RR_VCO_SEL, i); + ib[i] = rtw89_read_rf(rtwdev, RF_PATH_A, RR_IBD, RR_IBD_VAL); + } + rtw89_write_rf(rtwdev, RF_PATH_A, RR_VCI, RR_VCI_ON, 0x0); + + if (ib[0] != 0 && ib[1] != 0 && ib[2] != 0 && ib[3] != 0) + break; + } + + if (rek != 0) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]AACK rek = %d\n", rek); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, tmp05); +} + static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, enum rtw89_bandwidth bw, bool dav) { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h index c81eb98dcf92..cd38d9ed1ff3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -7,6 +7,7 @@ #include "core.h" +void rtw8851b_aack(struct rtw89_dev *rtwdev); void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); -- cgit v1.2.3 From ae546f0a23904761edeee1a154b94fb38b6195c0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 24 Apr 2023 14:52:40 +0800 Subject: wifi: rtw89: 8851b: rfk: add RCK RCK is synchronize RC calibration. Driver triggers this calibration and sets the result to register. This calibration is needed once when interface is going to up. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230424065242.17477-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 40 +++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 1 + 2 files changed, 41 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 471ed1a63476..7f454f68d08d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -17,6 +17,41 @@ static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) return RF_A; } +static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + u32 rf_reg5; + u32 rck_val; + u32 val; + int ret; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] ====== S%d RCK ======\n", path); + + rf_reg5 = rtw89_read_rf(rtwdev, path, RR_RSV1, RFREG_MASK); + + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] RF0x00 = 0x%05x\n", + rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK)); + + /* RCK trigger */ + rtw89_write_rf(rtwdev, path, RR_RCKC, RFREG_MASK, 0x00240); + + ret = read_poll_timeout_atomic(rtw89_read_rf, val, val, 2, 30, + false, rtwdev, path, RR_RCKS, BIT(3)); + + rck_val = rtw89_read_rf(rtwdev, path, RR_RCKC, RR_RCKC_CA); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] rck_val = 0x%x, ret = %d\n", + rck_val, ret); + + rtw89_write_rf(rtwdev, path, RR_RCKC, RFREG_MASK, rck_val); + rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RCK] RF 0x1b = 0x%x\n", + rtw89_read_rf(rtwdev, path, RR_RCKC, RFREG_MASK)); +} + void rtw8851b_aack(struct rtw89_dev *rtwdev) { u32 tmp05, ib[4]; @@ -59,6 +94,11 @@ void rtw8851b_aack(struct rtw89_dev *rtwdev) rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, tmp05); } +void rtw8851b_rck(struct rtw89_dev *rtwdev) +{ + _rck(rtwdev, RF_PATH_A); +} + static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, enum rtw89_bandwidth bw, bool dav) { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h index cd38d9ed1ff3..9f67a8c3b9d9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -8,6 +8,7 @@ #include "core.h" void rtw8851b_aack(struct rtw89_dev *rtwdev); +void rtw8851b_rck(struct rtw89_dev *rtwdev); void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); -- cgit v1.2.3 From 93fbbeedca3bc93abfe5711b62c8749061c66bc0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 24 Apr 2023 14:52:41 +0800 Subject: wifi: rtw89: 8851b: rfk: add DACK DACK (digital-to-analog converters calibration) is used to calibrate DAC to output good quality signals. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230424065242.17477-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 11 + drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 343 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 1 + 3 files changed, 355 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index ee1b985e03d9..ee35e3976a07 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4759,11 +4759,15 @@ #define B_IQKINF2_KCNT GENMASK(15, 8) #define B_IQKINF2_NCTLV GENMASK(7, 0) #define R_DCOF0 0xC000 +#define B_DCOF0_RST BIT(17) #define B_DCOF0_V GENMASK(4, 1) #define R_DCOF1 0xC004 +#define B_DCOF1_RST BIT(17) #define B_DCOF1_S BIT(0) #define R_DCOF8 0xC020 #define B_DCOF8_V GENMASK(4, 1) +#define R_DCOF9 0xC024 +#define B_DCOF9_RST BIT(17) #define R_DACK_S0P0 0xC040 #define B_DACK_S0P0_OK BIT(31) #define R_DACK_BIAS00 0xc048 @@ -4815,6 +4819,7 @@ #define B_ADDCK0D_VAL GENMASK(25, 16) #define R_ADDCK0 0xC0F4 #define B_ADDCK0_TRG BIT(11) +#define B_ADDCK0_IQ BIT(10) #define B_ADDCK0 GENMASK(9, 8) #define B_ADDCK0_MAN GENMASK(5, 4) #define B_ADDCK0_EN BIT(4) @@ -4826,6 +4831,7 @@ #define B_ADDCK0_RL0 GENMASK(17, 8) #define R_ADDCKR0 0xC0FC #define B_ADDCKR0_A0 GENMASK(19, 10) +#define B_ADDCKR0_DC GENMASK(15, 4) #define B_ADDCKR0_A1 GENMASK(9, 0) #define R_DACK10 0xC100 #define B_DACK10 GENMASK(4, 1) @@ -4876,6 +4882,11 @@ #define R_ADDCKR1 0xC1fC #define B_ADDCKR1_A0 GENMASK(19, 10) #define B_ADDCKR1_A1 GENMASK(9, 0) +#define R_DACKN0_CTL 0xC210 +#define B_DACKN0_EN BIT(0) +#define B_DACKN0_V GENMASK(21, 14) +#define R_DACKN1_CTL 0xC224 +#define B_DACKN1_V GENMASK(21, 14) /* WiFi CPU local domain */ #define R_AX_WDT_CTRL 0x0040 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 7f454f68d08d..816f365ae822 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -17,6 +17,344 @@ static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) return RF_A; } +static void _dack_reset(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + rtw89_phy_write32_mask(rtwdev, R_DCOF0, B_DCOF0_RST, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DCOF0, B_DCOF0_RST, 0x1); +} + +static void _drck(struct rtw89_dev *rtwdev) +{ + u32 rck_d; + u32 val; + int ret; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]Ddie RCK start!!!\n"); + + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_IDLE, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_EN, 0x1); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, + 1, 10000, false, + rtwdev, R_DRCK_RES, B_DRCK_POL); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DRCK timeout\n"); + + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DRCK_FH, B_DRCK_LAT, 0x1); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_DRCK_FH, B_DRCK_LAT, 0x0); + + rck_d = rtw89_phy_read32_mask(rtwdev, R_DRCK_RES, 0x7c00); + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_IDLE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_VAL, rck_d); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0xc0c4 = 0x%x\n", + rtw89_phy_read32_mask(rtwdev, R_DRCK, MASKDWORD)); +} + +static void _addck_backup(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0, 0x0); + + dack->addck_d[0][0] = rtw89_phy_read32_mask(rtwdev, R_ADDCKR0, B_ADDCKR0_A0); + dack->addck_d[0][1] = rtw89_phy_read32_mask(rtwdev, R_ADDCKR0, B_ADDCKR0_A1); +} + +static void _addck_reload(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0_RL, B_ADDCK0_RL1, dack->addck_d[0][0]); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0_RL, B_ADDCK0_RL0, dack->addck_d[0][1]); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0_RL, B_ADDCK0_RLS, 0x3); +} + +static void _dack_backup_s0(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u8 i; + + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + + for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { + rtw89_phy_write32_mask(rtwdev, R_DCOF0, B_DCOF0_V, i); + dack->msbk_d[0][0][i] = + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P2, B_DACK_S0M0); + + rtw89_phy_write32_mask(rtwdev, R_DCOF8, B_DCOF8_V, i); + dack->msbk_d[0][1][i] = + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P3, B_DACK_S0M1); + } + + dack->biask_d[0][0] = + rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS00, B_DACK_BIAS00); + dack->biask_d[0][1] = + rtw89_phy_read32_mask(rtwdev, R_DACK_BIAS01, B_DACK_BIAS01); + dack->dadck_d[0][0] = + rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK00, B_DACK_DADCK00) + 24; + dack->dadck_d[0][1] = + rtw89_phy_read32_mask(rtwdev, R_DACK_DADCK01, B_DACK_DADCK01) + 24; +} + +static void _dack_reload_by_path(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, u8 index) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u32 idx_offset, path_offset; + u32 offset, reg; + u32 tmp; + u8 i; + + if (index == 0) + idx_offset = 0; + else + idx_offset = 0x14; + + if (path == RF_PATH_A) + path_offset = 0; + else + path_offset = 0x28; + + offset = idx_offset + path_offset; + + rtw89_phy_write32_mask(rtwdev, R_DCOF1, B_DCOF1_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DCOF9, B_DCOF9_RST, 0x1); + + /* msbk_d: 15/14/13/12 */ + tmp = 0x0; + for (i = 0; i < 4; i++) + tmp |= dack->msbk_d[path][index][i + 12] << (i * 8); + reg = 0xc200 + offset; + rtw89_phy_write32(rtwdev, reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", reg, + rtw89_phy_read32_mask(rtwdev, reg, MASKDWORD)); + + /* msbk_d: 11/10/9/8 */ + tmp = 0x0; + for (i = 0; i < 4; i++) + tmp |= dack->msbk_d[path][index][i + 8] << (i * 8); + reg = 0xc204 + offset; + rtw89_phy_write32(rtwdev, reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", reg, + rtw89_phy_read32_mask(rtwdev, reg, MASKDWORD)); + + /* msbk_d: 7/6/5/4 */ + tmp = 0x0; + for (i = 0; i < 4; i++) + tmp |= dack->msbk_d[path][index][i + 4] << (i * 8); + reg = 0xc208 + offset; + rtw89_phy_write32(rtwdev, reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", reg, + rtw89_phy_read32_mask(rtwdev, reg, MASKDWORD)); + + /* msbk_d: 3/2/1/0 */ + tmp = 0x0; + for (i = 0; i < 4; i++) + tmp |= dack->msbk_d[path][index][i] << (i * 8); + reg = 0xc20c + offset; + rtw89_phy_write32(rtwdev, reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", reg, + rtw89_phy_read32_mask(rtwdev, reg, MASKDWORD)); + + /* dadak_d/biask_d */ + tmp = 0x0; + tmp = (dack->biask_d[path][index] << 22) | + (dack->dadck_d[path][index] << 14); + reg = 0xc210 + offset; + rtw89_phy_write32(rtwdev, reg, tmp); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x=0x%x\n", reg, + rtw89_phy_read32_mask(rtwdev, reg, MASKDWORD)); + + rtw89_phy_write32_mask(rtwdev, R_DACKN0_CTL + offset, B_DACKN0_EN, 0x1); +} + +static void _dack_reload(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + u8 index; + + for (index = 0; index < 2; index++) + _dack_reload_by_path(rtwdev, path, index); +} + +static void _addck(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u32 val; + int ret; + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_EN, 0x0); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0, 0x1); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, + 1, 10000, false, + rtwdev, R_ADDCKR0, BIT(0)); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADDCK timeout\n"); + dack->addck_timeout[0] = true; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]ADDCK ret = %d\n", ret); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_RST, 0x0); +} + +static void _new_dadck(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u32 i_dc, q_dc, ic, qc; + u32 val; + int ret; + + rtw89_rfk_parser(rtwdev, &rtw8851b_dadck_setup_defs_tbl); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val, + 1, 10000, false, + rtwdev, R_ADDCKR0, BIT(0)); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 DADCK timeout\n"); + dack->addck_timeout[0] = true; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DADCK ret = %d\n", ret); + + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_IQ, 0x0); + i_dc = rtw89_phy_read32_mask(rtwdev, R_ADDCKR0, B_ADDCKR0_DC); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0, B_ADDCK0_IQ, 0x1); + q_dc = rtw89_phy_read32_mask(rtwdev, R_ADDCKR0, B_ADDCKR0_DC); + + ic = 0x80 - sign_extend32(i_dc, 11) * 6; + qc = 0x80 - sign_extend32(q_dc, 11) * 6; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]before DADCK, i_dc=0x%x, q_dc=0x%x\n", i_dc, q_dc); + + dack->dadck_d[0][0] = ic; + dack->dadck_d[0][1] = qc; + + rtw89_phy_write32_mask(rtwdev, R_DACKN0_CTL, B_DACKN0_V, dack->dadck_d[0][0]); + rtw89_phy_write32_mask(rtwdev, R_DACKN1_CTL, B_DACKN1_V, dack->dadck_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DACK]after DADCK, 0xc210=0x%x, 0xc224=0x%x\n", + rtw89_phy_read32_mask(rtwdev, R_DACKN0_CTL, MASKDWORD), + rtw89_phy_read32_mask(rtwdev, R_DACKN1_CTL, MASKDWORD)); + + rtw89_rfk_parser(rtwdev, &rtw8851b_dadck_post_defs_tbl); +} + +static bool _dack_s0_poll(struct rtw89_dev *rtwdev) +{ + if (rtw89_phy_read32_mask(rtwdev, R_DACK_S0P0, B_DACK_S0P0_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P1, B_DACK_S0P1_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P2, B_DACK_S0P2_OK) == 0 || + rtw89_phy_read32_mask(rtwdev, R_DACK_S0P3, B_DACK_S0P3_OK) == 0) + return false; + + return true; +} + +static void _dack_s0(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + bool done; + int ret; + + rtw89_rfk_parser(rtwdev, &rtw8851b_dack_s0_1_defs_tbl); + _dack_reset(rtwdev, RF_PATH_A); + rtw89_phy_write32_mask(rtwdev, R_DCOF1, B_DCOF1_S, 0x1); + + ret = read_poll_timeout_atomic(_dack_s0_poll, done, done, + 1, 10000, false, rtwdev); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 DACK timeout\n"); + dack->msbk_timeout[0] = true; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK ret = %d\n", ret); + + rtw89_rfk_parser(rtwdev, &rtw8851b_dack_s0_2_defs_tbl); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]after S0 DADCK\n"); + + _dack_backup_s0(rtwdev); + _dack_reload(rtwdev, RF_PATH_A); + + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x0); +} + +static void _dack(struct rtw89_dev *rtwdev) +{ + _dack_s0(rtwdev); +} + +static void _dack_dump(struct rtw89_dev *rtwdev) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u8 i; + u8 t; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK ic = 0x%x, qc = 0x%x\n", + dack->addck_d[0][0], dack->addck_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 DAC_DCK ic = 0x%x, qc = 0x%x\n", + dack->dadck_d[0][0], dack->dadck_d[0][1]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 biask ic = 0x%x, qc = 0x%x\n", + dack->biask_d[0][0], dack->biask_d[0][1]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic:\n"); + for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { + t = dack->msbk_d[0][0][i]; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc:\n"); + for (i = 0; i < RTW89_DACK_MSBK_NR; i++) { + t = dack->msbk_d[0][1][i]; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]0x%x\n", t); + } +} + +static void _dack_manual_off(struct rtw89_dev *rtwdev) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_dack_manual_off_defs_tbl); +} + +static void _dac_cal(struct rtw89_dev *rtwdev, bool force) +{ + struct rtw89_dack_info *dack = &rtwdev->dack; + u32 rf0_0; + + dack->dack_done = false; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK 0x2\n"); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK start!!!\n"); + rf0_0 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_MOD, RFREG_MASK); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]RF0=0x%x\n", rf0_0); + + _drck(rtwdev); + _dack_manual_off(rtwdev); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RFREG_MASK, 0x337e1); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RR_RSV1_RST, 0x0); + + _addck(rtwdev); + _addck_backup(rtwdev); + _addck_reload(rtwdev); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RFREG_MASK, 0x40001); + + _dack(rtwdev); + _new_dadck(rtwdev); + _dack_dump(rtwdev); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RR_RSV1_RST, 0x1); + + dack->dack_done = true; + dack->dack_cnt++; + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK finish!!!\n"); +} + static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) { u32 rf_reg5; @@ -99,6 +437,11 @@ void rtw8851b_rck(struct rtw89_dev *rtwdev) _rck(rtwdev, RF_PATH_A); } +void rtw8851b_dack(struct rtw89_dev *rtwdev) +{ + _dac_cal(rtwdev, false); +} + static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, enum rtw89_bandwidth bw, bool dav) { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h index 9f67a8c3b9d9..a6ebe4d29573 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -9,6 +9,7 @@ void rtw8851b_aack(struct rtw89_dev *rtwdev); void rtw8851b_rck(struct rtw89_dev *rtwdev); +void rtw8851b_dack(struct rtw89_dev *rtwdev); void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); -- cgit v1.2.3 From a83c6bb22745168dbe6592a9872f262615ee174b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 24 Apr 2023 14:52:42 +0800 Subject: wifi: rtw89: 8851b: rfk: add IQK IQ signal calibration is a very important calibration to yield good RF performance. We do this calibration only if we are going to run on AP channel. During scanning phase, without this calibration RF performance is still acceptable because it transmits with low data rate at this phase. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230424065242.17477-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 5 + drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 1111 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 1 + 3 files changed, 1117 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index ee35e3976a07..21f68787ff10 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3580,6 +3580,7 @@ #define RR_MOD_MASK GENMASK(19, 16) #define RR_MOD_DCK GENMASK(14, 10) #define RR_MOD_RGM GENMASK(13, 4) +#define RR_MOD_RXB GENMASK(9, 5) #define RR_MOD_V_DOWN 0x0 #define RR_MOD_V_STANDBY 0x1 #define RR_TXAGC 0x10001 @@ -3719,6 +3720,7 @@ #define RR_RXBB 0x83 #define RR_RXBB_VOBUF GENMASK(15, 12) #define RR_RXBB_C2G GENMASK(16, 10) +#define RR_RXBB_C2 GENMASK(11, 8) #define RR_RXBB_C1G GENMASK(9, 8) #define RR_RXBB_FATT GENMASK(7, 0) #define RR_RXBB_ATTR GENMASK(7, 4) @@ -4601,6 +4603,8 @@ #define IQK_DF4_TXT_8_25MHZ 0x021 #define R_IQK_CFG 0x8034 #define B_IQK_CFG_SET GENMASK(5, 4) +#define R_IQK_RXA 0x8044 +#define B_IQK_RXAGC GENMASK(15, 13) #define R_TPG_SEL 0x8068 #define R_TPG_MOD 0x806C #define B_TPG_MOD_F GENMASK(2, 1) @@ -4648,6 +4652,7 @@ #define B_PRT_COM_SYNERR BIT(30) #define B_PRT_COM_DCI GENMASK(27, 16) #define B_PRT_COM_CORV GENMASK(15, 8) +#define B_RPT_COM_RDY GENMASK(15, 0) #define B_PRT_COM_DCQ GENMASK(11, 0) #define B_PRT_COM_RXOV BIT(8) #define B_PRT_COM_GL GENMASK(7, 4) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 816f365ae822..6eb47ed82010 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -12,11 +12,83 @@ #include "rtw8851b_rfk_table.h" #include "rtw8851b_table.h" +#define RTW8851B_RXK_GROUP_NR 4 +#define RTW8851B_TXK_GROUP_NR 1 +#define RTW8851B_IQK_VER 0x2a +#define RTW8851B_IQK_SS 1 +#define RTW8851B_LOK_GRAM 10 + +enum rtw8851b_iqk_type { + ID_TXAGC = 0x0, + ID_FLOK_COARSE = 0x1, + ID_FLOK_FINE = 0x2, + ID_TXK = 0x3, + ID_RXAGC = 0x4, + ID_RXK = 0x5, + ID_NBTXK = 0x6, + ID_NBRXK = 0x7, + ID_FLOK_VBUFFER = 0x8, + ID_A_FLOK_COARSE = 0x9, + ID_G_FLOK_COARSE = 0xa, + ID_A_FLOK_FINE = 0xb, + ID_G_FLOK_FINE = 0xc, + ID_IQK_RESTORE = 0x10, +}; + +static const u32 g_idxrxgain[RTW8851B_RXK_GROUP_NR] = {0x10e, 0x116, 0x28e, 0x296}; +static const u32 g_idxattc2[RTW8851B_RXK_GROUP_NR] = {0x0, 0xf, 0x0, 0xf}; +static const u32 g_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x0, 0x1, 0x2, 0x3}; +static const u32 a_idxrxgain[RTW8851B_RXK_GROUP_NR] = {0x10C, 0x112, 0x28c, 0x292}; +static const u32 a_idxattc2[RTW8851B_RXK_GROUP_NR] = {0xf, 0xf, 0xf, 0xf}; +static const u32 a_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x4, 0x5, 0x6, 0x7}; +static const u32 a_power_range[RTW8851B_TXK_GROUP_NR] = {0x0}; +static const u32 a_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; +static const u32 a_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x0a}; +static const u32 a_itqt[RTW8851B_TXK_GROUP_NR] = {0x12}; +static const u32 g_power_range[RTW8851B_TXK_GROUP_NR] = {0x0}; +static const u32 g_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; +static const u32 g_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x10}; +static const u32 g_itqt[RTW8851B_TXK_GROUP_NR] = {0x12}; + +static const u32 rtw8851b_backup_bb_regs[] = {0xc0ec, 0xc0e8}; +static const u32 rtw8851b_backup_rf_regs[] = { + 0xef, 0xde, 0x0, 0x1e, 0x2, 0x85, 0x90, 0x5}; + +#define BACKUP_BB_REGS_NR ARRAY_SIZE(rtw8851b_backup_bb_regs) +#define BACKUP_RF_REGS_NR ARRAY_SIZE(rtw8851b_backup_rf_regs) + static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { return RF_A; } +static void _adc_fifo_rst(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0101); + fsleep(10); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x1111); +} + +static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) +{ + u32 rf_mode; + u8 path; + int ret; + + for (path = 0; path < RF_PATH_MAX; path++) { + if (!(kpath & BIT(path))) + continue; + + ret = read_poll_timeout_atomic(rtw89_read_rf, rf_mode, + rf_mode != 2, 2, 5000, false, + rtwdev, path, 0x00, RR_MOD_MASK); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK] Wait S%d to Rx mode!! (ret = %d)\n", + path, ret); + } +} + static void _dack_reset(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) { rtw89_phy_write32_mask(rtwdev, R_DCOF0, B_DCOF0_RST, 0x0); @@ -355,6 +427,1029 @@ static void _dac_cal(struct rtw89_dev *rtwdev, bool force) rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK finish!!!\n"); } +static void _iqk_sram(struct rtw89_dev *rtwdev, u8 path) +{ + u32 i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, MASKDWORD, 0x00020000); + rtw89_phy_write32_mask(rtwdev, R_MDPK_RX_DCK, MASKDWORD, 0x80000000); + rtw89_phy_write32_mask(rtwdev, R_SRAM_IQRX2, MASKDWORD, 0x00000080); + rtw89_phy_write32_mask(rtwdev, R_SRAM_IQRX, MASKDWORD, 0x00010000); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x009); + + for (i = 0; i <= 0x9f; i++) { + rtw89_phy_write32_mask(rtwdev, R_SRAM_IQRX, MASKDWORD, + 0x00010000 + i); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]0x%x\n", + rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCI)); + } + + for (i = 0; i <= 0x9f; i++) { + rtw89_phy_write32_mask(rtwdev, R_SRAM_IQRX, MASKDWORD, + 0x00010000 + i); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]0x%x\n", + rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCQ)); + } + + rtw89_phy_write32_mask(rtwdev, R_SRAM_IQRX2, MASKDWORD, 0x00000000); + rtw89_phy_write32_mask(rtwdev, R_SRAM_IQRX, MASKDWORD, 0x00000000); +} + +static void _iqk_rxk_setting(struct rtw89_dev *rtwdev, u8 path) +{ + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, 0xc); + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_POW, 0x0); + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_POW, 0x1); +} + +static bool _iqk_check_cal(struct rtw89_dev *rtwdev, u8 path) +{ + bool fail1 = false, fail2 = false; + u32 val; + int ret; + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x55, + 10, 8200, false, + rtwdev, 0xbff8, MASKBYTE0); + if (ret) { + fail1 = true; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]NCTL1 IQK timeout!!!\n"); + } + + fsleep(10); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x8000, + 10, 200, false, + rtwdev, R_RPT_COM, B_RPT_COM_RDY); + if (ret) { + fail2 = true; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]NCTL2 IQK timeout!!!\n"); + } + + fsleep(10); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, MASKBYTE0, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, ret = %d, notready = %x fail=%d,%d\n", + path, ret, fail1 || fail2, fail1, fail2); + + return fail1 || fail2; +} + +static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path, u8 ktype) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool notready; + u32 iqk_cmd; + + switch (ktype) { + case ID_A_FLOK_COARSE: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_A_FLOK_COARSE ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + iqk_cmd = 0x108 | (1 << (4 + path)); + break; + case ID_G_FLOK_COARSE: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_G_FLOK_COARSE ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + iqk_cmd = 0x108 | (1 << (4 + path)); + break; + case ID_A_FLOK_FINE: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_A_FLOK_FINE ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + iqk_cmd = 0x308 | (1 << (4 + path)); + break; + case ID_G_FLOK_FINE: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_G_FLOK_FINE ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + iqk_cmd = 0x308 | (1 << (4 + path)); + break; + case ID_TXK: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_TXK ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); + iqk_cmd = 0x008 | (1 << (path + 4)) | + (((0x8 + iqk_info->iqk_bw[path]) & 0xf) << 8); + break; + case ID_RXAGC: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_RXAGC ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + iqk_cmd = 0x708 | (1 << (4 + path)) | (path << 1); + break; + case ID_RXK: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_RXK ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + iqk_cmd = 0x008 | (1 << (path + 4)) | + (((0xc + iqk_info->iqk_bw[path]) & 0xf) << 8); + break; + case ID_NBTXK: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_NBTXK ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, + 0x00b); + iqk_cmd = 0x408 | (1 << (4 + path)); + break; + case ID_NBRXK: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]============ S%d ID_NBRXK ============\n", path); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, + 0x011); + iqk_cmd = 0x608 | (1 << (4 + path)); + break; + default: + return false; + } + + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, iqk_cmd + 1); + notready = _iqk_check_cal(rtwdev, path); + if (iqk_info->iqk_sram_en && + (ktype == ID_NBRXK || ktype == ID_RXK)) + _iqk_sram(rtwdev, path); + + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, ktype= %x, id = %x, notready = %x\n", + path, ktype, iqk_cmd + 1, notready); + + return notready; +} + +static bool _rxk_2g_group_sel(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail = false; + bool notready; + u32 rf_0; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + for (gp = 0; gp < RTW8851B_RXK_GROUP_NR; gp++) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RGM, g_idxrxgain[gp]); + rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_C2, g_idxattc2[gp]); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP_V1, gp); + + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); + fsleep(10); + rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, g_idxrxagc[gp]); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, RXAGC 0x8008 = 0x%x, rxbb = %x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD), + rtw89_read_rf(rtwdev, path, RR_MOD, 0x003e0)); + + if (gp == 0x3) { + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); + } + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXK); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, WBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) + _iqk_sram(rtwdev, path); + + if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + MASKDWORD, iqk_info->nb_rxcfir[path] | 0x2); + iqk_info->is_wb_txiqk[path] = false; + } else { + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + MASKDWORD, 0x40000000); + iqk_info->is_wb_txiqk[path] = true; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, kfail = 0x%x, 0x8%x3c = 0x%x\n", path, kfail, + 1 << path, iqk_info->nb_rxcfir[path]); + return kfail; +} + +static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail = false; + bool notready; + u32 rf_0; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + for (gp = 0; gp < RTW8851B_RXK_GROUP_NR; gp++) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, 0x03ff0, a_idxrxgain[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[gp]); + + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP_V1, gp); + + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); + fsleep(100); + rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, RXAGC 0x8008 = 0x%x, rxbb = %x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD), + rtw89_read_rf(rtwdev, path, RR_MOD, RR_MOD_RXB)); + + if (gp == 0x3) { + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); + } + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXK); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, WBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) + _iqk_sram(rtwdev, path); + + if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, + iqk_info->nb_rxcfir[path] | 0x2); + iqk_info->is_wb_txiqk[path] = false; + } else { + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, + 0x40000000); + iqk_info->is_wb_txiqk[path] = true; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, kfail = 0x%x, 0x8%x3c = 0x%x\n", path, kfail, + 1 << path, iqk_info->nb_rxcfir[path]); + return kfail; +} + +static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail = false; + bool notready; + u8 gp = 0x3; + u32 rf_0; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[gp]); + + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP_V1, gp); + + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); + fsleep(100); + rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, RXAGC 0x8008 = 0x%x, rxbb = %x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD), + rtw89_read_rf(rtwdev, path, RR_MOD, 0x003e0)); + + if (gp == 0x3) { + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, WBRXK 0x8008 = 0x%x\n", + path, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + MASKDWORD, 0x40000002); + iqk_info->is_wb_rxiqk[path] = false; + } else { + iqk_info->is_wb_rxiqk[path] = false; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, kfail = 0x%x, 0x8%x3c = 0x%x\n", path, kfail, + 1 << path, iqk_info->nb_rxcfir[path]); + + return kfail; +} + +static bool _iqk_2g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail = false; + bool notready; + u8 gp = 0x3; + u32 rf_0; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RGM, g_idxrxgain[gp]); + rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_C2, g_idxattc2[gp]); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP_V1, gp); + + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RFREG_MASK, 0x80013); + fsleep(10); + rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, g_idxrxagc[gp]); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, RXAGC 0x8008 = 0x%x, rxbb = %x\n", + path, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD), + rtw89_read_rf(rtwdev, path, RR_MOD, 0x003e0)); + + if (gp == 0x3) { + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, WBRXK 0x8008 = 0x%x\n", + path, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), + MASKDWORD, 0x40000002); + iqk_info->is_wb_rxiqk[path] = false; + } else { + iqk_info->is_wb_rxiqk[path] = false; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, kfail = 0x%x, 0x8%x3c = 0x%x\n", path, kfail, + 1 << path, iqk_info->nb_rxcfir[path]); + return kfail; +} + +static void _iqk_rxclk_setting(struct rtw89_dev *rtwdev, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + + rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); + + if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_rxclk_80_defs_tbl); + else + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_rxclk_others_defs_tbl); +} + +static bool _txk_5g_group_sel(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail = false; + bool notready; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, gp); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, a_itqt[gp]); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); + iqk_info->nb_txcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_TXIQC, MASKDWORD) | 0x2; + + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), + MASKDWORD, a_itqt[gp]); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_TXK); + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD, iqk_info->nb_txcfir[path] | 0x2); + iqk_info->is_wb_txiqk[path] = false; + } else { + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD, 0x40000000); + iqk_info->is_wb_txiqk[path] = true; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, kfail = 0x%x, 0x8%x38 = 0x%x\n", path, kfail, + 1 << path, iqk_info->nb_txcfir[path]); + return kfail; +} + +static bool _txk_2g_group_sel(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail = false; + bool notready; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, g_power_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, g_track_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, g_gain_bb[gp]); + + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, g_itqt[gp]); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, gp); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); + iqk_info->nb_txcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_TXIQC, MASKDWORD) | 0x2; + + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), + MASKDWORD, g_itqt[gp]); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_TXK); + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD, iqk_info->nb_txcfir[path] | 0x2); + iqk_info->is_wb_txiqk[path] = false; + } else { + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD, 0x40000000); + iqk_info->is_wb_txiqk[path] = true; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, kfail = 0x%x, 0x8%x38 = 0x%x\n", path, kfail, + 1 << path, iqk_info->nb_txcfir[path]); + return kfail; +} + +static bool _iqk_5g_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail = false; + bool notready; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, gp); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, a_itqt[gp]); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); + iqk_info->nb_txcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_TXIQC, MASKDWORD) | 0x2; + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD, 0x40000002); + iqk_info->is_wb_rxiqk[path] = false; + } else { + iqk_info->is_wb_rxiqk[path] = false; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, kfail = 0x%x, 0x8%x38 = 0x%x\n", path, kfail, + 1 << path, iqk_info->nb_txcfir[path]); + return kfail; +} + +static bool _iqk_2g_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool kfail = false; + bool notready; + u8 gp; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, g_power_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, g_track_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, g_gain_bb[gp]); + + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, g_itqt[gp]); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, gp); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); + iqk_info->nb_txcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD) | 0x2; + } + + if (!notready) + kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); + + if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_TXIQC + (path << 8), + MASKDWORD, 0x40000002); + iqk_info->is_wb_rxiqk[path] = false; + } else { + iqk_info->is_wb_rxiqk[path] = false; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, kfail = 0x%x, 0x8%x38 = 0x%x\n", path, kfail, + 1 << path, iqk_info->nb_txcfir[path]); + return kfail; +} + +static bool _iqk_2g_lok(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + static const u32 g_txbb[RTW8851B_LOK_GRAM] = { + 0x02, 0x06, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x17}; + static const u32 g_itqt[RTW8851B_LOK_GRAM] = { + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x12, 0x12, 0x12, 0x1b}; + static const u32 g_wa[RTW8851B_LOK_GRAM] = { + 0x00, 0x04, 0x08, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x17}; + bool fail = false; + u8 i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTDBG, RR_LUTDBG_LOK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_TXIG, RR_TXIG_GR0, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_TXIG, RR_TXIG_GR1, 0x6); + + for (i = 0; i < RTW8851B_LOK_GRAM; i++) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_TXIG, RR_TXIG_TG, g_txbb[i]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RR_LUTWA_M1, g_wa[i]); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, B_KIP_IQP_IQSW, g_itqt[i]); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x021); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, + 0x00000109 | (1 << (4 + path))); + fail |= _iqk_check_cal(rtwdev, path); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, B_KIP_IQP_IQSW, g_itqt[i]); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, + 0x00000309 | (1 << (4 + path))); + fail |= _iqk_check_cal(rtwdev, path); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S0, i = %x, 0x8[19:15] = 0x%x,0x8[09:05] = 0x%x\n", i, + rtw89_read_rf(rtwdev, RF_PATH_A, RR_DTXLOK, 0xf8000), + rtw89_read_rf(rtwdev, RF_PATH_A, RR_DTXLOK, 0x003e0)); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S0, i = %x, 0x9[19:16] = 0x%x,0x9[09:06] = 0x%x\n", i, + rtw89_read_rf(rtwdev, RF_PATH_A, RR_RSV2, 0xf0000), + rtw89_read_rf(rtwdev, RF_PATH_A, RR_RSV2, 0x003c0)); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S0, i = %x, 0x58 = %x\n", i, + rtw89_read_rf(rtwdev, RF_PATH_A, RR_TXMO, RFREG_MASK)); + } + + return fail; +} + +static bool _iqk_5g_lok(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + static const u32 a_txbb[RTW8851B_LOK_GRAM] = { + 0x02, 0x06, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x17}; + static const u32 a_itqt[RTW8851B_LOK_GRAM] = { + 0x09, 0x09, 0x09, 0x12, 0x12, 0x12, 0x1b, 0x1b, 0x1b, 0x1b}; + static const u32 a_wa[RTW8851B_LOK_GRAM] = { + 0x80, 0x84, 0x88, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x97}; + bool fail = false; + u8 i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTDBG, RR_LUTDBG_LOK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_TXIG, RR_TXIG_GR0, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_TXIG, RR_TXIG_GR1, 0x7); + + for (i = 0; i < RTW8851B_LOK_GRAM; i++) { + rtw89_write_rf(rtwdev, RF_PATH_A, RR_TXIG, RR_TXIG_TG, a_txbb[i]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RR_LUTWA_M1, a_wa[i]); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, B_KIP_IQP_IQSW, a_itqt[i]); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x021); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, + 0x00000109 | (1 << (4 + path))); + fail |= _iqk_check_cal(rtwdev, path); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, B_KIP_IQP_IQSW, a_itqt[i]); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x021); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, + 0x00000309 | (1 << (4 + path))); + fail |= _iqk_check_cal(rtwdev, path); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S0, i = %x, 0x8[19:15] = 0x%x,0x8[09:05] = 0x%x\n", i, + rtw89_read_rf(rtwdev, RF_PATH_A, RR_DTXLOK, 0xf8000), + rtw89_read_rf(rtwdev, RF_PATH_A, RR_DTXLOK, 0x003e0)); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S0, i = %x, 0x9[19:16] = 0x%x,0x9[09:06] = 0x%x\n", i, + rtw89_read_rf(rtwdev, RF_PATH_A, RR_RSV2, 0xf0000), + rtw89_read_rf(rtwdev, RF_PATH_A, RR_RSV2, 0x003c0)); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S0, i = %x, 0x58 = %x\n", i, + rtw89_read_rf(rtwdev, RF_PATH_A, RR_TXMO, RFREG_MASK)); + } + + return fail; +} + +static void _iqk_txk_setting(struct rtw89_dev *rtwdev, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + + switch (iqk_info->iqk_band[path]) { + case RTW89_BAND_2G: + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]RTW89_BAND_2G\n"); + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_txk_2ghz_defs_tbl); + break; + case RTW89_BAND_5G: + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]RTW89_BAND_5G\n"); + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_txk_5ghz_defs_tbl); + break; + default: + break; + } +} + +#define IQK_LOK_RETRY 1 + +static void _iqk_by_path(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + bool lok_is_fail; + u8 i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + for (i = 0; i < IQK_LOK_RETRY; i++) { + _iqk_txk_setting(rtwdev, path); + if (iqk_info->iqk_band[path] == RTW89_BAND_2G) + lok_is_fail = _iqk_2g_lok(rtwdev, phy_idx, path); + else + lok_is_fail = _iqk_5g_lok(rtwdev, phy_idx, path); + + if (!lok_is_fail) + break; + } + + if (iqk_info->is_nbiqk) { + if (iqk_info->iqk_band[path] == RTW89_BAND_2G) + iqk_info->iqk_tx_fail[0][path] = + _iqk_2g_nbtxk(rtwdev, phy_idx, path); + else + iqk_info->iqk_tx_fail[0][path] = + _iqk_5g_nbtxk(rtwdev, phy_idx, path); + } else { + if (iqk_info->iqk_band[path] == RTW89_BAND_2G) + iqk_info->iqk_tx_fail[0][path] = + _txk_2g_group_sel(rtwdev, phy_idx, path); + else + iqk_info->iqk_tx_fail[0][path] = + _txk_5g_group_sel(rtwdev, phy_idx, path); + } + + _iqk_rxclk_setting(rtwdev, path); + _iqk_rxk_setting(rtwdev, path); + _adc_fifo_rst(rtwdev, phy_idx, path); + + if (iqk_info->is_nbiqk) { + if (iqk_info->iqk_band[path] == RTW89_BAND_2G) + iqk_info->iqk_rx_fail[0][path] = + _iqk_2g_nbrxk(rtwdev, phy_idx, path); + else + iqk_info->iqk_rx_fail[0][path] = + _iqk_5g_nbrxk(rtwdev, phy_idx, path); + } else { + if (iqk_info->iqk_band[path] == RTW89_BAND_2G) + iqk_info->iqk_rx_fail[0][path] = + _rxk_2g_group_sel(rtwdev, phy_idx, path); + else + iqk_info->iqk_rx_fail[0][path] = + _rxk_5g_group_sel(rtwdev, phy_idx, path); + } +} + +static void _rfk_backup_bb_reg(struct rtw89_dev *rtwdev, + u32 backup_bb_reg_val[]) +{ + u32 i; + + for (i = 0; i < BACKUP_BB_REGS_NR; i++) { + backup_bb_reg_val[i] = + rtw89_phy_read32_mask(rtwdev, rtw8851b_backup_bb_regs[i], + MASKDWORD); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]backup bb reg : %x, value =%x\n", + rtw8851b_backup_bb_regs[i], backup_bb_reg_val[i]); + } +} + +static void _rfk_backup_rf_reg(struct rtw89_dev *rtwdev, + u32 backup_rf_reg_val[], u8 rf_path) +{ + u32 i; + + for (i = 0; i < BACKUP_RF_REGS_NR; i++) { + backup_rf_reg_val[i] = + rtw89_read_rf(rtwdev, rf_path, + rtw8851b_backup_rf_regs[i], RFREG_MASK); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]backup rf S%d reg : %x, value =%x\n", rf_path, + rtw8851b_backup_rf_regs[i], backup_rf_reg_val[i]); + } +} + +static void _rfk_restore_bb_reg(struct rtw89_dev *rtwdev, + const u32 backup_bb_reg_val[]) +{ + u32 i; + + for (i = 0; i < BACKUP_BB_REGS_NR; i++) { + rtw89_phy_write32_mask(rtwdev, rtw8851b_backup_bb_regs[i], + MASKDWORD, backup_bb_reg_val[i]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]restore bb reg : %x, value =%x\n", + rtw8851b_backup_bb_regs[i], backup_bb_reg_val[i]); + } +} + +static void _rfk_restore_rf_reg(struct rtw89_dev *rtwdev, + const u32 backup_rf_reg_val[], u8 rf_path) +{ + u32 i; + + for (i = 0; i < BACKUP_RF_REGS_NR; i++) { + rtw89_write_rf(rtwdev, rf_path, rtw8851b_backup_rf_regs[i], + RFREG_MASK, backup_rf_reg_val[i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RFK]restore rf S%d reg: %x, value =%x\n", rf_path, + rtw8851b_backup_rf_regs[i], backup_rf_reg_val[i]); + } +} + +static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + u8 path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 idx = 0; + + iqk_info->iqk_band[path] = chan->band_type; + iqk_info->iqk_bw[path] = chan->band_width; + iqk_info->iqk_ch[path] = chan->channel; + iqk_info->iqk_table_idx[path] = idx; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d (PHY%d): / DBCC %s/ %s/ CH%d/ %s\n", + path, phy, rtwdev->dbcc_en ? "on" : "off", + iqk_info->iqk_band[path] == 0 ? "2G" : + iqk_info->iqk_band[path] == 1 ? "5G" : "6G", + iqk_info->iqk_ch[path], + iqk_info->iqk_bw[path] == 0 ? "20M" : + iqk_info->iqk_bw[path] == 1 ? "40M" : "80M"); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]times = 0x%x, ch =%x\n", + iqk_info->iqk_times, idx); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, iqk_info->syn1to2= 0x%x\n", + path, iqk_info->syn1to2); +} + +static void _iqk_start_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, + u8 path) +{ + _iqk_by_path(rtwdev, phy_idx, path); +} + +static void _iqk_restore(struct rtw89_dev *rtwdev, u8 path) +{ + bool fail; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, 0x00001219); + fsleep(10); + fail = _iqk_check_cal(rtwdev, path); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] restore fail=%d\n", fail); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000000); + rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x80000000); +} + +static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_afebb_restore_defs_tbl); +} + +static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); + rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000080); + rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x81ff010a); +} + +static void _iqk_macbb_setting(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, u8 path) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_macbb_defs_tbl); +} + +static void _iqk_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 idx, path; + + rtw89_phy_write32_mask(rtwdev, R_IQKINF, MASKDWORD, 0x0); + + if (iqk_info->is_iqk_init) + return; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); + + iqk_info->is_iqk_init = true; + iqk_info->is_nbiqk = false; + iqk_info->iqk_fft_en = false; + iqk_info->iqk_sram_en = false; + iqk_info->iqk_cfir_en = false; + iqk_info->iqk_xym_en = false; + iqk_info->thermal_rek_en = false; + iqk_info->iqk_times = 0x0; + + for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { + iqk_info->iqk_channel[idx] = 0x0; + for (path = 0; path < RF_PATH_NUM_8851B; path++) { + iqk_info->lok_cor_fail[idx][path] = false; + iqk_info->lok_fin_fail[idx][path] = false; + iqk_info->iqk_tx_fail[idx][path] = false; + iqk_info->iqk_rx_fail[idx][path] = false; + iqk_info->iqk_table_idx[path] = 0x0; + } + } +} + +static void _doiqk(struct rtw89_dev *rtwdev, bool force, + enum rtw89_phy_idx phy_idx, u8 path) +{ + struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, RF_AB); + u32 backup_rf_val[RTW8851B_IQK_SS][BACKUP_RF_REGS_NR]; + u32 backup_bb_val[BACKUP_BB_REGS_NR]; + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, + BTC_WRFK_ONESHOT_START); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]==========IQK strat!!!!!==========\n"); + iqk_info->iqk_times++; + iqk_info->kcount = 0; + iqk_info->version = RTW8851B_IQK_VER; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]Test Ver 0x%x\n", iqk_info->version); + _iqk_get_ch_info(rtwdev, phy_idx, path); + + _rfk_backup_bb_reg(rtwdev, &backup_bb_val[0]); + _rfk_backup_rf_reg(rtwdev, &backup_rf_val[path][0], path); + _iqk_macbb_setting(rtwdev, phy_idx, path); + _iqk_preset(rtwdev, path); + _iqk_start_iqk(rtwdev, phy_idx, path); + _iqk_restore(rtwdev, path); + _iqk_afebb_restore(rtwdev, phy_idx, path); + _rfk_restore_bb_reg(rtwdev, &backup_bb_val[0]); + _rfk_restore_rf_reg(rtwdev, &backup_rf_val[path][0], path); + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, + BTC_WRFK_ONESHOT_STOP); +} + +static void _iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool force) +{ + _doiqk(rtwdev, force, phy_idx, RF_PATH_A); +} + static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) { u32 rf_reg5; @@ -442,6 +1537,22 @@ void rtw8851b_dack(struct rtw89_dev *rtwdev) _dac_cal(rtwdev, false); } +void rtw8851b_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); + u32 tx_en; + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_START); + rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); + _wait_rx_mode(rtwdev, _kpath(rtwdev, phy_idx)); + + _iqk_init(rtwdev); + _iqk(rtwdev, phy_idx, false); + + rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_STOP); +} + static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, enum rtw89_bandwidth bw, bool dav) { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h index a6ebe4d29573..d86c630ff47e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -10,6 +10,7 @@ void rtw8851b_aack(struct rtw89_dev *rtwdev); void rtw8851b_rck(struct rtw89_dev *rtwdev); void rtw8851b_dack(struct rtw89_dev *rtwdev); +void rtw8851b_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); -- cgit v1.2.3 From 9d4f491b860ea6d04471c3342093b86a46eee63e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Apr 2023 13:44:04 +0300 Subject: wifi: rtw89: fix rtw89_read_chip_ver() for RTL8852B and RTL8851B The if statement is reversed so it will not record the chip version. This was detected using Smatch: drivers/net/wireless/realtek/rtw89/core.c:3593 rtw89_read_chip_ver() error: uninitialized symbol 'val'. Fixes: a6fb2bb84654 ("wifi: rtw89: read version of analog hardware") Signed-off-by: Dan Carpenter Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/e4d912a2-37f8-4068-8861-7b9494ae731b@kili.mountain --- drivers/net/wireless/realtek/rtw89/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index c376dae916e7..630124f9e025 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3668,7 +3668,7 @@ static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev) if (chip->chip_id == RTL8852B || chip->chip_id == RTL8851B) { ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CV, &val); - if (!ret) + if (ret) return; rtwdev->hal.acv = u8_get_bits(val, XTAL_SI_ACV_MASK); -- cgit v1.2.3 From c401bde6ead489938385867ce3a6d5faf9fb6aba Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 26 Apr 2023 21:32:36 +0200 Subject: wifi: mwifiex: Use list_count_nodes() mwifiex_wmm_list_len() is the same as list_count_nodes(), so use the latter instead of hand writing it. Turn 'ba_stream_num' and 'ba_stream_max' in size_t to keep the same type as what is returned by list_count_nodes(). Signed-off-by: Christophe JAILLET Reviewed-by: Brian Norris Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/e77ed7f719787cb8836a93b6a6972f4147e40bc6.1682537509.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/marvell/mwifiex/11n.h | 4 ++-- drivers/net/wireless/marvell/mwifiex/wmm.h | 15 --------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/11n.h b/drivers/net/wireless/marvell/mwifiex/11n.h index 94b5e3e4ba08..7738ebe1fec1 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.h +++ b/drivers/net/wireless/marvell/mwifiex/11n.h @@ -102,14 +102,14 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream( { struct mwifiex_private *priv; u8 i; - u32 ba_stream_num = 0, ba_stream_max; + size_t ba_stream_num = 0, ba_stream_max; ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED; for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; if (priv) - ba_stream_num += mwifiex_wmm_list_len( + ba_stream_num += list_count_nodes( &priv->tx_ba_stream_tbl_ptr); } diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.h b/drivers/net/wireless/marvell/mwifiex/wmm.h index 4f53a271dae0..d7659e688933 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.h +++ b/drivers/net/wireless/marvell/mwifiex/wmm.h @@ -38,21 +38,6 @@ mwifiex_get_tid(struct mwifiex_ra_list_tbl *ptr) return skb->priority; } -/* - * This function gets the length of a list. - */ -static inline int -mwifiex_wmm_list_len(struct list_head *head) -{ - struct list_head *pos; - int count = 0; - - list_for_each(pos, head) - ++count; - - return count; -} - /* * This function checks if a RA list is empty or not. */ -- cgit v1.2.3 From f3dc7bb037d813ab7da84f488dd485f0fce66347 Mon Sep 17 00:00:00 2001 From: Wang Jikai Date: Fri, 21 Apr 2023 09:22:00 +0000 Subject: wifi: mt7601u: delete dead code checking debugfs returns Smatch reports that: drivers/net/wireless/mediatek/mt7601u/debugfs.c:130 mt7601u_init_debugfs() warn: 'dir' is an error pointer or valid". Debugfs code is not supposed to need error checking so instead of changing this to if (IS_ERR()) the correct thing is to just delete the dead code. Signed-off-by: Wang Jikai Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421092200.24456-1-wangjikai@hust.edu.cn --- drivers/net/wireless/mediatek/mt7601u/debugfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c index 230b0e1061a7..dbddf256921b 100644 --- a/drivers/net/wireless/mediatek/mt7601u/debugfs.c +++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c @@ -127,8 +127,6 @@ void mt7601u_init_debugfs(struct mt7601u_dev *dev) struct dentry *dir; dir = debugfs_create_dir("mt7601u", dev->hw->wiphy->debugfsdir); - if (!dir) - return; debugfs_create_u8("temperature", 0400, dir, &dev->raw_temp); debugfs_create_u32("temp_mode", 0400, dir, &dev->temp_mode); -- cgit v1.2.3 From 5189a8dba849f0153f30561e3ac257e0be01abdd Mon Sep 17 00:00:00 2001 From: Karthik M Date: Fri, 28 Apr 2023 20:01:37 +0300 Subject: wifi: ath12k: add wait operation for tx management packets for flush from mac80211 Transmission of management packets are done in a work queue. Sometimes the workqueue does not finish Tx immediately, then it lead after the next step of vdev delete finished, it start to send the management packet to firmware and lead firmware crash. ieee80211_set_disassoc() have logic of ieee80211_flush_queues() after it send_deauth_disassoc() to ath12k, its purpose is make sure the deauth was actually sent, so it need to change ath12k to match the purpose of mac80211. To address these issues wait for Tx management as well as Tx data packets. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthik M Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230419095738.19859-1-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 1 + drivers/net/wireless/ath/ath12k/core.h | 1 + drivers/net/wireless/ath/ath12k/mac.c | 36 +++++++++++++++++++++++++++------- drivers/net/wireless/ath/ath12k/wmi.c | 8 +++++++- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index a89e66653f04..499b81cd938e 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -706,6 +706,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); idr_destroy(&ar->txmgmt_idr); + wake_up(&ar->txmgmt_empty_waitq); } wake_up(&ab->wmi_ab.tx_credits_wq); diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 9439052a652e..2f93296db792 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -533,6 +533,7 @@ struct ath12k { /* protects txmgmt_idr data */ spinlock_t txmgmt_idr_lock; atomic_t num_pending_mgmt_tx; + wait_queue_head_t txmgmt_empty_waitq; /* cycle count is reported twice for each visited channel during scan. * access protected by data_lock diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ee792822b411..b52675a113f4 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4375,6 +4375,21 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) return 0; } +static void ath12k_mgmt_over_wmi_tx_drop(struct ath12k *ar, struct sk_buff *skb) +{ + int num_mgmt; + + ieee80211_free_txskb(ar->hw, skb); + + num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); + + if (num_mgmt < 0) + WARN_ON_ONCE(1); + + if (!num_mgmt) + wake_up(&ar->txmgmt_empty_waitq); +} + int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) { struct sk_buff *msdu = skb; @@ -4391,7 +4406,7 @@ int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) info = IEEE80211_SKB_CB(msdu); memset(&info->status, 0, sizeof(info->status)); - ieee80211_free_txskb(ar->hw, msdu); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); return 0; } @@ -4475,7 +4490,7 @@ static void ath12k_mgmt_over_wmi_tx_purge(struct ath12k *ar) struct sk_buff *skb; while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) - ieee80211_free_txskb(ar->hw, skb); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); } static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) @@ -4490,7 +4505,7 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) skb_cb = ATH12K_SKB_CB(skb); if (!skb_cb->vif) { ath12k_warn(ar->ab, "no vif found for mgmt frame\n"); - ieee80211_free_txskb(ar->hw, skb); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); continue; } @@ -4501,16 +4516,14 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) if (ret) { ath12k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", arvif->vdev_id, ret); - ieee80211_free_txskb(ar->hw, skb); - } else { - atomic_inc(&ar->num_pending_mgmt_tx); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); } } else { ath12k_warn(ar->ab, "dropping mgmt frame for vdev %d, is_started %d\n", arvif->vdev_id, arvif->is_started); - ieee80211_free_txskb(ar->hw, skb); + ath12k_mgmt_over_wmi_tx_drop(ar, skb); } } } @@ -4541,6 +4554,7 @@ static int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb, } skb_queue_tail(q, skb); + atomic_inc(&ar->num_pending_mgmt_tx); ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); return 0; @@ -6014,6 +6028,13 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v ATH12K_FLUSH_TIMEOUT); if (time_left == 0) ath12k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left); + + time_left = wait_event_timeout(ar->txmgmt_empty_waitq, + (atomic_read(&ar->num_pending_mgmt_tx) == 0), + ATH12K_FLUSH_TIMEOUT); + if (time_left == 0) + ath12k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n", + time_left); } static int @@ -6991,6 +7012,7 @@ int ath12k_mac_register(struct ath12k_base *ab) if (ret) goto err_cleanup; + init_waitqueue_head(&ar->txmgmt_empty_waitq); idr_init(&ar->txmgmt_idr); spin_lock_init(&ar->txmgmt_idr_lock); } diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 7ae0bb78b2b5..f1d0743eb349 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -4640,6 +4640,7 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, struct sk_buff *msdu; struct ieee80211_tx_info *info; struct ath12k_skb_cb *skb_cb; + int num_mgmt; spin_lock_bh(&ar->txmgmt_idr_lock); msdu = idr_find(&ar->txmgmt_idr, desc_id); @@ -4663,10 +4664,15 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, ieee80211_tx_status_irqsafe(ar->hw, msdu); + num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); + /* WARN when we received this event without doing any mgmt tx */ - if (atomic_dec_if_positive(&ar->num_pending_mgmt_tx) < 0) + if (num_mgmt < 0) WARN_ON_ONCE(1); + if (!num_mgmt) + wake_up(&ar->txmgmt_empty_waitq); + return 0; } -- cgit v1.2.3 From e995f3f602a3fd9c8e0f97f59b37002d4ab5ec83 Mon Sep 17 00:00:00 2001 From: Karthik M Date: Fri, 28 Apr 2023 20:01:37 +0300 Subject: wifi: ath12k: fix potential wmi_mgmt_tx_queue race condition During stress test with maximum VAPs and peer connected, below warning is seen: [ 1079.110967] ath12k_pci 0004:01:00.0: mgmt tx queue is full [ 1079.117708] ath12k_pci 0004:01:00.0: failed to queue management frame -28 [ 1079.123191] ath12k_pci 0004:01:00.0: mgmt tx queue is full [ 1079.129960] ath12k_pci 0004:01:00.0: failed to queue management frame -28 [ 1079.135641] ath12k_pci 0004:01:00.0: mgmt tx queue is full This is caused by potential race condition while accessing skb_queue_len(). When ath12k_mgmt_over_wmi_tx_work() and ath12k_mac_mgmt_tx() is called concurrently, then skb_queue_len() might fetch list length which is modified by skb_queue_tail() or skb_dequeue(). Replace skb_queue_len() with skb_queue_len_lockless() which will prevent concurrent modified access using READ_ONCE(). And also use '>=', in case we queue a few SKBs simultaneously. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthik M Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230419095758.19998-1-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b52675a113f4..b337fb7f793f 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4548,7 +4548,7 @@ static int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb, return -ENOSPC; } - if (skb_queue_len(q) == ATH12K_TX_MGMT_NUM_PENDING_MAX) { + if (skb_queue_len_lockless(q) >= ATH12K_TX_MGMT_NUM_PENDING_MAX) { ath12k_warn(ar->ab, "mgmt tx queue is full\n"); return -ENOSPC; } -- cgit v1.2.3 From b719ebc37a1eacd4fd4f1264f731b016e5ec0c6e Mon Sep 17 00:00:00 2001 From: Alexander Wetzel Date: Thu, 23 Mar 2023 17:55:27 +0100 Subject: wifi: ath10k: Serialize wake_tx_queue ops Serialize the ath10k implementation of the wake_tx_queue ops. ath10k_mac_op_wake_tx_queue() must not run concurrent since it's using ieee80211_txq_schedule_start(). The intend of this patch is to sort out an issue discovered in the discussion referred to by the Link tag. I can't test it with real hardware and thus just implemented the per-ac queue lock Felix suggested. One obvious alternative to the per-ac lock would be to bring back the txqs_lock commit bb2edb733586 ("ath10k: migrate to mac80211 txq scheduling") dropped. Fixes: bb2edb733586 ("ath10k: migrate to mac80211 txq scheduling") Reported-by: Felix Fietkau Link: https://lore.kernel.org/r/519b5bb9-8899-ae7c-4eff-f3116cdfdb56@nbd.name CC: Signed-off-by: Alexander Wetzel Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230323165527.156414-1-alexander@wetzel-home.de --- drivers/net/wireless/ath/ath10k/core.c | 3 +++ drivers/net/wireless/ath/ath10k/core.h | 3 +++ drivers/net/wireless/ath/ath10k/mac.c | 6 ++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5eb131ab916f..533ed7169e11 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -3643,6 +3643,9 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, mutex_init(&ar->dump_mutex); spin_lock_init(&ar->data_lock); + for (int ac = 0; ac < IEEE80211_NUM_ACS; ac++) + spin_lock_init(&ar->queue_lock[ac]); + INIT_LIST_HEAD(&ar->peers); init_waitqueue_head(&ar->peer_mapping_wq); init_waitqueue_head(&ar->htt.empty_tx_wq); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index f5de8ce8fb45..4b5239de4018 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1170,6 +1170,9 @@ struct ath10k { /* protects shared structure data */ spinlock_t data_lock; + /* serialize wake_tx_queue calls per ac */ + spinlock_t queue_lock[IEEE80211_NUM_ACS]; + struct list_head arvifs; struct list_head peers; struct ath10k_peer *peer_map[ATH10K_MAX_NUM_PEER_IDS]; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 7675858f069b..9c4bf2fdbc0f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4732,13 +4732,14 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; int ret; - u8 ac; + u8 ac = txq->ac; ath10k_htt_tx_txq_update(hw, txq); if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH) return; - ac = txq->ac; + spin_lock_bh(&ar->queue_lock[ac]); + ieee80211_txq_schedule_start(hw, ac); txq = ieee80211_next_txq(hw, ac); if (!txq) @@ -4753,6 +4754,7 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw, ath10k_htt_tx_txq_update(hw, txq); out: ieee80211_txq_schedule_end(hw, ac); + spin_unlock_bh(&ar->queue_lock[ac]); } /* Must not be called with conf_mutex held as workers can use that also. */ -- cgit v1.2.3 From fd7bc9d9d4678321f0641810513cf7173f5c533c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 26 Apr 2023 22:49:07 +0200 Subject: wifi: ath10k: Use list_count_nodes() ath10k_wmi_fw_stats_num_peers() and ath10k_wmi_fw_stats_num_vdevs() really look the same as list_count_nodes(), so use the latter instead of hand writing it. The first ones use list_for_each_entry() and the other list_for_each(), but they both count the number of nodes in the list. Compile tested only. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/e6ec525c0c5057e97e33a63f8a4aa482e5c2da7f.1682541872.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/ath/ath10k/debug.c | 4 ++-- drivers/net/wireless/ath/ath10k/wmi.c | 34 ++++++--------------------------- drivers/net/wireless/ath/ath10k/wmi.h | 2 -- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index b9aea1510f7b..f9518e1c9903 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -293,8 +293,8 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) goto free; } - num_peers = ath10k_wmi_fw_stats_num_peers(&ar->debug.fw_stats.peers); - num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs); + num_peers = list_count_nodes(&ar->debug.fw_stats.peers); + num_vdevs = list_count_nodes(&ar->debug.fw_stats.vdevs); is_start = (list_empty(&ar->debug.fw_stats.pdevs) && !list_empty(&stats.pdevs)); is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 980d4124fa28..05fa7d4c0e1a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -8164,28 +8164,6 @@ ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config(struct ath10k *ar, u32 param) return skb; } -size_t ath10k_wmi_fw_stats_num_peers(struct list_head *head) -{ - struct ath10k_fw_stats_peer *i; - size_t num = 0; - - list_for_each_entry(i, head, list) - ++num; - - return num; -} - -size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head) -{ - struct ath10k_fw_stats_vdev *i; - size_t num = 0; - - list_for_each_entry(i, head, list) - ++num; - - return num; -} - static void ath10k_wmi_fw_pdev_base_stats_fill(const struct ath10k_fw_stats_pdev *pdev, char *buf, u32 *length) @@ -8462,8 +8440,8 @@ void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar, goto unlock; } - num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers); - num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs); + num_peers = list_count_nodes(&fw_stats->peers); + num_vdevs = list_count_nodes(&fw_stats->vdevs); ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len); ath10k_wmi_fw_pdev_tx_stats_fill(pdev, buf, &len); @@ -8520,8 +8498,8 @@ void ath10k_wmi_10x_op_fw_stats_fill(struct ath10k *ar, goto unlock; } - num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers); - num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs); + num_peers = list_count_nodes(&fw_stats->peers); + num_vdevs = list_count_nodes(&fw_stats->vdevs); ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len); ath10k_wmi_fw_pdev_extra_stats_fill(pdev, buf, &len); @@ -8668,8 +8646,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, goto unlock; } - num_peers = ath10k_wmi_fw_stats_num_peers(&fw_stats->peers); - num_vdevs = ath10k_wmi_fw_stats_num_vdevs(&fw_stats->vdevs); + num_peers = list_count_nodes(&fw_stats->peers); + num_vdevs = list_count_nodes(&fw_stats->vdevs); ath10k_wmi_fw_pdev_base_stats_fill(pdev, buf, &len); ath10k_wmi_fw_pdev_extra_stats_fill(pdev, buf, &len); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 6de3cc4640a0..6d04a66fe5e0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -7502,8 +7502,6 @@ void ath10k_wmi_main_op_fw_stats_fill(struct ath10k *ar, void ath10k_wmi_10x_op_fw_stats_fill(struct ath10k *ar, struct ath10k_fw_stats *fw_stats, char *buf); -size_t ath10k_wmi_fw_stats_num_peers(struct list_head *head); -size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head); void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, struct ath10k_fw_stats *fw_stats, char *buf); -- cgit v1.2.3 From 91dce40914337bc47ac95e00f2b055169ee53697 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 26 Apr 2023 22:48:59 +0200 Subject: wifi: ath11k: Use list_count_nodes() ath11k_wmi_fw_stats_num_vdevs() and ath11k_wmi_fw_stats_num_bcn() really look the same as list_count_nodes(), so use the latter instead of hand writing it. The first ones use list_for_each_entry() and the other list_for_each(), but they both count the number of nodes in the list. While at it, also remove to prototypes of non-existent functions. Based on the names and prototypes, it is likely that they should be equivalent to list_count_nodes(). Compile tested only. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/941484caae24b89d20524b1a5661dd1fd7025492.1682542084.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/ath/ath11k/wmi.c | 24 +----------------------- drivers/net/wireless/ath/ath11k/wmi.h | 3 --- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index d0b59bc2905a..a55b5fe37ecf 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -6548,28 +6548,6 @@ int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb, &parse); } -size_t ath11k_wmi_fw_stats_num_vdevs(struct list_head *head) -{ - struct ath11k_fw_stats_vdev *i; - size_t num = 0; - - list_for_each_entry(i, head, list) - ++num; - - return num; -} - -static size_t ath11k_wmi_fw_stats_num_bcn(struct list_head *head) -{ - struct ath11k_fw_stats_bcn *i; - size_t num = 0; - - list_for_each_entry(i, head, list) - ++num; - - return num; -} - static void ath11k_wmi_fw_pdev_base_stats_fill(const struct ath11k_fw_stats_pdev *pdev, char *buf, u32 *length) @@ -6880,7 +6858,7 @@ void ath11k_wmi_fw_stats_fill(struct ath11k *ar, } if (stats_id == WMI_REQUEST_BCN_STAT) { - num_bcn = ath11k_wmi_fw_stats_num_bcn(&fw_stats->bcn); + num_bcn = list_count_nodes(&fw_stats->bcn); len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 92fddb77669c..91bc3e648ce1 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -6372,9 +6372,6 @@ int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar, struct pdev_set_regdomain_params *param); int ath11k_wmi_pull_fw_stats(struct ath11k_base *ab, struct sk_buff *skb, struct ath11k_fw_stats *stats); -size_t ath11k_wmi_fw_stats_num_peers(struct list_head *head); -size_t ath11k_wmi_fw_stats_num_peers_extd(struct list_head *head); -size_t ath11k_wmi_fw_stats_num_vdevs(struct list_head *head); void ath11k_wmi_fw_stats_fill(struct ath11k *ar, struct ath11k_fw_stats *fw_stats, u32 stats_id, char *buf); -- cgit v1.2.3 From 69535186297b37e6e0a16290766666f4e8a55793 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Thu, 27 Apr 2023 22:30:15 -0400 Subject: bpf, docs: Update llvm_relocs.rst with typo fixes Correct a few typographical errors and fix some mistakes in examples. Signed-off-by: Will Hawkins Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230428023015.1698072-2-hawkinsw@obs.cr Signed-off-by: Alexei Starovoitov --- Documentation/bpf/llvm_reloc.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Documentation/bpf/llvm_reloc.rst b/Documentation/bpf/llvm_reloc.rst index ca8957d5b671..e4a777a6a3a2 100644 --- a/Documentation/bpf/llvm_reloc.rst +++ b/Documentation/bpf/llvm_reloc.rst @@ -48,7 +48,7 @@ the code with ``llvm-objdump -dr test.o``:: 14: 0f 10 00 00 00 00 00 00 r0 += r1 15: 95 00 00 00 00 00 00 00 exit -There are four relations in the above for four ``LD_imm64`` instructions. +There are four relocations in the above for four ``LD_imm64`` instructions. The following ``llvm-readelf -r test.o`` shows the binary values of the four relocations:: @@ -79,14 +79,16 @@ The following is the symbol table with ``llvm-readelf -s test.o``:: The 6th entry is global variable ``g1`` with value 0. Similarly, the second relocation is at ``.text`` offset ``0x18``, instruction 3, -for global variable ``g2`` which has a symbol value 4, the offset -from the start of ``.data`` section. - -The third and fourth relocations refers to static variables ``l1`` -and ``l2``. From ``.rel.text`` section above, it is not clear -which symbols they really refers to as they both refers to +has a type of ``R_BPF_64_64`` and refers to entry 7 in the symbol table. +The second relocation resolves to global variable ``g2`` which has a symbol +value 4. The symbol value represents the offset from the start of ``.data`` +section where the initial value of the global variable ``g2`` is stored. + +The third and fourth relocations refer to static variables ``l1`` +and ``l2``. From the ``.rel.text`` section above, it is not clear +to which symbols they really refer as they both refer to symbol table entry 4, symbol ``sec``, which has ``STT_SECTION`` type -and represents a section. So for static variable or function, +and represents a section. So for a static variable or function, the section offset is written to the original insn buffer, which is called ``A`` (addend). Looking at above insn ``7`` and ``11``, they have section offset ``8`` and ``12``. -- cgit v1.2.3 From f4dea9689c5fea3d07170c2cb0703e216f1a0922 Mon Sep 17 00:00:00 2001 From: Pengcheng Yang Date: Fri, 5 May 2023 16:50:58 +0800 Subject: samples/bpf: Fix buffer overflow in tcp_basertt Using sizeof(nv) or strlen(nv)+1 is correct. Fixes: c890063e4404 ("bpf: sample BPF_SOCKET_OPS_BASE_RTT program") Signed-off-by: Pengcheng Yang Link: https://lore.kernel.org/r/1683276658-2860-1-git-send-email-yangpc@wangsu.com Signed-off-by: Alexei Starovoitov --- samples/bpf/tcp_basertt_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bpf/tcp_basertt_kern.c b/samples/bpf/tcp_basertt_kern.c index 8dfe09a92fec..822b0742b815 100644 --- a/samples/bpf/tcp_basertt_kern.c +++ b/samples/bpf/tcp_basertt_kern.c @@ -47,7 +47,7 @@ int bpf_basertt(struct bpf_sock_ops *skops) case BPF_SOCK_OPS_BASE_RTT: n = bpf_getsockopt(skops, SOL_TCP, TCP_CONGESTION, cong, sizeof(cong)); - if (!n && !__builtin_memcmp(cong, nv, sizeof(nv)+1)) { + if (!n && !__builtin_memcmp(cong, nv, sizeof(nv))) { /* Set base_rtt to 80us */ rv = 80; } else if (n) { -- cgit v1.2.3 From b5ad4cdc46c7d6e7f8d2c9e24b6c9a1edec95154 Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Sat, 6 May 2023 11:15:44 +0800 Subject: bpf: Add bpf_task_under_cgroup() kfunc Add a kfunc that's similar to the bpf_current_task_under_cgroup. The difference is that it is a designated task. When hook sched related functions, sometimes it is necessary to specify a task instead of the current task. Signed-off-by: Feng Zhou Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230506031545.35991-2-zhoufeng.zf@bytedance.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/helpers.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index bb6b4637ebf2..a128fe0ab2d0 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2149,6 +2149,22 @@ __bpf_kfunc struct cgroup *bpf_cgroup_from_id(u64 cgid) return NULL; return cgrp; } + +/** + * bpf_task_under_cgroup - wrap task_under_cgroup_hierarchy() as a kfunc, test + * task's membership of cgroup ancestry. + * @task: the task to be tested + * @ancestor: possible ancestor of @task's cgroup + * + * Tests whether @task's default cgroup hierarchy is a descendant of @ancestor. + * It follows all the same rules as cgroup_is_descendant, and only applies + * to the default hierarchy. + */ +__bpf_kfunc long bpf_task_under_cgroup(struct task_struct *task, + struct cgroup *ancestor) +{ + return task_under_cgroup_hierarchy(task, ancestor); +} #endif /* CONFIG_CGROUPS */ /** @@ -2400,6 +2416,7 @@ BTF_ID_FLAGS(func, bpf_cgroup_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_cgroup_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_cgroup_ancestor, KF_ACQUIRE | KF_RCU | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_cgroup_from_id, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_task_under_cgroup, KF_RCU) #endif BTF_ID_FLAGS(func, bpf_task_from_pid, KF_ACQUIRE | KF_RET_NULL) BTF_SET8_END(generic_btf_ids) -- cgit v1.2.3 From 49e0263ab40f15a11cefa397bb17a0204505cead Mon Sep 17 00:00:00 2001 From: Feng Zhou Date: Sat, 6 May 2023 11:15:45 +0800 Subject: selftests/bpf: Add testcase for bpf_task_under_cgroup test_progs: Tests new kfunc bpf_task_under_cgroup(). The bpf program saves the new task's pid within a given cgroup to the remote_pid, which is convenient for the user-mode program to verify the test correctness. The user-mode program creates its own mount namespace, and mounts the cgroupsv2 hierarchy in there, call the fork syscall, then check if remote_pid and local_pid are unequal. Signed-off-by: Feng Zhou Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230506031545.35991-3-zhoufeng.zf@bytedance.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/DENYLIST.s390x | 1 + .../selftests/bpf/prog_tests/task_under_cgroup.c | 53 ++++++++++++++++++++++ .../selftests/bpf/progs/test_task_under_cgroup.c | 51 +++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/task_under_cgroup.c create mode 100644 tools/testing/selftests/bpf/progs/test_task_under_cgroup.c diff --git a/tools/testing/selftests/bpf/DENYLIST.s390x b/tools/testing/selftests/bpf/DENYLIST.s390x index c7463f3ec3c0..5061d9e24c16 100644 --- a/tools/testing/selftests/bpf/DENYLIST.s390x +++ b/tools/testing/selftests/bpf/DENYLIST.s390x @@ -26,3 +26,4 @@ user_ringbuf # failed to find kernel BTF type ID of verif_stats # trace_vprintk__open_and_load unexpected error: -9 (?) xdp_bonding # failed to auto-attach program 'trace_on_entry': -524 (trampoline) xdp_metadata # JIT does not support calling kernel function (kfunc) +test_task_under_cgroup # JIT does not support calling kernel function (kfunc) diff --git a/tools/testing/selftests/bpf/prog_tests/task_under_cgroup.c b/tools/testing/selftests/bpf/prog_tests/task_under_cgroup.c new file mode 100644 index 000000000000..4224727fb364 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/task_under_cgroup.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Bytedance */ + +#include +#include +#include +#include "test_task_under_cgroup.skel.h" + +#define FOO "/foo" + +void test_task_under_cgroup(void) +{ + struct test_task_under_cgroup *skel; + int ret, foo; + pid_t pid; + + foo = test__join_cgroup(FOO); + if (!ASSERT_OK(foo < 0, "cgroup_join_foo")) + return; + + skel = test_task_under_cgroup__open(); + if (!ASSERT_OK_PTR(skel, "test_task_under_cgroup__open")) + goto cleanup; + + skel->rodata->local_pid = getpid(); + skel->bss->remote_pid = getpid(); + skel->rodata->cgid = get_cgroup_id(FOO); + + ret = test_task_under_cgroup__load(skel); + if (!ASSERT_OK(ret, "test_task_under_cgroup__load")) + goto cleanup; + + ret = test_task_under_cgroup__attach(skel); + if (!ASSERT_OK(ret, "test_task_under_cgroup__attach")) + goto cleanup; + + pid = fork(); + if (pid == 0) + exit(0); + + ret = (pid == -1); + if (ASSERT_OK(ret, "fork process")) + wait(NULL); + + test_task_under_cgroup__detach(skel); + + ASSERT_NEQ(skel->bss->remote_pid, skel->rodata->local_pid, + "test task_under_cgroup"); + +cleanup: + test_task_under_cgroup__destroy(skel); + close(foo); +} diff --git a/tools/testing/selftests/bpf/progs/test_task_under_cgroup.c b/tools/testing/selftests/bpf/progs/test_task_under_cgroup.c new file mode 100644 index 000000000000..56cdc0a553f0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_task_under_cgroup.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Bytedance */ + +#include +#include +#include + +#include "bpf_misc.h" + +struct cgroup *bpf_cgroup_from_id(u64 cgid) __ksym; +long bpf_task_under_cgroup(struct task_struct *task, struct cgroup *ancestor) __ksym; +void bpf_cgroup_release(struct cgroup *p) __ksym; +struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym; +void bpf_task_release(struct task_struct *p) __ksym; + +const volatile int local_pid; +const volatile __u64 cgid; +int remote_pid; + +SEC("tp_btf/task_newtask") +int BPF_PROG(handle__task_newtask, struct task_struct *task, u64 clone_flags) +{ + struct cgroup *cgrp = NULL; + struct task_struct *acquired; + + if (local_pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + acquired = bpf_task_acquire(task); + if (!acquired) + return 0; + + if (local_pid == acquired->tgid) + goto out; + + cgrp = bpf_cgroup_from_id(cgid); + if (!cgrp) + goto out; + + if (bpf_task_under_cgroup(acquired, cgrp)) + remote_pid = acquired->tgid; + +out: + if (cgrp) + bpf_cgroup_release(cgrp); + bpf_task_release(acquired); + + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 3bda08b63670c39be390fcb00e7718775508e673 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 5 May 2023 18:31:30 -0700 Subject: bpf: Allow NULL buffers in bpf_dynptr_slice(_rw) bpf_dynptr_slice(_rw) uses a user provided buffer if it can not provide a pointer to a block of contiguous memory. This buffer is unused in the case of local dynptrs, and may be unused in other cases as well. There is no need to require the buffer, as the kfunc can just return NULL if it was needed and not provided. This adds another kfunc annotation, __opt, which combines with __sz and __szk to allow the buffer associated with the size to be NULL. If the buffer is NULL, the verifier does not check that the buffer is of sufficient size. Signed-off-by: Daniel Rosenberg Link: https://lore.kernel.org/r/20230506013134.2492210-2-drosen@google.com Signed-off-by: Alexei Starovoitov --- Documentation/bpf/kfuncs.rst | 23 ++++++++++++++++++++++- include/linux/skbuff.h | 2 +- kernel/bpf/helpers.c | 30 ++++++++++++++++++------------ kernel/bpf/verifier.c | 17 +++++++++++++---- 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst index ea2516374d92..7a3d9de5f315 100644 --- a/Documentation/bpf/kfuncs.rst +++ b/Documentation/bpf/kfuncs.rst @@ -100,7 +100,7 @@ Hence, whenever a constant scalar argument is accepted by a kfunc which is not a size parameter, and the value of the constant matters for program safety, __k suffix should be used. -2.2.2 __uninit Annotation +2.2.3 __uninit Annotation ------------------------- This annotation is used to indicate that the argument will be treated as @@ -117,6 +117,27 @@ Here, the dynptr will be treated as an uninitialized dynptr. Without this annotation, the verifier will reject the program if the dynptr passed in is not initialized. +2.2.4 __opt Annotation +------------------------- + +This annotation is used to indicate that the buffer associated with an __sz or __szk +argument may be null. If the function is passed a nullptr in place of the buffer, +the verifier will not check that length is appropriate for the buffer. The kfunc is +responsible for checking if this buffer is null before using it. + +An example is given below:: + + __bpf_kfunc void *bpf_dynptr_slice(..., void *buffer__opt, u32 buffer__szk) + { + ... + } + +Here, the buffer may be null. If buffer is not null, it at least of size buffer_szk. +Either way, the returned buffer is either NULL, or of size buffer_szk. Without this +annotation, the verifier will reject the program if a null pointer is passed in with +a nonzero size. + + .. _BPF_kfunc_nodef: 2.3 Using an existing kernel function diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 738776ab8838..8ddb4af1a501 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4033,7 +4033,7 @@ __skb_header_pointer(const struct sk_buff *skb, int offset, int len, if (likely(hlen - offset >= len)) return (void *)data + offset; - if (!skb || unlikely(skb_copy_bits(skb, offset, buffer, len) < 0)) + if (!skb || !buffer || unlikely(skb_copy_bits(skb, offset, buffer, len) < 0)) return NULL; return buffer; diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index a128fe0ab2d0..4ef4c4f8a355 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2190,13 +2190,15 @@ __bpf_kfunc struct task_struct *bpf_task_from_pid(s32 pid) * bpf_dynptr_slice() - Obtain a read-only pointer to the dynptr data. * @ptr: The dynptr whose data slice to retrieve * @offset: Offset into the dynptr - * @buffer: User-provided buffer to copy contents into - * @buffer__szk: Size (in bytes) of the buffer. This is the length of the - * requested slice. This must be a constant. + * @buffer__opt: User-provided buffer to copy contents into. May be NULL + * @buffer__szk: Size (in bytes) of the buffer if present. This is the + * length of the requested slice. This must be a constant. * * For non-skb and non-xdp type dynptrs, there is no difference between * bpf_dynptr_slice and bpf_dynptr_data. * + * If buffer__opt is NULL, the call will fail if buffer_opt was needed. + * * If the intention is to write to the data slice, please use * bpf_dynptr_slice_rdwr. * @@ -2213,7 +2215,7 @@ __bpf_kfunc struct task_struct *bpf_task_from_pid(s32 pid) * direct pointer) */ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset, - void *buffer, u32 buffer__szk) + void *buffer__opt, u32 buffer__szk) { enum bpf_dynptr_type type; u32 len = buffer__szk; @@ -2233,15 +2235,17 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset case BPF_DYNPTR_TYPE_RINGBUF: return ptr->data + ptr->offset + offset; case BPF_DYNPTR_TYPE_SKB: - return skb_header_pointer(ptr->data, ptr->offset + offset, len, buffer); + return skb_header_pointer(ptr->data, ptr->offset + offset, len, buffer__opt); case BPF_DYNPTR_TYPE_XDP: { void *xdp_ptr = bpf_xdp_pointer(ptr->data, ptr->offset + offset, len); if (xdp_ptr) return xdp_ptr; - bpf_xdp_copy_buf(ptr->data, ptr->offset + offset, buffer, len, false); - return buffer; + if (!buffer__opt) + return NULL; + bpf_xdp_copy_buf(ptr->data, ptr->offset + offset, buffer__opt, len, false); + return buffer__opt; } default: WARN_ONCE(true, "unknown dynptr type %d\n", type); @@ -2253,13 +2257,15 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset * bpf_dynptr_slice_rdwr() - Obtain a writable pointer to the dynptr data. * @ptr: The dynptr whose data slice to retrieve * @offset: Offset into the dynptr - * @buffer: User-provided buffer to copy contents into - * @buffer__szk: Size (in bytes) of the buffer. This is the length of the - * requested slice. This must be a constant. + * @buffer__opt: User-provided buffer to copy contents into. May be NULL + * @buffer__szk: Size (in bytes) of the buffer if present. This is the + * length of the requested slice. This must be a constant. * * For non-skb and non-xdp type dynptrs, there is no difference between * bpf_dynptr_slice and bpf_dynptr_data. * + * If buffer__opt is NULL, the call will fail if buffer_opt was needed. + * * The returned pointer is writable and may point to either directly the dynptr * data at the requested offset or to the buffer if unable to obtain a direct * data pointer to (example: the requested slice is to the paged area of an skb @@ -2290,7 +2296,7 @@ __bpf_kfunc void *bpf_dynptr_slice(const struct bpf_dynptr_kern *ptr, u32 offset * direct pointer) */ __bpf_kfunc void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr_kern *ptr, u32 offset, - void *buffer, u32 buffer__szk) + void *buffer__opt, u32 buffer__szk) { if (!ptr->data || __bpf_dynptr_is_rdonly(ptr)) return NULL; @@ -2317,7 +2323,7 @@ __bpf_kfunc void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr_kern *ptr, u32 o * will be copied out into the buffer and the user will need to call * bpf_dynptr_write() to commit changes. */ - return bpf_dynptr_slice(ptr, offset, buffer, buffer__szk); + return bpf_dynptr_slice(ptr, offset, buffer__opt, buffer__szk); } __bpf_kfunc int bpf_dynptr_adjust(struct bpf_dynptr_kern *ptr, u32 start, u32 end) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 0fa96581eb77..7e6bbae9db81 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -9743,6 +9743,11 @@ static bool is_kfunc_arg_const_mem_size(const struct btf *btf, return __kfunc_param_match_suffix(btf, arg, "__szk"); } +static bool is_kfunc_arg_optional(const struct btf *btf, const struct btf_param *arg) +{ + return __kfunc_param_match_suffix(btf, arg, "__opt"); +} + static bool is_kfunc_arg_constant(const struct btf *btf, const struct btf_param *arg) { return __kfunc_param_match_suffix(btf, arg, "__k"); @@ -10830,13 +10835,17 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ break; case KF_ARG_PTR_TO_MEM_SIZE: { + struct bpf_reg_state *buff_reg = ®s[regno]; + const struct btf_param *buff_arg = &args[i]; struct bpf_reg_state *size_reg = ®s[regno + 1]; const struct btf_param *size_arg = &args[i + 1]; - ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); - if (ret < 0) { - verbose(env, "arg#%d arg#%d memory, len pair leads to invalid memory access\n", i, i + 1); - return ret; + if (!register_is_null(buff_reg) || !is_kfunc_arg_optional(meta->btf, buff_arg)) { + ret = check_kfunc_mem_size_reg(env, size_reg, regno + 1); + if (ret < 0) { + verbose(env, "arg#%d arg#%d memory, len pair leads to invalid memory access\n", i, i + 1); + return ret; + } } if (is_kfunc_arg_const_mem_size(meta->btf, size_arg, size_reg)) { -- cgit v1.2.3 From 1ce33b6c846fbe0439eeee477b767de4bc3ad35f Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 5 May 2023 18:31:31 -0700 Subject: selftests/bpf: Test allowing NULL buffer in dynptr slice bpf_dynptr_slice(_rw) no longer requires a buffer for verification. If the buffer is needed, but not present, the function will return NULL. Signed-off-by: Daniel Rosenberg Link: https://lore.kernel.org/r/20230506013134.2492210-3-drosen@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/dynptr.c | 1 + tools/testing/selftests/bpf/progs/dynptr_success.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index 0478916aff37..13d4b9ab16e7 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -26,6 +26,7 @@ static struct { {"test_dynptr_is_null", SETUP_SYSCALL_SLEEP}, {"test_dynptr_is_rdonly", SETUP_SKB_PROG}, {"test_dynptr_clone", SETUP_SKB_PROG}, + {"test_dynptr_skb_no_buff", SETUP_SKB_PROG}, }; static void verify_success(const char *prog_name, enum test_setup_type setup_type) diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index be7de62de045..d299ef3b4d1f 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -505,3 +505,20 @@ int test_dynptr_clone(struct __sk_buff *skb) return 0; } + +SEC("?cgroup_skb/egress") +int test_dynptr_skb_no_buff(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr; + __u64 *data; + + if (bpf_dynptr_from_skb(skb, 0, &ptr)) { + err = 1; + return 1; + } + + /* This may return NULL. SKB may require a buffer */ + data = bpf_dynptr_slice(&ptr, 0, NULL, 1); + + return !!data; +} -- cgit v1.2.3 From 3881fdfed21ff129a23979c0a92df6d3c5f49aa9 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 5 May 2023 18:31:32 -0700 Subject: selftests/bpf: Check overflow in optional buffer This ensures we still reject invalid memory accesses in buffers that are marked optional. Signed-off-by: Daniel Rosenberg Link: https://lore.kernel.org/r/20230506013134.2492210-4-drosen@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/dynptr_fail.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index efe4ce72d00e..c2f0e18af951 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -1665,3 +1665,23 @@ int clone_xdp_packet_data(struct xdp_md *xdp) return 0; } + +/* Buffers that are provided must be sufficiently long */ +SEC("?cgroup_skb/egress") +__failure __msg("memory, len pair leads to invalid memory access") +int test_dynptr_skb_small_buff(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr; + char buffer[8] = {}; + __u64 *data; + + if (bpf_dynptr_from_skb(skb, 0, &ptr)) { + err = 1; + return 1; + } + + /* This may return NULL. SKB may require a buffer */ + data = bpf_dynptr_slice(&ptr, 0, buffer, 9); + + return !!data; +} -- cgit v1.2.3 From 2012c867c8005d72c949e274133df429ece78808 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 5 May 2023 18:31:33 -0700 Subject: bpf: verifier: Accept dynptr mem as mem in helpers This allows using memory retrieved from dynptrs with helper functions that accept ARG_PTR_TO_MEM. For instance, results from bpf_dynptr_data can be passed along to bpf_strncmp. Signed-off-by: Daniel Rosenberg Link: https://lore.kernel.org/r/20230506013134.2492210-5-drosen@google.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7e6bbae9db81..754129d41225 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -7495,12 +7495,16 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno, * ARG_PTR_TO_MEM + MAYBE_NULL is compatible with PTR_TO_MEM and PTR_TO_MEM + MAYBE_NULL, * but ARG_PTR_TO_MEM is compatible only with PTR_TO_MEM but NOT with PTR_TO_MEM + MAYBE_NULL * + * ARG_PTR_TO_MEM is compatible with PTR_TO_MEM that is tagged with a dynptr type. + * * Therefore we fold these flags depending on the arg_type before comparison. */ if (arg_type & MEM_RDONLY) type &= ~MEM_RDONLY; if (arg_type & PTR_MAYBE_NULL) type &= ~PTR_MAYBE_NULL; + if (base_type(arg_type) == ARG_PTR_TO_MEM) + type &= ~DYNPTR_TYPE_FLAG_MASK; if (meta->func_id == BPF_FUNC_kptr_xchg && type & MEM_ALLOC) type &= ~MEM_ALLOC; -- cgit v1.2.3 From 798e48fc28fa64aa4eca6e8a404fa20ac8f7c09e Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 5 May 2023 18:31:34 -0700 Subject: selftests/bpf: Accept mem from dynptr in helper funcs This ensures that buffers retrieved from dynptr_data are allowed to be passed in to helpers that take mem, like bpf_strncmp Signed-off-by: Daniel Rosenberg Link: https://lore.kernel.org/r/20230506013134.2492210-6-drosen@google.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/dynptr.c | 1 + tools/testing/selftests/bpf/progs/dynptr_success.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/dynptr.c b/tools/testing/selftests/bpf/prog_tests/dynptr.c index 13d4b9ab16e7..7cfac53c0d58 100644 --- a/tools/testing/selftests/bpf/prog_tests/dynptr.c +++ b/tools/testing/selftests/bpf/prog_tests/dynptr.c @@ -27,6 +27,7 @@ static struct { {"test_dynptr_is_rdonly", SETUP_SKB_PROG}, {"test_dynptr_clone", SETUP_SKB_PROG}, {"test_dynptr_skb_no_buff", SETUP_SKB_PROG}, + {"test_dynptr_skb_strcmp", SETUP_SKB_PROG}, }; static void verify_success(const char *prog_name, enum test_setup_type setup_type) diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index d299ef3b4d1f..0c053976f8f9 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -522,3 +522,24 @@ int test_dynptr_skb_no_buff(struct __sk_buff *skb) return !!data; } + +SEC("?cgroup_skb/egress") +int test_dynptr_skb_strcmp(struct __sk_buff *skb) +{ + struct bpf_dynptr ptr; + char *data; + + if (bpf_dynptr_from_skb(skb, 0, &ptr)) { + err = 1; + return 1; + } + + /* This may return NULL. SKB may require a buffer */ + data = bpf_dynptr_slice(&ptr, 0, NULL, 10); + if (data) { + bpf_strncmp(data, 10, "foo"); + return 1; + } + + return 1; +} -- cgit v1.2.3 From 94e86ef1b801d213dfb8543633dec86abb1a457d Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 8 May 2023 12:33:59 +0530 Subject: net: phy: dp83869: support mii mode when rgmii strap cfg is used The DP83869 PHY on TI's k3-am642-evm supports both MII and RGMII interfaces and is configured by default to use RGMII interface (strap). However, the board design allows switching dynamically to MII interface for testing purposes by applying different set of pinmuxes. To support switching to MII interface, update the DP83869 PHY driver to configure OP_MODE_DECODE.RGMII_MII_SEL(bit 5) properly when MII PHY interface mode is requested. Signed-off-by: Grygorii Strashko Signed-off-by: Siddharth Vadapalli Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230508070359.357474-1-s-vadapalli@ti.com Signed-off-by: Paolo Abeni --- drivers/net/phy/dp83869.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 9ab5eff502b7..fa8c6fdcf301 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -692,8 +692,19 @@ static int dp83869_configure_mode(struct phy_device *phydev, /* Below init sequence for each operational mode is defined in * section 9.4.8 of the datasheet. */ + phy_ctrl_val = dp83869->mode; + if (phydev->interface == PHY_INTERFACE_MODE_MII) { + if (dp83869->mode == DP83869_100M_MEDIA_CONVERT || + dp83869->mode == DP83869_RGMII_100_BASE) { + phy_ctrl_val |= DP83869_OP_MODE_MII; + } else { + phydev_err(phydev, "selected op-mode is not valid with MII mode\n"); + return -EINVAL; + } + } + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, - dp83869->mode); + phy_ctrl_val); if (ret) return ret; -- cgit v1.2.3 From 695df2f417d25202bdac9cde3c82d2acb6492b4d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 5 May 2023 16:11:25 +0300 Subject: wifi: ath: work around false-positive stringop-overread warning In a rare arm64 randconfig build, I got multiple warnings for ath11k and ath12k: In function 'ath11k_peer_assoc_h_ht', inlined from 'ath11k_peer_assoc_prepare' at drivers/net/wireless/ath/ath11k/mac.c:2665:2: drivers/net/wireless/ath/ath11k/mac.c:1709:13: error: 'ath11k_peer_assoc_h_ht_masked' reading 10 bytes from a region of size 0 [-Werror=stringop-overread] 1709 | if (ath11k_peer_assoc_h_ht_masked(ht_mcs_mask)) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This happens whenever gcc-13 fails to inline one of the functions that take a fixed-length array argument but gets passed a pointer. Change these functions to all take a regular pointer argument instead. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230417205447.1800912-1-arnd@kernel.org --- drivers/net/wireless/ath/ath11k/mac.c | 12 ++++++------ drivers/net/wireless/ath/ath12k/mac.c | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 05920ad413c5..f8dc0297d07d 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -433,7 +433,7 @@ u8 ath11k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband, } static u32 -ath11k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) +ath11k_mac_max_ht_nss(const u8 *ht_mcs_mask) { int nss; @@ -445,7 +445,7 @@ ath11k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) } static u32 -ath11k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) +ath11k_mac_max_vht_nss(const u16 *vht_mcs_mask) { int nss; @@ -457,7 +457,7 @@ ath11k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) } static u32 -ath11k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +ath11k_mac_max_he_nss(const u16 *he_mcs_mask) { int nss; @@ -1658,7 +1658,7 @@ static void ath11k_peer_assoc_h_rates(struct ath11k *ar, } static bool -ath11k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) +ath11k_peer_assoc_h_ht_masked(const u8 *ht_mcs_mask) { int nss; @@ -1670,7 +1670,7 @@ ath11k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) } static bool -ath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[]) +ath11k_peer_assoc_h_vht_masked(const u16 *vht_mcs_mask) { int nss; @@ -2065,7 +2065,7 @@ static u16 ath11k_peer_assoc_h_he_limit(u16 tx_mcs_set, } static bool -ath11k_peer_assoc_h_he_masked(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +ath11k_peer_assoc_h_he_masked(const u16 *he_mcs_mask) { int nss; diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b337fb7f793f..86408480c202 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -381,7 +381,7 @@ u8 ath12k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband, } static u32 -ath12k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) +ath12k_mac_max_ht_nss(const u8 *ht_mcs_mask) { int nss; @@ -393,7 +393,7 @@ ath12k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) } static u32 -ath12k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) +ath12k_mac_max_vht_nss(const u16 *vht_mcs_mask) { int nss; @@ -1303,7 +1303,7 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar, } static bool -ath12k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) +ath12k_peer_assoc_h_ht_masked(const u8 *ht_mcs_mask) { int nss; @@ -1315,7 +1315,7 @@ ath12k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN]) } static bool -ath12k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX]) +ath12k_peer_assoc_h_vht_masked(const u16 *vht_mcs_mask) { int nss; -- cgit v1.2.3 From a08dbb04d7365a04d52882143cf196005bfc88c3 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Fri, 5 May 2023 16:11:27 +0300 Subject: wifi: ath11k: driver settings for MBSSID and EMA Advertise the driver support for multiple BSSID (MBSSID) and enhanced multi-BSSID advertisements (EMA) by setting extended capabilities. Configure mbssid_max_interfaces and ema_max_profile_periodicity fields in structure wiphy which are used to advertise maximum number of interfaces and profile periodicity supported by the driver. Add new WMI fields to configure maximum vdev count supported for MBSSID and profile periodicity in case of EMA. Setting WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET flag indicates that the firmware should track and update the DTIM counts for each non-transmitted profile. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Co-developed-by: John Crispin Signed-off-by: John Crispin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230405221648.17950-2-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath11k/hw.c | 3 +++ drivers/net/wireless/ath/ath11k/hw.h | 1 + drivers/net/wireless/ath/ath11k/mac.c | 7 +++++++ drivers/net/wireless/ath/ath11k/wmi.c | 3 +++ drivers/net/wireless/ath/ath11k/wmi.h | 6 ++++++ 5 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index eb995f9cf0fa..3b5181e054d3 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -202,6 +202,9 @@ static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, config->twt_ap_sta_count = 1000; config->flag1 |= WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64; config->flag1 |= WMI_RSRC_CFG_FLAG1_ACK_RSSI; + config->ema_max_vap_cnt = ab->num_radios; + config->ema_max_profile_period = TARGET_EMA_MAX_PROFILE_PERIOD; + config->beacon_tx_offload_max_vdev += config->ema_max_vap_cnt; } static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw, diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 6a5dd2dbdb3a..f5533630a7f9 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -64,6 +64,7 @@ #define TARGET_NUM_WDS_ENTRIES 32 #define TARGET_DMA_BURST_SIZE 1 #define TARGET_RX_BATCHMODE 1 +#define TARGET_EMA_MAX_PROFILE_PERIOD 8 #define ATH11K_HW_MAX_QUEUES 4 #define ATH11K_QUEUE_LEN 4096 diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index f8dc0297d07d..a25299b3220b 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9001,19 +9001,23 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) static const u8 ath11k_if_types_ext_capa[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, }; static const u8 ath11k_if_types_ext_capa_sta[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, }; static const u8 ath11k_if_types_ext_capa_ap[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT, + [10] = WLAN_EXT_CAPA11_EMA_SUPPORT, }; static const struct wiphy_iftype_ext_capab ath11k_iftypes_ext_capa[] = { @@ -9251,6 +9255,9 @@ static int __ath11k_mac_register(struct ath11k *ar) wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER); + ar->hw->wiphy->mbssid_max_interfaces = TARGET_NUM_VDEVS(ab); + ar->hw->wiphy->ema_max_profile_periodicity = TARGET_EMA_MAX_PROFILE_PERIOD; + ath11k_reg_init(ar); if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) { diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index a55b5fe37ecf..88bd9b9f7a4e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -3987,6 +3987,9 @@ ath11k_wmi_copy_resource_config(struct wmi_resource_config *wmi_cfg, ~(1 << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT); wmi_cfg->host_service_flags |= (tg_cfg->is_reg_cc_ext_event_supported << WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT); + wmi_cfg->flags2 = WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET; + wmi_cfg->ema_max_vap_cnt = tg_cfg->ema_max_vap_cnt; + wmi_cfg->ema_max_profile_period = tg_cfg->ema_max_profile_period; } static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 91bc3e648ce1..d70cf0b1b95b 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2317,6 +2317,7 @@ struct wmi_init_cmd { } __packed; #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) +#define WMI_RSRC_CFG_FLAG2_CALC_NEXT_DTIM_COUNT_SET BIT(9) #define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18) #define WMI_CFG_HOST_SERVICE_FLAG_REG_CC_EXT 4 @@ -2389,6 +2390,9 @@ struct wmi_resource_config { u32 msdu_flow_override_config1; u32 flags2; u32 host_service_flags; + u32 max_rnr_neighbours; + u32 ema_max_vap_cnt; + u32 ema_max_profile_period; } __packed; struct wmi_service_ready_event { @@ -5646,6 +5650,8 @@ struct target_resource_config { u32 twt_ap_pdev_count; u32 twt_ap_sta_count; u8 is_reg_cc_ext_event_supported; + u32 ema_max_vap_cnt; + u32 ema_max_profile_period; }; enum wmi_debug_log_param { -- cgit v1.2.3 From 5a81610acf66c4ad6e1a1fbd09f3f555fca863b1 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Fri, 5 May 2023 16:11:27 +0300 Subject: wifi: ath11k: MBSSID configuration during vdev create/start Configure multiple BSSID flags and index of the transmitting interface in vdev create/start commands depending on the service bit WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Co-developed-by: John Crispin Signed-off-by: John Crispin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230405221648.17950-3-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 70 +++++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath11k/wmi.c | 5 +++ drivers/net/wireless/ath/ath11k/wmi.h | 19 ++++++++++ 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index a25299b3220b..5feb881067c9 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -6181,17 +6181,62 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw) atomic_set(&ar->num_pending_mgmt_tx, 0); } -static void -ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif, - struct vdev_create_params *params) +static int ath11k_mac_setup_vdev_params_mbssid(struct ath11k_vif *arvif, + u32 *flags, u32 *tx_vdev_id) +{ + struct ath11k *ar = arvif->ar; + struct ath11k_vif *tx_arvif; + struct ieee80211_vif *tx_vif; + + *tx_vdev_id = 0; + tx_vif = arvif->vif->mbssid_tx_vif; + if (!tx_vif) { + *flags = WMI_HOST_VDEV_FLAGS_NON_MBSSID_AP; + return 0; + } + + tx_arvif = (void *)tx_vif->drv_priv; + + if (arvif->vif->bss_conf.nontransmitted) { + if (ar->hw->wiphy != ieee80211_vif_to_wdev(tx_vif)->wiphy) + return -EINVAL; + + *flags = WMI_HOST_VDEV_FLAGS_NON_TRANSMIT_AP; + *tx_vdev_id = ath11k_vif_to_arvif(tx_vif)->vdev_id; + } else if (tx_arvif == arvif) { + *flags = WMI_HOST_VDEV_FLAGS_TRANSMIT_AP; + } else { + return -EINVAL; + } + + if (arvif->vif->bss_conf.ema_ap) + *flags |= WMI_HOST_VDEV_FLAGS_EMA_MODE; + + return 0; +} + +static int ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif, + struct vdev_create_params *params) { struct ath11k *ar = arvif->ar; struct ath11k_pdev *pdev = ar->pdev; + int ret; params->if_id = arvif->vdev_id; params->type = arvif->vdev_type; params->subtype = arvif->vdev_subtype; params->pdev_id = pdev->pdev_id; + params->mbssid_flags = 0; + params->mbssid_tx_vdev_id = 0; + + if (!test_bit(WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT, + ar->ab->wmi_ab.svc_map)) { + ret = ath11k_mac_setup_vdev_params_mbssid(arvif, + ¶ms->mbssid_flags, + ¶ms->mbssid_tx_vdev_id); + if (ret) + return ret; + } if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) { params->chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains; @@ -6206,6 +6251,7 @@ ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif, params->chains[NL80211_BAND_6GHZ].tx = ar->num_tx_chains; params->chains[NL80211_BAND_6GHZ].rx = ar->num_rx_chains; } + return 0; } static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw, @@ -6500,7 +6546,12 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++) vif->hw_queue[i] = i % (ATH11K_HW_MAX_QUEUES - 1); - ath11k_mac_setup_vdev_create_params(arvif, &vdev_param); + ret = ath11k_mac_setup_vdev_create_params(arvif, &vdev_param); + if (ret) { + ath11k_warn(ab, "failed to create vdev parameters %d: %d\n", + arvif->vdev_id, ret); + goto err; + } ret = ath11k_wmi_vdev_create(ar, vif->addr, &vdev_param); if (ret) { @@ -6905,6 +6956,17 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; + arg.mbssid_flags = 0; + arg.mbssid_tx_vdev_id = 0; + if (test_bit(WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT, + ar->ab->wmi_ab.svc_map)) { + ret = ath11k_mac_setup_vdev_params_mbssid(arvif, + &arg.mbssid_flags, + &arg.mbssid_tx_vdev_id); + if (ret) + return ret; + } + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; arg.ssid_len = arvif->u.ap.ssid_len; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 88bd9b9f7a4e..e57e9aa63c9f 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -724,6 +724,9 @@ int ath11k_wmi_vdev_create(struct ath11k *ar, u8 *macaddr, cmd->vdev_subtype = param->subtype; cmd->num_cfg_txrx_streams = WMI_NUM_SUPPORTED_BAND_MAX; cmd->pdev_id = param->pdev_id; + cmd->mbssid_flags = param->mbssid_flags; + cmd->mbssid_tx_vdev_id = param->mbssid_tx_vdev_id; + ether_addr_copy(cmd->vdev_macaddr.addr, macaddr); ptr = skb->data + sizeof(*cmd); @@ -941,6 +944,8 @@ int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg, cmd->cac_duration_ms = arg->cac_duration_ms; cmd->regdomain = arg->regdomain; cmd->he_ops = arg->he_ops; + cmd->mbssid_flags = arg->mbssid_flags; + cmd->mbssid_tx_vdev_id = arg->mbssid_tx_vdev_id; if (!restart) { if (arg->ssid) { diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index d70cf0b1b95b..623e687709c7 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -137,6 +137,14 @@ enum { WMI_AUTORATE_3200NS_GI = BIT(11), }; +enum { + WMI_HOST_VDEV_FLAGS_NON_MBSSID_AP = 0x00000001, + WMI_HOST_VDEV_FLAGS_TRANSMIT_AP = 0x00000002, + WMI_HOST_VDEV_FLAGS_NON_TRANSMIT_AP = 0x00000004, + WMI_HOST_VDEV_FLAGS_EMA_MODE = 0x00000008, + WMI_HOST_VDEV_FLAGS_SCAN_MODE_VAP = 0x00000010, +}; + /* * wmi command groups. */ @@ -2096,6 +2104,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_EXT2_MSG = 220, WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT = 246, WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249, + WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253, WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE = 263, /* The second 128 bits */ @@ -2583,6 +2592,8 @@ struct vdev_create_params { u8 rx; } chains[NUM_NL80211_BANDS]; u32 pdev_id; + u32 mbssid_flags; + u32 mbssid_tx_vdev_id; }; struct wmi_vdev_create_cmd { @@ -2593,6 +2604,8 @@ struct wmi_vdev_create_cmd { struct wmi_mac_addr vdev_macaddr; u32 num_cfg_txrx_streams; u32 pdev_id; + u32 mbssid_flags; + u32 mbssid_tx_vdev_id; } __packed; struct wmi_vdev_txrx_streams { @@ -2656,6 +2669,9 @@ struct wmi_vdev_start_request_cmd { u32 he_ops; u32 cac_duration_ms; u32 regdomain; + u32 min_data_rate; + u32 mbssid_flags; + u32 mbssid_tx_vdev_id; } __packed; #define MGMT_TX_DL_FRM_LEN 64 @@ -2825,6 +2841,9 @@ struct wmi_vdev_start_req_arg { u32 pref_rx_streams; u32 pref_tx_streams; u32 num_noa_descriptors; + u32 min_data_rate; + u32 mbssid_flags; + u32 mbssid_tx_vdev_id; }; struct peer_create_params { -- cgit v1.2.3 From cf604e72bc6e6db68c7fcaa8779b03ec14b8d2fa Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Fri, 5 May 2023 16:11:27 +0300 Subject: wifi: ath11k: rename MBSSID fields in wmi_vdev_up_cmd Rename trans_bssid to tx_vdev_bssid to make it similar to vdev_bssid. Rename profile_num to nontx_profile_cnt, and profile_idx to nontx_profile_idx which makes it clear that these store configurations related to MBSSID non-transmitting profiles. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230405221648.17950-4-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath11k/wmi.c | 6 +++--- drivers/net/wireless/ath/ath11k/wmi.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index e57e9aa63c9f..c7efa56bd93c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1029,10 +1029,10 @@ int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid) bss_conf = &arvif->vif->bss_conf; if (bss_conf->nontransmitted) { - ether_addr_copy(cmd->trans_bssid.addr, + ether_addr_copy(cmd->tx_vdev_bssid.addr, bss_conf->transmitter_bssid); - cmd->profile_idx = bss_conf->bssid_index; - cmd->profile_num = bss_conf->bssid_indicator; + cmd->nontx_profile_idx = bss_conf->bssid_index; + cmd->nontx_profile_cnt = bss_conf->bssid_indicator; } } diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 623e687709c7..a2e3ba92526e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -2625,9 +2625,9 @@ struct wmi_vdev_up_cmd { u32 vdev_id; u32 vdev_assoc_id; struct wmi_mac_addr vdev_bssid; - struct wmi_mac_addr trans_bssid; - u32 profile_idx; - u32 profile_num; + struct wmi_mac_addr tx_vdev_bssid; + u32 nontx_profile_idx; + u32 nontx_profile_cnt; } __packed; struct wmi_vdev_stop_cmd { -- cgit v1.2.3 From c82dc33f252fd8883be66f2d0230af0fd734c683 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Fri, 5 May 2023 16:11:27 +0300 Subject: wifi: ath11k: MBSSID parameter configuration in AP mode Include MBSSID parameters in WMI vdev up operation. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Co-developed-by: John Crispin Signed-off-by: John Crispin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230405221648.17950-5-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 29 +++++++++++++++++++++++------ drivers/net/wireless/ath/ath11k/wmi.c | 8 +++++++- drivers/net/wireless/ath/ath11k/wmi.h | 3 ++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 5feb881067c9..e04a8642d19c 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -964,7 +964,7 @@ static int ath11k_mac_monitor_vdev_start(struct ath11k *ar, int vdev_id, return ret; } - ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); + ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr, NULL, 0, 0); if (ret) { ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", vdev_id, ret); @@ -1423,6 +1423,7 @@ static void ath11k_control_beaconing(struct ath11k_vif *arvif, struct ieee80211_bss_conf *info) { struct ath11k *ar = arvif->ar; + struct ath11k_vif *tx_arvif = NULL; int ret = 0; lockdep_assert_held(&arvif->ar->conf_mutex); @@ -1451,8 +1452,14 @@ static void ath11k_control_beaconing(struct ath11k_vif *arvif, ether_addr_copy(arvif->bssid, info->bssid); + if (arvif->vif->mbssid_tx_vif) + tx_arvif = (struct ath11k_vif *)arvif->vif->mbssid_tx_vif->drv_priv; + ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, - arvif->bssid); + arvif->bssid, + tx_arvif ? tx_arvif->bssid : NULL, + info->bssid_index, + 1 << info->bssid_indicator); if (ret) { ath11k_warn(ar->ab, "failed to bring up vdev %d: %i\n", arvif->vdev_id, ret); @@ -2879,7 +2886,8 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, arvif->aid = vif->cfg.aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); - ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); + ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid, + NULL, 0, 0); if (ret) { ath11k_warn(ar->ab, "failed to set vdev %d up: %d\n", arvif->vdev_id, ret); @@ -7133,7 +7141,8 @@ ath11k_mac_update_vif_chan(struct ath11k *ar, int n_vifs) { struct ath11k_base *ab = ar->ab; - struct ath11k_vif *arvif; + struct ath11k_vif *arvif, *tx_arvif = NULL; + struct ieee80211_vif *mbssid_tx_vif; int ret; int i; bool monitor_vif = false; @@ -7187,8 +7196,15 @@ ath11k_mac_update_vif_chan(struct ath11k *ar, ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n", ret); + mbssid_tx_vif = arvif->vif->mbssid_tx_vif; + if (mbssid_tx_vif) + tx_arvif = (struct ath11k_vif *)mbssid_tx_vif->drv_priv; + ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, - arvif->bssid); + arvif->bssid, + tx_arvif ? tx_arvif->bssid : NULL, + arvif->vif->bss_conf.bssid_index, + 1 << arvif->vif->bss_conf.bssid_indicator); if (ret) { ath11k_warn(ab, "failed to bring vdev up %d: %d\n", arvif->vdev_id, ret); @@ -7306,7 +7322,8 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw, } if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { - ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr); + ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr, + NULL, 0, 0); if (ret) { ath11k_warn(ab, "failed put monitor up: %d\n", ret); return ret; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index c7efa56bd93c..12b31f389318 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1001,7 +1001,8 @@ int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg, return ret; } -int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid) +int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid, + u8 *tx_bssid, u32 nontx_profile_idx, u32 nontx_profile_cnt) { struct ath11k_pdev_wmi *wmi = ar->wmi; struct wmi_vdev_up_cmd *cmd; @@ -1025,6 +1026,11 @@ int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid) ether_addr_copy(cmd->vdev_bssid.addr, bssid); + cmd->nontx_profile_idx = nontx_profile_idx; + cmd->nontx_profile_cnt = nontx_profile_cnt; + if (tx_bssid) + ether_addr_copy(cmd->tx_vdev_bssid.addr, tx_bssid); + if (arvif && arvif->vif->type == NL80211_IFTYPE_STATION) { bss_conf = &arvif->vif->bss_conf; diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index a2e3ba92526e..55aceedc1795 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -6301,7 +6301,8 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, struct sk_buff *bcn); int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id); int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, - const u8 *bssid); + const u8 *bssid, u8 *tx_bssid, u32 nontx_profile_idx, + u32 nontx_profile_cnt); int ath11k_wmi_vdev_stop(struct ath11k *ar, u8 vdev_id); int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg, bool restart); -- cgit v1.2.3 From cb9bea773c85e372931cd7a177db4165adf29d95 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Fri, 5 May 2023 16:11:28 +0300 Subject: wifi: ath11k: refactor vif parameter configurations Security parameters for each non-transmitting profile can be different when MBSSID is enabled and this information is included in the MBSSID element in the Beacon frame. Current implementation to set rsnie_present and wpaie_present does not parse this element hence it applies only to the transmitting interface. Move the code to a separate function to make additions for non-transmitting interfaces cleaner. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230405221648.17950-6-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 41 ++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index e04a8642d19c..adb2122fe340 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1351,28 +1351,14 @@ err_mon_del: return ret; } -static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, + struct sk_buff *bcn) { - struct ath11k *ar = arvif->ar; - struct ath11k_base *ab = ar->ab; - struct ieee80211_hw *hw = ar->hw; - struct ieee80211_vif *vif = arvif->vif; - struct ieee80211_mutable_offsets offs = {}; - struct sk_buff *bcn; struct ieee80211_mgmt *mgmt; u8 *ies; - int ret; - - if (arvif->vdev_type != WMI_VDEV_TYPE_AP) - return 0; - - bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); - if (!bcn) { - ath11k_warn(ab, "failed to get beacon template from mac80211\n"); - return -EPERM; - } ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); + mgmt = (struct ieee80211_mgmt *)bcn->data; ies += sizeof(mgmt->u.beacon); if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies))) @@ -1386,7 +1372,28 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) arvif->wpaie_present = true; else arvif->wpaie_present = false; +} + +static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +{ + struct ath11k *ar = arvif->ar; + struct ath11k_base *ab = ar->ab; + struct ieee80211_hw *hw = ar->hw; + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_mutable_offsets offs = {}; + struct sk_buff *bcn; + int ret; + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + return 0; + + bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); + if (!bcn) { + ath11k_warn(ab, "failed to get beacon template from mac80211\n"); + return -EPERM; + } + ath11k_mac_set_vif_params(arvif, bcn); ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); kfree_skb(bcn); -- cgit v1.2.3 From 335a92765d308dfe22826f5562cd4b4389b45e71 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Fri, 5 May 2023 16:11:28 +0300 Subject: wifi: ath11k: MBSSID beacon support - Split ath11k_mac_setup_bcn_tmpl() to move the beacon retrieval and WMI command to a new function, ath11k_mac_setup_bcn_tmpl_legacy(). In the original function add checks to use the transmitting interface when MBSSID is enabled. - Set rsnie_present and wpaie_present fields for the non-transmitting interfaces when MBSSID is enabled. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Co-developed-by: John Crispin Signed-off-by: John Crispin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230405221648.17950-7-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 116 ++++++++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath11k/wmi.c | 1 + 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index adb2122fe340..3229f65fc6d2 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1351,6 +1351,84 @@ err_mon_del: return ret; } +static void ath11k_mac_setup_nontx_vif_rsnie(struct ath11k_vif *arvif, + bool tx_arvif_rsnie_present, + const u8 *profile, u8 profile_len) +{ + if (cfg80211_find_ie(WLAN_EID_RSN, profile, profile_len)) { + arvif->rsnie_present = true; + } else if (tx_arvif_rsnie_present) { + int i; + u8 nie_len; + const u8 *nie = cfg80211_find_ext_ie(WLAN_EID_EXT_NON_INHERITANCE, + profile, profile_len); + if (!nie) + return; + + nie_len = nie[1]; + nie += 2; + for (i = 0; i < nie_len; i++) { + if (nie[i] == WLAN_EID_RSN) { + arvif->rsnie_present = false; + break; + } + } + } +} + +static bool ath11k_mac_set_nontx_vif_params(struct ath11k_vif *tx_arvif, + struct ath11k_vif *arvif, + struct sk_buff *bcn) +{ + struct ieee80211_mgmt *mgmt; + const u8 *ies, *profile, *next_profile; + int ies_len; + + ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); + mgmt = (struct ieee80211_mgmt *)bcn->data; + ies += sizeof(mgmt->u.beacon); + ies_len = skb_tail_pointer(bcn) - ies; + + ies = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ies, ies_len); + arvif->rsnie_present = tx_arvif->rsnie_present; + + while (ies) { + u8 mbssid_len; + + ies_len -= (2 + ies[1]); + mbssid_len = ies[1] - 1; + profile = &ies[3]; + + while (mbssid_len) { + u8 profile_len; + + profile_len = profile[1]; + next_profile = profile + (2 + profile_len); + mbssid_len -= (2 + profile_len); + + profile += 2; + profile_len -= (2 + profile[1]); + profile += (2 + profile[1]); /* nontx capabilities */ + profile_len -= (2 + profile[1]); + profile += (2 + profile[1]); /* SSID */ + if (profile[2] == arvif->vif->bss_conf.bssid_index) { + profile_len -= 5; + profile = profile + 5; + ath11k_mac_setup_nontx_vif_rsnie(arvif, + tx_arvif->rsnie_present, + profile, + profile_len); + return true; + } + profile = next_profile; + } + ies = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, profile, + ies_len); + } + + return false; +} + static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, struct sk_buff *bcn) { @@ -1374,18 +1452,26 @@ static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, arvif->wpaie_present = false; } -static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif) { struct ath11k *ar = arvif->ar; struct ath11k_base *ab = ar->ab; + struct ath11k_vif *tx_arvif = arvif; struct ieee80211_hw *hw = ar->hw; struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; struct sk_buff *bcn; int ret; - if (arvif->vdev_type != WMI_VDEV_TYPE_AP) - return 0; + if (arvif->vif->mbssid_tx_vif) { + tx_arvif = (void *)arvif->vif->mbssid_tx_vif->drv_priv; + if (tx_arvif != arvif) { + ar = tx_arvif->ar; + ab = ar->ab; + hw = ar->hw; + vif = tx_arvif->vif; + } + } bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); if (!bcn) { @@ -1393,9 +1479,12 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) return -EPERM; } - ath11k_mac_set_vif_params(arvif, bcn); - ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); + if (tx_arvif == arvif) + ath11k_mac_set_vif_params(tx_arvif, bcn); + else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) + return -EINVAL; + ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); kfree_skb(bcn); if (ret) @@ -1405,6 +1494,23 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) return ret; } +static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) +{ + struct ieee80211_vif *vif = arvif->vif; + + if (arvif->vdev_type != WMI_VDEV_TYPE_AP) + return 0; + + /* Target does not expect beacon templates for the already up + * non-transmitting interfaces, and results in a crash if sent. + */ + if (vif->mbssid_tx_vif && + arvif != (void *)vif->mbssid_tx_vif->drv_priv && arvif->is_up) + return 0; + + return ath11k_mac_setup_bcn_tmpl_mbssid(arvif); +} + void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) { struct ieee80211_vif *vif = arvif->vif; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 12b31f389318..30364dfe12be 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1737,6 +1737,7 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, } cmd->buf_len = bcn->len; + cmd->mbssid_ie_offset = offs->mbssid_off; ptr = skb->data + sizeof(*cmd); -- cgit v1.2.3 From 87bd401138161008fdb82fbca6e213af117bfeb9 Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Fri, 5 May 2023 16:11:28 +0300 Subject: wifi: ath11k: EMA beacon support Add new function ath11k_mac_setup_bcn_tmpl_ema() which invokes the new API provided by MAC80211 to retrieve EMA beacons. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aloka Dixit Co-developed-by: John Crispin Signed-off-by: John Crispin Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230405221648.17950-8-quic_alokad@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 59 ++++++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/wmi.c | 3 +- drivers/net/wireless/ath/ath11k/wmi.h | 11 ++++++- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 3229f65fc6d2..a164b57dcf30 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1452,6 +1452,60 @@ static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, arvif->wpaie_present = false; } +static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif) +{ + struct ath11k_vif *tx_arvif; + struct ieee80211_ema_beacons *beacons; + int ret = 0; + bool nontx_vif_params_set = false; + u32 params = 0; + u8 i = 0; + + tx_arvif = (void *)arvif->vif->mbssid_tx_vif->drv_priv; + + beacons = ieee80211_beacon_get_template_ema_list(tx_arvif->ar->hw, + tx_arvif->vif, 0); + if (!beacons || !beacons->cnt) { + ath11k_warn(arvif->ar->ab, + "failed to get ema beacon templates from mac80211\n"); + return -EPERM; + } + + if (tx_arvif == arvif) + ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb); + else + arvif->wpaie_present = tx_arvif->wpaie_present; + + for (i = 0; i < beacons->cnt; i++) { + if (tx_arvif != arvif && !nontx_vif_params_set) + nontx_vif_params_set = + ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, + beacons->bcn[i].skb); + + params = beacons->cnt; + params |= (i << WMI_EMA_TMPL_IDX_SHIFT); + params |= ((!i ? 1 : 0) << WMI_EMA_FIRST_TMPL_SHIFT); + params |= ((i + 1 == beacons->cnt ? 1 : 0) << WMI_EMA_LAST_TMPL_SHIFT); + + ret = ath11k_wmi_bcn_tmpl(tx_arvif->ar, tx_arvif->vdev_id, + &beacons->bcn[i].offs, + beacons->bcn[i].skb, params); + if (ret) { + ath11k_warn(tx_arvif->ar->ab, + "failed to set ema beacon template id %i error %d\n", + i, ret); + break; + } + } + + ieee80211_beacon_free_ema_list(beacons); + + if (tx_arvif != arvif && !nontx_vif_params_set) + return -EINVAL; /* Profile not found in the beacons */ + + return ret; +} + static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif) { struct ath11k *ar = arvif->ar; @@ -1484,7 +1538,7 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif) else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) return -EINVAL; - ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); + ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, 0); kfree_skb(bcn); if (ret) @@ -1508,6 +1562,9 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) arvif != (void *)vif->mbssid_tx_vif->drv_priv && arvif->is_up) return 0; + if (vif->bss_conf.ema_ap && vif->mbssid_tx_vif) + return ath11k_mac_setup_bcn_tmpl_ema(arvif); + return ath11k_mac_setup_bcn_tmpl_mbssid(arvif); } diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 30364dfe12be..443199e85fa2 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1699,7 +1699,7 @@ int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, - struct sk_buff *bcn) + struct sk_buff *bcn, u32 ema_params) { struct ath11k_pdev_wmi *wmi = ar->wmi; struct wmi_bcn_tmpl_cmd *cmd; @@ -1738,6 +1738,7 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, cmd->buf_len = bcn->len; cmd->mbssid_ie_offset = offs->mbssid_off; + cmd->ema_params = ema_params; ptr = skb->data + sizeof(*cmd); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 55aceedc1795..43aaf55b7f2a 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -3566,6 +3566,10 @@ struct wmi_get_pdev_temperature_cmd { #define WMI_BEACON_TX_BUFFER_SIZE 512 +#define WMI_EMA_TMPL_IDX_SHIFT 8 +#define WMI_EMA_FIRST_TMPL_SHIFT 16 +#define WMI_EMA_LAST_TMPL_SHIFT 24 + struct wmi_bcn_tmpl_cmd { u32 tlv_header; u32 vdev_id; @@ -3576,6 +3580,11 @@ struct wmi_bcn_tmpl_cmd { u32 csa_event_bitmap; u32 mbssid_ie_offset; u32 esp_ie_offset; + u32 csc_switch_count_offset; + u32 csc_event_bitmap; + u32 mu_edca_ie_offset; + u32 feature_enable_bitmap; + u32 ema_params; } __packed; struct wmi_key_seq_counter { @@ -6298,7 +6307,7 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, struct sk_buff *frame); int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, - struct sk_buff *bcn); + struct sk_buff *bcn, u32 ema_param); int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id); int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid, u8 *tx_bssid, u32 nontx_profile_idx, -- cgit v1.2.3 From a731a43e8669a0b430c79a3e38890c27a5847a76 Mon Sep 17 00:00:00 2001 From: Yinjun Zhang Date: Tue, 9 May 2023 09:58:17 +0200 Subject: nfp: improve link modes reading process Avoid reading link modes from management firmware every time when `ethtool_get_link_ksettings` is called, only communicate with management firmware when necessary like we do for eth_table info. This change can ease the situation that when large number of vlan sub-interfaces are created and their information is requested by some monitoring process like PCP [1] through ethool ioctl frequently. [1] https://pcp.io Signed-off-by: Yinjun Zhang Acked-by: Simon Horman Signed-off-by: Louis Peens Reviewed-by: Leon Romanovsky Link: https://lore.kernel.org/r/20230509075817.10566-1-louis.peens@corigine.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/netronome/nfp/nfp_net_ethtool.c | 32 +++++-------- .../net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h | 7 ++- .../ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c | 54 +++++++++++----------- 3 files changed, 45 insertions(+), 48 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c index dfedb52b7e70..e75cbb287625 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c @@ -436,49 +436,41 @@ static void nfp_add_media_link_mode(struct nfp_port *port, struct nfp_eth_table_port *eth_port, struct ethtool_link_ksettings *cmd) { - u64 supported_modes[2], advertised_modes[2]; - struct nfp_eth_media_buf ethm = { - .eth_index = eth_port->eth_index, - }; - struct nfp_cpp *cpp = port->app->cpp; - - if (nfp_eth_read_media(cpp, ðm)) { - bitmap_fill(port->speed_bitmap, NFP_SUP_SPEED_NUMBER); - return; - } - bitmap_zero(port->speed_bitmap, NFP_SUP_SPEED_NUMBER); - for (u32 i = 0; i < 2; i++) { - supported_modes[i] = le64_to_cpu(ethm.supported_modes[i]); - advertised_modes[i] = le64_to_cpu(ethm.advertised_modes[i]); - } - for (u32 i = 0; i < NFP_MEDIA_LINK_MODES_NUMBER; i++) { if (i < 64) { - if (supported_modes[0] & BIT_ULL(i)) { + if (eth_port->link_modes_supp[0] & BIT_ULL(i)) { __set_bit(nfp_eth_media_table[i].ethtool_link_mode, cmd->link_modes.supported); __set_bit(nfp_eth_media_table[i].speed, port->speed_bitmap); } - if (advertised_modes[0] & BIT_ULL(i)) + if (eth_port->link_modes_ad[0] & BIT_ULL(i)) __set_bit(nfp_eth_media_table[i].ethtool_link_mode, cmd->link_modes.advertising); } else { - if (supported_modes[1] & BIT_ULL(i - 64)) { + if (eth_port->link_modes_supp[1] & BIT_ULL(i - 64)) { __set_bit(nfp_eth_media_table[i].ethtool_link_mode, cmd->link_modes.supported); __set_bit(nfp_eth_media_table[i].speed, port->speed_bitmap); } - if (advertised_modes[1] & BIT_ULL(i - 64)) + if (eth_port->link_modes_ad[1] & BIT_ULL(i - 64)) __set_bit(nfp_eth_media_table[i].ethtool_link_mode, cmd->link_modes.advertising); } } + + /* We take all speeds as supported when it fails to read + * link modes due to old management firmware that doesn't + * support link modes reading or error occurring, so that + * speed change of this port is allowed. + */ + if (bitmap_empty(port->speed_bitmap, NFP_SUP_SPEED_NUMBER)) + bitmap_fill(port->speed_bitmap, NFP_SUP_SPEED_NUMBER); } /** diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h index 781edc451bd4..6e044ac04917 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h @@ -196,6 +196,9 @@ enum nfp_ethtool_link_mode_list { * subports) * @ports.is_split: is interface part of a split port * @ports.fec_modes_supported: bitmap of FEC modes supported + * + * @ports.link_modes_supp: bitmap of link modes supported + * @ports.link_modes_ad: bitmap of link modes advertised */ struct nfp_eth_table { unsigned int count; @@ -235,6 +238,9 @@ struct nfp_eth_table { bool is_split; unsigned int fec_modes_supported; + + u64 link_modes_supp[2]; + u64 link_modes_ad[2]; } ports[]; }; @@ -313,7 +319,6 @@ struct nfp_eth_media_buf { }; int nfp_nsp_read_media(struct nfp_nsp *state, void *buf, unsigned int size); -int nfp_eth_read_media(struct nfp_cpp *cpp, struct nfp_eth_media_buf *ethm); #define NFP_NSP_VERSION_BUFSZ 1024 /* reasonable size, not in the ABI */ diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c index 570ac1bb2122..9d62085d772a 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c @@ -227,6 +227,30 @@ nfp_eth_calc_port_type(struct nfp_cpp *cpp, struct nfp_eth_table_port *entry) entry->port_type = PORT_DA; } +static void +nfp_eth_read_media(struct nfp_cpp *cpp, struct nfp_nsp *nsp, struct nfp_eth_table_port *entry) +{ + struct nfp_eth_media_buf ethm = { + .eth_index = entry->eth_index, + }; + unsigned int i; + int ret; + + if (!nfp_nsp_has_read_media(nsp)) + return; + + ret = nfp_nsp_read_media(nsp, ðm, sizeof(ethm)); + if (ret) { + nfp_err(cpp, "Reading media link modes failed: %d\n", ret); + return; + } + + for (i = 0; i < 2; i++) { + entry->link_modes_supp[i] = le64_to_cpu(ethm.supported_modes[i]); + entry->link_modes_ad[i] = le64_to_cpu(ethm.advertised_modes[i]); + } +} + /** * nfp_eth_read_ports() - retrieve port information * @cpp: NFP CPP handle @@ -293,8 +317,10 @@ __nfp_eth_read_ports(struct nfp_cpp *cpp, struct nfp_nsp *nsp) &table->ports[j++]); nfp_eth_calc_port_geometry(cpp, table); - for (i = 0; i < table->count; i++) + for (i = 0; i < table->count; i++) { nfp_eth_calc_port_type(cpp, &table->ports[i]); + nfp_eth_read_media(cpp, nsp, &table->ports[i]); + } kfree(entries); @@ -647,29 +673,3 @@ int __nfp_eth_set_split(struct nfp_nsp *nsp, unsigned int lanes) return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_PORT, NSP_ETH_PORT_LANES, lanes, NSP_ETH_CTRL_SET_LANES); } - -int nfp_eth_read_media(struct nfp_cpp *cpp, struct nfp_eth_media_buf *ethm) -{ - struct nfp_nsp *nsp; - int ret; - - nsp = nfp_nsp_open(cpp); - if (IS_ERR(nsp)) { - nfp_err(cpp, "Failed to access the NSP: %pe\n", nsp); - return PTR_ERR(nsp); - } - - if (!nfp_nsp_has_read_media(nsp)) { - nfp_warn(cpp, "Reading media link modes not supported. Please update flash\n"); - ret = -EOPNOTSUPP; - goto exit_close_nsp; - } - - ret = nfp_nsp_read_media(nsp, ethm, sizeof(*ethm)); - if (ret) - nfp_err(cpp, "Reading media link modes failed: %pe\n", ERR_PTR(ret)); - -exit_close_nsp: - nfp_nsp_close(nsp); - return ret; -} -- cgit v1.2.3 From 559ae55cfc334c91c62d2ea054a3345611363ee0 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Tue, 9 May 2023 09:12:07 +0200 Subject: net: skbuff: remove special handling for SLOB Commit c9929f0e344a ("mm/slob: remove CONFIG_SLOB") removes CONFIG_SLOB. Now, we can also remove special handling for socket buffers with the SLOB allocator. The code with HAVE_SKB_SMALL_HEAD_CACHE=1 is now the default behavior for all allocators. Remove an unnecessary distinction between SLOB and SLAB/SLUB allocator after the SLOB allocator is gone. Signed-off-by: Lukas Bulwahn Reviewed-by: Leon Romanovsky Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20230509071207.28942-1-lukas.bulwahn@gmail.com Signed-off-by: Jakub Kicinski --- net/core/skbuff.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 26a586007d8b..a82b33b1555e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -92,15 +92,7 @@ static struct kmem_cache *skbuff_fclone_cache __ro_after_init; static struct kmem_cache *skbuff_ext_cache __ro_after_init; #endif -/* skb_small_head_cache and related code is only supported - * for CONFIG_SLAB and CONFIG_SLUB. - * As soon as SLOB is removed from the kernel, we can clean up this. - */ -#if !defined(CONFIG_SLOB) -# define HAVE_SKB_SMALL_HEAD_CACHE 1 -#endif -#ifdef HAVE_SKB_SMALL_HEAD_CACHE static struct kmem_cache *skb_small_head_cache __ro_after_init; #define SKB_SMALL_HEAD_SIZE SKB_HEAD_ALIGN(MAX_TCP_HEADER) @@ -117,7 +109,6 @@ static struct kmem_cache *skb_small_head_cache __ro_after_init; #define SKB_SMALL_HEAD_HEADROOM \ SKB_WITH_OVERHEAD(SKB_SMALL_HEAD_CACHE_SIZE) -#endif /* HAVE_SKB_SMALL_HEAD_CACHE */ int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; EXPORT_SYMBOL(sysctl_max_skb_frags); @@ -562,7 +553,6 @@ static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node, void *obj; obj_size = SKB_HEAD_ALIGN(*size); -#ifdef HAVE_SKB_SMALL_HEAD_CACHE if (obj_size <= SKB_SMALL_HEAD_CACHE_SIZE && !(flags & KMALLOC_NOT_NORMAL_BITS)) { obj = kmem_cache_alloc_node(skb_small_head_cache, @@ -576,7 +566,6 @@ static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node, obj = kmem_cache_alloc_node(skb_small_head_cache, flags, node); goto out; } -#endif *size = obj_size = kmalloc_size_roundup(obj_size); /* * Try a regular allocation, when that fails and we're not entitled @@ -898,11 +887,9 @@ static bool skb_pp_recycle(struct sk_buff *skb, void *data, bool napi_safe) static void skb_kfree_head(void *head, unsigned int end_offset) { -#ifdef HAVE_SKB_SMALL_HEAD_CACHE if (end_offset == SKB_SMALL_HEAD_HEADROOM) kmem_cache_free(skb_small_head_cache, head); else -#endif kfree(head); } @@ -2160,7 +2147,6 @@ int __skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri) if (likely(skb_end_offset(skb) == saved_end_offset)) return 0; -#ifdef HAVE_SKB_SMALL_HEAD_CACHE /* We can not change skb->end if the original or new value * is SKB_SMALL_HEAD_HEADROOM, as it might break skb_kfree_head(). */ @@ -2174,7 +2160,6 @@ int __skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri) WARN_ON_ONCE(1); return 0; } -#endif shinfo = skb_shinfo(skb); @@ -4768,7 +4753,6 @@ void __init skb_init(void) 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -#ifdef HAVE_SKB_SMALL_HEAD_CACHE /* usercopy should only access first SKB_SMALL_HEAD_HEADROOM bytes. * struct skb_shared_info is located at the end of skb->head, * and should not be copied to/from user. @@ -4780,7 +4764,6 @@ void __init skb_init(void) 0, SKB_SMALL_HEAD_HEADROOM, NULL); -#endif skb_extensions_init(); } -- cgit v1.2.3 From 363d8ce4b94719a87dad865e2829f1dba0f7ef71 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:03 +0800 Subject: virtio_net: mergeable xdp: put old page immediately In the xdp implementation of virtio-net mergeable, it always checks whether two page is used and a page is selected to release. This is complicated for the processing of action, and be careful. In the entire process, we have such principles: * If xdp_page is used (PASS, TX, Redirect), then we release the old page. * If it is a drop case, we will release two. The old page obtained from buf is release inside err_xdp, and xdp_page needs be relased by us. But in fact, when we allocate a new page, we can release the old page immediately. Then just one is using, we just need to release the new page for drop case. On the drop path, err_xdp will release the variable "page", so we only need to let "page" point to the new xdp_page in advance. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a12ae26db0e2..e9ee4fd5fe5f 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1249,6 +1249,9 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, if (!xdp_page) goto err_xdp; offset = VIRTIO_XDP_HEADROOM; + + put_page(page); + page = xdp_page; } else if (unlikely(headroom < virtnet_get_headroom(vi))) { xdp_room = SKB_DATA_ALIGN(VIRTIO_XDP_HEADROOM + sizeof(struct skb_shared_info)); @@ -1263,11 +1266,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, page_address(page) + offset, len); frame_sz = PAGE_SIZE; offset = VIRTIO_XDP_HEADROOM; - } else { - xdp_page = page; + + put_page(page); + page = xdp_page; } - data = page_address(xdp_page) + offset; + data = page_address(page) + offset; err = virtnet_build_xdp_buff_mrg(dev, vi, rq, &xdp, data, len, frame_sz, &num_buf, &xdp_frags_truesz, stats); if (unlikely(err)) @@ -1282,8 +1286,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, if (unlikely(!head_skb)) goto err_xdp_frags; - if (unlikely(xdp_page != page)) - put_page(page); rcu_read_unlock(); return head_skb; case XDP_TX: @@ -1301,8 +1303,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, goto err_xdp_frags; } *xdp_xmit |= VIRTIO_XDP_TX; - if (unlikely(xdp_page != page)) - put_page(page); rcu_read_unlock(); goto xdp_xmit; case XDP_REDIRECT: @@ -1311,8 +1311,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, if (err) goto err_xdp_frags; *xdp_xmit |= VIRTIO_XDP_REDIR; - if (unlikely(xdp_page != page)) - put_page(page); rcu_read_unlock(); goto xdp_xmit; default: @@ -1325,9 +1323,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, goto err_xdp_frags; } err_xdp_frags: - if (unlikely(xdp_page != page)) - __free_pages(xdp_page, 0); - if (xdp_buff_has_frags(&xdp)) { shinfo = xdp_get_shared_info_from_buff(&xdp); for (i = 0; i < shinfo->nr_frags; i++) { -- cgit v1.2.3 From ad4858beb824aeba53deeae660ea7fab9e624bc0 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:04 +0800 Subject: virtio_net: introduce mergeable_xdp_get_buf() Separating the logic of preparation for xdp from receive_mergeable. The purpose of this is to simplify the logic of execution of XDP. The main logic here is that when headroom is insufficient, we need to allocate a new page and calculate offset. It should be noted that if there is new page, the variable page will refer to the new page. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 135 +++++++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 56 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index e9ee4fd5fe5f..a75745dfe2e1 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1166,6 +1166,81 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, return 0; } +static void *mergeable_xdp_get_buf(struct virtnet_info *vi, + struct receive_queue *rq, + struct bpf_prog *xdp_prog, + void *ctx, + unsigned int *frame_sz, + int *num_buf, + struct page **page, + int offset, + unsigned int *len, + struct virtio_net_hdr_mrg_rxbuf *hdr) +{ + unsigned int truesize = mergeable_ctx_to_truesize(ctx); + unsigned int headroom = mergeable_ctx_to_headroom(ctx); + struct page *xdp_page; + unsigned int xdp_room; + + /* Transient failure which in theory could occur if + * in-flight packets from before XDP was enabled reach + * the receive path after XDP is loaded. + */ + if (unlikely(hdr->hdr.gso_type)) + return NULL; + + /* Now XDP core assumes frag size is PAGE_SIZE, but buffers + * with headroom may add hole in truesize, which + * make their length exceed PAGE_SIZE. So we disabled the + * hole mechanism for xdp. See add_recvbuf_mergeable(). + */ + *frame_sz = truesize; + + /* This happens when headroom is not enough because + * of the buffer was prefilled before XDP is set. + * This should only happen for the first several packets. + * In fact, vq reset can be used here to help us clean up + * the prefilled buffers, but many existing devices do not + * support it, and we don't want to bother users who are + * using xdp normally. + */ + if (!xdp_prog->aux->xdp_has_frags && + (*num_buf > 1 || headroom < virtnet_get_headroom(vi))) { + /* linearize data for XDP */ + xdp_page = xdp_linearize_page(rq, num_buf, + *page, offset, + VIRTIO_XDP_HEADROOM, + len); + *frame_sz = PAGE_SIZE; + + if (!xdp_page) + return NULL; + offset = VIRTIO_XDP_HEADROOM; + + put_page(*page); + *page = xdp_page; + } else if (unlikely(headroom < virtnet_get_headroom(vi))) { + xdp_room = SKB_DATA_ALIGN(VIRTIO_XDP_HEADROOM + + sizeof(struct skb_shared_info)); + if (*len + xdp_room > PAGE_SIZE) + return NULL; + + xdp_page = alloc_page(GFP_ATOMIC); + if (!xdp_page) + return NULL; + + memcpy(page_address(xdp_page) + VIRTIO_XDP_HEADROOM, + page_address(*page) + offset, *len); + *frame_sz = PAGE_SIZE; + offset = VIRTIO_XDP_HEADROOM; + + put_page(*page); + *page = xdp_page; + } + + return page_address(*page) + offset; +} + static struct sk_buff *receive_mergeable(struct net_device *dev, struct virtnet_info *vi, struct receive_queue *rq, @@ -1185,7 +1260,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, unsigned int headroom = mergeable_ctx_to_headroom(ctx); unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; unsigned int room = SKB_DATA_ALIGN(headroom + tailroom); - unsigned int frame_sz, xdp_room; + unsigned int frame_sz; int err; head_skb = NULL; @@ -1215,63 +1290,11 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, u32 act; int i; - /* Transient failure which in theory could occur if - * in-flight packets from before XDP was enabled reach - * the receive path after XDP is loaded. - */ - if (unlikely(hdr->hdr.gso_type)) + data = mergeable_xdp_get_buf(vi, rq, xdp_prog, ctx, &frame_sz, + &num_buf, &page, offset, &len, hdr); + if (unlikely(!data)) goto err_xdp; - /* Now XDP core assumes frag size is PAGE_SIZE, but buffers - * with headroom may add hole in truesize, which - * make their length exceed PAGE_SIZE. So we disabled the - * hole mechanism for xdp. See add_recvbuf_mergeable(). - */ - frame_sz = truesize; - - /* This happens when headroom is not enough because - * of the buffer was prefilled before XDP is set. - * This should only happen for the first several packets. - * In fact, vq reset can be used here to help us clean up - * the prefilled buffers, but many existing devices do not - * support it, and we don't want to bother users who are - * using xdp normally. - */ - if (!xdp_prog->aux->xdp_has_frags && - (num_buf > 1 || headroom < virtnet_get_headroom(vi))) { - /* linearize data for XDP */ - xdp_page = xdp_linearize_page(rq, &num_buf, - page, offset, - VIRTIO_XDP_HEADROOM, - &len); - frame_sz = PAGE_SIZE; - - if (!xdp_page) - goto err_xdp; - offset = VIRTIO_XDP_HEADROOM; - - put_page(page); - page = xdp_page; - } else if (unlikely(headroom < virtnet_get_headroom(vi))) { - xdp_room = SKB_DATA_ALIGN(VIRTIO_XDP_HEADROOM + - sizeof(struct skb_shared_info)); - if (len + xdp_room > PAGE_SIZE) - goto err_xdp; - - xdp_page = alloc_page(GFP_ATOMIC); - if (!xdp_page) - goto err_xdp; - - memcpy(page_address(xdp_page) + VIRTIO_XDP_HEADROOM, - page_address(page) + offset, len); - frame_sz = PAGE_SIZE; - offset = VIRTIO_XDP_HEADROOM; - - put_page(page); - page = xdp_page; - } - - data = page_address(page) + offset; err = virtnet_build_xdp_buff_mrg(dev, vi, rq, &xdp, data, len, frame_sz, &num_buf, &xdp_frags_truesz, stats); if (unlikely(err)) -- cgit v1.2.3 From dbe4fec2447dd215964aad88b0e06f96c6958ee9 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:05 +0800 Subject: virtio_net: optimize mergeable_xdp_get_buf() The previous patch, in order to facilitate review, I do not do any modification. This patch has made some optimization on the top. * remove some repeated logics in this function. * add fast check for passing without any alloc. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a75745dfe2e1..3c3602982ea2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1196,6 +1196,11 @@ static void *mergeable_xdp_get_buf(struct virtnet_info *vi, */ *frame_sz = truesize; + if (likely(headroom >= virtnet_get_headroom(vi) && + (*num_buf == 1 || xdp_prog->aux->xdp_has_frags))) { + return page_address(*page) + offset; + } + /* This happens when headroom is not enough because * of the buffer was prefilled before XDP is set. * This should only happen for the first several packets. @@ -1204,22 +1209,15 @@ static void *mergeable_xdp_get_buf(struct virtnet_info *vi, * support it, and we don't want to bother users who are * using xdp normally. */ - if (!xdp_prog->aux->xdp_has_frags && - (*num_buf > 1 || headroom < virtnet_get_headroom(vi))) { + if (!xdp_prog->aux->xdp_has_frags) { /* linearize data for XDP */ xdp_page = xdp_linearize_page(rq, num_buf, *page, offset, VIRTIO_XDP_HEADROOM, len); - *frame_sz = PAGE_SIZE; - if (!xdp_page) return NULL; - offset = VIRTIO_XDP_HEADROOM; - - put_page(*page); - *page = xdp_page; - } else if (unlikely(headroom < virtnet_get_headroom(vi))) { + } else { xdp_room = SKB_DATA_ALIGN(VIRTIO_XDP_HEADROOM + sizeof(struct skb_shared_info)); if (*len + xdp_room > PAGE_SIZE) @@ -1231,14 +1229,15 @@ static void *mergeable_xdp_get_buf(struct virtnet_info *vi, memcpy(page_address(xdp_page) + VIRTIO_XDP_HEADROOM, page_address(*page) + offset, *len); - *frame_sz = PAGE_SIZE; - offset = VIRTIO_XDP_HEADROOM; - - put_page(*page); - *page = xdp_page; } - return page_address(*page) + offset; + *frame_sz = PAGE_SIZE; + + put_page(*page); + + *page = xdp_page; + + return page_address(*page) + VIRTIO_XDP_HEADROOM; } static struct sk_buff *receive_mergeable(struct net_device *dev, -- cgit v1.2.3 From 00765f8ed74240419091a1708c195405b55fe243 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:06 +0800 Subject: virtio_net: introduce virtnet_xdp_handler() to seprate the logic of run xdp At present, we have two similar logic to perform the XDP prog. Therefore, this patch separates the code of executing XDP, which is conducive to later maintenance. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 118 +++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 3c3602982ea2..9334350d8025 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -789,6 +789,60 @@ out: return ret; } +static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp, + struct net_device *dev, + unsigned int *xdp_xmit, + struct virtnet_rq_stats *stats) +{ + struct xdp_frame *xdpf; + int err; + u32 act; + + act = bpf_prog_run_xdp(xdp_prog, xdp); + stats->xdp_packets++; + + switch (act) { + case XDP_PASS: + return act; + + case XDP_TX: + stats->xdp_tx++; + xdpf = xdp_convert_buff_to_frame(xdp); + if (unlikely(!xdpf)) { + netdev_dbg(dev, "convert buff to frame failed for xdp\n"); + return XDP_DROP; + } + + err = virtnet_xdp_xmit(dev, 1, &xdpf, 0); + if (unlikely(!err)) { + xdp_return_frame_rx_napi(xdpf); + } else if (unlikely(err < 0)) { + trace_xdp_exception(dev, xdp_prog, act); + return XDP_DROP; + } + *xdp_xmit |= VIRTIO_XDP_TX; + return act; + + case XDP_REDIRECT: + stats->xdp_redirects++; + err = xdp_do_redirect(dev, xdp, xdp_prog); + if (err) + return XDP_DROP; + + *xdp_xmit |= VIRTIO_XDP_REDIR; + return act; + + default: + bpf_warn_invalid_xdp_action(dev, xdp_prog, act); + fallthrough; + case XDP_ABORTED: + trace_xdp_exception(dev, xdp_prog, act); + fallthrough; + case XDP_DROP: + return XDP_DROP; + } +} + static unsigned int virtnet_get_headroom(struct virtnet_info *vi) { return vi->xdp_enabled ? VIRTIO_XDP_HEADROOM : 0; @@ -880,7 +934,6 @@ static struct sk_buff *receive_small(struct net_device *dev, struct page *page = virt_to_head_page(buf); unsigned int delta = 0; struct page *xdp_page; - int err; unsigned int metasize = 0; len -= vi->hdr_len; @@ -902,7 +955,6 @@ static struct sk_buff *receive_small(struct net_device *dev, xdp_prog = rcu_dereference(rq->xdp_prog); if (xdp_prog) { struct virtio_net_hdr_mrg_rxbuf *hdr = buf + header_offset; - struct xdp_frame *xdpf; struct xdp_buff xdp; void *orig_data; u32 act; @@ -935,8 +987,8 @@ static struct sk_buff *receive_small(struct net_device *dev, xdp_prepare_buff(&xdp, buf + VIRTNET_RX_PAD + vi->hdr_len, xdp_headroom, len, true); orig_data = xdp.data; - act = bpf_prog_run_xdp(xdp_prog, &xdp); - stats->xdp_packets++; + + act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats); switch (act) { case XDP_PASS: @@ -946,35 +998,10 @@ static struct sk_buff *receive_small(struct net_device *dev, metasize = xdp.data - xdp.data_meta; break; case XDP_TX: - stats->xdp_tx++; - xdpf = xdp_convert_buff_to_frame(&xdp); - if (unlikely(!xdpf)) - goto err_xdp; - err = virtnet_xdp_xmit(dev, 1, &xdpf, 0); - if (unlikely(!err)) { - xdp_return_frame_rx_napi(xdpf); - } else if (unlikely(err < 0)) { - trace_xdp_exception(vi->dev, xdp_prog, act); - goto err_xdp; - } - *xdp_xmit |= VIRTIO_XDP_TX; - rcu_read_unlock(); - goto xdp_xmit; case XDP_REDIRECT: - stats->xdp_redirects++; - err = xdp_do_redirect(dev, &xdp, xdp_prog); - if (err) - goto err_xdp; - *xdp_xmit |= VIRTIO_XDP_REDIR; rcu_read_unlock(); goto xdp_xmit; default: - bpf_warn_invalid_xdp_action(vi->dev, xdp_prog, act); - fallthrough; - case XDP_ABORTED: - trace_xdp_exception(vi->dev, xdp_prog, act); - goto err_xdp; - case XDP_DROP: goto err_xdp; } } @@ -1282,7 +1309,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, if (xdp_prog) { unsigned int xdp_frags_truesz = 0; struct skb_shared_info *shinfo; - struct xdp_frame *xdpf; struct page *xdp_page; struct xdp_buff xdp; void *data; @@ -1299,8 +1325,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, if (unlikely(err)) goto err_xdp_frags; - act = bpf_prog_run_xdp(xdp_prog, &xdp); - stats->xdp_packets++; + act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats); switch (act) { case XDP_PASS: @@ -1311,38 +1336,11 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, rcu_read_unlock(); return head_skb; case XDP_TX: - stats->xdp_tx++; - xdpf = xdp_convert_buff_to_frame(&xdp); - if (unlikely(!xdpf)) { - netdev_dbg(dev, "convert buff to frame failed for xdp\n"); - goto err_xdp_frags; - } - err = virtnet_xdp_xmit(dev, 1, &xdpf, 0); - if (unlikely(!err)) { - xdp_return_frame_rx_napi(xdpf); - } else if (unlikely(err < 0)) { - trace_xdp_exception(vi->dev, xdp_prog, act); - goto err_xdp_frags; - } - *xdp_xmit |= VIRTIO_XDP_TX; - rcu_read_unlock(); - goto xdp_xmit; case XDP_REDIRECT: - stats->xdp_redirects++; - err = xdp_do_redirect(dev, &xdp, xdp_prog); - if (err) - goto err_xdp_frags; - *xdp_xmit |= VIRTIO_XDP_REDIR; rcu_read_unlock(); goto xdp_xmit; default: - bpf_warn_invalid_xdp_action(vi->dev, xdp_prog, act); - fallthrough; - case XDP_ABORTED: - trace_xdp_exception(vi->dev, xdp_prog, act); - fallthrough; - case XDP_DROP: - goto err_xdp_frags; + break; } err_xdp_frags: if (xdp_buff_has_frags(&xdp)) { -- cgit v1.2.3 From bb2c1e9e75be4a059fa795aac58b805091c9dae7 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:07 +0800 Subject: virtio_net: separate the logic of freeing xdp shinfo This patch introduce a new function that releases the xdp shinfo. The subsequent patch will reuse this function. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9334350d8025..c1538ab46795 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -789,6 +789,21 @@ out: return ret; } +static void put_xdp_frags(struct xdp_buff *xdp) +{ + struct skb_shared_info *shinfo; + struct page *xdp_page; + int i; + + if (xdp_buff_has_frags(xdp)) { + shinfo = xdp_get_shared_info_from_buff(xdp); + for (i = 0; i < shinfo->nr_frags; i++) { + xdp_page = skb_frag_page(&shinfo->frags[i]); + put_page(xdp_page); + } + } +} + static int virtnet_xdp_handler(struct bpf_prog *xdp_prog, struct xdp_buff *xdp, struct net_device *dev, unsigned int *xdp_xmit, @@ -1308,12 +1323,9 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, xdp_prog = rcu_dereference(rq->xdp_prog); if (xdp_prog) { unsigned int xdp_frags_truesz = 0; - struct skb_shared_info *shinfo; - struct page *xdp_page; struct xdp_buff xdp; void *data; u32 act; - int i; data = mergeable_xdp_get_buf(vi, rq, xdp_prog, ctx, &frame_sz, &num_buf, &page, offset, &len, hdr); @@ -1343,14 +1355,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, break; } err_xdp_frags: - if (xdp_buff_has_frags(&xdp)) { - shinfo = xdp_get_shared_info_from_buff(&xdp); - for (i = 0; i < shinfo->nr_frags; i++) { - xdp_page = skb_frag_page(&shinfo->frags[i]); - put_page(xdp_page); - } - } - + put_xdp_frags(&xdp); goto err_xdp; } rcu_read_unlock(); -- cgit v1.2.3 From 80f50f918c6e2d3f46aae717e6b04271298ab1c0 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:08 +0800 Subject: virtio_net: separate the logic of freeing the rest mergeable buf This patch introduce a new function that frees the rest mergeable buf. The subsequent patch will reuse this function. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index c1538ab46795..b26e95c96141 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1071,6 +1071,28 @@ err: return NULL; } +static void mergeable_buf_free(struct receive_queue *rq, int num_buf, + struct net_device *dev, + struct virtnet_rq_stats *stats) +{ + struct page *page; + void *buf; + int len; + + while (num_buf-- > 1) { + buf = virtqueue_get_buf(rq->vq, &len); + if (unlikely(!buf)) { + pr_debug("%s: rx error: %d buffers missing\n", + dev->name, num_buf); + dev->stats.rx_length_errors++; + break; + } + stats->bytes += len; + page = virt_to_head_page(buf); + put_page(page); + } +} + /* Why not use xdp_build_skb_from_frame() ? * XDP core assumes that xdp frags are PAGE_SIZE in length, while in * virtio-net there are 2 points that do not match its requirements: @@ -1431,18 +1453,8 @@ err_xdp: stats->xdp_drops++; err_skb: put_page(page); - while (num_buf-- > 1) { - buf = virtqueue_get_buf(rq->vq, &len); - if (unlikely(!buf)) { - pr_debug("%s: rx error: %d buffers missing\n", - dev->name, num_buf); - dev->stats.rx_length_errors++; - break; - } - stats->bytes += len; - page = virt_to_head_page(buf); - put_page(page); - } + mergeable_buf_free(rq, num_buf, dev, stats); + err_buf: stats->drops++; dev_kfree_skb(head_skb); -- cgit v1.2.3 From 4cb00b13c064088352a4f2ca4a8279010ad218a8 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:09 +0800 Subject: virtio_net: virtnet_build_xdp_buff_mrg() auto release xdp shinfo virtnet_build_xdp_buff_mrg() auto release xdp shinfo then the caller no need to careful the xdp shinfo. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b26e95c96141..2d1329c32751 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1194,7 +1194,7 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, dev->name, *num_buf, virtio16_to_cpu(vi->vdev, hdr->num_buffers)); dev->stats.rx_length_errors++; - return -EINVAL; + goto err; } stats->bytes += len; @@ -1213,7 +1213,7 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, pr_debug("%s: rx error: len %u exceeds truesize %lu\n", dev->name, len, (unsigned long)(truesize - room)); dev->stats.rx_length_errors++; - return -EINVAL; + goto err; } frag = &shinfo->frags[shinfo->nr_frags++]; @@ -1228,6 +1228,10 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, *xdp_frags_truesize = xdp_frags_truesz; return 0; + +err: + put_xdp_frags(xdp); + return -EINVAL; } static void *mergeable_xdp_get_buf(struct virtnet_info *vi, @@ -1357,7 +1361,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, err = virtnet_build_xdp_buff_mrg(dev, vi, rq, &xdp, data, len, frame_sz, &num_buf, &xdp_frags_truesz, stats); if (unlikely(err)) - goto err_xdp_frags; + goto err_xdp; act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats); -- cgit v1.2.3 From d8f2835a4746f26523cb512dc17e2b0a00dd31a9 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:10 +0800 Subject: virtio_net: introduce receive_mergeable_xdp() The purpose of this patch is to simplify the receive_mergeable(). Separate all the logic of XDP into a function. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 105 +++++++++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 2d1329c32751..2bb759deb658 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1308,6 +1308,66 @@ static void *mergeable_xdp_get_buf(struct virtnet_info *vi, return page_address(*page) + VIRTIO_XDP_HEADROOM; } +static struct sk_buff *receive_mergeable_xdp(struct net_device *dev, + struct virtnet_info *vi, + struct receive_queue *rq, + struct bpf_prog *xdp_prog, + void *buf, + void *ctx, + unsigned int len, + unsigned int *xdp_xmit, + struct virtnet_rq_stats *stats) +{ + struct virtio_net_hdr_mrg_rxbuf *hdr = buf; + int num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers); + struct page *page = virt_to_head_page(buf); + int offset = buf - page_address(page); + unsigned int xdp_frags_truesz = 0; + struct sk_buff *head_skb; + unsigned int frame_sz; + struct xdp_buff xdp; + void *data; + u32 act; + int err; + + data = mergeable_xdp_get_buf(vi, rq, xdp_prog, ctx, &frame_sz, &num_buf, &page, + offset, &len, hdr); + if (unlikely(!data)) + goto err_xdp; + + err = virtnet_build_xdp_buff_mrg(dev, vi, rq, &xdp, data, len, frame_sz, + &num_buf, &xdp_frags_truesz, stats); + if (unlikely(err)) + goto err_xdp; + + act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats); + + switch (act) { + case XDP_PASS: + head_skb = build_skb_from_xdp_buff(dev, vi, &xdp, xdp_frags_truesz); + if (unlikely(!head_skb)) + break; + return head_skb; + + case XDP_TX: + case XDP_REDIRECT: + return NULL; + + default: + break; + } + + put_xdp_frags(&xdp); + +err_xdp: + put_page(page); + mergeable_buf_free(rq, num_buf, dev, stats); + + stats->xdp_drops++; + stats->drops++; + return NULL; +} + static struct sk_buff *receive_mergeable(struct net_device *dev, struct virtnet_info *vi, struct receive_queue *rq, @@ -1327,8 +1387,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, unsigned int headroom = mergeable_ctx_to_headroom(ctx); unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; unsigned int room = SKB_DATA_ALIGN(headroom + tailroom); - unsigned int frame_sz; - int err; head_skb = NULL; stats->bytes += len - vi->hdr_len; @@ -1348,41 +1406,10 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, rcu_read_lock(); xdp_prog = rcu_dereference(rq->xdp_prog); if (xdp_prog) { - unsigned int xdp_frags_truesz = 0; - struct xdp_buff xdp; - void *data; - u32 act; - - data = mergeable_xdp_get_buf(vi, rq, xdp_prog, ctx, &frame_sz, - &num_buf, &page, offset, &len, hdr); - if (unlikely(!data)) - goto err_xdp; - - err = virtnet_build_xdp_buff_mrg(dev, vi, rq, &xdp, data, len, frame_sz, - &num_buf, &xdp_frags_truesz, stats); - if (unlikely(err)) - goto err_xdp; - - act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats); - - switch (act) { - case XDP_PASS: - head_skb = build_skb_from_xdp_buff(dev, vi, &xdp, xdp_frags_truesz); - if (unlikely(!head_skb)) - goto err_xdp_frags; - - rcu_read_unlock(); - return head_skb; - case XDP_TX: - case XDP_REDIRECT: - rcu_read_unlock(); - goto xdp_xmit; - default: - break; - } -err_xdp_frags: - put_xdp_frags(&xdp); - goto err_xdp; + head_skb = receive_mergeable_xdp(dev, vi, rq, xdp_prog, buf, ctx, + len, xdp_xmit, stats); + rcu_read_unlock(); + return head_skb; } rcu_read_unlock(); @@ -1452,9 +1479,6 @@ skip_xdp: ewma_pkt_len_add(&rq->mrg_avg_pkt_len, head_skb->len); return head_skb; -err_xdp: - rcu_read_unlock(); - stats->xdp_drops++; err_skb: put_page(page); mergeable_buf_free(rq, num_buf, dev, stats); @@ -1462,7 +1486,6 @@ err_skb: err_buf: stats->drops++; dev_kfree_skb(head_skb); -xdp_xmit: return NULL; } -- cgit v1.2.3 From 59ba3b1a88a8251d8fd0ef847afb59aa83a47126 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:11 +0800 Subject: virtio_net: merge: remove skip_xdp Now, the logic of merge xdp process is simple, we can remove the skip_xdp. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 2bb759deb658..0baa6651dbb0 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1382,7 +1382,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, struct page *page = virt_to_head_page(buf); int offset = buf - page_address(page); struct sk_buff *head_skb, *curr_skb; - struct bpf_prog *xdp_prog; unsigned int truesize = mergeable_ctx_to_truesize(ctx); unsigned int headroom = mergeable_ctx_to_headroom(ctx); unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0; @@ -1398,22 +1397,20 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, goto err_skb; } - if (likely(!vi->xdp_enabled)) { - xdp_prog = NULL; - goto skip_xdp; - } + if (unlikely(vi->xdp_enabled)) { + struct bpf_prog *xdp_prog; - rcu_read_lock(); - xdp_prog = rcu_dereference(rq->xdp_prog); - if (xdp_prog) { - head_skb = receive_mergeable_xdp(dev, vi, rq, xdp_prog, buf, ctx, - len, xdp_xmit, stats); + rcu_read_lock(); + xdp_prog = rcu_dereference(rq->xdp_prog); + if (xdp_prog) { + head_skb = receive_mergeable_xdp(dev, vi, rq, xdp_prog, buf, ctx, + len, xdp_xmit, stats); + rcu_read_unlock(); + return head_skb; + } rcu_read_unlock(); - return head_skb; } - rcu_read_unlock(); -skip_xdp: head_skb = page_to_skb(vi, rq, page, offset, len, truesize, headroom); curr_skb = head_skb; -- cgit v1.2.3 From c5f3e72f04c02cc2a0671adbb16224e61dc4bd8a Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:12 +0800 Subject: virtio_net: introduce receive_small_xdp() The purpose of this patch is to simplify the receive_small(). Separate all the logic of XDP of small into a function. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 165 ++++++++++++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 65 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 0baa6651dbb0..bc3bf190e614 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -931,6 +931,99 @@ err_buf: return NULL; } +static struct sk_buff *receive_small_xdp(struct net_device *dev, + struct virtnet_info *vi, + struct receive_queue *rq, + struct bpf_prog *xdp_prog, + void *buf, + unsigned int xdp_headroom, + unsigned int len, + unsigned int *xdp_xmit, + struct virtnet_rq_stats *stats) +{ + unsigned int header_offset = VIRTNET_RX_PAD + xdp_headroom; + unsigned int headroom = vi->hdr_len + header_offset; + struct virtio_net_hdr_mrg_rxbuf *hdr = buf + header_offset; + struct page *page = virt_to_head_page(buf); + struct page *xdp_page; + unsigned int buflen; + struct xdp_buff xdp; + struct sk_buff *skb; + unsigned int delta = 0; + unsigned int metasize = 0; + void *orig_data; + u32 act; + + if (unlikely(hdr->hdr.gso_type)) + goto err_xdp; + + buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) { + int offset = buf - page_address(page) + header_offset; + unsigned int tlen = len + vi->hdr_len; + int num_buf = 1; + + xdp_headroom = virtnet_get_headroom(vi); + header_offset = VIRTNET_RX_PAD + xdp_headroom; + headroom = vi->hdr_len + header_offset; + buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + xdp_page = xdp_linearize_page(rq, &num_buf, page, + offset, header_offset, + &tlen); + if (!xdp_page) + goto err_xdp; + + buf = page_address(xdp_page); + put_page(page); + page = xdp_page; + } + + xdp_init_buff(&xdp, buflen, &rq->xdp_rxq); + xdp_prepare_buff(&xdp, buf + VIRTNET_RX_PAD + vi->hdr_len, + xdp_headroom, len, true); + orig_data = xdp.data; + + act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats); + + switch (act) { + case XDP_PASS: + /* Recalculate length in case bpf program changed it */ + delta = orig_data - xdp.data; + len = xdp.data_end - xdp.data; + metasize = xdp.data - xdp.data_meta; + break; + + case XDP_TX: + case XDP_REDIRECT: + goto xdp_xmit; + + default: + goto err_xdp; + } + + skb = build_skb(buf, buflen); + if (!skb) + goto err; + + skb_reserve(skb, headroom - delta); + skb_put(skb, len); + if (metasize) + skb_metadata_set(skb, metasize); + + return skb; + +err_xdp: + stats->xdp_drops++; +err: + stats->drops++; + put_page(page); +xdp_xmit: + return NULL; +} + static struct sk_buff *receive_small(struct net_device *dev, struct virtnet_info *vi, struct receive_queue *rq, @@ -947,9 +1040,6 @@ static struct sk_buff *receive_small(struct net_device *dev, unsigned int buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); struct page *page = virt_to_head_page(buf); - unsigned int delta = 0; - struct page *xdp_page; - unsigned int metasize = 0; len -= vi->hdr_len; stats->bytes += len; @@ -969,56 +1059,10 @@ static struct sk_buff *receive_small(struct net_device *dev, rcu_read_lock(); xdp_prog = rcu_dereference(rq->xdp_prog); if (xdp_prog) { - struct virtio_net_hdr_mrg_rxbuf *hdr = buf + header_offset; - struct xdp_buff xdp; - void *orig_data; - u32 act; - - if (unlikely(hdr->hdr.gso_type)) - goto err_xdp; - - if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) { - int offset = buf - page_address(page) + header_offset; - unsigned int tlen = len + vi->hdr_len; - int num_buf = 1; - - xdp_headroom = virtnet_get_headroom(vi); - header_offset = VIRTNET_RX_PAD + xdp_headroom; - headroom = vi->hdr_len + header_offset; - buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - xdp_page = xdp_linearize_page(rq, &num_buf, page, - offset, header_offset, - &tlen); - if (!xdp_page) - goto err_xdp; - - buf = page_address(xdp_page); - put_page(page); - page = xdp_page; - } - - xdp_init_buff(&xdp, buflen, &rq->xdp_rxq); - xdp_prepare_buff(&xdp, buf + VIRTNET_RX_PAD + vi->hdr_len, - xdp_headroom, len, true); - orig_data = xdp.data; - - act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats); - - switch (act) { - case XDP_PASS: - /* Recalculate length in case bpf program changed it */ - delta = orig_data - xdp.data; - len = xdp.data_end - xdp.data; - metasize = xdp.data - xdp.data_meta; - break; - case XDP_TX: - case XDP_REDIRECT: - rcu_read_unlock(); - goto xdp_xmit; - default: - goto err_xdp; - } + skb = receive_small_xdp(dev, vi, rq, xdp_prog, buf, xdp_headroom, + len, xdp_xmit, stats); + rcu_read_unlock(); + return skb; } rcu_read_unlock(); @@ -1026,25 +1070,16 @@ skip_xdp: skb = build_skb(buf, buflen); if (!skb) goto err; - skb_reserve(skb, headroom - delta); + skb_reserve(skb, headroom); skb_put(skb, len); - if (!xdp_prog) { - buf += header_offset; - memcpy(skb_vnet_hdr(skb), buf, vi->hdr_len); - } /* keep zeroed vnet hdr since XDP is loaded */ - - if (metasize) - skb_metadata_set(skb, metasize); + buf += header_offset; + memcpy(skb_vnet_hdr(skb), buf, vi->hdr_len); return skb; -err_xdp: - rcu_read_unlock(); - stats->xdp_drops++; err: stats->drops++; put_page(page); -xdp_xmit: return NULL; } -- cgit v1.2.3 From fc8ce84b09bcc7306f3128f783967ecbfa617207 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:13 +0800 Subject: virtio_net: small: remove the delta In the case of XDP-PASS, skb_reserve uses the "delta" to compatible non-XDP, now that is not shared between xdp and non-xdp, so we can remove this logic. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index bc3bf190e614..abf4ddcb686e 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -949,9 +949,7 @@ static struct sk_buff *receive_small_xdp(struct net_device *dev, unsigned int buflen; struct xdp_buff xdp; struct sk_buff *skb; - unsigned int delta = 0; unsigned int metasize = 0; - void *orig_data; u32 act; if (unlikely(hdr->hdr.gso_type)) @@ -984,14 +982,12 @@ static struct sk_buff *receive_small_xdp(struct net_device *dev, xdp_init_buff(&xdp, buflen, &rq->xdp_rxq); xdp_prepare_buff(&xdp, buf + VIRTNET_RX_PAD + vi->hdr_len, xdp_headroom, len, true); - orig_data = xdp.data; act = virtnet_xdp_handler(xdp_prog, &xdp, dev, xdp_xmit, stats); switch (act) { case XDP_PASS: /* Recalculate length in case bpf program changed it */ - delta = orig_data - xdp.data; len = xdp.data_end - xdp.data; metasize = xdp.data - xdp.data_meta; break; @@ -1008,7 +1004,7 @@ static struct sk_buff *receive_small_xdp(struct net_device *dev, if (!skb) goto err; - skb_reserve(skb, headroom - delta); + skb_reserve(skb, xdp.data - buf); skb_put(skb, len); if (metasize) skb_metadata_set(skb, metasize); -- cgit v1.2.3 From 7af70fc169bd254aea780115b0f355956f84902b Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:14 +0800 Subject: virtio_net: small: avoid code duplication in xdp scenarios Avoid the problem that some variables(headroom and so on) will repeat the calculation when process xdp. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index abf4ddcb686e..b26d907b5ba5 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1031,11 +1031,10 @@ static struct sk_buff *receive_small(struct net_device *dev, struct sk_buff *skb; struct bpf_prog *xdp_prog; unsigned int xdp_headroom = (unsigned long)ctx; - unsigned int header_offset = VIRTNET_RX_PAD + xdp_headroom; - unsigned int headroom = vi->hdr_len + header_offset; - unsigned int buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); struct page *page = virt_to_head_page(buf); + unsigned int header_offset; + unsigned int headroom; + unsigned int buflen; len -= vi->hdr_len; stats->bytes += len; @@ -1063,6 +1062,11 @@ static struct sk_buff *receive_small(struct net_device *dev, rcu_read_unlock(); skip_xdp: + header_offset = VIRTNET_RX_PAD + xdp_headroom; + headroom = vi->hdr_len + header_offset; + buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + skb = build_skb(buf, buflen); if (!skb) goto err; -- cgit v1.2.3 From aef76506bc64bbf567490cbe437c26f1aadeee90 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:15 +0800 Subject: virtio_net: small: remove skip_xdp Because the skb build code is not shared between xdp and non-xdp, and the xdp code in receive_small() is simpler, so "skip_xdp" is not needed. We can remove it. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b26d907b5ba5..a0a4f35b965b 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1028,13 +1028,12 @@ static struct sk_buff *receive_small(struct net_device *dev, unsigned int *xdp_xmit, struct virtnet_rq_stats *stats) { - struct sk_buff *skb; - struct bpf_prog *xdp_prog; unsigned int xdp_headroom = (unsigned long)ctx; struct page *page = virt_to_head_page(buf); unsigned int header_offset; unsigned int headroom; unsigned int buflen; + struct sk_buff *skb; len -= vi->hdr_len; stats->bytes += len; @@ -1046,22 +1045,21 @@ static struct sk_buff *receive_small(struct net_device *dev, goto err; } - if (likely(!vi->xdp_enabled)) { - xdp_prog = NULL; - goto skip_xdp; - } + if (unlikely(vi->xdp_enabled)) { + struct bpf_prog *xdp_prog; - rcu_read_lock(); - xdp_prog = rcu_dereference(rq->xdp_prog); - if (xdp_prog) { - skb = receive_small_xdp(dev, vi, rq, xdp_prog, buf, xdp_headroom, - len, xdp_xmit, stats); + rcu_read_lock(); + xdp_prog = rcu_dereference(rq->xdp_prog); + if (xdp_prog) { + skb = receive_small_xdp(dev, vi, rq, xdp_prog, buf, + xdp_headroom, len, xdp_xmit, + stats); + rcu_read_unlock(); + return skb; + } rcu_read_unlock(); - return skb; } - rcu_read_unlock(); -skip_xdp: header_offset = VIRTNET_RX_PAD + xdp_headroom; headroom = vi->hdr_len + header_offset; buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + -- cgit v1.2.3 From 19e8c85e336d17ae43cf730590fe6337ea238af0 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:16 +0800 Subject: virtio_net: introduce receive_small_build_xdp Simplifying receive_small() function. Bringing the logic relating to build_skb together. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index a0a4f35b965b..37287ede1959 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -931,6 +931,34 @@ err_buf: return NULL; } +static struct sk_buff *receive_small_build_skb(struct virtnet_info *vi, + unsigned int xdp_headroom, + void *buf, + unsigned int len) +{ + unsigned int header_offset; + unsigned int headroom; + unsigned int buflen; + struct sk_buff *skb; + + header_offset = VIRTNET_RX_PAD + xdp_headroom; + headroom = vi->hdr_len + header_offset; + buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + skb = build_skb(buf, buflen); + if (!skb) + return NULL; + + skb_reserve(skb, headroom); + skb_put(skb, len); + + buf += header_offset; + memcpy(skb_vnet_hdr(skb), buf, vi->hdr_len); + + return skb; +} + static struct sk_buff *receive_small_xdp(struct net_device *dev, struct virtnet_info *vi, struct receive_queue *rq, @@ -1030,9 +1058,6 @@ static struct sk_buff *receive_small(struct net_device *dev, { unsigned int xdp_headroom = (unsigned long)ctx; struct page *page = virt_to_head_page(buf); - unsigned int header_offset; - unsigned int headroom; - unsigned int buflen; struct sk_buff *skb; len -= vi->hdr_len; @@ -1060,20 +1085,9 @@ static struct sk_buff *receive_small(struct net_device *dev, rcu_read_unlock(); } - header_offset = VIRTNET_RX_PAD + xdp_headroom; - headroom = vi->hdr_len + header_offset; - buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - - skb = build_skb(buf, buflen); - if (!skb) - goto err; - skb_reserve(skb, headroom); - skb_put(skb, len); - - buf += header_offset; - memcpy(skb_vnet_hdr(skb), buf, vi->hdr_len); - return skb; + skb = receive_small_build_skb(vi, xdp_headroom, buf, len); + if (likely(skb)) + return skb; err: stats->drops++; -- cgit v1.2.3 From 21e26a71f5d3cae2551abcda318263a6a8c15206 Mon Sep 17 00:00:00 2001 From: Xuan Zhuo Date: Mon, 8 May 2023 14:14:17 +0800 Subject: virtio_net: introduce virtnet_build_skb() This logic is used in multiple places, now we separate it into a helper. Signed-off-by: Xuan Zhuo Acked-by: Jason Wang Signed-off-by: Jakub Kicinski --- drivers/net/virtio_net.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 37287ede1959..97241006d64a 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -443,6 +443,22 @@ static unsigned int mergeable_ctx_to_truesize(void *mrg_ctx) return (unsigned long)mrg_ctx & ((1 << MRG_CTX_HEADER_SHIFT) - 1); } +static struct sk_buff *virtnet_build_skb(void *buf, unsigned int buflen, + unsigned int headroom, + unsigned int len) +{ + struct sk_buff *skb; + + skb = build_skb(buf, buflen); + if (unlikely(!skb)) + return NULL; + + skb_reserve(skb, headroom); + skb_put(skb, len); + + return skb; +} + /* Called from bottom half context */ static struct sk_buff *page_to_skb(struct virtnet_info *vi, struct receive_queue *rq, @@ -476,13 +492,10 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi, /* copy small packet so we can reuse these pages */ if (!NET_IP_ALIGN && len > GOOD_COPY_LEN && tailroom >= shinfo_size) { - skb = build_skb(buf, truesize); + skb = virtnet_build_skb(buf, truesize, p - buf, len); if (unlikely(!skb)) return NULL; - skb_reserve(skb, p - buf); - skb_put(skb, len); - page = (struct page *)page->private; if (page) give_pages(rq, page); @@ -946,13 +959,10 @@ static struct sk_buff *receive_small_build_skb(struct virtnet_info *vi, buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - skb = build_skb(buf, buflen); - if (!skb) + skb = virtnet_build_skb(buf, buflen, headroom, len); + if (unlikely(!skb)) return NULL; - skb_reserve(skb, headroom); - skb_put(skb, len); - buf += header_offset; memcpy(skb_vnet_hdr(skb), buf, vi->hdr_len); @@ -1028,12 +1038,10 @@ static struct sk_buff *receive_small_xdp(struct net_device *dev, goto err_xdp; } - skb = build_skb(buf, buflen); - if (!skb) + skb = virtnet_build_skb(buf, buflen, xdp.data - buf, len); + if (unlikely(!skb)) goto err; - skb_reserve(skb, xdp.data - buf); - skb_put(skb, len); if (metasize) skb_metadata_set(skb, metasize); -- cgit v1.2.3 From 3246627f11c56b4ec875b7225ba9b4fe0d53c271 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:27 +0200 Subject: net: stmmac: Make stmmac_pltfr_remove() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function returns zero unconditionally. Change it to return void instead which simplifies some callers as error handing becomes unnecessary. The function is also used for some drivers as remove callback. Switch these to the .remove_new() callback. For some others no error can happen in the remove callback now, convert them to .remove_new(), too. Acked-by: Jernej Skrabec Reviewed-by: Simon Horman Reviewed-by: Martin Blumenstingl Reviewed-by: Michal Kubiak Signed-off-by: Uwe Kleine-König Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c | 9 +++------ drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 9 +++------ drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 5 ++--- drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c | 4 +--- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 4 +--- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h | 2 +- 18 files changed, 23 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c index 9354bf419112..58a7f08e8d78 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c @@ -141,7 +141,7 @@ MODULE_DEVICE_TABLE(of, anarion_dwmac_match); static struct platform_driver anarion_dwmac_driver = { .probe = anarion_dwmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "anarion-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index ef8f3a940938..ef1023930fd0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -87,7 +87,7 @@ MODULE_DEVICE_TABLE(of, dwmac_generic_match); static struct platform_driver dwmac_generic_driver = { .probe = dwmac_generic_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = STMMAC_RESOURCE_NAME, .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c index 7c228bd0d099..b9378a63f0e8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c @@ -376,7 +376,7 @@ MODULE_DEVICE_TABLE(of, imx_dwmac_match); static struct platform_driver imx_dwmac_driver = { .probe = imx_dwmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "imx-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c index 378b4dd826bb..8063ba1c3ce8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c @@ -386,7 +386,7 @@ MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches); static struct platform_driver ingenic_mac_driver = { .probe = ingenic_mac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "ingenic-mac", .pm = pm_ptr(&ingenic_mac_pm_ops), diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c index 06d287f104be..a5e639ab0b9e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c @@ -169,20 +169,17 @@ err_remove_config_dt: return ret; } -static int intel_eth_plat_remove(struct platform_device *pdev) +static void intel_eth_plat_remove(struct platform_device *pdev) { struct intel_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); - int ret; - ret = stmmac_pltfr_remove(pdev); + stmmac_pltfr_remove(pdev); clk_disable_unprepare(dwmac->tx_clk); - - return ret; } static struct platform_driver intel_eth_plat_driver = { .probe = intel_eth_plat_probe, - .remove = intel_eth_plat_remove, + .remove_new = intel_eth_plat_remove, .driver = { .name = "intel-eth-plat", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index e888c8a9c830..e39406df8516 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -498,7 +498,7 @@ MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match); static struct platform_driver ipq806x_gmac_dwmac_driver = { .probe = ipq806x_gmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "ipq806x-gmac-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c index 9d77c647badd..18e84ba693a6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c @@ -83,7 +83,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match); static struct platform_driver lpc18xx_dwmac_driver = { .probe = lpc18xx_dwmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "lpc18xx-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c index 9ae31e3dc821..73c1dfa7ecb1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c @@ -678,15 +678,12 @@ err_remove_config_dt: return ret; } -static int mediatek_dwmac_remove(struct platform_device *pdev) +static void mediatek_dwmac_remove(struct platform_device *pdev) { struct mediatek_dwmac_plat_data *priv_plat = get_stmmac_bsp_priv(&pdev->dev); - int ret; - ret = stmmac_pltfr_remove(pdev); + stmmac_pltfr_remove(pdev); mediatek_dwmac_clks_config(priv_plat, false); - - return ret; } static const struct of_device_id mediatek_dwmac_match[] = { @@ -701,7 +698,7 @@ MODULE_DEVICE_TABLE(of, mediatek_dwmac_match); static struct platform_driver mediatek_dwmac_driver = { .probe = mediatek_dwmac_probe, - .remove = mediatek_dwmac_remove, + .remove_new = mediatek_dwmac_remove, .driver = { .name = "dwmac-mediatek", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c index 16fb66a0ca72..7aa5e6bc04eb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c @@ -91,7 +91,7 @@ MODULE_DEVICE_TABLE(of, meson6_dwmac_match); static struct platform_driver meson6_dwmac_driver = { .probe = meson6_dwmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "meson6-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index f6754e3643f3..92b16048f91c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -539,7 +539,7 @@ MODULE_DEVICE_TABLE(of, meson8b_dwmac_match); static struct platform_driver meson8b_dwmac_driver = { .probe = meson8b_dwmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "meson8b-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c index 62a69a91ab22..42954020de2c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c @@ -231,7 +231,7 @@ MODULE_DEVICE_TABLE(of, oxnas_dwmac_match); static struct platform_driver oxnas_dwmac_driver = { .probe = oxnas_dwmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "oxnas-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 16a8c361283b..494c22243259 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -668,16 +668,15 @@ err_mem: static int qcom_ethqos_remove(struct platform_device *pdev) { struct qcom_ethqos *ethqos; - int ret; ethqos = get_stmmac_bsp_priv(&pdev->dev); if (!ethqos) return -ENODEV; - ret = stmmac_pltfr_remove(pdev); + stmmac_pltfr_remove(pdev); ethqos_clks_config(ethqos, false); - return ret; + return 0; } static const struct of_device_id qcom_ethqos_match[] = { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 6b447d8f0bd8..6ee050300b31 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -524,7 +524,7 @@ MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); static struct platform_driver socfpga_dwmac_driver = { .probe = socfpga_dwmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "socfpga-dwmac", .pm = &socfpga_dwmac_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c index 4f51a7889642..d3a39d2fb3a9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c @@ -156,7 +156,7 @@ MODULE_DEVICE_TABLE(of, starfive_dwmac_match); static struct platform_driver starfive_dwmac_driver = { .probe = starfive_dwmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "starfive-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index fc3b0acc8f99..50963e91c347 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -179,7 +179,7 @@ MODULE_DEVICE_TABLE(of, sun7i_dwmac_match); static struct platform_driver sun7i_dwmac_driver = { .probe = sun7i_gmac_probe, - .remove = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "sun7i-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c index c3f10a92b62b..d43da71eb1e1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c @@ -265,9 +265,7 @@ static int visconti_eth_dwmac_remove(struct platform_device *pdev) struct stmmac_priv *priv = netdev_priv(ndev); int err; - err = stmmac_pltfr_remove(pdev); - if (err < 0) - dev_err(&pdev->dev, "failed to remove platform: %d\n", err); + stmmac_pltfr_remove(pdev); err = visconti_eth_clock_remove(pdev); if (err < 0) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index eb0b2898daa3..3c6b55b60461 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -707,7 +707,7 @@ EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); * Description: this function calls the main to free the net resources * and calls the platforms hook and release the resources (e.g. mem). */ -int stmmac_pltfr_remove(struct platform_device *pdev) +void stmmac_pltfr_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *priv = netdev_priv(ndev); @@ -719,8 +719,6 @@ int stmmac_pltfr_remove(struct platform_device *pdev) plat->exit(pdev, plat->bsp_priv); stmmac_remove_config_dt(pdev, plat); - - return 0; } EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 3fff3f59d73d..f7e457946681 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -19,7 +19,7 @@ void stmmac_remove_config_dt(struct platform_device *pdev, int stmmac_get_platform_resources(struct platform_device *pdev, struct stmmac_resources *stmmac_res); -int stmmac_pltfr_remove(struct platform_device *pdev); +void stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; static inline void *get_stmmac_bsp_priv(struct device *dev) -- cgit v1.2.3 From b9bc44fe068d6e44504f6f3eb03a325fd6843d60 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:28 +0200 Subject: net: stmmac: dwmac-visconti: Make visconti_eth_clock_remove() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function returns zero unconditionally. Change it to return void instead which simplifies one caller as error handing becomes unnecessary. Signed-off-by: Uwe Kleine-König Reviewed-by: Simon Horman Acked-by: Nobuhiro Iwamatsu Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c index d43da71eb1e1..56209af6243c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c @@ -198,7 +198,7 @@ static int visconti_eth_clock_probe(struct platform_device *pdev, return 0; } -static int visconti_eth_clock_remove(struct platform_device *pdev) +static void visconti_eth_clock_remove(struct platform_device *pdev) { struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev); struct net_device *ndev = platform_get_drvdata(pdev); @@ -206,8 +206,6 @@ static int visconti_eth_clock_remove(struct platform_device *pdev) clk_disable_unprepare(dwmac->phy_ref_clk); clk_disable_unprepare(priv->plat->stmmac_clk); - - return 0; } static int visconti_eth_dwmac_probe(struct platform_device *pdev) @@ -263,17 +261,14 @@ static int visconti_eth_dwmac_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *priv = netdev_priv(ndev); - int err; stmmac_pltfr_remove(pdev); - err = visconti_eth_clock_remove(pdev); - if (err < 0) - dev_err(&pdev->dev, "failed to remove clock: %d\n", err); + visconti_eth_clock_remove(pdev); stmmac_remove_config_dt(pdev, priv->plat); - return err; + return 0; } static const struct of_device_id visconti_eth_dwmac_match[] = { -- cgit v1.2.3 From c5f3ffe35cc92cce6292b5304409f3edc9281d66 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:29 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: Drop an if with an always false condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The remove callback is only ever called after .probe() returned successfully. After that get_stmmac_bsp_priv() always return non-NULL. Side note: The early exit would also be a bug because the return value of qcom_ethqos_remove() is ignored by the device core and the device is unbound unconditionally. So exiting early resulted in a dangerous resource leak as all devm allocated resources (some memory and the register mappings) are freed but the network device stays around. Using the network device afterwards probably oopses. Reviewed-by: Simon Horman Signed-off-by: Uwe Kleine-König Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 494c22243259..bf17c6c8f2eb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -667,11 +667,7 @@ err_mem: static int qcom_ethqos_remove(struct platform_device *pdev) { - struct qcom_ethqos *ethqos; - - ethqos = get_stmmac_bsp_priv(&pdev->dev); - if (!ethqos) - return -ENODEV; + struct qcom_ethqos *ethqos = get_stmmac_bsp_priv(&pdev->dev); stmmac_pltfr_remove(pdev); ethqos_clks_config(ethqos, false); -- cgit v1.2.3 From f4d05c41976170e29aac1bc51df22fb6989d1427 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:30 +0200 Subject: net: stmmac: dwmac-visconti: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Simon Horman Signed-off-by: Uwe Kleine-König Acked-by: Nobuhiro Iwamatsu Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c index 56209af6243c..acbb284be174 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c @@ -257,7 +257,7 @@ remove_config: return ret; } -static int visconti_eth_dwmac_remove(struct platform_device *pdev) +static void visconti_eth_dwmac_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *priv = netdev_priv(ndev); @@ -267,8 +267,6 @@ static int visconti_eth_dwmac_remove(struct platform_device *pdev) visconti_eth_clock_remove(pdev); stmmac_remove_config_dt(pdev, priv->plat); - - return 0; } static const struct of_device_id visconti_eth_dwmac_match[] = { @@ -279,7 +277,7 @@ MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match); static struct platform_driver visconti_eth_dwmac_driver = { .probe = visconti_eth_dwmac_probe, - .remove = visconti_eth_dwmac_remove, + .remove_new = visconti_eth_dwmac_remove, .driver = { .name = "visconti-eth-dwmac", .of_match_table = visconti_eth_dwmac_match, -- cgit v1.2.3 From 360cd89064b6e466b046680e79fd833325225a3f Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:31 +0200 Subject: net: stmmac: dwmac-dwc-qos-eth: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Simon Horman Signed-off-by: Uwe Kleine-König Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c index 18acf7dd74e5..9f88530c5e8c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c @@ -464,7 +464,7 @@ remove_config: return ret; } -static int dwc_eth_dwmac_remove(struct platform_device *pdev) +static void dwc_eth_dwmac_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *priv = netdev_priv(ndev); @@ -477,8 +477,6 @@ static int dwc_eth_dwmac_remove(struct platform_device *pdev) data->remove(pdev); stmmac_remove_config_dt(pdev, priv->plat); - - return 0; } static const struct of_device_id dwc_eth_dwmac_match[] = { @@ -490,7 +488,7 @@ MODULE_DEVICE_TABLE(of, dwc_eth_dwmac_match); static struct platform_driver dwc_eth_dwmac_driver = { .probe = dwc_eth_dwmac_probe, - .remove = dwc_eth_dwmac_remove, + .remove_new = dwc_eth_dwmac_remove, .driver = { .name = "dwc-eth-dwmac", .pm = &stmmac_pltfr_pm_ops, -- cgit v1.2.3 From 5580b559a80a3559a3b395a053f83e196aa801af Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:32 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Simon Horman Signed-off-by: Uwe Kleine-König Reviewed-by: Bhupesh Sharma Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index bf17c6c8f2eb..1db97a5209c4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -665,14 +665,12 @@ err_mem: return ret; } -static int qcom_ethqos_remove(struct platform_device *pdev) +static void qcom_ethqos_remove(struct platform_device *pdev) { struct qcom_ethqos *ethqos = get_stmmac_bsp_priv(&pdev->dev); stmmac_pltfr_remove(pdev); ethqos_clks_config(ethqos, false); - - return 0; } static const struct of_device_id qcom_ethqos_match[] = { @@ -685,7 +683,7 @@ MODULE_DEVICE_TABLE(of, qcom_ethqos_match); static struct platform_driver qcom_ethqos_driver = { .probe = qcom_ethqos_probe, - .remove = qcom_ethqos_remove, + .remove_new = qcom_ethqos_remove, .driver = { .name = "qcom-ethqos", .pm = &stmmac_pltfr_pm_ops, -- cgit v1.2.3 From 903cc461c901d854546096e01aa4bf32d2438c94 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:33 +0200 Subject: net: stmmac: dwmac-rk: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Simon Horman Signed-off-by: Uwe Kleine-König Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 4ea31ccf24d0..d81591b470a2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -1863,15 +1863,13 @@ err_remove_config_dt: return ret; } -static int rk_gmac_remove(struct platform_device *pdev) +static void rk_gmac_remove(struct platform_device *pdev) { struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(&pdev->dev); stmmac_dvr_remove(&pdev->dev); rk_gmac_powerdown(bsp_priv); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -1925,7 +1923,7 @@ MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match); static struct platform_driver rk_gmac_dwmac_driver = { .probe = rk_gmac_probe, - .remove = rk_gmac_remove, + .remove_new = rk_gmac_remove, .driver = { .name = "rk_gmac-dwmac", .pm = &rk_gmac_pm_ops, -- cgit v1.2.3 From b394982a10d93d772c962fb18f9a5f8c24f1d351 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:34 +0200 Subject: net: stmmac: dwmac-sti: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Simon Horman Signed-off-by: Uwe Kleine-König Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index 465ce66ef9c1..dcbb17c4f07a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -317,15 +317,13 @@ err_remove_config_dt: return ret; } -static int sti_dwmac_remove(struct platform_device *pdev) +static void sti_dwmac_remove(struct platform_device *pdev) { struct sti_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); stmmac_dvr_remove(&pdev->dev); clk_disable_unprepare(dwmac->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -365,7 +363,7 @@ MODULE_DEVICE_TABLE(of, sti_dwmac_match); static struct platform_driver sti_dwmac_driver = { .probe = sti_dwmac_probe, - .remove = sti_dwmac_remove, + .remove_new = sti_dwmac_remove, .driver = { .name = "sti-dwmac", .pm = &sti_dwmac_pm_ops, -- cgit v1.2.3 From fec3f552140ec5d10e3fb8eecbf8fd7f80476d02 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:35 +0200 Subject: net: stmmac: dwmac-stm32: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Simon Horman Signed-off-by: Uwe Kleine-König Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 0616b3a04ff3..bdb4de59a672 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -417,7 +417,7 @@ err_remove_config_dt: return ret; } -static int stm32_dwmac_remove(struct platform_device *pdev) +static void stm32_dwmac_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *priv = netdev_priv(ndev); @@ -431,8 +431,6 @@ static int stm32_dwmac_remove(struct platform_device *pdev) dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); } - - return 0; } static int stm32mp1_suspend(struct stm32_dwmac *dwmac) @@ -528,7 +526,7 @@ MODULE_DEVICE_TABLE(of, stm32_dwmac_match); static struct platform_driver stm32_dwmac_driver = { .probe = stm32_dwmac_probe, - .remove = stm32_dwmac_remove, + .remove_new = stm32_dwmac_remove, .driver = { .name = "stm32-dwmac", .pm = &stm32_dwmac_pm_ops, -- cgit v1.2.3 From cc708d4ed7b3d8d93c0e7f64c14a56d2b545e37a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:36 +0200 Subject: net: stmmac: dwmac-sun8i: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Acked-by: Jernej Skrabec Reviewed-by: Simon Horman Signed-off-by: Uwe Kleine-König Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index c2c592ba0eb8..1e714380d125 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -1294,7 +1294,7 @@ dwmac_deconfig: return ret; } -static int sun8i_dwmac_remove(struct platform_device *pdev) +static void sun8i_dwmac_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *priv = netdev_priv(ndev); @@ -1309,8 +1309,6 @@ static int sun8i_dwmac_remove(struct platform_device *pdev) stmmac_pltfr_remove(pdev); sun8i_dwmac_unset_syscon(gmac); - - return 0; } static void sun8i_dwmac_shutdown(struct platform_device *pdev) @@ -1341,7 +1339,7 @@ MODULE_DEVICE_TABLE(of, sun8i_dwmac_match); static struct platform_driver sun8i_dwmac_driver = { .probe = sun8i_dwmac_probe, - .remove = sun8i_dwmac_remove, + .remove_new = sun8i_dwmac_remove, .shutdown = sun8i_dwmac_shutdown, .driver = { .name = "dwmac-sun8i", -- cgit v1.2.3 From a86f8601c8f067d38bdb972885df4c0f5ed82738 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 8 May 2023 16:26:37 +0200 Subject: net: stmmac: dwmac-tegra: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Reviewed-by: Simon Horman Acked-by: Thierry Reding Signed-off-by: Uwe Kleine-König Reviewed-by: Michal Kubiak Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c index bdf990cf2f31..f8367c5b490b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c @@ -353,15 +353,13 @@ disable_clks: return err; } -static int tegra_mgbe_remove(struct platform_device *pdev) +static void tegra_mgbe_remove(struct platform_device *pdev) { struct tegra_mgbe *mgbe = get_stmmac_bsp_priv(&pdev->dev); clk_bulk_disable_unprepare(ARRAY_SIZE(mgbe_clks), mgbe->clks); stmmac_pltfr_remove(pdev); - - return 0; } static const struct of_device_id tegra_mgbe_match[] = { @@ -374,7 +372,7 @@ static SIMPLE_DEV_PM_OPS(tegra_mgbe_pm_ops, tegra_mgbe_suspend, tegra_mgbe_resum static struct platform_driver tegra_mgbe_driver = { .probe = tegra_mgbe_probe, - .remove = tegra_mgbe_remove, + .remove_new = tegra_mgbe_remove, .driver = { .name = "tegra-mgbe", .pm = &tegra_mgbe_pm_ops, -- cgit v1.2.3 From af8eacf2b42e0a736a7a2a1379fb6c0b7fd66da4 Mon Sep 17 00:00:00 2001 From: Teoh Ji Sheng Date: Mon, 8 May 2023 22:43:40 +0800 Subject: net: stmmac: xgmac: add ethtool per-queue irq statistic support Commit af9bf70154eb ("net: stmmac: add ethtool per-queue irq statistic support") introduced ethtool per-queue statistics support to display number of interrupts generated by DMA tx and DMA rx for DWMAC4 core. This patch extend the support to XGMAC core. Signed-off-by: Teoh Ji Sheng Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230508144339.3014402-1-ji.sheng.teoh@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index dfd53264e036..070bd912580b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -368,10 +368,12 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, if (likely(intr_status & XGMAC_RI)) { x->rx_normal_irq_n++; + x->rxq_stats[chan].rx_normal_irq_n++; ret |= handle_rx; } if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) { x->tx_normal_irq_n++; + x->txq_stats[chan].tx_normal_irq_n++; ret |= handle_tx; } } -- cgit v1.2.3 From 9d142ed484a3d517e779fc3c16028a720762643f Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 8 May 2023 22:45:23 +0200 Subject: net: veth: rely on napi_build_skb in veth_convert_skb_to_xdp_buff Since veth_convert_skb_to_xdp_buff routine runs in veth_poll() NAPI, rely on napi_build_skb() instead of build_skb() to reduce skb allocation cost. Signed-off-by: Lorenzo Bianconi Reviewed-by: Yunsheng Lin Link: https://lore.kernel.org/r/0f822c0b72f8b71555c11745cb8fb33399d02de9.1683578488.git.lorenzo@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/veth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index dce9f9d63e04..3ae496011640 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -747,7 +747,7 @@ static int veth_convert_skb_to_xdp_buff(struct veth_rq *rq, if (!page) goto drop; - nskb = build_skb(page_address(page), PAGE_SIZE); + nskb = napi_build_skb(page_address(page), PAGE_SIZE); if (!nskb) { page_pool_put_full_page(rq->page_pool, page, true); goto drop; -- cgit v1.2.3 From 81ac2722fa198fbfac62575259cf85163f3eeef0 Mon Sep 17 00:00:00 2001 From: Martin Wetterwald Date: Mon, 8 May 2023 19:44:47 +0200 Subject: net: ipconfig: Allow DNS to be overwritten by DHCPACK Some DHCP server implementations only send the important requested DHCP options in the final BOOTP reply (DHCPACK). One example is systemd-networkd. However, RFC2131, in section 4.3.1 states: > The server MUST return to the client: > [...] > o Parameters requested by the client, according to the following > rules: > > -- IF the server has been explicitly configured with a default > value for the parameter, the server MUST include that value > in an appropriate option in the 'option' field, ELSE I've reported the issue here: https://github.com/systemd/systemd/issues/27471 Linux PNP DHCP client implementation only takes into account the DNS servers received in the first BOOTP reply (DHCPOFFER). This usually isn't an issue as servers are required to put the same values in the DHCPOFFER and DHCPACK. However, RFC2131, in section 4.3.2 states: > Any configuration parameters in the DHCPACK message SHOULD NOT > conflict with those in the earlier DHCPOFFER message to which the > client is responding. The client SHOULD use the parameters in the > DHCPACK message for configuration. When making Linux PNP DHCP client (cmdline ip=dhcp) interact with systemd-networkd DHCP server, an interesting "protocol misunderstanding" happens: Because DNS servers were only specified in the DHCPACK and not in the DHCPOFFER, Linux will not catch the correct DNS servers: in the first BOOTP reply (DHCPOFFER), it sees that there is no DNS, and sets as fallback the IP of the DHCP server itself. When the second BOOTP reply comes (DHCPACK), it's already too late: the kernel will not overwrite the fallback setting it has set previously. This patch makes the kernel overwrite its DNS fallback by DNS servers specified in the DHCPACK if any. Signed-off-by: Martin Wetterwald Signed-off-by: David S. Miller --- net/ipv4/ipconfig.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index e90bc0aa85c7..202fa1943ccd 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -173,6 +173,9 @@ static int ic_proto_have_if __initdata; /* MTU for boot device */ static int ic_dev_mtu __initdata; +/* DHCPACK can overwrite DNS if fallback was set upon first BOOTP reply */ +static int ic_nameservers_fallback __initdata; + #ifdef IPCONFIG_DYNAMIC static DEFINE_SPINLOCK(ic_recv_lock); static volatile int ic_got_reply __initdata; /* Proto(s) that replied */ @@ -938,7 +941,8 @@ static void __init ic_do_bootp_ext(u8 *ext) if (servers > CONF_NAMESERVERS_MAX) servers = CONF_NAMESERVERS_MAX; for (i = 0; i < servers; i++) { - if (ic_nameservers[i] == NONE) + if (ic_nameservers[i] == NONE || + ic_nameservers_fallback) memcpy(&ic_nameservers[i], ext+1+4*i, 4); } break; @@ -1158,8 +1162,10 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ic_addrservaddr = b->iph.saddr; if (ic_gateway == NONE && b->relay_ip) ic_gateway = b->relay_ip; - if (ic_nameservers[0] == NONE) + if (ic_nameservers[0] == NONE) { ic_nameservers[0] = ic_servaddr; + ic_nameservers_fallback = 1; + } ic_got_reply = IC_BOOTP; drop_unlock: -- cgit v1.2.3 From 011be872643446a9b7c4485cfc8b5f50b0f93a13 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 9 May 2023 09:26:43 +0200 Subject: net: lan966x: Add ES0 VCAP model Provide ES0 (egress stage 0) VCAP model for lan966x. This provides rewriting functionality in the gress path. Signed-off-by: Horatiu Vultur Signed-off-by: David S. Miller --- .../microchip/lan966x/lan966x_vcap_ag_api.c | 264 ++++++++++++++++++++- drivers/net/ethernet/microchip/vcap/vcap_ag_api.h | 67 +++--- 2 files changed, 301 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_ag_api.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_ag_api.c index 66400a082d02..fb6851b94528 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_ag_api.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_ag_api.c @@ -2121,6 +2121,69 @@ static const struct vcap_field is2_smac_sip6_keyfield[] = { }, }; +static const struct vcap_field es0_vid_keyfield[] = { + [VCAP_KF_IF_EGR_PORT_NO] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 4, + }, + [VCAP_KF_IF_IGR_PORT] = { + .type = VCAP_FIELD_U32, + .offset = 4, + .width = 4, + }, + [VCAP_KF_ISDX_GT0_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 8, + .width = 1, + }, + [VCAP_KF_ISDX_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 9, + .width = 8, + }, + [VCAP_KF_L2_MC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 17, + .width = 1, + }, + [VCAP_KF_L2_BC_IS] = { + .type = VCAP_FIELD_BIT, + .offset = 18, + .width = 1, + }, + [VCAP_KF_8021Q_VID_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 19, + .width = 12, + }, + [VCAP_KF_8021Q_DEI_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 31, + .width = 1, + }, + [VCAP_KF_8021Q_PCP_CLS] = { + .type = VCAP_FIELD_U32, + .offset = 32, + .width = 3, + }, + [VCAP_KF_L3_DPL_CLS] = { + .type = VCAP_FIELD_BIT, + .offset = 35, + .width = 1, + }, + [VCAP_KF_RTP_ID] = { + .type = VCAP_FIELD_U32, + .offset = 36, + .width = 10, + }, + [VCAP_KF_PDU_TYPE] = { + .type = VCAP_FIELD_U32, + .offset = 46, + .width = 4, + }, +}; + /* keyfield_set */ static const struct vcap_set is1_keyfield_set[] = { [VCAP_KFS_NORMAL] = { @@ -2228,6 +2291,14 @@ static const struct vcap_set is2_keyfield_set[] = { }, }; +static const struct vcap_set es0_keyfield_set[] = { + [VCAP_KFS_VID] = { + .type_id = -1, + .sw_per_item = 1, + .sw_cnt = 1, + }, +}; + /* keyfield_set map */ static const struct vcap_field *is1_keyfield_set_map[] = { [VCAP_KFS_NORMAL] = is1_normal_keyfield, @@ -2255,6 +2326,10 @@ static const struct vcap_field *is2_keyfield_set_map[] = { [VCAP_KFS_SMAC_SIP6] = is2_smac_sip6_keyfield, }; +static const struct vcap_field *es0_keyfield_set_map[] = { + [VCAP_KFS_VID] = es0_vid_keyfield, +}; + /* keyfield_set map sizes */ static int is1_keyfield_set_map_size[] = { [VCAP_KFS_NORMAL] = ARRAY_SIZE(is1_normal_keyfield), @@ -2282,6 +2357,10 @@ static int is2_keyfield_set_map_size[] = { [VCAP_KFS_SMAC_SIP6] = ARRAY_SIZE(is2_smac_sip6_keyfield), }; +static int es0_keyfield_set_map_size[] = { + [VCAP_KFS_VID] = ARRAY_SIZE(es0_vid_keyfield), +}; + /* actionfields */ static const struct vcap_field is1_s1_actionfield[] = { [VCAP_AF_TYPE] = { @@ -2522,6 +2601,94 @@ static const struct vcap_field is2_smac_sip_actionfield[] = { }, }; +static const struct vcap_field es0_vid_actionfield[] = { + [VCAP_AF_PUSH_OUTER_TAG] = { + .type = VCAP_FIELD_U32, + .offset = 0, + .width = 2, + }, + [VCAP_AF_PUSH_INNER_TAG] = { + .type = VCAP_FIELD_BIT, + .offset = 2, + .width = 1, + }, + [VCAP_AF_TAG_A_TPID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 3, + .width = 2, + }, + [VCAP_AF_TAG_A_VID_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 5, + .width = 1, + }, + [VCAP_AF_TAG_A_PCP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 6, + .width = 2, + }, + [VCAP_AF_TAG_A_DEI_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 8, + .width = 2, + }, + [VCAP_AF_TAG_B_TPID_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 10, + .width = 2, + }, + [VCAP_AF_TAG_B_VID_SEL] = { + .type = VCAP_FIELD_BIT, + .offset = 12, + .width = 1, + }, + [VCAP_AF_TAG_B_PCP_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 13, + .width = 2, + }, + [VCAP_AF_TAG_B_DEI_SEL] = { + .type = VCAP_FIELD_U32, + .offset = 15, + .width = 2, + }, + [VCAP_AF_VID_A_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 17, + .width = 12, + }, + [VCAP_AF_PCP_A_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 29, + .width = 3, + }, + [VCAP_AF_DEI_A_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 32, + .width = 1, + }, + [VCAP_AF_VID_B_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 33, + .width = 12, + }, + [VCAP_AF_PCP_B_VAL] = { + .type = VCAP_FIELD_U32, + .offset = 45, + .width = 3, + }, + [VCAP_AF_DEI_B_VAL] = { + .type = VCAP_FIELD_BIT, + .offset = 48, + .width = 1, + }, + [VCAP_AF_ESDX] = { + .type = VCAP_FIELD_U32, + .offset = 49, + .width = 8, + }, +}; + /* actionfield_set */ static const struct vcap_set is1_actionfield_set[] = { [VCAP_AFS_S1] = { @@ -2544,6 +2711,14 @@ static const struct vcap_set is2_actionfield_set[] = { }, }; +static const struct vcap_set es0_actionfield_set[] = { + [VCAP_AFS_VID] = { + .type_id = -1, + .sw_per_item = 1, + .sw_cnt = 1, + }, +}; + /* actionfield_set map */ static const struct vcap_field *is1_actionfield_set_map[] = { [VCAP_AFS_S1] = is1_s1_actionfield, @@ -2554,6 +2729,10 @@ static const struct vcap_field *is2_actionfield_set_map[] = { [VCAP_AFS_SMAC_SIP] = is2_smac_sip_actionfield, }; +static const struct vcap_field *es0_actionfield_set_map[] = { + [VCAP_AFS_VID] = es0_vid_actionfield, +}; + /* actionfield_set map size */ static int is1_actionfield_set_map_size[] = { [VCAP_AFS_S1] = ARRAY_SIZE(is1_s1_actionfield), @@ -2564,6 +2743,10 @@ static int is2_actionfield_set_map_size[] = { [VCAP_AFS_SMAC_SIP] = ARRAY_SIZE(is2_smac_sip_actionfield), }; +static int es0_actionfield_set_map_size[] = { + [VCAP_AFS_VID] = ARRAY_SIZE(es0_vid_actionfield), +}; + /* Type Groups */ static const struct vcap_typegroup is1_x4_keyfield_set_typegroups[] = { { @@ -2659,6 +2842,10 @@ static const struct vcap_typegroup is2_x1_keyfield_set_typegroups[] = { {} }; +static const struct vcap_typegroup es0_x1_keyfield_set_typegroups[] = { + {} +}; + static const struct vcap_typegroup *is1_keyfield_set_typegroups[] = { [4] = is1_x4_keyfield_set_typegroups, [2] = is1_x2_keyfield_set_typegroups, @@ -2673,6 +2860,11 @@ static const struct vcap_typegroup *is2_keyfield_set_typegroups[] = { [5] = NULL, }; +static const struct vcap_typegroup *es0_keyfield_set_typegroups[] = { + [1] = es0_x1_keyfield_set_typegroups, + [2] = NULL, +}; + static const struct vcap_typegroup is1_x1_actionfield_set_typegroups[] = { {} }; @@ -2700,6 +2892,10 @@ static const struct vcap_typegroup is2_x1_actionfield_set_typegroups[] = { {} }; +static const struct vcap_typegroup es0_x1_actionfield_set_typegroups[] = { + {} +}; + static const struct vcap_typegroup *is1_actionfield_set_typegroups[] = { [1] = is1_x1_actionfield_set_typegroups, [5] = NULL, @@ -2711,6 +2907,11 @@ static const struct vcap_typegroup *is2_actionfield_set_typegroups[] = { [5] = NULL, }; +static const struct vcap_typegroup *es0_actionfield_set_typegroups[] = { + [1] = es0_x1_actionfield_set_typegroups, + [2] = NULL, +}; + /* Keyfieldset names */ static const char * const vcap_keyfield_set_names[] = { [VCAP_KFS_NO_VALUE] = "(None)", @@ -2743,6 +2944,7 @@ static const char * const vcap_keyfield_set_names[] = { [VCAP_KFS_RT] = "VCAP_KFS_RT", [VCAP_KFS_SMAC_SIP4] = "VCAP_KFS_SMAC_SIP4", [VCAP_KFS_SMAC_SIP6] = "VCAP_KFS_SMAC_SIP6", + [VCAP_KFS_VID] = "VCAP_KFS_VID", }; /* Actionfieldset names */ @@ -2751,9 +2953,11 @@ static const char * const vcap_actionfield_set_names[] = { [VCAP_AFS_BASE_TYPE] = "VCAP_AFS_BASE_TYPE", [VCAP_AFS_CLASSIFICATION] = "VCAP_AFS_CLASSIFICATION", [VCAP_AFS_CLASS_REDUCED] = "VCAP_AFS_CLASS_REDUCED", + [VCAP_AFS_ES0] = "VCAP_AFS_ES0", [VCAP_AFS_FULL] = "VCAP_AFS_FULL", [VCAP_AFS_S1] = "VCAP_AFS_S1", [VCAP_AFS_SMAC_SIP] = "VCAP_AFS_SMAC_SIP", + [VCAP_AFS_VID] = "VCAP_AFS_VID", }; /* Keyfield names */ @@ -2774,6 +2978,7 @@ static const char * const vcap_keyfield_names[] = { [VCAP_KF_8021Q_PCP1] = "8021Q_PCP1", [VCAP_KF_8021Q_PCP2] = "8021Q_PCP2", [VCAP_KF_8021Q_PCP_CLS] = "8021Q_PCP_CLS", + [VCAP_KF_8021Q_TPID] = "8021Q_TPID", [VCAP_KF_8021Q_TPID0] = "8021Q_TPID0", [VCAP_KF_8021Q_TPID1] = "8021Q_TPID1", [VCAP_KF_8021Q_TPID2] = "8021Q_TPID2", @@ -2799,6 +3004,7 @@ static const char * const vcap_keyfield_names[] = { [VCAP_KF_HOST_MATCH] = "HOST_MATCH", [VCAP_KF_IF_EGR_PORT_MASK] = "IF_EGR_PORT_MASK", [VCAP_KF_IF_EGR_PORT_MASK_RNG] = "IF_EGR_PORT_MASK_RNG", + [VCAP_KF_IF_EGR_PORT_NO] = "IF_EGR_PORT_NO", [VCAP_KF_IF_IGR_PORT] = "IF_IGR_PORT", [VCAP_KF_IF_IGR_PORT_MASK] = "IF_IGR_PORT_MASK", [VCAP_KF_IF_IGR_PORT_MASK_L3] = "IF_IGR_PORT_MASK_L3", @@ -2873,7 +3079,9 @@ static const char * const vcap_keyfield_names[] = { [VCAP_KF_OAM_OPCODE] = "OAM_OPCODE", [VCAP_KF_OAM_VER] = "OAM_VER", [VCAP_KF_OAM_Y1731_IS] = "OAM_Y1731_IS", + [VCAP_KF_PDU_TYPE] = "PDU_TYPE", [VCAP_KF_PROT_ACTIVE] = "PROT_ACTIVE", + [VCAP_KF_RTP_ID] = "RTP_ID", [VCAP_KF_RT_FRMID] = "RT_FRMID", [VCAP_KF_RT_TYPE] = "RT_TYPE", [VCAP_KF_RT_VLAN_IDX] = "RT_VLAN_IDX", @@ -2891,18 +3099,25 @@ static const char * const vcap_actionfield_names[] = { [VCAP_AF_COPY_PORT_NUM] = "COPY_PORT_NUM", [VCAP_AF_COPY_QUEUE_NUM] = "COPY_QUEUE_NUM", [VCAP_AF_CPU_COPY_ENA] = "CPU_COPY_ENA", + [VCAP_AF_CPU_QU] = "CPU_QU", [VCAP_AF_CPU_QUEUE_NUM] = "CPU_QUEUE_NUM", [VCAP_AF_CUSTOM_ACE_TYPE_ENA] = "CUSTOM_ACE_TYPE_ENA", + [VCAP_AF_DEI_A_VAL] = "DEI_A_VAL", + [VCAP_AF_DEI_B_VAL] = "DEI_B_VAL", + [VCAP_AF_DEI_C_VAL] = "DEI_C_VAL", [VCAP_AF_DEI_ENA] = "DEI_ENA", [VCAP_AF_DEI_VAL] = "DEI_VAL", [VCAP_AF_DLR_SEL] = "DLR_SEL", [VCAP_AF_DP_ENA] = "DP_ENA", [VCAP_AF_DP_VAL] = "DP_VAL", [VCAP_AF_DSCP_ENA] = "DSCP_ENA", + [VCAP_AF_DSCP_SEL] = "DSCP_SEL", [VCAP_AF_DSCP_VAL] = "DSCP_VAL", [VCAP_AF_ES2_REW_CMD] = "ES2_REW_CMD", + [VCAP_AF_ESDX] = "ESDX", [VCAP_AF_FWD_KILL_ENA] = "FWD_KILL_ENA", [VCAP_AF_FWD_MODE] = "FWD_MODE", + [VCAP_AF_FWD_SEL] = "FWD_SEL", [VCAP_AF_HIT_ME_ONCE] = "HIT_ME_ONCE", [VCAP_AF_HOST_MATCH] = "HOST_MATCH", [VCAP_AF_IGNORE_PIPELINE_CTRL] = "IGNORE_PIPELINE_CTRL", @@ -2912,6 +3127,7 @@ static const char * const vcap_actionfield_names[] = { [VCAP_AF_ISDX_ENA] = "ISDX_ENA", [VCAP_AF_ISDX_REPLACE_ENA] = "ISDX_REPLACE_ENA", [VCAP_AF_ISDX_VAL] = "ISDX_VAL", + [VCAP_AF_LOOP_ENA] = "LOOP_ENA", [VCAP_AF_LRN_DIS] = "LRN_DIS", [VCAP_AF_MAP_IDX] = "MAP_IDX", [VCAP_AF_MAP_KEY] = "MAP_KEY", @@ -2928,15 +3144,23 @@ static const char * const vcap_actionfield_names[] = { [VCAP_AF_OAM_SEL] = "OAM_SEL", [VCAP_AF_PAG_OVERRIDE_MASK] = "PAG_OVERRIDE_MASK", [VCAP_AF_PAG_VAL] = "PAG_VAL", + [VCAP_AF_PCP_A_VAL] = "PCP_A_VAL", + [VCAP_AF_PCP_B_VAL] = "PCP_B_VAL", + [VCAP_AF_PCP_C_VAL] = "PCP_C_VAL", [VCAP_AF_PCP_ENA] = "PCP_ENA", [VCAP_AF_PCP_VAL] = "PCP_VAL", + [VCAP_AF_PIPELINE_ACT] = "PIPELINE_ACT", [VCAP_AF_PIPELINE_FORCE_ENA] = "PIPELINE_FORCE_ENA", [VCAP_AF_PIPELINE_PT] = "PIPELINE_PT", [VCAP_AF_POLICE_ENA] = "POLICE_ENA", [VCAP_AF_POLICE_IDX] = "POLICE_IDX", [VCAP_AF_POLICE_REMARK] = "POLICE_REMARK", [VCAP_AF_POLICE_VCAP_ONLY] = "POLICE_VCAP_ONLY", + [VCAP_AF_POP_VAL] = "POP_VAL", [VCAP_AF_PORT_MASK] = "PORT_MASK", + [VCAP_AF_PUSH_CUSTOMER_TAG] = "PUSH_CUSTOMER_TAG", + [VCAP_AF_PUSH_INNER_TAG] = "PUSH_INNER_TAG", + [VCAP_AF_PUSH_OUTER_TAG] = "PUSH_OUTER_TAG", [VCAP_AF_QOS_ENA] = "QOS_ENA", [VCAP_AF_QOS_VAL] = "QOS_VAL", [VCAP_AF_REW_OP] = "REW_OP", @@ -2945,7 +3169,24 @@ static const char * const vcap_actionfield_names[] = { [VCAP_AF_SFID_VAL] = "SFID_VAL", [VCAP_AF_SGID_ENA] = "SGID_ENA", [VCAP_AF_SGID_VAL] = "SGID_VAL", + [VCAP_AF_SWAP_MACS_ENA] = "SWAP_MACS_ENA", + [VCAP_AF_TAG_A_DEI_SEL] = "TAG_A_DEI_SEL", + [VCAP_AF_TAG_A_PCP_SEL] = "TAG_A_PCP_SEL", + [VCAP_AF_TAG_A_TPID_SEL] = "TAG_A_TPID_SEL", + [VCAP_AF_TAG_A_VID_SEL] = "TAG_A_VID_SEL", + [VCAP_AF_TAG_B_DEI_SEL] = "TAG_B_DEI_SEL", + [VCAP_AF_TAG_B_PCP_SEL] = "TAG_B_PCP_SEL", + [VCAP_AF_TAG_B_TPID_SEL] = "TAG_B_TPID_SEL", + [VCAP_AF_TAG_B_VID_SEL] = "TAG_B_VID_SEL", + [VCAP_AF_TAG_C_DEI_SEL] = "TAG_C_DEI_SEL", + [VCAP_AF_TAG_C_PCP_SEL] = "TAG_C_PCP_SEL", + [VCAP_AF_TAG_C_TPID_SEL] = "TAG_C_TPID_SEL", + [VCAP_AF_TAG_C_VID_SEL] = "TAG_C_VID_SEL", [VCAP_AF_TYPE] = "TYPE", + [VCAP_AF_UNTAG_VID_ENA] = "UNTAG_VID_ENA", + [VCAP_AF_VID_A_VAL] = "VID_A_VAL", + [VCAP_AF_VID_B_VAL] = "VID_B_VAL", + [VCAP_AF_VID_C_VAL] = "VID_C_VAL", [VCAP_AF_VID_REPLACE_ENA] = "VID_REPLACE_ENA", [VCAP_AF_VID_VAL] = "VID_VAL", [VCAP_AF_VLAN_POP_CNT] = "VLAN_POP_CNT", @@ -2996,11 +3237,32 @@ const struct vcap_info lan966x_vcaps[] = { .keyfield_set_typegroups = is2_keyfield_set_typegroups, .actionfield_set_typegroups = is2_actionfield_set_typegroups, }, + [VCAP_TYPE_ES0] = { + .name = "es0", + .rows = 256, + .sw_count = 1, + .sw_width = 96, + .sticky_width = 1, + .act_width = 65, + .default_cnt = 8, + .require_cnt_dis = 0, + .version = 1, + .keyfield_set = es0_keyfield_set, + .keyfield_set_size = ARRAY_SIZE(es0_keyfield_set), + .actionfield_set = es0_actionfield_set, + .actionfield_set_size = ARRAY_SIZE(es0_actionfield_set), + .keyfield_set_map = es0_keyfield_set_map, + .keyfield_set_map_size = es0_keyfield_set_map_size, + .actionfield_set_map = es0_actionfield_set_map, + .actionfield_set_map_size = es0_actionfield_set_map_size, + .keyfield_set_typegroups = es0_keyfield_set_typegroups, + .actionfield_set_typegroups = es0_actionfield_set_typegroups, + }, }; const struct vcap_statistics lan966x_vcap_stats = { .name = "lan966x", - .count = 2, + .count = 3, .keyfield_set_names = vcap_keyfield_set_names, .actionfield_set_names = vcap_actionfield_set_names, .keyfield_names = vcap_keyfield_names, diff --git a/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h b/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h index a556c4419986..c3569a4c7b69 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_ag_api.h @@ -3,8 +3,8 @@ * Microchip VCAP API */ -/* This file is autogenerated by cml-utils 2023-02-16 11:41:14 +0100. - * Commit ID: be85f176b3a151fa748dcaf97c8824a5c2e065f3 +/* This file is autogenerated by cml-utils 2023-03-13 10:16:42 +0100. + * Commit ID: 259f0efd6d6d91bfbf62858de153cc757b6bffa3 (dirty) */ #ifndef __VCAP_AG_API__ @@ -51,6 +51,7 @@ enum vcap_keyfield_set { VCAP_KFS_RT, /* lan966x is1 X1 */ VCAP_KFS_SMAC_SIP4, /* lan966x is2 X1 */ VCAP_KFS_SMAC_SIP6, /* lan966x is2 X2 */ + VCAP_KFS_VID, /* lan966x es0 X1 */ }; /* List of keyfields with description @@ -79,7 +80,7 @@ enum vcap_keyfield_set { * Second DEI in multiple vlan tags (inner tag) * VCAP_KF_8021Q_DEI2: W1, sparx5: is0 * Third DEI in multiple vlan tags (not always available) - * VCAP_KF_8021Q_DEI_CLS: W1, sparx5: is2/es2, lan966x: is2 + * VCAP_KF_8021Q_DEI_CLS: W1, sparx5: is2/es2, lan966x: is2/es0 * Classified DEI * VCAP_KF_8021Q_PCP0: W3, sparx5: is0, lan966x: is1 * First PCP in multiple vlan tags (outer tag or default port tag) @@ -87,7 +88,7 @@ enum vcap_keyfield_set { * Second PCP in multiple vlan tags (inner tag) * VCAP_KF_8021Q_PCP2: W3, sparx5: is0 * Third PCP in multiple vlan tags (not always available) - * VCAP_KF_8021Q_PCP_CLS: W3, sparx5: is2/es2, lan966x: is2 + * VCAP_KF_8021Q_PCP_CLS: W3, sparx5: is2/es2, lan966x: is2/es0 * Classified PCP * VCAP_KF_8021Q_TPID: W3, sparx5: es0 * TPID for outer tag: 0: Customer TPID 1: Service TPID (88A8 or programmable) @@ -104,7 +105,7 @@ enum vcap_keyfield_set { * VCAP_KF_8021Q_VID2: W12, sparx5: is0 * Third VID in multiple vlan tags (not always available) * VCAP_KF_8021Q_VID_CLS: sparx5 is2 W13, sparx5 es0 W13, sparx5 es2 W13, - * lan966x is2 W12 + * lan966x is2 W12, lan966x es0 W12 * Classified VID * VCAP_KF_8021Q_VLAN_DBL_TAGGED_IS: W1, lan966x: is1 * Set if frame has two or more Q-tags. Independent of port VLAN awareness @@ -146,10 +147,10 @@ enum vcap_keyfield_set { * VCAP_KF_IF_EGR_PORT_MASK_RNG: W3, sparx5: es2 * Select which 32 port group is available in IF_EGR_PORT (or virtual ports or * CPU queue) - * VCAP_KF_IF_EGR_PORT_NO: W7, sparx5: es0 + * VCAP_KF_IF_EGR_PORT_NO: sparx5 es0 W7, lan966x es0 W4 * Egress port number * VCAP_KF_IF_IGR_PORT: sparx5 is0 W7, sparx5 es2 W9, lan966x is1 W3, lan966x - * is2 W4 + * is2 W4, lan966x es0 W4 * Sparx5: Logical ingress port number retrieved from * ANA_CL::PORT_ID_CFG.LPORT_NUM or ERLEG, LAN966x: ingress port nunmber * VCAP_KF_IF_IGR_PORT_MASK: sparx5 is0 W65, sparx5 is2 W32, sparx5 is2 W65, @@ -178,11 +179,12 @@ enum vcap_keyfield_set { * Payload after IPv6 header * VCAP_KF_IP_SNAP_IS: W1, sparx5: is0, lan966x: is1 * Set if frame is IPv4, IPv6, or SNAP frame - * VCAP_KF_ISDX_CLS: W12, sparx5: is2/es0/es2 + * VCAP_KF_ISDX_CLS: sparx5 is2 W12, sparx5 es0 W12, sparx5 es2 W12, lan966x es0 + * W8 * Classified ISDX - * VCAP_KF_ISDX_GT0_IS: W1, sparx5: is2/es0/es2, lan966x: is2 + * VCAP_KF_ISDX_GT0_IS: W1, sparx5: is2/es0/es2, lan966x: is2/es0 * Set if classified ISDX > 0 - * VCAP_KF_L2_BC_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2 + * VCAP_KF_L2_BC_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2/es0 * Set if frame's destination MAC address is the broadcast address * (FF-FF-FF-FF-FF-FF). * VCAP_KF_L2_DMAC: W48, sparx5: is0/is2/es2, lan966x: is1/is2 @@ -195,7 +197,7 @@ enum vcap_keyfield_set { * LLC header and data after up to two VLAN tags and the type/length field * VCAP_KF_L2_MAC: W48, lan966x: is1 * MAC address (FIRST=1: SMAC, FIRST=0: DMAC) - * VCAP_KF_L2_MC_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2 + * VCAP_KF_L2_MC_IS: W1, sparx5: is0/is2/es2, lan966x: is1/is2/es0 * Set if frame's destination MAC address is a multicast address (bit 40 = 1). * VCAP_KF_L2_PAYLOAD0: W16, lan966x: is2 * Payload bytes 0-1 after the frame's EtherType @@ -213,7 +215,7 @@ enum vcap_keyfield_set { * SNAP header after LLC header (AA-AA-03) * VCAP_KF_L3_DIP_EQ_SIP_IS: W1, sparx5: is2/es2, lan966x: is2 * Set if Src IP matches Dst IP address - * VCAP_KF_L3_DPL_CLS: W1, sparx5: es0/es2 + * VCAP_KF_L3_DPL_CLS: W1, sparx5: es0/es2, lan966x: es0 * The frames drop precedence level * VCAP_KF_L3_DSCP: W6, sparx5: is0, lan966x: is1 * Frame's DSCP value @@ -330,8 +332,12 @@ enum vcap_keyfield_set { * Frame's OAM version * VCAP_KF_OAM_Y1731_IS: W1, sparx5: is2/es2, lan966x: is2 * Set if frame's EtherType = 0x8902 + * VCAP_KF_PDU_TYPE: W4, lan966x: es0 + * PDU type value (none, OAM CCM, MRP, DLR, RTE, IPv4, IPv6, OAM non-CCM) * VCAP_KF_PROT_ACTIVE: W1, sparx5: es0/es2 * Protection is active + * VCAP_KF_RTP_ID: W10, lan966x: es0 + * Classified RTP_ID * VCAP_KF_RT_FRMID: W32, lan966x: is1 * Profinet or OPC-UA FrameId * VCAP_KF_RT_TYPE: W2, lan966x: is1 @@ -470,7 +476,9 @@ enum vcap_key_field { VCAP_KF_OAM_OPCODE, VCAP_KF_OAM_VER, VCAP_KF_OAM_Y1731_IS, + VCAP_KF_PDU_TYPE, VCAP_KF_PROT_ACTIVE, + VCAP_KF_RTP_ID, VCAP_KF_RT_FRMID, VCAP_KF_RT_TYPE, VCAP_KF_RT_VLAN_IDX, @@ -489,6 +497,7 @@ enum vcap_actionfield_set { VCAP_AFS_FULL, /* sparx5 is0 X3 */ VCAP_AFS_S1, /* lan966x is1 X1 */ VCAP_AFS_SMAC_SIP, /* lan966x is2 X1 */ + VCAP_AFS_VID, /* lan966x es0 X1 */ }; /* List of actionfields with description @@ -523,9 +532,9 @@ enum vcap_actionfield_set { * while bits 1:0 control first lookup. Encoding per lookup: 0: Disabled. 1: * Extract 40 bytes after position corresponding to the location of the IPv4 * header and use as key. 2: Extract 40 bytes after SMAC and use as key - * VCAP_AF_DEI_A_VAL: W1, sparx5: es0 + * VCAP_AF_DEI_A_VAL: W1, sparx5: es0, lan966x: es0 * DEI used in ES0 tag A. See TAG_A_DEI_SEL. - * VCAP_AF_DEI_B_VAL: W1, sparx5: es0 + * VCAP_AF_DEI_B_VAL: W1, sparx5: es0, lan966x: es0 * DEI used in ES0 tag B. See TAG_B_DEI_SEL. * VCAP_AF_DEI_C_VAL: W1, sparx5: es0 * DEI used in ES0 tag C. See TAG_C_DEI_SEL. @@ -556,7 +565,7 @@ enum vcap_actionfield_set { * VCAP_AF_ES2_REW_CMD: W3, sparx5: es2 * Command forwarded to REW: 0: No action. 1: SWAP MAC addresses. 2: Do L2CP * DMAC translation when entering or leaving a tunnel. - * VCAP_AF_ESDX: W13, sparx5: es0 + * VCAP_AF_ESDX: sparx5 es0 W13, lan966x es0 W8 * Egress counter index. Used to index egress counter set as defined in * REW::STAT_CFG. * VCAP_AF_FWD_KILL_ENA: W1, lan966x: is2 @@ -652,9 +661,9 @@ enum vcap_actionfield_set { * (input) AND ~PAG_OVERRIDE_MASK) OR (PAG_VAL AND PAG_OVERRIDE_MASK) * VCAP_AF_PAG_VAL: W8, sparx5: is0, lan966x: is1 * See PAG_OVERRIDE_MASK. - * VCAP_AF_PCP_A_VAL: W3, sparx5: es0 + * VCAP_AF_PCP_A_VAL: W3, sparx5: es0, lan966x: es0 * PCP used in ES0 tag A. See TAG_A_PCP_SEL. - * VCAP_AF_PCP_B_VAL: W3, sparx5: es0 + * VCAP_AF_PCP_B_VAL: W3, sparx5: es0, lan966x: es0 * PCP used in ES0 tag B. See TAG_B_PCP_SEL. * VCAP_AF_PCP_C_VAL: W3, sparx5: es0 * PCP used in ES0 tag C. See TAG_C_PCP_SEL. @@ -691,10 +700,10 @@ enum vcap_actionfield_set { * Selects tag C mode: 0: Do not push tag C. 1: Push tag C if * IFH.VSTAX.TAG.WAS_TAGGED = 1. 2: Push tag C if IFH.VSTAX.TAG.WAS_TAGGED = 0. * 3: Push tag C if UNTAG_VID_ENA = 0 or (C-TAG.VID ! = VID_C_VAL). - * VCAP_AF_PUSH_INNER_TAG: W1, sparx5: es0 + * VCAP_AF_PUSH_INNER_TAG: W1, sparx5: es0, lan966x: es0 * Controls inner tagging. 0: Do not push ES0 tag B as inner tag. 1: Push ES0 * tag B as inner tag. - * VCAP_AF_PUSH_OUTER_TAG: W2, sparx5: es0 + * VCAP_AF_PUSH_OUTER_TAG: W2, sparx5: es0, lan966x: es0 * Controls outer tagging. 0: No ES0 tag A: Port tag is allowed if enabled on * port. 1: ES0 tag A: Push ES0 tag A. No port tag. 2: Force port tag: Always * push port tag. No ES0 tag A. 3: Force untag: Never push port tag or ES0 tag @@ -720,29 +729,29 @@ enum vcap_actionfield_set { * VCAP_AF_SWAP_MACS_ENA: W1, sparx5: es0 * This setting is only active when FWD_SEL = 1 or FWD_SEL = 2 and PIPELINE_ACT * = LBK_ASM. 0: No action. 1: Swap MACs and clear bit 40 in new SMAC. - * VCAP_AF_TAG_A_DEI_SEL: W3, sparx5: es0 + * VCAP_AF_TAG_A_DEI_SEL: sparx5 es0 W3, lan966x es0 W2 * Selects PCP for ES0 tag A. 0: Classified DEI. 1: DEI_A_VAL. 2: DP and QoS * mapped to PCP (per port table). 3: DP. - * VCAP_AF_TAG_A_PCP_SEL: W3, sparx5: es0 + * VCAP_AF_TAG_A_PCP_SEL: sparx5 es0 W3, lan966x es0 W2 * Selects PCP for ES0 tag A. 0: Classified PCP. 1: PCP_A_VAL. 2: DP and QoS * mapped to PCP (per port table). 3: QoS class. - * VCAP_AF_TAG_A_TPID_SEL: W3, sparx5: es0 + * VCAP_AF_TAG_A_TPID_SEL: sparx5 es0 W3, lan966x es0 W2 * Selects TPID for ES0 tag A: 0: 0x8100. 1: 0x88A8. 2: Custom * (REW:PORT:PORT_VLAN_CFG.PORT_TPID). 3: If IFH.TAG_TYPE = 0 then 0x8100 else * custom. - * VCAP_AF_TAG_A_VID_SEL: W2, sparx5: es0 + * VCAP_AF_TAG_A_VID_SEL: sparx5 es0 W2, lan966x es0 W1 * Selects VID for ES0 tag A. 0: Classified VID + VID_A_VAL. 1: VID_A_VAL. - * VCAP_AF_TAG_B_DEI_SEL: W3, sparx5: es0 + * VCAP_AF_TAG_B_DEI_SEL: sparx5 es0 W3, lan966x es0 W2 * Selects PCP for ES0 tag B. 0: Classified DEI. 1: DEI_B_VAL. 2: DP and QoS * mapped to PCP (per port table). 3: DP. - * VCAP_AF_TAG_B_PCP_SEL: W3, sparx5: es0 + * VCAP_AF_TAG_B_PCP_SEL: sparx5 es0 W3, lan966x es0 W2 * Selects PCP for ES0 tag B. 0: Classified PCP. 1: PCP_B_VAL. 2: DP and QoS * mapped to PCP (per port table). 3: QoS class. - * VCAP_AF_TAG_B_TPID_SEL: W3, sparx5: es0 + * VCAP_AF_TAG_B_TPID_SEL: sparx5 es0 W3, lan966x es0 W2 * Selects TPID for ES0 tag B. 0: 0x8100. 1: 0x88A8. 2: Custom * (REW:PORT:PORT_VLAN_CFG.PORT_TPID). 3: If IFH.TAG_TYPE = 0 then 0x8100 else * custom. - * VCAP_AF_TAG_B_VID_SEL: W2, sparx5: es0 + * VCAP_AF_TAG_B_VID_SEL: sparx5 es0 W2, lan966x es0 W1 * Selects VID for ES0 tag B. 0: Classified VID + VID_B_VAL. 1: VID_B_VAL. * VCAP_AF_TAG_C_DEI_SEL: W3, sparx5: es0 * Selects DEI source for ES0 tag C. 0: Classified DEI. 1: DEI_C_VAL. 2: @@ -770,9 +779,9 @@ enum vcap_actionfield_set { * VCAP_AF_UNTAG_VID_ENA: W1, sparx5: es0 * Controls insertion of tag C. Untag or insert mode can be selected. See * PUSH_CUSTOMER_TAG. - * VCAP_AF_VID_A_VAL: W12, sparx5: es0 + * VCAP_AF_VID_A_VAL: W12, sparx5: es0, lan966x: es0 * VID used in ES0 tag A. See TAG_A_VID_SEL. - * VCAP_AF_VID_B_VAL: W12, sparx5: es0 + * VCAP_AF_VID_B_VAL: W12, sparx5: es0, lan966x: es0 * VID used in ES0 tag B. See TAG_B_VID_SEL. * VCAP_AF_VID_C_VAL: W12, sparx5: es0 * VID used in ES0 tag C. See TAG_C_VID_SEL. -- cgit v1.2.3 From 96b6c8a662a39a9ce3a0dac929e23c8a8d454f37 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 9 May 2023 09:26:44 +0200 Subject: net: lan966x: Add ES0 VCAP keyset configuration for lan966x Add ES0 VCAP port keyset configuration for lan966x and also update debugfs to show the keyset configuration. Signed-off-by: Horatiu Vultur Signed-off-by: David S. Miller --- .../net/ethernet/microchip/lan966x/lan966x_main.h | 3 + .../net/ethernet/microchip/lan966x/lan966x_regs.h | 15 ++++ .../microchip/lan966x/lan966x_vcap_debugfs.c | 23 ++++++ .../ethernet/microchip/lan966x/lan966x_vcap_impl.c | 82 ++++++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h index c977c70abc3d..882d5a08e7d5 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h @@ -101,6 +101,9 @@ #define LAN966X_VCAP_CID_IS2_L1 VCAP_CID_INGRESS_STAGE2_L1 /* IS2 lookup 1 */ #define LAN966X_VCAP_CID_IS2_MAX (VCAP_CID_INGRESS_STAGE2_L2 - 1) /* IS2 Max */ +#define LAN966X_VCAP_CID_ES0_L0 VCAP_CID_EGRESS_L0 /* ES0 lookup 0 */ +#define LAN966X_VCAP_CID_ES0_MAX (VCAP_CID_EGRESS_L1 - 1) /* ES0 Max */ + /* MAC table entry types. * ENTRYTYPE_NORMAL is subject to aging. * ENTRYTYPE_LOCKED is not subject to aging. diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h index f99f88b5caa8..222039180276 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h @@ -1471,12 +1471,27 @@ enum lan966x_target { /* REW:PORT:PORT_CFG */ #define REW_PORT_CFG(g) __REG(TARGET_REW, 0, 1, 0, g, 10, 128, 8, 0, 1, 4) +#define REW_PORT_CFG_ES0_EN BIT(4) +#define REW_PORT_CFG_ES0_EN_SET(x)\ + FIELD_PREP(REW_PORT_CFG_ES0_EN, x) +#define REW_PORT_CFG_ES0_EN_GET(x)\ + FIELD_GET(REW_PORT_CFG_ES0_EN, x) + #define REW_PORT_CFG_NO_REWRITE BIT(0) #define REW_PORT_CFG_NO_REWRITE_SET(x)\ FIELD_PREP(REW_PORT_CFG_NO_REWRITE, x) #define REW_PORT_CFG_NO_REWRITE_GET(x)\ FIELD_GET(REW_PORT_CFG_NO_REWRITE, x) +/* REW:COMMON:STAT_CFG */ +#define REW_STAT_CFG __REG(TARGET_REW, 0, 1, 3072, 0, 1, 528, 520, 0, 1, 4) + +#define REW_STAT_CFG_STAT_MODE GENMASK(1, 0) +#define REW_STAT_CFG_STAT_MODE_SET(x)\ + FIELD_PREP(REW_STAT_CFG_STAT_MODE, x) +#define REW_STAT_CFG_STAT_MODE_GET(x)\ + FIELD_GET(REW_STAT_CFG_STAT_MODE, x) + /* SYS:SYSTEM:RESET_CFG */ #define SYS_RESET_CFG __REG(TARGET_SYS, 0, 1, 4128, 0, 1, 168, 0, 0, 1, 4) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c index d90c08cfcf14..ac525ff1503e 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c @@ -190,6 +190,26 @@ static void lan966x_vcap_is2_port_keys(struct lan966x_port *port, out->prf(out->dst, "\n"); } +static void lan966x_vcap_es0_port_keys(struct lan966x_port *port, + struct vcap_admin *admin, + struct vcap_output_print *out) +{ + struct lan966x *lan966x = port->lan966x; + u32 val; + + out->prf(out->dst, " port[%d] (%s): ", port->chip_port, + netdev_name(port->dev)); + + val = lan_rd(lan966x, REW_PORT_CFG(port->chip_port)); + out->prf(out->dst, "\n state: "); + if (REW_PORT_CFG_ES0_EN_GET(val)) + out->prf(out->dst, "on"); + else + out->prf(out->dst, "off"); + + out->prf(out->dst, "\n"); +} + int lan966x_vcap_port_info(struct net_device *dev, struct vcap_admin *admin, struct vcap_output_print *out) @@ -210,6 +230,9 @@ int lan966x_vcap_port_info(struct net_device *dev, case VCAP_TYPE_IS1: lan966x_vcap_is1_port_keys(port, admin, out); break; + case VCAP_TYPE_ES0: + lan966x_vcap_es0_port_keys(port, admin, out); + break; default: out->prf(out->dst, " no info\n"); break; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c index 7ea8e8633609..a4414f63c9b1 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c @@ -10,6 +10,12 @@ #define LAN966X_IS1_LOOKUPS 3 #define LAN966X_IS2_LOOKUPS 2 +#define LAN966X_ES0_LOOKUPS 1 + +#define LAN966X_STAT_ESDX_GRN_BYTES 0x300 +#define LAN966X_STAT_ESDX_GRN_PKTS 0x301 +#define LAN966X_STAT_ESDX_YEL_BYTES 0x302 +#define LAN966X_STAT_ESDX_YEL_PKTS 0x303 static struct lan966x_vcap_inst { enum vcap_type vtype; /* type of vcap */ @@ -20,6 +26,14 @@ static struct lan966x_vcap_inst { int count; /* number of available addresses */ bool ingress; /* is vcap in the ingress path */ } lan966x_vcap_inst_cfg[] = { + { + .vtype = VCAP_TYPE_ES0, + .tgt_inst = 0, + .lookups = LAN966X_ES0_LOOKUPS, + .first_cid = LAN966X_VCAP_CID_ES0_L0, + .last_cid = LAN966X_VCAP_CID_ES0_MAX, + .count = 64, + }, { .vtype = VCAP_TYPE_IS1, /* IS1-0 */ .tgt_inst = 1, @@ -279,6 +293,8 @@ lan966x_vcap_validate_keyset(struct net_device *dev, err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist, l3_proto); break; + case VCAP_TYPE_ES0: + return kslist->keysets[0]; default: pr_err("vcap type: %s not supported\n", lan966x_vcaps[admin->vtype].name); @@ -338,6 +354,14 @@ static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port, VCAP_BIT_0); } +static void lan966x_vcap_es0_add_default_fields(struct lan966x_port *port, + struct vcap_admin *admin, + struct vcap_rule *rule) +{ + vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_NO, + port->chip_port, GENMASK(4, 0)); +} + static void lan966x_vcap_add_default_fields(struct net_device *dev, struct vcap_admin *admin, struct vcap_rule *rule) @@ -351,6 +375,9 @@ static void lan966x_vcap_add_default_fields(struct net_device *dev, case VCAP_TYPE_IS2: lan966x_vcap_is2_add_default_fields(port, admin, rule); break; + case VCAP_TYPE_ES0: + lan966x_vcap_es0_add_default_fields(port, admin, rule); + break; default: pr_err("vcap type: %s not supported\n", lan966x_vcaps[admin->vtype].name); @@ -366,6 +393,40 @@ static void lan966x_vcap_cache_erase(struct vcap_admin *admin) memset(&admin->cache.counter, 0, sizeof(admin->cache.counter)); } +/* The ESDX counter is only used/incremented if the frame has been classified + * with an ISDX > 0 (e.g by a rule in IS0). This is not mentioned in the + * datasheet. + */ +static void lan966x_es0_read_esdx_counter(struct lan966x *lan966x, + struct vcap_admin *admin, u32 id) +{ + u32 counter; + + id = id & 0xff; /* counter limit */ + mutex_lock(&lan966x->stats_lock); + lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG); + counter = lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS)) + + lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS)); + mutex_unlock(&lan966x->stats_lock); + if (counter) + admin->cache.counter = counter; +} + +static void lan966x_es0_write_esdx_counter(struct lan966x *lan966x, + struct vcap_admin *admin, u32 id) +{ + id = id & 0xff; /* counter limit */ + + mutex_lock(&lan966x->stats_lock); + lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG); + lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_BYTES)); + lan_wr(admin->cache.counter, lan966x, + SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS)); + lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_BYTES)); + lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS)); + mutex_unlock(&lan966x->stats_lock); +} + static void lan966x_vcap_cache_write(struct net_device *dev, struct vcap_admin *admin, enum vcap_selection sel, @@ -398,6 +459,9 @@ static void lan966x_vcap_cache_write(struct net_device *dev, admin->cache.sticky = admin->cache.counter > 0; lan_wr(admin->cache.counter, lan966x, VCAP_CNT_DAT(admin->tgt_inst, 0)); + + if (admin->vtype == VCAP_TYPE_ES0) + lan966x_es0_write_esdx_counter(lan966x, admin, start); break; default: break; @@ -437,6 +501,9 @@ static void lan966x_vcap_cache_read(struct net_device *dev, admin->cache.counter = lan_rd(lan966x, VCAP_CNT_DAT(instance, 0)); admin->cache.sticky = admin->cache.counter > 0; + + if (admin->vtype == VCAP_TYPE_ES0) + lan966x_es0_read_esdx_counter(lan966x, admin, start); } } @@ -625,6 +692,12 @@ static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x, lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p)); break; + case VCAP_TYPE_ES0: + for (int p = 0; p < lan966x->num_phys_ports; ++p) + lan_rmw(REW_PORT_CFG_ES0_EN_SET(false), + REW_PORT_CFG_ES0_EN, lan966x, + REW_PORT_CFG(p)); + break; default: pr_err("vcap type: %s not supported\n", lan966x_vcaps[admin->vtype].name); @@ -674,9 +747,18 @@ int lan966x_vcap_init(struct lan966x *lan966x) lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true), ANA_VCAP_CFG_S1_ENA, lan966x, ANA_VCAP_CFG(lan966x->ports[p]->chip_port)); + + lan_rmw(REW_PORT_CFG_ES0_EN_SET(true), + REW_PORT_CFG_ES0_EN, lan966x, + REW_PORT_CFG(lan966x->ports[p]->chip_port)); } } + /* Statistics: Use ESDX from ES0 if hit, otherwise no counting */ + lan_rmw(REW_STAT_CFG_STAT_MODE_SET(1), + REW_STAT_CFG_STAT_MODE, lan966x, + REW_STAT_CFG); + lan966x->vcap_ctrl = ctrl; return 0; -- cgit v1.2.3 From 85f050002ba99150168078adab6d0f38c0463494 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 9 May 2023 09:26:45 +0200 Subject: net: lan966x: Add TC support for ES0 VCAP Enable the TC command to use the lan966x ES0 VCAP. Currently support only one action which is vlan pop, other will be added later. Signed-off-by: Horatiu Vultur Signed-off-by: David S. Miller --- .../ethernet/microchip/lan966x/lan966x_tc_flower.c | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c index 47b2f7579dd2..96b3def6c474 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_tc_flower.c @@ -5,6 +5,8 @@ #include "vcap_api_client.h" #include "vcap_tc.h" +#define LAN966X_FORCE_UNTAGED 3 + static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st, u16 etype) { @@ -29,6 +31,8 @@ static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st, return true; } break; + case VCAP_TYPE_ES0: + return true; default: NL_SET_ERR_MSG_MOD(st->fco->common.extack, "VCAP type not supported"); @@ -318,6 +322,9 @@ static int lan966x_tc_set_actionset(struct vcap_admin *admin, case VCAP_TYPE_IS2: aset = VCAP_AFS_BASE_TYPE; break; + case VCAP_TYPE_ES0: + aset = VCAP_AFS_VID; + break; default: return -EINVAL; } @@ -353,6 +360,10 @@ static int lan966x_tc_add_rule_link_target(struct vcap_admin *admin, /* Add IS2 specific PAG key (for chaining rules from IS1) */ return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG, link_val, ~0); + case VCAP_TYPE_ES0: + /* Add ES0 specific ISDX key (for chaining rules from IS1) */ + return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, + link_val, ~0); default: break; } @@ -389,6 +400,18 @@ static int lan966x_tc_add_rule_link(struct vcap_control *vctrl, 0xff); if (err) return err; + } else if (admin->vtype == VCAP_TYPE_IS1 && + to_admin->vtype == VCAP_TYPE_ES0) { + /* This works for IS1->ES0 */ + err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_ADD_VAL, + diff); + if (err) + return err; + + err = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_REPLACE_ENA, + VCAP_BIT_1); + if (err) + return err; } else { NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported chain destination"); @@ -398,6 +421,23 @@ static int lan966x_tc_add_rule_link(struct vcap_control *vctrl, return err; } +static int lan966x_tc_add_rule_counter(struct vcap_admin *admin, + struct vcap_rule *vrule) +{ + int err = 0; + + switch (admin->vtype) { + case VCAP_TYPE_ES0: + err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX, + vrule->id); + break; + default: + break; + } + + return err; +} + static int lan966x_tc_flower_add(struct lan966x_port *port, struct flow_cls_offload *f, struct vcap_admin *admin, @@ -465,6 +505,21 @@ static int lan966x_tc_flower_add(struct lan966x_port *port, if (err) goto out; + break; + case FLOW_ACTION_VLAN_POP: + if (admin->vtype != VCAP_TYPE_ES0) { + NL_SET_ERR_MSG_MOD(f->common.extack, + "Cannot use vlan pop on non es0"); + err = -EOPNOTSUPP; + goto out; + } + + /* Force untag */ + err = vcap_rule_add_action_u32(vrule, VCAP_AF_PUSH_OUTER_TAG, + LAN966X_FORCE_UNTAGED); + if (err) + goto out; + break; default: NL_SET_ERR_MSG_MOD(f->common.extack, @@ -474,6 +529,12 @@ static int lan966x_tc_flower_add(struct lan966x_port *port, } } + err = lan966x_tc_add_rule_counter(admin, vrule); + if (err) { + vcap_set_tc_exterr(f, vrule); + goto out; + } + err = vcap_val_rule(vrule, l3_proto); if (err) { vcap_set_tc_exterr(f, vrule); -- cgit v1.2.3 From 5e316a818e75c585dc7b601e8b51823a4059d408 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 9 May 2023 11:05:16 +0200 Subject: net: veth: make PAGE_POOL_STATS optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since veth is very likely to be enabled and there are some drivers (e.g. mlx5) where CONFIG_PAGE_POOL_STATS is optional, make CONFIG_PAGE_POOL_STATS optional for veth too in order to keep it optional instead of required. Suggested-by: Jiri Benc Signed-off-by: Lorenzo Bianconi Reviewed-by: Simon Horman Acked-by: Jesper Dangaard Brouer Acked-by: Toke Høiland-Jørgensen Signed-off-by: David S. Miller --- drivers/net/Kconfig | 1 - drivers/net/veth.c | 24 +++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d0a1ed216d15..368c6f5b327e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -403,7 +403,6 @@ config TUN_VNET_CROSS_LE config VETH tristate "Virtual ethernet pair device" select PAGE_POOL - select PAGE_POOL_STATS help This device is a local ethernet tunnel. Devices are created in pairs. When one end receives the packet it appears on its pair and vice diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 3ae496011640..614f3e3efab0 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -176,12 +176,27 @@ static int veth_get_sset_count(struct net_device *dev, int sset) } } +static void veth_get_page_pool_stats(struct net_device *dev, u64 *data) +{ +#ifdef CONFIG_PAGE_POOL_STATS + struct veth_priv *priv = netdev_priv(dev); + struct page_pool_stats pp_stats = {}; + int i; + + for (i = 0; i < dev->real_num_rx_queues; i++) { + if (!priv->rq[i].page_pool) + continue; + page_pool_get_stats(priv->rq[i].page_pool, &pp_stats); + } + page_pool_ethtool_stats_get(data, &pp_stats); +#endif /* CONFIG_PAGE_POOL_STATS */ +} + static void veth_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { struct veth_priv *rcv_priv, *priv = netdev_priv(dev); struct net_device *peer = rtnl_dereference(priv->peer); - struct page_pool_stats pp_stats = {}; int i, j, idx, pp_idx; data[0] = peer ? peer->ifindex : 0; @@ -225,12 +240,7 @@ static void veth_get_ethtool_stats(struct net_device *dev, } page_pool_stats: - for (i = 0; i < dev->real_num_rx_queues; i++) { - if (!priv->rq[i].page_pool) - continue; - page_pool_get_stats(priv->rq[i].page_pool, &pp_stats); - } - page_pool_ethtool_stats_get(&data[pp_idx], &pp_stats); + veth_get_page_pool_stats(dev, &data[pp_idx]); } static void veth_get_channels(struct net_device *dev, -- cgit v1.2.3 From 2f0f556713f08515f3017fd35309b1f00fbc8932 Mon Sep 17 00:00:00 2001 From: Liang Li Date: Tue, 9 May 2023 09:09:19 +0000 Subject: selftests: bonding: delete unnecessary line "ip link set dev "$devbond1" nomaster" This line code in bond-eth-type-change.sh is unnecessary. Because $devbond1 was not added to any master device. Signed-off-by: Liang Li Acked-by: Hangbin Liu Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh b/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh index 5cdd22048ba7..862e947e17c7 100755 --- a/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh +++ b/tools/testing/selftests/drivers/net/bonding/bond-eth-type-change.sh @@ -53,7 +53,6 @@ bond_test_enslave_type_change() # restore ARPHRD_ETHER type by enslaving such device ip link set dev "$devbond2" master "$devbond0" check_err $? "could not enslave $devbond2 to $devbond0" - ip link set dev "$devbond1" nomaster bond_check_flags "$devbond0" -- cgit v1.2.3 From bd9424efc4825ecfc84cd81be777df71ba4404d1 Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Wed, 10 May 2023 13:58:09 +0530 Subject: macsec: Use helper macsec_netdev_priv for offload drivers Now macsec on top of vlan can be offloaded to macsec offloading devices so that VLAN tag is sent in clear text on wire i.e, packet structure is DMAC|SMAC|VLAN|SECTAG. Offloading devices can simply enable NETIF_F_HW_MACSEC feature in netdev->vlan_features for this to work. But the logic in offloading drivers to retrieve the private structure from netdev needs to be changed to check whether the netdev received is real device or a vlan device and get private structure accordingly. This patch changes the offloading drivers to use helper macsec_netdev_priv instead of netdev_priv. Signed-off-by: Subbaraya Sundeep Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_macsec.c | 40 +++++++++++----------- .../ethernet/marvell/octeontx2/nic/cn10k_macsec.c | 38 ++++++++++---------- .../ethernet/mellanox/mlx5/core/en_accel/macsec.c | 9 ----- include/net/macsec.h | 10 ++++++ 4 files changed, 49 insertions(+), 48 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c b/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c index 7eb5851eb95d..6afff8af5e86 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_macsec.c @@ -289,7 +289,7 @@ static int aq_get_txsc_stats(struct aq_hw_s *hw, const int sc_idx, static int aq_mdo_dev_open(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); int ret = 0; if (netif_carrier_ok(nic->ndev)) @@ -300,7 +300,7 @@ static int aq_mdo_dev_open(struct macsec_context *ctx) static int aq_mdo_dev_stop(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); int i; for (i = 0; i < AQ_MACSEC_MAX_SC; i++) { @@ -439,7 +439,7 @@ static enum aq_macsec_sc_sa sc_sa_from_num_an(const int num_an) static int aq_mdo_add_secy(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; const struct macsec_secy *secy = ctx->secy; enum aq_macsec_sc_sa sc_sa; @@ -474,7 +474,7 @@ static int aq_mdo_add_secy(struct macsec_context *ctx) static int aq_mdo_upd_secy(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); const struct macsec_secy *secy = ctx->secy; int txsc_idx; int ret = 0; @@ -528,7 +528,7 @@ static int aq_clear_txsc(struct aq_nic_s *nic, const int txsc_idx, static int aq_mdo_del_secy(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); int ret = 0; if (!nic->macsec_cfg) @@ -576,7 +576,7 @@ static int aq_update_txsa(struct aq_nic_s *nic, const unsigned int sc_idx, static int aq_mdo_add_txsa(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; const struct macsec_secy *secy = ctx->secy; struct aq_macsec_txsc *aq_txsc; @@ -603,7 +603,7 @@ static int aq_mdo_add_txsa(struct macsec_context *ctx) static int aq_mdo_upd_txsa(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; const struct macsec_secy *secy = ctx->secy; struct aq_macsec_txsc *aq_txsc; @@ -652,7 +652,7 @@ static int aq_clear_txsa(struct aq_nic_s *nic, struct aq_macsec_txsc *aq_txsc, static int aq_mdo_del_txsa(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; int txsc_idx; int ret = 0; @@ -744,7 +744,7 @@ static int aq_set_rxsc(struct aq_nic_s *nic, const u32 rxsc_idx) static int aq_mdo_add_rxsc(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; const u32 rxsc_idx_max = aq_sc_idx_max(cfg->sc_sa); u32 rxsc_idx; @@ -775,7 +775,7 @@ static int aq_mdo_add_rxsc(struct macsec_context *ctx) static int aq_mdo_upd_rxsc(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); int rxsc_idx; int ret = 0; @@ -838,7 +838,7 @@ static int aq_clear_rxsc(struct aq_nic_s *nic, const int rxsc_idx, static int aq_mdo_del_rxsc(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); enum aq_clear_type clear_type = AQ_CLEAR_SW; int rxsc_idx; int ret = 0; @@ -906,8 +906,8 @@ static int aq_update_rxsa(struct aq_nic_s *nic, const unsigned int sc_idx, static int aq_mdo_add_rxsa(struct macsec_context *ctx) { + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc; - struct aq_nic_s *nic = netdev_priv(ctx->netdev); const struct macsec_secy *secy = ctx->secy; struct aq_macsec_rxsc *aq_rxsc; int rxsc_idx; @@ -933,8 +933,8 @@ static int aq_mdo_add_rxsa(struct macsec_context *ctx) static int aq_mdo_upd_rxsa(struct macsec_context *ctx) { + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc; - struct aq_nic_s *nic = netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; const struct macsec_secy *secy = ctx->secy; int rxsc_idx; @@ -982,8 +982,8 @@ static int aq_clear_rxsa(struct aq_nic_s *nic, struct aq_macsec_rxsc *aq_rxsc, static int aq_mdo_del_rxsa(struct macsec_context *ctx) { + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); const struct macsec_rx_sc *rx_sc = ctx->sa.rx_sa->sc; - struct aq_nic_s *nic = netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; int rxsc_idx; int ret = 0; @@ -1000,7 +1000,7 @@ static int aq_mdo_del_rxsa(struct macsec_context *ctx) static int aq_mdo_get_dev_stats(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_common_stats *stats = &nic->macsec_cfg->stats; struct aq_hw_s *hw = nic->aq_hw; @@ -1020,7 +1020,7 @@ static int aq_mdo_get_dev_stats(struct macsec_context *ctx) static int aq_mdo_get_tx_sc_stats(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_tx_sc_stats *stats; struct aq_hw_s *hw = nic->aq_hw; struct aq_macsec_txsc *aq_txsc; @@ -1044,7 +1044,7 @@ static int aq_mdo_get_tx_sc_stats(struct macsec_context *ctx) static int aq_mdo_get_tx_sa_stats(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; struct aq_macsec_tx_sa_stats *stats; struct aq_hw_s *hw = nic->aq_hw; @@ -1084,7 +1084,7 @@ static int aq_mdo_get_tx_sa_stats(struct macsec_context *ctx) static int aq_mdo_get_rx_sc_stats(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; struct aq_macsec_rx_sa_stats *stats; struct aq_hw_s *hw = nic->aq_hw; @@ -1129,7 +1129,7 @@ static int aq_mdo_get_rx_sc_stats(struct macsec_context *ctx) static int aq_mdo_get_rx_sa_stats(struct macsec_context *ctx) { - struct aq_nic_s *nic = netdev_priv(ctx->netdev); + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); struct aq_macsec_cfg *cfg = nic->macsec_cfg; struct aq_macsec_rx_sa_stats *stats; struct aq_hw_s *hw = nic->aq_hw; @@ -1399,7 +1399,7 @@ static void aq_check_txsa_expiration(struct aq_nic_s *nic) #define AQ_LOCKED_MDO_DEF(mdo) \ static int aq_locked_mdo_##mdo(struct macsec_context *ctx) \ { \ - struct aq_nic_s *nic = netdev_priv(ctx->netdev); \ + struct aq_nic_s *nic = macsec_netdev_priv(ctx->netdev); \ int ret; \ mutex_lock(&nic->macsec_mutex); \ ret = aq_mdo_##mdo(ctx); \ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c index a487a98eac88..aea4c802bb9d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c @@ -1053,7 +1053,7 @@ static void cn10k_mcs_sync_stats(struct otx2_nic *pfvf, struct macsec_secy *secy static int cn10k_mdo_open(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; struct macsec_tx_sa *sw_tx_sa; @@ -1077,7 +1077,7 @@ static int cn10k_mdo_open(struct macsec_context *ctx) static int cn10k_mdo_stop(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct cn10k_mcs_txsc *txsc; int err; @@ -1095,7 +1095,7 @@ static int cn10k_mdo_stop(struct macsec_context *ctx) static int cn10k_mdo_add_secy(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; struct cn10k_mcs_txsc *txsc; @@ -1129,7 +1129,7 @@ static int cn10k_mdo_add_secy(struct macsec_context *ctx) static int cn10k_mdo_upd_secy(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; struct macsec_tx_sa *sw_tx_sa; @@ -1164,7 +1164,7 @@ static int cn10k_mdo_upd_secy(struct macsec_context *ctx) static int cn10k_mdo_del_secy(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct cn10k_mcs_txsc *txsc; @@ -1183,7 +1183,7 @@ static int cn10k_mdo_del_secy(struct macsec_context *ctx) static int cn10k_mdo_add_txsa(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct macsec_tx_sa *sw_tx_sa = ctx->sa.tx_sa; struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; @@ -1225,7 +1225,7 @@ static int cn10k_mdo_add_txsa(struct macsec_context *ctx) static int cn10k_mdo_upd_txsa(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct macsec_tx_sa *sw_tx_sa = ctx->sa.tx_sa; struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; @@ -1258,7 +1258,7 @@ static int cn10k_mdo_upd_txsa(struct macsec_context *ctx) static int cn10k_mdo_del_txsa(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; u8 sa_num = ctx->sa.assoc_num; struct cn10k_mcs_txsc *txsc; @@ -1278,7 +1278,7 @@ static int cn10k_mdo_del_txsa(struct macsec_context *ctx) static int cn10k_mdo_add_rxsc(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; struct cn10k_mcs_rxsc *rxsc; @@ -1312,7 +1312,7 @@ static int cn10k_mdo_add_rxsc(struct macsec_context *ctx) static int cn10k_mdo_upd_rxsc(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; bool enable = ctx->rx_sc->active; @@ -1331,7 +1331,7 @@ static int cn10k_mdo_upd_rxsc(struct macsec_context *ctx) static int cn10k_mdo_del_rxsc(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct cn10k_mcs_rxsc *rxsc; @@ -1349,8 +1349,8 @@ static int cn10k_mdo_del_rxsc(struct macsec_context *ctx) static int cn10k_mdo_add_rxsa(struct macsec_context *ctx) { + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct macsec_rx_sc *sw_rx_sc = ctx->sa.rx_sa->sc; - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa; u64 next_pn = rx_sa->next_pn_halves.lower; @@ -1389,8 +1389,8 @@ static int cn10k_mdo_add_rxsa(struct macsec_context *ctx) static int cn10k_mdo_upd_rxsa(struct macsec_context *ctx) { + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct macsec_rx_sc *sw_rx_sc = ctx->sa.rx_sa->sc; - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa; u64 next_pn = rx_sa->next_pn_halves.lower; @@ -1422,8 +1422,8 @@ static int cn10k_mdo_upd_rxsa(struct macsec_context *ctx) static int cn10k_mdo_del_rxsa(struct macsec_context *ctx) { + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct macsec_rx_sc *sw_rx_sc = ctx->sa.rx_sa->sc; - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; u8 sa_num = ctx->sa.assoc_num; struct cn10k_mcs_rxsc *rxsc; @@ -1445,8 +1445,8 @@ static int cn10k_mdo_del_rxsa(struct macsec_context *ctx) static int cn10k_mdo_get_dev_stats(struct macsec_context *ctx) { + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct mcs_secy_stats tx_rsp = { 0 }, rx_rsp = { 0 }; - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; struct cn10k_mcs_txsc *txsc; @@ -1481,7 +1481,7 @@ static int cn10k_mdo_get_dev_stats(struct macsec_context *ctx) static int cn10k_mdo_get_tx_sc_stats(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct mcs_sc_stats rsp = { 0 }; struct cn10k_mcs_txsc *txsc; @@ -1502,7 +1502,7 @@ static int cn10k_mdo_get_tx_sc_stats(struct macsec_context *ctx) static int cn10k_mdo_get_tx_sa_stats(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct mcs_sa_stats rsp = { 0 }; u8 sa_num = ctx->sa.assoc_num; @@ -1525,7 +1525,7 @@ static int cn10k_mdo_get_tx_sa_stats(struct macsec_context *ctx) static int cn10k_mdo_get_rx_sc_stats(struct macsec_context *ctx) { - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_secy *secy = ctx->secy; struct mcs_sc_stats rsp = { 0 }; @@ -1567,8 +1567,8 @@ static int cn10k_mdo_get_rx_sc_stats(struct macsec_context *ctx) static int cn10k_mdo_get_rx_sa_stats(struct macsec_context *ctx) { + struct otx2_nic *pfvf = macsec_netdev_priv(ctx->netdev); struct macsec_rx_sc *sw_rx_sc = ctx->sa.rx_sa->sc; - struct otx2_nic *pfvf = netdev_priv(ctx->netdev); struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct mcs_sa_stats rsp = { 0 }; u8 sa_num = ctx->sa.assoc_num; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c index 6b7b563f844a..592b165530ff 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c @@ -349,15 +349,6 @@ static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec, sa->macsec_rule = NULL; } -static struct mlx5e_priv *macsec_netdev_priv(const struct net_device *dev) -{ -#if IS_ENABLED(CONFIG_VLAN_8021Q) - if (is_vlan_dev(dev)) - return netdev_priv(vlan_dev_priv(dev)->real_dev); -#endif - return netdev_priv(dev); -} - static int mlx5e_macsec_init_sa(struct macsec_context *ctx, struct mlx5e_macsec_sa *sa, bool encrypt, diff --git a/include/net/macsec.h b/include/net/macsec.h index 5b9c61c4d3a6..441ed8fd4b5f 100644 --- a/include/net/macsec.h +++ b/include/net/macsec.h @@ -8,6 +8,7 @@ #define _NET_MACSEC_H_ #include +#include #include #include @@ -312,4 +313,13 @@ static inline bool macsec_send_sci(const struct macsec_secy *secy) (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb); } +static inline void *macsec_netdev_priv(const struct net_device *dev) +{ +#if IS_ENABLED(CONFIG_VLAN_8021Q) + if (is_vlan_dev(dev)) + return netdev_priv(vlan_dev_priv(dev)->real_dev); +#endif + return netdev_priv(dev); +} + #endif /* _NET_MACSEC_H_ */ -- cgit v1.2.3 From 6096bc0555726c1cdded8486d8800cd4d81eb764 Mon Sep 17 00:00:00 2001 From: wuych Date: Wed, 10 May 2023 14:06:49 +0800 Subject: net: liquidio: lio_vf_main: Remove unnecessary (void*) conversions Pointer variables of void * type do not require type cast. Signed-off-by: wuych Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_vf_main.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index e2921aec3da0..62c2eadc33e3 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -72,8 +72,7 @@ static int liquidio_stop(struct net_device *netdev); static int lio_wait_for_oq_pkts(struct octeon_device *oct) { - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; int retry = MAX_IO_PENDING_PKT_COUNT; int pkt_cnt = 0, pending_pkts; int i; @@ -442,8 +441,7 @@ static void octeon_pci_flr(struct octeon_device *oct) */ static void octeon_destroy_resources(struct octeon_device *oct) { - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; struct msix_entry *msix_entries; int i; @@ -659,8 +657,7 @@ static int send_rx_ctrl_cmd(struct lio *lio, int start_stop) static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx) { struct net_device *netdev = oct->props[ifidx].netdev; - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; struct napi_struct *napi, *n; struct lio *lio; @@ -909,8 +906,7 @@ static int liquidio_open(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; struct napi_struct *napi, *n; int ret = 0; @@ -956,8 +952,7 @@ static int liquidio_stop(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; struct napi_struct *napi, *n; int ret = 0; -- cgit v1.2.3 From 059fa492027e99c167f4c53822c0900ca9bc254a Mon Sep 17 00:00:00 2001 From: "Ilia.Gavrilov" Date: Wed, 10 May 2023 09:23:40 +0000 Subject: sctp: fix a potential OOB access in sctp_sched_set_sched() The 'sched' index value must be checked before accessing an element of the 'sctp_sched_ops' array. Otherwise, it can lead to OOB access. Note that it's harmless since the 'sched' parameter is checked before calling 'sctp_sched_set_sched'. Found by InfoTeCS on behalf of Linux Verification Center (linuxtesting.org) with SVACE. Acked-by: Marcelo Ricardo Leitner Reviewed-by: Xin Long Reviewed-by: Simon Horman Signed-off-by: Ilia.Gavrilov Signed-off-by: David S. Miller --- net/sctp/stream_sched.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/sctp/stream_sched.c b/net/sctp/stream_sched.c index e843760e9aaa..54afbe4fb087 100644 --- a/net/sctp/stream_sched.c +++ b/net/sctp/stream_sched.c @@ -148,18 +148,19 @@ static void sctp_sched_free_sched(struct sctp_stream *stream) int sctp_sched_set_sched(struct sctp_association *asoc, enum sctp_sched_type sched) { - struct sctp_sched_ops *n = sctp_sched_ops[sched]; struct sctp_sched_ops *old = asoc->outqueue.sched; struct sctp_datamsg *msg = NULL; + struct sctp_sched_ops *n; struct sctp_chunk *ch; int i, ret = 0; - if (old == n) - return ret; - if (sched > SCTP_SS_MAX) return -EINVAL; + n = sctp_sched_ops[sched]; + if (old == n) + return ret; + if (old) sctp_sched_free_sched(&asoc->stream); -- cgit v1.2.3 From 796fb97a8cd9f893026458d606a270d4d5799543 Mon Sep 17 00:00:00 2001 From: M Chetan Kumar Date: Tue, 9 May 2023 22:05:55 +0530 Subject: net: wwan: iosm: remove unused macro definition IOSM_IF_ID_PAYLOAD is defined but not used. Remove it to avoid unexpected usage. Signed-off-by: M Chetan Kumar Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/0697e811cb7f10b4fd8f99e66bda1329efdd3d1d.1683649868.git.m.chetan.kumar@linux.intel.com Signed-off-by: Jakub Kicinski --- drivers/net/wwan/iosm/iosm_ipc_wwan.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wwan/iosm/iosm_ipc_wwan.c b/drivers/net/wwan/iosm/iosm_ipc_wwan.c index 4c9022a93e01..ff747fc79aaf 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_wwan.c +++ b/drivers/net/wwan/iosm/iosm_ipc_wwan.c @@ -18,8 +18,6 @@ #define IOSM_IP_TYPE_IPV4 0x40 #define IOSM_IP_TYPE_IPV6 0x60 -#define IOSM_IF_ID_PAYLOAD 2 - /** * struct iosm_netdev_priv - netdev WWAN driver specific private data * @ipc_wwan: Pointer to iosm_wwan struct -- cgit v1.2.3 From c930192572db454371764f1efa81be9ff14e6961 Mon Sep 17 00:00:00 2001 From: M Chetan Kumar Date: Tue, 9 May 2023 22:06:22 +0530 Subject: net: wwan: iosm: remove unused enum definition ipc_time_unit enum is defined but not used. Remove it to avoid unexpected usage. Signed-off-by: M Chetan Kumar Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/8295a6138f13c686590ee4021384ee992f717408.1683649868.git.m.chetan.kumar@linux.intel.com Signed-off-by: Jakub Kicinski --- drivers/net/wwan/iosm/iosm_ipc_imem.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem.h b/drivers/net/wwan/iosm/iosm_ipc_imem.h index e700dc8bfe0a..93d57aa7854a 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem.h +++ b/drivers/net/wwan/iosm/iosm_ipc_imem.h @@ -140,17 +140,6 @@ enum ipc_channel_state { IMEM_CHANNEL_CLOSING, }; -/* Time Unit */ -enum ipc_time_unit { - IPC_SEC = 0, - IPC_MILLI_SEC = 1, - IPC_MICRO_SEC = 2, - IPC_NANO_SEC = 3, - IPC_PICO_SEC = 4, - IPC_FEMTO_SEC = 5, - IPC_ATTO_SEC = 6, -}; - /** * enum ipc_ctype - Enum defining supported channel type needed for control * /IP traffic. -- cgit v1.2.3 From 8a690c151134df1ac8d71db4370b71f132d0fba6 Mon Sep 17 00:00:00 2001 From: M Chetan Kumar Date: Tue, 9 May 2023 22:06:35 +0530 Subject: net: wwan: iosm: clean up unused struct members Below members are unused. - td_tag member defined in struct ipc_pipe. - adb_finish_timer & params defined in struct iosm_mux. Remove it to avoid unexpected usage. Signed-off-by: M Chetan Kumar Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/92ee483d79dfc871ed7408da8fec60b395ff3a9c.1683649868.git.m.chetan.kumar@linux.intel.com Signed-off-by: Jakub Kicinski --- drivers/net/wwan/iosm/iosm_ipc_imem.h | 2 -- drivers/net/wwan/iosm/iosm_ipc_mux.h | 4 ---- 2 files changed, 6 deletions(-) diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem.h b/drivers/net/wwan/iosm/iosm_ipc_imem.h index 93d57aa7854a..5664ac507c90 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem.h +++ b/drivers/net/wwan/iosm/iosm_ipc_imem.h @@ -193,7 +193,6 @@ enum ipc_hp_identifier { * @pipe_nr: Pipe identification number * @irq: Interrupt vector * @dir: Direction of data stream in pipe - * @td_tag: Unique tag of the buffer queued * @buf_size: Buffer size (in bytes) for preallocated * buffers (for DL pipes) * @nr_of_queued_entries: Aueued number of entries @@ -213,7 +212,6 @@ struct ipc_pipe { u32 pipe_nr; u32 irq; enum ipc_mem_pipe_dir dir; - u32 td_tag; u32 buf_size; u16 nr_of_queued_entries; u8 is_open:1; diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux.h b/drivers/net/wwan/iosm/iosm_ipc_mux.h index 9968bb885c1f..17ca8d1f9397 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_mux.h +++ b/drivers/net/wwan/iosm/iosm_ipc_mux.h @@ -333,9 +333,7 @@ struct mux_acb { * @wwan_q_offset: This will hold the offset of the given instance * Useful while passing or receiving packets from * wwan/imem layer. - * @adb_finish_timer: Timer for forcefully finishing the ADB * @acb_tx_sequence_nr: Sequence number for the ACB header. - * @params: user configurable parameters * @adb_tx_sequence_nr: Sequence number for ADB header * @acc_adb_size: Statistic data for logging * @acc_payload_size: Statistic data for logging @@ -367,9 +365,7 @@ struct iosm_mux { long long ul_data_pend_bytes; struct mux_acb acb; int wwan_q_offset; - struct hrtimer adb_finish_timer; u16 acb_tx_sequence_nr; - struct ipc_params *params; u16 adb_tx_sequence_nr; unsigned long long acc_adb_size; unsigned long long acc_payload_size; -- cgit v1.2.3 From ccce324dabfe2143519daf50ed8b1ef1d0c542f7 Mon Sep 17 00:00:00 2001 From: David Morley Date: Tue, 9 May 2023 18:05:58 +0000 Subject: tcp: make the first N SYN RTO backoffs linear Currently the SYN RTO schedule follows an exponential backoff scheme, which can be unnecessarily conservative in cases where there are link failures. In such cases, it's better to aggressively try to retransmit packets, so it takes routers less time to find a repath with a working link. We chose a default value for this sysctl of 4, to follow the macOS and IOS backoff scheme of 1,1,1,1,1,2,4,8, ... MacOS and IOS have used this backoff schedule for over a decade, since before this 2009 IETF presentation discussed the behavior: https://www.ietf.org/proceedings/75/slides/tcpm-1.pdf This commit makes the SYN RTO schedule start with a number of linear backoffs given by the following sysctl: * tcp_syn_linear_timeouts This changes the SYN RTO scheme to be: init_rto_val for tcp_syn_linear_timeouts, exp backoff starting at init_rto_val For example if init_rto_val = 1 and tcp_syn_linear_timeouts = 2, our backoff scheme would be: 1, 1, 1, 2, 4, 8, 16, ... Signed-off-by: David Morley Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Tested-by: David Morley Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20230509180558.2541885-1-morleyd.kernel@gmail.com Signed-off-by: Paolo Abeni --- Documentation/networking/ip-sysctl.rst | 17 ++++++++++++++--- include/net/netns/ipv4.h | 1 + net/ipv4/sysctl_net_ipv4.c | 10 ++++++++++ net/ipv4/tcp_ipv4.c | 1 + net/ipv4/tcp_timer.c | 17 +++++++++++++---- 5 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 6ec06a33688a..3f6d3d5f5626 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -881,9 +881,10 @@ tcp_fastopen_key - list of comma separated 32-digit hexadecimal INTEGERs tcp_syn_retries - INTEGER Number of times initial SYNs for an active TCP connection attempt will be retransmitted. Should not be higher than 127. Default value - is 6, which corresponds to 63seconds till the last retransmission - with the current initial RTO of 1second. With this the final timeout - for an active TCP connection attempt will happen after 127seconds. + is 6, which corresponds to 67seconds (with tcp_syn_linear_timeouts = 4) + till the last retransmission with the current initial RTO of 1second. + With this the final timeout for an active TCP connection attempt + will happen after 131seconds. tcp_timestamps - INTEGER Enable timestamps as defined in RFC1323. @@ -946,6 +947,16 @@ tcp_pacing_ca_ratio - INTEGER Default: 120 +tcp_syn_linear_timeouts - INTEGER + The number of times for an active TCP connection to retransmit SYNs with + a linear backoff timeout before defaulting to an exponential backoff + timeout. This has no effect on SYNACK at the passive TCP side. + + With an initial RTO of 1 and tcp_syn_linear_timeouts = 4 we would + expect SYN RTOs to be: 1, 1, 1, 1, 1, 2, 4, ... (4 linear timeouts, + and the first exponential backoff using 2^0 * initial_RTO). + Default: 4 + tcp_tso_win_divisor - INTEGER This allows control over what percentage of the congestion window can be consumed by a single TSO frame. diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index db762e35aca9..a4efb7a2796c 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -194,6 +194,7 @@ struct netns_ipv4 { int sysctl_udp_rmem_min; u8 sysctl_fib_notify_on_flag_change; + u8 sysctl_tcp_syn_linear_timeouts; #ifdef CONFIG_NET_L3_MASTER_DEV u8 sysctl_udp_l3mdev_accept; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 40fe70fc2015..6ae3345a3bdf 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -34,6 +34,7 @@ static int ip_ttl_min = 1; static int ip_ttl_max = 255; static int tcp_syn_retries_min = 1; static int tcp_syn_retries_max = MAX_TCP_SYNCNT; +static int tcp_syn_linear_timeouts_max = MAX_TCP_SYNCNT; static int ip_ping_group_range_min[] = { 0, 0 }; static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX }; static u32 u32_max_div_HZ = UINT_MAX / HZ; @@ -1470,6 +1471,15 @@ static struct ctl_table ipv4_net_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = &tcp_plb_max_cong_thresh, }, + { + .procname = "tcp_syn_linear_timeouts", + .data = &init_net.ipv4.sysctl_tcp_syn_linear_timeouts, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = &tcp_syn_linear_timeouts_max, + }, { } }; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 39bda2b1066e..db24ed8f8509 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3275,6 +3275,7 @@ static int __net_init tcp_sk_init(struct net *net) else net->ipv4.tcp_congestion_control = &tcp_reno; + net->ipv4.sysctl_tcp_syn_linear_timeouts = 4; return 0; } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index b839c2f91292..0d93a2573807 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -234,14 +234,19 @@ static int tcp_write_timeout(struct sock *sk) struct tcp_sock *tp = tcp_sk(sk); struct net *net = sock_net(sk); bool expired = false, do_reset; - int retry_until; + int retry_until, max_retransmits; if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { if (icsk->icsk_retransmits) __dst_negative_advice(sk); retry_until = icsk->icsk_syn_retries ? : READ_ONCE(net->ipv4.sysctl_tcp_syn_retries); - expired = icsk->icsk_retransmits >= retry_until; + + max_retransmits = retry_until; + if (sk->sk_state == TCP_SYN_SENT) + max_retransmits += READ_ONCE(net->ipv4.sysctl_tcp_syn_linear_timeouts); + + expired = icsk->icsk_retransmits >= max_retransmits; } else { if (retransmits_timed_out(sk, READ_ONCE(net->ipv4.sysctl_tcp_retries1), 0)) { /* Black hole detection */ @@ -577,8 +582,12 @@ out_reset_timer: icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) { icsk->icsk_backoff = 0; icsk->icsk_rto = min(__tcp_set_rto(tp), TCP_RTO_MAX); - } else { - /* Use normal (exponential) backoff */ + } else if (sk->sk_state != TCP_SYN_SENT || + icsk->icsk_backoff > + READ_ONCE(net->ipv4.sysctl_tcp_syn_linear_timeouts)) { + /* Use normal (exponential) backoff unless linear timeouts are + * activated. + */ icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); } inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, -- cgit v1.2.3 From fef99e840d465bad6549dd8775a5f967a711d171 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 10 May 2023 11:15:42 +0100 Subject: net: mvneta: fix transmit path dma-unmapping on error The transmit code assumes that the transmit descriptors that are used begin with the first descriptor in the ring, but this may not be the case. Fix this by providing a new function that dma-unmaps a range of numbered descriptor entries, and use that to do the unmapping. Signed-off-by: Russell King (Oracle) Reviewed-by: Eric Dumazet Signed-off-by: Paolo Abeni --- drivers/net/ethernet/marvell/mvneta.c | 53 ++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 2cad76d0a50e..62400ff61e34 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2714,14 +2714,40 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq, return 0; } +static void mvneta_release_descs(struct mvneta_port *pp, + struct mvneta_tx_queue *txq, + int first, int num) +{ + int desc_idx, i; + + desc_idx = first + num; + if (desc_idx >= txq->size) + desc_idx -= txq->size; + + for (i = num; i >= 0; i--) { + struct mvneta_tx_desc *tx_desc = txq->descs + desc_idx; + + if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr)) + dma_unmap_single(pp->dev->dev.parent, + tx_desc->buf_phys_addr, + tx_desc->data_size, + DMA_TO_DEVICE); + + mvneta_txq_desc_put(txq); + + if (desc_idx == 0) + desc_idx = txq->size; + desc_idx -= 1; + } +} + static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev, struct mvneta_tx_queue *txq) { int hdr_len, total_len, data_left; - int desc_count = 0; + int first_desc, desc_count = 0; struct mvneta_port *pp = netdev_priv(dev); struct tso_t tso; - int i; /* Count needed descriptors */ if ((txq->count + tso_count_descs(skb)) >= txq->size) @@ -2732,6 +2758,8 @@ static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev, return 0; } + first_desc = txq->txq_put_index; + /* Initialize the TSO handler, and prepare the first payload */ hdr_len = tso_start(skb, &tso); @@ -2772,15 +2800,7 @@ err_release: /* Release all used data descriptors; header descriptors must not * be DMA-unmapped. */ - for (i = desc_count - 1; i >= 0; i--) { - struct mvneta_tx_desc *tx_desc = txq->descs + i; - if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr)) - dma_unmap_single(pp->dev->dev.parent, - tx_desc->buf_phys_addr, - tx_desc->data_size, - DMA_TO_DEVICE); - mvneta_txq_desc_put(txq); - } + mvneta_release_descs(pp, txq, first_desc, desc_count - 1); return 0; } @@ -2790,6 +2810,7 @@ static int mvneta_tx_frag_process(struct mvneta_port *pp, struct sk_buff *skb, { struct mvneta_tx_desc *tx_desc; int i, nr_frags = skb_shinfo(skb)->nr_frags; + int first_desc = txq->txq_put_index; for (i = 0; i < nr_frags; i++) { struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; @@ -2828,15 +2849,7 @@ error: /* Release all descriptors that were used to map fragments of * this packet, as well as the corresponding DMA mappings */ - for (i = i - 1; i >= 0; i--) { - tx_desc = txq->descs + i; - dma_unmap_single(pp->dev->dev.parent, - tx_desc->buf_phys_addr, - tx_desc->data_size, - DMA_TO_DEVICE); - mvneta_txq_desc_put(txq); - } - + mvneta_release_descs(pp, txq, first_desc, i - 1); return -ENOMEM; } -- cgit v1.2.3 From b0bd1b07c3add928e33282a52ad64a3f011d4fb7 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 10 May 2023 11:15:48 +0100 Subject: net: mvneta: mark mapped and tso buffers separately Mark dma-mapped skbs and TSO buffers separately, so we can use buf->type to identify their differences. Signed-off-by: Russell King (Oracle) Reviewed-by: Eric Dumazet Signed-off-by: Paolo Abeni --- drivers/net/ethernet/marvell/mvneta.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 62400ff61e34..c05649f33d18 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -638,6 +638,7 @@ struct mvneta_rx_desc { #endif enum mvneta_tx_buf_type { + MVNETA_TYPE_TSO, MVNETA_TYPE_SKB, MVNETA_TYPE_XDP_TX, MVNETA_TYPE_XDP_NDO, @@ -1883,7 +1884,8 @@ static void mvneta_txq_bufs_free(struct mvneta_port *pp, dma_unmap_single(pp->dev->dev.parent, tx_desc->buf_phys_addr, tx_desc->data_size, DMA_TO_DEVICE); - if (buf->type == MVNETA_TYPE_SKB && buf->skb) { + if ((buf->type == MVNETA_TYPE_TSO || + buf->type == MVNETA_TYPE_SKB) && buf->skb) { bytes_compl += buf->skb->len; pkts_compl++; dev_kfree_skb_any(buf->skb); @@ -2674,7 +2676,7 @@ mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq) tx_desc->command |= MVNETA_TXD_F_DESC; tx_desc->buf_phys_addr = txq->tso_hdrs_phys + txq->txq_put_index * TSO_HEADER_SIZE; - buf->type = MVNETA_TYPE_SKB; + buf->type = MVNETA_TYPE_TSO; buf->skb = NULL; mvneta_txq_inc_put(txq); -- cgit v1.2.3 From f00ba4f41acc050c959803f290a0f0c03dc0da5c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 10 May 2023 11:15:53 +0100 Subject: net: mvneta: use buf->type to determine whether to dma-unmap Now that we use a different buffer type for TSO headers, we can use buf->type to determine whether the original buffer was DMA-mapped or not. The rules are: MVNETA_TYPE_XDP_TX - from a DMA pool, no unmap is required MVNETA_TYPE_XDP_NDO - dma_map_single()'d MVNETA_TYPE_SKB - normal skbuff, dma_map_single()'d MVNETA_TYPE_TSO - from the TSO buffer area This means we only need to call dma_unmap_single() on the XDP_NDO and SKB types of buffer, and we no longer need the private IS_TSO_HEADER() which relies on the TSO region being contiguously allocated. Signed-off-by: Russell King (Oracle) Reviewed-by: Eric Dumazet Signed-off-by: Paolo Abeni --- drivers/net/ethernet/marvell/mvneta.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index c05649f33d18..c23d75af65ee 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -364,10 +364,6 @@ MVNETA_SKB_HEADROOM)) #define MVNETA_MAX_RX_BUF_SIZE (PAGE_SIZE - MVNETA_SKB_PAD) -#define IS_TSO_HEADER(txq, addr) \ - ((addr >= txq->tso_hdrs_phys) && \ - (addr < txq->tso_hdrs_phys + txq->size * TSO_HEADER_SIZE)) - #define MVNETA_RX_GET_BM_POOL_ID(rxd) \ (((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT) @@ -1879,8 +1875,8 @@ static void mvneta_txq_bufs_free(struct mvneta_port *pp, mvneta_txq_inc_get(txq); - if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr) && - buf->type != MVNETA_TYPE_XDP_TX) + if (buf->type == MVNETA_TYPE_XDP_NDO || + buf->type == MVNETA_TYPE_SKB) dma_unmap_single(pp->dev->dev.parent, tx_desc->buf_phys_addr, tx_desc->data_size, DMA_TO_DEVICE); @@ -2728,8 +2724,9 @@ static void mvneta_release_descs(struct mvneta_port *pp, for (i = num; i >= 0; i--) { struct mvneta_tx_desc *tx_desc = txq->descs + desc_idx; + struct mvneta_tx_buf *buf = &txq->buf[desc_idx]; - if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr)) + if (buf->type == MVNETA_TYPE_SKB) dma_unmap_single(pp->dev->dev.parent, tx_desc->buf_phys_addr, tx_desc->data_size, -- cgit v1.2.3 From d41eb5557668096b0a57646107e6fc4631ba9cf1 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 10 May 2023 11:15:58 +0100 Subject: net: mvneta: move tso_build_hdr() into mvneta_tso_put_hdr() Move tso_build_hdr() into mvneta_tso_put_hdr() so that all the TSO header building code is in one place. Signed-off-by: Russell King (Oracle) Reviewed-by: Eric Dumazet Signed-off-by: Paolo Abeni --- drivers/net/ethernet/marvell/mvneta.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index c23d75af65ee..bea84e86cf99 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2659,19 +2659,24 @@ err_drop_frame: return rx_done; } -static inline void -mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq) +static void mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq, + struct tso_t *tso, int size, bool is_last) { struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; - int hdr_len = skb_tcp_all_headers(skb); + int tso_offset, hdr_len = skb_tcp_all_headers(skb); struct mvneta_tx_desc *tx_desc; + char *hdr; + + tso_offset = txq->txq_put_index * TSO_HEADER_SIZE; + + hdr = txq->tso_hdrs + tso_offset; + tso_build_hdr(skb, hdr, tso, size, is_last); tx_desc = mvneta_txq_next_desc_get(txq); tx_desc->data_size = hdr_len; tx_desc->command = mvneta_skb_tx_csum(skb); tx_desc->command |= MVNETA_TXD_F_DESC; - tx_desc->buf_phys_addr = txq->tso_hdrs_phys + - txq->txq_put_index * TSO_HEADER_SIZE; + tx_desc->buf_phys_addr = txq->tso_hdrs_phys + tso_offset; buf->type = MVNETA_TYPE_TSO; buf->skb = NULL; @@ -2764,17 +2769,12 @@ static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev, total_len = skb->len - hdr_len; while (total_len > 0) { - char *hdr; - data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len); total_len -= data_left; desc_count++; /* prepare packet headers: MAC + IP + TCP */ - hdr = txq->tso_hdrs + txq->txq_put_index * TSO_HEADER_SIZE; - tso_build_hdr(skb, hdr, &tso, data_left, total_len == 0); - - mvneta_tso_put_hdr(skb, txq); + mvneta_tso_put_hdr(skb, txq, &tso, data_left, total_len == 0); while (data_left > 0) { int size; -- cgit v1.2.3 From 33f4cefb26e98c3cfe68ee7c88b766aa786b8733 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 10 May 2023 11:16:03 +0100 Subject: net: mvneta: allocate TSO header DMA memory in chunks Now that we no longer need to check whether the DMA address is within the TSO header DMA memory range for the queue, we can allocate the TSO header DMA memory in chunks rather than one contiguous order-6 chunk, which can stress the kernel's memory subsystems to allocate. Instead, use order-1 (8k) allocations, which will result in 32 order-1 pages containing 32 TSO headers. Signed-off-by: Russell King (Oracle) Reviewed-by: Eric Dumazet Signed-off-by: Paolo Abeni --- drivers/net/ethernet/marvell/mvneta.c | 88 ++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index bea84e86cf99..6c6b66d3ea6e 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -344,6 +344,15 @@ #define MVNETA_MAX_SKB_DESCS (MVNETA_MAX_TSO_SEGS * 2 + MAX_SKB_FRAGS) +/* The size of a TSO header page */ +#define MVNETA_TSO_PAGE_SIZE (2 * PAGE_SIZE) + +/* Number of TSO headers per page. This should be a power of 2 */ +#define MVNETA_TSO_PER_PAGE (MVNETA_TSO_PAGE_SIZE / TSO_HEADER_SIZE) + +/* Maximum number of TSO header pages */ +#define MVNETA_MAX_TSO_PAGES (MVNETA_MAX_TXD / MVNETA_TSO_PER_PAGE) + /* descriptor aligned size */ #define MVNETA_DESC_ALIGNED_SIZE 32 @@ -687,10 +696,10 @@ struct mvneta_tx_queue { int next_desc_to_proc; /* DMA buffers for TSO headers */ - char *tso_hdrs; + char *tso_hdrs[MVNETA_MAX_TSO_PAGES]; /* DMA address of TSO headers */ - dma_addr_t tso_hdrs_phys; + dma_addr_t tso_hdrs_phys[MVNETA_MAX_TSO_PAGES]; /* Affinity mask for CPUs*/ cpumask_t affinity_mask; @@ -2659,24 +2668,71 @@ err_drop_frame: return rx_done; } +static void mvneta_free_tso_hdrs(struct mvneta_port *pp, + struct mvneta_tx_queue *txq) +{ + struct device *dev = pp->dev->dev.parent; + int i; + + for (i = 0; i < MVNETA_MAX_TSO_PAGES; i++) { + if (txq->tso_hdrs[i]) { + dma_free_coherent(dev, MVNETA_TSO_PAGE_SIZE, + txq->tso_hdrs[i], + txq->tso_hdrs_phys[i]); + txq->tso_hdrs[i] = NULL; + } + } +} + +static int mvneta_alloc_tso_hdrs(struct mvneta_port *pp, + struct mvneta_tx_queue *txq) +{ + struct device *dev = pp->dev->dev.parent; + int i, num; + + num = DIV_ROUND_UP(txq->size, MVNETA_TSO_PER_PAGE); + for (i = 0; i < num; i++) { + txq->tso_hdrs[i] = dma_alloc_coherent(dev, MVNETA_TSO_PAGE_SIZE, + &txq->tso_hdrs_phys[i], + GFP_KERNEL); + if (!txq->tso_hdrs[i]) { + mvneta_free_tso_hdrs(pp, txq); + return -ENOMEM; + } + } + + return 0; +} + +static char *mvneta_get_tso_hdr(struct mvneta_tx_queue *txq, dma_addr_t *dma) +{ + int index, offset; + + index = txq->txq_put_index / MVNETA_TSO_PER_PAGE; + offset = (txq->txq_put_index % MVNETA_TSO_PER_PAGE) * TSO_HEADER_SIZE; + + *dma = txq->tso_hdrs_phys[index] + offset; + + return txq->tso_hdrs[index] + offset; +} + static void mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq, struct tso_t *tso, int size, bool is_last) { struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; - int tso_offset, hdr_len = skb_tcp_all_headers(skb); + int hdr_len = skb_tcp_all_headers(skb); struct mvneta_tx_desc *tx_desc; + dma_addr_t hdr_phys; char *hdr; - tso_offset = txq->txq_put_index * TSO_HEADER_SIZE; - - hdr = txq->tso_hdrs + tso_offset; + hdr = mvneta_get_tso_hdr(txq, &hdr_phys); tso_build_hdr(skb, hdr, tso, size, is_last); tx_desc = mvneta_txq_next_desc_get(txq); tx_desc->data_size = hdr_len; tx_desc->command = mvneta_skb_tx_csum(skb); tx_desc->command |= MVNETA_TXD_F_DESC; - tx_desc->buf_phys_addr = txq->tso_hdrs_phys + tso_offset; + tx_desc->buf_phys_addr = hdr_phys; buf->type = MVNETA_TYPE_TSO; buf->skb = NULL; @@ -3469,7 +3525,7 @@ static void mvneta_rxq_deinit(struct mvneta_port *pp, static int mvneta_txq_sw_init(struct mvneta_port *pp, struct mvneta_tx_queue *txq) { - int cpu; + int cpu, err; txq->size = pp->tx_ring_size; @@ -3494,11 +3550,9 @@ static int mvneta_txq_sw_init(struct mvneta_port *pp, return -ENOMEM; /* Allocate DMA buffers for TSO MAC/IP/TCP headers */ - txq->tso_hdrs = dma_alloc_coherent(pp->dev->dev.parent, - txq->size * TSO_HEADER_SIZE, - &txq->tso_hdrs_phys, GFP_KERNEL); - if (!txq->tso_hdrs) - return -ENOMEM; + err = mvneta_alloc_tso_hdrs(pp, txq); + if (err) + return err; /* Setup XPS mapping */ if (pp->neta_armada3700) @@ -3550,10 +3604,7 @@ static void mvneta_txq_sw_deinit(struct mvneta_port *pp, kfree(txq->buf); - if (txq->tso_hdrs) - dma_free_coherent(pp->dev->dev.parent, - txq->size * TSO_HEADER_SIZE, - txq->tso_hdrs, txq->tso_hdrs_phys); + mvneta_free_tso_hdrs(pp, txq); if (txq->descs) dma_free_coherent(pp->dev->dev.parent, txq->size * MVNETA_DESC_ALIGNED_SIZE, @@ -3562,7 +3613,6 @@ static void mvneta_txq_sw_deinit(struct mvneta_port *pp, netdev_tx_reset_queue(nq); txq->buf = NULL; - txq->tso_hdrs = NULL; txq->descs = NULL; txq->last_desc = 0; txq->next_desc_to_proc = 0; @@ -5833,6 +5883,8 @@ static int __init mvneta_driver_init(void) { int ret; + BUILD_BUG_ON_NOT_POWER_OF_2(MVNETA_TSO_PER_PAGE); + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "net/mvneta:online", mvneta_cpu_online, mvneta_cpu_down_prepare); -- cgit v1.2.3 From 9ce4bb09123e9754996e358bd808d39f5d112899 Mon Sep 17 00:00:00 2001 From: Amisha Patel Date: Fri, 21 Apr 2023 18:10:20 +0000 Subject: wifi: wilc1000: fix for absent RSN capabilities WFA testcase Mandatory WFA testcase CT_Security_WPA2Personal_STA_RSNEBoundsVerification-AbsentRSNCap, performs bounds verfication on Beacon and/or Probe response frames. It failed and observed the reason to be absence of cipher suite and AKM suite in RSN information. To fix this, enable the RSN flag before extracting RSN capabilities. Fixes: cd21d99e595e ("wifi: wilc1000: validate pairwise and authentication suite offsets") Signed-off-by: Amisha Patel Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230421181005.4865-1-amisha.patel@microchip.com --- drivers/net/wireless/microchip/wilc1000/hif.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index 5adc69d5bcae..a28da5938481 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -485,6 +485,9 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, int rsn_ie_len = sizeof(struct element) + rsn_ie[1]; int offset = 8; + param->mode_802_11i = 2; + param->rsn_found = true; + /* extract RSN capabilities */ if (offset < rsn_ie_len) { /* skip over pairwise suites */ @@ -494,11 +497,8 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, /* skip over authentication suites */ offset += (rsn_ie[offset] * 4) + 2; - if (offset + 1 < rsn_ie_len) { - param->mode_802_11i = 2; - param->rsn_found = true; + if (offset + 1 < rsn_ie_len) memcpy(param->rsn_cap, &rsn_ie[offset], 2); - } } } } -- cgit v1.2.3 From 7acd69507088b968beda8c2693591211fab333df Mon Sep 17 00:00:00 2001 From: Amisha Patel Date: Tue, 9 May 2023 17:29:08 +0000 Subject: wifi: wilc1000: Increase ASSOC response buffer In recent access points, information element is longer as they include additional data which exceeds 256 bytes. To accommodate longer association response, increase the ASSOC response buffer. Signed-off-by: Amisha Patel Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230509172811.4953-1-amisha.patel@microchip.com --- drivers/net/wireless/microchip/wilc1000/hif.h | 2 -- drivers/net/wireless/microchip/wilc1000/wlan_cfg.h | 2 +- drivers/net/wireless/microchip/wilc1000/wlan_if.h | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h index baa2881f4465..8e386db72e45 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.h +++ b/drivers/net/wireless/microchip/wilc1000/hif.h @@ -30,8 +30,6 @@ enum { WILC_GET_CFG }; -#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256 - struct rf_info { u8 link_speed; s8 rssi; diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h index 614c5673f232..7038b74f8e8f 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h @@ -30,7 +30,7 @@ struct wilc_cfg_str { struct wilc_cfg_str_vals { u8 mac_address[7]; u8 firmware_version[129]; - u8 assoc_rsp[256]; + u8 assoc_rsp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; }; struct wilc_cfg { diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_if.h b/drivers/net/wireless/microchip/wilc1000/wlan_if.h index df2f5a63bdf6..254a046e3b1b 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan_if.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan_if.h @@ -10,6 +10,8 @@ #include #include "fw.h" +#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 512 + /******************************************** * * Wlan Configuration ID -- cgit v1.2.3 From e2ff1181b3d48257aab26bfd2165f3c7d271499f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 3 May 2023 18:09:55 +0300 Subject: wifi: rtw88: unlock on error path in rtw_ops_add_interface() Call mutex_unlock(&rtwdev->mutex); before returning on this error path. Fixes: f0e741e4ddbc ("wifi: rtw88: add bitmap for dynamic port settings") Signed-off-by: Dan Carpenter Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/ddd10a74-5982-4f65-8c59-c1cca558d239@kili.mountain --- drivers/net/wireless/realtek/rtw88/mac80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 7aa6edad0d01..02cd19ee6e4c 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -173,8 +173,10 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); port = find_first_zero_bit(rtwdev->hw_port, RTW_PORT_NUM); - if (port >= RTW_PORT_NUM) + if (port >= RTW_PORT_NUM) { + mutex_unlock(&rtwdev->mutex); return -EINVAL; + } set_bit(port, rtwdev->hw_port); rtwvif->port = port; -- cgit v1.2.3 From d9aef04fcfa81ee4fb2804a21a3712b7bbd936af Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 May 2023 15:53:15 +0200 Subject: wifi: mwifiex: Fix the size of a memory allocation in mwifiex_ret_802_11_scan() The type of "mwifiex_adapter->nd_info" is "struct cfg80211_wowlan_nd_info", not "struct cfg80211_wowlan_nd_match". Use struct_size() to ease the computation of the needed size. The current code over-allocates some memory, so is safe. But it wastes 32 bytes. Fixes: 7d7f07d8c5d3 ("mwifiex: add wowlan net-detect support") Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/7a6074fb056d2181e058a3cc6048d8155c20aec7.1683371982.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/marvell/mwifiex/scan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index ac8001c84293..644b1e134b01 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -2187,9 +2187,9 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, if (nd_config) { adapter->nd_info = - kzalloc(sizeof(struct cfg80211_wowlan_nd_match) + - sizeof(struct cfg80211_wowlan_nd_match *) * - scan_rsp->number_of_sets, GFP_ATOMIC); + kzalloc(struct_size(adapter->nd_info, matches, + scan_rsp->number_of_sets), + GFP_ATOMIC); if (adapter->nd_info) adapter->nd_info->n_matches = scan_rsp->number_of_sets; -- cgit v1.2.3 From e897b0bef38a8b40101c0e6e009395506c256460 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Mon, 8 May 2023 16:12:09 +0800 Subject: wifi: rtw89: introduce realtek ACPI DSM method Introduce realtek ACPI DSM method to get required BIOS configurations. It will be used in the following commits. And, enum rtw89_acpi_dsm_func is added for listing the functions which are currently recognized. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230508081211.38760-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/Makefile | 3 +- drivers/net/wireless/realtek/rtw89/acpi.c | 52 +++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/acpi.h | 21 ++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/realtek/rtw89/acpi.c create mode 100644 drivers/net/wireless/realtek/rtw89/acpi.h diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index 2dc48fa10c6b..99e870d6a7d7 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -13,7 +13,8 @@ rtw89_core-y += core.o \ coex.o \ ps.o \ chan.o \ - ser.o + ser.o \ + acpi.o rtw89_core-$(CONFIG_PM) += wow.o diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c new file mode 100644 index 000000000000..8aaf83a2a6b4 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2021-2023 Realtek Corporation + */ + +#include +#include + +#include "acpi.h" +#include "debug.h" + +static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00, + 0x82, 0xBD, 0xFE, 0x86, + 0x07, 0x80, 0x3A, 0xA7); + +static int rtw89_acpi_dsm_get(struct rtw89_dev *rtwdev, union acpi_object *obj, + u8 *value) +{ + switch (obj->type) { + case ACPI_TYPE_INTEGER: + *value = (u8)obj->integer.value; + break; + case ACPI_TYPE_BUFFER: + *value = obj->buffer.pointer[0]; + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_UNEXP, + "acpi dsm return unhandled type: %d\n", obj->type); + return -EINVAL; + } + + return 0; +} + +int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, + enum rtw89_acpi_dsm_func func, u8 *value) +{ + union acpi_object *obj; + int ret; + + obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid, + 0, func, NULL); + if (!obj) { + rtw89_debug(rtwdev, RTW89_DBG_UNEXP, + "acpi dsm fail to evaluate func: %d\n", func); + return -ENOENT; + } + + ret = rtw89_acpi_dsm_get(rtwdev, obj, value); + + ACPI_FREE(obj); + return ret; +} diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h new file mode 100644 index 000000000000..ed74d8ceb733 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2021-2023 Realtek Corporation + */ + +#ifndef __RTW89_ACPI_H__ +#define __RTW89_ACPI_H__ + +#include "core.h" + +enum rtw89_acpi_dsm_func { + RTW89_ACPI_DSM_FUNC_IDN_BAND_SUP = 2, + RTW89_ACPI_DSM_FUNC_6G_DIS = 3, + RTW89_ACPI_DSM_FUNC_6G_BP = 4, + RTW89_ACPI_DSM_FUNC_TAS_EN = 5, + RTW89_ACPI_DSM_FUNC_59G_EN = 6, +}; + +int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, + enum rtw89_acpi_dsm_func func, u8 *value); + +#endif -- cgit v1.2.3 From a002f98123dd5e6b6d66c1b42a37dfd6e25ade4c Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Mon, 8 May 2023 16:12:10 +0800 Subject: wifi: rtw89: regd: judge UNII-4 according to BIOS and chip For realtek regulatory, there are following two kinds of configurations to determine whether to allow UNII-4 band, i.e. 5.9GHz channels. 1. default setting according to whether chip support it or not 2. evaluate realtek ACPI DSM with RTW89_ACPI_DSM_FUNC_59G_EN (func. 6) If (1) is false, we won't try (2) and just disallow UNII-4. Otherwise, if (2) is not supported or returns a non-specific value, we follow the default setting either. Besides, this commit aims to add decision logic in rtw89 regulatory. Actually, driver doesn't register UNII-4 yet. That will be handled by another commit. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230508081211.38760-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 7 +++- drivers/net/wireless/realtek/rtw89/core.h | 2 ++ drivers/net/wireless/realtek/rtw89/regd.c | 51 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + 7 files changed, 63 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 630124f9e025..09296e79f07b 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3850,7 +3850,12 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) return ret; } - hw->wiphy->reg_notifier = rtw89_regd_notifier; + ret = rtw89_regd_setup(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to set up regd\n"); + goto err_free_supported_band; + } + hw->wiphy->sar_capa = &rtw89_sar_capa; ret = ieee80211_register_hw(hw); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index f697902706ac..cdd8e312cef7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3179,6 +3179,7 @@ struct rtw89_chip_info { u8 support_chanctx_num; u8 support_bands; bool support_bw160; + bool support_unii4; bool support_ul_tb_ctrl; bool hw_sec_hdr; u8 rf_path_num; @@ -5044,6 +5045,7 @@ int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev, void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc); int rtw89_chip_info_setup(struct rtw89_dev *rtwdev); bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate); +int rtw89_regd_setup(struct rtw89_dev *rtwdev); int rtw89_regd_init(struct rtw89_dev *rtwdev, void (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)); void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request); diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 6e5a740b128f..7800ca36bc13 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2020 Realtek Corporation */ +#include "acpi.h" #include "debug.h" #include "ps.h" @@ -282,6 +283,56 @@ do { \ __r->txpwr_regd[RTW89_BAND_6G]); \ } while (0) +static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, + struct wiphy *wiphy) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + bool regd_allow_unii_4 = chip->support_unii4; + int ret; + u8 val; + + if (!chip->support_unii4) + goto bottom; + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &val); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval unii 4: %d\n", ret); + goto bottom; + } + + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: eval if allow unii 4: %d\n", val); + + switch (val) { + case 0: + regd_allow_unii_4 = false; + break; + case 1: + regd_allow_unii_4 = true; + break; + default: + break; + } + +bottom: + rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow unii 4: %d\n", + regd_allow_unii_4); +} + +int rtw89_regd_setup(struct rtw89_dev *rtwdev) +{ + struct wiphy *wiphy = rtwdev->hw->wiphy; + + if (!wiphy) + return -EINVAL; + + rtw89_regd_setup_unii4(rtwdev, wiphy); + + wiphy->reg_notifier = rtw89_regd_notifier; + return 0; +} + int rtw89_regd_init(struct rtw89_dev *rtwdev, void (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index b68ebe950c4e..00cabf92c5a9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -123,6 +123,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), .support_bw160 = false, + .support_unii4 = true, .support_ul_tb_ctrl = true, .hw_sec_hdr = false, .rf_path_num = 1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index a8a58ff36e95..4e6f3bbdc2d8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2105,6 +2105,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), .support_bw160 = false, + .support_unii4 = false, .support_ul_tb_ctrl = false, .hw_sec_hdr = false, .rf_path_num = 2, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index fa12d4a7f79f..b1a6b985842b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2536,6 +2536,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), .support_bw160 = false, + .support_unii4 = true, .support_ul_tb_ctrl = true, .hw_sec_hdr = false, .rf_path_num = 2, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index d9272bce0325..f2e70bda8e48 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2836,6 +2836,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { BIT(NL80211_BAND_5GHZ) | BIT(NL80211_BAND_6GHZ), .support_bw160 = true, + .support_unii4 = true, .support_ul_tb_ctrl = false, .hw_sec_hdr = true, .rf_path_num = 2, -- cgit v1.2.3 From e3b77c06c8863a53a0d80f7dcaff923c590e3edd Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Mon, 8 May 2023 16:12:11 +0800 Subject: wifi: rtw89: support U-NII-4 channels on 5GHz band U-NII-4 band, i.e 5.9GHz channels, can be supported by chip 8852C, 8852B and 8851B. But, it is not supported by chip 8852A. Flag support_unii4 is added in chip info and defined by chip accordingly to indicate that. We reference this flag of runtime chip to decide whether to register 5.9GHz channels. After that, we consider if U-NII-4 band is allowed by our regulatory rule of U-NII-4. If chip::support_unii4 but not regd::allow_unii4, we stll do not register 5.9GHz channels. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230508081211.38760-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 3 +++ drivers/net/wireless/realtek/rtw89/regd.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 09296e79f07b..fbcb9b6e6f75 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -77,6 +77,9 @@ static struct ieee80211_channel rtw89_channels_5ghz[] = { RTW89_DEF_CHAN_5G(5785, 157), RTW89_DEF_CHAN_5G(5805, 161), RTW89_DEF_CHAN_5G_NO_HT40MINUS(5825, 165), + RTW89_DEF_CHAN_5G(5845, 169), + RTW89_DEF_CHAN_5G(5865, 173), + RTW89_DEF_CHAN_5G(5885, 177), }; static struct ieee80211_channel rtw89_channels_6ghz[] = { diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 7800ca36bc13..377a7a1c560b 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -288,6 +288,7 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, { const struct rtw89_chip_info *chip = rtwdev->chip; bool regd_allow_unii_4 = chip->support_unii4; + struct ieee80211_supported_band *sband; int ret; u8 val; @@ -318,6 +319,15 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, bottom: rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow unii 4: %d\n", regd_allow_unii_4); + + if (regd_allow_unii_4) + return; + + sband = wiphy->bands[NL80211_BAND_5GHZ]; + if (!sband) + return; + + sband->n_channels -= 3; } int rtw89_regd_setup(struct rtw89_dev *rtwdev) -- cgit v1.2.3 From aa70fa4f7dd80e4e495c30ff10a6c373c26902e0 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Mon, 8 May 2023 16:43:33 +0800 Subject: wifi: rtw89: pci: fix interrupt enable mask for HALT C2H of RTL8851B RTL8851B keeps almost the same interrupt flow as RTL8852A and RTL8852B. But, it uses a different bitmask for interrupt indicator of FW HALT C2H. So, we make a chip judgement in pci when configuring interrupt mask. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230508084335.42953-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/pci.c | 9 +++++++-- drivers/net/wireless/realtek/rtw89/pci.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index b53f346fef97..92bfef942d3a 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -3216,11 +3216,16 @@ static void rtw89_pci_clear_resource(struct rtw89_dev *rtwdev, void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 hs0isr_ind_int_en = B_AX_HS0ISR_IND_INT_EN; + + if (chip->chip_id == RTL8851B) + hs0isr_ind_int_en = B_AX_HS0ISR_IND_INT_EN_WKARND; rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | 0; if (rtwpci->under_recovery) { - rtwpci->intrs[0] = B_AX_HS0ISR_IND_INT_EN; + rtwpci->intrs[0] = hs0isr_ind_int_en; rtwpci->intrs[1] = 0; } else { rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN | @@ -3230,7 +3235,7 @@ void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev) B_AX_RXDMA_STUCK_INT_EN | B_AX_RDU_INT_EN | B_AX_RPQBD_FULL_INT_EN | - B_AX_HS0ISR_IND_INT_EN; + hs0isr_ind_int_en; rtwpci->intrs[1] = B_AX_HC10ISR_IND_INT_EN; } diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 0e4bd210b100..2f3d1ad3b0f7 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -150,6 +150,7 @@ #define B_AX_HD1ISR_IND_INT_EN BIT(26) #define B_AX_HD0ISR_IND_INT_EN BIT(25) #define B_AX_HS0ISR_IND_INT_EN BIT(24) +#define B_AX_HS0ISR_IND_INT_EN_WKARND BIT(23) #define B_AX_RETRAIN_INT_EN BIT(21) #define B_AX_RPQBD_FULL_INT_EN BIT(20) #define B_AX_RDU_INT_EN BIT(19) -- cgit v1.2.3 From 56617fd02adbf2ce7e18469895846ba82150cb1f Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Mon, 8 May 2023 16:43:34 +0800 Subject: wifi: rtw89: ser: L1 add pre-M0 and post-M0 states Newer FW re-design SER (syetem error recovery) L1 (level 1) flow. New L1 flow will expect two extra states before original L1 flow. * Before: fw --- M1 --> driver fw <-- M2 --- driver fw --- M3 --> driver fw <-- M4 --- driver fw --- M5 --> driver * After: fw --- pre-M0 --> driver fw <-- post-M0 --- driver fw --- M1 --> driver fw <-- M2 --- driver fw --- M3 --> driver fw <-- M4 --- driver fw --- M5 --> driver Then before M1, FW gets one more interval to deal with things that FW should have handled well. To consider backward/forward compatibility, FW and driver won't change flow from M1 to M5. (only except that halt trigger control will change a little bit.) So, there will be two differnt starting points of SER L1. * old FW: SER L1 starts from M1 * new FW: SER L1 starts from pre-M0 Then, driver adds the new SER L1 entry and also keep the original one instead of changing it. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230508084335.42953-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 6 +++++ drivers/net/wireless/realtek/rtw89/mac.h | 2 ++ drivers/net/wireless/realtek/rtw89/ser.c | 43 ++++++++++++++++++++++++++++++- 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index cdd8e312cef7..d36bdbdd1b77 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3946,6 +3946,7 @@ enum rtw89_ser_rcvy_step { struct rtw89_ser { u8 state; u8 alarm_event; + bool prehandle_l1; struct work_struct ser_hdl_work; struct delayed_work ser_alarm_work; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 64dc36470840..e5996a94c0de 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -676,6 +676,7 @@ EXPORT_SYMBOL(rtw89_mac_get_err_status); int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err) { + struct rtw89_ser *ser = &rtwdev->ser; u32 halt; int ret = 0; @@ -692,6 +693,11 @@ int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err) } rtw89_write32(rtwdev, R_AX_HALT_H2C, err); + + if (ser->prehandle_l1 && + (err == MAC_AX_ERR_L1_DISABLE_EN || err == MAC_AX_ERR_L1_RCVY_EN)) + return 0; + rtw89_write32(rtwdev, R_AX_HALT_H2C_CTRL, B_AX_HALT_H2C_TRIGGER); return 0; diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index d3922d4fe288..e340720bbb88 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -642,6 +642,7 @@ enum mac_ax_err_info { MAC_AX_ERR_L0_PROMOTE_TO_L1 = 0x0010, /* L1 */ + MAC_AX_ERR_L1_PREERR_DMAC = 0x999, MAC_AX_ERR_L1_ERR_DMAC = 0x1000, MAC_AX_ERR_L1_RESET_DISABLE_DMAC_DONE = 0x1001, MAC_AX_ERR_L1_RESET_RECOVERY_DONE = 0x1002, @@ -780,6 +781,7 @@ enum mac_ax_err_info { MAC_AX_ERR_L1_RCVY_EN = 0x0002, MAC_AX_ERR_L1_RCVY_STOP_REQ = 0x0003, MAC_AX_ERR_L1_RCVY_START_REQ = 0x0004, + MAC_AX_ERR_L1_RESET_START_DMAC = 0x000A, MAC_AX_ERR_L0_CFG_NOTIFY = 0x0010, MAC_AX_ERR_L0_CFG_DIS_NOTIFY = 0x0011, MAC_AX_ERR_L0_CFG_HANDSHAKE = 0x0012, diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 9e9f6947e7f1..9ba99f3764e7 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -20,12 +20,14 @@ enum ser_evt { SER_EV_NONE, SER_EV_STATE_IN, SER_EV_STATE_OUT, + SER_EV_L1_RESET_PREPARE, /* pre-M0 */ SER_EV_L1_RESET, /* M1 */ SER_EV_DO_RECOVERY, /* M3 */ SER_EV_MAC_RESET_DONE, /* M5 */ SER_EV_L2_RESET, SER_EV_L2_RECFG_DONE, SER_EV_L2_RECFG_TIMEOUT, + SER_EV_M1_TIMEOUT, SER_EV_M3_TIMEOUT, SER_EV_FW_M5_TIMEOUT, SER_EV_L0_RESET, @@ -34,6 +36,7 @@ enum ser_evt { enum ser_state { SER_IDLE_ST, + SER_L1_RESET_PRE_ST, SER_RESET_TRX_ST, SER_DO_HCI_ST, SER_L2_RESET_ST, @@ -374,6 +377,13 @@ static int hal_stop_dma(struct rtw89_ser *ser) return ret; } +static void hal_send_post_m0_event(struct rtw89_ser *ser) +{ + struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); + + rtw89_mac_set_err_status(rtwdev, MAC_AX_ERR_L1_RESET_START_DMAC); +} + static void hal_send_m2_event(struct rtw89_ser *ser) { struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); @@ -398,6 +408,9 @@ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) rtw89_hci_recovery_complete(rtwdev); clear_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags); break; + case SER_EV_L1_RESET_PREPARE: + ser_state_goto(ser, SER_L1_RESET_PRE_ST); + break; case SER_EV_L1_RESET: ser_state_goto(ser, SER_RESET_TRX_ST); break; @@ -412,6 +425,28 @@ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) } } +static void ser_l1_reset_pre_st_hdl(struct rtw89_ser *ser, u8 evt) +{ + switch (evt) { + case SER_EV_STATE_IN: + ser->prehandle_l1 = true; + hal_send_post_m0_event(ser); + ser_set_alarm(ser, 1000, SER_EV_M1_TIMEOUT); + break; + case SER_EV_L1_RESET: + ser_state_goto(ser, SER_RESET_TRX_ST); + break; + case SER_EV_M1_TIMEOUT: + ser_state_goto(ser, SER_L2_RESET_ST); + break; + case SER_EV_STATE_OUT: + ser_del_alarm(ser); + break; + default: + break; + } +} + static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) { struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); @@ -654,12 +689,14 @@ static const struct event_ent ser_ev_tbl[] = { {SER_EV_NONE, "SER_EV_NONE"}, {SER_EV_STATE_IN, "SER_EV_STATE_IN"}, {SER_EV_STATE_OUT, "SER_EV_STATE_OUT"}, - {SER_EV_L1_RESET, "SER_EV_L1_RESET"}, + {SER_EV_L1_RESET_PREPARE, "SER_EV_L1_RESET_PREPARE pre-m0"}, + {SER_EV_L1_RESET, "SER_EV_L1_RESET m1"}, {SER_EV_DO_RECOVERY, "SER_EV_DO_RECOVERY m3"}, {SER_EV_MAC_RESET_DONE, "SER_EV_MAC_RESET_DONE m5"}, {SER_EV_L2_RESET, "SER_EV_L2_RESET"}, {SER_EV_L2_RECFG_DONE, "SER_EV_L2_RECFG_DONE"}, {SER_EV_L2_RECFG_TIMEOUT, "SER_EV_L2_RECFG_TIMEOUT"}, + {SER_EV_M1_TIMEOUT, "SER_EV_M1_TIMEOUT"}, {SER_EV_M3_TIMEOUT, "SER_EV_M3_TIMEOUT"}, {SER_EV_FW_M5_TIMEOUT, "SER_EV_FW_M5_TIMEOUT"}, {SER_EV_L0_RESET, "SER_EV_L0_RESET"}, @@ -668,6 +705,7 @@ static const struct event_ent ser_ev_tbl[] = { static const struct state_ent ser_st_tbl[] = { {SER_IDLE_ST, "SER_IDLE_ST", ser_idle_st_hdl}, + {SER_L1_RESET_PRE_ST, "SER_L1_RESET_PRE_ST", ser_l1_reset_pre_st_hdl}, {SER_RESET_TRX_ST, "SER_RESET_TRX_ST", ser_reset_trx_st_hdl}, {SER_DO_HCI_ST, "SER_DO_HCI_ST", ser_do_hci_st_hdl}, {SER_L2_RESET_ST, "SER_L2_RESET_ST", ser_l2_reset_st_hdl} @@ -713,6 +751,9 @@ int rtw89_ser_notify(struct rtw89_dev *rtwdev, u32 err) rtw89_info(rtwdev, "SER catches error: 0x%x\n", err); switch (err) { + case MAC_AX_ERR_L1_PREERR_DMAC: /* pre-M0 */ + event = SER_EV_L1_RESET_PREPARE; + break; case MAC_AX_ERR_L1_ERR_DMAC: case MAC_AX_ERR_L0_PROMOTE_TO_L1: event = SER_EV_L1_RESET; /* M1 */ -- cgit v1.2.3 From 8130e94e888bf90e495f88d1a1e63c43e1cfbc18 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Mon, 8 May 2023 16:43:35 +0800 Subject: wifi: rtw89: suppress the log for specific SER called CMDPSR_FRZTO For 8852CE, there is abnormal state called CMDPSR_FRZTO, which occasionally happens in some platforms, and could be found by firmware and fixed in current SER flow, so we add suppress function to avoid verbose message for this resolved case. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230508084335.42953-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/mac.c | 36 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index d36bdbdd1b77..b60cd9852259 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3940,6 +3940,7 @@ enum rtw89_ser_rcvy_step { RTW89_SER_DRV_STOP_RX, RTW89_SER_DRV_STOP_RUN, RTW89_SER_HAL_STOP_DMA, + RTW89_SER_SUPPRESS_LOG, RTW89_NUM_OF_SER_FLAGS }; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index e5996a94c0de..acba53cf7cc3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -644,6 +644,39 @@ static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev, rtw89_info(rtwdev, "<---\n"); } +static bool rtw89_mac_suppress_log(struct rtw89_dev *rtwdev, u32 err) +{ + struct rtw89_ser *ser = &rtwdev->ser; + u32 dmac_err, imr, isr; + int ret; + + if (rtwdev->chip->chip_id == RTL8852C) { + ret = rtw89_mac_check_mac_en(rtwdev, 0, RTW89_DMAC_SEL); + if (ret) + return true; + + if (err == MAC_AX_ERR_L1_ERR_DMAC) { + dmac_err = rtw89_read32(rtwdev, R_AX_DMAC_ERR_ISR); + imr = rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_IMR); + isr = rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_ISR); + + if ((dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) && + ((isr & imr) & B_AX_B0_ISR_ERR_CMDPSR_FRZTO)) { + set_bit(RTW89_SER_SUPPRESS_LOG, ser->flags); + return true; + } + } else if (err == MAC_AX_ERR_L1_RESET_DISABLE_DMAC_DONE) { + if (test_bit(RTW89_SER_SUPPRESS_LOG, ser->flags)) + return true; + } else if (err == MAC_AX_ERR_L1_RESET_RECOVERY_DONE) { + if (test_and_clear_bit(RTW89_SER_SUPPRESS_LOG, ser->flags)) + return true; + } + } + + return false; +} + u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) { u32 err, err_scnr; @@ -667,6 +700,9 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev) else if (err_scnr == RTW89_RXI300_ERROR) err = MAC_AX_ERR_RXI300; + if (rtw89_mac_suppress_log(rtwdev, err)) + return err; + rtw89_fw_st_dbg_dump(rtwdev); rtw89_mac_dump_err_status(rtwdev, err); -- cgit v1.2.3 From 995585ecdf42c14fbd4d9d12ca73bf54358581c6 Mon Sep 17 00:00:00 2001 From: Philipp Rosenberger Date: Tue, 9 May 2023 06:28:56 +0200 Subject: net: enc28j60: Use threaded interrupt instead of workqueue The Microchip ENC28J60 SPI Ethernet driver schedules a work item from the interrupt handler because accesses to the SPI bus may sleep. On PREEMPT_RT (which forces interrupt handling into threads) this old-fashioned approach unnecessarily increases latency because an interrupt results in first waking the interrupt thread, then scheduling the work item. So, a double indirection to handle an interrupt. Avoid by converting the driver to modern threaded interrupt handling. Signed-off-by: Philipp Rosenberger Signed-off-by: Zhi Han [lukas: rewrite commit message, linewrap request_threaded_irq() call] Signed-off-by: Lukas Wunner Reviewed-by: Piotr Raczynski Link: https://lore.kernel.org/r/342380d989ce26bc49f0e5d45fbb0416a5f7809f.1683606193.git.lukas@wunner.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/enc28j60.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c index 176efbeae127..d6c9491537e4 100644 --- a/drivers/net/ethernet/microchip/enc28j60.c +++ b/drivers/net/ethernet/microchip/enc28j60.c @@ -58,7 +58,6 @@ struct enc28j60_net { struct mutex lock; struct sk_buff *tx_skb; struct work_struct tx_work; - struct work_struct irq_work; struct work_struct setrx_work; struct work_struct restart_work; u8 bank; /* current register bank selected */ @@ -1118,10 +1117,9 @@ static int enc28j60_rx_interrupt(struct net_device *ndev) return ret; } -static void enc28j60_irq_work_handler(struct work_struct *work) +static irqreturn_t enc28j60_irq(int irq, void *dev_id) { - struct enc28j60_net *priv = - container_of(work, struct enc28j60_net, irq_work); + struct enc28j60_net *priv = dev_id; struct net_device *ndev = priv->netdev; int intflags, loop; @@ -1225,6 +1223,8 @@ static void enc28j60_irq_work_handler(struct work_struct *work) /* re-enable interrupts */ locked_reg_bfset(priv, EIE, EIE_INTIE); + + return IRQ_HANDLED; } /* @@ -1309,22 +1309,6 @@ static void enc28j60_tx_work_handler(struct work_struct *work) enc28j60_hw_tx(priv); } -static irqreturn_t enc28j60_irq(int irq, void *dev_id) -{ - struct enc28j60_net *priv = dev_id; - - /* - * Can't do anything in interrupt context because we need to - * block (spi_sync() is blocking) so fire of the interrupt - * handling workqueue. - * Remember that we access enc28j60 registers through SPI bus - * via spi_sync() call. - */ - schedule_work(&priv->irq_work); - - return IRQ_HANDLED; -} - static void enc28j60_tx_timeout(struct net_device *ndev, unsigned int txqueue) { struct enc28j60_net *priv = netdev_priv(ndev); @@ -1559,7 +1543,6 @@ static int enc28j60_probe(struct spi_device *spi) mutex_init(&priv->lock); INIT_WORK(&priv->tx_work, enc28j60_tx_work_handler); INIT_WORK(&priv->setrx_work, enc28j60_setrx_work_handler); - INIT_WORK(&priv->irq_work, enc28j60_irq_work_handler); INIT_WORK(&priv->restart_work, enc28j60_restart_work_handler); spi_set_drvdata(spi, priv); /* spi to priv reference */ SET_NETDEV_DEV(dev, &spi->dev); @@ -1578,7 +1561,8 @@ static int enc28j60_probe(struct spi_device *spi) /* Board setup must set the relevant edge trigger type; * level triggers won't currently work. */ - ret = request_irq(spi->irq, enc28j60_irq, 0, DRV_NAME, priv); + ret = request_threaded_irq(spi->irq, NULL, enc28j60_irq, IRQF_ONESHOT, + DRV_NAME, priv); if (ret < 0) { if (netif_msg_probe(priv)) dev_err(&spi->dev, "request irq %d failed (ret = %d)\n", -- cgit v1.2.3 From 7f88efc8162cc6d516cacf1d82edc923b423483f Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 10 May 2023 22:02:47 +0200 Subject: net: samsung: sxgbe: Make sxgbe_drv_remove() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sxgbe_drv_remove() returned zero unconditionally, so it can be converted to return void without losing anything. The upside is that it becomes more obvious in its callers that there is no error to handle. Signed-off-by: Uwe Kleine-König Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h | 2 +- drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 4 +--- drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h index 0f45107db8dd..d14e0cfc3a6b 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h @@ -511,7 +511,7 @@ struct sxgbe_priv_data { struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device, struct sxgbe_plat_data *plat_dat, void __iomem *addr); -int sxgbe_drv_remove(struct net_device *ndev); +void sxgbe_drv_remove(struct net_device *ndev); void sxgbe_set_ethtool_ops(struct net_device *netdev); int sxgbe_mdio_unregister(struct net_device *ndev); int sxgbe_mdio_register(struct net_device *ndev); diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c index 9664f029fa16..71439825ea4e 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c @@ -2203,7 +2203,7 @@ error_free_netdev: * Description: this function resets the TX/RX processes, disables the MAC RX/TX * changes the link status, releases the DMA descriptor rings. */ -int sxgbe_drv_remove(struct net_device *ndev) +void sxgbe_drv_remove(struct net_device *ndev) { struct sxgbe_priv_data *priv = netdev_priv(ndev); u8 queue_num; @@ -2231,8 +2231,6 @@ int sxgbe_drv_remove(struct net_device *ndev) kfree(priv->hw); free_netdev(ndev); - - return 0; } #ifdef CONFIG_PM diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c index 4e5526303f07..fb59ff94509a 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c @@ -172,9 +172,10 @@ err_out: static int sxgbe_platform_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); - int ret = sxgbe_drv_remove(ndev); - return ret; + sxgbe_drv_remove(ndev); + + return 0; } #ifdef CONFIG_PM -- cgit v1.2.3 From 48c0db05a1bf60067cdee062a6bfad6db5c1f602 Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Thu, 11 May 2023 11:47:12 +0530 Subject: octeontx2-pf: mcs: Offload extended packet number(XPN) feature The macsec hardware block supports XPN cipher suites also. Hence added changes to offload XPN feature. Changes include configuring SecY policy to XPN cipher suite, Salt and SSCI values. 64 bit packet number is passed instead of 32 bit packet number. Signed-off-by: Subbaraya Sundeep Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/nic/cn10k_macsec.c | 89 +++++++++++++++++----- .../ethernet/marvell/octeontx2/nic/otx2_common.h | 5 ++ 2 files changed, 75 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c index aea4c802bb9d..8eaa50d0f668 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c @@ -6,7 +6,6 @@ #include #include -#include #include "otx2_common.h" #define MCS_TCAM0_MAC_DA_MASK GENMASK_ULL(47, 0) @@ -212,6 +211,7 @@ static int cn10k_mcs_write_rx_secy(struct otx2_nic *pfvf, struct mcs_secy_plcy_write_req *req; struct mbox *mbox = &pfvf->mbox; u64 policy; + u8 cipher; int ret; mutex_lock(&mbox->lock); @@ -227,7 +227,21 @@ static int cn10k_mcs_write_rx_secy(struct otx2_nic *pfvf, policy |= MCS_RX_SECY_PLCY_RP; policy |= MCS_RX_SECY_PLCY_AUTH_ENA; - policy |= FIELD_PREP(MCS_RX_SECY_PLCY_CIP, MCS_GCM_AES_128); + + switch (secy->key_len) { + case 16: + cipher = secy->xpn ? MCS_GCM_AES_XPN_128 : MCS_GCM_AES_128; + break; + case 32: + cipher = secy->xpn ? MCS_GCM_AES_XPN_256 : MCS_GCM_AES_256; + break; + default: + cipher = MCS_GCM_AES_128; + dev_warn(pfvf->dev, "Unsupported key length\n"); + break; + }; + + policy |= FIELD_PREP(MCS_RX_SECY_PLCY_CIP, cipher); policy |= FIELD_PREP(MCS_RX_SECY_PLCY_VAL, secy->validate_frames); policy |= MCS_RX_SECY_PLCY_ENA; @@ -323,9 +337,12 @@ static int cn10k_mcs_write_rx_sa_plcy(struct otx2_nic *pfvf, { unsigned char *src = rxsc->sa_key[assoc_num]; struct mcs_sa_plcy_write_req *plcy_req; + u8 *salt_p = rxsc->salt[assoc_num]; struct mcs_rx_sc_sa_map *map_req; struct mbox *mbox = &pfvf->mbox; + u64 ssci_salt_95_64 = 0; u8 reg, key_len; + u64 salt_63_0; int ret; mutex_lock(&mbox->lock); @@ -349,6 +366,15 @@ static int cn10k_mcs_write_rx_sa_plcy(struct otx2_nic *pfvf, reg++; } + if (secy->xpn) { + memcpy((u8 *)&salt_63_0, salt_p, 8); + memcpy((u8 *)&ssci_salt_95_64, salt_p + 8, 4); + ssci_salt_95_64 |= (__force u64)rxsc->ssci[assoc_num] << 32; + + plcy_req->plcy[0][6] = salt_63_0; + plcy_req->plcy[0][7] = ssci_salt_95_64; + } + plcy_req->sa_index[0] = rxsc->hw_sa_id[assoc_num]; plcy_req->sa_cnt = 1; plcy_req->dir = MCS_RX; @@ -404,6 +430,7 @@ static int cn10k_mcs_write_tx_secy(struct otx2_nic *pfvf, u8 tag_offset = 12; u8 sectag_tci = 0; u64 policy; + u8 cipher; int ret; sw_tx_sc = &secy->tx_sc; @@ -434,7 +461,21 @@ static int cn10k_mcs_write_tx_secy(struct otx2_nic *pfvf, policy |= FIELD_PREP(MCS_TX_SECY_PLCY_ST_OFFSET, tag_offset); policy |= MCS_TX_SECY_PLCY_INS_MODE; policy |= MCS_TX_SECY_PLCY_AUTH_ENA; - policy |= FIELD_PREP(MCS_TX_SECY_PLCY_CIP, MCS_GCM_AES_128); + + switch (secy->key_len) { + case 16: + cipher = secy->xpn ? MCS_GCM_AES_XPN_128 : MCS_GCM_AES_128; + break; + case 32: + cipher = secy->xpn ? MCS_GCM_AES_XPN_256 : MCS_GCM_AES_256; + break; + default: + cipher = MCS_GCM_AES_128; + dev_warn(pfvf->dev, "Unsupported key length\n"); + break; + }; + + policy |= FIELD_PREP(MCS_TX_SECY_PLCY_CIP, cipher); if (secy->protect_frames) policy |= MCS_TX_SECY_PLCY_PROTECT; @@ -544,8 +585,11 @@ static int cn10k_mcs_write_tx_sa_plcy(struct otx2_nic *pfvf, { unsigned char *src = txsc->sa_key[assoc_num]; struct mcs_sa_plcy_write_req *plcy_req; + u8 *salt_p = txsc->salt[assoc_num]; struct mbox *mbox = &pfvf->mbox; + u64 ssci_salt_95_64 = 0; u8 reg, key_len; + u64 salt_63_0; int ret; mutex_lock(&mbox->lock); @@ -561,6 +605,15 @@ static int cn10k_mcs_write_tx_sa_plcy(struct otx2_nic *pfvf, reg++; } + if (secy->xpn) { + memcpy((u8 *)&salt_63_0, salt_p, 8); + memcpy((u8 *)&ssci_salt_95_64, salt_p + 8, 4); + ssci_salt_95_64 |= (__force u64)txsc->ssci[assoc_num] << 32; + + plcy_req->plcy[0][6] = salt_63_0; + plcy_req->plcy[0][7] = ssci_salt_95_64; + } + plcy_req->plcy[0][8] = assoc_num; plcy_req->sa_index[0] = txsc->hw_sa_id[assoc_num]; plcy_req->sa_cnt = 1; @@ -922,8 +975,7 @@ static int cn10k_mcs_secy_tx_cfg(struct otx2_nic *pfvf, struct macsec_secy *secy { if (sw_tx_sa) { cn10k_mcs_write_tx_sa_plcy(pfvf, secy, txsc, sa_num); - cn10k_write_tx_sa_pn(pfvf, txsc, sa_num, - sw_tx_sa->next_pn_halves.lower); + cn10k_write_tx_sa_pn(pfvf, txsc, sa_num, sw_tx_sa->next_pn); cn10k_mcs_link_tx_sa2sc(pfvf, secy, txsc, sa_num, sw_tx_sa->active); } @@ -959,7 +1011,7 @@ static int cn10k_mcs_secy_rx_cfg(struct otx2_nic *pfvf, cn10k_mcs_write_rx_sa_plcy(pfvf, secy, mcs_rx_sc, sa_num, sw_rx_sa->active); cn10k_mcs_write_rx_sa_pn(pfvf, mcs_rx_sc, sa_num, - sw_rx_sa->next_pn_halves.lower); + sw_rx_sa->next_pn); } cn10k_mcs_write_rx_flowid(pfvf, mcs_rx_sc, hw_secy_id); @@ -1103,13 +1155,6 @@ static int cn10k_mdo_add_secy(struct macsec_context *ctx) if (secy->icv_len != MACSEC_DEFAULT_ICV_LEN) return -EOPNOTSUPP; - /* Stick to 16 bytes key len until XPN support is added */ - if (secy->key_len != 16) - return -EOPNOTSUPP; - - if (secy->xpn) - return -EOPNOTSUPP; - txsc = cn10k_mcs_create_txsc(pfvf); if (IS_ERR(txsc)) return -ENOSPC; @@ -1202,6 +1247,9 @@ static int cn10k_mdo_add_txsa(struct macsec_context *ctx) return -ENOSPC; memcpy(&txsc->sa_key[sa_num], ctx->sa.key, secy->key_len); + memcpy(&txsc->salt[sa_num], sw_tx_sa->key.salt.bytes, MACSEC_SALT_LEN); + txsc->ssci[sa_num] = sw_tx_sa->ssci; + txsc->sa_bmap |= 1 << sa_num; if (netif_running(secy->netdev)) { @@ -1210,7 +1258,7 @@ static int cn10k_mdo_add_txsa(struct macsec_context *ctx) return err; err = cn10k_write_tx_sa_pn(pfvf, txsc, sa_num, - sw_tx_sa->next_pn_halves.lower); + sw_tx_sa->next_pn); if (err) return err; @@ -1243,7 +1291,7 @@ static int cn10k_mdo_upd_txsa(struct macsec_context *ctx) if (netif_running(secy->netdev)) { /* Keys cannot be changed after creation */ err = cn10k_write_tx_sa_pn(pfvf, txsc, sa_num, - sw_tx_sa->next_pn_halves.lower); + sw_tx_sa->next_pn); if (err) return err; @@ -1353,7 +1401,6 @@ static int cn10k_mdo_add_rxsa(struct macsec_context *ctx) struct macsec_rx_sc *sw_rx_sc = ctx->sa.rx_sa->sc; struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa; - u64 next_pn = rx_sa->next_pn_halves.lower; struct macsec_secy *secy = ctx->secy; bool sa_in_use = rx_sa->active; u8 sa_num = ctx->sa.assoc_num; @@ -1371,6 +1418,9 @@ static int cn10k_mdo_add_rxsa(struct macsec_context *ctx) return -ENOSPC; memcpy(&rxsc->sa_key[sa_num], ctx->sa.key, ctx->secy->key_len); + memcpy(&rxsc->salt[sa_num], rx_sa->key.salt.bytes, MACSEC_SALT_LEN); + rxsc->ssci[sa_num] = rx_sa->ssci; + rxsc->sa_bmap |= 1 << sa_num; if (netif_running(secy->netdev)) { @@ -1379,7 +1429,8 @@ static int cn10k_mdo_add_rxsa(struct macsec_context *ctx) if (err) return err; - err = cn10k_mcs_write_rx_sa_pn(pfvf, rxsc, sa_num, next_pn); + err = cn10k_mcs_write_rx_sa_pn(pfvf, rxsc, sa_num, + rx_sa->next_pn); if (err) return err; } @@ -1393,7 +1444,6 @@ static int cn10k_mdo_upd_rxsa(struct macsec_context *ctx) struct macsec_rx_sc *sw_rx_sc = ctx->sa.rx_sa->sc; struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa; - u64 next_pn = rx_sa->next_pn_halves.lower; struct macsec_secy *secy = ctx->secy; bool sa_in_use = rx_sa->active; u8 sa_num = ctx->sa.assoc_num; @@ -1412,7 +1462,8 @@ static int cn10k_mdo_upd_rxsa(struct macsec_context *ctx) if (err) return err; - err = cn10k_mcs_write_rx_sa_pn(pfvf, rxsc, sa_num, next_pn); + err = cn10k_mcs_write_rx_sa_pn(pfvf, rxsc, sa_num, + rx_sa->next_pn); if (err) return err; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 0c8fc66ade82..d17274aab374 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -398,6 +399,8 @@ struct cn10k_mcs_txsc { u8 sa_bmap; u8 sa_key[CN10K_MCS_SA_PER_SC][MACSEC_MAX_KEY_LEN]; u8 encoding_sa; + u8 salt[CN10K_MCS_SA_PER_SC][MACSEC_SALT_LEN]; + ssci_t ssci[CN10K_MCS_SA_PER_SC]; }; struct cn10k_mcs_rxsc { @@ -410,6 +413,8 @@ struct cn10k_mcs_rxsc { u16 hw_sa_id[CN10K_MCS_SA_PER_SC]; u8 sa_bmap; u8 sa_key[CN10K_MCS_SA_PER_SC][MACSEC_MAX_KEY_LEN]; + u8 salt[CN10K_MCS_SA_PER_SC][MACSEC_SALT_LEN]; + ssci_t ssci[CN10K_MCS_SA_PER_SC]; }; struct cn10k_mcs_cfg { -- cgit v1.2.3 From 0fae8847563b0c990f8cffcb8d3668fbcaca4919 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 11 May 2023 15:21:19 +0800 Subject: ipvlan: Remove NULL check before dev_{put, hold} The call netdev_{put, hold} of dev_{put, hold} will check NULL, so there is no need to check before using dev_{put, hold}, remove it to silence the warning: ./drivers/net/ipvlan/ipvlan_core.c:559:3-11: WARNING: NULL check before dev_{put, hold} functions is not needed. Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=4930 Signed-off-by: Yang Li Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index ab5133eb1d51..a8977965a7f2 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -555,8 +555,7 @@ static void ipvlan_multicast_enqueue(struct ipvl_port *port, spin_lock(&port->backlog.lock); if (skb_queue_len(&port->backlog) < IPVLAN_QBACKLOG_LIMIT) { - if (skb->dev) - dev_hold(skb->dev); + dev_hold(skb->dev); __skb_queue_tail(&port->backlog, skb); spin_unlock(&port->backlog.lock); schedule_work(&port->wq); -- cgit v1.2.3 From b16d76fe9a27d337c16972a71d959bcf0c96c2e6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 May 2023 11:47:09 -0400 Subject: net/handshake: Remove unneeded check from handshake_dup() handshake_req_submit() now verifies that the socket has a file. Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") Reviewed-by: Simon Horman Signed-off-by: Chuck Lever Signed-off-by: David S. Miller --- net/handshake/netlink.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c index 35c9c445e0b8..7ec8a76c3c8a 100644 --- a/net/handshake/netlink.c +++ b/net/handshake/netlink.c @@ -99,9 +99,6 @@ static int handshake_dup(struct socket *sock) struct file *file; int newfd; - if (!sock->file) - return -EBADF; - file = get_file(sock->file); newfd = get_unused_fd_flags(O_CLOEXEC); if (newfd < 0) { -- cgit v1.2.3 From 2200c1a87074548f0a36e5aae5ad283ce2ac43b2 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 May 2023 11:47:40 -0400 Subject: net/handshake: Fix handshake_dup() ref counting If get_unused_fd_flags() fails, we ended up calling fput(sock->file) twice. Reported-by: Dan Carpenter Suggested-by: Paolo Abeni Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") Signed-off-by: Chuck Lever Signed-off-by: David S. Miller --- net/handshake/netlink.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c index 7ec8a76c3c8a..f5dc170689d9 100644 --- a/net/handshake/netlink.c +++ b/net/handshake/netlink.c @@ -139,15 +139,16 @@ int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info) goto out_complete; } err = req->hr_proto->hp_accept(req, info, fd); - if (err) + if (err) { + fput(sock->file); goto out_complete; + } trace_handshake_cmd_accept(net, req, req->hr_sk, fd); return 0; out_complete: handshake_complete(req, -EIO, NULL); - fput(sock->file); out_status: trace_handshake_cmd_accept_err(net, req, NULL, err); return err; -- cgit v1.2.3 From 7301034026d0efe0e86af0cb685405da120583d4 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 May 2023 11:48:13 -0400 Subject: net/handshake: Fix uninitialized local variable trace_handshake_cmd_done_err() simply records the pointer in @req, so initializing it to NULL is sufficient and safe. Reported-by: Dan Carpenter Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") Reviewed-by: Simon Horman Signed-off-by: Chuck Lever Signed-off-by: David S. Miller --- net/handshake/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c index f5dc170689d9..16a4bde648ba 100644 --- a/net/handshake/netlink.c +++ b/net/handshake/netlink.c @@ -157,8 +157,8 @@ out_status: int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info) { struct net *net = sock_net(skb->sk); + struct handshake_req *req = NULL; struct socket *sock = NULL; - struct handshake_req *req; int fd, status, err; if (GENL_REQ_ATTR_CHECK(info, HANDSHAKE_A_DONE_SOCKFD)) -- cgit v1.2.3 From e36a93e1723eb09c8393604ddc8ef2966f592597 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 May 2023 11:48:45 -0400 Subject: net/handshake: handshake_genl_notify() shouldn't ignore @flags Reported-by: Dan Carpenter Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") Reviewed-by: Simon Horman Signed-off-by: Chuck Lever Signed-off-by: David S. Miller --- net/handshake/netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/handshake/netlink.c b/net/handshake/netlink.c index 16a4bde648ba..1086653e1fad 100644 --- a/net/handshake/netlink.c +++ b/net/handshake/netlink.c @@ -48,7 +48,7 @@ int handshake_genl_notify(struct net *net, const struct handshake_proto *proto, proto->hp_handler_class)) return -ESRCH; - msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); + msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, flags); if (!msg) return -ENOMEM; -- cgit v1.2.3 From f921bd41001ccff2249f5f443f2917f7ef937daf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 May 2023 11:49:17 -0400 Subject: net/handshake: Unpin sock->file if a handshake is cancelled If user space never calls DONE, sock->file's reference count remains elevated. Enable sock->file to be freed eventually in this case. Reported-by: Jakub Kacinski Fixes: 3b3009ea8abb ("net/handshake: Create a NETLINK service for handling handshake requests") Signed-off-by: Chuck Lever Signed-off-by: David S. Miller --- net/handshake/handshake.h | 1 + net/handshake/request.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/net/handshake/handshake.h b/net/handshake/handshake.h index 4dac965c99df..8aeaadca844f 100644 --- a/net/handshake/handshake.h +++ b/net/handshake/handshake.h @@ -31,6 +31,7 @@ struct handshake_req { struct list_head hr_list; struct rhash_head hr_rhash; unsigned long hr_flags; + struct file *hr_file; const struct handshake_proto *hr_proto; struct sock *hr_sk; void (*hr_odestruct)(struct sock *sk); diff --git a/net/handshake/request.c b/net/handshake/request.c index 94d5cef3e048..d78d41abb3d9 100644 --- a/net/handshake/request.c +++ b/net/handshake/request.c @@ -239,6 +239,7 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req, } req->hr_odestruct = req->hr_sk->sk_destruct; req->hr_sk->sk_destruct = handshake_sk_destruct; + req->hr_file = sock->file; ret = -EOPNOTSUPP; net = sock_net(req->hr_sk); @@ -334,6 +335,9 @@ bool handshake_req_cancel(struct sock *sk) return false; } + /* Request accepted and waiting for DONE */ + fput(req->hr_file); + out_true: trace_handshake_cancel(net, req, sk); -- cgit v1.2.3 From eefca7ec514262aef08d0ef261552f2f604bd851 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 11 May 2023 11:49:50 -0400 Subject: net/handshake: Enable the SNI extension to work properly Enable the upper layer protocol to specify the SNI peername. This avoids the need for tlshd to use a DNS lookup, which can return a hostname that doesn't match the incoming certificate's SubjectName. Fixes: 2fd5532044a8 ("net/handshake: Add a kernel API for requesting a TLSv1.3 handshake") Reviewed-by: Simon Horman Signed-off-by: Chuck Lever Signed-off-by: David S. Miller --- Documentation/netlink/specs/handshake.yaml | 4 ++++ Documentation/networking/tls-handshake.rst | 5 +++++ include/net/handshake.h | 1 + include/uapi/linux/handshake.h | 1 + net/handshake/tlshd.c | 8 ++++++++ 5 files changed, 19 insertions(+) diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/netlink/specs/handshake.yaml index 614f1a585511..6d89e30f5fd5 100644 --- a/Documentation/netlink/specs/handshake.yaml +++ b/Documentation/netlink/specs/handshake.yaml @@ -68,6 +68,9 @@ attribute-sets: type: nest nested-attributes: x509 multi-attr: true + - + name: peername + type: string - name: done attributes: @@ -105,6 +108,7 @@ operations: - auth-mode - peer-identity - certificate + - peername - name: done doc: Handler reports handshake completion diff --git a/Documentation/networking/tls-handshake.rst b/Documentation/networking/tls-handshake.rst index a2817a88e905..6f5ea1646a47 100644 --- a/Documentation/networking/tls-handshake.rst +++ b/Documentation/networking/tls-handshake.rst @@ -53,6 +53,7 @@ fills in a structure that contains the parameters of the request: struct socket *ta_sock; tls_done_func_t ta_done; void *ta_data; + const char *ta_peername; unsigned int ta_timeout_ms; key_serial_t ta_keyring; key_serial_t ta_my_cert; @@ -71,6 +72,10 @@ instantiated a struct file in sock->file. has completed. Further explanation of this function is in the "Handshake Completion" sesction below. +The consumer can provide a NUL-terminated hostname in the @ta_peername +field that is sent as part of ClientHello. If no peername is provided, +the DNS hostname associated with the server's IP address is used instead. + The consumer can fill in the @ta_timeout_ms field to force the servicing handshake agent to exit after a number of milliseconds. This enables the socket to be fully closed once both the kernel and the handshake agent diff --git a/include/net/handshake.h b/include/net/handshake.h index 3352b1ab43b3..2e26e436e85f 100644 --- a/include/net/handshake.h +++ b/include/net/handshake.h @@ -24,6 +24,7 @@ struct tls_handshake_args { struct socket *ta_sock; tls_done_func_t ta_done; void *ta_data; + const char *ta_peername; unsigned int ta_timeout_ms; key_serial_t ta_keyring; key_serial_t ta_my_cert; diff --git a/include/uapi/linux/handshake.h b/include/uapi/linux/handshake.h index 1de4d0b95325..3d7ea58778c9 100644 --- a/include/uapi/linux/handshake.h +++ b/include/uapi/linux/handshake.h @@ -44,6 +44,7 @@ enum { HANDSHAKE_A_ACCEPT_AUTH_MODE, HANDSHAKE_A_ACCEPT_PEER_IDENTITY, HANDSHAKE_A_ACCEPT_CERTIFICATE, + HANDSHAKE_A_ACCEPT_PEERNAME, __HANDSHAKE_A_ACCEPT_MAX, HANDSHAKE_A_ACCEPT_MAX = (__HANDSHAKE_A_ACCEPT_MAX - 1) diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c index fcbeb63b4eb1..b735f5cced2f 100644 --- a/net/handshake/tlshd.c +++ b/net/handshake/tlshd.c @@ -31,6 +31,7 @@ struct tls_handshake_req { int th_type; unsigned int th_timeout_ms; int th_auth_mode; + const char *th_peername; key_serial_t th_keyring; key_serial_t th_certificate; key_serial_t th_privkey; @@ -48,6 +49,7 @@ tls_handshake_req_init(struct handshake_req *req, treq->th_timeout_ms = args->ta_timeout_ms; treq->th_consumer_done = args->ta_done; treq->th_consumer_data = args->ta_data; + treq->th_peername = args->ta_peername; treq->th_keyring = args->ta_keyring; treq->th_num_peerids = 0; treq->th_certificate = TLS_NO_CERT; @@ -214,6 +216,12 @@ static int tls_handshake_accept(struct handshake_req *req, ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_MESSAGE_TYPE, treq->th_type); if (ret < 0) goto out_cancel; + if (treq->th_peername) { + ret = nla_put_string(msg, HANDSHAKE_A_ACCEPT_PEERNAME, + treq->th_peername); + if (ret < 0) + goto out_cancel; + } if (treq->th_timeout_ms) { ret = nla_put_u32(msg, HANDSHAKE_A_ACCEPT_TIMEOUT, treq->th_timeout_ms); if (ret < 0) -- cgit v1.2.3 From c1bc7d73c96425db12bb92fbf24c37fd1c9ac329 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 11 May 2023 17:07:12 +0200 Subject: bonding: Always assign be16 value to vlan_proto The type of the vlan_proto field is __be16. And most users of the field use it as such. In the case of setting or testing the field for the special VLAN_N_VID value, host byte order is used. Which seems incorrect. It also seems somewhat odd to store a VLAN ID value in a field that is otherwise used to store Ether types. Address this issue by defining BOND_VLAN_PROTO_NONE, a big endian value. 0xffff was chosen somewhat arbitrarily. What is important is that it doesn't overlap with any valid VLAN Ether types. I don't believe the problems described above are a bug because VLAN_N_VID in both little-endian and big-endian byte order does not conflict with any supported VLAN Ether types in big-endian byte order. Reported by sparse as: .../bond_main.c:2857:26: warning: restricted __be16 degrades to integer .../bond_main.c:2863:20: warning: restricted __be16 degrades to integer .../bond_main.c:2939:40: warning: incorrect type in assignment (different base types) .../bond_main.c:2939:40: expected restricted __be16 [usertype] vlan_proto .../bond_main.c:2939:40: got int No functional changes intended. Compile tested only. Signed-off-by: Simon Horman Acked-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3fed888629f7..ebf61c19dcef 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2871,6 +2871,8 @@ static bool bond_has_this_ip(struct bonding *bond, __be32 ip) return ret; } +#define BOND_VLAN_PROTO_NONE cpu_to_be16(0xffff) + static bool bond_handle_vlan(struct slave *slave, struct bond_vlan_tag *tags, struct sk_buff *skb) { @@ -2878,13 +2880,13 @@ static bool bond_handle_vlan(struct slave *slave, struct bond_vlan_tag *tags, struct net_device *slave_dev = slave->dev; struct bond_vlan_tag *outer_tag = tags; - if (!tags || tags->vlan_proto == VLAN_N_VID) + if (!tags || tags->vlan_proto == BOND_VLAN_PROTO_NONE) return true; tags++; /* Go through all the tags backwards and add them to the packet */ - while (tags->vlan_proto != VLAN_N_VID) { + while (tags->vlan_proto != BOND_VLAN_PROTO_NONE) { if (!tags->vlan_id) { tags++; continue; @@ -2960,7 +2962,7 @@ struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, tags = kcalloc(level + 1, sizeof(*tags), GFP_ATOMIC); if (!tags) return ERR_PTR(-ENOMEM); - tags[level].vlan_proto = VLAN_N_VID; + tags[level].vlan_proto = BOND_VLAN_PROTO_NONE; return tags; } -- cgit v1.2.3 From aeefbb574c38025fd65a1b053c41595ba13b2408 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 11 May 2023 16:39:25 +0200 Subject: selftests: Add SO_DONTROUTE option to nettest. Add --client-dontroute and --server-dontroute options to nettest. They allow to set the SO_DONTROUTE option to the client and server sockets respectively. This will be used by the following patches to test the SO_DONTROUTE kernel behaviour with TCP and UDP. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/nettest.c | 46 ++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/nettest.c b/tools/testing/selftests/net/nettest.c index ee9a72982705..39a0e01f8554 100644 --- a/tools/testing/selftests/net/nettest.c +++ b/tools/testing/selftests/net/nettest.c @@ -76,7 +76,9 @@ struct sock_args { has_grp:1, has_expected_laddr:1, has_expected_raddr:1, - bind_test_only:1; + bind_test_only:1, + client_dontroute:1, + server_dontroute:1; unsigned short port; @@ -611,6 +613,18 @@ static int set_dsfield(int sd, int version, int dsfield) return 0; } +static int set_dontroute(int sd) +{ + unsigned int one = 1; + + if (setsockopt(sd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) { + log_err_errno("setsockopt(SO_DONTROUTE)"); + return -1; + } + + return 0; +} + static int str_to_uint(const char *str, int min, int max, unsigned int *value) { int number; @@ -1351,6 +1365,14 @@ static int msock_init(struct sock_args *args, int server) if (set_dsfield(sd, AF_INET, args->dsfield) != 0) goto out_err; + if (server) { + if (args->server_dontroute && set_dontroute(sd) != 0) + goto out_err; + } else { + if (args->client_dontroute && set_dontroute(sd) != 0) + goto out_err; + } + if (args->dev && bind_to_device(sd, args->dev) != 0) goto out_err; else if (args->use_setsockopt && @@ -1482,6 +1504,9 @@ static int lsock_init(struct sock_args *args) if (set_dsfield(sd, args->version, args->dsfield) != 0) goto err; + if (args->server_dontroute && set_dontroute(sd) != 0) + goto err; + if (args->dev && bind_to_device(sd, args->dev) != 0) goto err; else if (args->use_setsockopt && @@ -1698,6 +1723,9 @@ static int connectsock(void *addr, socklen_t alen, struct sock_args *args) if (set_dsfield(sd, args->version, args->dsfield) != 0) goto err; + if (args->client_dontroute && set_dontroute(sd) != 0) + goto err; + if (args->dev && bind_to_device(sd, args->dev) != 0) goto err; else if (args->use_setsockopt && @@ -1905,10 +1933,14 @@ static int ipc_parent(int cpid, int fd, struct sock_args *args) #define GETOPT_STR "sr:l:c:Q:p:t:g:P:DRn:M:X:m:d:I:BN:O:SUCi6xL:0:1:2:3:Fbqf" #define OPT_FORCE_BIND_KEY_IFINDEX 1001 #define OPT_NO_BIND_KEY_IFINDEX 1002 +#define OPT_CLIENT_DONTROUTE 1003 +#define OPT_SERVER_DONTROUTE 1004 static struct option long_opts[] = { {"force-bind-key-ifindex", 0, 0, OPT_FORCE_BIND_KEY_IFINDEX}, {"no-bind-key-ifindex", 0, 0, OPT_NO_BIND_KEY_IFINDEX}, + {"client-dontroute", 0, 0, OPT_CLIENT_DONTROUTE}, + {"server-dontroute", 0, 0, OPT_SERVER_DONTROUTE}, {0, 0, 0, 0} }; @@ -1954,6 +1986,12 @@ static void print_usage(char *prog) " --no-bind-key-ifindex: Force TCP_MD5SIG_FLAG_IFINDEX off\n" " --force-bind-key-ifindex: Force TCP_MD5SIG_FLAG_IFINDEX on\n" " (default: only if -I is passed)\n" + " --client-dontroute: don't use gateways for client socket: send\n" + " packets only if destination is on link (see\n" + " SO_DONTROUTE in socket(7))\n" + " --server-dontroute: don't use gateways for server socket: send\n" + " packets only if destination is on link (see\n" + " SO_DONTROUTE in socket(7))\n" "\n" " -g grp multicast group (e.g., 239.1.1.1)\n" " -i interactive mode (default is echo and terminate)\n" @@ -2076,6 +2114,12 @@ int main(int argc, char *argv[]) case OPT_NO_BIND_KEY_IFINDEX: args.bind_key_ifindex = -1; break; + case OPT_CLIENT_DONTROUTE: + args.client_dontroute = 1; + break; + case OPT_SERVER_DONTROUTE: + args.server_dontroute = 1; + break; case 'X': args.client_pw = optarg; break; -- cgit v1.2.3 From dd017c72dde677cef5a5a965ca71ac4736b53452 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 11 May 2023 16:39:32 +0200 Subject: selftests: fcnal: Test SO_DONTROUTE on TCP sockets. Use nettest --{client,server}-dontroute to test the kernel behaviour with TCP sockets having the SO_DONTROUTE option. Sending packets to a neighbour (on link) host, should work. When the host is behind a router, sending should fail. Client and server sockets are tested independently, so that we can cover different TCP kernel paths. SO_DONTROUTE also affects the syncookies path. So ipv4_tcp_dontroute() is made to work with or without syncookies, to cover both paths. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fcnal-test.sh | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index 21ca91473c09..3a1f3051321f 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -1098,6 +1098,59 @@ test_ipv4_md5_vrf__global_server__bind_ifindex0() set_sysctl net.ipv4.tcp_l3mdev_accept="$old_tcp_l3mdev_accept" } +ipv4_tcp_dontroute() +{ + local syncookies=$1 + local nsa_syncookies + local nsb_syncookies + local a + + # + # Link local connection tests (SO_DONTROUTE). + # Connections should succeed only when the remote IP address is + # on link (doesn't need to be routed through a gateway). + # + + nsa_syncookies=$(ip netns exec "${NSA}" sysctl -n net.ipv4.tcp_syncookies) + nsb_syncookies=$(ip netns exec "${NSB}" sysctl -n net.ipv4.tcp_syncookies) + ip netns exec "${NSA}" sysctl -wq net.ipv4.tcp_syncookies=${syncookies} + ip netns exec "${NSB}" sysctl -wq net.ipv4.tcp_syncookies=${syncookies} + + # Test with eth1 address (on link). + + a=${NSB_IP} + log_start + do_run_cmd nettest -B -N "${NSA}" -O "${NSB}" -r ${a} --client-dontroute + log_test_addr ${a} $? 0 "SO_DONTROUTE client, syncookies=${syncookies}" + + a=${NSB_IP} + log_start + do_run_cmd nettest -B -N "${NSA}" -O "${NSB}" -r ${a} --server-dontroute + log_test_addr ${a} $? 0 "SO_DONTROUTE server, syncookies=${syncookies}" + + # Test with loopback address (routed). + # + # The client would use the eth1 address as source IP by default. + # Therefore, we need to use the -c option here, to force the use of the + # routed (loopback) address as source IP (so that the server will try + # to respond to a routed address and not a link local one). + + a=${NSB_LO_IP} + log_start + show_hint "Should fail 'Network is unreachable' since server is not on link" + do_run_cmd nettest -B -N "${NSA}" -O "${NSB}" -c "${NSA_LO_IP}" -r ${a} --client-dontroute + log_test_addr ${a} $? 1 "SO_DONTROUTE client, syncookies=${syncookies}" + + a=${NSB_LO_IP} + log_start + show_hint "Should timeout since server cannot respond (client is not on link)" + do_run_cmd nettest -B -N "${NSA}" -O "${NSB}" -c "${NSA_LO_IP}" -r ${a} --server-dontroute + log_test_addr ${a} $? 2 "SO_DONTROUTE server, syncookies=${syncookies}" + + ip netns exec "${NSB}" sysctl -wq net.ipv4.tcp_syncookies=${nsb_syncookies} + ip netns exec "${NSA}" sysctl -wq net.ipv4.tcp_syncookies=${nsa_syncookies} +} + ipv4_tcp_novrf() { local a @@ -1217,6 +1270,9 @@ ipv4_tcp_novrf() log_test_addr ${a} $? 1 "No server, device client, local conn" ipv4_tcp_md5_novrf + + ipv4_tcp_dontroute 0 + ipv4_tcp_dontroute 2 } ipv4_tcp_vrf() -- cgit v1.2.3 From a431327c4faacf978defa94dd0da1710d0c69801 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 11 May 2023 16:39:39 +0200 Subject: selftests: fcnal: Test SO_DONTROUTE on UDP sockets. Use nettest --client-dontroute to test the kernel behaviour with UDP sockets having the SO_DONTROUTE option. Sending packets to a neighbour (on link) host, should work. When the host is behind a router, sending should fail. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fcnal-test.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index 3a1f3051321f..08b4b96cbd63 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -1641,6 +1641,23 @@ ipv4_udp_novrf() log_start run_cmd nettest -D -d ${NSA_DEV} -r ${a} log_test_addr ${a} $? 2 "No server, device client, local conn" + + # + # Link local connection tests (SO_DONTROUTE). + # Connections should succeed only when the remote IP address is + # on link (doesn't need to be routed through a gateway). + # + + a=${NSB_IP} + log_start + do_run_cmd nettest -B -D -N "${NSA}" -O "${NSB}" -r ${a} --client-dontroute + log_test_addr ${a} $? 0 "SO_DONTROUTE client" + + a=${NSB_LO_IP} + log_start + show_hint "Should fail 'Network is unreachable' since server is not on link" + do_run_cmd nettest -B -D -N "${NSA}" -O "${NSB}" -r ${a} --client-dontroute + log_test_addr ${a} $? 1 "SO_DONTROUTE client" } ipv4_udp_vrf() -- cgit v1.2.3 From ceec9f272432b03168376d6487e7e7817d215f07 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 11 May 2023 16:39:46 +0200 Subject: selftests: fcnal: Test SO_DONTROUTE on raw and ping sockets. Use ping -r to test the kernel behaviour with raw and ping sockets having the SO_DONTROUTE option. Since ipv4_ping_novrf() is called with different values of net.ipv4.ping_group_range, then it tests both raw and ping sockets (ping uses ping sockets if its user ID belongs to ping_group_range and raw sockets otherwise). With both socket types, sending packets to a neighbour (on link) host, should work. When the host is behind a router, sending should fail. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fcnal-test.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/testing/selftests/net/fcnal-test.sh b/tools/testing/selftests/net/fcnal-test.sh index 08b4b96cbd63..05b5c4af7a08 100755 --- a/tools/testing/selftests/net/fcnal-test.sh +++ b/tools/testing/selftests/net/fcnal-test.sh @@ -584,6 +584,20 @@ ipv4_ping_novrf() log_test_addr ${a} $? 0 "ping out, address bind" done + # + # out, but don't use gateway if peer is not on link + # + a=${NSB_IP} + log_start + run_cmd ping -c 1 -w 1 -r ${a} + log_test_addr ${a} $? 0 "ping out (don't route), peer on link" + + a=${NSB_LO_IP} + log_start + show_hint "Fails since peer is not on link" + run_cmd ping -c 1 -w 1 -r ${a} + log_test_addr ${a} $? 1 "ping out (don't route), peer not on link" + # # in # -- cgit v1.2.3 From 2598619e012cee5273a2821441b9a051ad931249 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 11 May 2023 15:25:06 +0200 Subject: sctp: add bpf_bypass_getsockopt proto callback Implement ->bpf_bypass_getsockopt proto callback and filter out SCTP_SOCKOPT_PEELOFF, SCTP_SOCKOPT_PEELOFF_FLAGS and SCTP_SOCKOPT_CONNECTX3 socket options from running eBPF hook on them. SCTP_SOCKOPT_PEELOFF and SCTP_SOCKOPT_PEELOFF_FLAGS options do fd_install(), and if BPF_CGROUP_RUN_PROG_GETSOCKOPT hook returns an error after success of the original handler sctp_getsockopt(...), userspace will receive an error from getsockopt syscall and will be not aware that fd was successfully installed into a fdtable. As pointed by Marcelo Ricardo Leitner it seems reasonable to skip bpf getsockopt hook for SCTP_SOCKOPT_CONNECTX3 sockopt too. Because internaly, it triggers connect() and if error is masked then userspace will be confused. This patch was born as a result of discussion around a new SCM_PIDFD interface: https://lore.kernel.org/all/20230413133355.350571-3-aleksandr.mikhalitsyn@canonical.com/ Fixes: 0d01da6afc54 ("bpf: implement getsockopt and setsockopt hooks") Cc: Daniel Borkmann Cc: Christian Brauner Cc: Stanislav Fomichev Cc: Neil Horman Cc: Marcelo Ricardo Leitner Cc: Xin Long Cc: linux-sctp@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Suggested-by: Stanislav Fomichev Acked-by: Stanislav Fomichev Signed-off-by: Alexander Mikhalitsyn Acked-by: Xin Long Signed-off-by: David S. Miller --- net/sctp/socket.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index cda8c2874691..a68e1d541b12 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -8281,6 +8281,22 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname, return retval; } +static bool sctp_bpf_bypass_getsockopt(int level, int optname) +{ + if (level == SOL_SCTP) { + switch (optname) { + case SCTP_SOCKOPT_PEELOFF: + case SCTP_SOCKOPT_PEELOFF_FLAGS: + case SCTP_SOCKOPT_CONNECTX3: + return true; + default: + return false; + } + } + + return false; +} + static int sctp_hash(struct sock *sk) { /* STUB */ @@ -9650,6 +9666,7 @@ struct proto sctp_prot = { .shutdown = sctp_shutdown, .setsockopt = sctp_setsockopt, .getsockopt = sctp_getsockopt, + .bpf_bypass_getsockopt = sctp_bpf_bypass_getsockopt, .sendmsg = sctp_sendmsg, .recvmsg = sctp_recvmsg, .bind = sctp_bind, @@ -9705,6 +9722,7 @@ struct proto sctpv6_prot = { .shutdown = sctp_shutdown, .setsockopt = sctp_setsockopt, .getsockopt = sctp_getsockopt, + .bpf_bypass_getsockopt = sctp_bpf_bypass_getsockopt, .sendmsg = sctp_sendmsg, .recvmsg = sctp_recvmsg, .bind = sctp_bind, -- cgit v1.2.3 From d3616dc7793ffab17f3362fb439bfc1f887e6d8e Mon Sep 17 00:00:00 2001 From: wuych Date: Fri, 12 May 2023 10:44:03 +0800 Subject: net: liquidio: lio_main: Remove unnecessary (void*) conversions Pointer variables of void * type do not require type cast. Signed-off-by: wuych Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_main.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 9bd1d2d7027d..100daadbea2a 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -191,8 +191,7 @@ static void octeon_droq_bh(struct tasklet_struct *t) static int lio_wait_for_oq_pkts(struct octeon_device *oct) { - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; int retry = 100, pkt_cnt = 0, pending_pkts = 0; int i; @@ -950,8 +949,7 @@ static void octeon_destroy_resources(struct octeon_device *oct) { int i, refcount; struct msix_entry *msix_entries; - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; struct handshake *hs; @@ -1211,8 +1209,7 @@ static int send_rx_ctrl_cmd(struct lio *lio, int start_stop) static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx) { struct net_device *netdev = oct->props[ifidx].netdev; - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; struct napi_struct *napi, *n; struct lio *lio; @@ -1774,8 +1771,7 @@ static int liquidio_open(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; struct napi_struct *napi, *n; int ret = 0; @@ -1855,8 +1851,7 @@ static int liquidio_stop(struct net_device *netdev) { struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)oct->priv; + struct octeon_device_priv *oct_priv = oct->priv; struct napi_struct *napi, *n; int ret = 0; @@ -4057,8 +4052,7 @@ static int octeon_device_init(struct octeon_device *octeon_dev) char bootcmd[] = "\n"; char *dbg_enb = NULL; enum lio_fw_state fw_state; - struct octeon_device_priv *oct_priv = - (struct octeon_device_priv *)octeon_dev->priv; + struct octeon_device_priv *oct_priv = octeon_dev->priv; atomic_set(&octeon_dev->status, OCT_DEV_BEGIN_STATE); /* Enable access to the octeon device and make its DMA capability -- cgit v1.2.3 From 28fa3ac487c6d30aaa10570481c27b6adfc492b3 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 11 May 2023 20:47:28 +0100 Subject: sfc: release encap match in efx_tc_flow_free() When force-freeing leftover entries from our match_action_ht, call efx_tc_delete_rule(), which releases all the rule's resources, rather than open-coding it. The open-coded version was missing a call to release the rule's encap match (if any). It probably doesn't matter as everything's being torn down anyway, but it's cleaner this way and prevents further error messages potentially being logged by efx_tc_encap_match_free() later on. Move efx_tc_flow_free() further down the file to avoid introducing a forward declaration of efx_tc_delete_rule(). Fixes: 17654d84b47c ("sfc: add offloading of 'foreign' TC (decap) rules") Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/tc.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 0327639a628a..236b44a4215e 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -132,23 +132,6 @@ static void efx_tc_free_action_set_list(struct efx_nic *efx, /* Don't kfree, as acts is embedded inside a struct efx_tc_flow_rule */ } -static void efx_tc_flow_free(void *ptr, void *arg) -{ - struct efx_tc_flow_rule *rule = ptr; - struct efx_nic *efx = arg; - - netif_err(efx, drv, efx->net_dev, - "tc rule %lx still present at teardown, removing\n", - rule->cookie); - - efx_mae_delete_rule(efx, rule->fw_id); - - /* Release entries in subsidiary tables */ - efx_tc_free_action_set_list(efx, &rule->acts, true); - - kfree(rule); -} - /* Boilerplate for the simple 'copy a field' cases */ #define _MAP_KEY_AND_MASK(_name, _type, _tcget, _tcfield, _field) \ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_##_name)) { \ @@ -1454,6 +1437,21 @@ static void efx_tc_encap_match_free(void *ptr, void *__unused) kfree(encap); } +static void efx_tc_flow_free(void *ptr, void *arg) +{ + struct efx_tc_flow_rule *rule = ptr; + struct efx_nic *efx = arg; + + netif_err(efx, drv, efx->net_dev, + "tc rule %lx still present at teardown, removing\n", + rule->cookie); + + /* Also releases entries in subsidiary tables */ + efx_tc_delete_rule(efx, rule); + + kfree(rule); +} + int efx_init_struct_tc(struct efx_nic *efx) { int rc; -- cgit v1.2.3 From 56beb35d85e290b71372d7ee1093621f6abb6e96 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 11 May 2023 20:47:29 +0100 Subject: sfc: populate enc_ip_tos matches in MAE outer rules Currently tc.c will block them before they get here, but following patch will change that. Use the extack message from efx_mae_check_encap_match_caps() instead of writing a new one, since there's now more being fed in than just an IP version. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mae.c | 16 +++++++++++++++- drivers/net/ethernet/sfc/mae.h | 1 + drivers/net/ethernet/sfc/tc.c | 9 +++------ drivers/net/ethernet/sfc/tc.h | 1 + 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c index 49706a7b94bf..8f4bb5d36ad8 100644 --- a/drivers/net/ethernet/sfc/mae.c +++ b/drivers/net/ethernet/sfc/mae.c @@ -482,12 +482,14 @@ int efx_mae_match_check_caps(struct efx_nic *efx, rc; \ }) /* Checks that the fields needed for encap-rule matches are supported by the - * MAE. All the fields are exact-match. + * MAE. All the fields are exact-match, except possibly ENC_IP_TOS. */ int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, + u8 ip_tos_mask, struct netlink_ext_ack *extack) { u8 *supported_fields = efx->tc->caps->outer_rule_fields; + enum mask_type typ; int rc; if (CHECK(ENC_ETHER_TYPE)) @@ -504,6 +506,14 @@ int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, if (CHECK(ENC_L4_DPORT) || CHECK(ENC_IP_PROTO)) return rc; + typ = classify_mask(&ip_tos_mask, sizeof(ip_tos_mask)); + rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_IP_TOS], + typ); + if (rc) { + NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s", + mask_type_name(typ), "enc_ip_tos"); + return rc; + } return 0; } #undef CHECK @@ -1003,6 +1013,10 @@ int efx_mae_register_encap_match(struct efx_nic *efx, ~(__be16)0); MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, IPPROTO_UDP); MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, ~0); + MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS, + encap->ip_tos); + MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK, + encap->ip_tos_mask); rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h index 9226219491a0..cec61bfde4d4 100644 --- a/drivers/net/ethernet/sfc/mae.h +++ b/drivers/net/ethernet/sfc/mae.h @@ -82,6 +82,7 @@ int efx_mae_match_check_caps(struct efx_nic *efx, const struct efx_tc_match_fields *mask, struct netlink_ext_ack *extack); int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, + u8 ip_tos_mask, struct netlink_ext_ack *extack); int efx_mae_check_encap_type_supported(struct efx_nic *efx, enum efx_encap_type typ); diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 236b44a4215e..c2dda3ae5492 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -410,12 +410,9 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, return -EOPNOTSUPP; } - rc = efx_mae_check_encap_match_caps(efx, ipv6, extack); - if (rc) { - NL_SET_ERR_MSG_FMT_MOD(extack, "MAE hw reports no support for IPv%d encap matches", - ipv6 ? 6 : 4); - return -EOPNOTSUPP; - } + rc = efx_mae_check_encap_match_caps(efx, ipv6, match->mask.enc_ip_tos, extack); + if (rc) + return rc; encap = kzalloc(sizeof(*encap), GFP_USER); if (!encap) diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h index 04cced6a2d39..8d2abca26c23 100644 --- a/drivers/net/ethernet/sfc/tc.h +++ b/drivers/net/ethernet/sfc/tc.h @@ -78,6 +78,7 @@ struct efx_tc_encap_match { __be32 src_ip, dst_ip; struct in6_addr src_ip6, dst_ip6; __be16 udp_dport; + u8 ip_tos, ip_tos_mask; struct rhash_head linkage; enum efx_encap_type tun_type; refcount_t ref; -- cgit v1.2.3 From 3c9561c0a5b988be3dfd24ea1de2301b95efc640 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 11 May 2023 20:47:30 +0100 Subject: sfc: support TC decap rules matching on enc_ip_tos Allow efx_tc_encap_match entries to include an ip_tos and ip_tos_mask. To avoid partially-overlapping Outer Rules (which can lead to undefined behaviour in the hardware), store extra "pseudo" entries in our encap_match hashtable, which are used to enforce that all Outer Rule entries within a given tuple (or IPv6 equivalent) have the same ip_tos_mask. The "direct" encap_match entry takes a reference on the "pseudo", allowing it to be destroyed when all "direct" entries using it are removed. efx_tc_em_pseudo_type is an enum rather than just a bool because in future an additional pseudo-type will be added to support Conntrack offload. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/tc.c | 145 +++++++++++++++++++++++++++++++----------- drivers/net/ethernet/sfc/tc.h | 24 +++++++ 2 files changed, 133 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index c2dda3ae5492..8e1769d2c4ee 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -202,6 +202,7 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx, BIT(FLOW_DISSECTOR_KEY_ENC_KEYID) | BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) | BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) | + BIT(FLOW_DISSECTOR_KEY_ENC_IP) | BIT(FLOW_DISSECTOR_KEY_ENC_PORTS) | BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) | BIT(FLOW_DISSECTOR_KEY_TCP) | @@ -346,20 +347,47 @@ static int efx_tc_flower_parse_match(struct efx_nic *efx, return 0; } +static void efx_tc_flower_release_encap_match(struct efx_nic *efx, + struct efx_tc_encap_match *encap) +{ + int rc; + + if (!refcount_dec_and_test(&encap->ref)) + return; /* still in use */ + + if (encap->type == EFX_TC_EM_DIRECT) { + rc = efx_mae_unregister_encap_match(efx, encap); + if (rc) + /* Display message but carry on and remove entry from our + * SW tables, because there's not much we can do about it. + */ + netif_err(efx, drv, efx->net_dev, + "Failed to release encap match %#x, rc %d\n", + encap->fw_id, rc); + } + rhashtable_remove_fast(&efx->tc->encap_match_ht, &encap->linkage, + efx_tc_encap_match_ht_params); + if (encap->pseudo) + efx_tc_flower_release_encap_match(efx, encap->pseudo); + kfree(encap); +} + static int efx_tc_flower_record_encap_match(struct efx_nic *efx, struct efx_tc_match *match, enum efx_encap_type type, + enum efx_tc_em_pseudo_type em_type, + u8 child_ip_tos_mask, struct netlink_ext_ack *extack) { - struct efx_tc_encap_match *encap, *old; + struct efx_tc_encap_match *encap, *old, *pseudo = NULL; bool ipv6 = false; int rc; /* We require that the socket-defining fields (IP addrs and UDP dest - * port) are present and exact-match. Other fields are currently not - * allowed. This meets what OVS will ask for, and means that we don't - * need to handle difficult checks for overlapping matches as could - * come up if we allowed masks or varying sets of match fields. + * port) are present and exact-match. Other fields may only be used + * if the field-set (and any masks) are the same for all encap + * matches on the same tuple; this is enforced by + * pseudo encap matches. */ if (match->mask.enc_dst_ip | match->mask.enc_src_ip) { if (!IS_ALL_ONES(match->mask.enc_dst_ip)) { @@ -402,21 +430,37 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, return -EOPNOTSUPP; } if (match->mask.enc_ip_tos) { - NL_SET_ERR_MSG_MOD(extack, "Egress encap match on IP ToS not supported"); - return -EOPNOTSUPP; + struct efx_tc_match pmatch = *match; + + if (em_type == EFX_TC_EM_PSEUDO_MASK) { /* can't happen */ + NL_SET_ERR_MSG_MOD(extack, "Bad recursion in egress encap match handler"); + return -EOPNOTSUPP; + } + pmatch.value.enc_ip_tos = 0; + pmatch.mask.enc_ip_tos = 0; + rc = efx_tc_flower_record_encap_match(efx, &pmatch, type, + EFX_TC_EM_PSEUDO_MASK, + match->mask.enc_ip_tos, + extack); + if (rc) + return rc; + pseudo = pmatch.encap; } if (match->mask.enc_ip_ttl) { NL_SET_ERR_MSG_MOD(extack, "Egress encap match on IP TTL not supported"); - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + goto fail_pseudo; } rc = efx_mae_check_encap_match_caps(efx, ipv6, match->mask.enc_ip_tos, extack); if (rc) - return rc; + goto fail_pseudo; encap = kzalloc(sizeof(*encap), GFP_USER); - if (!encap) - return -ENOMEM; + if (!encap) { + rc = -ENOMEM; + goto fail_pseudo; + } encap->src_ip = match->value.enc_src_ip; encap->dst_ip = match->value.enc_dst_ip; #ifdef CONFIG_IPV6 @@ -425,12 +469,56 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, #endif encap->udp_dport = match->value.enc_dport; encap->tun_type = type; + encap->ip_tos = match->value.enc_ip_tos; + encap->ip_tos_mask = match->mask.enc_ip_tos; + encap->child_ip_tos_mask = child_ip_tos_mask; + encap->type = em_type; + encap->pseudo = pseudo; old = rhashtable_lookup_get_insert_fast(&efx->tc->encap_match_ht, &encap->linkage, efx_tc_encap_match_ht_params); if (old) { /* don't need our new entry */ kfree(encap); + if (pseudo) /* don't need our new pseudo either */ + efx_tc_flower_release_encap_match(efx, pseudo); + /* check old and new em_types are compatible */ + switch (old->type) { + case EFX_TC_EM_DIRECT: + /* old EM is in hardware, so mustn't overlap with a + * pseudo, but may be shared with another direct EM + */ + if (em_type == EFX_TC_EM_DIRECT) + break; + NL_SET_ERR_MSG_MOD(extack, "Pseudo encap match conflicts with existing direct entry"); + return -EEXIST; + case EFX_TC_EM_PSEUDO_MASK: + /* old EM is protecting a ToS-qualified filter, so may + * only be shared with another pseudo for the same + * ToS mask. + */ + if (em_type != EFX_TC_EM_PSEUDO_MASK) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "%s encap match conflicts with existing pseudo(MASK) entry", + encap->type ? "Pseudo" : "Direct"); + return -EEXIST; + } + if (child_ip_tos_mask != old->child_ip_tos_mask) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "Pseudo encap match for TOS mask %#04x conflicts with existing pseudo(MASK) entry for TOS mask %#04x", + child_ip_tos_mask, + old->child_ip_tos_mask); + return -EEXIST; + } + break; + default: /* Unrecognised pseudo-type. Just say no */ + NL_SET_ERR_MSG_FMT_MOD(extack, + "%s encap match conflicts with existing pseudo(%d) entry", + encap->type ? "Pseudo" : "Direct", + old->type); + return -EEXIST; + } + /* check old and new tun_types are compatible */ if (old->tun_type != type) { NL_SET_ERR_MSG_FMT_MOD(extack, "Egress encap match with conflicting tun_type %u != %u", @@ -442,10 +530,12 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, /* existing entry found */ encap = old; } else { - rc = efx_mae_register_encap_match(efx, encap); - if (rc) { - NL_SET_ERR_MSG_MOD(extack, "Failed to record egress encap match in HW"); - goto fail; + if (em_type == EFX_TC_EM_DIRECT) { + rc = efx_mae_register_encap_match(efx, encap); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Failed to record egress encap match in HW"); + goto fail; + } } refcount_set(&encap->ref, 1); } @@ -455,30 +545,12 @@ fail: rhashtable_remove_fast(&efx->tc->encap_match_ht, &encap->linkage, efx_tc_encap_match_ht_params); kfree(encap); +fail_pseudo: + if (pseudo) + efx_tc_flower_release_encap_match(efx, pseudo); return rc; } -static void efx_tc_flower_release_encap_match(struct efx_nic *efx, - struct efx_tc_encap_match *encap) -{ - int rc; - - if (!refcount_dec_and_test(&encap->ref)) - return; /* still in use */ - - rc = efx_mae_unregister_encap_match(efx, encap); - if (rc) - /* Display message but carry on and remove entry from our - * SW tables, because there's not much we can do about it. - */ - netif_err(efx, drv, efx->net_dev, - "Failed to release encap match %#x, rc %d\n", - encap->fw_id, rc); - rhashtable_remove_fast(&efx->tc->encap_match_ht, &encap->linkage, - efx_tc_encap_match_ht_params); - kfree(encap); -} - static void efx_tc_delete_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rule) { efx_mae_delete_rule(efx, rule->fw_id); @@ -632,6 +704,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx, } rc = efx_tc_flower_record_encap_match(efx, &match, type, + EFX_TC_EM_DIRECT, 0, extack); if (rc) goto release; diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h index 8d2abca26c23..0f14481d2d9e 100644 --- a/drivers/net/ethernet/sfc/tc.h +++ b/drivers/net/ethernet/sfc/tc.h @@ -74,6 +74,27 @@ static inline bool efx_tc_match_is_encap(const struct efx_tc_match_fields *mask) mask->enc_ip_ttl || mask->enc_sport || mask->enc_dport; } +/** + * enum efx_tc_em_pseudo_type - &struct efx_tc_encap_match pseudo type + * + * These are used to classify "pseudo" encap matches, which don't refer + * to an entry in hardware but rather indicate that a section of the + * match space is in use by another Outer Rule. + * + * @EFX_TC_EM_DIRECT: real HW entry in Outer Rule table; not a pseudo. + * Hardware index in &struct efx_tc_encap_match.fw_id is valid. + * @EFX_TC_EM_PSEUDO_MASK: registered by an encap match which includes a + * match on an optional field (currently only ip_tos), to prevent an + * overlapping encap match _without_ optional fields. + * The pseudo encap match may be referenced again by an encap match + * with a different ip_tos value, but all ip_tos_mask must match the + * first (stored in our child_ip_tos_mask). + */ +enum efx_tc_em_pseudo_type { + EFX_TC_EM_DIRECT, + EFX_TC_EM_PSEUDO_MASK, +}; + struct efx_tc_encap_match { __be32 src_ip, dst_ip; struct in6_addr src_ip6, dst_ip6; @@ -81,8 +102,11 @@ struct efx_tc_encap_match { u8 ip_tos, ip_tos_mask; struct rhash_head linkage; enum efx_encap_type tun_type; + u8 child_ip_tos_mask; refcount_t ref; + enum efx_tc_em_pseudo_type type; u32 fw_id; /* index of this entry in firmware encap match table */ + struct efx_tc_encap_match *pseudo; /* Referenced pseudo EM if needed */ }; struct efx_tc_match { -- cgit v1.2.3 From b6583d5e9e94adce1be61ec59fef4e129f0bc68a Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 11 May 2023 20:47:31 +0100 Subject: sfc: support TC decap rules matching on enc_src_port Allow efx_tc_encap_match entries to include a udp_sport and a udp_sport_mask. As with enc_ip_tos, use pseudos to enforce that all encap matches within a given tuple have the same udp_sport_mask. Note that since we use a single layer of pseudos for both fields, two matches that differ in (say) udp_sport value aren't permitted to have different ip_tos_mask, even though this would technically be safe. Current userland TC does not support setting enc_src_port; this patch was tested with an iproute2 patched to support it. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mae.c | 14 +++++++++++++- drivers/net/ethernet/sfc/mae.h | 2 +- drivers/net/ethernet/sfc/tc.c | 31 +++++++++++++++++++++---------- drivers/net/ethernet/sfc/tc.h | 10 ++++++---- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c index 8f4bb5d36ad8..37a4c6925ad4 100644 --- a/drivers/net/ethernet/sfc/mae.c +++ b/drivers/net/ethernet/sfc/mae.c @@ -485,7 +485,7 @@ int efx_mae_match_check_caps(struct efx_nic *efx, * MAE. All the fields are exact-match, except possibly ENC_IP_TOS. */ int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, - u8 ip_tos_mask, + u8 ip_tos_mask, __be16 udp_sport_mask, struct netlink_ext_ack *extack) { u8 *supported_fields = efx->tc->caps->outer_rule_fields; @@ -506,6 +506,14 @@ int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, if (CHECK(ENC_L4_DPORT) || CHECK(ENC_IP_PROTO)) return rc; + typ = classify_mask((const u8 *)&udp_sport_mask, sizeof(udp_sport_mask)); + rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_L4_SPORT], + typ); + if (rc) { + NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s", + mask_type_name(typ), "enc_src_port"); + return rc; + } typ = classify_mask(&ip_tos_mask, sizeof(ip_tos_mask)); rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_IP_TOS], typ); @@ -1011,6 +1019,10 @@ int efx_mae_register_encap_match(struct efx_nic *efx, encap->udp_dport); MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, ~(__be16)0); + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, + encap->udp_sport); + MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, + encap->udp_sport_mask); MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, IPPROTO_UDP); MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, ~0); MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS, diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h index cec61bfde4d4..1cf8dfeb0c28 100644 --- a/drivers/net/ethernet/sfc/mae.h +++ b/drivers/net/ethernet/sfc/mae.h @@ -82,7 +82,7 @@ int efx_mae_match_check_caps(struct efx_nic *efx, const struct efx_tc_match_fields *mask, struct netlink_ext_ack *extack); int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, - u8 ip_tos_mask, + u8 ip_tos_mask, __be16 udp_sport_mask, struct netlink_ext_ack *extack); int efx_mae_check_encap_type_supported(struct efx_nic *efx, enum efx_encap_type typ); diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 8e1769d2c4ee..da684b4b7211 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -377,6 +377,7 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, enum efx_encap_type type, enum efx_tc_em_pseudo_type em_type, u8 child_ip_tos_mask, + __be16 child_udp_sport_mask, struct netlink_ext_ack *extack) { struct efx_tc_encap_match *encap, *old, *pseudo = NULL; @@ -425,11 +426,7 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, NL_SET_ERR_MSG_MOD(extack, "Egress encap match is not exact on dst UDP port"); return -EOPNOTSUPP; } - if (match->mask.enc_sport) { - NL_SET_ERR_MSG_MOD(extack, "Egress encap match on src UDP port not supported"); - return -EOPNOTSUPP; - } - if (match->mask.enc_ip_tos) { + if (match->mask.enc_sport || match->mask.enc_ip_tos) { struct efx_tc_match pmatch = *match; if (em_type == EFX_TC_EM_PSEUDO_MASK) { /* can't happen */ @@ -438,9 +435,12 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, } pmatch.value.enc_ip_tos = 0; pmatch.mask.enc_ip_tos = 0; + pmatch.value.enc_sport = 0; + pmatch.mask.enc_sport = 0; rc = efx_tc_flower_record_encap_match(efx, &pmatch, type, EFX_TC_EM_PSEUDO_MASK, match->mask.enc_ip_tos, + match->mask.enc_sport, extack); if (rc) return rc; @@ -452,7 +452,8 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, goto fail_pseudo; } - rc = efx_mae_check_encap_match_caps(efx, ipv6, match->mask.enc_ip_tos, extack); + rc = efx_mae_check_encap_match_caps(efx, ipv6, match->mask.enc_ip_tos, + match->mask.enc_sport, extack); if (rc) goto fail_pseudo; @@ -472,6 +473,9 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, encap->ip_tos = match->value.enc_ip_tos; encap->ip_tos_mask = match->mask.enc_ip_tos; encap->child_ip_tos_mask = child_ip_tos_mask; + encap->udp_sport = match->value.enc_sport; + encap->udp_sport_mask = match->mask.enc_sport; + encap->child_udp_sport_mask = child_udp_sport_mask; encap->type = em_type; encap->pseudo = pseudo; old = rhashtable_lookup_get_insert_fast(&efx->tc->encap_match_ht, @@ -493,9 +497,9 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, NL_SET_ERR_MSG_MOD(extack, "Pseudo encap match conflicts with existing direct entry"); return -EEXIST; case EFX_TC_EM_PSEUDO_MASK: - /* old EM is protecting a ToS-qualified filter, so may - * only be shared with another pseudo for the same - * ToS mask. + /* old EM is protecting a ToS- or src port-qualified + * filter, so may only be shared with another pseudo + * for the same ToS and src port masks. */ if (em_type != EFX_TC_EM_PSEUDO_MASK) { NL_SET_ERR_MSG_FMT_MOD(extack, @@ -510,6 +514,13 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, old->child_ip_tos_mask); return -EEXIST; } + if (child_udp_sport_mask != old->child_udp_sport_mask) { + NL_SET_ERR_MSG_FMT_MOD(extack, + "Pseudo encap match for UDP src port mask %#x conflicts with existing pseudo(MASK) entry for mask %#x", + child_udp_sport_mask, + old->child_udp_sport_mask); + return -EEXIST; + } break; default: /* Unrecognised pseudo-type. Just say no */ NL_SET_ERR_MSG_FMT_MOD(extack, @@ -704,7 +715,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx, } rc = efx_tc_flower_record_encap_match(efx, &match, type, - EFX_TC_EM_DIRECT, 0, + EFX_TC_EM_DIRECT, 0, 0, extack); if (rc) goto release; diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h index 0f14481d2d9e..24e9640c74e9 100644 --- a/drivers/net/ethernet/sfc/tc.h +++ b/drivers/net/ethernet/sfc/tc.h @@ -84,11 +84,11 @@ static inline bool efx_tc_match_is_encap(const struct efx_tc_match_fields *mask) * @EFX_TC_EM_DIRECT: real HW entry in Outer Rule table; not a pseudo. * Hardware index in &struct efx_tc_encap_match.fw_id is valid. * @EFX_TC_EM_PSEUDO_MASK: registered by an encap match which includes a - * match on an optional field (currently only ip_tos), to prevent an - * overlapping encap match _without_ optional fields. + * match on an optional field (currently ip_tos and/or udp_sport), + * to prevent an overlapping encap match _without_ optional fields. * The pseudo encap match may be referenced again by an encap match - * with a different ip_tos value, but all ip_tos_mask must match the - * first (stored in our child_ip_tos_mask). + * with different values for these fields, but all masks must match the + * first (stored in our child_* fields). */ enum efx_tc_em_pseudo_type { EFX_TC_EM_DIRECT, @@ -99,10 +99,12 @@ struct efx_tc_encap_match { __be32 src_ip, dst_ip; struct in6_addr src_ip6, dst_ip6; __be16 udp_dport; + __be16 udp_sport, udp_sport_mask; u8 ip_tos, ip_tos_mask; struct rhash_head linkage; enum efx_encap_type tun_type; u8 child_ip_tos_mask; + __be16 child_udp_sport_mask; refcount_t ref; enum efx_tc_em_pseudo_type type; u32 fw_id; /* index of this entry in firmware encap match table */ -- cgit v1.2.3 From 7b99f75942da332e3f4f865e55a10fec95a30d4f Mon Sep 17 00:00:00 2001 From: Alan Maguire Date: Wed, 10 May 2023 14:02:41 +0100 Subject: bpf: Add --skip_encoding_btf_inconsistent_proto, --btf_gen_optimized to pahole flags for v1.25 v1.25 of pahole supports filtering out functions with multiple inconsistent function prototypes or optimized-out parameters from the BTF representation. These present problems because there is no additional info in BTF saying which inconsistent prototype matches which function instance to help guide attachment, and functions with optimized-out parameters can lead to incorrect assumptions about register contents. So for now, filter out such functions while adding BTF representations for functions that have "."-suffixes (foo.isra.0) but not optimized-out parameters. This patch assumes that below linked changes land in pahole for v1.25. Issues with pahole filtering being too aggressive in removing functions appear to be resolved now, but CI and further testing will confirm. Signed-off-by: Alan Maguire Acked-by: Jiri Olsa Link: https://lore.kernel.org/r/20230510130241.1696561-1-alan.maguire@oracle.com Signed-off-by: Alexei Starovoitov --- scripts/pahole-flags.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh index 1f1f1d397c39..728d55190d97 100755 --- a/scripts/pahole-flags.sh +++ b/scripts/pahole-flags.sh @@ -23,5 +23,8 @@ if [ "${pahole_ver}" -ge "124" ]; then # see PAHOLE_HAS_LANG_EXCLUDE extra_paholeopt="${extra_paholeopt} --lang_exclude=rust" fi +if [ "${pahole_ver}" -ge "125" ]; then + extra_paholeopt="${extra_paholeopt} --skip_encoding_btf_inconsistent_proto --btf_gen_optimized" +fi echo ${extra_paholeopt} -- cgit v1.2.3 From ee9fd0ac3017c4313be91a220a9ac4c99dde7ad4 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Wed, 10 May 2023 21:37:48 -0700 Subject: bpf: Address KCSAN report on bpf_lru_list KCSAN reported a data-race when accessing node->ref. Although node->ref does not have to be accurate, take this chance to use a more common READ_ONCE() and WRITE_ONCE() pattern instead of data_race(). There is an existing bpf_lru_node_is_ref() and bpf_lru_node_set_ref(). This patch also adds bpf_lru_node_clear_ref() to do the WRITE_ONCE(node->ref, 0) also. ================================================================== BUG: KCSAN: data-race in __bpf_lru_list_rotate / __htab_lru_percpu_map_update_elem write to 0xffff888137038deb of 1 bytes by task 11240 on cpu 1: __bpf_lru_node_move kernel/bpf/bpf_lru_list.c:113 [inline] __bpf_lru_list_rotate_active kernel/bpf/bpf_lru_list.c:149 [inline] __bpf_lru_list_rotate+0x1bf/0x750 kernel/bpf/bpf_lru_list.c:240 bpf_lru_list_pop_free_to_local kernel/bpf/bpf_lru_list.c:329 [inline] bpf_common_lru_pop_free kernel/bpf/bpf_lru_list.c:447 [inline] bpf_lru_pop_free+0x638/0xe20 kernel/bpf/bpf_lru_list.c:499 prealloc_lru_pop kernel/bpf/hashtab.c:290 [inline] __htab_lru_percpu_map_update_elem+0xe7/0x820 kernel/bpf/hashtab.c:1316 bpf_percpu_hash_update+0x5e/0x90 kernel/bpf/hashtab.c:2313 bpf_map_update_value+0x2a9/0x370 kernel/bpf/syscall.c:200 generic_map_update_batch+0x3ae/0x4f0 kernel/bpf/syscall.c:1687 bpf_map_do_batch+0x2d9/0x3d0 kernel/bpf/syscall.c:4534 __sys_bpf+0x338/0x810 __do_sys_bpf kernel/bpf/syscall.c:5096 [inline] __se_sys_bpf kernel/bpf/syscall.c:5094 [inline] __x64_sys_bpf+0x43/0x50 kernel/bpf/syscall.c:5094 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd read to 0xffff888137038deb of 1 bytes by task 11241 on cpu 0: bpf_lru_node_set_ref kernel/bpf/bpf_lru_list.h:70 [inline] __htab_lru_percpu_map_update_elem+0x2f1/0x820 kernel/bpf/hashtab.c:1332 bpf_percpu_hash_update+0x5e/0x90 kernel/bpf/hashtab.c:2313 bpf_map_update_value+0x2a9/0x370 kernel/bpf/syscall.c:200 generic_map_update_batch+0x3ae/0x4f0 kernel/bpf/syscall.c:1687 bpf_map_do_batch+0x2d9/0x3d0 kernel/bpf/syscall.c:4534 __sys_bpf+0x338/0x810 __do_sys_bpf kernel/bpf/syscall.c:5096 [inline] __se_sys_bpf kernel/bpf/syscall.c:5094 [inline] __x64_sys_bpf+0x43/0x50 kernel/bpf/syscall.c:5094 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd value changed: 0x01 -> 0x00 Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 11241 Comm: syz-executor.3 Not tainted 6.3.0-rc7-syzkaller-00136-g6a66fdd29ea1 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 03/30/2023 ================================================================== Reported-by: syzbot+ebe648a84e8784763f82@syzkaller.appspotmail.com Signed-off-by: Martin KaFai Lau Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230511043748.1384166-1-martin.lau@linux.dev Signed-off-by: Alexei Starovoitov --- kernel/bpf/bpf_lru_list.c | 21 +++++++++++++-------- kernel/bpf/bpf_lru_list.h | 7 ++----- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/kernel/bpf/bpf_lru_list.c b/kernel/bpf/bpf_lru_list.c index d99e89f113c4..3dabdd137d10 100644 --- a/kernel/bpf/bpf_lru_list.c +++ b/kernel/bpf/bpf_lru_list.c @@ -41,7 +41,12 @@ static struct list_head *local_pending_list(struct bpf_lru_locallist *loc_l) /* bpf_lru_node helpers */ static bool bpf_lru_node_is_ref(const struct bpf_lru_node *node) { - return node->ref; + return READ_ONCE(node->ref); +} + +static void bpf_lru_node_clear_ref(struct bpf_lru_node *node) +{ + WRITE_ONCE(node->ref, 0); } static void bpf_lru_list_count_inc(struct bpf_lru_list *l, @@ -89,7 +94,7 @@ static void __bpf_lru_node_move_in(struct bpf_lru_list *l, bpf_lru_list_count_inc(l, tgt_type); node->type = tgt_type; - node->ref = 0; + bpf_lru_node_clear_ref(node); list_move(&node->list, &l->lists[tgt_type]); } @@ -110,7 +115,7 @@ static void __bpf_lru_node_move(struct bpf_lru_list *l, bpf_lru_list_count_inc(l, tgt_type); node->type = tgt_type; } - node->ref = 0; + bpf_lru_node_clear_ref(node); /* If the moving node is the next_inactive_rotation candidate, * move the next_inactive_rotation pointer also. @@ -353,7 +358,7 @@ static void __local_list_add_pending(struct bpf_lru *lru, *(u32 *)((void *)node + lru->hash_offset) = hash; node->cpu = cpu; node->type = BPF_LRU_LOCAL_LIST_T_PENDING; - node->ref = 0; + bpf_lru_node_clear_ref(node); list_add(&node->list, local_pending_list(loc_l)); } @@ -419,7 +424,7 @@ static struct bpf_lru_node *bpf_percpu_lru_pop_free(struct bpf_lru *lru, if (!list_empty(free_list)) { node = list_first_entry(free_list, struct bpf_lru_node, list); *(u32 *)((void *)node + lru->hash_offset) = hash; - node->ref = 0; + bpf_lru_node_clear_ref(node); __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_INACTIVE); } @@ -522,7 +527,7 @@ static void bpf_common_lru_push_free(struct bpf_lru *lru, } node->type = BPF_LRU_LOCAL_LIST_T_FREE; - node->ref = 0; + bpf_lru_node_clear_ref(node); list_move(&node->list, local_free_list(loc_l)); raw_spin_unlock_irqrestore(&loc_l->lock, flags); @@ -568,7 +573,7 @@ static void bpf_common_lru_populate(struct bpf_lru *lru, void *buf, node = (struct bpf_lru_node *)(buf + node_offset); node->type = BPF_LRU_LIST_T_FREE; - node->ref = 0; + bpf_lru_node_clear_ref(node); list_add(&node->list, &l->lists[BPF_LRU_LIST_T_FREE]); buf += elem_size; } @@ -594,7 +599,7 @@ again: node = (struct bpf_lru_node *)(buf + node_offset); node->cpu = cpu; node->type = BPF_LRU_LIST_T_FREE; - node->ref = 0; + bpf_lru_node_clear_ref(node); list_add(&node->list, &l->lists[BPF_LRU_LIST_T_FREE]); i++; buf += elem_size; diff --git a/kernel/bpf/bpf_lru_list.h b/kernel/bpf/bpf_lru_list.h index 4ea227c9c1ad..8f3c8b2b4490 100644 --- a/kernel/bpf/bpf_lru_list.h +++ b/kernel/bpf/bpf_lru_list.h @@ -64,11 +64,8 @@ struct bpf_lru { static inline void bpf_lru_node_set_ref(struct bpf_lru_node *node) { - /* ref is an approximation on access frequency. It does not - * have to be very accurate. Hence, no protection is used. - */ - if (!node->ref) - node->ref = 1; + if (!READ_ONCE(node->ref)) + WRITE_ONCE(node->ref, 1); } int bpf_lru_init(struct bpf_lru *lru, bool percpu, u32 hash_offset, -- cgit v1.2.3 From bdeeed3498c7871c17465bb4f11d1bc67f9098af Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 8 May 2023 23:55:02 -0700 Subject: libbpf: fix offsetof() and container_of() to work with CO-RE It seems like __builtin_offset() doesn't preserve CO-RE field relocations properly. So if offsetof() macro is defined through __builtin_offset(), CO-RE-enabled BPF code using container_of() will be subtly and silently broken. To avoid this problem, redefine offsetof() and container_of() in the form that works with CO-RE relocations more reliably. Fixes: 5fbc220862fc ("tools/libpf: Add offsetof/container_of macro in bpf_helpers.h") Reported-by: Lennart Poettering Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230509065502.2306180-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/bpf_helpers.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index 929a3baca8ef..bbab9ad9dc5a 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -77,16 +77,21 @@ /* * Helper macros to manipulate data structures */ -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((unsigned long)&((TYPE *)0)->MEMBER) -#endif -#ifndef container_of + +/* offsetof() definition that uses __builtin_offset() might not preserve field + * offset CO-RE relocation properly, so force-redefine offsetof() using + * old-school approach which works with CO-RE correctly + */ +#undef offsetof +#define offsetof(type, member) ((unsigned long)&((type *)0)->member) + +/* redefined container_of() to ensure we use the above offsetof() macro */ +#undef container_of #define container_of(ptr, type, member) \ ({ \ void *__mptr = (void *)(ptr); \ ((type *)(__mptr - offsetof(type, member))); \ }) -#endif /* * Compiler (optimization) barrier. -- cgit v1.2.3 From a7e3448086d580abadccff399316c6eb5ecdedbf Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 11 May 2023 10:21:08 -0700 Subject: net: phy: Allow drivers to always call into ->suspend() A few PHY drivers are currently attempting to not suspend the PHY when Wake-on-LAN is enabled, however that code is not currently executing at all due to an early check in phy_suspend(). This prevents PHY drivers from making an appropriate decisions and put the hardware into a low power state if desired. In order to allow the PHY drivers to opt into getting their ->suspend routine to be called, add a PHY_ALWAYS_CALL_SUSPEND bit which can be set. A boolean that tracks whether the PHY or the attached MAC has Wake-on-LAN enabled is also provided for convenience. If phydev::wol_enabled then the PHY shall not prevent its own Wake-on-LAN detection logic from working and shall not prevent the Ethernet MAC from receiving packets for matching. Reviewed-by: Simon Horman Reviewed-by: Andrew Lunn Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 5 +++-- include/linux/phy.h | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 17d0d0555a79..8852b0c53114 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1860,9 +1860,10 @@ int phy_suspend(struct phy_device *phydev) if (phydev->suspended) return 0; - /* If the device has WOL enabled, we cannot suspend the PHY */ phy_ethtool_get_wol(phydev, &wol); - if (wol.wolopts || (netdev && netdev->wol_enabled)) + phydev->wol_enabled = wol.wolopts || (netdev && netdev->wol_enabled); + /* If the device has WOL enabled, we cannot suspend the PHY */ + if (phydev->wol_enabled && !(phydrv->flags & PHY_ALWAYS_CALL_SUSPEND)) return -EBUSY; if (!phydrv || !phydrv->suspend) diff --git a/include/linux/phy.h b/include/linux/phy.h index c5a0dc829714..e0df8b3c2bdb 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -86,6 +86,7 @@ extern const int phy_10gbit_features_array[1]; #define PHY_IS_INTERNAL 0x00000001 #define PHY_RST_AFTER_CLK_EN 0x00000002 #define PHY_POLL_CABLE_TEST 0x00000004 +#define PHY_ALWAYS_CALL_SUSPEND 0x00000008 #define MDIO_DEVICE_IS_PHY 0x80000000 /** @@ -548,6 +549,8 @@ struct macsec_ops; * @downshifted_rate: Set true if link speed has been downshifted. * @is_on_sfp_module: Set true if PHY is located on an SFP module. * @mac_managed_pm: Set true if MAC driver takes of suspending/resuming PHY + * @wol_enabled: Set to true if the PHY or the attached MAC have Wake-on-LAN + * enabled. * @state: State of the PHY for management purposes * @dev_flags: Device-specific flags used by the PHY driver. * @@ -644,6 +647,7 @@ struct phy_device { unsigned downshifted_rate:1; unsigned is_on_sfp_module:1; unsigned mac_managed_pm:1; + unsigned wol_enabled:1; unsigned autoneg:1; /* The most recently read link state */ -- cgit v1.2.3 From 8baddaa9d4bac939004b5058f3ade7e2bf0a6e43 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 11 May 2023 10:21:09 -0700 Subject: net: phy: broadcom: Add support for Wake-on-LAN Add support for WAKE_UCAST, WAKE_MCAST, WAKE_BCAST, WAKE_MAGIC and WAKE_MAGICSECURE. This is only supported with the BCM54210E and compatible Ethernet PHYs. Using the in-band interrupt or an out of band GPIO interrupts are supported. Broadcom PHYs will generate a Wake-on-LAN level low interrupt on LED4 as soon as one of the supported patterns is being matched. That includes generating such an interrupt even if the PHY is operated during normal modes. If WAKE_UCAST is selected, this could lead to the LED4 interrupt firing up for every packet being received which is absolutely undesirable from a performance point of view. Because the Wake-on-LAN configuration can be set long before the system is actually put to sleep, we cannot have an interrupt service routine to clear on read the interrupt status register and ensure that new packet matches will be detected. It is desirable to enable the Wake-on-LAN interrupt as late as possible during the system suspend process such that we limit the number of interrupts to be handled by the system, but also conversely feed into the Linux's system suspend way of dealing with interrupts in and around the points of no return. Reviewed-by: Simon Horman Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/bcm-phy-lib.c | 212 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/bcm-phy-lib.h | 5 + drivers/net/phy/broadcom.c | 126 ++++++++++++++++++++++++- include/linux/brcmphy.h | 55 +++++++++++ 4 files changed, 395 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index b2c0baa51f39..27c57f6ab211 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -6,12 +6,14 @@ #include "bcm-phy-lib.h" #include #include +#include #include #include #include #include #include #include +#include #define MII_BCM_CHANNEL_WIDTH 0x2000 #define BCM_CL45VEN_EEE_ADV 0x3c @@ -816,6 +818,216 @@ int bcm_phy_cable_test_get_status_rdb(struct phy_device *phydev, } EXPORT_SYMBOL_GPL(bcm_phy_cable_test_get_status_rdb); +#define BCM54XX_WOL_SUPPORTED_MASK (WAKE_UCAST | \ + WAKE_MCAST | \ + WAKE_BCAST | \ + WAKE_MAGIC | \ + WAKE_MAGICSECURE) + +int bcm_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +{ + struct net_device *ndev = phydev->attached_dev; + u8 da[ETH_ALEN], mask[ETH_ALEN]; + unsigned int i; + u16 ctl; + int ret; + + /* Allow a MAC driver to play through its own Wake-on-LAN + * implementation + */ + if (wol->wolopts & ~BCM54XX_WOL_SUPPORTED_MASK) + return -EOPNOTSUPP; + + /* The PHY supports passwords of 4, 6 and 8 bytes in size, but Linux's + * ethtool only supports 6, for now. + */ + BUILD_BUG_ON(sizeof(wol->sopass) != ETH_ALEN); + + /* Clear previous interrupts */ + ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); + if (ret < 0) + return ret; + + ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_MAIN_CTL); + if (ret < 0) + return ret; + + ctl = ret; + + if (!wol->wolopts) { + if (phy_interrupt_is_valid(phydev)) + disable_irq_wake(phydev->irq); + + /* Leave all interrupts disabled */ + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_INT_MASK, + BCM54XX_WOL_ALL_INTRS); + if (ret < 0) + return ret; + + /* Disable the global Wake-on-LAN enable bit */ + ctl &= ~BCM54XX_WOL_EN; + + return bcm_phy_write_exp(phydev, BCM54XX_WOL_MAIN_CTL, ctl); + } + + /* Clear the previously configured mode and mask mode for Wake-on-LAN */ + ctl &= ~(BCM54XX_WOL_MODE_MASK << BCM54XX_WOL_MODE_SHIFT); + ctl &= ~(BCM54XX_WOL_MASK_MODE_MASK << BCM54XX_WOL_MASK_MODE_SHIFT); + ctl &= ~BCM54XX_WOL_DIR_PKT_EN; + ctl &= ~(BCM54XX_WOL_SECKEY_OPT_MASK << BCM54XX_WOL_SECKEY_OPT_SHIFT); + + /* When using WAKE_MAGIC, we program the magic pattern filter to match + * the device's MAC address and we accept any MAC DA in the Ethernet + * frame. + * + * When using WAKE_UCAST, WAKE_BCAST or WAKE_MCAST, we program the + * following: + * - WAKE_UCAST -> MAC DA is the device's MAC with a perfect match + * - WAKE_MCAST -> MAC DA is X1:XX:XX:XX:XX:XX where XX is don't care + * - WAKE_BCAST -> MAC DA is FF:FF:FF:FF:FF:FF with a perfect match + * + * Note that the Broadcast MAC DA is inherently going to match the + * multicast pattern being matched. + */ + memset(mask, 0, sizeof(mask)); + + if (wol->wolopts & WAKE_MCAST) { + memset(da, 0, sizeof(da)); + memset(mask, 0xff, sizeof(mask)); + da[0] = 0x01; + mask[0] = ~da[0]; + } else { + if (wol->wolopts & WAKE_UCAST) { + ether_addr_copy(da, ndev->dev_addr); + } else if (wol->wolopts & WAKE_BCAST) { + eth_broadcast_addr(da); + } else if (wol->wolopts & WAKE_MAGICSECURE) { + ether_addr_copy(da, wol->sopass); + } else if (wol->wolopts & WAKE_MAGIC) { + memset(da, 0, sizeof(da)); + memset(mask, 0xff, sizeof(mask)); + } + } + + for (i = 0; i < ETH_ALEN / 2; i++) { + if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) { + ret = bcm_phy_write_exp(phydev, + BCM54XX_WOL_MPD_DATA1(2 - i), + ndev->dev_addr[i * 2] << 8 | + ndev->dev_addr[i * 2 + 1]); + if (ret < 0) + return ret; + } + + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MPD_DATA2(2 - i), + da[i * 2] << 8 | da[i * 2 + 1]); + if (ret < 0) + return ret; + + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MASK(2 - i), + mask[i * 2] << 8 | mask[i * 2 + 1]); + if (ret) + return ret; + } + + if (wol->wolopts & WAKE_MAGICSECURE) { + ctl |= BCM54XX_WOL_SECKEY_OPT_6B << + BCM54XX_WOL_SECKEY_OPT_SHIFT; + ctl |= BCM54XX_WOL_MODE_SINGLE_MPDSEC << BCM54XX_WOL_MODE_SHIFT; + ctl |= BCM54XX_WOL_MASK_MODE_DA_FF << + BCM54XX_WOL_MASK_MODE_SHIFT; + } else { + if (wol->wolopts & WAKE_MAGIC) + ctl |= BCM54XX_WOL_MODE_SINGLE_MPD; + else + ctl |= BCM54XX_WOL_DIR_PKT_EN; + ctl |= BCM54XX_WOL_MASK_MODE_DA_ONLY << + BCM54XX_WOL_MASK_MODE_SHIFT; + } + + /* Globally enable Wake-on-LAN */ + ctl |= BCM54XX_WOL_EN | BCM54XX_WOL_CRC_CHK; + + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MAIN_CTL, ctl); + if (ret < 0) + return ret; + + /* Enable WOL interrupt on LED4 */ + ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_LED_CTL); + if (ret < 0) + return ret; + + ret |= BCM54XX_LED4_SEL_INTR; + ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_LED_CTL, ret); + if (ret < 0) + return ret; + + /* Enable all Wake-on-LAN interrupt sources */ + ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_INT_MASK, 0); + if (ret < 0) + return ret; + + if (phy_interrupt_is_valid(phydev)) + enable_irq_wake(phydev->irq); + + return 0; +} +EXPORT_SYMBOL_GPL(bcm_phy_set_wol); + +void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +{ + struct net_device *ndev = phydev->attached_dev; + u8 da[ETH_ALEN]; + unsigned int i; + int ret; + u16 ctl; + + wol->supported = BCM54XX_WOL_SUPPORTED_MASK; + wol->wolopts = 0; + + ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_MAIN_CTL); + if (ret < 0) + return; + + ctl = ret; + + if (!(ctl & BCM54XX_WOL_EN)) + return; + + for (i = 0; i < sizeof(da) / 2; i++) { + ret = bcm_phy_read_exp(phydev, + BCM54XX_WOL_MPD_DATA2(2 - i)); + if (ret < 0) + return; + + da[i * 2] = ret >> 8; + da[i * 2 + 1] = ret & 0xff; + } + + if (ctl & BCM54XX_WOL_DIR_PKT_EN) { + if (is_broadcast_ether_addr(da)) + wol->wolopts |= WAKE_BCAST; + else if (is_multicast_ether_addr(da)) + wol->wolopts |= WAKE_MCAST; + else if (ether_addr_equal(da, ndev->dev_addr)) + wol->wolopts |= WAKE_UCAST; + } else { + ctl = (ctl >> BCM54XX_WOL_MODE_SHIFT) & BCM54XX_WOL_MODE_MASK; + switch (ctl) { + case BCM54XX_WOL_MODE_SINGLE_MPD: + wol->wolopts |= WAKE_MAGIC; + break; + case BCM54XX_WOL_MODE_SINGLE_MPDSEC: + wol->wolopts |= WAKE_MAGICSECURE; + memcpy(wol->sopass, da, sizeof(da)); + break; + default: + break; + } + } +} +EXPORT_SYMBOL_GPL(bcm_phy_get_wol); + MODULE_DESCRIPTION("Broadcom PHY Library"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Broadcom Corporation"); diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 729db441797a..c6fed43ec913 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -9,6 +9,8 @@ #include #include +struct ethtool_wolinfo; + /* 28nm only register definitions */ #define MISC_ADDR(base, channel) base, channel @@ -111,4 +113,7 @@ static inline void bcm_ptp_stop(struct bcm_ptp_private *priv) } #endif +int bcm_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); +void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); + #endif /* _LINUX_BCM_PHY_LIB_H */ diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index ad71c88c87e7..418e6bc0e998 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -14,8 +14,12 @@ #include #include #include +#include #include #include +#include +#include +#include #define BRCM_PHY_MODEL(phydev) \ ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask) @@ -30,8 +34,17 @@ MODULE_LICENSE("GPL"); struct bcm54xx_phy_priv { u64 *stats; struct bcm_ptp_private *ptp; + int wake_irq; + bool wake_irq_enabled; }; +static bool bcm54xx_phy_can_wakeup(struct phy_device *phydev) +{ + struct bcm54xx_phy_priv *priv = phydev->priv; + + return phy_interrupt_is_valid(phydev) || priv->wake_irq >= 0; +} + static int bcm54xx_config_clock_delay(struct phy_device *phydev) { int rc, val; @@ -413,6 +426,16 @@ static int bcm54xx_config_init(struct phy_device *phydev) bcm54xx_ptp_config_init(phydev); + /* Acknowledge any left over interrupt and charge the device for + * wake-up. + */ + err = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); + if (err < 0) + return err; + + if (err) + pm_wakeup_event(&phydev->mdio.dev, 0); + return 0; } @@ -437,12 +460,39 @@ out: return ret; } +static int bcm54xx_set_wakeup_irq(struct phy_device *phydev, bool state) +{ + struct bcm54xx_phy_priv *priv = phydev->priv; + int ret = 0; + + if (!bcm54xx_phy_can_wakeup(phydev)) + return ret; + + if (priv->wake_irq_enabled != state) { + if (state) + ret = enable_irq_wake(priv->wake_irq); + else + ret = disable_irq_wake(priv->wake_irq); + priv->wake_irq_enabled = state; + } + + return ret; +} + static int bcm54xx_suspend(struct phy_device *phydev) { - int ret; + int ret = 0; bcm54xx_ptp_stop(phydev); + /* Acknowledge any Wake-on-LAN interrupt prior to suspend */ + ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); + if (ret < 0) + return ret; + + if (phydev->wol_enabled) + return bcm54xx_set_wakeup_irq(phydev, true); + /* We cannot use a read/modify/write here otherwise the PHY gets into * a bad state where its LEDs keep flashing, thus defeating the purpose * of low power mode. @@ -456,7 +506,13 @@ static int bcm54xx_suspend(struct phy_device *phydev) static int bcm54xx_resume(struct phy_device *phydev) { - int ret; + int ret = 0; + + if (phydev->wol_enabled) { + ret = bcm54xx_set_wakeup_irq(phydev, false); + if (ret) + return ret; + } ret = bcm54xx_iddq_set(phydev, false); if (ret < 0) @@ -801,14 +857,54 @@ static int brcm_fet_suspend(struct phy_device *phydev) return err; } +static void bcm54xx_phy_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + /* We cannot wake-up if we do not have a dedicated PHY interrupt line + * or an out of band GPIO descriptor for wake-up. Zeroing + * wol->supported allows the caller (MAC driver) to play through and + * offer its own Wake-on-LAN scheme if available. + */ + if (!bcm54xx_phy_can_wakeup(phydev)) { + wol->supported = 0; + return; + } + + bcm_phy_get_wol(phydev, wol); +} + +static int bcm54xx_phy_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int ret; + + /* We cannot wake-up if we do not have a dedicated PHY interrupt line + * or an out of band GPIO descriptor for wake-up. Returning -EOPNOTSUPP + * allows the caller (MAC driver) to play through and offer its own + * Wake-on-LAN scheme if available. + */ + if (!bcm54xx_phy_can_wakeup(phydev)) + return -EOPNOTSUPP; + + ret = bcm_phy_set_wol(phydev, wol); + if (ret < 0) + return ret; + + return 0; +} + static int bcm54xx_phy_probe(struct phy_device *phydev) { struct bcm54xx_phy_priv *priv; + struct gpio_desc *wakeup_gpio; + int ret = 0; priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->wake_irq = -ENXIO; + phydev->priv = priv; priv->stats = devm_kcalloc(&phydev->mdio.dev, @@ -821,7 +917,28 @@ static int bcm54xx_phy_probe(struct phy_device *phydev) if (IS_ERR(priv->ptp)) return PTR_ERR(priv->ptp); - return 0; + /* We cannot utilize the _optional variant here since we want to know + * whether the GPIO descriptor exists or not to advertise Wake-on-LAN + * support or not. + */ + wakeup_gpio = devm_gpiod_get(&phydev->mdio.dev, "wakeup", GPIOD_IN); + if (PTR_ERR(wakeup_gpio) == -EPROBE_DEFER) + return PTR_ERR(wakeup_gpio); + + if (!IS_ERR(wakeup_gpio)) { + priv->wake_irq = gpiod_to_irq(wakeup_gpio); + ret = irq_set_irq_type(priv->wake_irq, IRQ_TYPE_LEVEL_LOW); + if (ret) + return ret; + } + + /* If we do not have a main interrupt or a side-band wake-up interrupt, + * then the device cannot be marked as wake-up capable. + */ + if (!bcm54xx_phy_can_wakeup(phydev)) + return 0; + + return device_init_wakeup(&phydev->mdio.dev, true); } static void bcm54xx_get_stats(struct phy_device *phydev, @@ -894,6 +1011,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM54210E", /* PHY_GBIT_FEATURES */ + .flags = PHY_ALWAYS_CALL_SUSPEND, .get_sset_count = bcm_phy_get_sset_count, .get_strings = bcm_phy_get_strings, .get_stats = bcm54xx_get_stats, @@ -904,6 +1022,8 @@ static struct phy_driver broadcom_drivers[] = { .link_change_notify = bcm54xx_link_change_notify, .suspend = bcm54xx_suspend, .resume = bcm54xx_resume, + .get_wol = bcm54xx_phy_get_wol, + .set_wol = bcm54xx_phy_set_wol, }, { .phy_id = PHY_ID_BCM5461, .phy_id_mask = 0xfffffff0, diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index 9e77165f3ef6..e9afbfb6d7a5 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -89,6 +89,7 @@ #define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ #define MII_BCM54XX_EXP_SEL_TOP 0x0d00 /* TOP_MISC expansion register select */ #define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ +#define MII_BCM54XX_EXP_SEL_WOL 0x0e00 /* Wake-on-LAN expansion select register */ #define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ #define MII_BCM54XX_EXP_SEL_ETC 0x0d00 /* Expansion register spare + 2k mem */ @@ -253,6 +254,9 @@ #define BCM54XX_TOP_MISC_IDDQ_SD (1 << 2) #define BCM54XX_TOP_MISC_IDDQ_SR (1 << 3) +#define BCM54XX_TOP_MISC_LED_CTL (MII_BCM54XX_EXP_SEL_TOP + 0x0C) +#define BCM54XX_LED4_SEL_INTR BIT(1) + /* * BCM5482: Secondary SerDes registers */ @@ -272,6 +276,57 @@ #define BCM54612E_EXP_SPARE0 (MII_BCM54XX_EXP_SEL_ETC + 0x34) #define BCM54612E_LED4_CLK125OUT_EN (1 << 1) + +/* Wake-on-LAN registers */ +#define BCM54XX_WOL_MAIN_CTL (MII_BCM54XX_EXP_SEL_WOL + 0x80) +#define BCM54XX_WOL_EN BIT(0) +#define BCM54XX_WOL_MODE_SINGLE_MPD 0 +#define BCM54XX_WOL_MODE_SINGLE_MPDSEC 1 +#define BCM54XX_WOL_MODE_DUAL 2 +#define BCM54XX_WOL_MODE_SHIFT 1 +#define BCM54XX_WOL_MODE_MASK 0x3 +#define BCM54XX_WOL_MP_MSB_FF_EN BIT(3) +#define BCM54XX_WOL_SECKEY_OPT_4B 0 +#define BCM54XX_WOL_SECKEY_OPT_6B 1 +#define BCM54XX_WOL_SECKEY_OPT_8B 2 +#define BCM54XX_WOL_SECKEY_OPT_SHIFT 4 +#define BCM54XX_WOL_SECKEY_OPT_MASK 0x3 +#define BCM54XX_WOL_L2_TYPE_CHK BIT(6) +#define BCM54XX_WOL_L4IPV4UDP_CHK BIT(7) +#define BCM54XX_WOL_L4IPV6UDP_CHK BIT(8) +#define BCM54XX_WOL_UDPPORT_CHK BIT(9) +#define BCM54XX_WOL_CRC_CHK BIT(10) +#define BCM54XX_WOL_SECKEY_MODE BIT(11) +#define BCM54XX_WOL_RST BIT(12) +#define BCM54XX_WOL_DIR_PKT_EN BIT(13) +#define BCM54XX_WOL_MASK_MODE_DA_FF 0 +#define BCM54XX_WOL_MASK_MODE_DA_MPD 1 +#define BCM54XX_WOL_MASK_MODE_DA_ONLY 2 +#define BCM54XX_WOL_MASK_MODE_MPD 3 +#define BCM54XX_WOL_MASK_MODE_SHIFT 14 +#define BCM54XX_WOL_MASK_MODE_MASK 0x3 + +#define BCM54XX_WOL_INNER_PROTO (MII_BCM54XX_EXP_SEL_WOL + 0x81) +#define BCM54XX_WOL_OUTER_PROTO (MII_BCM54XX_EXP_SEL_WOL + 0x82) +#define BCM54XX_WOL_OUTER_PROTO2 (MII_BCM54XX_EXP_SEL_WOL + 0x83) + +#define BCM54XX_WOL_MPD_DATA1(x) (MII_BCM54XX_EXP_SEL_WOL + 0x84 + (x)) +#define BCM54XX_WOL_MPD_DATA2(x) (MII_BCM54XX_EXP_SEL_WOL + 0x87 + (x)) +#define BCM54XX_WOL_SEC_KEY_8B (MII_BCM54XX_EXP_SEL_WOL + 0x8A) +#define BCM54XX_WOL_MASK(x) (MII_BCM54XX_EXP_SEL_WOL + 0x8B + (x)) +#define BCM54XX_SEC_KEY_STORE(x) (MII_BCM54XX_EXP_SEL_WOL + 0x8E) +#define BCM54XX_WOL_SHARED_CNT (MII_BCM54XX_EXP_SEL_WOL + 0x92) + +#define BCM54XX_WOL_INT_MASK (MII_BCM54XX_EXP_SEL_WOL + 0x93) +#define BCM54XX_WOL_PKT1 BIT(0) +#define BCM54XX_WOL_PKT2 BIT(1) +#define BCM54XX_WOL_DIR BIT(2) +#define BCM54XX_WOL_ALL_INTRS (BCM54XX_WOL_PKT1 | \ + BCM54XX_WOL_PKT2 | \ + BCM54XX_WOL_DIR) + +#define BCM54XX_WOL_INT_STATUS (MII_BCM54XX_EXP_SEL_WOL + 0x94) + /*****************************************************************************/ /* Fast Ethernet Transceiver definitions. */ /*****************************************************************************/ -- cgit v1.2.3 From 7e400ff35cbe3b25fc1da1586b6cd9bc426dfb1c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 11 May 2023 10:21:10 -0700 Subject: net: bcmgenet: Add support for PHY-based Wake-on-LAN If available, interrogate the PHY to find out whether we can use it for Wake-on-LAN. This can be a more power efficient way of implementing that feature, especially when the MAC is powered off in low power states. Reviewed-by: Simon Horman Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c index 3a4b6cb7b7b9..7a41cad5788f 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c @@ -42,6 +42,12 @@ void bcmgenet_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct bcmgenet_priv *priv = netdev_priv(dev); struct device *kdev = &priv->pdev->dev; + if (dev->phydev) { + phy_ethtool_get_wol(dev->phydev, wol); + if (wol->supported) + return; + } + if (!device_can_wakeup(kdev)) { wol->supported = 0; wol->wolopts = 0; @@ -63,6 +69,14 @@ int bcmgenet_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct bcmgenet_priv *priv = netdev_priv(dev); struct device *kdev = &priv->pdev->dev; + int ret; + + /* Try Wake-on-LAN from the PHY first */ + if (dev->phydev) { + ret = phy_ethtool_set_wol(dev->phydev, wol); + if (ret != -EOPNOTSUPP) + return ret; + } if (!device_can_wakeup(kdev)) return -ENOTSUPP; -- cgit v1.2.3 From 69474a8a5837be63f13c6f60a7d622b98ed5c539 Mon Sep 17 00:00:00 2001 From: Vladimir Nikishkin Date: Fri, 12 May 2023 11:40:33 +0800 Subject: net: vxlan: Add nolocalbypass option to vxlan. If a packet needs to be encapsulated towards a local destination IP, the packet will undergo a "local bypass" and be injected into the Rx path as if it was received by the target VXLAN device without undergoing encapsulation. If such a device does not exist, the packet will be dropped. There are scenarios where we do not want to perform such a bypass, but instead want the packet to be encapsulated and locally received by a user space program for post-processing. To that end, add a new VXLAN device attribute that controls whether a "local bypass" is performed or not. Default to performing a bypass to maintain existing behavior. Signed-off-by: Vladimir Nikishkin Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/vxlan/vxlan_core.c | 21 +++++++++++++++++++-- include/net/vxlan.h | 4 +++- include/uapi/linux/if_link.h | 1 + 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 561fe1b314f5..78744549c1b3 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2352,7 +2352,8 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev, #endif /* Bypass encapsulation if the destination is local */ if (rt_flags & RTCF_LOCAL && - !(rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) { + !(rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) && + vxlan->cfg.flags & VXLAN_F_LOCALBYPASS) { struct vxlan_dev *dst_vxlan; dst_release(dst); @@ -3172,6 +3173,7 @@ static void vxlan_raw_setup(struct net_device *dev) } static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { + [IFLA_VXLAN_UNSPEC] = { .strict_start_type = IFLA_VXLAN_LOCALBYPASS }, [IFLA_VXLAN_ID] = { .type = NLA_U32 }, [IFLA_VXLAN_GROUP] = { .len = sizeof_field(struct iphdr, daddr) }, [IFLA_VXLAN_GROUP6] = { .len = sizeof(struct in6_addr) }, @@ -3202,6 +3204,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_TTL_INHERIT] = { .type = NLA_FLAG }, [IFLA_VXLAN_DF] = { .type = NLA_U8 }, [IFLA_VXLAN_VNIFILTER] = { .type = NLA_U8 }, + [IFLA_VXLAN_LOCALBYPASS] = NLA_POLICY_MAX(NLA_U8, 1), }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[], @@ -4011,6 +4014,17 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[], conf->flags |= VXLAN_F_UDP_ZERO_CSUM_TX; } + if (data[IFLA_VXLAN_LOCALBYPASS]) { + err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LOCALBYPASS, + VXLAN_F_LOCALBYPASS, changelink, + true, extack); + if (err) + return err; + } else if (!changelink) { + /* default to local bypass on a new device */ + conf->flags |= VXLAN_F_LOCALBYPASS; + } + if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]) { err = vxlan_nl2flag(conf, data, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, VXLAN_F_UDP_ZERO_CSUM6_TX, changelink, @@ -4232,6 +4246,7 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LOCALBYPASS */ 0; } @@ -4308,7 +4323,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX, !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_TX)) || nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX, - !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX))) + !!(vxlan->cfg.flags & VXLAN_F_REMCSUM_RX)) || + nla_put_u8(skb, IFLA_VXLAN_LOCALBYPASS, + !!(vxlan->cfg.flags & VXLAN_F_LOCALBYPASS))) goto nla_put_failure; if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports)) diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 20bd7d893e10..0be91ca78d3a 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -328,6 +328,7 @@ struct vxlan_dev { #define VXLAN_F_TTL_INHERIT 0x10000 #define VXLAN_F_VNIFILTER 0x20000 #define VXLAN_F_MDB 0x40000 +#define VXLAN_F_LOCALBYPASS 0x80000 /* Flags that are used in the receive path. These flags must match in * order for a socket to be shareable @@ -348,7 +349,8 @@ struct vxlan_dev { VXLAN_F_UDP_ZERO_CSUM6_TX | \ VXLAN_F_UDP_ZERO_CSUM6_RX | \ VXLAN_F_COLLECT_METADATA | \ - VXLAN_F_VNIFILTER) + VXLAN_F_VNIFILTER | \ + VXLAN_F_LOCALBYPASS) struct net_device *vxlan_dev_create(struct net *net, const char *name, u8 name_assign_type, struct vxlan_config *conf); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 4ac1000b0ef2..0f6a0fe09bdb 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -828,6 +828,7 @@ enum { IFLA_VXLAN_TTL_INHERIT, IFLA_VXLAN_DF, IFLA_VXLAN_VNIFILTER, /* only applicable with COLLECT_METADATA mode */ + IFLA_VXLAN_LOCALBYPASS, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) -- cgit v1.2.3 From 305c041899971ff210ad5f9c50249d179c95ada4 Mon Sep 17 00:00:00 2001 From: Vladimir Nikishkin Date: Fri, 12 May 2023 11:40:34 +0800 Subject: selftests: net: vxlan: Add tests for vxlan nolocalbypass option. Add test to make sure that the localbypass option is on by default. Add test to change vxlan localbypass to nolocalbypass and check that packets are delivered to userspace. Signed-off-by: Vladimir Nikishkin Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/Makefile | 1 + .../selftests/net/test_vxlan_nolocalbypass.sh | 240 +++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100755 tools/testing/selftests/net/test_vxlan_nolocalbypass.sh diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index c12df57d5539..7f3ab2a93ed6 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -84,6 +84,7 @@ TEST_GEN_FILES += ip_local_port_range TEST_GEN_FILES += bind_wildcard TEST_PROGS += test_vxlan_mdb.sh TEST_PROGS += test_bridge_neigh_suppress.sh +TEST_PROGS += test_vxlan_nolocalbypass.sh TEST_FILES := settings diff --git a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh new file mode 100755 index 000000000000..46067db53068 --- /dev/null +++ b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# This test is for checking the [no]localbypass VXLAN device option. The test +# configures two VXLAN devices in the same network namespace and a tc filter on +# the loopback device that drops encapsulated packets. The test sends packets +# from the first VXLAN device and verifies that by default these packets are +# received by the second VXLAN device. The test then enables the nolocalbypass +# option and verifies that packets are no longer received by the second VXLAN +# device. + +ret=0 +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +TESTS=" + nolocalbypass +" +VERBOSE=0 +PAUSE_ON_FAIL=no +PAUSE=no + +################################################################################ +# Utilities + +log_test() +{ + local rc=$1 + local expected=$2 + local msg="$3" + + if [ ${rc} -eq ${expected} ]; then + printf "TEST: %-60s [ OK ]\n" "${msg}" + nsuccess=$((nsuccess+1)) + else + ret=1 + nfail=$((nfail+1)) + printf "TEST: %-60s [FAIL]\n" "${msg}" + if [ "$VERBOSE" = "1" ]; then + echo " rc=$rc, expected $expected" + fi + + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + fi + + if [ "${PAUSE}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + + [ "$VERBOSE" = "1" ] && echo +} + +run_cmd() +{ + local cmd="$1" + local out + local stderr="2>/dev/null" + + if [ "$VERBOSE" = "1" ]; then + printf "COMMAND: $cmd\n" + stderr= + fi + + out=$(eval $cmd $stderr) + rc=$? + if [ "$VERBOSE" = "1" -a -n "$out" ]; then + echo " $out" + fi + + return $rc +} + +tc_check_packets() +{ + local ns=$1; shift + local id=$1; shift + local handle=$1; shift + local count=$1; shift + local pkts + + sleep 0.1 + pkts=$(tc -n $ns -j -s filter show $id \ + | jq ".[] | select(.options.handle == $handle) | \ + .options.actions[0].stats.packets") + [[ $pkts == $count ]] +} + +################################################################################ +# Setup + +setup() +{ + ip netns add ns1 + + ip -n ns1 link set dev lo up + ip -n ns1 address add 192.0.2.1/32 dev lo + ip -n ns1 address add 198.51.100.1/32 dev lo + + ip -n ns1 link add name vx0 up type vxlan id 100 local 198.51.100.1 \ + dstport 4789 nolearning + ip -n ns1 link add name vx1 up type vxlan id 100 dstport 4790 +} + +cleanup() +{ + ip netns del ns1 &> /dev/null +} + +################################################################################ +# Tests + +nolocalbypass() +{ + local smac=00:01:02:03:04:05 + local dmac=00:0a:0b:0c:0d:0e + + run_cmd "bridge -n ns1 fdb add $dmac dev vx0 self static dst 192.0.2.1 port 4790" + + run_cmd "tc -n ns1 qdisc add dev vx1 clsact" + run_cmd "tc -n ns1 filter add dev vx1 ingress pref 1 handle 101 proto all flower src_mac $smac dst_mac $dmac action pass" + + run_cmd "tc -n ns1 qdisc add dev lo clsact" + run_cmd "tc -n ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop" + + run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'" + log_test $? 0 "localbypass enabled" + + run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + + tc_check_packets "ns1" "dev vx1 ingress" 101 1 + log_test $? 0 "Packet received by local VXLAN device - localbypass" + + run_cmd "ip -n ns1 link set dev vx0 type vxlan nolocalbypass" + + run_cmd "ip -n ns1 -d link show dev vx0 | grep 'nolocalbypass'" + log_test $? 0 "localbypass disabled" + + run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + + tc_check_packets "ns1" "dev vx1 ingress" 101 1 + log_test $? 0 "Packet not received by local VXLAN device - nolocalbypass" + + run_cmd "ip -n ns1 link set dev vx0 type vxlan localbypass" + + run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'" + log_test $? 0 "localbypass enabled" + + run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" + + tc_check_packets "ns1" "dev vx1 ingress" 101 2 + log_test $? 0 "Packet received by local VXLAN device - localbypass" +} + +################################################################################ +# Usage + +usage() +{ + cat < Test(s) to run (default: all) + (options: $TESTS) + -p Pause on fail + -P Pause after each test before cleanup + -v Verbose mode (show commands and output) +EOF +} + +################################################################################ +# Main + +trap cleanup EXIT + +while getopts ":t:pPvh" opt; do + case $opt in + t) TESTS=$OPTARG ;; + p) PAUSE_ON_FAIL=yes;; + P) PAUSE=yes;; + v) VERBOSE=$(($VERBOSE + 1));; + h) usage; exit 0;; + *) usage; exit 1;; + esac +done + +# Make sure we don't pause twice. +[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no + +if [ "$(id -u)" -ne 0 ];then + echo "SKIP: Need root privileges" + exit $ksft_skip; +fi + +if [ ! -x "$(command -v ip)" ]; then + echo "SKIP: Could not run test without ip tool" + exit $ksft_skip +fi + +if [ ! -x "$(command -v bridge)" ]; then + echo "SKIP: Could not run test without bridge tool" + exit $ksft_skip +fi + +if [ ! -x "$(command -v mausezahn)" ]; then + echo "SKIP: Could not run test without mausezahn tool" + exit $ksft_skip +fi + +if [ ! -x "$(command -v jq)" ]; then + echo "SKIP: Could not run test without jq tool" + exit $ksft_skip +fi + +ip link help vxlan 2>&1 | grep -q "localbypass" +if [ $? -ne 0 ]; then + echo "SKIP: iproute2 ip too old, missing VXLAN nolocalbypass support" + exit $ksft_skip +fi + +cleanup + +for t in $TESTS +do + setup; $t; cleanup; +done + +if [ "$TESTS" != "none" ]; then + printf "\nTests passed: %3d\n" ${nsuccess} + printf "Tests failed: %3d\n" ${nfail} +fi + +exit $ret -- cgit v1.2.3 From b51f4113ebb02011f0ca86abc3134b28d2071b6a Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 11 May 2023 09:12:12 +0800 Subject: net: introduce and use skb_frag_fill_page_desc() Most users use __skb_frag_set_page()/skb_frag_off_set()/ skb_frag_size_set() to fill the page desc for a skb frag. Introduce skb_frag_fill_page_desc() to do that. net/bpf/test_run.c does not call skb_frag_off_set() to set the offset, "copy_from_user(page_address(page), ...)" and 'shinfo' being part of the 'data' kzalloced in bpf_test_init() suggest that it is assuming offset to be initialized as zero, so call skb_frag_fill_page_desc() with offset being zero for this case. Also, skb_frag_set_page() is not used anymore, so remove it. Signed-off-by: Yunsheng Lin Reviewed-by: Leon Romanovsky Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 6 ++--- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 ++-- drivers/net/ethernet/chelsio/cxgb3/sge.c | 5 ++-- drivers/net/ethernet/emulex/benet/be_main.c | 32 +++++++++++++----------- drivers/net/ethernet/freescale/enetc/enetc.c | 5 ++-- drivers/net/ethernet/fungible/funeth/funeth_rx.c | 5 ++-- drivers/net/ethernet/marvell/mvneta.c | 5 ++-- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 4 +-- drivers/net/ethernet/sun/cassini.c | 8 ++---- drivers/net/virtio_net.c | 4 +-- drivers/net/vmxnet3/vmxnet3_drv.c | 4 +-- drivers/net/xen-netback/netback.c | 4 +-- include/linux/skbuff.h | 27 ++++++++------------ net/bpf/test_run.c | 3 +-- net/core/gro.c | 4 +-- net/core/pktgen.c | 13 ++++++---- net/core/skbuff.c | 7 +++--- net/tls/tls_device.c | 10 +++----- net/xfrm/xfrm_ipcomp.c | 5 +--- 19 files changed, 64 insertions(+), 92 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 7f933175cbda..4de22eed099a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -532,10 +532,10 @@ static bool aq_add_rx_fragment(struct device *dev, buff_->rxdata.pg_off, buff_->len, DMA_FROM_DEVICE); - skb_frag_off_set(frag, buff_->rxdata.pg_off); - skb_frag_size_set(frag, buff_->len); sinfo->xdp_frags_size += buff_->len; - __skb_frag_set_page(frag, buff_->rxdata.page); + skb_frag_fill_page_desc(frag, buff_->rxdata.page, + buff_->rxdata.pg_off, + buff_->len); buff_->is_cleaned = 1; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index dcd9367f05af..efaff5018af8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1085,9 +1085,8 @@ static u32 __bnxt_rx_agg_pages(struct bnxt *bp, RX_AGG_CMP_LEN) >> RX_AGG_CMP_LEN_SHIFT; cons_rx_buf = &rxr->rx_agg_ring[cons]; - skb_frag_off_set(frag, cons_rx_buf->offset); - skb_frag_size_set(frag, frag_len); - __skb_frag_set_page(frag, cons_rx_buf->page); + skb_frag_fill_page_desc(frag, cons_rx_buf->page, + cons_rx_buf->offset, frag_len); shinfo->nr_frags = i + 1; __clear_bit(cons, rxr->rx_agg_bmap); diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index efa7f401529e..2e9a74fe0970 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -2184,9 +2184,8 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs, len -= offset; rx_frag += nr_frags; - __skb_frag_set_page(rx_frag, sd->pg_chunk.page); - skb_frag_off_set(rx_frag, sd->pg_chunk.offset + offset); - skb_frag_size_set(rx_frag, len); + skb_frag_fill_page_desc(rx_frag, sd->pg_chunk.page, + sd->pg_chunk.offset + offset, len); skb->len += len; skb->data_len += len; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 7e408bcc88de..3164ed205cf7 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2343,11 +2343,10 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb, hdr_len = ETH_HLEN; memcpy(skb->data, start, hdr_len); skb_shinfo(skb)->nr_frags = 1; - skb_frag_set_page(skb, 0, page_info->page); - skb_frag_off_set(&skb_shinfo(skb)->frags[0], - page_info->page_offset + hdr_len); - skb_frag_size_set(&skb_shinfo(skb)->frags[0], - curr_frag_len - hdr_len); + skb_frag_fill_page_desc(&skb_shinfo(skb)->frags[0], + page_info->page, + page_info->page_offset + hdr_len, + curr_frag_len - hdr_len); skb->data_len = curr_frag_len - hdr_len; skb->truesize += rx_frag_size; skb->tail += hdr_len; @@ -2369,16 +2368,17 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb, if (page_info->page_offset == 0) { /* Fresh page */ j++; - skb_frag_set_page(skb, j, page_info->page); - skb_frag_off_set(&skb_shinfo(skb)->frags[j], - page_info->page_offset); - skb_frag_size_set(&skb_shinfo(skb)->frags[j], 0); + skb_frag_fill_page_desc(&skb_shinfo(skb)->frags[j], + page_info->page, + page_info->page_offset, + curr_frag_len); skb_shinfo(skb)->nr_frags++; } else { put_page(page_info->page); + skb_frag_size_add(&skb_shinfo(skb)->frags[j], + curr_frag_len); } - skb_frag_size_add(&skb_shinfo(skb)->frags[j], curr_frag_len); skb->len += curr_frag_len; skb->data_len += curr_frag_len; skb->truesize += rx_frag_size; @@ -2451,14 +2451,16 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo, if (i == 0 || page_info->page_offset == 0) { /* First frag or Fresh page */ j++; - skb_frag_set_page(skb, j, page_info->page); - skb_frag_off_set(&skb_shinfo(skb)->frags[j], - page_info->page_offset); - skb_frag_size_set(&skb_shinfo(skb)->frags[j], 0); + skb_frag_fill_page_desc(&skb_shinfo(skb)->frags[j], + page_info->page, + page_info->page_offset, + curr_frag_len); } else { put_page(page_info->page); + skb_frag_size_add(&skb_shinfo(skb)->frags[j], + curr_frag_len); } - skb_frag_size_add(&skb_shinfo(skb)->frags[j], curr_frag_len); + skb->truesize += rx_frag_size; remaining -= curr_frag_len; memset(page_info, 0, sizeof(*page_info)); diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 3c4fa26f0f9b..63854294ac33 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1445,9 +1445,8 @@ static void enetc_add_rx_buff_to_xdp(struct enetc_bdr *rx_ring, int i, xdp_buff_set_frag_pfmemalloc(xdp_buff); frag = &shinfo->frags[shinfo->nr_frags]; - skb_frag_off_set(frag, rx_swbd->page_offset); - skb_frag_size_set(frag, size); - __skb_frag_set_page(frag, rx_swbd->page); + skb_frag_fill_page_desc(frag, rx_swbd->page, rx_swbd->page_offset, + size); shinfo->nr_frags++; } diff --git a/drivers/net/ethernet/fungible/funeth/funeth_rx.c b/drivers/net/ethernet/fungible/funeth/funeth_rx.c index 29a6c2ede43a..7e2584895de3 100644 --- a/drivers/net/ethernet/fungible/funeth/funeth_rx.c +++ b/drivers/net/ethernet/fungible/funeth/funeth_rx.c @@ -323,9 +323,8 @@ static int fun_gather_pkt(struct funeth_rxq *q, unsigned int tot_len, if (ref_ok) ref_ok |= buf->node; - __skb_frag_set_page(frags, buf->page); - skb_frag_off_set(frags, q->buf_offset); - skb_frag_size_set(frags++, frag_len); + skb_frag_fill_page_desc(frags++, buf->page, q->buf_offset, + frag_len); tot_len -= frag_len; if (!tot_len) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 6c6b66d3ea6e..e2abc00d0472 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2376,9 +2376,8 @@ mvneta_swbm_add_rx_fragment(struct mvneta_port *pp, if (data_len > 0 && sinfo->nr_frags < MAX_SKB_FRAGS) { skb_frag_t *frag = &sinfo->frags[sinfo->nr_frags++]; - skb_frag_off_set(frag, pp->rx_offset_correction); - skb_frag_size_set(frag, data_len); - __skb_frag_set_page(frag, page); + skb_frag_fill_page_desc(frag, page, + pp->rx_offset_correction, data_len); if (!xdp_buff_has_frags(xdp)) { sinfo->xdp_frags_size = *size; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 69634829558e..704b022cd1f0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -491,9 +491,7 @@ mlx5e_add_skb_shared_info_frag(struct mlx5e_rq *rq, struct skb_shared_info *sinf } frag = &sinfo->frags[sinfo->nr_frags++]; - __skb_frag_set_page(frag, frag_page->page); - skb_frag_off_set(frag, frag_offset); - skb_frag_size_set(frag, len); + skb_frag_fill_page_desc(frag, frag_page->page, frag_offset, len); if (page_is_pfmemalloc(frag_page->page)) xdp_buff_set_frag_pfmemalloc(xdp); diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index 4ef05bad4613..2d52f54ebb45 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -1998,10 +1998,8 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc, skb->truesize += hlen - swivel; skb->len += hlen - swivel; - __skb_frag_set_page(frag, page->buffer); + skb_frag_fill_page_desc(frag, page->buffer, off, hlen - swivel); __skb_frag_ref(frag); - skb_frag_off_set(frag, off); - skb_frag_size_set(frag, hlen - swivel); /* any more data? */ if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) { @@ -2024,10 +2022,8 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc, skb->len += hlen; frag++; - __skb_frag_set_page(frag, page->buffer); + skb_frag_fill_page_desc(frag, page->buffer, 0, hlen); __skb_frag_ref(frag); - skb_frag_off_set(frag, 0); - skb_frag_size_set(frag, hlen); RX_USED_ADD(page, hlen + cp->crc_size); } diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 97241006d64a..29eccc8ff41f 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1272,9 +1272,7 @@ static int virtnet_build_xdp_buff_mrg(struct net_device *dev, } frag = &shinfo->frags[shinfo->nr_frags++]; - __skb_frag_set_page(frag, page); - skb_frag_off_set(frag, offset); - skb_frag_size_set(frag, len); + skb_frag_fill_page_desc(frag, page, offset, len); if (page_is_pfmemalloc(page)) xdp_buff_set_frag_pfmemalloc(xdp); diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index f2b76ee866a4..7fa74b8b2100 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -686,9 +686,7 @@ vmxnet3_append_frag(struct sk_buff *skb, struct Vmxnet3_RxCompDesc *rcd, BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS); - __skb_frag_set_page(frag, rbi->page); - skb_frag_off_set(frag, 0); - skb_frag_size_set(frag, rcd->len); + skb_frag_fill_page_desc(frag, rbi->page, 0, rcd->len); skb->data_len += rcd->len; skb->truesize += PAGE_SIZE; skb_shinfo(skb)->nr_frags++; diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index c1501f41e2d8..3d79b35eb577 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1128,9 +1128,7 @@ static int xenvif_handle_frag_list(struct xenvif_queue *queue, struct sk_buff *s BUG(); offset += len; - __skb_frag_set_page(&frags[i], page); - skb_frag_off_set(&frags[i], 0); - skb_frag_size_set(&frags[i], len); + skb_frag_fill_page_desc(&frags[i], page, 0, len); } /* Release all the original (foreign) frags. */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 738776ab8838..30be21c7d05f 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2411,6 +2411,15 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb) return skb_headlen(skb) + __skb_pagelen(skb); } +static inline void skb_frag_fill_page_desc(skb_frag_t *frag, + struct page *page, + int off, int size) +{ + frag->bv_page = page; + frag->bv_offset = off; + skb_frag_size_set(frag, size); +} + static inline void __skb_fill_page_desc_noacc(struct skb_shared_info *shinfo, int i, struct page *page, int off, int size) @@ -2422,9 +2431,7 @@ static inline void __skb_fill_page_desc_noacc(struct skb_shared_info *shinfo, * that not all callers have unique ownership of the page but rely * on page_is_pfmemalloc doing the right thing(tm). */ - frag->bv_page = page; - frag->bv_offset = off; - skb_frag_size_set(frag, size); + skb_frag_fill_page_desc(frag, page, off, size); } /** @@ -3496,20 +3503,6 @@ static inline void __skb_frag_set_page(skb_frag_t *frag, struct page *page) frag->bv_page = page; } -/** - * skb_frag_set_page - sets the page contained in a paged fragment of an skb - * @skb: the buffer - * @f: the fragment offset - * @page: the page to set - * - * Sets the @f'th fragment of @skb to contain @page. - */ -static inline void skb_frag_set_page(struct sk_buff *skb, int f, - struct page *page) -{ - __skb_frag_set_page(&skb_shinfo(skb)->frags[f], page); -} - bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio); /** diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index e79e3a415ca9..98143b86a9dd 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -1415,11 +1415,10 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr, } frag = &sinfo->frags[sinfo->nr_frags++]; - __skb_frag_set_page(frag, page); data_len = min_t(u32, kattr->test.data_size_in - size, PAGE_SIZE); - skb_frag_size_set(frag, data_len); + skb_frag_fill_page_desc(frag, page, 0, data_len); if (copy_from_user(page_address(page), data_in + size, data_len)) { diff --git a/net/core/gro.c b/net/core/gro.c index 2d84165cb4f1..6783a47a6136 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -239,9 +239,7 @@ int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) pinfo->nr_frags = nr_frags + 1 + skbinfo->nr_frags; - __skb_frag_set_page(frag, page); - skb_frag_off_set(frag, first_offset); - skb_frag_size_set(frag, first_size); + skb_frag_fill_page_desc(frag, page, first_offset, first_size); memcpy(frag + 1, skbinfo->frags, sizeof(*frag) * skbinfo->nr_frags); /* We dont need to clear skbinfo->nr_frags here */ diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 760238196db1..f56b8d697014 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2785,14 +2785,17 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb, break; } get_page(pkt_dev->page); - skb_frag_set_page(skb, i, pkt_dev->page); - skb_frag_off_set(&skb_shinfo(skb)->frags[i], 0); + /*last fragment, fill rest of data*/ if (i == (frags - 1)) - skb_frag_size_set(&skb_shinfo(skb)->frags[i], - (datalen < PAGE_SIZE ? datalen : PAGE_SIZE)); + skb_frag_fill_page_desc(&skb_shinfo(skb)->frags[i], + pkt_dev->page, 0, + (datalen < PAGE_SIZE ? + datalen : PAGE_SIZE)); else - skb_frag_size_set(&skb_shinfo(skb)->frags[i], frag_len); + skb_frag_fill_page_desc(&skb_shinfo(skb)->frags[i], + pkt_dev->page, 0, frag_len); + datalen -= skb_frag_size(&skb_shinfo(skb)->frags[i]); skb->len += skb_frag_size(&skb_shinfo(skb)->frags[i]); skb->data_len += skb_frag_size(&skb_shinfo(skb)->frags[i]); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 01b48e68aca0..6724a84ebb09 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4234,10 +4234,9 @@ static inline skb_frag_t skb_head_frag_to_page_desc(struct sk_buff *frag_skb) struct page *page; page = virt_to_head_page(frag_skb->head); - __skb_frag_set_page(&head_frag, page); - skb_frag_off_set(&head_frag, frag_skb->data - - (unsigned char *)page_address(page)); - skb_frag_size_set(&head_frag, skb_headlen(frag_skb)); + skb_frag_fill_page_desc(&head_frag, page, frag_skb->data - + (unsigned char *)page_address(page), + skb_headlen(frag_skb)); return head_frag; } diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index a7cc4f9faac2..daeff54bdbfa 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -268,9 +268,8 @@ static void tls_append_frag(struct tls_record_info *record, skb_frag_size_add(frag, size); } else { ++frag; - __skb_frag_set_page(frag, pfrag->page); - skb_frag_off_set(frag, pfrag->offset); - skb_frag_size_set(frag, size); + skb_frag_fill_page_desc(frag, pfrag->page, pfrag->offset, + size); ++record->num_frags; get_page(pfrag->page); } @@ -357,9 +356,8 @@ static int tls_create_new_record(struct tls_offload_context_tx *offload_ctx, return -ENOMEM; frag = &record->frags[0]; - __skb_frag_set_page(frag, pfrag->page); - skb_frag_off_set(frag, pfrag->offset); - skb_frag_size_set(frag, prepend_size); + skb_frag_fill_page_desc(frag, pfrag->page, pfrag->offset, + prepend_size); get_page(pfrag->page); pfrag->offset += prepend_size; diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c index 80143360bf09..9c0fa0e1786a 100644 --- a/net/xfrm/xfrm_ipcomp.c +++ b/net/xfrm/xfrm_ipcomp.c @@ -74,14 +74,11 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb) if (!page) return -ENOMEM; - __skb_frag_set_page(frag, page); - len = PAGE_SIZE; if (dlen < len) len = dlen; - skb_frag_off_set(frag, 0); - skb_frag_size_set(frag, len); + skb_frag_fill_page_desc(frag, page, 0, len); memcpy(skb_frag_address(frag), scratch, len); skb->truesize += len; -- cgit v1.2.3 From 278fda0d52f67244044384abd7dd5b3a5b3a5604 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 11 May 2023 09:12:13 +0800 Subject: net: remove __skb_frag_set_page() The remaining users calling __skb_frag_set_page() with page being NULL seems to be doing defensive programming, as shinfo->nr_frags is already decremented, so remove them. Signed-off-by: Yunsheng Lin Reviewed-by: Leon Romanovsky Reviewed-by: Michael Chan Reviewed-by: Jesse Brandeburg Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2.c | 1 - drivers/net/ethernet/broadcom/bnxt/bnxt.c | 5 +---- include/linux/skbuff.h | 12 ------------ 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 466e1d62bcf6..0d917a9699c5 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -2955,7 +2955,6 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, shinfo = skb_shinfo(skb); shinfo->nr_frags--; page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]); - __skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL); cons_rx_pg->page = page; dev_kfree_skb(skb); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index efaff5018af8..f42e51bd3e42 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1102,10 +1102,7 @@ static u32 __bnxt_rx_agg_pages(struct bnxt *bp, xdp_buff_set_frag_pfmemalloc(xdp); if (bnxt_alloc_rx_page(bp, rxr, prod, GFP_ATOMIC) != 0) { - unsigned int nr_frags; - - nr_frags = --shinfo->nr_frags; - __skb_frag_set_page(&shinfo->frags[nr_frags], NULL); + --shinfo->nr_frags; cons_rx_buf->page = page; /* Update prod since possibly some pages have been diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 30be21c7d05f..00e8c435fa1a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3491,18 +3491,6 @@ static inline void skb_frag_page_copy(skb_frag_t *fragto, fragto->bv_page = fragfrom->bv_page; } -/** - * __skb_frag_set_page - sets the page contained in a paged fragment - * @frag: the paged fragment - * @page: the page to set - * - * Sets the fragment @frag to contain @page. - */ -static inline void __skb_frag_set_page(skb_frag_t *frag, struct page *page) -{ - frag->bv_page = page; -} - bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio); /** -- cgit v1.2.3 From f1b5dfe63f6a9eb17948cbaee4da4b66f51ac794 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 10 May 2023 14:54:43 -0700 Subject: ping: Convert hlist_nulls to plain hlist. Since introduced in commit c319b4d76b9e ("net: ipv4: add IPPROTO_ICMP socket kind"), ping socket does not use SLAB_TYPESAFE_BY_RCU nor check nulls marker in loops. Signed-off-by: Kuniyuki Iwashima Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/ipv4/ping.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 5178a3f3cb53..3793c81bda8a 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -49,13 +49,8 @@ #include #endif -#define ping_portaddr_for_each_entry(__sk, node, list) \ - hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node) -#define ping_portaddr_for_each_entry_rcu(__sk, node, list) \ - hlist_nulls_for_each_entry_rcu(__sk, node, list, sk_nulls_node) - struct ping_table { - struct hlist_nulls_head hash[PING_HTABLE_SIZE]; + struct hlist_head hash[PING_HTABLE_SIZE]; spinlock_t lock; }; @@ -74,17 +69,16 @@ static inline u32 ping_hashfn(const struct net *net, u32 num, u32 mask) } EXPORT_SYMBOL_GPL(ping_hash); -static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table, - struct net *net, unsigned int num) +static inline struct hlist_head *ping_hashslot(struct ping_table *table, + struct net *net, unsigned int num) { return &table->hash[ping_hashfn(net, num, PING_HTABLE_MASK)]; } int ping_get_port(struct sock *sk, unsigned short ident) { - struct hlist_nulls_node *node; - struct hlist_nulls_head *hlist; struct inet_sock *isk, *isk2; + struct hlist_head *hlist; struct sock *sk2 = NULL; isk = inet_sk(sk); @@ -98,7 +92,7 @@ int ping_get_port(struct sock *sk, unsigned short ident) result++; /* avoid zero */ hlist = ping_hashslot(&ping_table, sock_net(sk), result); - ping_portaddr_for_each_entry(sk2, node, hlist) { + sk_for_each(sk2, hlist) { isk2 = inet_sk(sk2); if (isk2->inet_num == result) @@ -115,7 +109,7 @@ next_port: goto fail; } else { hlist = ping_hashslot(&ping_table, sock_net(sk), ident); - ping_portaddr_for_each_entry(sk2, node, hlist) { + sk_for_each(sk2, hlist) { isk2 = inet_sk(sk2); /* BUG? Why is this reuse and not reuseaddr? ping.c @@ -133,9 +127,8 @@ next_port: isk->inet_num = ident; if (sk_unhashed(sk)) { pr_debug("was not hashed\n"); - sock_hold(sk); + sk_add_node_rcu(sk, hlist); sock_set_flag(sk, SOCK_RCU_FREE); - hlist_nulls_add_head_rcu(&sk->sk_nulls_node, hlist); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); } spin_unlock(&ping_table.lock); @@ -161,9 +154,7 @@ void ping_unhash(struct sock *sk) pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); spin_lock(&ping_table.lock); - if (sk_hashed(sk)) { - hlist_nulls_del_init_rcu(&sk->sk_nulls_node); - sock_put(sk); + if (sk_del_node_init_rcu(sk)) { isk->inet_num = 0; isk->inet_sport = 0; sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); @@ -175,10 +166,9 @@ EXPORT_SYMBOL_GPL(ping_unhash); /* Called under rcu_read_lock() */ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident) { - struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident); + struct hlist_head *hslot = ping_hashslot(&ping_table, net, ident); struct sock *sk = NULL; struct inet_sock *isk; - struct hlist_nulls_node *hnode; int dif, sdif; if (skb->protocol == htons(ETH_P_IP)) { @@ -197,7 +187,7 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident) return NULL; } - ping_portaddr_for_each_entry_rcu(sk, hnode, hslot) { + sk_for_each_rcu(sk, hslot) { isk = inet_sk(sk); pr_debug("iterate\n"); @@ -1045,15 +1035,14 @@ static struct sock *ping_get_first(struct seq_file *seq, int start) for (state->bucket = start; state->bucket < PING_HTABLE_SIZE; ++state->bucket) { - struct hlist_nulls_node *node; - struct hlist_nulls_head *hslot; + struct hlist_head *hslot; hslot = &ping_table.hash[state->bucket]; - if (hlist_nulls_empty(hslot)) + if (hlist_empty(hslot)) continue; - sk_nulls_for_each(sk, node, hslot) { + sk_for_each(sk, hslot) { if (net_eq(sock_net(sk), net) && sk->sk_family == state->family) goto found; @@ -1070,7 +1059,7 @@ static struct sock *ping_get_next(struct seq_file *seq, struct sock *sk) struct net *net = seq_file_net(seq); do { - sk = sk_nulls_next(sk); + sk = sk_next(sk); } while (sk && (!net_eq(sock_net(sk), net))); if (!sk) @@ -1206,6 +1195,6 @@ void __init ping_init(void) int i; for (i = 0; i < PING_HTABLE_SIZE; i++) - INIT_HLIST_NULLS_HEAD(&ping_table.hash[i], i); + INIT_HLIST_HEAD(&ping_table.hash[i]); spin_lock_init(&ping_table.lock); } -- cgit v1.2.3 From 314cf958de2a784dd3984190311e15aa1fbf2717 Mon Sep 17 00:00:00 2001 From: Daire McNamara Date: Fri, 12 May 2023 13:20:32 +0100 Subject: net: macb: Shorten max_tx_len to 4KiB - 56 on mpfs On mpfs, with SRAM configured for 4 queues, setting max_tx_len to GEM_TX_MAX_LEN=0x3f0 results multiple AMBA errors. Setting max_tx_len to (4KiB - 56) removes those errors. The details are described in erratum 1686 by Cadence The max jumbo frame size is also reduced for mpfs to (4KiB - 56). Signed-off-by: Daire McNamara Reviewed-by: Conor Dooley Reviewed-by: Simon Horman Reviewed-by: Claudiu Beznea Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.h | 1 + drivers/net/ethernet/cadence/macb_main.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index cfbdd0022764..b6d5bf8deb79 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -1181,6 +1181,7 @@ struct macb_config { struct clk **hclk, struct clk **tx_clk, struct clk **rx_clk, struct clk **tsu_clk); int (*init)(struct platform_device *pdev); + unsigned int max_tx_length; int jumbo_max_len; const struct macb_usrio_config *usrio; }; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 29a1199dad14..50a4b04315e9 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4117,14 +4117,12 @@ static int macb_init(struct platform_device *pdev) /* setup appropriated routines according to adapter type */ if (macb_is_gem(bp)) { - bp->max_tx_length = GEM_MAX_TX_LEN; bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; bp->macbgem_ops.mog_init_rings = gem_init_rings; bp->macbgem_ops.mog_rx = gem_rx; dev->ethtool_ops = &gem_ethtool_ops; } else { - bp->max_tx_length = MACB_MAX_TX_LEN; bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; bp->macbgem_ops.mog_init_rings = macb_init_rings; @@ -4861,7 +4859,8 @@ static const struct macb_config mpfs_config = { .clk_init = macb_clk_init, .init = init_reset_optional, .usrio = &macb_default_usrio, - .jumbo_max_len = 10240, + .max_tx_length = 4040, /* Cadence Erratum 1686 */ + .jumbo_max_len = 4040, }; static const struct macb_config sama7g5_gem_config = { @@ -5012,6 +5011,13 @@ static int macb_probe(struct platform_device *pdev) if (macb_config) bp->jumbo_max_len = macb_config->jumbo_max_len; + if (!hw_is_gem(bp->regs, bp->native_io)) + bp->max_tx_length = MACB_MAX_TX_LEN; + else if (macb_config->max_tx_length) + bp->max_tx_length = macb_config->max_tx_length; + else + bp->max_tx_length = GEM_MAX_TX_LEN; + bp->wol = 0; if (of_property_read_bool(np, "magic-packet")) bp->wol |= MACB_WOL_HAS_MAGIC_PACKET; -- cgit v1.2.3 From 144470c88c5d9a4cab81da22a26c129e6702c6cf Mon Sep 17 00:00:00 2001 From: Shenwei Wang Date: Fri, 12 May 2023 08:20:10 -0500 Subject: net: fec: using the standard return codes when xdp xmit errors This patch standardizes the inconsistent return values for unsuccessful XDP transmits by using standardized error codes (-EBUSY or -ENOMEM). Signed-off-by: Shenwei Wang Reviewed-by: Simon Horman Reviewed-by: Horatiu Vultur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 42ec6ca3bf03..cd215ab20ff9 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3799,7 +3799,7 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, if (entries_free < MAX_SKB_FRAGS + 1) { netdev_err(fep->netdev, "NOT enough BD for SG!\n"); xdp_return_frame(frame); - return NETDEV_TX_BUSY; + return -EBUSY; } /* Fill in a Tx ring entry */ @@ -3813,7 +3813,7 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, dma_addr = dma_map_single(&fep->pdev->dev, frame->data, frame->len, DMA_TO_DEVICE); if (dma_mapping_error(&fep->pdev->dev, dma_addr)) - return FEC_ENET_XDP_CONSUMED; + return -ENOMEM; status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST); if (fep->bufdesc_ex) @@ -3869,7 +3869,7 @@ static int fec_enet_xdp_xmit(struct net_device *dev, __netif_tx_lock(nq, cpu); for (i = 0; i < num_frames; i++) { - if (fec_enet_txq_xmit_frame(fep, txq, frames[i]) != 0) + if (fec_enet_txq_xmit_frame(fep, txq, frames[i]) < 0) break; sent_frames++; } -- cgit v1.2.3 From a0b7955310a445fc0d45a0ac576bad8720cd6057 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 12 May 2023 17:58:37 +0100 Subject: net: phylink: constify fwnode arguments Both phylink_create() and phylink_fwnode_phy_connect() do not modify the fwnode argument that they are passed, so lets constify these. Reviewed-by: Simon Horman Signed-off-by: Russell King (Oracle) Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 11 ++++++----- include/linux/phylink.h | 9 +++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index a4111f1be375..cf53096047e6 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -708,7 +708,7 @@ static int phylink_validate(struct phylink *pl, unsigned long *supported, } static int phylink_parse_fixedlink(struct phylink *pl, - struct fwnode_handle *fwnode) + const struct fwnode_handle *fwnode) { struct fwnode_handle *fixed_node; bool pause, asym_pause, autoneg; @@ -819,7 +819,8 @@ static int phylink_parse_fixedlink(struct phylink *pl, return 0; } -static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode) +static int phylink_parse_mode(struct phylink *pl, + const struct fwnode_handle *fwnode) { struct fwnode_handle *dn; const char *managed; @@ -1441,7 +1442,7 @@ static void phylink_fixed_poll(struct timer_list *t) static const struct sfp_upstream_ops sfp_phylink_ops; static int phylink_register_sfp(struct phylink *pl, - struct fwnode_handle *fwnode) + const struct fwnode_handle *fwnode) { struct sfp_bus *bus; int ret; @@ -1480,7 +1481,7 @@ static int phylink_register_sfp(struct phylink *pl, * must use IS_ERR() to check for errors from this function. */ struct phylink *phylink_create(struct phylink_config *config, - struct fwnode_handle *fwnode, + const struct fwnode_handle *fwnode, phy_interface_t iface, const struct phylink_mac_ops *mac_ops) { @@ -1809,7 +1810,7 @@ EXPORT_SYMBOL_GPL(phylink_of_phy_connect); * Returns 0 on success or a negative errno. */ int phylink_fwnode_phy_connect(struct phylink *pl, - struct fwnode_handle *fwnode, + const struct fwnode_handle *fwnode, u32 flags) { struct fwnode_handle *phy_fwnode; diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 71755c66c162..bb782f05ad08 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -568,16 +568,17 @@ void phylink_generic_validate(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state); -struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *, - phy_interface_t iface, - const struct phylink_mac_ops *mac_ops); +struct phylink *phylink_create(struct phylink_config *, + const struct fwnode_handle *, + phy_interface_t, + const struct phylink_mac_ops *); void phylink_destroy(struct phylink *); bool phylink_expects_phy(struct phylink *pl); int phylink_connect_phy(struct phylink *, struct phy_device *); int phylink_of_phy_connect(struct phylink *, struct device_node *, u32 flags); int phylink_fwnode_phy_connect(struct phylink *pl, - struct fwnode_handle *fwnode, + const struct fwnode_handle *fwnode, u32 flags); void phylink_disconnect_phy(struct phylink *); -- cgit v1.2.3 From befcc1fce564bdb20ee55be981a355b0a7d0eac5 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 12 May 2023 16:35:58 +0100 Subject: sfc: fix use-after-free in efx_tc_flower_record_encap_match() When writing error messages to extack for pseudo collisions, we can't use encap->type as encap has already been freed. Fortunately the same value is stored in local variable em_type, so use that instead. Fixes: 3c9561c0a5b9 ("sfc: support TC decap rules matching on enc_ip_tos") Reported-by: Simon Horman Signed-off-by: Edward Cree Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/tc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index da684b4b7211..6dfbdb39f2fe 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -504,7 +504,7 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, if (em_type != EFX_TC_EM_PSEUDO_MASK) { NL_SET_ERR_MSG_FMT_MOD(extack, "%s encap match conflicts with existing pseudo(MASK) entry", - encap->type ? "Pseudo" : "Direct"); + em_type ? "Pseudo" : "Direct"); return -EEXIST; } if (child_ip_tos_mask != old->child_ip_tos_mask) { @@ -525,7 +525,7 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, default: /* Unrecognised pseudo-type. Just say no */ NL_SET_ERR_MSG_FMT_MOD(extack, "%s encap match conflicts with existing pseudo(%d) entry", - encap->type ? "Pseudo" : "Direct", + em_type ? "Pseudo" : "Direct", old->type); return -EEXIST; } -- cgit v1.2.3 From 29ebbba7d46136cba324264e513a1e964ca16c0a Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Thu, 11 May 2023 10:04:53 -0700 Subject: bpf: Don't EFAULT for {g,s}setsockopt with wrong optlen With the way the hooks implemented right now, we have a special condition: optval larger than PAGE_SIZE will expose only first 4k into BPF; any modifications to the optval are ignored. If the BPF program doesn't handle this condition by resetting optlen to 0, the userspace will get EFAULT. The intention of the EFAULT was to make it apparent to the developers that the program is doing something wrong. However, this inadvertently might affect production workloads with the BPF programs that are not too careful (i.e., returning EFAULT for perfectly valid setsockopt/getsockopt calls). Let's try to minimize the chance of BPF program screwing up userspace by ignoring the output of those BPF programs (instead of returning EFAULT to the userspace). pr_info_once those cases to the dmesg to help with figuring out what's going wrong. Fixes: 0d01da6afc54 ("bpf: implement getsockopt and setsockopt hooks") Suggested-by: Martin KaFai Lau Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230511170456.1759459-2-sdf@google.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/cgroup.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index a06e118a9be5..14c870595428 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1826,6 +1826,12 @@ int __cgroup_bpf_run_filter_setsockopt(struct sock *sk, int *level, ret = 1; } else if (ctx.optlen > max_optlen || ctx.optlen < -1) { /* optlen is out of bounds */ + if (*optlen > PAGE_SIZE && ctx.optlen >= 0) { + pr_info_once("bpf setsockopt: ignoring program buffer with optlen=%d (max_optlen=%d)\n", + ctx.optlen, max_optlen); + ret = 0; + goto out; + } ret = -EFAULT; } else { /* optlen within bounds, run kernel handler */ @@ -1881,8 +1887,10 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level, .optname = optname, .current_task = current, }; + int orig_optlen; int ret; + orig_optlen = max_optlen; ctx.optlen = max_optlen; max_optlen = sockopt_alloc_buf(&ctx, max_optlen, &buf); if (max_optlen < 0) @@ -1905,6 +1913,7 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level, ret = -EFAULT; goto out; } + orig_optlen = ctx.optlen; if (copy_from_user(ctx.optval, optval, min(ctx.optlen, max_optlen)) != 0) { @@ -1922,6 +1931,12 @@ int __cgroup_bpf_run_filter_getsockopt(struct sock *sk, int level, goto out; if (optval && (ctx.optlen > max_optlen || ctx.optlen < 0)) { + if (orig_optlen > PAGE_SIZE && ctx.optlen >= 0) { + pr_info_once("bpf getsockopt: ignoring program buffer with optlen=%d (max_optlen=%d)\n", + ctx.optlen, max_optlen); + ret = retval; + goto out; + } ret = -EFAULT; goto out; } -- cgit v1.2.3 From 989a4a7dbff21399da42e808a4ae134023546f41 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Thu, 11 May 2023 10:04:54 -0700 Subject: selftests/bpf: Update EFAULT {g,s}etsockopt selftests Instead of assuming EFAULT, let's assume the BPF program's output is ignored. Remove "getsockopt: deny arbitrary ctx->retval" because it was actually testing optlen. We have separate set of tests for retval. Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230511170456.1759459-3-sdf@google.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/prog_tests/sockopt.c | 96 ++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt.c b/tools/testing/selftests/bpf/prog_tests/sockopt.c index aa4debf62fc6..33dd4532e642 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt.c @@ -5,10 +5,15 @@ static char bpf_log_buf[4096]; static bool verbose; +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + enum sockopt_test_error { OK = 0, DENY_LOAD, DENY_ATTACH, + EOPNOTSUPP_GETSOCKOPT, EPERM_GETSOCKOPT, EFAULT_GETSOCKOPT, EPERM_SETSOCKOPT, @@ -273,10 +278,31 @@ static struct sockopt_test { .error = EFAULT_GETSOCKOPT, }, { - .descr = "getsockopt: deny arbitrary ctx->retval", + .descr = "getsockopt: ignore >PAGE_SIZE optlen", .insns = { - /* ctx->retval = 123 */ - BPF_MOV64_IMM(BPF_REG_0, 123), + /* write 0xFF to the first optval byte */ + + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + /* r2 = ctx->optval */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), + /* r6 = ctx->optval + 1 */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), + + /* r7 = ctx->optval_end */ + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, + offsetof(struct bpf_sockopt, optval_end)), + + /* if (ctx->optval + 1 <= ctx->optval_end) { */ + BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), + /* ctx->optval[0] = 0xF0 */ + BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xFF), + /* } */ + + /* retval changes are ignored */ + /* ctx->retval = 5 */ + BPF_MOV64_IMM(BPF_REG_0, 5), BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, offsetof(struct bpf_sockopt, retval)), @@ -287,9 +313,11 @@ static struct sockopt_test { .attach_type = BPF_CGROUP_GETSOCKOPT, .expected_attach_type = BPF_CGROUP_GETSOCKOPT, - .get_optlen = 64, - - .error = EFAULT_GETSOCKOPT, + .get_level = 1234, + .get_optname = 5678, + .get_optval = {}, /* the changes are ignored */ + .get_optlen = PAGE_SIZE + 1, + .error = EOPNOTSUPP_GETSOCKOPT, }, { .descr = "getsockopt: support smaller ctx->optlen", @@ -648,6 +676,45 @@ static struct sockopt_test { .error = EFAULT_SETSOCKOPT, }, + { + .descr = "setsockopt: ignore >PAGE_SIZE optlen", + .insns = { + /* write 0xFF to the first optval byte */ + + /* r6 = ctx->optval */ + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, + offsetof(struct bpf_sockopt, optval)), + /* r2 = ctx->optval */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_6), + /* r6 = ctx->optval + 1 */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_6, 1), + + /* r7 = ctx->optval_end */ + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_1, + offsetof(struct bpf_sockopt, optval_end)), + + /* if (ctx->optval + 1 <= ctx->optval_end) { */ + BPF_JMP_REG(BPF_JGT, BPF_REG_6, BPF_REG_7, 1), + /* ctx->optval[0] = 0xF0 */ + BPF_ST_MEM(BPF_B, BPF_REG_2, 0, 0xF0), + /* } */ + + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .attach_type = BPF_CGROUP_SETSOCKOPT, + .expected_attach_type = BPF_CGROUP_SETSOCKOPT, + + .set_level = SOL_IP, + .set_optname = IP_TOS, + .set_optval = {}, + .set_optlen = PAGE_SIZE + 1, + + .get_level = SOL_IP, + .get_optname = IP_TOS, + .get_optval = {}, /* the changes are ignored */ + .get_optlen = 4, + }, { .descr = "setsockopt: allow changing ctx->optlen within bounds", .insns = { @@ -906,6 +973,13 @@ static int run_test(int cgroup_fd, struct sockopt_test *test) } if (test->set_optlen) { + if (test->set_optlen >= PAGE_SIZE) { + int num_pages = test->set_optlen / PAGE_SIZE; + int remainder = test->set_optlen % PAGE_SIZE; + + test->set_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder; + } + err = setsockopt(sock_fd, test->set_level, test->set_optname, test->set_optval, test->set_optlen); if (err) { @@ -921,7 +995,15 @@ static int run_test(int cgroup_fd, struct sockopt_test *test) } if (test->get_optlen) { + if (test->get_optlen >= PAGE_SIZE) { + int num_pages = test->get_optlen / PAGE_SIZE; + int remainder = test->get_optlen % PAGE_SIZE; + + test->get_optlen = num_pages * sysconf(_SC_PAGESIZE) + remainder; + } + optval = malloc(test->get_optlen); + memset(optval, 0, test->get_optlen); socklen_t optlen = test->get_optlen; socklen_t expected_get_optlen = test->get_optlen_ret ?: test->get_optlen; @@ -929,6 +1011,8 @@ static int run_test(int cgroup_fd, struct sockopt_test *test) err = getsockopt(sock_fd, test->get_level, test->get_optname, optval, &optlen); if (err) { + if (errno == EOPNOTSUPP && test->error == EOPNOTSUPP_GETSOCKOPT) + goto free_optval; if (errno == EPERM && test->error == EPERM_GETSOCKOPT) goto free_optval; if (errno == EFAULT && test->error == EFAULT_GETSOCKOPT) -- cgit v1.2.3 From e01b4a72f132c1ca63e3ed851bef9b3c62ae6149 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Thu, 11 May 2023 10:04:55 -0700 Subject: selftests/bpf: Correctly handle optlen > 4096 Even though it's not relevant in selftests, the people might still copy-paste from them. So let's take care of optlen > 4096 cases explicitly. Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230511170456.1759459-4-sdf@google.com Signed-off-by: Martin KaFai Lau --- .../bpf/prog_tests/cgroup_getset_retval.c | 20 ++++ .../selftests/bpf/prog_tests/sockopt_inherit.c | 59 ++++------- .../selftests/bpf/prog_tests/sockopt_multi.c | 108 ++++++--------------- .../selftests/bpf/prog_tests/sockopt_qos_to_cc.c | 2 + .../bpf/progs/cgroup_getset_retval_getsockopt.c | 13 +++ .../bpf/progs/cgroup_getset_retval_setsockopt.c | 17 ++++ .../testing/selftests/bpf/progs/sockopt_inherit.c | 18 +++- tools/testing/selftests/bpf/progs/sockopt_multi.c | 26 ++++- .../selftests/bpf/progs/sockopt_qos_to_cc.c | 10 +- tools/testing/selftests/bpf/progs/sockopt_sk.c | 25 +++-- 10 files changed, 166 insertions(+), 132 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c b/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c index 4d2fa99273d8..2bb5773d6f99 100644 --- a/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c +++ b/tools/testing/selftests/bpf/prog_tests/cgroup_getset_retval.c @@ -25,6 +25,8 @@ static void test_setsockopt_set(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that sets EUNATCH, assert that * we actually get that error when we run setsockopt() */ @@ -59,6 +61,8 @@ static void test_setsockopt_set_and_get(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that sets EUNATCH, and one that gets the * previously set errno. Assert that we get the same errno back. */ @@ -100,6 +104,8 @@ static void test_setsockopt_default_zero(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that gets the previously set errno. * Assert that, without anything setting one, we get 0. */ @@ -134,6 +140,8 @@ static void test_setsockopt_default_zero_and_set(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that gets the previously set errno, and then * one that sets the errno to EUNATCH. Assert that the get does not * see EUNATCH set later, and does not prevent EUNATCH from being set. @@ -177,6 +185,8 @@ static void test_setsockopt_override(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that sets EUNATCH, then one that sets EISCONN, * and then one that gets the exported errno. Assert both the syscall * and the helper sees the last set errno. @@ -224,6 +234,8 @@ static void test_setsockopt_legacy_eperm(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that return a reject without setting errno * (legacy reject), and one that gets the errno. Assert that for * backward compatibility the syscall result in EPERM, and this @@ -268,6 +280,8 @@ static void test_setsockopt_legacy_no_override(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach setsockopt that sets EUNATCH, then one that return a reject * without setting errno, and then one that gets the exported errno. * Assert both the syscall and the helper's errno are unaffected by @@ -319,6 +333,8 @@ static void test_getsockopt_get(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach getsockopt that gets previously set errno. Assert that the * error from kernel is in both ctx_retval_value and retval_value. */ @@ -359,6 +375,8 @@ static void test_getsockopt_override(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach getsockopt that sets retval to -EISCONN. Assert that this * overrides the value from kernel. */ @@ -396,6 +414,8 @@ static void test_getsockopt_retval_sync(int cgroup_fd, int sock_fd) if (!ASSERT_OK_PTR(obj, "skel-load")) return; + obj->bss->page_size = sysconf(_SC_PAGESIZE); + /* Attach getsockopt that sets retval to -EISCONN, and one that clears * ctx retval. Assert that the clearing ctx retval is synced to helper * and clears any errors both from kernel and BPF.. diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c b/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c index 60c17a8e2789..917f486db826 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_inherit.c @@ -2,6 +2,8 @@ #include #include "cgroup_helpers.h" +#include "sockopt_inherit.skel.h" + #define SOL_CUSTOM 0xdeadbeef #define CUSTOM_INHERIT1 0 #define CUSTOM_INHERIT2 1 @@ -132,58 +134,30 @@ static int start_server(void) return fd; } -static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title, - const char *prog_name) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) { - log_err("Failed to deduct types for %s BPF program", prog_name); - return -1; - } - - prog = bpf_object__find_program_by_name(obj, prog_name); - if (!prog) { - log_err("Failed to find %s BPF program", prog_name); - return -1; - } - - err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, - attach_type, 0); - if (err) { - log_err("Failed to attach %s BPF program", prog_name); - return -1; - } - - return 0; -} - static void run_test(int cgroup_fd) { + struct bpf_link *link_getsockopt = NULL; + struct bpf_link *link_setsockopt = NULL; int server_fd = -1, client_fd; - struct bpf_object *obj; + struct sockopt_inherit *obj; void *server_err; pthread_t tid; int err; - obj = bpf_object__open_file("sockopt_inherit.bpf.o", NULL); - if (!ASSERT_OK_PTR(obj, "obj_open")) + obj = sockopt_inherit__open_and_load(); + if (!ASSERT_OK_PTR(obj, "skel-load")) return; - err = bpf_object__load(obj); - if (!ASSERT_OK(err, "obj_load")) - goto close_bpf_object; + obj->bss->page_size = sysconf(_SC_PAGESIZE); - err = prog_attach(obj, cgroup_fd, "cgroup/getsockopt", "_getsockopt"); - if (!ASSERT_OK(err, "prog_attach _getsockopt")) + link_getsockopt = bpf_program__attach_cgroup(obj->progs._getsockopt, + cgroup_fd); + if (!ASSERT_OK_PTR(link_getsockopt, "cg-attach-getsockopt")) goto close_bpf_object; - err = prog_attach(obj, cgroup_fd, "cgroup/setsockopt", "_setsockopt"); - if (!ASSERT_OK(err, "prog_attach _setsockopt")) + link_setsockopt = bpf_program__attach_cgroup(obj->progs._setsockopt, + cgroup_fd); + if (!ASSERT_OK_PTR(link_setsockopt, "cg-attach-setsockopt")) goto close_bpf_object; server_fd = start_server(); @@ -217,7 +191,10 @@ static void run_test(int cgroup_fd) close_server_fd: close(server_fd); close_bpf_object: - bpf_object__close(obj); + bpf_link__destroy(link_getsockopt); + bpf_link__destroy(link_setsockopt); + + sockopt_inherit__destroy(obj); } void test_sockopt_inherit(void) diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c b/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c index 7f5659349011..759bbb6f8c5f 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_multi.c @@ -2,61 +2,13 @@ #include #include "cgroup_helpers.h" -static int prog_attach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) { - log_err("Failed to deduct types for %s BPF program", title); - return -1; - } - - prog = bpf_object__find_program_by_name(obj, name); - if (!prog) { - log_err("Failed to find %s BPF program", name); - return -1; - } - - err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, - attach_type, BPF_F_ALLOW_MULTI); - if (err) { - log_err("Failed to attach %s BPF program", name); - return -1; - } - - return 0; -} +#include "sockopt_multi.skel.h" -static int prog_detach(struct bpf_object *obj, int cgroup_fd, const char *title, const char *name) -{ - enum bpf_attach_type attach_type; - enum bpf_prog_type prog_type; - struct bpf_program *prog; - int err; - - err = libbpf_prog_type_by_name(title, &prog_type, &attach_type); - if (err) - return -1; - - prog = bpf_object__find_program_by_name(obj, name); - if (!prog) - return -1; - - err = bpf_prog_detach2(bpf_program__fd(prog), cgroup_fd, - attach_type); - if (err) - return -1; - - return 0; -} - -static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, +static int run_getsockopt_test(struct sockopt_multi *obj, int cg_parent, int cg_child, int sock_fd) { + struct bpf_link *link_parent = NULL; + struct bpf_link *link_child = NULL; socklen_t optlen; __u8 buf; int err; @@ -89,8 +41,9 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, * - child: 0x80 -> 0x90 */ - err = prog_attach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); - if (err) + link_child = bpf_program__attach_cgroup(obj->progs._getsockopt_child, + cg_child); + if (!ASSERT_OK_PTR(link_child, "cg-attach-getsockopt_child")) goto detach; buf = 0x00; @@ -113,8 +66,9 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, * - parent: 0x90 -> 0xA0 */ - err = prog_attach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent"); - if (err) + link_parent = bpf_program__attach_cgroup(obj->progs._getsockopt_parent, + cg_parent); + if (!ASSERT_OK_PTR(link_parent, "cg-attach-getsockopt_parent")) goto detach; buf = 0x00; @@ -157,11 +111,8 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, * - parent: unexpected 0x40, EPERM */ - err = prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); - if (err) { - log_err("Failed to detach child program"); - goto detach; - } + bpf_link__destroy(link_child); + link_child = NULL; buf = 0x00; optlen = 1; @@ -198,15 +149,17 @@ static int run_getsockopt_test(struct bpf_object *obj, int cg_parent, } detach: - prog_detach(obj, cg_child, "cgroup/getsockopt", "_getsockopt_child"); - prog_detach(obj, cg_parent, "cgroup/getsockopt", "_getsockopt_parent"); + bpf_link__destroy(link_child); + bpf_link__destroy(link_parent); return err; } -static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, +static int run_setsockopt_test(struct sockopt_multi *obj, int cg_parent, int cg_child, int sock_fd) { + struct bpf_link *link_parent = NULL; + struct bpf_link *link_child = NULL; socklen_t optlen; __u8 buf; int err; @@ -236,8 +189,9 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, /* Attach child program and make sure it adds 0x10. */ - err = prog_attach(obj, cg_child, "cgroup/setsockopt", "_setsockopt"); - if (err) + link_child = bpf_program__attach_cgroup(obj->progs._setsockopt, + cg_child); + if (!ASSERT_OK_PTR(link_child, "cg-attach-setsockopt_child")) goto detach; buf = 0x80; @@ -263,8 +217,9 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, /* Attach parent program and make sure it adds another 0x10. */ - err = prog_attach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt"); - if (err) + link_parent = bpf_program__attach_cgroup(obj->progs._setsockopt, + cg_parent); + if (!ASSERT_OK_PTR(link_parent, "cg-attach-setsockopt_parent")) goto detach; buf = 0x80; @@ -289,8 +244,8 @@ static int run_setsockopt_test(struct bpf_object *obj, int cg_parent, } detach: - prog_detach(obj, cg_child, "cgroup/setsockopt", "_setsockopt"); - prog_detach(obj, cg_parent, "cgroup/setsockopt", "_setsockopt"); + bpf_link__destroy(link_child); + bpf_link__destroy(link_parent); return err; } @@ -298,9 +253,8 @@ detach: void test_sockopt_multi(void) { int cg_parent = -1, cg_child = -1; - struct bpf_object *obj = NULL; + struct sockopt_multi *obj = NULL; int sock_fd = -1; - int err = -1; cg_parent = test__join_cgroup("/parent"); if (!ASSERT_GE(cg_parent, 0, "join_cgroup /parent")) @@ -310,13 +264,11 @@ void test_sockopt_multi(void) if (!ASSERT_GE(cg_child, 0, "join_cgroup /parent/child")) goto out; - obj = bpf_object__open_file("sockopt_multi.bpf.o", NULL); - if (!ASSERT_OK_PTR(obj, "obj_load")) + obj = sockopt_multi__open_and_load(); + if (!ASSERT_OK_PTR(obj, "skel-load")) goto out; - err = bpf_object__load(obj); - if (!ASSERT_OK(err, "obj_load")) - goto out; + obj->bss->page_size = sysconf(_SC_PAGESIZE); sock_fd = socket(AF_INET, SOCK_STREAM, 0); if (!ASSERT_GE(sock_fd, 0, "socket")) @@ -327,7 +279,7 @@ void test_sockopt_multi(void) out: close(sock_fd); - bpf_object__close(obj); + sockopt_multi__destroy(obj); close(cg_child); close(cg_parent); } diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt_qos_to_cc.c b/tools/testing/selftests/bpf/prog_tests/sockopt_qos_to_cc.c index 6b53b3cb8dad..6b2d300e9fd4 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt_qos_to_cc.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt_qos_to_cc.c @@ -42,6 +42,8 @@ void test_sockopt_qos_to_cc(void) if (!ASSERT_OK_PTR(skel, "skel")) goto done; + skel->bss->page_size = sysconf(_SC_PAGESIZE); + sock_fd = socket(AF_INET6, SOCK_STREAM, 0); if (!ASSERT_GE(sock_fd, 0, "v6 socket open")) goto done; diff --git a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_getsockopt.c b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_getsockopt.c index b2a409e6382a..932b8ecd4ae3 100644 --- a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_getsockopt.c +++ b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_getsockopt.c @@ -12,6 +12,7 @@ __u32 invocations = 0; __u32 assertion_error = 0; __u32 retval_value = 0; __u32 ctx_retval_value = 0; +__u32 page_size = 0; SEC("cgroup/getsockopt") int get_retval(struct bpf_sockopt *ctx) @@ -20,6 +21,10 @@ int get_retval(struct bpf_sockopt *ctx) ctx_retval_value = ctx->retval; __sync_fetch_and_add(&invocations, 1); + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } @@ -31,6 +36,10 @@ int set_eisconn(struct bpf_sockopt *ctx) if (bpf_set_retval(-EISCONN)) assertion_error = 1; + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } @@ -41,5 +50,9 @@ int clear_retval(struct bpf_sockopt *ctx) ctx->retval = 0; + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } diff --git a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c index d6e5903e06ba..b7fa8804e19d 100644 --- a/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c +++ b/tools/testing/selftests/bpf/progs/cgroup_getset_retval_setsockopt.c @@ -11,6 +11,7 @@ __u32 invocations = 0; __u32 assertion_error = 0; __u32 retval_value = 0; +__u32 page_size = 0; SEC("cgroup/setsockopt") int get_retval(struct bpf_sockopt *ctx) @@ -18,6 +19,10 @@ int get_retval(struct bpf_sockopt *ctx) retval_value = bpf_get_retval(); __sync_fetch_and_add(&invocations, 1); + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } @@ -29,6 +34,10 @@ int set_eunatch(struct bpf_sockopt *ctx) if (bpf_set_retval(-EUNATCH)) assertion_error = 1; + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 0; } @@ -40,6 +49,10 @@ int set_eisconn(struct bpf_sockopt *ctx) if (bpf_set_retval(-EISCONN)) assertion_error = 1; + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 0; } @@ -48,5 +61,9 @@ int legacy_eperm(struct bpf_sockopt *ctx) { __sync_fetch_and_add(&invocations, 1); + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 0; } diff --git a/tools/testing/selftests/bpf/progs/sockopt_inherit.c b/tools/testing/selftests/bpf/progs/sockopt_inherit.c index 9fb241b97291..c8f59caa4639 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_inherit.c +++ b/tools/testing/selftests/bpf/progs/sockopt_inherit.c @@ -9,6 +9,8 @@ char _license[] SEC("license") = "GPL"; #define CUSTOM_INHERIT2 1 #define CUSTOM_LISTENER 2 +__u32 page_size = 0; + struct sockopt_inherit { __u8 val; }; @@ -55,7 +57,7 @@ int _getsockopt(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_CUSTOM) - return 1; /* only interested in SOL_CUSTOM */ + goto out; /* only interested in SOL_CUSTOM */ if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -70,6 +72,12 @@ int _getsockopt(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } SEC("cgroup/setsockopt") @@ -80,7 +88,7 @@ int _setsockopt(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_CUSTOM) - return 1; /* only interested in SOL_CUSTOM */ + goto out; /* only interested in SOL_CUSTOM */ if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -93,4 +101,10 @@ int _setsockopt(struct bpf_sockopt *ctx) ctx->optlen = -1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } diff --git a/tools/testing/selftests/bpf/progs/sockopt_multi.c b/tools/testing/selftests/bpf/progs/sockopt_multi.c index 177a59069dae..96f29fce050b 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_multi.c +++ b/tools/testing/selftests/bpf/progs/sockopt_multi.c @@ -5,6 +5,8 @@ char _license[] SEC("license") = "GPL"; +__u32 page_size = 0; + SEC("cgroup/getsockopt") int _getsockopt_child(struct bpf_sockopt *ctx) { @@ -12,7 +14,7 @@ int _getsockopt_child(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_IP || ctx->optname != IP_TOS) - return 1; + goto out; if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -26,6 +28,12 @@ int _getsockopt_child(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } SEC("cgroup/getsockopt") @@ -35,7 +43,7 @@ int _getsockopt_parent(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_IP || ctx->optname != IP_TOS) - return 1; + goto out; if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -49,6 +57,12 @@ int _getsockopt_parent(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } SEC("cgroup/setsockopt") @@ -58,7 +72,7 @@ int _setsockopt(struct bpf_sockopt *ctx) __u8 *optval = ctx->optval; if (ctx->level != SOL_IP || ctx->optname != IP_TOS) - return 1; + goto out; if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -67,4 +81,10 @@ int _setsockopt(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } diff --git a/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c b/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c index 1bce83b6e3a7..dbe235ede7f3 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c +++ b/tools/testing/selftests/bpf/progs/sockopt_qos_to_cc.c @@ -9,6 +9,8 @@ char _license[] SEC("license") = "GPL"; +__u32 page_size = 0; + SEC("cgroup/setsockopt") int sockopt_qos_to_cc(struct bpf_sockopt *ctx) { @@ -19,7 +21,7 @@ int sockopt_qos_to_cc(struct bpf_sockopt *ctx) char cc_cubic[TCP_CA_NAME_MAX] = "cubic"; if (ctx->level != SOL_IPV6 || ctx->optname != IPV6_TCLASS) - return 1; + goto out; if (optval + 1 > optval_end) return 0; /* EPERM, bounds check */ @@ -36,4 +38,10 @@ int sockopt_qos_to_cc(struct bpf_sockopt *ctx) return 0; } return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } diff --git a/tools/testing/selftests/bpf/progs/sockopt_sk.c b/tools/testing/selftests/bpf/progs/sockopt_sk.c index fe1df4cd206e..cb990a7d3d45 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_sk.c +++ b/tools/testing/selftests/bpf/progs/sockopt_sk.c @@ -37,7 +37,7 @@ int _getsockopt(struct bpf_sockopt *ctx) /* Bypass AF_NETLINK. */ sk = ctx->sk; if (sk && sk->family == AF_NETLINK) - return 1; + goto out; /* Make sure bpf_get_netns_cookie is callable. */ @@ -52,8 +52,7 @@ int _getsockopt(struct bpf_sockopt *ctx) * let next BPF program in the cgroup chain or kernel * handle it. */ - ctx->optlen = 0; /* bypass optval>PAGE_SIZE */ - return 1; + goto out; } if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) { @@ -61,7 +60,7 @@ int _getsockopt(struct bpf_sockopt *ctx) * let next BPF program in the cgroup chain or kernel * handle it. */ - return 1; + goto out; } if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) { @@ -69,7 +68,7 @@ int _getsockopt(struct bpf_sockopt *ctx) * let next BPF program in the cgroup chain or kernel * handle it. */ - return 1; + goto out; } if (ctx->level == SOL_TCP && ctx->optname == TCP_ZEROCOPY_RECEIVE) { @@ -85,7 +84,7 @@ int _getsockopt(struct bpf_sockopt *ctx) if (((struct tcp_zerocopy_receive *)optval)->address != 0) return 0; /* unexpected data */ - return 1; + goto out; } if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) { @@ -129,6 +128,12 @@ int _getsockopt(struct bpf_sockopt *ctx) ctx->optlen = 1; return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } SEC("cgroup/setsockopt") @@ -142,7 +147,7 @@ int _setsockopt(struct bpf_sockopt *ctx) /* Bypass AF_NETLINK. */ sk = ctx->sk; if (sk && sk->family == AF_NETLINK) - return 1; + goto out; /* Make sure bpf_get_netns_cookie is callable. */ @@ -224,4 +229,10 @@ int _setsockopt(struct bpf_sockopt *ctx) */ return 1; + +out: + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > page_size) + ctx->optlen = 0; + return 1; } -- cgit v1.2.3 From 6b6a23d5d8e857e0dda1bbe5043cf4d5e9c711d3 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Thu, 11 May 2023 10:04:56 -0700 Subject: bpf: Document EFAULT changes for sockopt And add examples for how to correctly handle large optlens. This is less relevant now when we don't EFAULT anymore, but that's still the correct thing to do. Signed-off-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230511170456.1759459-5-sdf@google.com Signed-off-by: Martin KaFai Lau --- Documentation/bpf/prog_cgroup_sockopt.rst | 57 ++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/Documentation/bpf/prog_cgroup_sockopt.rst b/Documentation/bpf/prog_cgroup_sockopt.rst index 172f957204bf..1226a94af07a 100644 --- a/Documentation/bpf/prog_cgroup_sockopt.rst +++ b/Documentation/bpf/prog_cgroup_sockopt.rst @@ -98,10 +98,65 @@ can access only the first ``PAGE_SIZE`` of that data. So it has to options: indicates that the kernel should use BPF's trimmed ``optval``. When the BPF program returns with the ``optlen`` greater than -``PAGE_SIZE``, the userspace will receive ``EFAULT`` errno. +``PAGE_SIZE``, the userspace will receive original kernel +buffers without any modifications that the BPF program might have +applied. Example ======= +Recommended way to handle BPF programs is as follows: + +.. code-block:: c + + SEC("cgroup/getsockopt") + int getsockopt(struct bpf_sockopt *ctx) + { + /* Custom socket option. */ + if (ctx->level == MY_SOL && ctx->optname == MY_OPTNAME) { + ctx->retval = 0; + optval[0] = ...; + ctx->optlen = 1; + return 1; + } + + /* Modify kernel's socket option. */ + if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) { + ctx->retval = 0; + optval[0] = ...; + ctx->optlen = 1; + return 1; + } + + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > PAGE_SIZE) + ctx->optlen = 0; + + return 1; + } + + SEC("cgroup/setsockopt") + int setsockopt(struct bpf_sockopt *ctx) + { + /* Custom socket option. */ + if (ctx->level == MY_SOL && ctx->optname == MY_OPTNAME) { + /* do something */ + ctx->optlen = -1; + return 1; + } + + /* Modify kernel's socket option. */ + if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) { + optval[0] = ...; + return 1; + } + + /* optval larger than PAGE_SIZE use kernel's buffer. */ + if (ctx->optlen > PAGE_SIZE) + ctx->optlen = 0; + + return 1; + } + See ``tools/testing/selftests/bpf/progs/sockopt_sk.c`` for an example of BPF program that handles socket options. -- cgit v1.2.3 From b2cbac9b9b28730e9e53be20b6cdf979d3b9f27e Mon Sep 17 00:00:00 2001 From: Angus Chen Date: Fri, 12 May 2023 09:01:52 +0800 Subject: net: Remove low_thresh in ip defrag As low_thresh has no work in fragment reassembles,del it. And Mark it deprecated in sysctl Document. Signed-off-by: Angus Chen Signed-off-by: David S. Miller --- Documentation/networking/nf_conntrack-sysctl.rst | 1 + include/net/inet_frag.h | 1 - net/ieee802154/6lowpan/reassembly.c | 9 ++++----- net/ipv4/ip_fragment.c | 13 +++++-------- net/ipv6/netfilter/nf_conntrack_reasm.c | 9 ++++----- net/ipv6/reassembly.c | 9 ++++----- 6 files changed, 18 insertions(+), 24 deletions(-) diff --git a/Documentation/networking/nf_conntrack-sysctl.rst b/Documentation/networking/nf_conntrack-sysctl.rst index 8b1045c3b59e..9ca356bc7217 100644 --- a/Documentation/networking/nf_conntrack-sysctl.rst +++ b/Documentation/networking/nf_conntrack-sysctl.rst @@ -55,6 +55,7 @@ nf_conntrack_frag6_high_thresh - INTEGER nf_conntrack_frag6_low_thresh is reached. nf_conntrack_frag6_low_thresh - INTEGER + (Obsolete since linux-4.17) default 196608 See nf_conntrack_frag6_low_thresh diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 325ad893f624..8543e740891a 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -13,7 +13,6 @@ struct fqdir { /* sysctls */ long high_thresh; - long low_thresh; int timeout; int max_dist; struct inet_frags *f; diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c index a91283d1e5bf..3ba4c0f27af9 100644 --- a/net/ieee802154/6lowpan/reassembly.c +++ b/net/ieee802154/6lowpan/reassembly.c @@ -318,7 +318,7 @@ err: } #ifdef CONFIG_SYSCTL - +static unsigned long lowpanfrag_low_thresh_unuesd = IPV6_FRAG_LOW_THRESH; static struct ctl_table lowpan_frags_ns_ctl_table[] = { { .procname = "6lowpanfrag_high_thresh", @@ -374,9 +374,9 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) } table[0].data = &ieee802154_lowpan->fqdir->high_thresh; - table[0].extra1 = &ieee802154_lowpan->fqdir->low_thresh; - table[1].data = &ieee802154_lowpan->fqdir->low_thresh; - table[1].extra2 = &ieee802154_lowpan->fqdir->high_thresh; + table[0].extra1 = &lowpanfrag_low_thresh_unuesd; + table[1].data = &lowpanfrag_low_thresh_unuesd; + table[1].extra2 = &ieee802154_lowpan->fqdir->high_thresh; table[2].data = &ieee802154_lowpan->fqdir->timeout; hdr = register_net_sysctl(net, "net/ieee802154/6lowpan", table); @@ -451,7 +451,6 @@ static int __net_init lowpan_frags_init_net(struct net *net) return res; ieee802154_lowpan->fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH; - ieee802154_lowpan->fqdir->low_thresh = IPV6_FRAG_LOW_THRESH; ieee802154_lowpan->fqdir->timeout = IPV6_FRAG_TIMEOUT; res = lowpan_frags_ns_sysctl_register(net); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 69c00ffdcf3e..0db5eb3dec83 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -553,7 +553,7 @@ EXPORT_SYMBOL(ip_check_defrag); #ifdef CONFIG_SYSCTL static int dist_min; - +static unsigned long ipfrag_low_thresh_unused; static struct ctl_table ip4_frags_ns_ctl_table[] = { { .procname = "ipfrag_high_thresh", @@ -609,9 +609,9 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net) } table[0].data = &net->ipv4.fqdir->high_thresh; - table[0].extra1 = &net->ipv4.fqdir->low_thresh; - table[1].data = &net->ipv4.fqdir->low_thresh; - table[1].extra2 = &net->ipv4.fqdir->high_thresh; + table[0].extra1 = &ipfrag_low_thresh_unused; + table[1].data = &ipfrag_low_thresh_unused; + table[1].extra2 = &net->ipv4.fqdir->high_thresh; table[2].data = &net->ipv4.fqdir->timeout; table[3].data = &net->ipv4.fqdir->max_dist; @@ -674,12 +674,9 @@ static int __net_init ipv4_frags_init_net(struct net *net) * A 64K fragment consumes 129736 bytes (44*2944)+200 * (1500 truesize == 2944, sizeof(struct ipq) == 200) * - * We will commit 4MB at one time. Should we cross that limit - * we will prune down to 3MB, making room for approx 8 big 64K - * fragments 8x128k. + * We will commit 4MB at one time. Should we cross that limit. */ net->ipv4.fqdir->high_thresh = 4 * 1024 * 1024; - net->ipv4.fqdir->low_thresh = 3 * 1024 * 1024; /* * Important NOTE! Fragment queue must be destroyed before MSL expires. * RFC791 is wrong proposing to prolongate timer each fragment arrival diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index d13240f13607..dc8a2854e7f3 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -42,7 +42,7 @@ static struct nft_ct_frag6_pernet *nf_frag_pernet(struct net *net) } #ifdef CONFIG_SYSCTL - +static unsigned long nf_conntrack_frag6_low_thresh_unused = IPV6_FRAG_LOW_THRESH; static struct ctl_table nf_ct_frag6_sysctl_table[] = { { .procname = "nf_conntrack_frag6_timeout", @@ -82,10 +82,10 @@ static int nf_ct_frag6_sysctl_register(struct net *net) nf_frag = nf_frag_pernet(net); table[0].data = &nf_frag->fqdir->timeout; - table[1].data = &nf_frag->fqdir->low_thresh; - table[1].extra2 = &nf_frag->fqdir->high_thresh; + table[1].data = &nf_conntrack_frag6_low_thresh_unused; + table[1].extra2 = &nf_frag->fqdir->high_thresh; table[2].data = &nf_frag->fqdir->high_thresh; - table[2].extra1 = &nf_frag->fqdir->low_thresh; + table[2].extra1 = &nf_conntrack_frag6_low_thresh_unused; hdr = register_net_sysctl(net, "net/netfilter", table); if (hdr == NULL) @@ -500,7 +500,6 @@ static int nf_ct_net_init(struct net *net) return res; nf_frag->fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH; - nf_frag->fqdir->low_thresh = IPV6_FRAG_LOW_THRESH; nf_frag->fqdir->timeout = IPV6_FRAG_TIMEOUT; res = nf_ct_frag6_sysctl_register(net); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 5bc8a28e67f9..eb8373c25675 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -416,7 +416,7 @@ static const struct inet6_protocol frag_protocol = { }; #ifdef CONFIG_SYSCTL - +static unsigned long ip6_frags_low_thresh_unused = IPV6_FRAG_LOW_THRESH; static struct ctl_table ip6_frags_ns_ctl_table[] = { { .procname = "ip6frag_high_thresh", @@ -465,9 +465,9 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net) } table[0].data = &net->ipv6.fqdir->high_thresh; - table[0].extra1 = &net->ipv6.fqdir->low_thresh; - table[1].data = &net->ipv6.fqdir->low_thresh; - table[1].extra2 = &net->ipv6.fqdir->high_thresh; + table[0].extra1 = &ip6_frags_low_thresh_unused; + table[1].data = &ip6_frags_low_thresh_unused; + table[1].extra2 = &net->ipv6.fqdir->high_thresh; table[2].data = &net->ipv6.fqdir->timeout; hdr = register_net_sysctl(net, "net/ipv6", table); @@ -536,7 +536,6 @@ static int __net_init ipv6_frags_init_net(struct net *net) return res; net->ipv6.fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH; - net->ipv6.fqdir->low_thresh = IPV6_FRAG_LOW_THRESH; net->ipv6.fqdir->timeout = IPV6_FRAG_TIMEOUT; res = ip6_frags_ns_sysctl_register(net); -- cgit v1.2.3 From 12e7789ad5b476e945aba8edb1161c633cb7db31 Mon Sep 17 00:00:00 2001 From: Naveen Mamindlapalli Date: Sat, 13 May 2023 14:21:36 +0530 Subject: sch_htb: Allow HTB priority parameter in offload mode The current implementation of HTB offload returns the EINVAL error for unsupported parameters like prio and quantum. This patch removes the error returning checks for 'prio' parameter and populates its value to tc_htb_qopt_offload structure such that driver can use the same. Add prio parameter check in mlx5 driver, as mlx5 devices are not capable of supporting the prio parameter when htb offload is used. Report error if prio parameter is set to a non-default value. Signed-off-by: Naveen Mamindlapalli Co-developed-by: Rahul Rameshbabu Signed-off-by: Rahul Rameshbabu Signed-off-by: Hariprasad Kelam Signed-off-by: Sunil Kovvuri Goutham Reviewed-by: Simon Horman Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en/qos.c | 7 ++++++- include/net/pkt_cls.h | 1 + net/sched/sch_htb.c | 7 +++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c index 2842195ee548..1874c2f0587f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c @@ -379,6 +379,12 @@ int mlx5e_htb_setup_tc(struct mlx5e_priv *priv, struct tc_htb_qopt_offload *htb_ if (!htb && htb_qopt->command != TC_HTB_CREATE) return -EINVAL; + if (htb_qopt->prio) { + NL_SET_ERR_MSG_MOD(htb_qopt->extack, + "prio parameter is not supported by device with HTB offload enabled."); + return -EOPNOTSUPP; + } + switch (htb_qopt->command) { case TC_HTB_CREATE: if (!mlx5_qos_is_supported(priv->mdev)) { @@ -515,4 +521,3 @@ int mlx5e_mqprio_rl_get_node_hw_id(struct mlx5e_mqprio_rl *rl, int tc, u32 *hw_i *hw_id = rl->leaves_id[tc]; return 0; } - diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index b3b5b0b62f16..a2ea45c7b53e 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -868,6 +868,7 @@ struct tc_htb_qopt_offload { u16 qid; u64 rate; u64 ceil; + u8 prio; }; #define TC_HTB_CLASSID_ROOT U32_MAX diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 8aef7dd9fb88..325c29041c7d 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1814,10 +1814,6 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, NL_SET_ERR_MSG(extack, "HTB offload doesn't support the quantum parameter"); goto failure; } - if (hopt->prio) { - NL_SET_ERR_MSG(extack, "HTB offload doesn't support the prio parameter"); - goto failure; - } } /* Keeping backward compatible with rate_table based iproute2 tc */ @@ -1913,6 +1909,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, TC_HTB_CLASSID_ROOT, .rate = max_t(u64, hopt->rate.rate, rate64), .ceil = max_t(u64, hopt->ceil.rate, ceil64), + .prio = hopt->prio, .extack = extack, }; err = htb_offload(dev, &offload_opt); @@ -1933,6 +1930,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, TC_H_MIN(parent->common.classid), .rate = max_t(u64, hopt->rate.rate, rate64), .ceil = max_t(u64, hopt->ceil.rate, ceil64), + .prio = hopt->prio, .extack = extack, }; err = htb_offload(dev, &offload_opt); @@ -2018,6 +2016,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, .classid = cl->common.classid, .rate = max_t(u64, hopt->rate.rate, rate64), .ceil = max_t(u64, hopt->ceil.rate, ceil64), + .prio = hopt->prio, .extack = extack, }; err = htb_offload(dev, &offload_opt); -- cgit v1.2.3 From 508c58f76ca510956625c945f9b8eb104f2c8208 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Sat, 13 May 2023 14:21:37 +0530 Subject: octeontx2-pf: Rename tot_tx_queues to non_qos_queues current implementation is such that tot_tx_queues contains both xdp queues and normal tx queues. which will be allocated in interface open calls and deallocated on interface down calls respectively. With addition of QOS, where send quees are allocated/deallacated upon user request Qos send queues won't be part of tot_tx_queues. So this patch renames tot_tx_queues to non_qos_queues. Signed-off-by: Hariprasad Kelam Reviewed-by: Simon Horman Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c | 12 ++++++------ drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h | 2 +- drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 14 +++++++------- drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index 8a41ad8ca04f..43bc56fb3c33 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -762,7 +762,7 @@ void otx2_sqb_flush(struct otx2_nic *pfvf) int timeout = 1000; ptr = (u64 *)otx2_get_regaddr(pfvf, NIX_LF_SQ_OP_STATUS); - for (qidx = 0; qidx < pfvf->hw.tot_tx_queues; qidx++) { + for (qidx = 0; qidx < pfvf->hw.non_qos_queues; qidx++) { incr = (u64)qidx << 32; while (timeout) { val = otx2_atomic64_add(incr, ptr); @@ -1048,7 +1048,7 @@ int otx2_config_nix_queues(struct otx2_nic *pfvf) } /* Initialize TX queues */ - for (qidx = 0; qidx < pfvf->hw.tot_tx_queues; qidx++) { + for (qidx = 0; qidx < pfvf->hw.non_qos_queues; qidx++) { u16 sqb_aura = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, qidx); err = otx2_sq_init(pfvf, qidx, sqb_aura); @@ -1095,7 +1095,7 @@ int otx2_config_nix(struct otx2_nic *pfvf) /* Set RQ/SQ/CQ counts */ nixlf->rq_cnt = pfvf->hw.rx_queues; - nixlf->sq_cnt = pfvf->hw.tot_tx_queues; + nixlf->sq_cnt = pfvf->hw.non_qos_queues; nixlf->cq_cnt = pfvf->qset.cq_cnt; nixlf->rss_sz = MAX_RSS_INDIR_TBL_SIZE; nixlf->rss_grps = MAX_RSS_GROUPS; @@ -1133,7 +1133,7 @@ void otx2_sq_free_sqbs(struct otx2_nic *pfvf) int sqb, qidx; u64 iova, pa; - for (qidx = 0; qidx < hw->tot_tx_queues; qidx++) { + for (qidx = 0; qidx < hw->non_qos_queues; qidx++) { sq = &qset->sq[qidx]; if (!sq->sqb_ptrs) continue; @@ -1349,7 +1349,7 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf) stack_pages = (num_sqbs + hw->stack_pg_ptrs - 1) / hw->stack_pg_ptrs; - for (qidx = 0; qidx < hw->tot_tx_queues; qidx++) { + for (qidx = 0; qidx < hw->non_qos_queues; qidx++) { pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, qidx); /* Initialize aura context */ err = otx2_aura_init(pfvf, pool_id, pool_id, num_sqbs); @@ -1369,7 +1369,7 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf) goto fail; /* Allocate pointers and free them to aura/pool */ - for (qidx = 0; qidx < hw->tot_tx_queues; qidx++) { + for (qidx = 0; qidx < hw->non_qos_queues; qidx++) { pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, qidx); pool = &pfvf->qset.pool[pool_id]; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index d17274aab374..76c50dd8e5ef 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -190,7 +190,7 @@ struct otx2_hw { u16 rx_queues; u16 tx_queues; u16 xdp_queues; - u16 tot_tx_queues; + u16 non_qos_queues; /* tx queues plus xdp queues */ u16 max_queues; u16 pool_cnt; u16 rqpool_cnt; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index 18284ad75157..cc4a94fd9afc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -1257,7 +1257,7 @@ static irqreturn_t otx2_q_intr_handler(int irq, void *data) } /* SQ */ - for (qidx = 0; qidx < pf->hw.tot_tx_queues; qidx++) { + for (qidx = 0; qidx < pf->hw.non_qos_queues; qidx++) { u64 sq_op_err_dbg, mnq_err_dbg, snd_err_dbg; u8 sq_op_err_code, mnq_err_code, snd_err_code; @@ -1383,7 +1383,7 @@ static void otx2_free_sq_res(struct otx2_nic *pf) otx2_ctx_disable(&pf->mbox, NIX_AQ_CTYPE_SQ, false); /* Free SQB pointers */ otx2_sq_free_sqbs(pf); - for (qidx = 0; qidx < pf->hw.tot_tx_queues; qidx++) { + for (qidx = 0; qidx < pf->hw.non_qos_queues; qidx++) { sq = &qset->sq[qidx]; qmem_free(pf->dev, sq->sqe); qmem_free(pf->dev, sq->tso_hdrs); @@ -1433,7 +1433,7 @@ static int otx2_init_hw_resources(struct otx2_nic *pf) * so, aura count = pool count. */ hw->rqpool_cnt = hw->rx_queues; - hw->sqpool_cnt = hw->tot_tx_queues; + hw->sqpool_cnt = hw->non_qos_queues; hw->pool_cnt = hw->rqpool_cnt + hw->sqpool_cnt; /* Maximum hardware supported transmit length */ @@ -1688,7 +1688,7 @@ int otx2_open(struct net_device *netdev) netif_carrier_off(netdev); - pf->qset.cq_cnt = pf->hw.rx_queues + pf->hw.tot_tx_queues; + pf->qset.cq_cnt = pf->hw.rx_queues + pf->hw.non_qos_queues; /* RQ and SQs are mapped to different CQs, * so find out max CQ IRQs (i.e CINTs) needed. */ @@ -1708,7 +1708,7 @@ int otx2_open(struct net_device *netdev) if (!qset->cq) goto err_free_mem; - qset->sq = kcalloc(pf->hw.tot_tx_queues, + qset->sq = kcalloc(pf->hw.non_qos_queues, sizeof(struct otx2_snd_queue), GFP_KERNEL); if (!qset->sq) goto err_free_mem; @@ -2529,7 +2529,7 @@ static int otx2_xdp_setup(struct otx2_nic *pf, struct bpf_prog *prog) xdp_features_clear_redirect_target(dev); } - pf->hw.tot_tx_queues += pf->hw.xdp_queues; + pf->hw.non_qos_queues += pf->hw.xdp_queues; if (if_up) otx2_open(pf->netdev); @@ -2760,7 +2760,7 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) hw->pdev = pdev; hw->rx_queues = qcount; hw->tx_queues = qcount; - hw->tot_tx_queues = qcount; + hw->non_qos_queues = qcount; hw->max_queues = qcount; hw->rbuf_len = OTX2_DEFAULT_RBUF_LEN; /* Use CQE of 128 byte descriptor size by default */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index 53366dbfbf27..64be99ace04e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -570,7 +570,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) hw->rx_queues = qcount; hw->tx_queues = qcount; hw->max_queues = qcount; - hw->tot_tx_queues = qcount; + hw->non_qos_queues = qcount; hw->rbuf_len = OTX2_DEFAULT_RBUF_LEN; /* Use CQE of 128 byte descriptor size by default */ hw->xqe_size = 128; -- cgit v1.2.3 From ab6dddd2a669a0ecc2ce07485c7a15fadbb5a0aa Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Sat, 13 May 2023 14:21:38 +0530 Subject: octeontx2-pf: qos send queues management Current implementation is such that the number of Send queues (SQs) are decided on the device probe which is equal to the number of online cpus. These SQs are allocated and deallocated in interface open and c lose calls respectively. This patch defines new APIs for initializing and deinitializing Send queues dynamically and allocates more number of transmit queues for QOS feature. Signed-off-by: Subbaraya Sundeep Signed-off-by: Hariprasad Kelam Signed-off-by: Sunil Kovvuri Goutham Reviewed-by: Simon Horman Reviewed-by: Jacob Keller Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 5 + .../net/ethernet/marvell/octeontx2/nic/Makefile | 2 +- .../ethernet/marvell/octeontx2/nic/otx2_common.c | 43 ++-- .../ethernet/marvell/octeontx2/nic/otx2_common.h | 39 ++- .../net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 44 +++- .../net/ethernet/marvell/octeontx2/nic/otx2_txrx.c | 24 +- .../net/ethernet/marvell/octeontx2/nic/otx2_txrx.h | 3 +- .../net/ethernet/marvell/octeontx2/nic/otx2_vf.c | 7 +- drivers/net/ethernet/marvell/octeontx2/nic/qos.h | 19 ++ .../net/ethernet/marvell/octeontx2/nic/qos_sq.c | 282 +++++++++++++++++++++ 10 files changed, 426 insertions(+), 42 deletions(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/qos.h create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 9533b1d92960..3b26893efdf8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -1222,6 +1222,11 @@ static int rvu_dbg_npa_ctx_display(struct seq_file *m, void *unused, int ctype) for (aura = id; aura < max_id; aura++) { aq_req.aura_id = aura; + + /* Skip if queue is uninitialized */ + if (ctype == NPA_AQ_CTYPE_POOL && !test_bit(aura, pfvf->pool_bmap)) + continue; + seq_printf(m, "======%s : %d=======\n", (ctype == NPA_AQ_CTYPE_AURA) ? "AURA" : "POOL", aq_req.aura_id); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile index 73fdb8798614..3d31ddf7c652 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o otx2_ptp.o rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \ otx2_flows.o otx2_tc.o cn10k.o otx2_dmac_flt.o \ - otx2_devlink.o + otx2_devlink.o qos_sq.o rvu_nicvf-y := otx2_vf.o otx2_devlink.o rvu_nicpf-$(CONFIG_DCB) += otx2_dcbnl.o diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index 43bc56fb3c33..adbcc087d2a8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -513,8 +513,8 @@ void otx2_config_irq_coalescing(struct otx2_nic *pfvf, int qidx) (pfvf->hw.cq_ecount_wait - 1)); } -int __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, - dma_addr_t *dma) +static int __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, + dma_addr_t *dma) { u8 *buf; @@ -532,8 +532,8 @@ int __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, return 0; } -static int otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, - dma_addr_t *dma) +int otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, + dma_addr_t *dma) { int ret; @@ -758,11 +758,16 @@ int otx2_txschq_stop(struct otx2_nic *pfvf) void otx2_sqb_flush(struct otx2_nic *pfvf) { int qidx, sqe_tail, sqe_head; + struct otx2_snd_queue *sq; u64 incr, *ptr, val; int timeout = 1000; ptr = (u64 *)otx2_get_regaddr(pfvf, NIX_LF_SQ_OP_STATUS); - for (qidx = 0; qidx < pfvf->hw.non_qos_queues; qidx++) { + for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) { + sq = &pfvf->qset.sq[qidx]; + if (!sq->sqb_ptrs) + continue; + incr = (u64)qidx << 32; while (timeout) { val = otx2_atomic64_add(incr, ptr); @@ -862,7 +867,7 @@ int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) return otx2_sync_mbox_msg(&pfvf->mbox); } -static int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura) +int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura) { struct otx2_qset *qset = &pfvf->qset; struct otx2_snd_queue *sq; @@ -935,9 +940,17 @@ static int otx2_cq_init(struct otx2_nic *pfvf, u16 qidx) cq->cint_idx = qidx - pfvf->hw.rx_queues; cq->cqe_cnt = qset->sqe_cnt; } else { - cq->cq_type = CQ_XDP; - cq->cint_idx = qidx - non_xdp_queues; - cq->cqe_cnt = qset->sqe_cnt; + if (pfvf->hw.xdp_queues && + qidx < non_xdp_queues + pfvf->hw.xdp_queues) { + cq->cq_type = CQ_XDP; + cq->cint_idx = qidx - non_xdp_queues; + cq->cqe_cnt = qset->sqe_cnt; + } else { + cq->cq_type = CQ_QOS; + cq->cint_idx = qidx - non_xdp_queues - + pfvf->hw.xdp_queues; + cq->cqe_cnt = qset->sqe_cnt; + } } cq->cqe_size = pfvf->qset.xqe_size; @@ -1095,7 +1108,7 @@ int otx2_config_nix(struct otx2_nic *pfvf) /* Set RQ/SQ/CQ counts */ nixlf->rq_cnt = pfvf->hw.rx_queues; - nixlf->sq_cnt = pfvf->hw.non_qos_queues; + nixlf->sq_cnt = otx2_get_total_tx_queues(pfvf); nixlf->cq_cnt = pfvf->qset.cq_cnt; nixlf->rss_sz = MAX_RSS_INDIR_TBL_SIZE; nixlf->rss_grps = MAX_RSS_GROUPS; @@ -1133,7 +1146,7 @@ void otx2_sq_free_sqbs(struct otx2_nic *pfvf) int sqb, qidx; u64 iova, pa; - for (qidx = 0; qidx < hw->non_qos_queues; qidx++) { + for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) { sq = &qset->sq[qidx]; if (!sq->sqb_ptrs) continue; @@ -1201,8 +1214,8 @@ void otx2_aura_pool_free(struct otx2_nic *pfvf) pfvf->qset.pool = NULL; } -static int otx2_aura_init(struct otx2_nic *pfvf, int aura_id, - int pool_id, int numptrs) +int otx2_aura_init(struct otx2_nic *pfvf, int aura_id, + int pool_id, int numptrs) { struct npa_aq_enq_req *aq; struct otx2_pool *pool; @@ -1278,8 +1291,8 @@ static int otx2_aura_init(struct otx2_nic *pfvf, int aura_id, return 0; } -static int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, - int stack_pages, int numptrs, int buf_size) +int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, + int stack_pages, int numptrs, int buf_size) { struct npa_aq_enq_req *aq; struct otx2_pool *pool; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 76c50dd8e5ef..eb5009152c92 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -28,6 +28,7 @@ #include "otx2_txrx.h" #include "otx2_devlink.h" #include +#include "qos.h" /* IPv4 flag more fragment bit */ #define IPV4_FLAG_MORE 0x20 @@ -190,6 +191,7 @@ struct otx2_hw { u16 rx_queues; u16 tx_queues; u16 xdp_queues; + u16 tc_tx_queues; u16 non_qos_queues; /* tx queues plus xdp queues */ u16 max_queues; u16 pool_cnt; @@ -506,6 +508,8 @@ struct otx2_nic { u16 pfc_schq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC]; bool pfc_alloc_status[NIX_PF_PFC_PRIO_MAX]; #endif + /* qos */ + struct otx2_qos qos; /* napi event count. It is needed for adaptive irq coalescing. */ u32 napi_events; @@ -750,8 +754,7 @@ static inline void cn10k_aura_freeptr(void *dev, int aura, u64 buf) /* Alloc pointer from pool/aura */ static inline u64 otx2_aura_allocptr(struct otx2_nic *pfvf, int aura) { - u64 *ptr = (u64 *)otx2_get_regaddr(pfvf, - NPA_LF_AURA_OP_ALLOCX(0)); + u64 *ptr = (__force u64 *)otx2_get_regaddr(pfvf, NPA_LF_AURA_OP_ALLOCX(0)); u64 incr = (u64)aura | BIT_ULL(63); return otx2_atomic64_add(incr, ptr); @@ -893,12 +896,23 @@ static inline void otx2_dma_unmap_page(struct otx2_nic *pfvf, static inline u16 otx2_get_smq_idx(struct otx2_nic *pfvf, u16 qidx) { + u16 smq; #ifdef CONFIG_DCB if (qidx < NIX_PF_PFC_PRIO_MAX && pfvf->pfc_alloc_status[qidx]) return pfvf->pfc_schq_list[NIX_TXSCH_LVL_SMQ][qidx]; #endif + /* check if qidx falls under QOS queues */ + if (qidx >= pfvf->hw.non_qos_queues) + smq = pfvf->qos.qid_to_sqmap[qidx - pfvf->hw.non_qos_queues]; + else + smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][0]; - return pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][0]; + return smq; +} + +static inline u16 otx2_get_total_tx_queues(struct otx2_nic *pfvf) +{ + return pfvf->hw.non_qos_queues + pfvf->hw.tc_tx_queues; } /* MSI-X APIs */ @@ -927,17 +941,22 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool pfc_en); int otx2_txsch_alloc(struct otx2_nic *pfvf); int otx2_txschq_stop(struct otx2_nic *pfvf); void otx2_sqb_flush(struct otx2_nic *pfvf); -int __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, - dma_addr_t *dma); +int otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, + dma_addr_t *dma); int otx2_rxtx_enable(struct otx2_nic *pfvf, bool enable); void otx2_ctx_disable(struct mbox *mbox, int type, bool npa); int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable); void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq); void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq); +int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura); int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); int otx2_alloc_buffer(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, dma_addr_t *dma); +int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, + int stack_pages, int numptrs, int buf_size); +int otx2_aura_init(struct otx2_nic *pfvf, int aura_id, + int pool_id, int numptrs); /* RSS configuration APIs*/ int otx2_rss_init(struct otx2_nic *pfvf); @@ -1045,4 +1064,14 @@ static inline void cn10k_handle_mcs_event(struct otx2_nic *pfvf, {} #endif /* CONFIG_MACSEC */ +/* qos support */ +static inline void otx2_qos_init(struct otx2_nic *pfvf, int qos_txqs) +{ + struct otx2_hw *hw = &pfvf->hw; + + hw->tc_tx_queues = qos_txqs; +} + +u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb, + struct net_device *sb_dev); #endif /* OTX2_COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index cc4a94fd9afc..918114dc4688 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -23,6 +23,7 @@ #include "otx2_struct.h" #include "otx2_ptp.h" #include "cn10k.h" +#include "qos.h" #include #define DRV_NAME "rvu_nicpf" @@ -1228,6 +1229,7 @@ static char *nix_snd_status_e_str[NIX_SND_STATUS_MAX] = { static irqreturn_t otx2_q_intr_handler(int irq, void *data) { struct otx2_nic *pf = data; + struct otx2_snd_queue *sq; u64 val, *ptr; u64 qidx = 0; @@ -1257,10 +1259,14 @@ static irqreturn_t otx2_q_intr_handler(int irq, void *data) } /* SQ */ - for (qidx = 0; qidx < pf->hw.non_qos_queues; qidx++) { + for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) { u64 sq_op_err_dbg, mnq_err_dbg, snd_err_dbg; u8 sq_op_err_code, mnq_err_code, snd_err_code; + sq = &pf->qset.sq[qidx]; + if (!sq->sqb_ptrs) + continue; + /* Below debug registers captures first errors corresponding to * those registers. We don't have to check against SQ qid as * these are fatal errors. @@ -1383,7 +1389,7 @@ static void otx2_free_sq_res(struct otx2_nic *pf) otx2_ctx_disable(&pf->mbox, NIX_AQ_CTYPE_SQ, false); /* Free SQB pointers */ otx2_sq_free_sqbs(pf); - for (qidx = 0; qidx < pf->hw.non_qos_queues; qidx++) { + for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) { sq = &qset->sq[qidx]; qmem_free(pf->dev, sq->sqe); qmem_free(pf->dev, sq->tso_hdrs); @@ -1433,7 +1439,7 @@ static int otx2_init_hw_resources(struct otx2_nic *pf) * so, aura count = pool count. */ hw->rqpool_cnt = hw->rx_queues; - hw->sqpool_cnt = hw->non_qos_queues; + hw->sqpool_cnt = otx2_get_total_tx_queues(pf); hw->pool_cnt = hw->rqpool_cnt + hw->sqpool_cnt; /* Maximum hardware supported transmit length */ @@ -1688,11 +1694,14 @@ int otx2_open(struct net_device *netdev) netif_carrier_off(netdev); - pf->qset.cq_cnt = pf->hw.rx_queues + pf->hw.non_qos_queues; /* RQ and SQs are mapped to different CQs, * so find out max CQ IRQs (i.e CINTs) needed. */ - pf->hw.cint_cnt = max(pf->hw.rx_queues, pf->hw.tx_queues); + pf->hw.cint_cnt = max3(pf->hw.rx_queues, pf->hw.tx_queues, + pf->hw.tc_tx_queues); + + pf->qset.cq_cnt = pf->hw.rx_queues + otx2_get_total_tx_queues(pf); + qset->napi = kcalloc(pf->hw.cint_cnt, sizeof(*cq_poll), GFP_KERNEL); if (!qset->napi) return -ENOMEM; @@ -1743,6 +1752,11 @@ int otx2_open(struct net_device *netdev) else cq_poll->cq_ids[CQ_XDP] = CINT_INVALID_CQ; + cq_poll->cq_ids[CQ_QOS] = (qidx < pf->hw.tc_tx_queues) ? + (qidx + pf->hw.rx_queues + + pf->hw.non_qos_queues) : + CINT_INVALID_CQ; + cq_poll->dev = (void *)pf; cq_poll->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_CQE; INIT_WORK(&cq_poll->dim.work, otx2_dim_work); @@ -1947,6 +1961,12 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev) int qidx = skb_get_queue_mapping(skb); struct otx2_snd_queue *sq; struct netdev_queue *txq; + int sq_idx; + + /* XDP SQs are not mapped with TXQs + * advance qid to derive correct sq mapped with QOS + */ + sq_idx = (qidx >= pf->hw.tx_queues) ? (qidx + pf->hw.xdp_queues) : qidx; /* Check for minimum and maximum packet length */ if (skb->len <= ETH_HLEN || @@ -1955,7 +1975,7 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } - sq = &pf->qset.sq[qidx]; + sq = &pf->qset.sq[sq_idx]; txq = netdev_get_tx_queue(netdev, qidx); if (!otx2_sq_append_skb(netdev, sq, skb, qidx)) { @@ -1973,8 +1993,8 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } -static u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb, - struct net_device *sb_dev) +u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb, + struct net_device *sb_dev) { #ifdef CONFIG_DCB struct otx2_nic *pf = netdev_priv(netdev); @@ -1996,6 +2016,7 @@ pick_tx: #endif return netdev_pick_tx(netdev, skb, NULL); } +EXPORT_SYMBOL(otx2_select_queue); static netdev_features_t otx2_fix_features(struct net_device *dev, netdev_features_t features) @@ -2712,10 +2733,10 @@ static void otx2_sriov_vfcfg_cleanup(struct otx2_nic *pf) static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *dev = &pdev->dev; + int err, qcount, qos_txqs; struct net_device *netdev; struct otx2_nic *pf; struct otx2_hw *hw; - int err, qcount; int num_vec; err = pcim_enable_device(pdev); @@ -2740,8 +2761,9 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* Set number of queues */ qcount = min_t(int, num_online_cpus(), OTX2_MAX_CQ_CNT); + qos_txqs = min_t(int, qcount, OTX2_QOS_MAX_LEAF_NODES); - netdev = alloc_etherdev_mqs(sizeof(*pf), qcount, qcount); + netdev = alloc_etherdev_mqs(sizeof(*pf), qcount + qos_txqs, qcount); if (!netdev) { err = -ENOMEM; goto err_release_regions; @@ -2929,6 +2951,8 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_pf_sriov_init; #endif + otx2_qos_init(pf, qos_txqs); + return 0; err_pf_sriov_init: diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c index 7045fedfd73a..e288f46b23a8 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c @@ -464,12 +464,13 @@ process_cqe: break; } - if (cq->cq_type == CQ_XDP) { + qidx = cq->cq_idx - pfvf->hw.rx_queues; + + if (cq->cq_type == CQ_XDP) otx2_xdp_snd_pkt_handler(pfvf, sq, cqe); - } else { - otx2_snd_pkt_handler(pfvf, cq, sq, cqe, budget, - &tx_pkts, &tx_bytes); - } + else + otx2_snd_pkt_handler(pfvf, cq, &pfvf->qset.sq[qidx], + cqe, budget, &tx_pkts, &tx_bytes); cqe->hdr.cqe_type = NIX_XQE_TYPE_INVALID; processed_cqe++; @@ -486,7 +487,11 @@ process_cqe: if (likely(tx_pkts)) { struct netdev_queue *txq; - txq = netdev_get_tx_queue(pfvf->netdev, cq->cint_idx); + qidx = cq->cq_idx - pfvf->hw.rx_queues; + + if (qidx >= pfvf->hw.tx_queues) + qidx -= pfvf->hw.xdp_queues; + txq = netdev_get_tx_queue(pfvf->netdev, qidx); netdev_tx_completed_queue(txq, tx_pkts, tx_bytes); /* Check if queue was stopped earlier due to ring full */ smp_mb(); @@ -736,7 +741,8 @@ static void otx2_sqe_add_hdr(struct otx2_nic *pfvf, struct otx2_snd_queue *sq, sqe_hdr->aura = sq->aura_id; /* Post a CQE Tx after pkt transmission */ sqe_hdr->pnc = 1; - sqe_hdr->sq = qidx; + sqe_hdr->sq = (qidx >= pfvf->hw.tx_queues) ? + qidx + pfvf->hw.xdp_queues : qidx; } sqe_hdr->total = skb->len; /* Set SQE identifier which will be used later for freeing SKB */ @@ -1221,8 +1227,10 @@ void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq) struct nix_cqe_tx_s *cqe; int processed_cqe = 0; struct sg_list *sg; + int qidx; - sq = &pfvf->qset.sq[cq->cint_idx]; + qidx = cq->cq_idx - pfvf->hw.rx_queues; + sq = &pfvf->qset.sq[qidx]; if (otx2_nix_cq_op_status(pfvf, cq) || !cq->pend_cqe) return; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h index 93cac2c2664c..7ab6db9a986f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h @@ -102,7 +102,8 @@ enum cq_type { CQ_RX, CQ_TX, CQ_XDP, - CQS_PER_CINT = 3, /* RQ + SQ + XDP */ + CQ_QOS, + CQS_PER_CINT = 4, /* RQ + SQ + XDP + QOS_SQ */ }; struct otx2_cq_poll { diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index 64be99ace04e..cd92b9535cdb 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -479,6 +479,7 @@ static const struct net_device_ops otx2vf_netdev_ops = { .ndo_open = otx2vf_open, .ndo_stop = otx2vf_stop, .ndo_start_xmit = otx2vf_xmit, + .ndo_select_queue = otx2_select_queue, .ndo_set_rx_mode = otx2vf_set_rx_mode, .ndo_set_mac_address = otx2_set_mac_address, .ndo_change_mtu = otx2vf_change_mtu, @@ -524,10 +525,10 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int num_vec = pci_msix_vec_count(pdev); struct device *dev = &pdev->dev; + int err, qcount, qos_txqs; struct net_device *netdev; struct otx2_nic *vf; struct otx2_hw *hw; - int err, qcount; err = pcim_enable_device(pdev); if (err) { @@ -550,7 +551,8 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); qcount = num_online_cpus(); - netdev = alloc_etherdev_mqs(sizeof(*vf), qcount, qcount); + qos_txqs = min_t(int, qcount, OTX2_QOS_MAX_LEAF_NODES); + netdev = alloc_etherdev_mqs(sizeof(*vf), qcount + qos_txqs, qcount); if (!netdev) { err = -ENOMEM; goto err_release_regions; @@ -699,6 +701,7 @@ static int otx2vf_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_shutdown_tc; #endif + otx2_qos_init(vf, qos_txqs); return 0; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.h b/drivers/net/ethernet/marvell/octeontx2/nic/qos.h new file mode 100644 index 000000000000..73a62d092e99 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Marvell RVU Ethernet driver + * + * Copyright (C) 2023 Marvell. + * + */ +#ifndef OTX2_QOS_H +#define OTX2_QOS_H + +#define OTX2_QOS_MAX_LEAF_NODES 16 + +int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq); +void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx, u16 mdq); + +struct otx2_qos { + u16 qid_to_sqmap[OTX2_QOS_MAX_LEAF_NODES]; + }; + +#endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c new file mode 100644 index 000000000000..e142d43f5a62 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU Physical Function ethernet driver + * + * Copyright (C) 2023 Marvell. + * + */ + +#include +#include + +#include "cn10k.h" +#include "otx2_reg.h" +#include "otx2_common.h" +#include "otx2_txrx.h" +#include "otx2_struct.h" + +#define OTX2_QOS_MAX_LEAF_NODES 16 + +static void otx2_qos_aura_pool_free(struct otx2_nic *pfvf, int pool_id) +{ + struct otx2_pool *pool; + + if (!pfvf->qset.pool) + return; + + pool = &pfvf->qset.pool[pool_id]; + qmem_free(pfvf->dev, pool->stack); + qmem_free(pfvf->dev, pool->fc_addr); + pool->stack = NULL; + pool->fc_addr = NULL; +} + +static int otx2_qos_sq_aura_pool_init(struct otx2_nic *pfvf, int qidx) +{ + struct otx2_qset *qset = &pfvf->qset; + int pool_id, stack_pages, num_sqbs; + struct otx2_hw *hw = &pfvf->hw; + struct otx2_snd_queue *sq; + struct otx2_pool *pool; + dma_addr_t bufptr; + int err, ptr; + u64 iova, pa; + + /* Calculate number of SQBs needed. + * + * For a 128byte SQE, and 4K size SQB, 31 SQEs will fit in one SQB. + * Last SQE is used for pointing to next SQB. + */ + num_sqbs = (hw->sqb_size / 128) - 1; + num_sqbs = (qset->sqe_cnt + num_sqbs) / num_sqbs; + + /* Get no of stack pages needed */ + stack_pages = + (num_sqbs + hw->stack_pg_ptrs - 1) / hw->stack_pg_ptrs; + + pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, qidx); + pool = &pfvf->qset.pool[pool_id]; + + /* Initialize aura context */ + err = otx2_aura_init(pfvf, pool_id, pool_id, num_sqbs); + if (err) + return err; + + /* Initialize pool context */ + err = otx2_pool_init(pfvf, pool_id, stack_pages, + num_sqbs, hw->sqb_size); + if (err) + goto aura_free; + + /* Flush accumulated messages */ + err = otx2_sync_mbox_msg(&pfvf->mbox); + if (err) + goto pool_free; + + /* Allocate pointers and free them to aura/pool */ + sq = &qset->sq[qidx]; + sq->sqb_count = 0; + sq->sqb_ptrs = kcalloc(num_sqbs, sizeof(*sq->sqb_ptrs), GFP_KERNEL); + if (!sq->sqb_ptrs) { + err = -ENOMEM; + goto pool_free; + } + + for (ptr = 0; ptr < num_sqbs; ptr++) { + err = otx2_alloc_rbuf(pfvf, pool, &bufptr); + if (err) + goto sqb_free; + pfvf->hw_ops->aura_freeptr(pfvf, pool_id, bufptr); + sq->sqb_ptrs[sq->sqb_count++] = (u64)bufptr; + } + + return 0; + +sqb_free: + while (ptr--) { + if (!sq->sqb_ptrs[ptr]) + continue; + iova = sq->sqb_ptrs[ptr]; + pa = otx2_iova_to_phys(pfvf->iommu_domain, iova); + dma_unmap_page_attrs(pfvf->dev, iova, hw->sqb_size, + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + put_page(virt_to_page(phys_to_virt(pa))); + otx2_aura_allocptr(pfvf, pool_id); + } + sq->sqb_count = 0; + kfree(sq->sqb_ptrs); +pool_free: + qmem_free(pfvf->dev, pool->stack); +aura_free: + qmem_free(pfvf->dev, pool->fc_addr); + otx2_mbox_reset(&pfvf->mbox.mbox, 0); + return err; +} + +static void otx2_qos_sq_free_sqbs(struct otx2_nic *pfvf, int qidx) +{ + struct otx2_qset *qset = &pfvf->qset; + struct otx2_hw *hw = &pfvf->hw; + struct otx2_snd_queue *sq; + u64 iova, pa; + int sqb; + + sq = &qset->sq[qidx]; + if (!sq->sqb_ptrs) + return; + for (sqb = 0; sqb < sq->sqb_count; sqb++) { + if (!sq->sqb_ptrs[sqb]) + continue; + iova = sq->sqb_ptrs[sqb]; + pa = otx2_iova_to_phys(pfvf->iommu_domain, iova); + dma_unmap_page_attrs(pfvf->dev, iova, hw->sqb_size, + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + put_page(virt_to_page(phys_to_virt(pa))); + } + + sq->sqb_count = 0; + + sq = &qset->sq[qidx]; + qmem_free(pfvf->dev, sq->sqe); + qmem_free(pfvf->dev, sq->tso_hdrs); + kfree(sq->sg); + kfree(sq->sqb_ptrs); + qmem_free(pfvf->dev, sq->timestamps); + + memset((void *)sq, 0, sizeof(*sq)); +} + +/* send queue id */ +static void otx2_qos_sqb_flush(struct otx2_nic *pfvf, int qidx) +{ + int sqe_tail, sqe_head; + u64 incr, *ptr, val; + + ptr = (__force u64 *)otx2_get_regaddr(pfvf, NIX_LF_SQ_OP_STATUS); + incr = (u64)qidx << 32; + val = otx2_atomic64_add(incr, ptr); + sqe_head = (val >> 20) & 0x3F; + sqe_tail = (val >> 28) & 0x3F; + if (sqe_head != sqe_tail) + usleep_range(50, 60); +} + +static int otx2_qos_ctx_disable(struct otx2_nic *pfvf, u16 qidx, int aura_id) +{ + struct nix_cn10k_aq_enq_req *cn10k_sq_aq; + struct npa_aq_enq_req *aura_aq; + struct npa_aq_enq_req *pool_aq; + struct nix_aq_enq_req *sq_aq; + + if (test_bit(CN10K_LMTST, &pfvf->hw.cap_flag)) { + cn10k_sq_aq = otx2_mbox_alloc_msg_nix_cn10k_aq_enq(&pfvf->mbox); + if (!cn10k_sq_aq) + return -ENOMEM; + cn10k_sq_aq->qidx = qidx; + cn10k_sq_aq->sq.ena = 0; + cn10k_sq_aq->sq_mask.ena = 1; + cn10k_sq_aq->ctype = NIX_AQ_CTYPE_SQ; + cn10k_sq_aq->op = NIX_AQ_INSTOP_WRITE; + } else { + sq_aq = otx2_mbox_alloc_msg_nix_aq_enq(&pfvf->mbox); + if (!sq_aq) + return -ENOMEM; + sq_aq->qidx = qidx; + sq_aq->sq.ena = 0; + sq_aq->sq_mask.ena = 1; + sq_aq->ctype = NIX_AQ_CTYPE_SQ; + sq_aq->op = NIX_AQ_INSTOP_WRITE; + } + + aura_aq = otx2_mbox_alloc_msg_npa_aq_enq(&pfvf->mbox); + if (!aura_aq) { + otx2_mbox_reset(&pfvf->mbox.mbox, 0); + return -ENOMEM; + } + + aura_aq->aura_id = aura_id; + aura_aq->aura.ena = 0; + aura_aq->aura_mask.ena = 1; + aura_aq->ctype = NPA_AQ_CTYPE_AURA; + aura_aq->op = NPA_AQ_INSTOP_WRITE; + + pool_aq = otx2_mbox_alloc_msg_npa_aq_enq(&pfvf->mbox); + if (!pool_aq) { + otx2_mbox_reset(&pfvf->mbox.mbox, 0); + return -ENOMEM; + } + + pool_aq->aura_id = aura_id; + pool_aq->pool.ena = 0; + pool_aq->pool_mask.ena = 1; + + pool_aq->ctype = NPA_AQ_CTYPE_POOL; + pool_aq->op = NPA_AQ_INSTOP_WRITE; + + return otx2_sync_mbox_msg(&pfvf->mbox); +} + +int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq) +{ + struct otx2_hw *hw = &pfvf->hw; + int pool_id, sq_idx, err; + + if (pfvf->flags & OTX2_FLAG_INTF_DOWN) + return -EPERM; + + sq_idx = hw->non_qos_queues + qidx; + + mutex_lock(&pfvf->mbox.lock); + err = otx2_qos_sq_aura_pool_init(pfvf, sq_idx); + if (err) + goto out; + + pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, sq_idx); + pfvf->qos.qid_to_sqmap[qidx] = smq; + err = otx2_sq_init(pfvf, sq_idx, pool_id); + if (err) + goto out; +out: + mutex_unlock(&pfvf->mbox.lock); + return err; +} + +void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx, u16 mdq) +{ + struct otx2_qset *qset = &pfvf->qset; + struct otx2_hw *hw = &pfvf->hw; + struct otx2_snd_queue *sq; + struct otx2_cq_queue *cq; + int pool_id, sq_idx; + + sq_idx = hw->non_qos_queues + qidx; + + /* If the DOWN flag is set SQs are already freed */ + if (pfvf->flags & OTX2_FLAG_INTF_DOWN) + return; + + sq = &pfvf->qset.sq[sq_idx]; + if (!sq->sqb_ptrs) + return; + + if (sq_idx < hw->non_qos_queues || + sq_idx >= otx2_get_total_tx_queues(pfvf)) { + netdev_err(pfvf->netdev, "Send Queue is not a QoS queue\n"); + return; + } + + cq = &qset->cq[pfvf->hw.rx_queues + sq_idx]; + pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, sq_idx); + + otx2_qos_sqb_flush(pfvf, sq_idx); + otx2_smq_flush(pfvf, otx2_get_smq_idx(pfvf, sq_idx)); + otx2_cleanup_tx_cqes(pfvf, cq); + + mutex_lock(&pfvf->mbox.lock); + otx2_qos_ctx_disable(pfvf, sq_idx, pool_id); + mutex_unlock(&pfvf->mbox.lock); + + otx2_qos_sq_free_sqbs(pfvf, sq_idx); + otx2_qos_aura_pool_free(pfvf, pool_id); +} -- cgit v1.2.3 From 6b4b2ded9c4282deea421eef144ab0ced954721c Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Sat, 13 May 2023 14:21:39 +0530 Subject: octeontx2-pf: Refactor schedular queue alloc/free calls 1. Upon txschq free request, the transmit schedular config in hardware is not getting reset. This patch adds necessary changes to do the same. 2. Current implementation calls txschq alloc during interface initialization and in response handler updates the default txschq array. This creates a problem for htb offload where txsch alloc will be called for every tc class. This patch addresses the issue by reading txschq response in mbox caller function instead in the response handler. 3. Current otx2_txschq_stop routine tries to free all txschq nodes allocated to the interface. This creates a problem for htb offload. This patch introduces the otx2_txschq_free_one to free txschq in a given level. Signed-off-by: Hariprasad Kelam Signed-off-by: Naveen Mamindlapalli Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 45 +++++++++++++++ .../ethernet/marvell/octeontx2/nic/otx2_common.c | 67 ++++++++++++++-------- .../ethernet/marvell/octeontx2/nic/otx2_common.h | 3 +- .../net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 13 +---- .../net/ethernet/marvell/octeontx2/nic/otx2_vf.c | 4 -- 5 files changed, 94 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 4ad707e758b9..79ed7af0b0a4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -1691,6 +1691,42 @@ exit: return true; } +static void nix_reset_tx_schedule(struct rvu *rvu, int blkaddr, + int lvl, int schq) +{ + u64 tlx_parent = 0, tlx_schedule = 0; + + switch (lvl) { + case NIX_TXSCH_LVL_TL2: + tlx_parent = NIX_AF_TL2X_PARENT(schq); + tlx_schedule = NIX_AF_TL2X_SCHEDULE(schq); + break; + case NIX_TXSCH_LVL_TL3: + tlx_parent = NIX_AF_TL3X_PARENT(schq); + tlx_schedule = NIX_AF_TL3X_SCHEDULE(schq); + break; + case NIX_TXSCH_LVL_TL4: + tlx_parent = NIX_AF_TL4X_PARENT(schq); + tlx_schedule = NIX_AF_TL4X_SCHEDULE(schq); + break; + case NIX_TXSCH_LVL_MDQ: + /* no need to reset SMQ_CFG as HW clears this CSR + * on SMQ flush + */ + tlx_parent = NIX_AF_MDQX_PARENT(schq); + tlx_schedule = NIX_AF_MDQX_SCHEDULE(schq); + break; + default: + return; + } + + if (tlx_parent) + rvu_write64(rvu, blkaddr, tlx_parent, 0x0); + + if (tlx_schedule) + rvu_write64(rvu, blkaddr, tlx_schedule, 0x0); +} + /* Disable shaping of pkts by a scheduler queue * at a given scheduler level. */ @@ -2039,6 +2075,7 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, pfvf_map[schq] = TXSCH_MAP(pcifunc, 0); nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq); + nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); } for (idx = 0; idx < req->schq[lvl]; idx++) { @@ -2048,6 +2085,7 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, pfvf_map[schq] = TXSCH_MAP(pcifunc, 0); nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq); + nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); } } @@ -2143,6 +2181,7 @@ static int nix_txschq_free(struct rvu *rvu, u16 pcifunc) continue; nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); nix_clear_tx_xoff(rvu, blkaddr, lvl, schq); + nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq); } } nix_clear_tx_xoff(rvu, blkaddr, NIX_TXSCH_LVL_TL1, @@ -2181,6 +2220,7 @@ static int nix_txschq_free(struct rvu *rvu, u16 pcifunc) for (schq = 0; schq < txsch->schq.max; schq++) { if (TXSCH_MAP_FUNC(txsch->pfvf_map[schq]) != pcifunc) continue; + nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); rvu_free_rsrc(&txsch->schq, schq); txsch->pfvf_map[schq] = TXSCH_MAP(0, NIX_TXSCHQ_FREE); } @@ -2240,6 +2280,9 @@ static int nix_txschq_free_one(struct rvu *rvu, */ nix_clear_tx_xoff(rvu, blkaddr, lvl, schq); + nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); + nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq); + /* Flush if it is a SMQ. Onus of disabling * TL2/3 queue links before SMQ flush is on user */ @@ -2249,6 +2292,8 @@ static int nix_txschq_free_one(struct rvu *rvu, goto err; } + nix_reset_tx_schedule(rvu, blkaddr, lvl, schq); + /* Free the resource */ rvu_free_rsrc(&txsch->schq, schq); txsch->pfvf_map[schq] = TXSCH_MAP(0, NIX_TXSCHQ_FREE); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index adbcc087d2a8..6df6f6380b55 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -716,7 +716,8 @@ EXPORT_SYMBOL(otx2_smq_flush); int otx2_txsch_alloc(struct otx2_nic *pfvf) { struct nix_txsch_alloc_req *req; - int lvl; + struct nix_txsch_alloc_rsp *rsp; + int lvl, schq, rc; /* Get memory to put this msg */ req = otx2_mbox_alloc_msg_nix_txsch_alloc(&pfvf->mbox); @@ -726,33 +727,68 @@ int otx2_txsch_alloc(struct otx2_nic *pfvf) /* Request one schq per level */ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) req->schq[lvl] = 1; + rc = otx2_sync_mbox_msg(&pfvf->mbox); + if (rc) + return rc; - return otx2_sync_mbox_msg(&pfvf->mbox); + rsp = (struct nix_txsch_alloc_rsp *) + otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + if (IS_ERR(rsp)) + return PTR_ERR(rsp); + + /* Setup transmit scheduler list */ + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) + for (schq = 0; schq < rsp->schq[lvl]; schq++) + pfvf->hw.txschq_list[lvl][schq] = + rsp->schq_list[lvl][schq]; + + pfvf->hw.txschq_link_cfg_lvl = rsp->link_cfg_lvl; + + return 0; } -int otx2_txschq_stop(struct otx2_nic *pfvf) +void otx2_txschq_free_one(struct otx2_nic *pfvf, u16 lvl, u16 schq) { struct nix_txsch_free_req *free_req; - int lvl, schq, err; + int err; mutex_lock(&pfvf->mbox.lock); - /* Free the transmit schedulers */ + free_req = otx2_mbox_alloc_msg_nix_txsch_free(&pfvf->mbox); if (!free_req) { mutex_unlock(&pfvf->mbox.lock); - return -ENOMEM; + netdev_err(pfvf->netdev, + "Failed alloc txschq free req\n"); + return; } - free_req->flags = TXSCHQ_FREE_ALL; + free_req->schq_lvl = lvl; + free_req->schq = schq; + err = otx2_sync_mbox_msg(&pfvf->mbox); + if (err) { + netdev_err(pfvf->netdev, + "Failed stop txschq %d at level %d\n", schq, lvl); + } + mutex_unlock(&pfvf->mbox.lock); +} + +void otx2_txschq_stop(struct otx2_nic *pfvf) +{ + int lvl, schq; + + /* free non QOS TLx nodes */ + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) + otx2_txschq_free_one(pfvf, lvl, + pfvf->hw.txschq_list[lvl][0]); /* Clear the txschq list */ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { for (schq = 0; schq < MAX_TXSCHQ_PER_FUNC; schq++) pfvf->hw.txschq_list[lvl][schq] = 0; } - return err; + } void otx2_sqb_flush(struct otx2_nic *pfvf) @@ -1642,21 +1678,6 @@ void mbox_handler_cgx_fec_stats(struct otx2_nic *pfvf, pfvf->hw.cgx_fec_uncorr_blks += rsp->fec_uncorr_blks; } -void mbox_handler_nix_txsch_alloc(struct otx2_nic *pf, - struct nix_txsch_alloc_rsp *rsp) -{ - int lvl, schq; - - /* Setup transmit scheduler list */ - for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) - for (schq = 0; schq < rsp->schq[lvl]; schq++) - pf->hw.txschq_list[lvl][schq] = - rsp->schq_list[lvl][schq]; - - pf->hw.txschq_link_cfg_lvl = rsp->link_cfg_lvl; -} -EXPORT_SYMBOL(mbox_handler_nix_txsch_alloc); - void mbox_handler_npa_lf_alloc(struct otx2_nic *pfvf, struct npa_lf_alloc_rsp *rsp) { diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index eb5009152c92..0b870a88f9fd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -939,7 +939,8 @@ int otx2_config_nix(struct otx2_nic *pfvf); int otx2_config_nix_queues(struct otx2_nic *pfvf); int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool pfc_en); int otx2_txsch_alloc(struct otx2_nic *pfvf); -int otx2_txschq_stop(struct otx2_nic *pfvf); +void otx2_txschq_stop(struct otx2_nic *pfvf); +void otx2_txschq_free_one(struct otx2_nic *pfvf, u16 lvl, u16 schq); void otx2_sqb_flush(struct otx2_nic *pfvf); int otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, dma_addr_t *dma); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index 918114dc4688..0ca99482558c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -792,10 +792,6 @@ static void otx2_process_pfaf_mbox_msg(struct otx2_nic *pf, case MBOX_MSG_NIX_LF_ALLOC: mbox_handler_nix_lf_alloc(pf, (struct nix_lf_alloc_rsp *)msg); break; - case MBOX_MSG_NIX_TXSCH_ALLOC: - mbox_handler_nix_txsch_alloc(pf, - (struct nix_txsch_alloc_rsp *)msg); - break; case MBOX_MSG_NIX_BP_ENABLE: mbox_handler_nix_bp_enable(pf, (struct nix_bp_cfg_rsp *)msg); break; @@ -1522,8 +1518,7 @@ err_free_nix_queues: otx2_free_cq_res(pf); otx2_ctx_disable(mbox, NIX_AQ_CTYPE_RQ, false); err_free_txsch: - if (otx2_txschq_stop(pf)) - dev_err(pf->dev, "%s failed to stop TX schedulers\n", __func__); + otx2_txschq_stop(pf); err_free_sq_ptrs: otx2_sq_free_sqbs(pf); err_free_rq_ptrs: @@ -1558,15 +1553,13 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) struct mbox *mbox = &pf->mbox; struct otx2_cq_queue *cq; struct msg_req *req; - int qidx, err; + int qidx; /* Ensure all SQE are processed */ otx2_sqb_flush(pf); /* Stop transmission */ - err = otx2_txschq_stop(pf); - if (err) - dev_err(pf->dev, "RVUPF: Failed to stop/free TX schedulers\n"); + otx2_txschq_stop(pf); #ifdef CONFIG_DCB if (pf->pfc_en) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index cd92b9535cdb..404855bccb4b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -70,10 +70,6 @@ static void otx2vf_process_vfaf_mbox_msg(struct otx2_nic *vf, case MBOX_MSG_NIX_LF_ALLOC: mbox_handler_nix_lf_alloc(vf, (struct nix_lf_alloc_rsp *)msg); break; - case MBOX_MSG_NIX_TXSCH_ALLOC: - mbox_handler_nix_txsch_alloc(vf, - (struct nix_txsch_alloc_rsp *)msg); - break; case MBOX_MSG_NIX_BP_ENABLE: mbox_handler_nix_bp_enable(vf, (struct nix_bp_cfg_rsp *)msg); break; -- cgit v1.2.3 From cb748a7ebad79b35a4cb652c2148fbebdcd860f3 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Sat, 13 May 2023 14:21:40 +0530 Subject: octeontx2-pf: Prepare for QOS offload This patch moves rate limiting definitions to a common header file and adds csr definitions required for QOS code. Signed-off-by: Hariprasad Kelam Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/nic/otx2_common.h | 28 ++++++++++++++++++++++ .../net/ethernet/marvell/octeontx2/nic/otx2_reg.h | 13 ++++++++++ .../net/ethernet/marvell/octeontx2/nic/otx2_tc.c | 22 ++--------------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 0b870a88f9fd..4ce2009d5247 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -185,6 +185,21 @@ struct mbox { int up_num_msgs; /* mbox_up number of messages */ }; +/* Egress rate limiting definitions */ +#define MAX_BURST_EXPONENT 0x0FULL +#define MAX_BURST_MANTISSA 0xFFULL +#define MAX_BURST_SIZE 130816ULL +#define MAX_RATE_DIVIDER_EXPONENT 12ULL +#define MAX_RATE_EXPONENT 0x0FULL +#define MAX_RATE_MANTISSA 0xFFULL + +/* Bitfields in NIX_TLX_PIR register */ +#define TLX_RATE_MANTISSA GENMASK_ULL(8, 1) +#define TLX_RATE_EXPONENT GENMASK_ULL(12, 9) +#define TLX_RATE_DIVIDER_EXPONENT GENMASK_ULL(16, 13) +#define TLX_BURST_MANTISSA GENMASK_ULL(36, 29) +#define TLX_BURST_EXPONENT GENMASK_ULL(40, 37) + struct otx2_hw { struct pci_dev *pdev; struct otx2_rss_info rss_info; @@ -253,6 +268,7 @@ struct otx2_hw { #define CN10K_RPM 3 #define CN10K_PTP_ONESTEP 4 #define CN10K_HW_MACSEC 5 +#define QOS_CIR_PIR_SUPPORT 6 unsigned long cap_flag; #define LMT_LINE_SIZE 128 @@ -591,6 +607,7 @@ static inline void otx2_setup_dev_hw_settings(struct otx2_nic *pfvf) __set_bit(CN10K_LMTST, &hw->cap_flag); __set_bit(CN10K_RPM, &hw->cap_flag); __set_bit(CN10K_PTP_ONESTEP, &hw->cap_flag); + __set_bit(QOS_CIR_PIR_SUPPORT, &hw->cap_flag); } if (is_dev_cn10kb(pfvf->pdev)) @@ -915,6 +932,17 @@ static inline u16 otx2_get_total_tx_queues(struct otx2_nic *pfvf) return pfvf->hw.non_qos_queues + pfvf->hw.tc_tx_queues; } +static inline u64 otx2_convert_rate(u64 rate) +{ + u64 converted_rate; + + /* Convert bytes per second to Mbps */ + converted_rate = rate * 8; + converted_rate = max_t(u64, converted_rate / 1000000, 1); + + return converted_rate; +} + /* MSI-X APIs */ void otx2_free_cints(struct otx2_nic *pfvf, int n); void otx2_set_cints_affinity(struct otx2_nic *pfvf); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_reg.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_reg.h index 1b967eaf948b..45a32e4b49d1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_reg.h @@ -145,12 +145,25 @@ #define NIX_AF_TL1X_TOPOLOGY(a) (0xC80 | (a) << 16) #define NIX_AF_TL2X_PARENT(a) (0xE88 | (a) << 16) #define NIX_AF_TL2X_SCHEDULE(a) (0xE00 | (a) << 16) +#define NIX_AF_TL2X_TOPOLOGY(a) (0xE80 | (a) << 16) +#define NIX_AF_TL2X_CIR(a) (0xE20 | (a) << 16) +#define NIX_AF_TL2X_PIR(a) (0xE30 | (a) << 16) #define NIX_AF_TL3X_PARENT(a) (0x1088 | (a) << 16) #define NIX_AF_TL3X_SCHEDULE(a) (0x1000 | (a) << 16) +#define NIX_AF_TL3X_SHAPE(a) (0x1010 | (a) << 16) +#define NIX_AF_TL3X_CIR(a) (0x1020 | (a) << 16) +#define NIX_AF_TL3X_PIR(a) (0x1030 | (a) << 16) +#define NIX_AF_TL3X_TOPOLOGY(a) (0x1080 | (a) << 16) #define NIX_AF_TL4X_PARENT(a) (0x1288 | (a) << 16) #define NIX_AF_TL4X_SCHEDULE(a) (0x1200 | (a) << 16) +#define NIX_AF_TL4X_SHAPE(a) (0x1210 | (a) << 16) +#define NIX_AF_TL4X_CIR(a) (0x1220 | (a) << 16) #define NIX_AF_TL4X_PIR(a) (0x1230 | (a) << 16) +#define NIX_AF_TL4X_TOPOLOGY(a) (0x1280 | (a) << 16) #define NIX_AF_MDQX_SCHEDULE(a) (0x1400 | (a) << 16) +#define NIX_AF_MDQX_SHAPE(a) (0x1410 | (a) << 16) +#define NIX_AF_MDQX_CIR(a) (0x1420 | (a) << 16) +#define NIX_AF_MDQX_PIR(a) (0x1430 | (a) << 16) #define NIX_AF_MDQX_PARENT(a) (0x1480 | (a) << 16) #define NIX_AF_TL3_TL2X_LINKX_CFG(a, b) (0x1700 | (a) << 16 | (b) << 3) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c index 8392f63e433f..2735cfff8fc1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -20,24 +20,9 @@ #include "cn10k.h" #include "otx2_common.h" -/* Egress rate limiting definitions */ -#define MAX_BURST_EXPONENT 0x0FULL -#define MAX_BURST_MANTISSA 0xFFULL -#define MAX_BURST_SIZE 130816ULL -#define MAX_RATE_DIVIDER_EXPONENT 12ULL -#define MAX_RATE_EXPONENT 0x0FULL -#define MAX_RATE_MANTISSA 0xFFULL - #define CN10K_MAX_BURST_MANTISSA 0x7FFFULL #define CN10K_MAX_BURST_SIZE 8453888ULL -/* Bitfields in NIX_TLX_PIR register */ -#define TLX_RATE_MANTISSA GENMASK_ULL(8, 1) -#define TLX_RATE_EXPONENT GENMASK_ULL(12, 9) -#define TLX_RATE_DIVIDER_EXPONENT GENMASK_ULL(16, 13) -#define TLX_BURST_MANTISSA GENMASK_ULL(36, 29) -#define TLX_BURST_EXPONENT GENMASK_ULL(40, 37) - #define CN10K_TLX_BURST_MANTISSA GENMASK_ULL(43, 29) #define CN10K_TLX_BURST_EXPONENT GENMASK_ULL(47, 44) @@ -264,7 +249,6 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic, struct netlink_ext_ack *extack = cls->common.extack; struct flow_action *actions = &cls->rule->action; struct flow_action_entry *entry; - u64 rate; int err; err = otx2_tc_validate_flow(nic, actions, extack); @@ -288,10 +272,8 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic, NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); return -EOPNOTSUPP; } - /* Convert bytes per second to Mbps */ - rate = entry->police.rate_bytes_ps * 8; - rate = max_t(u64, rate / 1000000, 1); - err = otx2_set_matchall_egress_rate(nic, entry->police.burst, rate); + err = otx2_set_matchall_egress_rate(nic, entry->police.burst, + otx2_convert_rate(entry->police.rate_bytes_ps)); if (err) return err; nic->flags |= OTX2_FLAG_TC_MATCHALL_EGRESS_ENABLED; -- cgit v1.2.3 From 5e6808b4c68d7882971514ab3279926eb07c8b2d Mon Sep 17 00:00:00 2001 From: Naveen Mamindlapalli Date: Sat, 13 May 2023 14:21:41 +0530 Subject: octeontx2-pf: Add support for HTB offload This patch registers callbacks to support HTB offload. Below are features supported, - supports traffic shaping on the given class by honoring rate and ceil configuration. - supports traffic scheduling, which prioritizes different types of traffic based on strict priority values. - supports the creation of leaf to inner classes such that parent node rate limits apply to all child nodes. Signed-off-by: Naveen Mamindlapalli Signed-off-by: Hariprasad Kelam Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/common.h | 2 +- .../net/ethernet/marvell/octeontx2/nic/Makefile | 2 +- .../ethernet/marvell/octeontx2/nic/otx2_common.c | 5 + .../ethernet/marvell/octeontx2/nic/otx2_common.h | 10 + .../net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 53 +- .../net/ethernet/marvell/octeontx2/nic/otx2_tc.c | 7 +- .../net/ethernet/marvell/octeontx2/nic/otx2_vf.c | 1 + drivers/net/ethernet/marvell/octeontx2/nic/qos.c | 1363 ++++++++++++++++++++ drivers/net/ethernet/marvell/octeontx2/nic/qos.h | 58 +- .../net/ethernet/marvell/octeontx2/nic/qos_sq.c | 20 +- 10 files changed, 1507 insertions(+), 14 deletions(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/nic/qos.c diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index 8931864ee110..f5bf719a6ccf 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -142,7 +142,7 @@ enum nix_scheduler { #define TXSCH_RR_QTM_MAX ((1 << 24) - 1) #define TXSCH_TL1_DFLT_RR_QTM TXSCH_RR_QTM_MAX -#define TXSCH_TL1_DFLT_RR_PRIO (0x1ull) +#define TXSCH_TL1_DFLT_RR_PRIO (0x7ull) #define CN10K_MAX_DWRR_WEIGHT 16384 /* Weight is 14bit on CN10K */ /* Min/Max packet sizes, excluding FCS */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile index 3d31ddf7c652..5664f768cb0c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/nic/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_OCTEONTX2_VF) += rvu_nicvf.o otx2_ptp.o rvu_nicpf-y := otx2_pf.o otx2_common.o otx2_txrx.o otx2_ethtool.o \ otx2_flows.o otx2_tc.o cn10k.o otx2_dmac_flt.o \ - otx2_devlink.o qos_sq.o + otx2_devlink.o qos_sq.o qos.o rvu_nicvf-y := otx2_vf.o otx2_devlink.o rvu_nicpf-$(CONFIG_DCB) += otx2_dcbnl.o diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index 6df6f6380b55..f9286648e45c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -89,6 +89,11 @@ int otx2_update_sq_stats(struct otx2_nic *pfvf, int qidx) if (!pfvf->qset.sq) return 0; + if (qidx >= pfvf->hw.non_qos_queues) { + if (!test_bit(qidx - pfvf->hw.non_qos_queues, pfvf->qos.qos_sq_bmap)) + return 0; + } + otx2_nix_sq_op_stats(&sq->stats, pfvf, qidx); return 1; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 4ce2009d5247..0f2b2a901225 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -1099,8 +1099,18 @@ static inline void otx2_qos_init(struct otx2_nic *pfvf, int qos_txqs) struct otx2_hw *hw = &pfvf->hw; hw->tc_tx_queues = qos_txqs; + INIT_LIST_HEAD(&pfvf->qos.qos_tree); + mutex_init(&pfvf->qos.qos_lock); +} + +static inline void otx2_shutdown_qos(struct otx2_nic *pfvf) +{ + mutex_destroy(&pfvf->qos.qos_lock); } u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb, struct net_device *sb_dev); +int otx2_get_txq_by_classid(struct otx2_nic *pfvf, u16 classid); +void otx2_qos_config_txschq(struct otx2_nic *pfvf); +void otx2_clean_qos_queues(struct otx2_nic *pfvf); #endif /* OTX2_COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index 0ca99482558c..e1883c3edda3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -1387,6 +1387,9 @@ static void otx2_free_sq_res(struct otx2_nic *pf) otx2_sq_free_sqbs(pf); for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) { sq = &qset->sq[qidx]; + /* Skip freeing Qos queues if they are not initialized */ + if (!sq->sqe) + continue; qmem_free(pf->dev, sq->sqe); qmem_free(pf->dev, sq->tso_hdrs); kfree(sq->sg); @@ -1566,6 +1569,8 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) otx2_pfc_txschq_stop(pf); #endif + otx2_clean_qos_queues(pf); + mutex_lock(&mbox->lock); /* Disable backpressure */ if (!(pf->pcifunc & RVU_PFVF_FUNC_MASK)) @@ -1710,7 +1715,7 @@ int otx2_open(struct net_device *netdev) if (!qset->cq) goto err_free_mem; - qset->sq = kcalloc(pf->hw.non_qos_queues, + qset->sq = kcalloc(otx2_get_total_tx_queues(pf), sizeof(struct otx2_snd_queue), GFP_KERNEL); if (!qset->sq) goto err_free_mem; @@ -1833,6 +1838,9 @@ int otx2_open(struct net_device *netdev) /* 'intf_down' may be checked on any cpu */ smp_wmb(); + /* Enable QoS configuration before starting tx queues */ + otx2_qos_config_txschq(pf); + /* we have already received link status notification */ if (pf->linfo.link_up && !(pf->pcifunc & RVU_PFVF_FUNC_MASK)) otx2_handle_link_event(pf); @@ -1986,14 +1994,48 @@ static netdev_tx_t otx2_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } +static int otx2_qos_select_htb_queue(struct otx2_nic *pf, struct sk_buff *skb, + u16 htb_maj_id) +{ + u16 classid; + + if ((TC_H_MAJ(skb->priority) >> 16) == htb_maj_id) + classid = TC_H_MIN(skb->priority); + else + classid = READ_ONCE(pf->qos.defcls); + + if (!classid) + return 0; + + return otx2_get_txq_by_classid(pf, classid); +} + u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb, struct net_device *sb_dev) { -#ifdef CONFIG_DCB struct otx2_nic *pf = netdev_priv(netdev); + bool qos_enabled; +#ifdef CONFIG_DCB u8 vlan_prio; #endif + int txq; + + qos_enabled = (netdev->real_num_tx_queues > pf->hw.tx_queues) ? true : false; + if (unlikely(qos_enabled)) { + /* This smp_load_acquire() pairs with smp_store_release() in + * otx2_qos_root_add() called from htb offload root creation + */ + u16 htb_maj_id = smp_load_acquire(&pf->qos.maj_id); + if (unlikely(htb_maj_id)) { + txq = otx2_qos_select_htb_queue(pf, skb, htb_maj_id); + if (txq > 0) + return txq; + goto process_pfc; + } + } + +process_pfc: #ifdef CONFIG_DCB if (!skb_vlan_tag_present(skb)) goto pick_tx; @@ -2007,7 +2049,11 @@ u16 otx2_select_queue(struct net_device *netdev, struct sk_buff *skb, pick_tx: #endif - return netdev_pick_tx(netdev, skb, NULL); + txq = netdev_pick_tx(netdev, skb, NULL); + if (unlikely(qos_enabled)) + return txq % pf->hw.tx_queues; + + return txq; } EXPORT_SYMBOL(otx2_select_queue); @@ -3121,6 +3167,7 @@ static void otx2_remove(struct pci_dev *pdev) otx2_ptp_destroy(pf); otx2_mcam_flow_del(pf); otx2_shutdown_tc(pf); + otx2_shutdown_qos(pf); otx2_detach_resources(&pf->mbox); if (pf->hw.lmt_info) free_percpu(pf->hw.lmt_info); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c index 2735cfff8fc1..231c3f0efb60 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -19,6 +19,7 @@ #include "cn10k.h" #include "otx2_common.h" +#include "qos.h" #define CN10K_MAX_BURST_MANTISSA 0x7FFFULL #define CN10K_MAX_BURST_SIZE 8453888ULL @@ -132,8 +133,8 @@ static void otx2_get_egress_rate_cfg(u64 maxrate, u32 *exp, } } -static u64 otx2_get_txschq_rate_regval(struct otx2_nic *nic, - u64 maxrate, u32 burst) +u64 otx2_get_txschq_rate_regval(struct otx2_nic *nic, + u64 maxrate, u32 burst) { u32 burst_exp, burst_mantissa; u32 exp, mantissa, div_exp; @@ -1109,6 +1110,8 @@ int otx2_setup_tc(struct net_device *netdev, enum tc_setup_type type, switch (type) { case TC_SETUP_BLOCK: return otx2_setup_tc_block(netdev, type_data); + case TC_SETUP_QDISC_HTB: + return otx2_setup_tc_htb(netdev, type_data); default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c index 404855bccb4b..3734c799e416 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c @@ -760,6 +760,7 @@ static void otx2vf_remove(struct pci_dev *pdev) otx2_ptp_destroy(vf); otx2_mcam_flow_del(vf); otx2_shutdown_tc(vf); + otx2_shutdown_qos(vf); otx2vf_disable_mbox_intr(vf); otx2_detach_resources(&vf->mbox); free_percpu(vf->hw.lmt_info); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c new file mode 100644 index 000000000000..d3a76c5ccda8 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c @@ -0,0 +1,1363 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell RVU Ethernet driver + * + * Copyright (C) 2023 Marvell. + * + */ +#include +#include +#include +#include + +#include "otx2_common.h" +#include "cn10k.h" +#include "qos.h" + +#define OTX2_QOS_QID_INNER 0xFFFFU +#define OTX2_QOS_QID_NONE 0xFFFEU +#define OTX2_QOS_ROOT_CLASSID 0xFFFFFFFF +#define OTX2_QOS_CLASS_NONE 0 +#define OTX2_QOS_DEFAULT_PRIO 0xF +#define OTX2_QOS_INVALID_SQ 0xFFFF + +static void otx2_qos_update_tx_netdev_queues(struct otx2_nic *pfvf) +{ + struct otx2_hw *hw = &pfvf->hw; + int tx_queues, qos_txqs, err; + + qos_txqs = bitmap_weight(pfvf->qos.qos_sq_bmap, + OTX2_QOS_MAX_LEAF_NODES); + + tx_queues = hw->tx_queues + qos_txqs; + + err = netif_set_real_num_tx_queues(pfvf->netdev, tx_queues); + if (err) { + netdev_err(pfvf->netdev, + "Failed to set no of Tx queues: %d\n", tx_queues); + return; + } +} + +static void otx2_qos_get_regaddr(struct otx2_qos_node *node, + struct nix_txschq_config *cfg, + int index) +{ + if (node->level == NIX_TXSCH_LVL_SMQ) { + cfg->reg[index++] = NIX_AF_MDQX_PARENT(node->schq); + cfg->reg[index++] = NIX_AF_MDQX_SCHEDULE(node->schq); + cfg->reg[index++] = NIX_AF_MDQX_PIR(node->schq); + cfg->reg[index] = NIX_AF_MDQX_CIR(node->schq); + } else if (node->level == NIX_TXSCH_LVL_TL4) { + cfg->reg[index++] = NIX_AF_TL4X_PARENT(node->schq); + cfg->reg[index++] = NIX_AF_TL4X_SCHEDULE(node->schq); + cfg->reg[index++] = NIX_AF_TL4X_PIR(node->schq); + cfg->reg[index] = NIX_AF_TL4X_CIR(node->schq); + } else if (node->level == NIX_TXSCH_LVL_TL3) { + cfg->reg[index++] = NIX_AF_TL3X_PARENT(node->schq); + cfg->reg[index++] = NIX_AF_TL3X_SCHEDULE(node->schq); + cfg->reg[index++] = NIX_AF_TL3X_PIR(node->schq); + cfg->reg[index] = NIX_AF_TL3X_CIR(node->schq); + } else if (node->level == NIX_TXSCH_LVL_TL2) { + cfg->reg[index++] = NIX_AF_TL2X_PARENT(node->schq); + cfg->reg[index++] = NIX_AF_TL2X_SCHEDULE(node->schq); + cfg->reg[index++] = NIX_AF_TL2X_PIR(node->schq); + cfg->reg[index] = NIX_AF_TL2X_CIR(node->schq); + } +} + +static void otx2_config_sched_shaping(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct nix_txschq_config *cfg, + int *num_regs) +{ + u64 maxrate; + + otx2_qos_get_regaddr(node, cfg, *num_regs); + + /* configure parent txschq */ + cfg->regval[*num_regs] = node->parent->schq << 16; + (*num_regs)++; + + /* configure prio/quantum */ + if (node->qid == OTX2_QOS_QID_NONE) { + cfg->regval[*num_regs] = node->prio << 24 | + mtu_to_dwrr_weight(pfvf, pfvf->tx_max_pktlen); + (*num_regs)++; + return; + } + + /* configure priority */ + cfg->regval[*num_regs] = (node->schq - node->parent->prio_anchor) << 24; + (*num_regs)++; + + /* configure PIR */ + maxrate = (node->rate > node->ceil) ? node->rate : node->ceil; + + cfg->regval[*num_regs] = + otx2_get_txschq_rate_regval(pfvf, maxrate, 65536); + (*num_regs)++; + + /* Don't configure CIR when both CIR+PIR not supported + * On 96xx, CIR + PIR + RED_ALGO=STALL causes deadlock + */ + if (!test_bit(QOS_CIR_PIR_SUPPORT, &pfvf->hw.cap_flag)) + return; + + cfg->regval[*num_regs] = + otx2_get_txschq_rate_regval(pfvf, node->rate, 65536); + (*num_regs)++; +} + +static void __otx2_qos_txschq_cfg(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct nix_txschq_config *cfg) +{ + struct otx2_hw *hw = &pfvf->hw; + int num_regs = 0; + u8 level; + + level = node->level; + + /* program txschq registers */ + if (level == NIX_TXSCH_LVL_SMQ) { + cfg->reg[num_regs] = NIX_AF_SMQX_CFG(node->schq); + cfg->regval[num_regs] = ((u64)pfvf->tx_max_pktlen << 8) | + OTX2_MIN_MTU; + cfg->regval[num_regs] |= (0x20ULL << 51) | (0x80ULL << 39) | + (0x2ULL << 36); + num_regs++; + + otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); + + } else if (level == NIX_TXSCH_LVL_TL4) { + otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); + } else if (level == NIX_TXSCH_LVL_TL3) { + /* configure link cfg */ + if (level == pfvf->qos.link_cfg_lvl) { + cfg->reg[num_regs] = NIX_AF_TL3_TL2X_LINKX_CFG(node->schq, hw->tx_link); + cfg->regval[num_regs] = BIT_ULL(13) | BIT_ULL(12); + num_regs++; + } + + otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); + } else if (level == NIX_TXSCH_LVL_TL2) { + /* configure link cfg */ + if (level == pfvf->qos.link_cfg_lvl) { + cfg->reg[num_regs] = NIX_AF_TL3_TL2X_LINKX_CFG(node->schq, hw->tx_link); + cfg->regval[num_regs] = BIT_ULL(13) | BIT_ULL(12); + num_regs++; + } + + /* check if node is root */ + if (node->qid == OTX2_QOS_QID_INNER && !node->parent) { + cfg->reg[num_regs] = NIX_AF_TL2X_SCHEDULE(node->schq); + cfg->regval[num_regs] = TXSCH_TL1_DFLT_RR_PRIO << 24 | + mtu_to_dwrr_weight(pfvf, + pfvf->tx_max_pktlen); + num_regs++; + goto txschq_cfg_out; + } + + otx2_config_sched_shaping(pfvf, node, cfg, &num_regs); + } + +txschq_cfg_out: + cfg->num_regs = num_regs; +} + +static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf, + struct otx2_qos_node *parent) +{ + struct mbox *mbox = &pfvf->mbox; + struct nix_txschq_config *cfg; + int rc; + + if (parent->level == NIX_TXSCH_LVL_MDQ) + return 0; + + mutex_lock(&mbox->lock); + + cfg = otx2_mbox_alloc_msg_nix_txschq_cfg(&pfvf->mbox); + if (!cfg) { + mutex_unlock(&mbox->lock); + return -ENOMEM; + } + + cfg->lvl = parent->level; + + if (parent->level == NIX_TXSCH_LVL_TL4) + cfg->reg[0] = NIX_AF_TL4X_TOPOLOGY(parent->schq); + else if (parent->level == NIX_TXSCH_LVL_TL3) + cfg->reg[0] = NIX_AF_TL3X_TOPOLOGY(parent->schq); + else if (parent->level == NIX_TXSCH_LVL_TL2) + cfg->reg[0] = NIX_AF_TL2X_TOPOLOGY(parent->schq); + else if (parent->level == NIX_TXSCH_LVL_TL1) + cfg->reg[0] = NIX_AF_TL1X_TOPOLOGY(parent->schq); + + cfg->regval[0] = (u64)parent->prio_anchor << 32; + if (parent->level == NIX_TXSCH_LVL_TL1) + cfg->regval[0] |= (u64)TXSCH_TL1_DFLT_RR_PRIO << 1; + + cfg->num_regs++; + + rc = otx2_sync_mbox_msg(&pfvf->mbox); + + mutex_unlock(&mbox->lock); + + return rc; +} + +static void otx2_qos_free_hw_node_schq(struct otx2_nic *pfvf, + struct otx2_qos_node *parent) +{ + struct otx2_qos_node *node; + + list_for_each_entry_reverse(node, &parent->child_schq_list, list) + otx2_txschq_free_one(pfvf, node->level, node->schq); +} + +static void otx2_qos_free_hw_node(struct otx2_nic *pfvf, + struct otx2_qos_node *parent) +{ + struct otx2_qos_node *node, *tmp; + + list_for_each_entry_safe(node, tmp, &parent->child_list, list) { + otx2_qos_free_hw_node(pfvf, node); + otx2_qos_free_hw_node_schq(pfvf, node); + otx2_txschq_free_one(pfvf, node->level, node->schq); + } +} + +static void otx2_qos_free_hw_cfg(struct otx2_nic *pfvf, + struct otx2_qos_node *node) +{ + mutex_lock(&pfvf->qos.qos_lock); + + /* free child node hw mappings */ + otx2_qos_free_hw_node(pfvf, node); + otx2_qos_free_hw_node_schq(pfvf, node); + + /* free node hw mappings */ + otx2_txschq_free_one(pfvf, node->level, node->schq); + + mutex_unlock(&pfvf->qos.qos_lock); +} + +static void otx2_qos_sw_node_delete(struct otx2_nic *pfvf, + struct otx2_qos_node *node) +{ + hash_del_rcu(&node->hlist); + + if (node->qid != OTX2_QOS_QID_INNER && node->qid != OTX2_QOS_QID_NONE) { + __clear_bit(node->qid, pfvf->qos.qos_sq_bmap); + otx2_qos_update_tx_netdev_queues(pfvf); + } + + list_del(&node->list); + kfree(node); +} + +static void otx2_qos_free_sw_node_schq(struct otx2_nic *pfvf, + struct otx2_qos_node *parent) +{ + struct otx2_qos_node *node, *tmp; + + list_for_each_entry_safe(node, tmp, &parent->child_schq_list, list) { + list_del(&node->list); + kfree(node); + } +} + +static void __otx2_qos_free_sw_node(struct otx2_nic *pfvf, + struct otx2_qos_node *parent) +{ + struct otx2_qos_node *node, *tmp; + + list_for_each_entry_safe(node, tmp, &parent->child_list, list) { + __otx2_qos_free_sw_node(pfvf, node); + otx2_qos_free_sw_node_schq(pfvf, node); + otx2_qos_sw_node_delete(pfvf, node); + } +} + +static void otx2_qos_free_sw_node(struct otx2_nic *pfvf, + struct otx2_qos_node *node) +{ + mutex_lock(&pfvf->qos.qos_lock); + + __otx2_qos_free_sw_node(pfvf, node); + otx2_qos_free_sw_node_schq(pfvf, node); + otx2_qos_sw_node_delete(pfvf, node); + + mutex_unlock(&pfvf->qos.qos_lock); +} + +static void otx2_qos_destroy_node(struct otx2_nic *pfvf, + struct otx2_qos_node *node) +{ + otx2_qos_free_hw_cfg(pfvf, node); + otx2_qos_free_sw_node(pfvf, node); +} + +static void otx2_qos_fill_cfg_schq(struct otx2_qos_node *parent, + struct otx2_qos_cfg *cfg) +{ + struct otx2_qos_node *node; + + list_for_each_entry(node, &parent->child_schq_list, list) + cfg->schq[node->level]++; +} + +static void otx2_qos_fill_cfg_tl(struct otx2_qos_node *parent, + struct otx2_qos_cfg *cfg) +{ + struct otx2_qos_node *node; + + list_for_each_entry(node, &parent->child_list, list) { + otx2_qos_fill_cfg_tl(node, cfg); + cfg->schq_contig[node->level]++; + otx2_qos_fill_cfg_schq(node, cfg); + } +} + +static void otx2_qos_prepare_txschq_cfg(struct otx2_nic *pfvf, + struct otx2_qos_node *parent, + struct otx2_qos_cfg *cfg) +{ + mutex_lock(&pfvf->qos.qos_lock); + otx2_qos_fill_cfg_tl(parent, cfg); + mutex_unlock(&pfvf->qos.qos_lock); +} + +static void otx2_qos_read_txschq_cfg_schq(struct otx2_qos_node *parent, + struct otx2_qos_cfg *cfg) +{ + struct otx2_qos_node *node; + int cnt; + + list_for_each_entry(node, &parent->child_schq_list, list) { + cnt = cfg->dwrr_node_pos[node->level]; + cfg->schq_list[node->level][cnt] = node->schq; + cfg->schq[node->level]++; + cfg->dwrr_node_pos[node->level]++; + } +} + +static void otx2_qos_read_txschq_cfg_tl(struct otx2_qos_node *parent, + struct otx2_qos_cfg *cfg) +{ + struct otx2_qos_node *node; + int cnt; + + list_for_each_entry(node, &parent->child_list, list) { + otx2_qos_read_txschq_cfg_tl(node, cfg); + cnt = cfg->static_node_pos[node->level]; + cfg->schq_contig_list[node->level][cnt] = node->schq; + cfg->schq_contig[node->level]++; + cfg->static_node_pos[node->level]++; + otx2_qos_read_txschq_cfg_schq(node, cfg); + } +} + +static void otx2_qos_read_txschq_cfg(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + mutex_lock(&pfvf->qos.qos_lock); + otx2_qos_read_txschq_cfg_tl(node, cfg); + mutex_unlock(&pfvf->qos.qos_lock); +} + +static struct otx2_qos_node * +otx2_qos_alloc_root(struct otx2_nic *pfvf) +{ + struct otx2_qos_node *node; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return ERR_PTR(-ENOMEM); + + node->parent = NULL; + if (!is_otx2_vf(pfvf->pcifunc)) + node->level = NIX_TXSCH_LVL_TL1; + else + node->level = NIX_TXSCH_LVL_TL2; + + WRITE_ONCE(node->qid, OTX2_QOS_QID_INNER); + node->classid = OTX2_QOS_ROOT_CLASSID; + + hash_add_rcu(pfvf->qos.qos_hlist, &node->hlist, node->classid); + list_add_tail(&node->list, &pfvf->qos.qos_tree); + INIT_LIST_HEAD(&node->child_list); + INIT_LIST_HEAD(&node->child_schq_list); + + return node; +} + +static int otx2_qos_add_child_node(struct otx2_qos_node *parent, + struct otx2_qos_node *node) +{ + struct list_head *head = &parent->child_list; + struct otx2_qos_node *tmp_node; + struct list_head *tmp; + + for (tmp = head->next; tmp != head; tmp = tmp->next) { + tmp_node = list_entry(tmp, struct otx2_qos_node, list); + if (tmp_node->prio == node->prio) + return -EEXIST; + if (tmp_node->prio > node->prio) { + list_add_tail(&node->list, tmp); + return 0; + } + } + + list_add_tail(&node->list, head); + return 0; +} + +static int otx2_qos_alloc_txschq_node(struct otx2_nic *pfvf, + struct otx2_qos_node *node) +{ + struct otx2_qos_node *txschq_node, *parent, *tmp; + int lvl; + + parent = node; + for (lvl = node->level - 1; lvl >= NIX_TXSCH_LVL_MDQ; lvl--) { + txschq_node = kzalloc(sizeof(*txschq_node), GFP_KERNEL); + if (!txschq_node) + goto err_out; + + txschq_node->parent = parent; + txschq_node->level = lvl; + txschq_node->classid = OTX2_QOS_CLASS_NONE; + WRITE_ONCE(txschq_node->qid, OTX2_QOS_QID_NONE); + txschq_node->rate = 0; + txschq_node->ceil = 0; + txschq_node->prio = 0; + + mutex_lock(&pfvf->qos.qos_lock); + list_add_tail(&txschq_node->list, &node->child_schq_list); + mutex_unlock(&pfvf->qos.qos_lock); + + INIT_LIST_HEAD(&txschq_node->child_list); + INIT_LIST_HEAD(&txschq_node->child_schq_list); + parent = txschq_node; + } + + return 0; + +err_out: + list_for_each_entry_safe(txschq_node, tmp, &node->child_schq_list, + list) { + list_del(&txschq_node->list); + kfree(txschq_node); + } + return -ENOMEM; +} + +static struct otx2_qos_node * +otx2_qos_sw_create_leaf_node(struct otx2_nic *pfvf, + struct otx2_qos_node *parent, + u16 classid, u32 prio, u64 rate, u64 ceil, + u16 qid) +{ + struct otx2_qos_node *node; + int err; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return ERR_PTR(-ENOMEM); + + node->parent = parent; + node->level = parent->level - 1; + node->classid = classid; + WRITE_ONCE(node->qid, qid); + + node->rate = otx2_convert_rate(rate); + node->ceil = otx2_convert_rate(ceil); + node->prio = prio; + + __set_bit(qid, pfvf->qos.qos_sq_bmap); + + hash_add_rcu(pfvf->qos.qos_hlist, &node->hlist, classid); + + mutex_lock(&pfvf->qos.qos_lock); + err = otx2_qos_add_child_node(parent, node); + if (err) { + mutex_unlock(&pfvf->qos.qos_lock); + return ERR_PTR(err); + } + mutex_unlock(&pfvf->qos.qos_lock); + + INIT_LIST_HEAD(&node->child_list); + INIT_LIST_HEAD(&node->child_schq_list); + + err = otx2_qos_alloc_txschq_node(pfvf, node); + if (err) { + otx2_qos_sw_node_delete(pfvf, node); + return ERR_PTR(-ENOMEM); + } + + return node; +} + +static struct otx2_qos_node * +otx2_sw_node_find(struct otx2_nic *pfvf, u32 classid) +{ + struct otx2_qos_node *node = NULL; + + hash_for_each_possible(pfvf->qos.qos_hlist, node, hlist, classid) { + if (node->classid == classid) + break; + } + + return node; +} + +static struct otx2_qos_node * +otx2_sw_node_find_rcu(struct otx2_nic *pfvf, u32 classid) +{ + struct otx2_qos_node *node = NULL; + + hash_for_each_possible_rcu(pfvf->qos.qos_hlist, node, hlist, classid) { + if (node->classid == classid) + break; + } + + return node; +} + +int otx2_get_txq_by_classid(struct otx2_nic *pfvf, u16 classid) +{ + struct otx2_qos_node *node; + u16 qid; + int res; + + node = otx2_sw_node_find_rcu(pfvf, classid); + if (!node) { + res = -ENOENT; + goto out; + } + qid = READ_ONCE(node->qid); + if (qid == OTX2_QOS_QID_INNER) { + res = -EINVAL; + goto out; + } + res = pfvf->hw.tx_queues + qid; +out: + return res; +} + +static int +otx2_qos_txschq_config(struct otx2_nic *pfvf, struct otx2_qos_node *node) +{ + struct mbox *mbox = &pfvf->mbox; + struct nix_txschq_config *req; + int rc; + + mutex_lock(&mbox->lock); + + req = otx2_mbox_alloc_msg_nix_txschq_cfg(&pfvf->mbox); + if (!req) { + mutex_unlock(&mbox->lock); + return -ENOMEM; + } + + req->lvl = node->level; + __otx2_qos_txschq_cfg(pfvf, node, req); + + rc = otx2_sync_mbox_msg(&pfvf->mbox); + + mutex_unlock(&mbox->lock); + + return rc; +} + +static int otx2_qos_txschq_alloc(struct otx2_nic *pfvf, + struct otx2_qos_cfg *cfg) +{ + struct nix_txsch_alloc_req *req; + struct nix_txsch_alloc_rsp *rsp; + struct mbox *mbox = &pfvf->mbox; + int lvl, rc, schq; + + mutex_lock(&mbox->lock); + req = otx2_mbox_alloc_msg_nix_txsch_alloc(&pfvf->mbox); + if (!req) { + mutex_unlock(&mbox->lock); + return -ENOMEM; + } + + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + req->schq[lvl] = cfg->schq[lvl]; + req->schq_contig[lvl] = cfg->schq_contig[lvl]; + } + + rc = otx2_sync_mbox_msg(&pfvf->mbox); + if (rc) { + mutex_unlock(&mbox->lock); + return rc; + } + + rsp = (struct nix_txsch_alloc_rsp *) + otx2_mbox_get_rsp(&pfvf->mbox.mbox, 0, &req->hdr); + + if (IS_ERR(rsp)) { + rc = PTR_ERR(rsp); + goto out; + } + + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + for (schq = 0; schq < rsp->schq_contig[lvl]; schq++) { + cfg->schq_contig_list[lvl][schq] = + rsp->schq_contig_list[lvl][schq]; + } + } + + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + for (schq = 0; schq < rsp->schq[lvl]; schq++) { + cfg->schq_list[lvl][schq] = + rsp->schq_list[lvl][schq]; + } + } + + pfvf->qos.link_cfg_lvl = rsp->link_cfg_lvl; + +out: + mutex_unlock(&mbox->lock); + return rc; +} + +static void otx2_qos_txschq_fill_cfg_schq(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + struct otx2_qos_node *tmp; + int cnt; + + list_for_each_entry(tmp, &node->child_schq_list, list) { + cnt = cfg->dwrr_node_pos[tmp->level]; + tmp->schq = cfg->schq_list[tmp->level][cnt]; + cfg->dwrr_node_pos[tmp->level]++; + } +} + +static void otx2_qos_txschq_fill_cfg_tl(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + struct otx2_qos_node *tmp; + int cnt; + + list_for_each_entry(tmp, &node->child_list, list) { + otx2_qos_txschq_fill_cfg_tl(pfvf, tmp, cfg); + cnt = cfg->static_node_pos[tmp->level]; + tmp->schq = cfg->schq_contig_list[tmp->level][cnt]; + if (cnt == 0) + node->prio_anchor = tmp->schq; + cfg->static_node_pos[tmp->level]++; + otx2_qos_txschq_fill_cfg_schq(pfvf, tmp, cfg); + } +} + +static void otx2_qos_txschq_fill_cfg(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + mutex_lock(&pfvf->qos.qos_lock); + otx2_qos_txschq_fill_cfg_tl(pfvf, node, cfg); + otx2_qos_txschq_fill_cfg_schq(pfvf, node, cfg); + mutex_unlock(&pfvf->qos.qos_lock); +} + +static int otx2_qos_txschq_push_cfg_schq(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + struct otx2_qos_node *tmp; + int ret; + + list_for_each_entry(tmp, &node->child_schq_list, list) { + ret = otx2_qos_txschq_config(pfvf, tmp); + if (ret) + return -EIO; + ret = otx2_qos_txschq_set_parent_topology(pfvf, tmp->parent); + if (ret) + return -EIO; + } + + return 0; +} + +static int otx2_qos_txschq_push_cfg_tl(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + struct otx2_qos_node *tmp; + int ret; + + list_for_each_entry(tmp, &node->child_list, list) { + ret = otx2_qos_txschq_push_cfg_tl(pfvf, tmp, cfg); + if (ret) + return -EIO; + ret = otx2_qos_txschq_config(pfvf, tmp); + if (ret) + return -EIO; + ret = otx2_qos_txschq_push_cfg_schq(pfvf, tmp, cfg); + if (ret) + return -EIO; + } + + ret = otx2_qos_txschq_set_parent_topology(pfvf, node); + if (ret) + return -EIO; + + return 0; +} + +static int otx2_qos_txschq_push_cfg(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + int ret; + + mutex_lock(&pfvf->qos.qos_lock); + ret = otx2_qos_txschq_push_cfg_tl(pfvf, node, cfg); + if (ret) + goto out; + ret = otx2_qos_txschq_push_cfg_schq(pfvf, node, cfg); +out: + mutex_unlock(&pfvf->qos.qos_lock); + return ret; +} + +static int otx2_qos_txschq_update_config(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + otx2_qos_txschq_fill_cfg(pfvf, node, cfg); + + return otx2_qos_txschq_push_cfg(pfvf, node, cfg); +} + +static int otx2_qos_txschq_update_root_cfg(struct otx2_nic *pfvf, + struct otx2_qos_node *root, + struct otx2_qos_cfg *cfg) +{ + root->schq = cfg->schq_list[root->level][0]; + return otx2_qos_txschq_config(pfvf, root); +} + +static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg) +{ + int lvl, idx, schq; + + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + for (idx = 0; idx < cfg->schq[lvl]; idx++) { + schq = cfg->schq_list[lvl][idx]; + otx2_txschq_free_one(pfvf, lvl, schq); + } + } + + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + for (idx = 0; idx < cfg->schq_contig[lvl]; idx++) { + schq = cfg->schq_contig_list[lvl][idx]; + otx2_txschq_free_one(pfvf, lvl, schq); + } + } +} + +static void otx2_qos_enadis_sq(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + u16 qid) +{ + if (pfvf->qos.qid_to_sqmap[qid] != OTX2_QOS_INVALID_SQ) + otx2_qos_disable_sq(pfvf, qid); + + pfvf->qos.qid_to_sqmap[qid] = node->schq; + otx2_qos_enable_sq(pfvf, qid); +} + +static void otx2_qos_update_smq_schq(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + bool action) +{ + struct otx2_qos_node *tmp; + + if (node->qid == OTX2_QOS_QID_INNER) + return; + + list_for_each_entry(tmp, &node->child_schq_list, list) { + if (tmp->level == NIX_TXSCH_LVL_MDQ) { + if (action == QOS_SMQ_FLUSH) + otx2_smq_flush(pfvf, tmp->schq); + else + otx2_qos_enadis_sq(pfvf, tmp, node->qid); + } + } +} + +static void __otx2_qos_update_smq(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + bool action) +{ + struct otx2_qos_node *tmp; + + list_for_each_entry(tmp, &node->child_list, list) { + __otx2_qos_update_smq(pfvf, tmp, action); + if (tmp->qid == OTX2_QOS_QID_INNER) + continue; + if (tmp->level == NIX_TXSCH_LVL_MDQ) { + if (action == QOS_SMQ_FLUSH) + otx2_smq_flush(pfvf, tmp->schq); + else + otx2_qos_enadis_sq(pfvf, tmp, tmp->qid); + } else { + otx2_qos_update_smq_schq(pfvf, tmp, action); + } + } +} + +static void otx2_qos_update_smq(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + bool action) +{ + mutex_lock(&pfvf->qos.qos_lock); + __otx2_qos_update_smq(pfvf, node, action); + otx2_qos_update_smq_schq(pfvf, node, action); + mutex_unlock(&pfvf->qos.qos_lock); +} + +static int otx2_qos_push_txschq_cfg(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + int ret; + + ret = otx2_qos_txschq_alloc(pfvf, cfg); + if (ret) + return -ENOSPC; + + if (!(pfvf->netdev->flags & IFF_UP)) { + otx2_qos_txschq_fill_cfg(pfvf, node, cfg); + return 0; + } + + ret = otx2_qos_txschq_update_config(pfvf, node, cfg); + if (ret) { + otx2_qos_free_cfg(pfvf, cfg); + return -EIO; + } + + otx2_qos_update_smq(pfvf, node, QOS_CFG_SQ); + + return 0; +} + +static int otx2_qos_update_tree(struct otx2_nic *pfvf, + struct otx2_qos_node *node, + struct otx2_qos_cfg *cfg) +{ + otx2_qos_prepare_txschq_cfg(pfvf, node->parent, cfg); + return otx2_qos_push_txschq_cfg(pfvf, node->parent, cfg); +} + +static int otx2_qos_root_add(struct otx2_nic *pfvf, u16 htb_maj_id, u16 htb_defcls, + struct netlink_ext_ack *extack) +{ + struct otx2_qos_cfg *new_cfg; + struct otx2_qos_node *root; + int err; + + netdev_dbg(pfvf->netdev, + "TC_HTB_CREATE: handle=0x%x defcls=0x%x\n", + htb_maj_id, htb_defcls); + + root = otx2_qos_alloc_root(pfvf); + if (IS_ERR(root)) { + err = PTR_ERR(root); + return err; + } + + /* allocate txschq queue */ + new_cfg = kzalloc(sizeof(*new_cfg), GFP_KERNEL); + if (!new_cfg) { + NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); + err = -ENOMEM; + goto free_root_node; + } + /* allocate htb root node */ + new_cfg->schq[root->level] = 1; + err = otx2_qos_txschq_alloc(pfvf, new_cfg); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Error allocating txschq"); + goto free_root_node; + } + + if (!(pfvf->netdev->flags & IFF_UP) || + root->level == NIX_TXSCH_LVL_TL1) { + root->schq = new_cfg->schq_list[root->level][0]; + goto out; + } + + /* update the txschq configuration in hw */ + err = otx2_qos_txschq_update_root_cfg(pfvf, root, new_cfg); + if (err) { + NL_SET_ERR_MSG_MOD(extack, + "Error updating txschq configuration"); + goto txschq_free; + } + +out: + WRITE_ONCE(pfvf->qos.defcls, htb_defcls); + /* Pairs with smp_load_acquire() in ndo_select_queue */ + smp_store_release(&pfvf->qos.maj_id, htb_maj_id); + kfree(new_cfg); + return 0; + +txschq_free: + otx2_qos_free_cfg(pfvf, new_cfg); +free_root_node: + kfree(new_cfg); + otx2_qos_sw_node_delete(pfvf, root); + return err; +} + +static int otx2_qos_root_destroy(struct otx2_nic *pfvf) +{ + struct otx2_qos_node *root; + + netdev_dbg(pfvf->netdev, "TC_HTB_DESTROY\n"); + + /* find root node */ + root = otx2_sw_node_find(pfvf, OTX2_QOS_ROOT_CLASSID); + if (!root) + return -ENOENT; + + /* free the hw mappings */ + otx2_qos_destroy_node(pfvf, root); + + return 0; +} + +static int otx2_qos_validate_configuration(struct otx2_qos_node *parent, + struct netlink_ext_ack *extack, + struct otx2_nic *pfvf, + u64 prio) +{ + if (test_bit(prio, parent->prio_bmap)) { + NL_SET_ERR_MSG_MOD(extack, + "Static priority child with same priority exists"); + return -EEXIST; + } + + if (prio == TXSCH_TL1_DFLT_RR_PRIO) { + NL_SET_ERR_MSG_MOD(extack, + "Priority is reserved for Round Robin"); + return -EINVAL; + } + + return 0; +} + +static int otx2_qos_leaf_alloc_queue(struct otx2_nic *pfvf, u16 classid, + u32 parent_classid, u64 rate, u64 ceil, + u64 prio, struct netlink_ext_ack *extack) +{ + struct otx2_qos_cfg *old_cfg, *new_cfg; + struct otx2_qos_node *node, *parent; + int qid, ret, err; + + netdev_dbg(pfvf->netdev, + "TC_HTB_LEAF_ALLOC_QUEUE: classid=0x%x parent_classid=0x%x rate=%lld ceil=%lld prio=%lld\n", + classid, parent_classid, rate, ceil, prio); + + if (prio > OTX2_QOS_MAX_PRIO) { + NL_SET_ERR_MSG_MOD(extack, "Valid priority range 0 to 7"); + ret = -EOPNOTSUPP; + goto out; + } + + /* get parent node */ + parent = otx2_sw_node_find(pfvf, parent_classid); + if (!parent) { + NL_SET_ERR_MSG_MOD(extack, "parent node not found"); + ret = -ENOENT; + goto out; + } + if (parent->level == NIX_TXSCH_LVL_MDQ) { + NL_SET_ERR_MSG_MOD(extack, "HTB qos max levels reached"); + ret = -EOPNOTSUPP; + goto out; + } + + ret = otx2_qos_validate_configuration(parent, extack, pfvf, prio); + if (ret) + goto out; + + set_bit(prio, parent->prio_bmap); + + /* read current txschq configuration */ + old_cfg = kzalloc(sizeof(*old_cfg), GFP_KERNEL); + if (!old_cfg) { + NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); + ret = -ENOMEM; + goto reset_prio; + } + otx2_qos_read_txschq_cfg(pfvf, parent, old_cfg); + + /* allocate a new sq */ + qid = otx2_qos_get_qid(pfvf); + if (qid < 0) { + NL_SET_ERR_MSG_MOD(extack, "Reached max supported QOS SQ's"); + ret = -ENOMEM; + goto free_old_cfg; + } + + /* Actual SQ mapping will be updated after SMQ alloc */ + pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; + + /* allocate and initialize a new child node */ + node = otx2_qos_sw_create_leaf_node(pfvf, parent, classid, prio, rate, + ceil, qid); + if (IS_ERR(node)) { + NL_SET_ERR_MSG_MOD(extack, "Unable to allocate leaf node"); + ret = PTR_ERR(node); + goto free_old_cfg; + } + + /* push new txschq config to hw */ + new_cfg = kzalloc(sizeof(*new_cfg), GFP_KERNEL); + if (!new_cfg) { + NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); + ret = -ENOMEM; + goto free_node; + } + ret = otx2_qos_update_tree(pfvf, node, new_cfg); + if (ret) { + NL_SET_ERR_MSG_MOD(extack, "HTB HW configuration error"); + kfree(new_cfg); + otx2_qos_sw_node_delete(pfvf, node); + /* restore the old qos tree */ + err = otx2_qos_txschq_update_config(pfvf, parent, old_cfg); + if (err) { + netdev_err(pfvf->netdev, + "Failed to restore txcshq configuration"); + goto free_old_cfg; + } + + otx2_qos_update_smq(pfvf, parent, QOS_CFG_SQ); + goto free_old_cfg; + } + + /* update tx_real_queues */ + otx2_qos_update_tx_netdev_queues(pfvf); + + /* free new txschq config */ + kfree(new_cfg); + + /* free old txschq config */ + otx2_qos_free_cfg(pfvf, old_cfg); + kfree(old_cfg); + + return pfvf->hw.tx_queues + qid; + +free_node: + otx2_qos_sw_node_delete(pfvf, node); +free_old_cfg: + kfree(old_cfg); +reset_prio: + clear_bit(prio, parent->prio_bmap); +out: + return ret; +} + +static int otx2_qos_leaf_to_inner(struct otx2_nic *pfvf, u16 classid, + u16 child_classid, u64 rate, u64 ceil, u64 prio, + struct netlink_ext_ack *extack) +{ + struct otx2_qos_cfg *old_cfg, *new_cfg; + struct otx2_qos_node *node, *child; + int ret, err; + u16 qid; + + netdev_dbg(pfvf->netdev, + "TC_HTB_LEAF_TO_INNER classid %04x, child %04x, rate %llu, ceil %llu\n", + classid, child_classid, rate, ceil); + + if (prio > OTX2_QOS_MAX_PRIO) { + NL_SET_ERR_MSG_MOD(extack, "Valid priority range 0 to 7"); + ret = -EOPNOTSUPP; + goto out; + } + + /* find node related to classid */ + node = otx2_sw_node_find(pfvf, classid); + if (!node) { + NL_SET_ERR_MSG_MOD(extack, "HTB node not found"); + ret = -ENOENT; + goto out; + } + /* check max qos txschq level */ + if (node->level == NIX_TXSCH_LVL_MDQ) { + NL_SET_ERR_MSG_MOD(extack, "HTB qos level not supported"); + ret = -EOPNOTSUPP; + goto out; + } + + set_bit(prio, node->prio_bmap); + + /* store the qid to assign to leaf node */ + qid = node->qid; + + /* read current txschq configuration */ + old_cfg = kzalloc(sizeof(*old_cfg), GFP_KERNEL); + if (!old_cfg) { + NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); + ret = -ENOMEM; + goto reset_prio; + } + otx2_qos_read_txschq_cfg(pfvf, node, old_cfg); + + /* delete the txschq nodes allocated for this node */ + otx2_qos_free_sw_node_schq(pfvf, node); + + /* mark this node as htb inner node */ + WRITE_ONCE(node->qid, OTX2_QOS_QID_INNER); + + /* allocate and initialize a new child node */ + child = otx2_qos_sw_create_leaf_node(pfvf, node, child_classid, + prio, rate, ceil, qid); + if (IS_ERR(child)) { + NL_SET_ERR_MSG_MOD(extack, "Unable to allocate leaf node"); + ret = PTR_ERR(child); + goto free_old_cfg; + } + + /* push new txschq config to hw */ + new_cfg = kzalloc(sizeof(*new_cfg), GFP_KERNEL); + if (!new_cfg) { + NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); + ret = -ENOMEM; + goto free_node; + } + ret = otx2_qos_update_tree(pfvf, child, new_cfg); + if (ret) { + NL_SET_ERR_MSG_MOD(extack, "HTB HW configuration error"); + kfree(new_cfg); + otx2_qos_sw_node_delete(pfvf, child); + /* restore the old qos tree */ + WRITE_ONCE(node->qid, qid); + err = otx2_qos_alloc_txschq_node(pfvf, node); + if (err) { + netdev_err(pfvf->netdev, + "Failed to restore old leaf node"); + goto free_old_cfg; + } + err = otx2_qos_txschq_update_config(pfvf, node, old_cfg); + if (err) { + netdev_err(pfvf->netdev, + "Failed to restore txcshq configuration"); + goto free_old_cfg; + } + otx2_qos_update_smq(pfvf, node, QOS_CFG_SQ); + goto free_old_cfg; + } + + /* free new txschq config */ + kfree(new_cfg); + + /* free old txschq config */ + otx2_qos_free_cfg(pfvf, old_cfg); + kfree(old_cfg); + + return 0; + +free_node: + otx2_qos_sw_node_delete(pfvf, child); +free_old_cfg: + kfree(old_cfg); +reset_prio: + clear_bit(prio, node->prio_bmap); +out: + return ret; +} + +static int otx2_qos_leaf_del(struct otx2_nic *pfvf, u16 *classid, + struct netlink_ext_ack *extack) +{ + struct otx2_qos_node *node, *parent; + u64 prio; + u16 qid; + + netdev_dbg(pfvf->netdev, "TC_HTB_LEAF_DEL classid %04x\n", *classid); + + /* find node related to classid */ + node = otx2_sw_node_find(pfvf, *classid); + if (!node) { + NL_SET_ERR_MSG_MOD(extack, "HTB node not found"); + return -ENOENT; + } + parent = node->parent; + prio = node->prio; + qid = node->qid; + + otx2_qos_disable_sq(pfvf, node->qid); + + otx2_qos_destroy_node(pfvf, node); + pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; + + clear_bit(prio, parent->prio_bmap); + + return 0; +} + +static int otx2_qos_leaf_del_last(struct otx2_nic *pfvf, u16 classid, bool force, + struct netlink_ext_ack *extack) +{ + struct otx2_qos_node *node, *parent; + struct otx2_qos_cfg *new_cfg; + u64 prio; + int err; + u16 qid; + + netdev_dbg(pfvf->netdev, + "TC_HTB_LEAF_DEL_LAST classid %04x\n", classid); + + /* find node related to classid */ + node = otx2_sw_node_find(pfvf, classid); + if (!node) { + NL_SET_ERR_MSG_MOD(extack, "HTB node not found"); + return -ENOENT; + } + + /* save qid for use by parent */ + qid = node->qid; + prio = node->prio; + + parent = otx2_sw_node_find(pfvf, node->parent->classid); + if (!parent) { + NL_SET_ERR_MSG_MOD(extack, "parent node not found"); + return -ENOENT; + } + + /* destroy the leaf node */ + otx2_qos_destroy_node(pfvf, node); + pfvf->qos.qid_to_sqmap[qid] = OTX2_QOS_INVALID_SQ; + + clear_bit(prio, parent->prio_bmap); + + /* create downstream txschq entries to parent */ + err = otx2_qos_alloc_txschq_node(pfvf, parent); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "HTB failed to create txsch configuration"); + return err; + } + WRITE_ONCE(parent->qid, qid); + __set_bit(qid, pfvf->qos.qos_sq_bmap); + + /* push new txschq config to hw */ + new_cfg = kzalloc(sizeof(*new_cfg), GFP_KERNEL); + if (!new_cfg) { + NL_SET_ERR_MSG_MOD(extack, "Memory allocation error"); + return -ENOMEM; + } + /* fill txschq cfg and push txschq cfg to hw */ + otx2_qos_fill_cfg_schq(parent, new_cfg); + err = otx2_qos_push_txschq_cfg(pfvf, parent, new_cfg); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "HTB HW configuration error"); + kfree(new_cfg); + return err; + } + kfree(new_cfg); + + /* update tx_real_queues */ + otx2_qos_update_tx_netdev_queues(pfvf); + + return 0; +} + +void otx2_clean_qos_queues(struct otx2_nic *pfvf) +{ + struct otx2_qos_node *root; + + root = otx2_sw_node_find(pfvf, OTX2_QOS_ROOT_CLASSID); + if (!root) + return; + + otx2_qos_update_smq(pfvf, root, QOS_SMQ_FLUSH); +} + +void otx2_qos_config_txschq(struct otx2_nic *pfvf) +{ + struct otx2_qos_node *root; + int err; + + root = otx2_sw_node_find(pfvf, OTX2_QOS_ROOT_CLASSID); + if (!root) + return; + + err = otx2_qos_txschq_config(pfvf, root); + if (err) { + netdev_err(pfvf->netdev, "Error update txschq configuration\n"); + goto root_destroy; + } + + err = otx2_qos_txschq_push_cfg_tl(pfvf, root, NULL); + if (err) { + netdev_err(pfvf->netdev, "Error update txschq configuration\n"); + goto root_destroy; + } + + otx2_qos_update_smq(pfvf, root, QOS_CFG_SQ); + return; + +root_destroy: + netdev_err(pfvf->netdev, "Failed to update Scheduler/Shaping config in Hardware\n"); + /* Free resources allocated */ + otx2_qos_root_destroy(pfvf); +} + +int otx2_setup_tc_htb(struct net_device *ndev, struct tc_htb_qopt_offload *htb) +{ + struct otx2_nic *pfvf = netdev_priv(ndev); + int res; + + switch (htb->command) { + case TC_HTB_CREATE: + return otx2_qos_root_add(pfvf, htb->parent_classid, + htb->classid, htb->extack); + case TC_HTB_DESTROY: + return otx2_qos_root_destroy(pfvf); + case TC_HTB_LEAF_ALLOC_QUEUE: + res = otx2_qos_leaf_alloc_queue(pfvf, htb->classid, + htb->parent_classid, + htb->rate, htb->ceil, + htb->prio, htb->extack); + if (res < 0) + return res; + htb->qid = res; + return 0; + case TC_HTB_LEAF_TO_INNER: + return otx2_qos_leaf_to_inner(pfvf, htb->parent_classid, + htb->classid, htb->rate, + htb->ceil, htb->prio, + htb->extack); + case TC_HTB_LEAF_DEL: + return otx2_qos_leaf_del(pfvf, &htb->classid, htb->extack); + case TC_HTB_LEAF_DEL_LAST: + case TC_HTB_LEAF_DEL_LAST_FORCE: + return otx2_qos_leaf_del_last(pfvf, htb->classid, + htb->command == TC_HTB_LEAF_DEL_LAST_FORCE, + htb->extack); + case TC_HTB_LEAF_QUERY_QUEUE: + res = otx2_get_txq_by_classid(pfvf, htb->classid); + htb->qid = res; + return 0; + case TC_HTB_NODE_MODIFY: + fallthrough; + default: + return -EOPNOTSUPP; + } +} diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.h b/drivers/net/ethernet/marvell/octeontx2/nic/qos.h index 73a62d092e99..19773284be27 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.h @@ -7,13 +7,63 @@ #ifndef OTX2_QOS_H #define OTX2_QOS_H +#include +#include +#include + +#define OTX2_QOS_MAX_LVL 4 +#define OTX2_QOS_MAX_PRIO 7 #define OTX2_QOS_MAX_LEAF_NODES 16 -int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq); -void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx, u16 mdq); +enum qos_smq_operations { + QOS_CFG_SQ, + QOS_SMQ_FLUSH, +}; + +u64 otx2_get_txschq_rate_regval(struct otx2_nic *nic, u64 maxrate, u32 burst); + +int otx2_setup_tc_htb(struct net_device *ndev, struct tc_htb_qopt_offload *htb); +int otx2_qos_get_qid(struct otx2_nic *pfvf); +void otx2_qos_free_qid(struct otx2_nic *pfvf, int qidx); +int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx); +void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx); + +struct otx2_qos_cfg { + u16 schq[NIX_TXSCH_LVL_CNT]; + u16 schq_contig[NIX_TXSCH_LVL_CNT]; + int static_node_pos[NIX_TXSCH_LVL_CNT]; + int dwrr_node_pos[NIX_TXSCH_LVL_CNT]; + u16 schq_contig_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC]; + u16 schq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC]; +}; struct otx2_qos { - u16 qid_to_sqmap[OTX2_QOS_MAX_LEAF_NODES]; - }; + DECLARE_HASHTABLE(qos_hlist, order_base_2(OTX2_QOS_MAX_LEAF_NODES)); + struct mutex qos_lock; /* child list lock */ + u16 qid_to_sqmap[OTX2_QOS_MAX_LEAF_NODES]; + struct list_head qos_tree; + DECLARE_BITMAP(qos_sq_bmap, OTX2_QOS_MAX_LEAF_NODES); + u16 maj_id; + u16 defcls; + u8 link_cfg_lvl; /* LINKX_CFG CSRs mapped to TL3 or TL2's index ? */ +}; + +struct otx2_qos_node { + struct list_head list; /* list management */ + struct list_head child_list; + struct list_head child_schq_list; + struct hlist_node hlist; + DECLARE_BITMAP(prio_bmap, OTX2_QOS_MAX_PRIO + 1); + struct otx2_qos_node *parent; /* parent qos node */ + u64 rate; /* htb params */ + u64 ceil; + u32 classid; + u32 prio; + u16 schq; /* hw txschq */ + u16 qid; + u16 prio_anchor; + u8 level; +}; + #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c index e142d43f5a62..d96ed29c1567 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c @@ -217,7 +217,22 @@ static int otx2_qos_ctx_disable(struct otx2_nic *pfvf, u16 qidx, int aura_id) return otx2_sync_mbox_msg(&pfvf->mbox); } -int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq) +int otx2_qos_get_qid(struct otx2_nic *pfvf) +{ + int qidx; + + qidx = find_first_zero_bit(pfvf->qos.qos_sq_bmap, + pfvf->hw.tc_tx_queues); + + return qidx == pfvf->hw.tc_tx_queues ? -ENOSPC : qidx; +} + +void otx2_qos_free_qid(struct otx2_nic *pfvf, int qidx) +{ + clear_bit(qidx, pfvf->qos.qos_sq_bmap); +} + +int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx) { struct otx2_hw *hw = &pfvf->hw; int pool_id, sq_idx, err; @@ -233,7 +248,6 @@ int otx2_qos_enable_sq(struct otx2_nic *pfvf, int qidx, u16 smq) goto out; pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_SQ, sq_idx); - pfvf->qos.qid_to_sqmap[qidx] = smq; err = otx2_sq_init(pfvf, sq_idx, pool_id); if (err) goto out; @@ -242,7 +256,7 @@ out: return err; } -void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx, u16 mdq) +void otx2_qos_disable_sq(struct otx2_nic *pfvf, int qidx) { struct otx2_qset *qset = &pfvf->qset; struct otx2_hw *hw = &pfvf->hw; -- cgit v1.2.3 From 6cebb6a4b114783af5f4747ffe3ec87d94eccf52 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Sat, 13 May 2023 14:21:42 +0530 Subject: octeontx2-pf: ethtool expose qos stats This patch extends ethtool stats support for QoS send queues as well. upon the number of transmit channels change request, Ensures the real number of transmit queues are equal to active QoS send queues plus configured transmit queues. ethtool -S eth0 txq_qos0: bytes: 3021391800 txq_qos0: frames: 1998275 txq_qos1: bytes: 4619766312 txq_qos1: frames: 3055401 ... ... Signed-off-by: Hariprasad Kelam Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/nic/otx2_ethtool.c | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c index 0f8d1a69139f..c47d91da32dc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c @@ -92,10 +92,16 @@ static void otx2_get_qset_strings(struct otx2_nic *pfvf, u8 **data, int qset) *data += ETH_GSTRING_LEN; } } - for (qidx = 0; qidx < pfvf->hw.tx_queues; qidx++) { + + for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) { for (stats = 0; stats < otx2_n_queue_stats; stats++) { - sprintf(*data, "txq%d: %s", qidx + start_qidx, - otx2_queue_stats[stats].name); + if (qidx >= pfvf->hw.non_qos_queues) + sprintf(*data, "txq_qos%d: %s", + qidx + start_qidx - pfvf->hw.non_qos_queues, + otx2_queue_stats[stats].name); + else + sprintf(*data, "txq%d: %s", qidx + start_qidx, + otx2_queue_stats[stats].name); *data += ETH_GSTRING_LEN; } } @@ -159,7 +165,7 @@ static void otx2_get_qset_stats(struct otx2_nic *pfvf, [otx2_queue_stats[stat].index]; } - for (qidx = 0; qidx < pfvf->hw.tx_queues; qidx++) { + for (qidx = 0; qidx < otx2_get_total_tx_queues(pfvf); qidx++) { if (!otx2_update_sq_stats(pfvf, qidx)) { for (stat = 0; stat < otx2_n_queue_stats; stat++) *((*data)++) = 0; @@ -254,7 +260,7 @@ static int otx2_get_sset_count(struct net_device *netdev, int sset) return -EINVAL; qstats_count = otx2_n_queue_stats * - (pfvf->hw.rx_queues + pfvf->hw.tx_queues); + (pfvf->hw.rx_queues + otx2_get_total_tx_queues(pfvf)); if (!test_bit(CN10K_RPM, &pfvf->hw.cap_flag)) mac_stats = CGX_RX_STATS_COUNT + CGX_TX_STATS_COUNT; otx2_update_lmac_fec_stats(pfvf); @@ -282,7 +288,7 @@ static int otx2_set_channels(struct net_device *dev, { struct otx2_nic *pfvf = netdev_priv(dev); bool if_up = netif_running(dev); - int err = 0; + int err, qos_txqs; if (!channel->rx_count || !channel->tx_count) return -EINVAL; @@ -296,14 +302,19 @@ static int otx2_set_channels(struct net_device *dev, if (if_up) dev->netdev_ops->ndo_stop(dev); - err = otx2_set_real_num_queues(dev, channel->tx_count, + qos_txqs = bitmap_weight(pfvf->qos.qos_sq_bmap, + OTX2_QOS_MAX_LEAF_NODES); + + err = otx2_set_real_num_queues(dev, channel->tx_count + qos_txqs, channel->rx_count); if (err) return err; pfvf->hw.rx_queues = channel->rx_count; pfvf->hw.tx_queues = channel->tx_count; - pfvf->qset.cq_cnt = pfvf->hw.tx_queues + pfvf->hw.rx_queues; + if (pfvf->xdp_prog) + pfvf->hw.xdp_queues = channel->rx_count; + pfvf->hw.non_qos_queues = pfvf->hw.tx_queues + pfvf->hw.xdp_queues; if (if_up) err = dev->netdev_ops->ndo_open(dev); @@ -1405,7 +1416,7 @@ static int otx2vf_get_sset_count(struct net_device *netdev, int sset) return -EINVAL; qstats_count = otx2_n_queue_stats * - (vf->hw.rx_queues + vf->hw.tx_queues); + (vf->hw.rx_queues + otx2_get_total_tx_queues(vf)); return otx2_n_dev_stats + otx2_n_drv_stats + qstats_count + 1; } -- cgit v1.2.3 From efe103065ccb4984c094d1547d71d498129cdd89 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Sat, 13 May 2023 14:21:43 +0530 Subject: docs: octeontx2: Add Documentation for QOS Add QOS example configuration along with tc-htb commands Signed-off-by: Hariprasad Kelam Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../device_drivers/ethernet/marvell/octeontx2.rst | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst index 5ba9015336e2..bfd233cfac35 100644 --- a/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst +++ b/Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst @@ -13,6 +13,7 @@ Contents - `Drivers`_ - `Basic packet flow`_ - `Devlink health reporters`_ +- `Quality of service`_ Overview ======== @@ -287,3 +288,47 @@ For example:: NIX_AF_ERR: NIX Error Interrupt Reg : 64 Rx on unmapped PF_FUNC + + +Quality of service +================== + + +Hardware algorithms used in scheduling +-------------------------------------- + +octeontx2 silicon and CN10K transmit interface consists of five transmit levels +starting from SMQ/MDQ, TL4 to TL1. Each packet will traverse MDQ, TL4 to TL1 +levels. Each level contains an array of queues to support scheduling and shaping. +The hardware uses the below algorithms depending on the priority of scheduler queues. +once the usercreates tc classes with different priorities, the driver configures +schedulers allocated to the class with specified priority along with rate-limiting +configuration. + +1. Strict Priority + + - Once packets are submitted to MDQ, hardware picks all active MDQs having different priority + using strict priority. + +2. Round Robin + + - Active MDQs having the same priority level are chosen using round robin. + + +Setup HTB offload +----------------- + +1. Enable HW TC offload on the interface:: + + # ethtool -K hw-tc-offload on + +2. Crate htb root:: + + # tc qdisc add dev clsact + # tc qdisc replace dev root handle 1: htb offload + +3. Create tc classes with different priorities:: + + # tc class add dev parent 1: classid 1:1 htb rate 10Gbit prio 1 + + # tc class add dev parent 1: classid 1:2 htb rate 10Gbit prio 7 -- cgit v1.2.3 From c515a4443cb8c8802751223b13855d1575db8cad Mon Sep 17 00:00:00 2001 From: Anup Sharma Date: Sat, 13 May 2023 16:36:54 +0530 Subject: net: ethernet: microchip: vcap: Remove extra semicolon Remove the extra semicolon at end. Issue identified using semicolon.cocci Coccinelle semantic patch. drivers/net/ethernet/microchip/vcap/vcap_api.c:1124:3-4: Unneeded semicolon drivers/net/ethernet/microchip/vcap/vcap_api.c:1165:3-4: Unneeded semicolon drivers/net/ethernet/microchip/vcap/vcap_api.c:1239:3-4: Unneeded semicolon drivers/net/ethernet/microchip/vcap/vcap_api.c:1287:3-4: Unneeded semicolon Signed-off-by: Anup Sharma Changes: V1 -> V2: Target tree included in the subject line. Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/vcap/vcap_api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index 5675b0962bc3..a418ad8e8770 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -1121,7 +1121,7 @@ static void vcap_copy_to_client_actionfield(struct vcap_rule_internal *ri, vcap_copy_from_w32be(field->data.u128.value, value, field_size, width); break; - }; + } } else { switch (field->ctrl.type) { case VCAP_FIELD_BIT: @@ -1162,7 +1162,7 @@ static void vcap_copy_to_client_actionfield(struct vcap_rule_internal *ri, value, width, field_size); break; - }; + } } } @@ -1236,7 +1236,7 @@ static void vcap_copy_to_client_keyfield(struct vcap_rule_internal *ri, vcap_copy_from_w32be(field->data.u128.mask, mask, field_size, width); break; - }; + } } else { switch (field->ctrl.type) { case VCAP_FIELD_BIT: @@ -1284,7 +1284,7 @@ static void vcap_copy_to_client_keyfield(struct vcap_rule_internal *ri, value, mask, width, field_size); break; - }; + } } } -- cgit v1.2.3 From d1e4632b304c594d6f0d4cb7581350e5a6fc33b7 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 15 May 2023 16:56:45 +0800 Subject: octeontx2-pf: mcs: Remove unneeded semicolon ./drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c:242:2-3: Unneeded semicolon ./drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c:476:2-3: Unneeded semicolon Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=4947 Signed-off-by: Yang Li Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c index 8eaa50d0f668..b59532cf53ce 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c @@ -239,7 +239,7 @@ static int cn10k_mcs_write_rx_secy(struct otx2_nic *pfvf, cipher = MCS_GCM_AES_128; dev_warn(pfvf->dev, "Unsupported key length\n"); break; - }; + } policy |= FIELD_PREP(MCS_RX_SECY_PLCY_CIP, cipher); policy |= FIELD_PREP(MCS_RX_SECY_PLCY_VAL, secy->validate_frames); @@ -473,7 +473,7 @@ static int cn10k_mcs_write_tx_secy(struct otx2_nic *pfvf, cipher = MCS_GCM_AES_128; dev_warn(pfvf->dev, "Unsupported key length\n"); break; - }; + } policy |= FIELD_PREP(MCS_TX_SECY_PLCY_CIP, cipher); -- cgit v1.2.3 From 0d9b41daa5907756a31772d8af8ac5ff25cf17c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 13 May 2023 13:52:04 +0200 Subject: nfc: llcp: fix possible use of uninitialized variable in nfc_llcp_send_connect() If sock->service_name is NULL, the local variable service_name_tlv_length will not be assigned by nfc_llcp_build_tlv(), later leading to using value frmo the stack. Smatch warning: net/nfc/llcp_commands.c:442 nfc_llcp_send_connect() error: uninitialized symbol 'service_name_tlv_length'. Fixes: de9e5aeb4f40 ("NFC: llcp: Fix usage of llcp_add_tlv()") Signed-off-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- net/nfc/llcp_commands.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 41e3a20c8935..cdb001de0692 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -390,7 +390,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) const u8 *service_name_tlv = NULL; const u8 *miux_tlv = NULL; const u8 *rw_tlv = NULL; - u8 service_name_tlv_length, miux_tlv_length, rw_tlv_length, rw; + u8 service_name_tlv_length = 0; + u8 miux_tlv_length, rw_tlv_length, rw; int err; u16 size = 0; __be16 miux; -- cgit v1.2.3 From 4d585f48ee6b38c54c075b151c5efd2ff65f8ffd Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Wed, 10 May 2023 14:30:47 -0700 Subject: bpf: Remove anonymous union in bpf_kfunc_call_arg_meta For kfuncs like bpf_obj_drop and bpf_refcount_acquire - which take user-defined types as input - the verifier needs to track the specific type passed in when checking a particular kfunc call. This requires tracking (btf, btf_id) tuple. In commit 7c50b1cb76ac ("bpf: Add bpf_refcount_acquire kfunc") I added an anonymous union with inner structs named after the specific kfuncs tracking this information, with the goal of making it more obvious which kfunc this data was being tracked / expected to be tracked on behalf of. In a recent series adding a new user of this tuple, Alexei mentioned that he didn't like this union usage as it doesn't really help with readability or bug-proofing ([0]). In an offline convo we agreed to have the tuple be fields (arg_btf, arg_btf_id), with comments in bpf_kfunc_call_arg_meta definition enumerating the uses of the fields by kfunc-specific handling logic. Such a pattern is used by struct bpf_reg_state without trouble. Accordingly, this patch removes the anonymous union in favor of arg_btf and arg_btf_id fields and comment enumerating their current uses. The patch also removes struct btf_and_id, which was only being used by the removed union's inner structs. This is a mechanical change, existing linked_list and rbtree tests will validate that correct (btf, btf_id) are being passed. [0]: https://lore.kernel.org/bpf/20230505021707.vlyiwy57vwxglbka@dhcp-172-26-102-232.dhcp.thefacebook.com Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20230510213047.1633612-1-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 754129d41225..5c636276d907 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -279,11 +279,6 @@ struct bpf_call_arg_meta { struct btf_field *kptr_field; }; -struct btf_and_id { - struct btf *btf; - u32 btf_id; -}; - struct bpf_kfunc_call_arg_meta { /* In parameters */ struct btf *btf; @@ -302,10 +297,18 @@ struct bpf_kfunc_call_arg_meta { u64 value; bool found; } arg_constant; - union { - struct btf_and_id arg_obj_drop; - struct btf_and_id arg_refcount_acquire; - }; + + /* arg_btf and arg_btf_id are used by kfunc-specific handling, + * generally to pass info about user-defined local kptr types to later + * verification logic + * bpf_obj_drop + * Record the local kptr type to be drop'd + * bpf_refcount_acquire (via KF_ARG_PTR_TO_REFCOUNTED_KPTR arg type) + * Record the local kptr type to be refcount_incr'd + */ + struct btf *arg_btf; + u32 arg_btf_id; + struct { struct btf_field *field; } arg_list_head; @@ -10680,8 +10683,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ } if (meta->btf == btf_vmlinux && meta->func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) { - meta->arg_obj_drop.btf = reg->btf; - meta->arg_obj_drop.btf_id = reg->btf_id; + meta->arg_btf = reg->btf; + meta->arg_btf_id = reg->btf_id; } break; case KF_ARG_PTR_TO_DYNPTR: @@ -10892,8 +10895,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ verbose(env, "bpf_refcount_acquire calls are disabled for now\n"); return -EINVAL; } - meta->arg_refcount_acquire.btf = reg->btf; - meta->arg_refcount_acquire.btf_id = reg->btf_id; + meta->arg_btf = reg->btf; + meta->arg_btf_id = reg->btf_id; break; } } @@ -11125,12 +11128,12 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, } else if (meta.func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl]) { mark_reg_known_zero(env, regs, BPF_REG_0); regs[BPF_REG_0].type = PTR_TO_BTF_ID | MEM_ALLOC; - regs[BPF_REG_0].btf = meta.arg_refcount_acquire.btf; - regs[BPF_REG_0].btf_id = meta.arg_refcount_acquire.btf_id; + regs[BPF_REG_0].btf = meta.arg_btf; + regs[BPF_REG_0].btf_id = meta.arg_btf_id; insn_aux->kptr_struct_meta = - btf_find_struct_meta(meta.arg_refcount_acquire.btf, - meta.arg_refcount_acquire.btf_id); + btf_find_struct_meta(meta.arg_btf, + meta.arg_btf_id); } else if (meta.func_id == special_kfunc_list[KF_bpf_list_pop_front] || meta.func_id == special_kfunc_list[KF_bpf_list_pop_back]) { struct btf_field *field = meta.arg_list_head.field; @@ -11260,8 +11263,8 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, if (meta.btf == btf_vmlinux && btf_id_set_contains(&special_kfunc_set, meta.func_id)) { if (meta.func_id == special_kfunc_list[KF_bpf_obj_drop_impl]) { insn_aux->kptr_struct_meta = - btf_find_struct_meta(meta.arg_obj_drop.btf, - meta.arg_obj_drop.btf_id); + btf_find_struct_meta(meta.arg_btf, + meta.arg_btf_id); } } } -- cgit v1.2.3 From 87807f77a03d0271211b75f84b2a8b88f4e8e5d4 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Tue, 9 May 2023 12:04:20 +0200 Subject: wifi: brcmfmac: wcc: Add debug messages The message is attach and detach function are merly for debugging, change them from pr_err to pr_debug. Signed-off-by: Matthias Brugger Reviewed-by: Hans de Goede Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230509100420.26094-1-matthias.bgg@kernel.org --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c index 02de99818efa..5573a47766ad 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c @@ -12,13 +12,13 @@ static int brcmf_wcc_attach(struct brcmf_pub *drvr) { - pr_err("%s: executing\n", __func__); + pr_debug("%s: executing\n", __func__); return 0; } static void brcmf_wcc_detach(struct brcmf_pub *drvr) { - pr_err("%s: executing\n", __func__); + pr_debug("%s: executing\n", __func__); } const struct brcmf_fwvid_ops brcmf_wcc_ops = { -- cgit v1.2.3 From c98411dc8cf6c15b8dbbfb37475bcc08b8958880 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 13 May 2023 23:47:38 +0300 Subject: wifi: rtl8xxxu: Support new chip RTL8192FU This is a newer chip, similar to the RTL8710BU in that it uses the same PHY status structs. Features: 2.4 GHz, b/g/n mode, 2T2R, 300 Mbps. It can allegedly have Bluetooth, but that's not implemented here. This chip can have many RFE (RF front end) types, of which types 1 and 5 are the only ones tested. Many of the other types need different initialisation tables. They can be added if someone wants them. The vendor driver v5.8.6.2_35538.20191028_COEX20190910-0d02 from https://github.com/BrightX/rtl8192fu was used as reference, with additional device IDs taken from https://github.com/kelebek333/rtl8192fu-dkms. The vendor driver also claims to support devices with ID 0bda:a725, but that is found in some bluetooth-only devices, so it's not supported here. Signed-off-by: Bitterblue Smith Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/7dcf9fb9-1c97-ac28-5286-2236e287a18c@gmail.com --- drivers/net/wireless/realtek/rtl8xxxu/Kconfig | 3 +- drivers/net/wireless/realtek/rtl8xxxu/Makefile | 2 +- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 47 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c | 3 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c | 2090 ++++++++++++++++++++ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 1 + .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 108 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 39 + 9 files changed, 2263 insertions(+), 31 deletions(-) create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig index 82bcaf44a65f..44ad94757a03 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig +++ b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig @@ -11,7 +11,8 @@ config RTL8XXXU parts written to utilize the Linux mac80211 stack. The driver is known to work with a number of RTL8723AU, RL8188CU, RTL8188RU, RTL8191CU, RTL8192CU, RTL8723BU, RTL8192EU, - RTL8188FU, RTL8188EU, and RTL8710BU (aka RTL8188GU) devices. + RTL8188FU, RTL8188EU, RTL8710BU (aka RTL8188GU), and RTL8192FU + devices. This driver is under development and has a limited feature set. In particular it does not yet support 40MHz channels diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Makefile b/drivers/net/wireless/realtek/rtl8xxxu/Makefile index 1bf083c15dcd..fa466589eccb 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/Makefile +++ b/drivers/net/wireless/realtek/rtl8xxxu/Makefile @@ -3,4 +3,4 @@ obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o rtl8xxxu-y := rtl8xxxu_core.o rtl8xxxu_8192e.o rtl8xxxu_8723b.o \ rtl8xxxu_8723a.o rtl8xxxu_8192c.o rtl8xxxu_8188f.o \ - rtl8xxxu_8188e.o rtl8xxxu_8710b.o + rtl8xxxu_8188e.o rtl8xxxu_8710b.o rtl8xxxu_8192f.o diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 2c756640f59d..9283119038b7 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -39,6 +39,7 @@ #define TX_TOTAL_PAGE_NUM_8188E 0xa9 #define TX_TOTAL_PAGE_NUM_8192E 0xf3 #define TX_TOTAL_PAGE_NUM_8723B 0xf7 +#define TX_TOTAL_PAGE_NUM_8192F 0xf7 /* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */ #define TX_PAGE_NUM_PUBQ 0xe7 #define TX_PAGE_NUM_HI_PQ 0x0c @@ -65,6 +66,11 @@ #define TX_PAGE_NUM_LO_PQ_8723B 0x02 #define TX_PAGE_NUM_NORM_PQ_8723B 0x02 +#define TX_PAGE_NUM_PUBQ_8192F 0xde +#define TX_PAGE_NUM_HI_PQ_8192F 0x08 +#define TX_PAGE_NUM_LO_PQ_8192F 0x08 +#define TX_PAGE_NUM_NORM_PQ_8192F 0x08 + #define RTL_FW_PAGE_SIZE 4096 #define RTL8XXXU_FIRMWARE_POLL_MAX 1000 @@ -81,6 +87,7 @@ #define EFUSE_REAL_CONTENT_LEN_8723A 512 #define EFUSE_BT_MAP_LEN_8723A 1024 #define EFUSE_MAX_WORD_UNIT 4 +#define EFUSE_UNDEFINED 0xff enum rtl8xxxu_rtl_chip { RTL8192S = 0x81920, @@ -105,6 +112,7 @@ enum rtl8xxxu_rtl_chip { RTL8195A = 0x8195a, RTL8188F = 0x8188f, RTL8710B = 0x8710b, + RTL8192F = 0x8192f, }; enum rtl8xxxu_rx_type { @@ -1246,6 +1254,40 @@ struct rtl8710bu_efuse { u8 res7[0x3c]; } __packed; +struct rtl8192fu_efuse { + __le16 rtl_id; + u8 res0[0x0e]; + struct rtl8192eu_efuse_tx_power tx_power_index_A; /* 0x10 */ + struct rtl8192eu_efuse_tx_power tx_power_index_B; /* 0x3a */ + u8 res2[0x54]; + u8 channel_plan; /* 0xb8 */ + u8 xtal_k; /* 0xb9 */ + u8 thermal_meter; /* 0xba */ + u8 iqk_lck; /* 0xbb */ + u8 pa_type; /* 0xbc */ + u8 lna_type_2g; /* 0xbd */ + u8 res3[1]; + u8 lna_type_5g; /* 0xbf */ + u8 res4[1]; + u8 rf_board_option; /* 0xc1 */ + u8 rf_feature_option; /* 0xc2 */ + u8 rf_bt_setting; /* 0xc3 */ + u8 eeprom_version; /* 0xc4 */ + u8 eeprom_customer_id; /* 0xc5 */ + u8 res5[3]; + u8 rf_antenna_option; /* 0xc9 */ + u8 rfe_option; /* 0xca */ + u8 country_code; /* 0xcb */ + u8 res6[52]; + u8 vid[2]; /* 0x100 */ + u8 pid[2]; /* 0x102 */ + u8 usb_optional_function; /* 0x104 */ + u8 res7[2]; + u8 mac_addr[ETH_ALEN]; /* 0x107 */ + u8 device_info[80]; /* 0x10d */ + u8 res9[163]; +} __packed; + struct rtl8xxxu_reg8val { u16 reg; u8 val; @@ -1796,6 +1838,7 @@ struct rtl8xxxu_priv { u32 cck_agc_report_type:1; u32 cck_new_agc:1; u8 default_crystal_cap; + u8 rfe_type; unsigned int pipe_interrupt; unsigned int pipe_in; unsigned int pipe_out[TXDESC_QUEUE_MAX]; @@ -1835,6 +1878,7 @@ struct rtl8xxxu_priv { struct rtl8188fu_efuse efuse8188fu; struct rtl8188eu_efuse efuse8188eu; struct rtl8710bu_efuse efuse8710bu; + struct rtl8192fu_efuse efuse8192fu; } efuse_wifi; u32 adda_backup[RTL8XXXU_ADDA_REGS]; u32 mac_backup[RTL8XXXU_MAC_REGS]; @@ -1943,6 +1987,7 @@ struct rtl8xxxu_fileops { u8 init_reg_hmtfr:1; u8 ampdu_max_time; u8 ustime_tsf_edca; + u16 max_aggr_num; u8 supports_ap:1; u16 max_macid_num; u32 adda_1t_init; @@ -2031,6 +2076,7 @@ void rtl8xxxu_gen1_phy_iq_calibrate(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_init_phy_bb(struct rtl8xxxu_priv *priv); void rtl8xxxu_gen1_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40); +void rtl8188f_channel_to_group(int channel, int *group, int *cck_group); void rtl8188f_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40); void rtl8xxxu_gen1_config_channel(struct ieee80211_hw *hw); @@ -2095,6 +2141,7 @@ void rtl8xxxu_update_ra_report(struct rtl8xxxu_ra_report *rarpt, void rtl8188e_ra_info_init_all(struct rtl8xxxu_ra_info *ra); void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *skb); +extern struct rtl8xxxu_fileops rtl8192fu_fops; extern struct rtl8xxxu_fileops rtl8710bu_fops; extern struct rtl8xxxu_fileops rtl8188fu_fops; extern struct rtl8xxxu_fileops rtl8188eu_fops; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index 71b7f0d31bf4..cb45546c4c68 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -351,7 +351,7 @@ out: return ret; } -static void rtl8188f_channel_to_group(int channel, int *group, int *cck_group) +void rtl8188f_channel_to_group(int channel, int *group, int *cck_group) { if (channel < 3) *group = 0; @@ -1748,6 +1748,7 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .init_reg_hmtfr = 1, .ampdu_max_time = 0x70, .ustime_tsf_edca = 0x28, + .max_aggr_num = 0x0c14, .supports_ap = 1, .max_macid_num = 16, .adda_1t_init = 0x03c00014, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c new file mode 100644 index 000000000000..50225f1d9478 --- /dev/null +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c @@ -0,0 +1,2090 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * RTL8XXXU mac80211 USB driver - 8192fu specific subdriver + * + * Copyright (c) 2023 Bitterblue Smith + * + * Portions copied from existing rtl8xxxu code: + * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtl8xxxu.h" +#include "rtl8xxxu_regs.h" + +static const struct rtl8xxxu_reg8val rtl8192f_mac_init_table[] = { + {0x420, 0x00}, {0x422, 0x78}, {0x428, 0x0a}, {0x429, 0x10}, + {0x430, 0x00}, {0x431, 0x00}, {0x432, 0x00}, {0x433, 0x01}, + {0x434, 0x04}, {0x435, 0x05}, {0x436, 0x07}, {0x437, 0x08}, + {0x43c, 0x04}, {0x43d, 0x05}, {0x43e, 0x07}, {0x43f, 0x08}, + {0x440, 0x5d}, {0x441, 0x01}, {0x442, 0x00}, {0x444, 0x10}, + {0x445, 0xf0}, {0x446, 0x0e}, {0x447, 0x1f}, {0x448, 0x00}, + {0x449, 0x00}, {0x44a, 0x00}, {0x44b, 0x00}, {0x44c, 0x10}, + {0x44d, 0xf0}, {0x44e, 0x0e}, {0x44f, 0x00}, {0x450, 0x00}, + {0x451, 0x00}, {0x452, 0x00}, {0x453, 0x00}, {0x480, 0x20}, + {0x49c, 0x30}, {0x49d, 0xf0}, {0x49e, 0x03}, {0x49f, 0x3e}, + {0x4a0, 0x00}, {0x4a1, 0x00}, {0x4a2, 0x00}, {0x4a3, 0x00}, + {0x4a4, 0x15}, {0x4a5, 0xf0}, {0x4a6, 0x01}, {0x4a7, 0x0e}, + {0x4a8, 0xe0}, {0x4a9, 0x00}, {0x4aa, 0x00}, {0x4ab, 0x00}, + {0x2448, 0x06}, {0x244a, 0x06}, {0x244c, 0x06}, {0x244e, 0x06}, + {0x4c7, 0x80}, {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4ca, 0x3c}, + {0x4cb, 0x3c}, {0x4cc, 0xff}, {0x4cd, 0xff}, {0x4ce, 0x01}, + {0x500, 0x26}, {0x501, 0xa2}, {0x502, 0x2f}, {0x503, 0x00}, + {0x504, 0x28}, {0x505, 0xa3}, {0x506, 0x5e}, {0x507, 0x00}, + {0x508, 0x2b}, {0x509, 0xa4}, {0x50a, 0x5e}, {0x50b, 0x00}, + {0x50c, 0x4f}, {0x50d, 0xa4}, {0x50e, 0x00}, {0x50f, 0x00}, + {0x512, 0x1c}, {0x514, 0x0a}, {0x516, 0x0a}, {0x521, 0x2f}, + {0x525, 0x0f}, {0x550, 0x10}, {0x551, 0x10}, {0x559, 0x02}, + {0x55c, 0x50}, {0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, + {0x609, 0x2a}, {0x60c, 0x18}, {0x620, 0xff}, {0x621, 0xff}, + {0x622, 0xff}, {0x623, 0xff}, {0x624, 0xff}, {0x625, 0xff}, + {0x626, 0xff}, {0x627, 0xff}, {0x638, 0x50}, {0x63c, 0x0a}, + {0x63d, 0x0a}, {0x63e, 0x0e}, {0x63f, 0x0e}, {0x640, 0x40}, + {0x642, 0x40}, {0x643, 0x00}, {0x652, 0xc8}, {0x66e, 0x05}, + {0x6a0, 0xff}, {0x6a1, 0xff}, {0x6a2, 0xff}, {0x6a3, 0xff}, + {0x6a4, 0xff}, {0x6a5, 0xff}, {0x6de, 0x84}, {0x700, 0x21}, + {0x701, 0x43}, {0x702, 0x65}, {0x703, 0x87}, {0x708, 0x21}, + {0x709, 0x43}, {0x70a, 0x65}, {0x70b, 0x87}, {0x718, 0x40}, + {0x7c0, 0x38}, {0x7c2, 0x0f}, {0x7c3, 0xc0}, {0x073, 0x04}, + {0x7c4, 0x77}, {0x024, 0xc7}, {0x7ec, 0xff}, {0x7ed, 0xff}, + {0x7ee, 0xff}, {0x7ef, 0xff}, + {0xffff, 0xff}, +}; + +/* If updating the phy init table, also update rtl8192f_revise_cck_tx_psf(). */ +static const struct rtl8xxxu_reg32val rtl8192fu_phy_init_table[] = { + {0x800, 0x80006C00}, {0x804, 0x00004001}, + {0x808, 0x0000FC00}, {0x80C, 0x00000000}, + {0x810, 0x20200322}, {0x814, 0x020C3910}, + {0x818, 0x00000385}, {0x81C, 0x07000000}, + {0x820, 0x01000100}, {0x824, 0x00390204}, + {0x828, 0x01000100}, {0x82C, 0x00390204}, + {0x830, 0x25252525}, {0x834, 0x25252525}, + {0x838, 0x25252525}, {0x83C, 0x25252525}, + {0x840, 0x00010000}, {0x844, 0x00010000}, + {0x848, 0x25252525}, {0x84C, 0x25252525}, + {0x850, 0x00031FE0}, {0x854, 0x00000000}, + {0x858, 0x569A569A}, {0x85C, 0x00400040}, + {0x860, 0x66F60000}, {0x864, 0x061F0000}, + {0x868, 0x25252525}, {0x86C, 0x25252525}, + {0x870, 0x00000300}, {0x874, 0x04003400}, + {0x878, 0x08080808}, {0x87C, 0x004F0201}, + {0x880, 0xD8001402}, {0x884, 0xC0000120}, + {0x888, 0x00000000}, {0x88C, 0xCC0000C0}, + {0x890, 0x00000000}, {0x894, 0xFFFFFFFE}, + {0x898, 0x40302010}, {0x89C, 0x00706050}, + {0x900, 0x00000000}, {0x904, 0x00000023}, + {0x908, 0x00000F00}, {0x90C, 0x81121313}, + {0x910, 0x024C0000}, {0x914, 0x00000000}, + {0x918, 0x00000000}, {0x91C, 0x00000000}, + {0x920, 0x00000000}, {0x924, 0x00000000}, + {0x928, 0x00000000}, {0x92C, 0x00000000}, + {0x930, 0x88000000}, {0x934, 0x00000245}, + {0x938, 0x00024588}, {0x93C, 0x00000000}, + {0x940, 0x000007FF}, {0x944, 0x3F3F0000}, + {0x948, 0x000001A3}, {0x94C, 0x20200008}, + {0x950, 0x00338A98}, {0x954, 0x00000000}, + {0x958, 0xCBCAD87A}, {0x95C, 0x06EB5735}, + {0x960, 0x00000000}, {0x964, 0x00000000}, + {0x968, 0x00000000}, {0x96C, 0x00000003}, + {0x970, 0x00000000}, {0x974, 0x00000000}, + {0x978, 0x00000000}, {0x97C, 0x10030000}, + {0x980, 0x00000000}, {0x984, 0x02800280}, + {0x988, 0x020A5704}, {0x98C, 0x1461C826}, + {0x990, 0x0001469E}, {0x994, 0x008858D1}, + {0x998, 0x400086C9}, {0x99C, 0x44444242}, + {0x9A0, 0x00000000}, {0x9A4, 0x00000000}, + {0x9A8, 0x00000000}, {0x9AC, 0xC0000000}, + {0xA00, 0x00D047C8}, {0xA04, 0xC1FF0008}, + {0xA08, 0x88838300}, {0xA0C, 0x2E20100F}, + {0xA10, 0x9500BB78}, {0xA14, 0x11144028}, + {0xA18, 0x00881117}, {0xA1C, 0x89140F00}, + {0xA20, 0xE82C0001}, {0xA24, 0x64B80C1C}, + {0xA28, 0x00158810}, {0xA2C, 0x10BB8000}, + {0xA70, 0x00008000}, {0xA74, 0x80800100}, + {0xA78, 0x000089F0}, {0xA7C, 0x225B0606}, + {0xA80, 0x20803210}, {0xA84, 0x00200200}, + {0xA88, 0x00000000}, {0xA8C, 0x00000000}, + {0xA90, 0x00000000}, {0xA94, 0x00000000}, + {0xA98, 0x00000000}, {0xA9C, 0x00460000}, + {0xAA0, 0x00000000}, {0xAA4, 0x00020014}, + {0xAA8, 0xBA0A0008}, {0xAAC, 0x01235667}, + {0xAB0, 0x00000000}, {0xAB4, 0x00201402}, + {0xAB8, 0x0000001C}, {0xABC, 0x0000F7FF}, + {0xAC0, 0xD4C0A742}, {0xAC4, 0x00000000}, + {0xAC8, 0x00000F08}, {0xACC, 0x00000F07}, + {0xAD0, 0xA1052A10}, {0xAD4, 0x0D9D8452}, + {0xAD8, 0x9E024024}, {0xADC, 0x0023C001}, + {0xAE0, 0x00000391}, {0xB2C, 0x00000000}, + {0xC00, 0x00000080}, {0xC04, 0x6F005433}, + {0xC08, 0x000004E4}, {0xC0C, 0x6C6C6C6C}, + {0xC10, 0x22000000}, {0xC14, 0x40000100}, + {0xC18, 0x22000000}, {0xC1C, 0x40000100}, + {0xC20, 0x00000000}, {0xC24, 0x40000100}, + {0xC28, 0x00000000}, {0xC2C, 0x40000100}, + {0xC30, 0x0401E809}, {0xC34, 0x30000020}, + {0xC38, 0x23808080}, {0xC3C, 0x00002F44}, + {0xC40, 0x1CF8403F}, {0xC44, 0x000100C7}, + {0xC48, 0xEC060106}, {0xC4C, 0x007F037F}, + {0xC50, 0x00E48020}, {0xC54, 0x04008017}, + {0xC58, 0x00000020}, {0xC5C, 0x00708492}, + {0xC60, 0x09280200}, {0xC64, 0x5014838B}, + {0xC68, 0x47C006C7}, {0xC6C, 0x00000035}, + {0xC70, 0x00001007}, {0xC74, 0x02815269}, + {0xC78, 0x0FE07F1F}, {0xC7C, 0x00B91612}, + {0xC80, 0x40000100}, {0xC84, 0x32000000}, + {0xC88, 0x40000100}, {0xC8C, 0xA0240000}, + {0xC90, 0x400E161E}, {0xC94, 0x00000F00}, + {0xC98, 0x400E161E}, {0xC9C, 0x0000BDC8}, + {0xCA0, 0x00000000}, {0xCA4, 0x098300A0}, + {0xCA8, 0x00006B00}, {0xCAC, 0x87F45B1A}, + {0xCB0, 0x0000002D}, {0xCB4, 0x00000000}, + {0xCB8, 0x00000000}, {0xCBC, 0x28100200}, + {0xCC0, 0x0010A3D0}, {0xCC4, 0x00000F7D}, + {0xCC8, 0x00000000}, {0xCCC, 0x00000000}, + {0xCD0, 0x593659AD}, {0xCD4, 0xB7545121}, + {0xCD8, 0x64B22427}, {0xCDC, 0x00766932}, + {0xCE0, 0x40201000}, {0xCE4, 0x00000000}, + {0xCE8, 0x40E04407}, {0xCEC, 0x2E572000}, + {0xD00, 0x000D8780}, {0xD04, 0x40020403}, + {0xD08, 0x0002907F}, {0xD0C, 0x20010201}, + {0xD10, 0x06288888}, {0xD14, 0x8888367B}, + {0xD18, 0x7D806DB3}, {0xD1C, 0x0000007F}, + {0xD20, 0x567600B8}, {0xD24, 0x0000018B}, + {0xD28, 0xD513FF7D}, {0xD2C, 0xCC979975}, + {0xD30, 0x04928000}, {0xD34, 0x40608000}, + {0xD38, 0x88DDA000}, {0xD3C, 0x00026EE2}, + {0xD50, 0x67270001}, {0xD54, 0x20500000}, + {0xD58, 0x16161616}, {0xD5C, 0x71F20064}, + {0xD60, 0x4653DA60}, {0xD64, 0x3E718A3C}, + {0xD68, 0x00000183}, {0xD7C, 0x00000000}, + {0xD80, 0x50000000}, {0xD84, 0x31310400}, + {0xD88, 0xF5B50000}, {0xD8C, 0x00000000}, + {0xD90, 0x00000000}, {0xD94, 0x44BBBB44}, + {0xD98, 0x44BB44FF}, {0xD9C, 0x06033688}, + {0xE00, 0x25252525}, {0xE04, 0x25252525}, + {0xE08, 0x25252525}, {0xE10, 0x25252525}, + {0xE14, 0x25252525}, {0xE18, 0x25252525}, + {0xE1C, 0x25252525}, {0xE20, 0x00000000}, + {0xE24, 0x00200000}, {0xE28, 0x00000000}, + {0xE2C, 0x00000000}, {0xE30, 0x01007C00}, + {0xE34, 0x01004800}, {0xE38, 0x10008C0F}, + {0xE3C, 0x3C008C0F}, {0xE40, 0x01007C00}, + {0xE44, 0x00000000}, {0xE48, 0x00000000}, + {0xE4C, 0x00000000}, {0xE50, 0x01007C00}, + {0xE54, 0x01004800}, {0xE58, 0x10008C0F}, + {0xE5C, 0x3C008C0F}, {0xE60, 0x02100000}, + {0xE64, 0xBBBBBBBB}, {0xE68, 0x40404040}, + {0xE6C, 0x80408040}, {0xE70, 0x80408040}, + {0xE74, 0x40404040}, {0xE78, 0x00400040}, + {0xE7C, 0x40404040}, {0xE80, 0x00FF0000}, + {0xE84, 0x80408040}, {0xE88, 0x40404040}, + {0xE8C, 0x80408040}, {0xED0, 0x80408040}, + {0xED4, 0x80408040}, {0xED8, 0x80408040}, + {0xEDC, 0xC040C040}, {0xEE0, 0xC040C040}, + {0xEE4, 0x00400040}, {0xEE8, 0xD8001402}, + {0xEEC, 0xC0000120}, {0xEF0, 0x02000B09}, + {0xEF4, 0x00000001}, {0xEF8, 0x00000000}, + {0xF00, 0x00000300}, {0xF04, 0x00000002}, + {0xF08, 0x00007D0C}, {0xF0C, 0x0000A907}, + {0xF10, 0x00005807}, {0xF14, 0x00000003}, + {0xF18, 0x07D003E8}, {0xF1C, 0x8000001F}, + {0xF20, 0x00000000}, {0xF24, 0x00000000}, + {0xF28, 0x00000000}, {0xF2C, 0x00000000}, + {0xF30, 0x00000000}, {0xF34, 0x00000000}, + {0xF38, 0x00030055}, {0xF3C, 0x0000003A}, + {0xF40, 0x00000002}, {0xF44, 0x00000000}, + {0xF48, 0x00000000}, {0xF4C, 0x0B000000}, + {0xF50, 0x00000000}, + {0xffff, 0xffffffff}, +}; + +static const struct rtl8xxxu_reg32val rtl8192f_agc_table[] = { + {0xC78, 0x0FA0001F}, {0xC78, 0x0FA0011F}, + {0xC78, 0x0FA0021F}, {0xC78, 0x0FA0031F}, + {0xC78, 0x0FA0041F}, {0xC78, 0x0FA0051F}, + {0xC78, 0x0F90061F}, {0xC78, 0x0F80071F}, + {0xC78, 0x0F70081F}, {0xC78, 0x0F60091F}, + {0xC78, 0x0F500A1F}, {0xC78, 0x0F400B1F}, + {0xC78, 0x0F300C1F}, {0xC78, 0x0F200D1F}, + {0xC78, 0x0F100E1F}, {0xC78, 0x0F000F1F}, + {0xC78, 0x0EF0101F}, {0xC78, 0x0EE0111F}, + {0xC78, 0x0ED0121F}, {0xC78, 0x0EC0131F}, + {0xC78, 0x0EB0141F}, {0xC78, 0x0EA0151F}, + {0xC78, 0x0E90161F}, {0xC78, 0x0E80171F}, + {0xC78, 0x0E70181F}, {0xC78, 0x0E60191F}, + {0xC78, 0x0E501A1F}, {0xC78, 0x0E401B1F}, + {0xC78, 0x0E301C1F}, {0xC78, 0x0C701D1F}, + {0xC78, 0x0C601E1F}, {0xC78, 0x0C501F1F}, + {0xC78, 0x0C40201F}, {0xC78, 0x0C30211F}, + {0xC78, 0x0A60221F}, {0xC78, 0x0A50231F}, + {0xC78, 0x0A40241F}, {0xC78, 0x0A30251F}, + {0xC78, 0x0860261F}, {0xC78, 0x0850271F}, + {0xC78, 0x0840281F}, {0xC78, 0x0830291F}, + {0xC78, 0x06702A1F}, {0xC78, 0x06602B1F}, + {0xC78, 0x06502C1F}, {0xC78, 0x06402D1F}, + {0xC78, 0x06302E1F}, {0xC78, 0x04602F1F}, + {0xC78, 0x0450301F}, {0xC78, 0x0440311F}, + {0xC78, 0x0430321F}, {0xC78, 0x0260331F}, + {0xC78, 0x0250341F}, {0xC78, 0x0240351F}, + {0xC78, 0x0230361F}, {0xC78, 0x0050371F}, + {0xC78, 0x0040381F}, {0xC78, 0x0030391F}, + {0xC78, 0x00203A1F}, {0xC78, 0x00103B1F}, + {0xC78, 0x00003C1F}, {0xC78, 0x00003D1F}, + {0xC78, 0x00003E1F}, {0xC78, 0x00003F1F}, + + {0xC78, 0x0FA0401F}, {0xC78, 0x0FA0411F}, + {0xC78, 0x0FA0421F}, {0xC78, 0x0FA0431F}, + {0xC78, 0x0F90441F}, {0xC78, 0x0F80451F}, + {0xC78, 0x0F70461F}, {0xC78, 0x0F60471F}, + {0xC78, 0x0F50481F}, {0xC78, 0x0F40491F}, + {0xC78, 0x0F304A1F}, {0xC78, 0x0F204B1F}, + {0xC78, 0x0F104C1F}, {0xC78, 0x0F004D1F}, + {0xC78, 0x0EF04E1F}, {0xC78, 0x0EE04F1F}, + {0xC78, 0x0ED0501F}, {0xC78, 0x0EC0511F}, + {0xC78, 0x0EB0521F}, {0xC78, 0x0EA0531F}, + {0xC78, 0x0E90541F}, {0xC78, 0x0E80551F}, + {0xC78, 0x0E70561F}, {0xC78, 0x0E60571F}, + {0xC78, 0x0E50581F}, {0xC78, 0x0E40591F}, + {0xC78, 0x0E305A1F}, {0xC78, 0x0E205B1F}, + {0xC78, 0x0E105C1F}, {0xC78, 0x0C505D1F}, + {0xC78, 0x0C405E1F}, {0xC78, 0x0C305F1F}, + {0xC78, 0x0C20601F}, {0xC78, 0x0C10611F}, + {0xC78, 0x0A40621F}, {0xC78, 0x0A30631F}, + {0xC78, 0x0A20641F}, {0xC78, 0x0A10651F}, + {0xC78, 0x0840661F}, {0xC78, 0x0830671F}, + {0xC78, 0x0820681F}, {0xC78, 0x0810691F}, + {0xC78, 0x06506A1F}, {0xC78, 0x06406B1F}, + {0xC78, 0x06306C1F}, {0xC78, 0x06206D1F}, + {0xC78, 0x06106E1F}, {0xC78, 0x04406F1F}, + {0xC78, 0x0430701F}, {0xC78, 0x0420711F}, + {0xC78, 0x0410721F}, {0xC78, 0x0240731F}, + {0xC78, 0x0230741F}, {0xC78, 0x0220751F}, + {0xC78, 0x0210761F}, {0xC78, 0x0030771F}, + {0xC78, 0x0020781F}, {0xC78, 0x0010791F}, + {0xC78, 0x00007A1F}, {0xC78, 0x00007B1F}, + {0xC78, 0x00007C1F}, {0xC78, 0x00007D1F}, + {0xC78, 0x00007E1F}, {0xC78, 0x00007F1F}, + + {0xC78, 0x0FA0801F}, {0xC78, 0x0FA0811F}, + {0xC78, 0x0FA0821F}, {0xC78, 0x0FA0831F}, + {0xC78, 0x0FA0841F}, {0xC78, 0x0FA0851F}, + {0xC78, 0x0F90861F}, {0xC78, 0x0F80871F}, + {0xC78, 0x0F70881F}, {0xC78, 0x0F60891F}, + {0xC78, 0x0F508A1F}, {0xC78, 0x0F408B1F}, + {0xC78, 0x0F308C1F}, {0xC78, 0x0F208D1F}, + {0xC78, 0x0F108E1F}, {0xC78, 0x0B908F1F}, + {0xC78, 0x0B80901F}, {0xC78, 0x0B70911F}, + {0xC78, 0x0B60921F}, {0xC78, 0x0B50931F}, + {0xC78, 0x0B40941F}, {0xC78, 0x0B30951F}, + {0xC78, 0x0B20961F}, {0xC78, 0x0B10971F}, + {0xC78, 0x0B00981F}, {0xC78, 0x0AF0991F}, + {0xC78, 0x0AE09A1F}, {0xC78, 0x0AD09B1F}, + {0xC78, 0x0AC09C1F}, {0xC78, 0x0AB09D1F}, + {0xC78, 0x0AA09E1F}, {0xC78, 0x0A909F1F}, + {0xC78, 0x0A80A01F}, {0xC78, 0x0A70A11F}, + {0xC78, 0x0A60A21F}, {0xC78, 0x0A50A31F}, + {0xC78, 0x0A40A41F}, {0xC78, 0x0A30A51F}, + {0xC78, 0x0A20A61F}, {0xC78, 0x0A10A71F}, + {0xC78, 0x0A00A81F}, {0xC78, 0x0830A91F}, + {0xC78, 0x0820AA1F}, {0xC78, 0x0810AB1F}, + {0xC78, 0x0800AC1F}, {0xC78, 0x0640AD1F}, + {0xC78, 0x0630AE1F}, {0xC78, 0x0620AF1F}, + {0xC78, 0x0610B01F}, {0xC78, 0x0600B11F}, + {0xC78, 0x0430B21F}, {0xC78, 0x0420B31F}, + {0xC78, 0x0410B41F}, {0xC78, 0x0400B51F}, + {0xC78, 0x0230B61F}, {0xC78, 0x0220B71F}, + {0xC78, 0x0210B81F}, {0xC78, 0x0200B91F}, + {0xC78, 0x0000BA1F}, {0xC78, 0x0000BB1F}, + {0xC78, 0x0000BC1F}, {0xC78, 0x0000BD1F}, + {0xC78, 0x0000BE1F}, {0xC78, 0x0000BF1F}, + {0xC50, 0x00E48024}, {0xC50, 0x00E48020}, + {0xffff, 0xffffffff} +}; + +static const struct rtl8xxxu_rfregval rtl8192fu_radioa_init_table[] = { + {0x00, 0x30000}, {0x18, 0x0FC07}, {0x81, 0x0FC00}, {0x82, 0x003C0}, + {0x84, 0x00005}, {0x86, 0xA33A5}, {0x87, 0x00000}, {0x88, 0x58010}, + {0x8E, 0x64540}, {0x8F, 0x282D8}, {0x51, 0x02C06}, {0x52, 0x7A007}, + {0x53, 0x10061}, {0x54, 0x60018}, {0x55, 0x82020}, {0x56, 0x08CC6}, + {0x57, 0x2CC00}, {0x58, 0x00000}, {0x5A, 0x50000}, {0x5B, 0x00006}, + {0x5C, 0x00015}, {0x65, 0x20000}, {0x6E, 0x38319}, {0xF5, 0x43180}, + {0xEF, 0x00002}, {0x33, 0x00301}, {0x33, 0x1032A}, {0x33, 0x2032A}, + {0xEF, 0x00000}, {0xDF, 0x00002}, {0x35, 0x00000}, {0xF0, 0x08008}, + {0xEF, 0x00800}, {0x33, 0x0040E}, {0x33, 0x04845}, {0x33, 0x08848}, + {0x33, 0x0C84B}, {0x33, 0x1088A}, {0x33, 0x14C50}, {0x33, 0x18C8E}, + {0x33, 0x1CCCD}, {0x33, 0x20CD0}, {0x33, 0x24CD3}, {0x33, 0x28CD6}, + {0x33, 0x4002B}, {0x33, 0x4402E}, {0x33, 0x48846}, {0x33, 0x4C849}, + {0x33, 0x50888}, {0x33, 0x54CC6}, {0x33, 0x58CC9}, {0x33, 0x5CCCC}, + {0x33, 0x60CCF}, {0x33, 0x64CD2}, {0x33, 0x68CD5}, {0xEF, 0x00000}, + {0xEF, 0x00400}, {0x33, 0x01C23}, {0x33, 0x05C23}, {0x33, 0x09D23}, + {0x33, 0x0DD23}, {0x33, 0x11FA3}, {0x33, 0x15FA3}, {0x33, 0x19FAB}, + {0x33, 0x1DFAB}, {0xEF, 0x00000}, {0xEF, 0x00200}, {0x33, 0x00030}, + {0x33, 0x04030}, {0x33, 0x08030}, {0x33, 0x0C030}, {0x33, 0x10030}, + {0x33, 0x14030}, {0x33, 0x18030}, {0x33, 0x1C030}, {0x33, 0x20030}, + {0x33, 0x24030}, {0x33, 0x28030}, {0x33, 0x2C030}, {0x33, 0x30030}, + {0x33, 0x34030}, {0x33, 0x38030}, {0x33, 0x3C030}, {0xEF, 0x00000}, + {0xEF, 0x00100}, {0x33, 0x44001}, {0x33, 0x48001}, {0x33, 0x4C001}, + {0x33, 0x50001}, {0x33, 0x54001}, {0x33, 0x58001}, {0x33, 0x5C001}, + {0x33, 0x60001}, {0x33, 0x64001}, {0x33, 0x68001}, {0x33, 0x6C001}, + {0x33, 0x70001}, {0x33, 0x74001}, {0x33, 0x78001}, {0x33, 0x04000}, + {0x33, 0x08000}, {0x33, 0x0C000}, {0x33, 0x10000}, {0x33, 0x14000}, + {0x33, 0x18001}, {0x33, 0x1C002}, {0x33, 0x20002}, {0x33, 0x24002}, + {0x33, 0x28002}, {0x33, 0x2C002}, {0x33, 0x30002}, {0x33, 0x34002}, + {0x33, 0x38002}, {0xEF, 0x00000}, {0x84, 0x00000}, {0xEF, 0x80010}, + {0x30, 0x20000}, {0x31, 0x0006F}, {0x32, 0x01FF7}, {0xEF, 0x00000}, + {0x84, 0x00000}, {0xEF, 0x80000}, {0x30, 0x30000}, {0x31, 0x0006F}, + {0x32, 0xF1DF3}, {0xEF, 0x00000}, {0x84, 0x00000}, {0xEF, 0x80000}, + {0x30, 0x38000}, {0x31, 0x0006F}, {0x32, 0xF1FF2}, {0xEF, 0x00000}, + {0x1B, 0x746CE}, {0xEF, 0x20000}, {0x33, 0x30000}, {0x33, 0x38000}, + {0x33, 0x70000}, {0x33, 0x78000}, {0xEF, 0x00000}, {0xDF, 0x08000}, + {0xB0, 0xFFBCB}, {0xB3, 0x06000}, {0xB7, 0x18DF0}, {0xB8, 0x38FF0}, + {0xC9, 0x00600}, {0xDF, 0x00000}, {0xB1, 0x33B8F}, {0xB2, 0x33762}, + {0xB4, 0x141F0}, {0xB5, 0x14080}, {0xB6, 0x12425}, {0xB9, 0xC0008}, + {0xBA, 0x40005}, {0xC2, 0x02C01}, {0xC3, 0x0000B}, {0xC4, 0x81E2F}, + {0xC5, 0x5C28F}, {0xC6, 0x000A0}, {0xCA, 0x02000}, {0xFE, 0x00000}, + {0x18, 0x08C07}, {0xFE, 0x00000}, {0xFE, 0x00000}, {0xFE, 0x00000}, + {0x00, 0x31DD5}, + {0xff, 0xffffffff} +}; + +static const struct rtl8xxxu_rfregval rtl8192fu_radiob_init_table[] = { + {0x00, 0x30000}, {0x81, 0x0FC00}, {0x82, 0x003C0}, {0x84, 0x00005}, + {0x86, 0xA33A5}, {0x87, 0x00000}, {0x88, 0x58010}, {0x8E, 0x64540}, + {0x8F, 0x282D8}, {0x51, 0x02C06}, {0x52, 0x7A007}, {0x53, 0x10061}, + {0x54, 0x60018}, {0x55, 0x82020}, {0x56, 0x08CC6}, {0x57, 0x2CC00}, + {0x58, 0x00000}, {0x5A, 0x50000}, {0x5B, 0x00006}, {0x5C, 0x00015}, + {0x65, 0x20000}, {0x6E, 0x38319}, {0xF5, 0x43180}, {0xEF, 0x00002}, + {0x33, 0x00301}, {0x33, 0x1032A}, {0x33, 0x2032A}, {0xEF, 0x00000}, + {0xDF, 0x00002}, {0x35, 0x00000}, {0xF0, 0x08008}, {0xEF, 0x00800}, + {0x33, 0x0040E}, {0x33, 0x04845}, {0x33, 0x08848}, {0x33, 0x0C84B}, + {0x33, 0x1088A}, {0x33, 0x14CC8}, {0x33, 0x18CCB}, {0x33, 0x1CCCE}, + {0x33, 0x20CD1}, {0x33, 0x24CD4}, {0x33, 0x28CD7}, {0x33, 0x4002B}, + {0x33, 0x4402E}, {0x33, 0x48846}, {0x33, 0x4C849}, {0x33, 0x50888}, + {0x33, 0x54CC6}, {0x33, 0x58CC9}, {0x33, 0x5CCCC}, {0x33, 0x60CCF}, + {0x33, 0x64CD2}, {0x33, 0x68CD5}, {0xEF, 0x00000}, {0xEF, 0x00400}, + {0x33, 0x01D23}, {0x33, 0x05D23}, {0x33, 0x09FA3}, {0x33, 0x0DFA3}, + {0x33, 0x11D2B}, {0x33, 0x15D2B}, {0x33, 0x19FAB}, {0x33, 0x1DFAB}, + {0xEF, 0x00000}, {0xEF, 0x00200}, {0x33, 0x00030}, {0x33, 0x04030}, + {0x33, 0x08030}, {0x33, 0x0C030}, {0x33, 0x10030}, {0x33, 0x14030}, + {0x33, 0x18030}, {0x33, 0x1C030}, {0x33, 0x20030}, {0x33, 0x24030}, + {0x33, 0x28030}, {0x33, 0x2C030}, {0x33, 0x30030}, {0x33, 0x34030}, + {0x33, 0x38030}, {0x33, 0x3C030}, {0xEF, 0x00000}, {0xEF, 0x00100}, + {0x33, 0x44000}, {0x33, 0x48000}, {0x33, 0x4C000}, {0x33, 0x50000}, + {0x33, 0x54000}, {0x33, 0x58000}, {0x33, 0x5C000}, {0x33, 0x60000}, + {0x33, 0x64000}, {0x33, 0x68000}, {0x33, 0x6C000}, {0x33, 0x70000}, + {0x33, 0x74000}, {0x33, 0x78000}, {0x33, 0x04000}, {0x33, 0x08000}, + {0x33, 0x0C000}, {0x33, 0x10000}, {0x33, 0x14000}, {0x33, 0x18000}, + {0x33, 0x1C001}, {0x33, 0x20001}, {0x33, 0x24001}, {0x33, 0x28001}, + {0x33, 0x2C001}, {0x33, 0x30001}, {0x33, 0x34001}, {0x33, 0x38001}, + {0xEF, 0x00000}, {0x84, 0x00000}, {0xEF, 0x80010}, {0x30, 0x20000}, + {0x31, 0x0006F}, {0x32, 0x01FF7}, {0xEF, 0x00000}, {0x84, 0x00000}, + {0xEF, 0x80000}, {0x30, 0x30000}, {0x31, 0x0006F}, {0x32, 0xF1DF3}, + {0xEF, 0x00000}, {0x84, 0x00000}, {0xEF, 0x80000}, {0x30, 0x38000}, + {0x31, 0x0006F}, {0x32, 0xF1FF2}, {0xEF, 0x00000}, {0x1B, 0x746CE}, + {0xEF, 0x20000}, {0x33, 0x30000}, {0x33, 0x38000}, {0x33, 0x70000}, + {0x33, 0x78000}, {0xEF, 0x00000}, {0x00, 0x31DD5}, + {0xff, 0xffffffff} +}; + +static int rtl8192fu_identify_chip(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u32 sys_cfg, vendor, val32; + + strscpy(priv->chip_name, "8192FU", sizeof(priv->chip_name)); + priv->rtl_chip = RTL8192F; + priv->rf_paths = 2; + priv->rx_paths = 2; + priv->tx_paths = 2; + + sys_cfg = rtl8xxxu_read32(priv, REG_SYS_CFG); + priv->chip_cut = u32_get_bits(sys_cfg, SYS_CFG_CHIP_VERSION_MASK); + if (sys_cfg & SYS_CFG_TRP_VAUX_EN) { + dev_info(dev, "Unsupported test chip\n"); + return -EOPNOTSUPP; + } + + val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL); + priv->has_wifi = u32_get_bits(val32, MULTI_WIFI_FUNC_EN); + priv->has_bluetooth = u32_get_bits(val32, MULTI_BT_FUNC_EN); + priv->has_gps = u32_get_bits(val32, MULTI_GPS_FUNC_EN); + priv->is_multi_func = 1; + + vendor = sys_cfg & SYS_CFG_VENDOR_ID; + rtl8xxxu_identify_vendor_1bit(priv, vendor); + + val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS); + priv->rom_rev = u32_get_bits(val32, GPIO_RF_RL_ID); + + return rtl8xxxu_config_endpoints_no_sie(priv); +} + +static void +rtl8192f_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) +{ + u8 cck, ofdmbase, mcsbase; + u32 val32, ofdm, mcs; + int group, cck_group; + + rtl8188f_channel_to_group(channel, &group, &cck_group); + + cck = priv->cck_tx_power_index_A[cck_group]; + + rtl8xxxu_write32_mask(priv, REG_TX_AGC_A_CCK1_MCS32, 0x00007f00, cck); + + val32 = (cck << 16) | (cck << 8) | cck; + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, + 0x7f7f7f00, val32); + + ofdmbase = priv->ht40_1s_tx_power_index_A[group]; + ofdmbase += priv->ofdm_tx_power_diff[RF_A].a; + ofdm = ofdmbase | ofdmbase << 8 | ofdmbase << 16 | ofdmbase << 24; + + rtl8xxxu_write32_mask(priv, REG_TX_AGC_A_RATE18_06, 0x7f7f7f7f, ofdm); + rtl8xxxu_write32_mask(priv, REG_TX_AGC_A_RATE54_24, 0x7f7f7f7f, ofdm); + + mcsbase = priv->ht40_1s_tx_power_index_A[group]; + if (ht40) + mcsbase += priv->ht40_tx_power_diff[RF_A].a; + else + mcsbase += priv->ht20_tx_power_diff[RF_A].a; + mcs = mcsbase | mcsbase << 8 | mcsbase << 16 | mcsbase << 24; + + rtl8xxxu_write32_mask(priv, REG_TX_AGC_A_MCS03_MCS00, 0x7f7f7f7f, mcs); + rtl8xxxu_write32_mask(priv, REG_TX_AGC_A_MCS07_MCS04, 0x7f7f7f7f, mcs); + rtl8xxxu_write32_mask(priv, REG_TX_AGC_A_MCS11_MCS08, 0x7f7f7f7f, mcs); + rtl8xxxu_write32_mask(priv, REG_TX_AGC_A_MCS15_MCS12, 0x7f7f7f7f, mcs); + + if (priv->tx_paths == 1) + return; + + cck = priv->cck_tx_power_index_B[cck_group]; + + val32 = (cck << 16) | (cck << 8) | cck; + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_CCK1_55_MCS32, + 0x7f7f7f00, val32); + + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, + 0x0000007f, cck); + + ofdmbase = priv->ht40_1s_tx_power_index_B[group]; + ofdmbase += priv->ofdm_tx_power_diff[RF_B].b; + ofdm = ofdmbase | ofdmbase << 8 | ofdmbase << 16 | ofdmbase << 24; + + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_RATE18_06, 0x7f7f7f7f, ofdm); + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_RATE54_24, 0x7f7f7f7f, ofdm); + + mcsbase = priv->ht40_1s_tx_power_index_B[group]; + if (ht40) + mcsbase += priv->ht40_tx_power_diff[RF_B].b; + else + mcsbase += priv->ht20_tx_power_diff[RF_B].b; + mcs = mcsbase | mcsbase << 8 | mcsbase << 16 | mcsbase << 24; + + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_MCS03_MCS00, 0x7f7f7f7f, mcs); + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_MCS07_MCS04, 0x7f7f7f7f, mcs); + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_MCS11_MCS08, 0x7f7f7f7f, mcs); + rtl8xxxu_write32_mask(priv, REG_TX_AGC_B_MCS15_MCS12, 0x7f7f7f7f, mcs); +} + +static void rtl8192f_revise_cck_tx_psf(struct rtl8xxxu_priv *priv, u8 channel) +{ + if (channel == 13) { + /* Special value for channel 13 */ + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER1, 0xf8fe0001); + /* Normal values */ + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER2, 0x64B80C1C); + rtl8xxxu_write16(priv, REG_CCK0_DEBUG_PORT, 0x8810); + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER3, 0x01235667); + } else if (channel == 14) { + /* Normal value */ + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER1, 0xE82C0001); + /* Special values for channel 14 */ + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER2, 0x0000B81C); + rtl8xxxu_write16(priv, REG_CCK0_DEBUG_PORT, 0x0000); + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER3, 0x00003667); + } else { + /* Restore normal values from the phy init table */ + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER1, 0xE82C0001); + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER2, 0x64B80C1C); + rtl8xxxu_write16(priv, REG_CCK0_DEBUG_PORT, 0x8810); + rtl8xxxu_write32(priv, REG_CCK0_TX_FILTER3, 0x01235667); + } +} + +static void rtl8192fu_config_kfree(struct rtl8xxxu_priv *priv, u8 channel) +{ + u8 bb_gain[3] = { EFUSE_UNDEFINED, EFUSE_UNDEFINED, EFUSE_UNDEFINED }; + u8 bb_gain_path_mask[2] = { 0x0f, 0xf0 }; + enum rtl8xxxu_rfpath rfpath; + u8 bb_gain_for_path; + u8 channel_idx = 0; + + if (channel >= 1 && channel <= 3) + channel_idx = 0; + if (channel >= 4 && channel <= 9) + channel_idx = 1; + if (channel >= 10 && channel <= 14) + channel_idx = 2; + + rtl8xxxu_read_efuse8(priv, 0x1ee, &bb_gain[1]); + rtl8xxxu_read_efuse8(priv, 0x1ec, &bb_gain[0]); + rtl8xxxu_read_efuse8(priv, 0x1ea, &bb_gain[2]); + + if (bb_gain[1] == EFUSE_UNDEFINED) + return; + + if (bb_gain[0] == EFUSE_UNDEFINED) + bb_gain[0] = bb_gain[1]; + + if (bb_gain[2] == EFUSE_UNDEFINED) + bb_gain[2] = bb_gain[1]; + + for (rfpath = RF_A; rfpath < priv->rf_paths; rfpath++) { + /* power_trim based on 55[19:14] */ + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_UNKNOWN_55, + BIT(5), 1); + + /* enable 55[14] for 0.5db step */ + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_GAIN_CTRL, + BIT(18), 1); + + /* enter power_trim debug mode */ + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_UNKNOWN_DF, + BIT(7), 1); + + /* write enable */ + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_WE_LUT, BIT(7), 1); + + bb_gain_for_path = (bb_gain[channel_idx] & bb_gain_path_mask[rfpath]); + bb_gain_for_path >>= __ffs(bb_gain_path_mask[rfpath]); + + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_TXPA_G3, + 0x70000, channel_idx * 2); + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_TXPA_G3, + 0x3f, bb_gain_for_path); + + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_TXPA_G3, + 0x70000, channel_idx * 2 + 1); + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_TXPA_G3, + 0x3f, bb_gain_for_path); + + /* leave power_trim debug mode */ + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_UNKNOWN_DF, + BIT(7), 0); + + /* write disable */ + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_WE_LUT, BIT(7), 0); + } +} + +static void rtl8192fu_config_channel(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + bool ht40 = conf_is_ht40(&hw->conf); + u8 channel, subchannel = 0; + bool sec_ch_above = 0; + u32 val32; + + channel = (u8)hw->conf.chandef.chan->hw_value; + + if (conf_is_ht40_plus(&hw->conf)) { + sec_ch_above = 1; + channel += 2; + subchannel = 2; + } else if (conf_is_ht40_minus(&hw->conf)) { + sec_ch_above = 0; + channel -= 2; + subchannel = 1; + } + + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG); + + rtl8192f_revise_cck_tx_psf(priv, channel); + + /* Set channel */ + val32 &= ~(BIT(18) | BIT(17)); /* select the 2.4G band(?) */ + u32p_replace_bits(&val32, channel, 0xff); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, val32); + if (priv->rf_paths > 1) + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_MODE_AG, val32); + + rtl8192fu_config_kfree(priv, channel); + + rtl8xxxu_write8(priv, REG_DATA_SUBCHANNEL, subchannel); + + /* small BW */ + rtl8xxxu_write32_clear(priv, REG_OFDM0_TX_PSDO_NOISE_WEIGHT, GENMASK(31, 30)); + + rtl8xxxu_write32_mask(priv, REG_FPGA0_RF_MODE, FPGA_RF_MODE, ht40); + rtl8xxxu_write32_mask(priv, REG_FPGA1_RF_MODE, FPGA_RF_MODE, ht40); + + /* ADC clock = 160M */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_RF_MODE, GENMASK(10, 8), 4); + + /* DAC clock = 80M */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_RF_MODE, BIT(13) | BIT(12), 2); + + /* ADC buffer clk */ + rtl8xxxu_write32_mask(priv, REG_ANTDIV_PARA1, BIT(27) | BIT(26), 2); + + if (ht40) + /* Set Control channel to upper or lower. */ + rtl8xxxu_write32_mask(priv, REG_CCK0_SYSTEM, + CCK0_SIDEBAND, !sec_ch_above); + + /* Enable CCK */ + rtl8xxxu_write32_set(priv, REG_FPGA0_RF_MODE, FPGA_RF_MODE_CCK); + + /* RF TRX_BW */ + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG); + val32 &= ~MODE_AG_BW_MASK; + if (ht40) + val32 |= MODE_AG_BW_40MHZ_8723B; + else + val32 |= MODE_AG_BW_20MHZ_8723B; + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, val32); + if (priv->rf_paths > 1) + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_MODE_AG, val32); + + /* Modify RX DFIR parameters */ + rtl8xxxu_write32_mask(priv, REG_TAP_UPD_97F, BIT(21) | BIT(20), 2); + + rtl8xxxu_write32_mask(priv, REG_DOWNSAM_FACTOR, BIT(29) | BIT(28), 2); + + if (ht40) + val32 = 0x3; + else + val32 = 0x1a3; + rtl8xxxu_write32_mask(priv, REG_RX_DFIR_MOD_97F, 0x1ff, val32); +} + +static void rtl8192fu_init_aggregation(struct rtl8xxxu_priv *priv) +{ + u32 agg_rx; + u8 agg_ctrl; + + /* RX aggregation */ + agg_ctrl = rtl8xxxu_read8(priv, REG_TRXDMA_CTRL); + agg_ctrl &= ~TRXDMA_CTRL_RXDMA_AGG_EN; + + agg_rx = rtl8xxxu_read32(priv, REG_RXDMA_AGG_PG_TH); + agg_rx &= ~RXDMA_USB_AGG_ENABLE; + agg_rx &= ~0xFF0F; /* reset agg size and timeout */ + + rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl); + rtl8xxxu_write32(priv, REG_RXDMA_AGG_PG_TH, agg_rx); +} + +static int rtl8192fu_parse_efuse(struct rtl8xxxu_priv *priv) +{ + struct rtl8192fu_efuse *efuse = &priv->efuse_wifi.efuse8192fu; + int i; + + if (efuse->rtl_id != cpu_to_le16(0x8129)) + return -EINVAL; + + ether_addr_copy(priv->mac_addr, efuse->mac_addr); + + memcpy(priv->cck_tx_power_index_A, efuse->tx_power_index_A.cck_base, + sizeof(efuse->tx_power_index_A.cck_base)); + memcpy(priv->cck_tx_power_index_B, efuse->tx_power_index_B.cck_base, + sizeof(efuse->tx_power_index_B.cck_base)); + + memcpy(priv->ht40_1s_tx_power_index_A, + efuse->tx_power_index_A.ht40_base, + sizeof(efuse->tx_power_index_A.ht40_base)); + memcpy(priv->ht40_1s_tx_power_index_B, + efuse->tx_power_index_B.ht40_base, + sizeof(efuse->tx_power_index_B.ht40_base)); + + priv->ht20_tx_power_diff[0].a = + efuse->tx_power_index_A.ht20_ofdm_1s_diff.b; + priv->ht20_tx_power_diff[0].b = + efuse->tx_power_index_B.ht20_ofdm_1s_diff.b; + + priv->ht40_tx_power_diff[0].a = 0; + priv->ht40_tx_power_diff[0].b = 0; + + for (i = 1; i < RTL8723B_TX_COUNT; i++) { + priv->ofdm_tx_power_diff[i].a = + efuse->tx_power_index_A.pwr_diff[i - 1].ofdm; + priv->ofdm_tx_power_diff[i].b = + efuse->tx_power_index_B.pwr_diff[i - 1].ofdm; + + priv->ht20_tx_power_diff[i].a = + efuse->tx_power_index_A.pwr_diff[i - 1].ht20; + priv->ht20_tx_power_diff[i].b = + efuse->tx_power_index_B.pwr_diff[i - 1].ht20; + + priv->ht40_tx_power_diff[i].a = + efuse->tx_power_index_A.pwr_diff[i - 1].ht40; + priv->ht40_tx_power_diff[i].b = + efuse->tx_power_index_B.pwr_diff[i - 1].ht40; + } + + priv->default_crystal_cap = efuse->xtal_k & 0x3f; + + priv->rfe_type = efuse->rfe_option & 0x1f; + + if (priv->rfe_type != 5 && priv->rfe_type != 1) + dev_warn(&priv->udev->dev, + "%s: RFE type %d was not tested. Please send an email to linux-wireless@vger.kernel.org about this.\n", + __func__, priv->rfe_type); + + return 0; +} + +static int rtl8192fu_load_firmware(struct rtl8xxxu_priv *priv) +{ + return rtl8xxxu_load_firmware(priv, "rtlwifi/rtl8192fufw.bin"); +} + +static void rtl8192fu_init_phy_bb(struct rtl8xxxu_priv *priv) +{ + /* Enable BB and RF */ + rtl8xxxu_write16_set(priv, REG_SYS_FUNC, + SYS_FUNC_BBRSTB | SYS_FUNC_BB_GLB_RSTN); + + rtl8xxxu_write8(priv, REG_RF_CTRL, RF_ENABLE | RF_RSTB | RF_SDMRSTB); + + /* To Fix MAC loopback mode fail. */ + rtl8xxxu_write8(priv, REG_LDOHCI12_CTRL, 0xf); + rtl8xxxu_write8(priv, REG_SYS_SWR_CTRL2 + 1, 0xe9); + + rtl8xxxu_init_phy_regs(priv, rtl8192fu_phy_init_table); + + rtl8xxxu_init_phy_regs(priv, rtl8192f_agc_table); +} + +static int rtl8192fu_init_phy_rf(struct rtl8xxxu_priv *priv) +{ + int ret; + + ret = rtl8xxxu_init_phy_rf(priv, rtl8192fu_radioa_init_table, RF_A); + if (ret) + return ret; + + return rtl8xxxu_init_phy_rf(priv, rtl8192fu_radiob_init_table, RF_B); +} + +static void rtl8192f_phy_lc_calibrate(struct rtl8xxxu_priv *priv) +{ + u32 backup_mask = BIT(31) | BIT(30); + u32 backup; + u32 val32; + + /* Aries's NarrowBand */ + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TX_PSDO_NOISE_WEIGHT); + backup = u32_get_bits(val32, backup_mask); + + u32p_replace_bits(&val32, 0, backup_mask); + rtl8xxxu_write32(priv, REG_OFDM0_TX_PSDO_NOISE_WEIGHT, val32); + + rtl8188f_phy_lc_calibrate(priv); + + /* Aries's NarrowBand */ + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TX_PSDO_NOISE_WEIGHT); + u32p_replace_bits(&val32, backup, backup_mask); + rtl8xxxu_write32(priv, REG_OFDM0_TX_PSDO_NOISE_WEIGHT, val32); + + /* reset OFDM state */ + rtl8xxxu_write32_clear(priv, REG_FPGA0_RF_MODE, FPGA_RF_MODE_OFDM); + rtl8xxxu_write32_set(priv, REG_FPGA0_RF_MODE, FPGA_RF_MODE_OFDM); +} + +static int rtl8192fu_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_e94, reg_e9c, val32; + u32 rf_0x58_i, rf_0x58_q; + u8 rfe = priv->rfe_type; + int result = 0; + int ktime, i; + + /* Leave IQK mode */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xccf000c0); + rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44ffbb44); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00400040); + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x6f005403); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000804e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x04203400); + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); + + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(4), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(11), 1); + if (rfe == 7 || rfe == 8 || rfe == 9 || rfe == 12) + val32 = 0x30; + else + val32 = 0xe9; + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x003ff, val32); + + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x18008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x8214000f); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28140000); + + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00e62911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa005800); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8005800); + + mdelay(15); + + ktime = 0; + while (rtl8xxxu_read32(priv, REG_IQK_RPT_TXA) == 0 && ktime < 21) { + mdelay(5); + ktime += 5; + } + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + + /* reload 0xdf and CCK_IND off */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_WE_LUT, BIT(4), 1); + + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_TXMOD); + rf_0x58_i = u32_get_bits(val32, 0xfc000); + rf_0x58_q = u32_get_bits(val32, 0x003f0); + + for (i = 0; i < 8; i++) { + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_TXPA_G3, + 0x1c000, i); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_TXPA_G3, + 0x00fc0, rf_0x58_i); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_TXPA_G3, + 0x0003f, rf_0x58_q); + } + + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_AC, BIT(14), 0); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_WE_LUT, BIT(4), 0); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00810, 0); + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000)) + result |= 0x01; + + return result; +} + +static int rtl8192fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) +{ + u32 reg_ea4, reg_eac, reg_e94, reg_e9c, val32; + int result = 0; + int ktime; + + /* Leave IQK mode */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + /* PA/PAD control by 0x56, and set = 0x0 */ + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(1), 1); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_P1, 0); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x003ff, 0x27); + + /* Enter IQK mode */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x18008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160027); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160000); + + /* Tx IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0086a911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa005800); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8005800); + + mdelay(15); + + ktime = 0; + while (rtl8xxxu_read32(priv, REG_IQK_RPT_TXA) == 0 && ktime < 21) { + mdelay(5); + ktime += 5; + } + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + + if (!(reg_eac & BIT(28)) && + ((reg_e94 & 0x03ff0000) != 0x01420000) && + ((reg_e9c & 0x03ff0000) != 0x00420000)) { + result |= 0x01; + } else { /* If TX not OK, ignore RX */ + /* PA/PAD controlled by 0x0 */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, + BIT(11), 0); + + return result; + } + + val32 = 0x80007c00 | (reg_e94 & 0x3ff0000) | ((reg_e9c & 0x3ff0000) >> 16); + rtl8xxxu_write32(priv, REG_TX_IQK, val32); + + /* Modify RX IQK mode table */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + /* PA/PAD control by 0x56, and set = 0x0 */ + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(1), 1); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_P1, 0); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x003ff, 0x1e0); + + rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xccf000c0); + rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44ffbb44); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00400040); + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x6f005403); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000804e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x04203400); + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); + + /* Enter IQK mode */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); + + /* path-A IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x18008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82170000); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28170000); + + /* RX IQK setting */ + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a8d1); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa005800); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8005800); + + mdelay(15); + + ktime = 0; + while (rtl8xxxu_read32(priv, REG_IQK_RPT_RXA) == 0 && ktime < 21) { + mdelay(5); + ktime += 5; + } + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2); + + /* Leave IQK mode */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(11), 0); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_P1, 0x02000); + + if (!(reg_eac & BIT(27)) && + ((reg_ea4 & 0x03ff0000) != 0x01320000) && + ((reg_eac & 0x03ff0000) != 0x00360000)) + result |= 0x02; + + return result; +} + +static int rtl8192fu_iqk_path_b(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_eb4, reg_ebc, val32; + u32 rf_0x58_i, rf_0x58_q; + u8 rfe = priv->rfe_type; + int result = 0; + int ktime, i; + + /* PA/PAD controlled by 0x0 */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xccf000c0); + rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44ffbb44); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00400040); + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x6f005403); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000804e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x04203400); + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000000); + + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(4), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(11), 1); + if (rfe == 7 || rfe == 8 || rfe == 9 || rfe == 12) + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_56, + 0x003ff, 0x30); + else + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_56, + 0x00fff, 0xe9); + + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); + + /* Path B IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x18008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x8214000F); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28140000); + + rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00); + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00e62911); + + /* One shot, path B LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa005800); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8005800); + + mdelay(15); + + ktime = 0; + while (rtl8xxxu_read32(priv, REG_IQK_RPT_TXB) == 0 && ktime < 21) { + mdelay(5); + ktime += 5; + } + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B); + reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B); + + /* reload 0xdf and CCK_IND off */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_WE_LUT, BIT(4), 1); + + val32 = rtl8xxxu_read_rfreg(priv, RF_B, RF6052_REG_TXMOD); + rf_0x58_i = u32_get_bits(val32, 0xfc000); + rf_0x58_q = u32_get_bits(val32, 0x003f0); + + for (i = 0; i < 8; i++) { + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_TXPA_G3, + 0x1c000, i); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_TXPA_G3, + 0x00fc0, rf_0x58_i); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_TXPA_G3, + 0x0003f, rf_0x58_q); + } + + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_AC, BIT(14), 0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_WE_LUT, BIT(4), 0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00810, 0); + + if (!(reg_eac & BIT(31)) && + ((reg_eb4 & 0x03ff0000) != 0x01420000) && + ((reg_ebc & 0x03ff0000) != 0x00420000)) + result |= 0x01; + else + dev_warn(&priv->udev->dev, "%s: Path B IQK failed!\n", + __func__); + + return result; +} + +static int rtl8192fu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) +{ + u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc, val32; + int result = 0; + int ktime; + + /* Leave IQK mode */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(1), 1); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_P1, 0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x003ff, 0x67); + + rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xccf000c0); + rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44ffbb44); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00400040); + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x6f005403); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000804e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x04203400); + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000000); + + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); + + /* path-B IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x18008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82160027); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28160000); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0086a911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa005800); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8005800); + + mdelay(15); + + ktime = 0; + while (rtl8xxxu_read32(priv, REG_IQK_RPT_TXB) == 0 && ktime < 21) { + mdelay(5); + ktime += 5; + } + + /* Check failed */ + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B); + reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B); + + if (!(reg_eac & BIT(31)) && + ((reg_eb4 & 0x03ff0000) != 0x01420000) && + ((reg_ebc & 0x03ff0000) != 0x00420000)) { + result |= 0x01; + } else { + /* PA/PAD controlled by 0x0 */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, + BIT(11), 0); + + return result; + } + + val32 = 0x80007c00 | (reg_eb4 & 0x03ff0000) | ((reg_ebc >> 16) & 0x03ff); + rtl8xxxu_write32(priv, REG_TX_IQK, val32); + + /* Modify RX IQK mode table */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(1), 1); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_P1, 0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x003ff, 0x1e0); + + rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xccf000c0); + rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44ffbb44); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00400040); + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x6f005403); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000804e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x04203400); + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000000); + + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); + + /* Path B IQK setting */ + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c); + rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c); + rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x18008c1c); + + rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82170000); + rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28170000); + + /* IQK setting */ + rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800); + + /* LO calibration setting */ + rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911); + + /* One shot, path A LOK & IQK */ + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa005800); + rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8005800); + + mdelay(15); + + ktime = 0; + while (rtl8xxxu_read32(priv, REG_IQK_RPT_RXB) == 0 && ktime < 21) { + mdelay(5); + ktime += 5; + } + + reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2); + reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2); + + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); + + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(11), 0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(1), 0); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_P1, 0x02000); + + if (!(reg_eac & BIT(30)) && + ((reg_ec4 & 0x03ff0000) != 0x01320000) && + ((reg_ecc & 0x03ff0000) != 0x00360000)) + result |= 0x02; + else + dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n", + __func__); + + return result; +} + +static void rtl8192fu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, + int result[][8], int t) +{ + static const u32 adda_regs[2] = { + REG_ANAPWR1, REG_RX_WAIT_CCA + }; + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + REG_TXPAUSE, REG_BEACON_CTRL, + REG_BEACON_CTRL_1, REG_GPIO_MUXCFG + }; + static const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR, + REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, + REG_DPDT_CTRL, REG_RFE_CTRL_ANTA_SRC, + REG_RFE_CTRL_ANT_SRC2, REG_CCK0_AFE_SETTING + }; + u32 rx_initial_gain_a, rx_initial_gain_b; + struct device *dev = &priv->udev->dev; + int path_a_ok, path_b_ok; + u8 rfe = priv->rfe_type; + int retry = 2; + u32 i, val32; + + /* + * Note: IQ calibration must be performed after loading + * PHY_REG.txt , and radio_a, radio_b.txt + */ + + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rx_initial_gain_a = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1); + rx_initial_gain_b = rtl8xxxu_read32(priv, REG_OFDM0_XB_AGC_CORE1); + + if (t == 0) { + /* Save ADDA parameters, turn Path A ADDA on */ + rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup, + ARRAY_SIZE(adda_regs)); + rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + rtl8xxxu_save_regs(priv, iqk_bb_regs, + priv->bb_backup, RTL8XXXU_BB_REGS); + } + + /* Instead of rtl8xxxu_path_adda_on */ + rtl8xxxu_write32_set(priv, REG_FPGA0_XCD_RF_PARM, BIT(31)); + + /* MAC settings */ + rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff); + rtl8xxxu_write8_clear(priv, REG_GPIO_MUXCFG, GPIO_MUXCFG_IO_SEL_ENBT); + + if (rfe == 7 || rfe == 8 || rfe == 9 || rfe == 12) { + /* in ePA IQK, rfe_func_config & SW both pull down */ + /* path A */ + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANTA_SRC, 0xF, 0x7); + rtl8xxxu_write32_mask(priv, REG_DPDT_CTRL, 0x1, 0x0); + + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANTA_SRC, 0xF00, 0x7); + rtl8xxxu_write32_mask(priv, REG_DPDT_CTRL, 0x4, 0x0); + + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANTA_SRC, 0xF000, 0x7); + rtl8xxxu_write32_mask(priv, REG_DPDT_CTRL, 0x8, 0x0); + + /* path B */ + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC2, 0xF0, 0x7); + rtl8xxxu_write32_mask(priv, REG_DPDT_CTRL, 0x20000, 0x0); + + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC2, 0xF0000, 0x7); + rtl8xxxu_write32_mask(priv, REG_DPDT_CTRL, 0x100000, 0x0); + + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC3, 0xF000, 0x7); + rtl8xxxu_write32_mask(priv, REG_DPDT_CTRL, 0x8000000, 0x0); + } + + if (priv->rf_paths > 1) { + /* path B standby */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x000000); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0x10000); + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); + } + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8192fu_iqk_path_a(priv); + + if (path_a_ok == 0x01) { + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A); + result[t][0] = (val32 >> 16) & 0x3ff; + + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A); + result[t][1] = (val32 >> 16) & 0x3ff; + break; + } else { + result[t][0] = 0x100; + result[t][1] = 0x0; + } + } + + for (i = 0; i < retry; i++) { + path_a_ok = rtl8192fu_rx_iqk_path_a(priv); + + if (path_a_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2); + result[t][2] = (val32 >> 16) & 0x3ff; + + val32 = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); + result[t][3] = (val32 >> 16) & 0x3ff; + break; + } else { + result[t][2] = 0x100; + result[t][3] = 0x0; + } + } + + if (!path_a_ok) + dev_warn(dev, "%s: Path A IQK failed!\n", __func__); + + if (priv->rf_paths > 1) { + for (i = 0; i < retry; i++) { + path_b_ok = rtl8192fu_iqk_path_b(priv); + + if (path_b_ok == 0x01) { + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B); + result[t][4] = (val32 >> 16) & 0x3ff; + + val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B); + result[t][5] = (val32 >> 16) & 0x3ff; + break; + } else { + result[t][4] = 0x100; + result[t][5] = 0x0; + } + } + + for (i = 0; i < retry; i++) { + path_b_ok = rtl8192fu_rx_iqk_path_b(priv); + + if (path_b_ok == 0x03) { + val32 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2); + result[t][6] = (val32 >> 16) & 0x3ff; + + val32 = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2); + result[t][7] = (val32 >> 16) & 0x3ff; + break; + } else { + result[t][6] = 0x100; + result[t][7] = 0x0; + } + } + + if (!path_b_ok) + dev_warn(dev, "%s: Path B IQK failed!\n", __func__); + } + + /* Back to BB mode, load original value */ + rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); + + rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xcc0000c0); + + rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44bbbb44); + rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x80408040); + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x6f005433); + rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000004e4); + rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x04003400); + rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); + + /* Reload ADDA power saving parameters */ + rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup, + ARRAY_SIZE(adda_regs)); + + /* Reload MAC parameters */ + rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup); + + /* Reload BB parameters */ + rtl8xxxu_restore_regs(priv, iqk_bb_regs, priv->bb_backup, RTL8XXXU_BB_REGS); + + rtl8xxxu_write32_clear(priv, REG_FPGA0_XCD_RF_PARM, BIT(31)); + + /* Restore RX initial gain */ + rtl8xxxu_write32_mask(priv, REG_OFDM0_XA_AGC_CORE1, 0xff, 0x50); + rtl8xxxu_write32_mask(priv, REG_OFDM0_XA_AGC_CORE1, 0xff, + rx_initial_gain_a & 0xff); + if (priv->rf_paths > 1) { + rtl8xxxu_write32_mask(priv, REG_OFDM0_XB_AGC_CORE1, 0xff, 0x50); + rtl8xxxu_write32_mask(priv, REG_OFDM0_XB_AGC_CORE1, 0xff, + rx_initial_gain_b & 0xff); + } +} + +static void rtl8192fu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) +{ + s32 reg_e94, reg_e9c, reg_ea4, reg_eac; + s32 reg_eb4, reg_ebc, reg_ec4, reg_ecc; + struct device *dev = &priv->udev->dev; + u32 path_a_0xdf, path_a_0x35; + u32 path_b_0xdf, path_b_0x35; + bool path_a_ok, path_b_ok; + u8 rfe = priv->rfe_type; + u32 rfe_path_select; + int result[4][8]; /* last is final result */ + int i, candidate; + s32 reg_tmp = 0; + bool simu; + u32 val32; + + rfe_path_select = rtl8xxxu_read32(priv, REG_RFE_PATH_SELECT); + + path_a_0xdf = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF); + path_a_0x35 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_P1); + path_b_0xdf = rtl8xxxu_read_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF); + path_b_0x35 = rtl8xxxu_read_rfreg(priv, RF_B, RF6052_REG_GAIN_P1); + + memset(result, 0, sizeof(result)); + candidate = -1; + + path_a_ok = false; + path_b_ok = false; + + for (i = 0; i < 3; i++) { + rtl8192fu_phy_iqcalibrate(priv, result, i); + + if (i == 1) { + simu = rtl8xxxu_gen2_simularity_compare(priv, result, 0, 1); + if (simu) { + candidate = 0; + break; + } + } + + if (i == 2) { + simu = rtl8xxxu_gen2_simularity_compare(priv, result, 0, 2); + if (simu) { + candidate = 0; + break; + } + + simu = rtl8xxxu_gen2_simularity_compare(priv, result, 1, 2); + if (simu) { + candidate = 1; + } else { + for (i = 0; i < 8; i++) + reg_tmp += result[3][i]; + + if (reg_tmp) + candidate = 3; + else + candidate = -1; + } + } + } + + if (candidate >= 0) { + reg_e94 = result[candidate][0]; + reg_e9c = result[candidate][1]; + reg_ea4 = result[candidate][2]; + reg_eac = result[candidate][3]; + reg_eb4 = result[candidate][4]; + reg_ebc = result[candidate][5]; + reg_ec4 = result[candidate][6]; + reg_ecc = result[candidate][7]; + + dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate); + dev_dbg(dev, "%s: e94=%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x ecc=%c\n", + __func__, reg_e94, reg_e9c, reg_ea4, reg_eac, + reg_eb4, reg_ebc, reg_ec4, reg_ecc); + + path_a_ok = true; + path_b_ok = true; + } + + rtl8xxxu_write32_mask(priv, REG_TX_IQK_TONE_A, 0x3ff00000, 0x100); + rtl8xxxu_write32_mask(priv, REG_NP_ANTA, 0x3ff, 0); + rtl8xxxu_write32_mask(priv, REG_TX_IQK_TONE_B, 0x3ff00000, 0x100); + rtl8xxxu_write32_mask(priv, REG_TAP_UPD_97F, 0x3ff, 0); + + if (candidate >= 0) { + if (reg_e94) + rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result, + candidate, (reg_ea4 == 0)); + + if (reg_eb4) + rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result, + candidate, (reg_ec4 == 0)); + } + + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, path_a_0xdf); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_P1, path_a_0x35); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, path_b_0xdf); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_P1, path_b_0x35); + + if (rfe == 7 || rfe == 8 || rfe == 9 || rfe == 12) { + rtl8xxxu_write32_set(priv, REG_SW_GPIO_SHARE_CTRL_1, 0x70000); + rtl8xxxu_write32_clear(priv, REG_LEDCFG0, 0x6c00000); + rtl8xxxu_write32_set(priv, REG_PAD_CTRL1, BIT(29) | BIT(28)); + rtl8xxxu_write32_clear(priv, REG_SW_GPIO_SHARE_CTRL_0, + 0x600000 | BIT(4)); + + /* + * Originally: + * odm_set_bb_reg(dm, R_0x944, BIT(11) | 0x1F, 0x3F); + * + * It clears bit 11 and sets bits 0..4. The mask doesn't cover + * bit 5 so it's not modified. Is that what it's supposed to + * accomplish? + */ + val32 = rtl8xxxu_read32(priv, REG_RFE_BUFFER); + val32 &= ~BIT(11); + val32 |= 0x1f; + rtl8xxxu_write32(priv, REG_RFE_BUFFER, val32); + + if (rfe == 7) { + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANTA_SRC, + 0xfffff, 0x23200); + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC2, + 0xfffff, 0x23200); + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC1, + 0xf000, 0x3); + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC3, + 0xf000, 0x3); + } else { + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANTA_SRC, + 0xfffff, 0x22200); + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC2, + 0xfffff, 0x22200); + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC1, + 0xf000, 0x2); + rtl8xxxu_write32_mask(priv, REG_RFE_CTRL_ANT_SRC3, + 0xf000, 0x2); + } + + rtl8xxxu_write32_clear(priv, REG_RFE_OPT62, BIT(2)); + + if (rfe == 7) + rtl8xxxu_write32(priv, REG_RFE_OPT, 0x03000003); + + rtl8xxxu_write32(priv, REG_RFE_PATH_SELECT, rfe_path_select); + } +} + +static void rtl8192fu_disabled_to_emu(struct rtl8xxxu_priv *priv) +{ + rtl8xxxu_write16_clear(priv, REG_APS_FSMCO, + APS_FSMCO_HW_POWERDOWN | APS_FSMCO_HW_SUSPEND); + + rtl8xxxu_write32_clear(priv, REG_GPIO_INTM, BIT(16)); + + rtl8xxxu_write16_clear(priv, REG_APS_FSMCO, + APS_FSMCO_PCIE | APS_FSMCO_HW_SUSPEND); +} + +static int rtl8192fu_emu_to_active(struct rtl8xxxu_priv *priv) +{ + u32 val32; + u16 val16; + int count; + + /* enable LDOA12 MACRO block for all interface */ + rtl8xxxu_write8_set(priv, REG_LDOA15_CTRL, LDOA15_ENABLE); + + /* disable BT_GPS_SEL pins */ + rtl8xxxu_write32_clear(priv, REG_PAD_CTRL1, BIT(28)); + + mdelay(1); + + /* release analog Ips to digital */ + rtl8xxxu_write8_clear(priv, REG_SYS_ISO_CTRL, SYS_ISO_ANALOG_IPS); + + val16 = APS_FSMCO_PCIE | APS_FSMCO_HW_SUSPEND | APS_FSMCO_SW_LPS; + rtl8xxxu_write16_clear(priv, REG_APS_FSMCO, val16); + + /* wait till 0x04[17] = 1 power ready */ + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if (val32 & BIT(17)) + break; + + udelay(10); + } + + if (!count) + return -EBUSY; + + rtl8xxxu_write32_set(priv, REG_APS_FSMCO, APS_FSMCO_WLON_RESET); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if ((val32 & (APS_FSMCO_MAC_ENABLE | APS_FSMCO_MAC_OFF)) == 0) + break; + + udelay(10); + } + + if (!count) + return -EBUSY; + + /* SWR OCP enable */ + rtl8xxxu_write32_set(priv, REG_AFE_MISC, BIT(18)); + + rtl8xxxu_write16_clear(priv, REG_APS_FSMCO, APS_FSMCO_HW_POWERDOWN); + + rtl8xxxu_write16_clear(priv, REG_APS_FSMCO, + APS_FSMCO_PCIE | APS_FSMCO_HW_SUSPEND); + + /* 0x7c[31]=1, LDO has max output capability */ + rtl8xxxu_write32_set(priv, REG_LDO_SW_CTRL, BIT(31)); + + rtl8xxxu_write16_set(priv, REG_APS_FSMCO, APS_FSMCO_MAC_ENABLE); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) + break; + + udelay(10); + } + + if (!count) + return -EBUSY; + + /* Enable WL control XTAL setting */ + rtl8xxxu_write8_set(priv, REG_AFE_MISC, AFE_MISC_WL_XTAL_CTRL); + + /* Enable falling edge triggering interrupt */ + rtl8xxxu_write16_set(priv, REG_GPIO_INTM, GPIO_INTM_EDGE_TRIG_IRQ); + + /* Enable GPIO9 data mode */ + rtl8xxxu_write16_clear(priv, REG_GPIO_IO_SEL_2, GPIO_IO_SEL_2_GPIO09_IRQ); + + /* Enable GPIO9 input mode */ + rtl8xxxu_write16_clear(priv, REG_GPIO_IO_SEL_2, GPIO_IO_SEL_2_GPIO09_INPUT); + + /* Enable HSISR GPIO[C:0] interrupt */ + rtl8xxxu_write8_set(priv, REG_HSIMR, BIT(0)); + + /* RF HW ON/OFF Enable */ + rtl8xxxu_write8_clear(priv, REG_MULTI_FUNC_CTRL, MULTI_WIFI_HW_ROF_EN); + + /* Register Lock Disable */ + rtl8xxxu_write8_set(priv, REG_RSV_CTRL, BIT(7)); + + /* For GPIO9 internal pull high setting */ + rtl8xxxu_write16_set(priv, REG_MULTI_FUNC_CTRL, BIT(14)); + + /* reset RF path S1 */ + rtl8xxxu_write8(priv, REG_RF_CTRL, 0); + + /* reset RF path S0 */ + rtl8xxxu_write8(priv, REG_AFE_CTRL4 + 3, 0); + + /* enable RF path S1 */ + rtl8xxxu_write8(priv, REG_RF_CTRL, RF_SDMRSTB | RF_RSTB | RF_ENABLE); + + /* enable RF path S0 */ + rtl8xxxu_write8(priv, REG_AFE_CTRL4 + 3, RF_SDMRSTB | RF_RSTB | RF_ENABLE); + + /* AFE_Ctrl */ + rtl8xxxu_write8_set(priv, REG_RSVD_1, BIT(5)); + + /* AFE_Ctrl */ + rtl8xxxu_write8(priv, REG_RSVD_4, 0xcc); + + /* AFE_Ctrl 0x24[4:3]=00 for xtal gmn */ + rtl8xxxu_write8_clear(priv, REG_AFE_XTAL_CTRL, BIT(4) | BIT(3)); + + /* GPIO_A[31:0] Pull down software register */ + rtl8xxxu_write32(priv, REG_GPIO_A0, 0xffffffff); + + /* GPIO_B[7:0] Pull down software register */ + rtl8xxxu_write8(priv, REG_GPIO_B0, 0xff); + + /* Register Lock Enable */ + rtl8xxxu_write8_clear(priv, REG_RSV_CTRL, BIT(7)); + + return 0; +} + +static int rtl8192fu_active_to_emu(struct rtl8xxxu_priv *priv) +{ + u32 val32; + int count; + + /* Reset BB, RF enter Power Down mode */ + rtl8xxxu_write8_clear(priv, REG_SYS_FUNC, SYS_FUNC_BBRSTB); + + /* Enable rising edge triggering interrupt */ + rtl8xxxu_write16_clear(priv, REG_GPIO_INTM, GPIO_INTM_EDGE_TRIG_IRQ); + + /* release WLON reset */ + rtl8xxxu_write32_set(priv, REG_APS_FSMCO, APS_FSMCO_WLON_RESET); + + /* turn off MAC by HW state machine */ + rtl8xxxu_write16_set(priv, REG_APS_FSMCO, APS_FSMCO_MAC_OFF); + + for (count = RTL8XXXU_MAX_REG_POLL; count; count--) { + val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO); + if ((val32 & APS_FSMCO_MAC_OFF) == 0) + break; + + udelay(10); + } + + if (!count) + return -EBUSY; + + /* analog Ips to digital, 1:isolation */ + rtl8xxxu_write8_set(priv, REG_SYS_ISO_CTRL, SYS_ISO_ANALOG_IPS); + + /* disable LDOA12 MACRO block */ + rtl8xxxu_write8_clear(priv, REG_LDOA15_CTRL, LDOA15_ENABLE); + + return 0; +} + +static int rtl8192fu_emu_to_disabled(struct rtl8xxxu_priv *priv) +{ + u16 val16; + + /* SOP option to disable BG/MB */ + rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x20); + + /* 0x04[12:11] = 2b'01 enable WL suspend */ + val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO); + val16 &= ~APS_FSMCO_PCIE; + val16 |= APS_FSMCO_HW_SUSPEND; + rtl8xxxu_write16(priv, REG_APS_FSMCO, val16); + + /* enable GPIO9 as EXT WAKEUP */ + rtl8xxxu_write32_set(priv, REG_GPIO_INTM, BIT(16)); + + return 0; +} + +static int rtl8192fu_active_to_lps(struct rtl8xxxu_priv *priv) +{ + struct device *dev = &priv->udev->dev; + u16 val16; + u32 val32; + int retry; + + /* Tx Pause */ + rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff); + + retry = 100; + + /* Poll 32 bit wide REG_SCH_TX_CMD for 0 to ensure no TX is pending. */ + do { + val32 = rtl8xxxu_read32(priv, REG_SCH_TX_CMD); + if (!val32) + break; + + udelay(10); + } while (retry--); + + if (!retry) { + dev_warn(dev, "%s: Failed to flush TX queue\n", __func__); + return -EBUSY; + } + + /* Disable CCK and OFDM, clock gated */ + rtl8xxxu_write8_clear(priv, REG_SYS_FUNC, SYS_FUNC_BBRSTB); + + udelay(2); + + /* Whole BB is reset */ + rtl8xxxu_write8_clear(priv, REG_SYS_FUNC, SYS_FUNC_BB_GLB_RSTN); + + /* Reset MAC TRX */ + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 &= 0xff00; + val16 |= CR_HCI_RXDMA_ENABLE | CR_HCI_TXDMA_ENABLE; + val16 &= ~CR_SECURITY_ENABLE; + rtl8xxxu_write16(priv, REG_CR, val16); + + /* Respond TxOK to scheduler */ + rtl8xxxu_write8_set(priv, REG_DUAL_TSF_RST, DUAL_TSF_TX_OK); + + return 0; +} + +static int rtl8192fu_power_on(struct rtl8xxxu_priv *priv) +{ + u16 val16; + int ret; + + rtl8xxxu_write8(priv, REG_USB_ACCESS_TIMEOUT, 0x80); + + rtl8192fu_disabled_to_emu(priv); + + ret = rtl8192fu_emu_to_active(priv); + if (ret) + return ret; + + rtl8xxxu_write16(priv, REG_CR, 0); + + val16 = rtl8xxxu_read16(priv, REG_CR); + + val16 |= CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE | + CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | + CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE | + CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE; + rtl8xxxu_write16(priv, REG_CR, val16); + + return 0; +} + +static void rtl8192fu_power_off(struct rtl8xxxu_priv *priv) +{ + rtl8xxxu_flush_fifo(priv); + + /* Stop Tx Report Timer. 0x4EC[Bit1]=b'0 */ + rtl8xxxu_write8_clear(priv, REG_TX_REPORT_CTRL, + TX_REPORT_CTRL_TIMER_ENABLE); + + /* stop rx */ + rtl8xxxu_write8(priv, REG_CR, 0x00); + + rtl8192fu_active_to_lps(priv); + + /* Reset Firmware if running in RAM */ + if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL) + rtl8xxxu_firmware_self_reset(priv); + + /* Reset MCU */ + rtl8xxxu_write16_clear(priv, REG_SYS_FUNC, SYS_FUNC_CPU_ENABLE); + + /* Reset MCU ready status */ + rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00); + + rtl8192fu_active_to_emu(priv); + rtl8192fu_emu_to_disabled(priv); +} + +static void rtl8192f_reset_8051(struct rtl8xxxu_priv *priv) +{ + rtl8xxxu_write8_clear(priv, REG_RSV_CTRL, BIT(1)); + + rtl8xxxu_write8_clear(priv, REG_RSV_CTRL + 1, BIT(0)); + + rtl8xxxu_write16_clear(priv, REG_SYS_FUNC, SYS_FUNC_CPU_ENABLE); + + rtl8xxxu_write8_clear(priv, REG_RSV_CTRL, BIT(1)); + + rtl8xxxu_write8_set(priv, REG_RSV_CTRL + 1, BIT(0)); + + rtl8xxxu_write16_set(priv, REG_SYS_FUNC, SYS_FUNC_CPU_ENABLE); +} + +static void rtl8192f_enable_rf(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + rtl8xxxu_write8(priv, REG_RF_CTRL, RF_ENABLE | RF_RSTB | RF_SDMRSTB); + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK); + val32 |= OFDM_RF_PATH_RX_A | OFDM_RF_PATH_RX_B | + OFDM_RF_PATH_TX_A | OFDM_RF_PATH_TX_B; + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); +} + +static void rtl8192f_disable_rf(struct rtl8xxxu_priv *priv) +{ + u32 val32; + + val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE); + val32 &= ~OFDM_RF_PATH_TX_MASK; + rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32); + + /* Power down RF module */ + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0); +} + +static void rtl8192f_usb_quirks(struct rtl8xxxu_priv *priv) +{ + u16 val16; + + rtl8xxxu_gen2_usb_quirks(priv); + + val16 = rtl8xxxu_read16(priv, REG_CR); + val16 |= (CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE); + rtl8xxxu_write16(priv, REG_CR, val16); +} + +#define XTAL1 GENMASK(6, 1) +#define XTAL0 GENMASK(30, 25) + +static void rtl8192f_set_crystal_cap(struct rtl8xxxu_priv *priv, u8 crystal_cap) +{ + struct rtl8xxxu_cfo_tracking *cfo = &priv->cfo_tracking; + u32 xtal1, xtal0; + + if (crystal_cap == cfo->crystal_cap) + return; + + xtal1 = rtl8xxxu_read32(priv, REG_AFE_PLL_CTRL); + xtal0 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL); + + dev_dbg(&priv->udev->dev, + "%s: Adjusting crystal cap from 0x%x (actually 0x%x 0x%x) to 0x%x\n", + __func__, + cfo->crystal_cap, + u32_get_bits(xtal1, XTAL1), + u32_get_bits(xtal0, XTAL0), + crystal_cap); + + u32p_replace_bits(&xtal1, crystal_cap, XTAL1); + u32p_replace_bits(&xtal0, crystal_cap, XTAL0); + rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, xtal1); + rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, xtal0); + + cfo->crystal_cap = crystal_cap; +} + +static s8 rtl8192f_cck_rssi(struct rtl8xxxu_priv *priv, struct rtl8723au_phy_stats *phy_stats) +{ + struct jaguar2_phy_stats_type0 *phy_stats0 = (struct jaguar2_phy_stats_type0 *)phy_stats; + u8 lna_idx = (phy_stats0->lna_h << 3) | phy_stats0->lna_l; + u8 vga_idx = phy_stats0->vga; + s8 rx_pwr_all; + + switch (lna_idx) { + case 7: + rx_pwr_all = -44 - (2 * vga_idx); + break; + case 5: + rx_pwr_all = -28 - (2 * vga_idx); + break; + case 3: + rx_pwr_all = -10 - (2 * vga_idx); + break; + case 0: + rx_pwr_all = 14 - (2 * vga_idx); + break; + default: + rx_pwr_all = 0; + break; + } + + return rx_pwr_all; +} + +static int rtl8192fu_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct rtl8xxxu_priv *priv = container_of(led_cdev, + struct rtl8xxxu_priv, + led_cdev); + u16 ledcfg; + + /* Values obtained by observing the USB traffic from the Windows driver. */ + rtl8xxxu_write32(priv, REG_SW_GPIO_SHARE_CTRL_0, 0x20080); + rtl8xxxu_write32(priv, REG_SW_GPIO_SHARE_CTRL_1, 0x1b0000); + + ledcfg = rtl8xxxu_read16(priv, REG_LEDCFG0); + + if (brightness == LED_OFF) { + /* Value obtained like above. */ + ledcfg = BIT(1) | BIT(7); + } else if (brightness == LED_ON) { + /* Value obtained like above. */ + ledcfg = BIT(1) | BIT(7) | BIT(11); + } else if (brightness == RTL8XXXU_HW_LED_CONTROL) { + /* Value obtained by brute force. */ + ledcfg = BIT(8) | BIT(9); + } + + rtl8xxxu_write16(priv, REG_LEDCFG0, ledcfg); + + return 0; +} + +struct rtl8xxxu_fileops rtl8192fu_fops = { + .identify_chip = rtl8192fu_identify_chip, + .parse_efuse = rtl8192fu_parse_efuse, + .load_firmware = rtl8192fu_load_firmware, + .power_on = rtl8192fu_power_on, + .power_off = rtl8192fu_power_off, + .read_efuse = rtl8xxxu_read_efuse, + .reset_8051 = rtl8192f_reset_8051, + .llt_init = rtl8xxxu_auto_llt_table, + .init_phy_bb = rtl8192fu_init_phy_bb, + .init_phy_rf = rtl8192fu_init_phy_rf, + .phy_lc_calibrate = rtl8192f_phy_lc_calibrate, + .phy_iq_calibrate = rtl8192fu_phy_iq_calibrate, + .config_channel = rtl8192fu_config_channel, + .parse_rx_desc = rtl8xxxu_parse_rxdesc24, + .parse_phystats = jaguar2_rx_parse_phystats, + .init_aggregation = rtl8192fu_init_aggregation, + .init_burst = rtl8xxxu_init_burst, + .enable_rf = rtl8192f_enable_rf, + .disable_rf = rtl8192f_disable_rf, + .usb_quirks = rtl8192f_usb_quirks, + .set_tx_power = rtl8192f_set_tx_power, + .update_rate_mask = rtl8xxxu_gen2_update_rate_mask, + .report_connect = rtl8xxxu_gen2_report_connect, + .report_rssi = rtl8xxxu_gen2_report_rssi, + .fill_txdesc = rtl8xxxu_fill_txdesc_v2, + .set_crystal_cap = rtl8192f_set_crystal_cap, + .cck_rssi = rtl8192f_cck_rssi, + .led_classdev_brightness_set = rtl8192fu_led_brightness_set, + .writeN_block_size = 254, + .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24), + .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40), + .has_tx_report = 1, + .gen2_thermal_meter = 1, + .needs_full_init = 1, + .init_reg_rxfltmap = 1, + .init_reg_pkt_life_time = 1, + .init_reg_hmtfr = 1, + .ampdu_max_time = 0x5e, + .ustime_tsf_edca = 0x50, + .max_aggr_num = 0x1f1f, + .trxff_boundary = 0x3f3f, + .pbp_rx = PBP_PAGE_SIZE_256, + .pbp_tx = PBP_PAGE_SIZE_256, + .mactable = rtl8192f_mac_init_table, + .total_page_num = TX_TOTAL_PAGE_NUM_8192F, + .page_num_hi = TX_PAGE_NUM_HI_PQ_8192F, + .page_num_lo = TX_PAGE_NUM_LO_PQ_8192F, + .page_num_norm = TX_PAGE_NUM_NORM_PQ_8192F, +}; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c index 22d4704dd31e..2990475100ec 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c @@ -1874,6 +1874,7 @@ struct rtl8xxxu_fileops rtl8710bu_fops = { * but in rtl8xxxu 0x50 causes slow upload and random packet loss. Why? */ .ustime_tsf_edca = 0x28, + .max_aggr_num = 0x0c14, .adda_1t_init = 0x03c00016, .adda_1t_path_on = 0x03c00016, .trxff_boundary = 0x3f7f, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index abc56c7de6f7..a7ad62a8a7c6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -1741,6 +1741,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .init_reg_hmtfr = 1, .ampdu_max_time = 0x5e, .ustime_tsf_edca = 0x50, + .max_aggr_num = 0x0c14, .adda_1t_init = 0x01c00014, .adda_1t_path_on = 0x01c00014, .adda_2t_path_on_a = 0x01c00014, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 37df47c27a69..52029fdf67c8 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -56,6 +56,7 @@ MODULE_FIRMWARE("rtlwifi/rtl8723bu_bt.bin"); MODULE_FIRMWARE("rtlwifi/rtl8188fufw.bin"); MODULE_FIRMWARE("rtlwifi/rtl8710bufw_SMIC.bin"); MODULE_FIRMWARE("rtlwifi/rtl8710bufw_UMC.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192fufw.bin"); module_param_named(debug, rtl8xxxu_debug, int, 0600); MODULE_PARM_DESC(debug, "Set debug mask"); @@ -2020,12 +2021,18 @@ exit: static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) { int pages, remainder, i, ret; + u16 reg_fw_start_address; u16 reg_mcu_fw_dl; u8 val8; u16 val16; u32 val32; u8 *fwptr; + if (priv->rtl_chip == RTL8192F) + reg_fw_start_address = REG_FW_START_ADDRESS_8192F; + else + reg_fw_start_address = REG_FW_START_ADDRESS; + if (priv->rtl_chip == RTL8710B) { reg_mcu_fw_dl = REG_8051FW_CTRL_V1_8710B; } else { @@ -2081,7 +2088,7 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) val8 |= i; rtl8xxxu_write8(priv, reg_mcu_fw_dl + 2, val8); - ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS, + ret = rtl8xxxu_writeN(priv, reg_fw_start_address, fwptr, RTL_FW_PAGE_SIZE); if (ret != RTL_FW_PAGE_SIZE) { ret = -EAGAIN; @@ -2095,7 +2102,7 @@ static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv) val8 = rtl8xxxu_read8(priv, reg_mcu_fw_dl + 2) & 0xF8; val8 |= i; rtl8xxxu_write8(priv, reg_mcu_fw_dl + 2, val8); - ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS, + ret = rtl8xxxu_writeN(priv, reg_fw_start_address, fwptr, remainder); if (ret != remainder) { ret = -EAGAIN; @@ -2149,6 +2156,7 @@ int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, const char *fw_name) case 0x2300: case 0x88f0: case 0x10b0: + case 0x92f0: break; default: ret = -EINVAL; @@ -2595,6 +2603,7 @@ static int rtl8xxxu_init_queue_priority(struct rtl8xxxu_priv *priv) u16 hiq, mgq, bkq, beq, viq, voq; int hip, mgp, bkp, bep, vip, vop; int ret = 0; + u32 val32; switch (priv->ep_tx_count) { case 1: @@ -2677,15 +2686,28 @@ static int rtl8xxxu_init_queue_priority(struct rtl8xxxu_priv *priv) * queue here .... why? */ if (!ret) { - val16 = rtl8xxxu_read16(priv, REG_TRXDMA_CTRL); - val16 &= 0x7; - val16 |= (voq << TRXDMA_CTRL_VOQ_SHIFT) | - (viq << TRXDMA_CTRL_VIQ_SHIFT) | - (beq << TRXDMA_CTRL_BEQ_SHIFT) | - (bkq << TRXDMA_CTRL_BKQ_SHIFT) | - (mgq << TRXDMA_CTRL_MGQ_SHIFT) | - (hiq << TRXDMA_CTRL_HIQ_SHIFT); - rtl8xxxu_write16(priv, REG_TRXDMA_CTRL, val16); + /* Only RTL8192F seems to do it like this. */ + if (priv->rtl_chip == RTL8192F) { + val32 = rtl8xxxu_read32(priv, REG_TRXDMA_CTRL); + val32 &= 0x7; + val32 |= (voq << TRXDMA_CTRL_VOQ_SHIFT_8192F) | + (viq << TRXDMA_CTRL_VIQ_SHIFT_8192F) | + (beq << TRXDMA_CTRL_BEQ_SHIFT_8192F) | + (bkq << TRXDMA_CTRL_BKQ_SHIFT_8192F) | + (mgq << TRXDMA_CTRL_MGQ_SHIFT_8192F) | + (hiq << TRXDMA_CTRL_HIQ_SHIFT_8192F); + rtl8xxxu_write32(priv, REG_TRXDMA_CTRL, val32); + } else { + val16 = rtl8xxxu_read16(priv, REG_TRXDMA_CTRL); + val16 &= 0x7; + val16 |= (voq << TRXDMA_CTRL_VOQ_SHIFT) | + (viq << TRXDMA_CTRL_VIQ_SHIFT) | + (beq << TRXDMA_CTRL_BEQ_SHIFT) | + (bkq << TRXDMA_CTRL_BKQ_SHIFT) | + (mgq << TRXDMA_CTRL_MGQ_SHIFT) | + (hiq << TRXDMA_CTRL_HIQ_SHIFT); + rtl8xxxu_write16(priv, REG_TRXDMA_CTRL, val16); + } priv->pipe_out[TXDESC_QUEUE_VO] = usb_sndbulkpipe(priv->udev, priv->out_ep[vop]); @@ -2856,10 +2878,14 @@ void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv, bool iqk_ok, reg = (result[candidate][7] >> 6) & 0xf; - val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGCR_SSI_TABLE); - val32 &= ~0x0000f000; - val32 |= (reg << 12); - rtl8xxxu_write32(priv, REG_OFDM0_AGCR_SSI_TABLE, val32); + if (priv->rtl_chip == RTL8192F) { + rtl8xxxu_write32_mask(priv, REG_RXIQB_EXT, 0x000000f0, reg); + } else { + val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGCR_SSI_TABLE); + val32 &= ~0x0000f000; + val32 |= (reg << 12); + rtl8xxxu_write32(priv, REG_OFDM0_AGCR_SSI_TABLE, val32); + } } #define MAX_TOLERANCE 5 @@ -3958,13 +3984,14 @@ void rtl8xxxu_init_burst(struct rtl8xxxu_priv *priv) val8 |= HT_SINGLE_AMPDU_ENABLE; rtl8xxxu_write8(priv, REG_HT_SINGLE_AMPDU_8723B, val8); - rtl8xxxu_write16(priv, REG_MAX_AGGR_NUM, 0x0c14); + rtl8xxxu_write16(priv, REG_MAX_AGGR_NUM, priv->fops->max_aggr_num); rtl8xxxu_write8(priv, REG_AMPDU_MAX_TIME_8723B, priv->fops->ampdu_max_time); rtl8xxxu_write32(priv, REG_AGGLEN_LMT, 0xffffffff); rtl8xxxu_write8(priv, REG_RX_PKT_LIMIT, 0x18); rtl8xxxu_write8(priv, REG_PIFS, 0x00); - if (priv->rtl_chip == RTL8188F || priv->rtl_chip == RTL8710B) { + if (priv->rtl_chip == RTL8188F || priv->rtl_chip == RTL8710B || + priv->rtl_chip == RTL8192F) { rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL, FWHW_TXQ_CTRL_AMPDU_RETRY); rtl8xxxu_write32(priv, REG_FAST_EDCA_CTRL, 0x03086666); } @@ -4078,9 +4105,14 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) if (ret) goto exit; + /* Mac APLL Setting */ + if (priv->rtl_chip == RTL8192F) + rtl8xxxu_write16_set(priv, REG_AFE_CTRL4, BIT(4) | BIT(15)); + /* RFSW Control - clear bit 14 ?? */ if (priv->rtl_chip != RTL8723B && priv->rtl_chip != RTL8192E && - priv->rtl_chip != RTL8188E && priv->rtl_chip != RTL8710B) + priv->rtl_chip != RTL8188E && priv->rtl_chip != RTL8710B && + priv->rtl_chip != RTL8192F) rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003); val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW | @@ -4094,7 +4126,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* 0x860[6:5]= 00 - why? - this sets antenna B */ if (priv->rtl_chip != RTL8192E && priv->rtl_chip != RTL8188E && - priv->rtl_chip != RTL8710B) + priv->rtl_chip != RTL8710B && priv->rtl_chip != RTL8192F) rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66f60210); if (!macpower) { @@ -4168,7 +4200,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write8(priv, 0xa3, val8); } - if (priv->rtl_chip == RTL8710B) + if (priv->rtl_chip == RTL8710B || priv->rtl_chip == RTL8192F) rtl8xxxu_write8(priv, REG_EARLY_MODE_CONTROL_8710B, 0); } @@ -4195,7 +4227,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, val8); } else if (priv->rtl_chip == RTL8710B) { rtl8xxxu_write32(priv, REG_HIMR0_8710B, 0); - } else { + } else if (priv->rtl_chip != RTL8192F) { /* * Enable all interrupts - not obvious USB needs to do this */ @@ -4283,7 +4315,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) val16 = BEACON_DISABLE_TSF_UPDATE | (BEACON_DISABLE_TSF_UPDATE << 8); rtl8xxxu_write16(priv, REG_BEACON_CTRL, val16); rtl8xxxu_write16(priv, REG_TBTT_PROHIBIT, 0x6404); - if (priv->rtl_chip != RTL8188F && priv->rtl_chip != RTL8710B) + if (priv->rtl_chip != RTL8188F && priv->rtl_chip != RTL8710B && + priv->rtl_chip != RTL8192F) /* Firmware will control REG_DRVERLYINT when power saving is enable, */ /* so don't set this register on STA mode. */ rtl8xxxu_write8(priv, REG_DRIVER_EARLY_INT, DRIVER_EARLY_INT_TIME); @@ -4334,7 +4367,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) /* Disable BAR - not sure if this has any effect on USB */ rtl8xxxu_write32(priv, REG_BAR_MODE_CTRL, 0x0201ffff); - if (priv->rtl_chip != RTL8188F && priv->rtl_chip != RTL8188E && priv->rtl_chip != RTL8710B) + if (priv->rtl_chip != RTL8188F && priv->rtl_chip != RTL8188E && + priv->rtl_chip != RTL8710B && priv->rtl_chip != RTL8192F) rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0); if (fops->init_statistics) @@ -4352,9 +4386,10 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) * Reset USB mode switch setting */ rtl8xxxu_write8(priv, REG_ACLK_MON, 0x00); - } else if (priv->rtl_chip == RTL8188F || priv->rtl_chip == RTL8188E) { + } else if (priv->rtl_chip == RTL8188F || priv->rtl_chip == RTL8188E || + priv->rtl_chip == RTL8192F) { /* - * Init GPIO settings for 8188f, 8188e + * Init GPIO settings for 8188f, 8188e, 8192f */ val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG); val8 &= ~GPIO_MUXCFG_IO_SEL_ENBT; @@ -5516,8 +5551,10 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, tx_desc->pkt_size = cpu_to_le16(pktlen); tx_desc->pkt_offset = tx_desc_size; - tx_desc->txdw0 = - TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT; + /* These bits mean different things to the RTL8192F. */ + if (priv->rtl_chip != RTL8192F) + tx_desc->txdw0 = + TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT; if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || is_broadcast_ether_addr(ieee80211_get_DA(hdr))) tx_desc->txdw0 |= TXDESC_BROADMULTICAST; @@ -5587,7 +5624,7 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, rtl8xxxu_calc_tx_desc_csum(tx_desc); /* avoid zero checksum make tx hang */ - if (priv->rtl_chip == RTL8710B) + if (priv->rtl_chip == RTL8710B || priv->rtl_chip == RTL8192F) tx_desc->csum = ~tx_desc->csum; usb_fill_bulk_urb(&tx_urb->urb, priv->udev, priv->pipe_out[queue], @@ -7460,6 +7497,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, case 0xf179: case 0x8179: case 0xb711: + case 0xf192: untested = 0; break; } @@ -7484,6 +7522,10 @@ static int rtl8xxxu_probe(struct usb_interface *interface, if (id->idProduct == 0x0109) untested = 0; break; + case 0x0b05: + if (id->idProduct == 0x18f1) + untested = 0; + break; default: break; } @@ -7750,6 +7792,16 @@ static const struct usb_device_id dev_table[] = { /* TOTOLINK N150UA V5 / N150UA-B */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x2005, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8710bu_fops}, +/* Comfast CF-826F */ +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0xf192, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192fu_fops}, +/* Asus USB-N13 rev C1 */ +{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x18f1, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192fu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xb722, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192fu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x318b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192fu_fops}, #ifdef CONFIG_RTL8XXXU_UNTESTED /* Still supported by rtlwifi */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 8571d5129f32..17573f81a2f1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -67,6 +67,7 @@ #define REG_SPS0_CTRL 0x0011 #define REG_SPS_OCP_CFG 0x0018 #define REG_8192E_LDOV12_CTRL 0x0014 +#define REG_SYS_SWR_CTRL2 0x0014 #define REG_RSV_CTRL 0x001c #define RSV_CTRL_WLOCK_1C BIT(5) #define RSV_CTRL_DIS_PRST BIT(6) @@ -215,6 +216,8 @@ #define REG_HMBOX_EXT_2 0x008c #define REG_HMBOX_EXT_3 0x008e +#define REG_RSVD_1 0x0097 + /* Interrupt registers for 8192e/8723bu/8812 */ #define REG_HIMR0 0x00b0 #define IMR0_TXCCK BIT(30) /* TXRPT interrupt when CCX bit @@ -283,6 +286,7 @@ #define REG_BIST_SCAN 0x00d0 #define REG_BIST_RPT 0x00d4 #define REG_BIST_ROM_RPT 0x00d8 +#define REG_RSVD_4 0x00dc #define REG_USB_SIE_INTF 0x00e0 #define REG_PCIE_MIO_INTF 0x00e4 #define REG_PCIE_MIO_INTD 0x00e8 @@ -390,6 +394,12 @@ #define TRXDMA_CTRL_BKQ_SHIFT 10 #define TRXDMA_CTRL_MGQ_SHIFT 12 #define TRXDMA_CTRL_HIQ_SHIFT 14 +#define TRXDMA_CTRL_VOQ_SHIFT_8192F 4 +#define TRXDMA_CTRL_VIQ_SHIFT_8192F 7 +#define TRXDMA_CTRL_BEQ_SHIFT_8192F 10 +#define TRXDMA_CTRL_BKQ_SHIFT_8192F 13 +#define TRXDMA_CTRL_MGQ_SHIFT_8192F 16 +#define TRXDMA_CTRL_HIQ_SHIFT_8192F 19 #define TRXDMA_QUEUE_LOW 1 #define TRXDMA_QUEUE_NORMAL 2 #define TRXDMA_QUEUE_HIGH 3 @@ -973,12 +983,18 @@ #define FPGA1_TX_OFDM_TXSC_MASK 0x30000000 #define REG_ANT_MAPPING1 0x0914 +#define REG_RFE_OPT 0x0920 #define REG_DPDT_CTRL 0x092c /* 8723BU */ #define REG_RFE_CTRL_ANTA_SRC 0x0930 /* 8723BU */ +#define REG_RFE_CTRL_ANT_SRC1 0x0934 +#define REG_RFE_CTRL_ANT_SRC2 0x0938 +#define REG_RFE_CTRL_ANT_SRC3 0x093c #define REG_RFE_PATH_SELECT 0x0940 /* 8723BU */ #define REG_RFE_BUFFER 0x0944 /* 8723BU */ #define REG_S0S1_PATH_SWITCH 0x0948 /* 8723BU */ +#define REG_RX_DFIR_MOD_97F 0x0948 #define REG_OFDM_RX_DFIR 0x954 +#define REG_RFE_OPT62 0x0968 #define REG_CCK0_SYSTEM 0x0a00 #define CCK0_SIDEBAND BIT(4) @@ -1038,6 +1054,8 @@ #define REG_OFDM0_FA_RSTC 0x0c0c +#define REG_DOWNSAM_FACTOR 0x0c10 + #define REG_OFDM0_XA_RX_AFE 0x0c10 #define REG_OFDM0_XA_RX_IQ_IMBALANCE 0x0c14 #define REG_OFDM0_XB_RX_IQ_IMBALANCE 0x0c1c @@ -1074,6 +1092,8 @@ /* 8188eu */ #define REG_ANTDIV_PARA1 0x0ca4 +#define REG_RXIQB_EXT 0x0ca8 + /* 8723bu */ #define REG_OFDM0_TX_PSDO_NOISE_WEIGHT 0x0ce4 @@ -1093,6 +1113,8 @@ #define REG_OFDM1_CSI_FIX_MASK1 0x0d40 #define REG_OFDM1_CSI_FIX_MASK2 0x0d44 +#define REG_ANAPWR1 0x0d94 + #define REG_TX_AGC_A_RATE18_06 0x0e00 #define REG_TX_AGC_A_RATE54_24 0x0e04 #define REG_TX_AGC_A_CCK1_MCS32 0x0e08 @@ -1101,6 +1123,10 @@ #define REG_TX_AGC_A_MCS11_MCS08 0x0e18 #define REG_TX_AGC_A_MCS15_MCS12 0x0e1c +#define REG_NP_ANTA 0x0e20 + +#define REG_TAP_UPD_97F 0x0e24 + #define REG_FPGA0_IQK 0x0e28 #define REG_TX_IQK_TONE_A 0x0e30 @@ -1129,19 +1155,23 @@ #define REG_RX_CCK 0x0e8c #define REG_TX_POWER_BEFORE_IQK_A 0x0e94 +#define REG_IQK_RPT_TXA 0x0e98 #define REG_TX_POWER_AFTER_IQK_A 0x0e9c #define REG_RX_POWER_BEFORE_IQK_A 0x0ea0 #define REG_RX_POWER_BEFORE_IQK_A_2 0x0ea4 #define REG_RX_POWER_AFTER_IQK_A 0x0ea8 +#define REG_IQK_RPT_RXA 0x0ea8 #define REG_RX_POWER_AFTER_IQK_A_2 0x0eac #define REG_TX_POWER_BEFORE_IQK_B 0x0eb4 +#define REG_IQK_RPT_TXB 0x0eb8 #define REG_TX_POWER_AFTER_IQK_B 0x0ebc #define REG_RX_POWER_BEFORE_IQK_B 0x0ec0 #define REG_RX_POWER_BEFORE_IQK_B_2 0x0ec4 #define REG_RX_POWER_AFTER_IQK_B 0x0ec8 +#define REG_IQK_RPT_RXB 0x0ec8 #define REG_RX_POWER_AFTER_IQK_B_2 0x0ecc #define REG_RX_OFDM 0x0ed0 @@ -1152,6 +1182,12 @@ #define REG_PMPD_ANAEN 0x0eec #define REG_FW_START_ADDRESS 0x1000 +#define REG_FW_START_ADDRESS_8192F 0x4000 + +#define REG_SW_GPIO_SHARE_CTRL_0 0x1038 +#define REG_SW_GPIO_SHARE_CTRL_1 0x103c +#define REG_GPIO_A0 0x1050 +#define REG_GPIO_B0 0x105b #define REG_USB_INFO 0xfe17 #define REG_USB_HIMR 0xfe38 @@ -1316,12 +1352,15 @@ /* * NextGen regs: 8723BU */ +#define RF6052_REG_GAIN_P1 0x35 #define RF6052_REG_T_METER_8723B 0x42 #define RF6052_REG_UNKNOWN_43 0x43 #define RF6052_REG_UNKNOWN_55 0x55 #define RF6052_REG_UNKNOWN_56 0x56 +#define RF6052_REG_TXMOD 0x58 #define RF6052_REG_RXG_MIX_SWBW 0x87 #define RF6052_REG_S0S1 0xb0 #define RF6052_REG_UNKNOWN_DF 0xdf #define RF6052_REG_UNKNOWN_ED 0xed #define RF6052_REG_WE_LUT 0xef +#define RF6052_REG_GAIN_CTRL 0xf5 -- cgit v1.2.3 From 103d6e9d61e012d9f7d0aae33529924f9a3d78d9 Mon Sep 17 00:00:00 2001 From: Bitterblue Smith Date: Sat, 13 May 2023 23:48:27 +0300 Subject: wifi: rtl8xxxu: Rename some registers Give proper names: RF6052_REG_UNKNOWN_56 -> RF6052_REG_PAD_TXG RF6052_REG_UNKNOWN_DF -> RF6052_REG_GAIN_CCA And fix typos: REG_OFDM0_AGCR_SSI_TABLE -> REG_OFDM0_AGC_RSSI_TABLE REG_BB_ACCEESS_CTRL -> REG_BB_ACCESS_CTRL Signed-off-by: Bitterblue Smith Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/40157253-76bd-8b23-06e0-3365139b5395@gmail.com --- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c | 20 +++---- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c | 28 +++++----- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c | 64 +++++++++++----------- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c | 36 ++++++------ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 4 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 6 +- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 8 +-- 7 files changed, 83 insertions(+), 83 deletions(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index cb45546c4c68..1e1c8fa194cb 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -654,7 +654,7 @@ static void rtl8188fu_config_channel(struct ieee80211_hw *hw) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RX_BB2, val32); /* RC Corner */ - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00140); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x00140); rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RX_G2, 0x01c6c); } @@ -854,8 +854,8 @@ static int rtl8188fu_iqk_path_a(struct rtl8xxxu_priv *priv, u32 *lok_result) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0x07ff7); /* PA,PAD gain adjust */ - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x980); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x5102a); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x980); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_PAD_TXG, 0x5102a); /* enter IQK mode */ val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); @@ -886,7 +886,7 @@ static int rtl8188fu_iqk_path_a(struct rtl8xxxu_priv *priv, u32 *lok_result) val32 &= 0x000000ff; rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x180); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x180); /* save LOK result */ *lok_result = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_TXM_IDAC); @@ -927,8 +927,8 @@ static int rtl8188fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv, u32 lok_result) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf1173); /* PA,PAD gain adjust */ - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x980); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x5102a); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x980); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_PAD_TXG, 0x5102a); /* * Enter IQK mode @@ -967,7 +967,7 @@ static int rtl8188fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv, u32 lok_result) val32 &= 0x000000ff; rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x180); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x180); /* Check failed */ reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); @@ -1002,8 +1002,8 @@ static int rtl8188fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv, u32 lok_result) /* * PA, PAD setting */ - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x980); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x51000); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x980); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_PAD_TXG, 0x51000); /* * Enter IQK mode @@ -1041,7 +1041,7 @@ static int rtl8188fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv, u32 lok_result) val32 &= 0x000000ff; rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x180); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x180); /* reload LOK value */ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXM_IDAC, lok_result); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index fcc2926ea938..f673aa9ba15a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -716,7 +716,7 @@ static int rtl8192eu_iqk_path_a(struct rtl8xxxu_priv *priv) * PA/PAD controlled by 0x0 */ rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00180); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x00180); rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0); rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x20000); @@ -776,8 +776,8 @@ static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf1173); /* PA/PAD control by 0x56, and set = 0x0 */ - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00980); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x511e0); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x00980); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_PAD_TXG, 0x511e0); /* Enter IQK mode */ rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); @@ -816,7 +816,7 @@ static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) } else { /* PA/PAD controlled by 0x0 */ rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x180); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x180); goto out; } @@ -838,8 +838,8 @@ static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf7ff2); /* PA/PAD control by 0x56, and set = 0x0 */ - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00980); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x510e0); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x00980); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_PAD_TXG, 0x510e0); /* Enter IQK mode */ rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); @@ -869,7 +869,7 @@ static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2); rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x180); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x180); if (!(reg_eac & BIT(27)) && ((reg_ea4 & 0x03ff0000) != 0x01320000) && @@ -889,7 +889,7 @@ static int rtl8192eu_iqk_path_b(struct rtl8xxxu_priv *priv) int result = 0; rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000); - rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00180); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_CCA, 0x00180); rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_WE_LUT, 0x800a0); rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x20000); @@ -952,8 +952,8 @@ static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf1173); /* PA/PAD control by 0x56, and set = 0x0 */ - rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00980); - rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x511e0); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_CCA, 0x00980); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_PAD_TXG, 0x511e0); /* Enter IQK mode */ rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); @@ -995,7 +995,7 @@ static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) * Vendor driver restores RF_A here which I believe is a bug */ rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000); - rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x180); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_CCA, 0x180); goto out; } @@ -1017,8 +1017,8 @@ static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7ff2); /* PA/PAD control by 0x56, and set = 0x0 */ - rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00980); - rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x510e0); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_CCA, 0x00980); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_PAD_TXG, 0x510e0); /* Enter IQK mode */ rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000); @@ -1049,7 +1049,7 @@ static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2); rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000); - rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x180); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_CCA, 0x180); if (!(reg_eac & BIT(30)) && ((reg_ec4 & 0x03ff0000) != 0x01320000) && diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c index 50225f1d9478..18dc5221a9c0 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c @@ -569,7 +569,7 @@ static void rtl8192fu_config_kfree(struct rtl8xxxu_priv *priv, u8 channel) BIT(18), 1); /* enter power_trim debug mode */ - rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_UNKNOWN_DF, + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_GAIN_CCA, BIT(7), 1); /* write enable */ @@ -589,7 +589,7 @@ static void rtl8192fu_config_kfree(struct rtl8xxxu_priv *priv, u8 channel) 0x3f, bb_gain_for_path); /* leave power_trim debug mode */ - rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_UNKNOWN_DF, + rtl8xxxu_write_rfreg_mask(priv, rfpath, RF6052_REG_GAIN_CCA, BIT(7), 0); /* write disable */ @@ -831,13 +831,13 @@ static int rtl8192fu_iqk_path_a(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x04203400); rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(4), 1); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, BIT(4), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, BIT(11), 1); if (rfe == 7 || rfe == 8 || rfe == 9 || rfe == 12) val32 = 0x30; else val32 = 0xe9; - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x003ff, val32); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_PAD_TXG, 0x003ff, val32); rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); @@ -893,7 +893,7 @@ static int rtl8192fu_iqk_path_a(struct rtl8xxxu_priv *priv) rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_AC, BIT(14), 0); rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_WE_LUT, BIT(4), 0); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00810, 0); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, 0x00810, 0); if (!(reg_eac & BIT(28)) && ((reg_e94 & 0x03ff0000) != 0x01420000) && @@ -913,10 +913,10 @@ static int rtl8192fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); /* PA/PAD control by 0x56, and set = 0x0 */ - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(1), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, BIT(1), 1); rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_P1, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(11), 1); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x003ff, 0x27); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_PAD_TXG, 0x003ff, 0x27); /* Enter IQK mode */ rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); @@ -962,7 +962,7 @@ static int rtl8192fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) /* PA/PAD controlled by 0x0 */ rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, BIT(11), 0); return result; @@ -975,10 +975,10 @@ static int rtl8192fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); /* PA/PAD control by 0x56, and set = 0x0 */ - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(1), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, BIT(1), 1); rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_P1, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(11), 1); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x003ff, 0x1e0); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_PAD_TXG, 0x003ff, 0x1e0); rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xccf000c0); rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44ffbb44); @@ -1025,7 +1025,7 @@ static int rtl8192fu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) /* Leave IQK mode */ rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_UNKNOWN_DF, BIT(11), 0); + rtl8xxxu_write_rfreg_mask(priv, RF_A, RF6052_REG_GAIN_CCA, BIT(11), 0); rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_P1, 0x02000); if (!(reg_eac & BIT(27)) && @@ -1055,13 +1055,13 @@ static int rtl8192fu_iqk_path_b(struct rtl8xxxu_priv *priv) rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x04203400); rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000000); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(4), 1); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(4), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(11), 1); if (rfe == 7 || rfe == 8 || rfe == 9 || rfe == 12) - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_56, + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_PAD_TXG, 0x003ff, 0x30); else - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_56, + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_PAD_TXG, 0x00fff, 0xe9); rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0x808000); @@ -1118,7 +1118,7 @@ static int rtl8192fu_iqk_path_b(struct rtl8xxxu_priv *priv) rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_AC, BIT(14), 0); rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_WE_LUT, BIT(4), 0); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00810, 0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, 0x00810, 0); if (!(reg_eac & BIT(31)) && ((reg_eb4 & 0x03ff0000) != 0x01420000) && @@ -1140,10 +1140,10 @@ static int rtl8192fu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) /* Leave IQK mode */ rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(1), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(1), 1); rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_P1, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(11), 1); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x003ff, 0x67); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_PAD_TXG, 0x003ff, 0x67); rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xccf000c0); rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44ffbb44); @@ -1192,7 +1192,7 @@ static int rtl8192fu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) /* PA/PAD controlled by 0x0 */ rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(11), 0); return result; @@ -1204,10 +1204,10 @@ static int rtl8192fu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) /* Modify RX IQK mode table */ rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(1), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(1), 1); rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_P1, 0); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(11), 1); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x003ff, 0x1e0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(11), 1); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_PAD_TXG, 0x003ff, 0x1e0); rtl8xxxu_write32(priv, REG_FPGA0_ANALOG4, 0xccf000c0); rtl8xxxu_write32(priv, REG_ANAPWR1, 0x44ffbb44); @@ -1253,8 +1253,8 @@ static int rtl8192fu_rx_iqk_path_b(struct rtl8xxxu_priv *priv) rtl8xxxu_write32_mask(priv, REG_FPGA0_IQK, 0xffffff00, 0); rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(11), 0); - rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_UNKNOWN_DF, BIT(1), 0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(11), 0); + rtl8xxxu_write_rfreg_mask(priv, RF_B, RF6052_REG_GAIN_CCA, BIT(1), 0); rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_P1, 0x02000); if (!(reg_eac & BIT(30)) && @@ -1472,9 +1472,9 @@ static void rtl8192fu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) rfe_path_select = rtl8xxxu_read32(priv, REG_RFE_PATH_SELECT); - path_a_0xdf = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF); + path_a_0xdf = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA); path_a_0x35 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_P1); - path_b_0xdf = rtl8xxxu_read_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF); + path_b_0xdf = rtl8xxxu_read_rfreg(priv, RF_B, RF6052_REG_GAIN_CCA); path_b_0x35 = rtl8xxxu_read_rfreg(priv, RF_B, RF6052_REG_GAIN_P1); memset(result, 0, sizeof(result)); @@ -1550,9 +1550,9 @@ static void rtl8192fu_phy_iq_calibrate(struct rtl8xxxu_priv *priv) candidate, (reg_ec4 == 0)); } - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, path_a_0xdf); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, path_a_0xdf); rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_P1, path_a_0x35); - rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, path_b_0xdf); + rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_CCA, path_b_0xdf); rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_GAIN_P1, path_b_0x35); if (rfe == 7 || rfe == 8 || rfe == 9 || rfe == 12) { diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c index 2990475100ec..f0d17b75c5f1 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c @@ -1031,12 +1031,12 @@ static int rtl8710bu_iqk_path_a(struct rtl8xxxu_priv *priv, u32 *lok_result) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0x07ff7); /* PA,PAD gain adjust */ - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA); val32 |= BIT(11); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, val32); - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, val32); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_PAD_TXG); u32p_replace_bits(&val32, 0x1ed, 0x00fff); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_PAD_TXG, val32); /* enter IQK mode */ val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK); @@ -1068,9 +1068,9 @@ static int rtl8710bu_iqk_path_a(struct rtl8xxxu_priv *priv, u32 *lok_result) u32p_replace_bits(&val32, 0, 0xffffff00); rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA); val32 &= ~BIT(11); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, val32); /* save LOK result */ *lok_result = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_TXM_IDAC); @@ -1113,12 +1113,12 @@ static int rtl8710bu_rx_iqk_path_a(struct rtl8xxxu_priv *priv, u32 lok_result) rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf1173); /* PA,PAD gain adjust */ - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA); val32 |= BIT(11); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, val32); - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, val32); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_PAD_TXG); u32p_replace_bits(&val32, 0xf, 0x003e0); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_PAD_TXG, val32); /* * Enter IQK mode @@ -1170,9 +1170,9 @@ static int rtl8710bu_rx_iqk_path_a(struct rtl8xxxu_priv *priv, u32 lok_result) u32p_replace_bits(&val32, 0, 0xffffff00); rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA); val32 &= ~BIT(11); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, val32); return result; } @@ -1197,12 +1197,12 @@ static int rtl8710bu_rx_iqk_path_a(struct rtl8xxxu_priv *priv, u32 lok_result) /* * PA, PAD setting */ - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA); val32 |= BIT(11); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, val32); - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, val32); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_PAD_TXG); u32p_replace_bits(&val32, 0x2a, 0x00fff); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_PAD_TXG, val32); /* * Enter IQK mode @@ -1241,9 +1241,9 @@ static int rtl8710bu_rx_iqk_path_a(struct rtl8xxxu_priv *priv, u32 lok_result) u32p_replace_bits(&val32, 0, 0xffffff00); rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32); - val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF); + val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA); val32 &= ~BIT(11); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, val32); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, val32); /* reload LOK value */ rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXM_IDAC, lok_result); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index a7ad62a8a7c6..13ad5d5b73f4 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -824,7 +824,7 @@ static int rtl8723bu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) /* * PA, PAD setting */ - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0xf80); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0xf80); rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_55, 0x4021f); /* @@ -888,7 +888,7 @@ static int rtl8723bu_rx_iqk_path_a(struct rtl8xxxu_priv *priv) reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2); reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2); - rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x780); + rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_GAIN_CCA, 0x780); val32 = (reg_eac >> 16) & 0x3ff; if (val32 & 0x200) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 52029fdf67c8..8d74a0cdf2c5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -643,7 +643,7 @@ const u32 rtl8xxxu_iqk_phy_iq_bb_reg[RTL8XXXU_BB_REGS] = { REG_OFDM0_XA_RX_IQ_IMBALANCE, REG_OFDM0_XB_RX_IQ_IMBALANCE, REG_OFDM0_ENERGY_CCA_THRES, - REG_OFDM0_AGCR_SSI_TABLE, + REG_OFDM0_AGC_RSSI_TABLE, REG_OFDM0_XA_TX_IQ_IMBALANCE, REG_OFDM0_XB_TX_IQ_IMBALANCE, REG_OFDM0_XC_TX_AFE, @@ -2881,10 +2881,10 @@ void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv, bool iqk_ok, if (priv->rtl_chip == RTL8192F) { rtl8xxxu_write32_mask(priv, REG_RXIQB_EXT, 0x000000f0, reg); } else { - val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGCR_SSI_TABLE); + val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGC_RSSI_TABLE); val32 &= ~0x0000f000; val32 |= (reg << 12); - rtl8xxxu_write32(priv, REG_OFDM0_AGCR_SSI_TABLE, val32); + rtl8xxxu_write32(priv, REG_OFDM0_AGC_RSSI_TABLE, val32); } } diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 17573f81a2f1..920ee50e2115 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -449,7 +449,7 @@ #define LLT_OP_READ (0x2 << 30) #define LLT_OP_MASK (0x3 << 30) -#define REG_BB_ACCEESS_CTRL 0x01e8 +#define REG_BB_ACCESS_CTRL 0x01e8 #define REG_BB_ACCESS_DATA 0x01ec #define REG_HMBOX_EXT0_8723B 0x01f0 @@ -1077,7 +1077,7 @@ #define REG_OFDM0_AGC_PARM1 0x0c70 -#define REG_OFDM0_AGCR_SSI_TABLE 0x0c78 +#define REG_OFDM0_AGC_RSSI_TABLE 0x0c78 #define REG_OFDM0_XA_TX_IQ_IMBALANCE 0x0c80 #define REG_OFDM0_XB_TX_IQ_IMBALANCE 0x0c88 @@ -1356,11 +1356,11 @@ #define RF6052_REG_T_METER_8723B 0x42 #define RF6052_REG_UNKNOWN_43 0x43 #define RF6052_REG_UNKNOWN_55 0x55 -#define RF6052_REG_UNKNOWN_56 0x56 +#define RF6052_REG_PAD_TXG 0x56 #define RF6052_REG_TXMOD 0x58 #define RF6052_REG_RXG_MIX_SWBW 0x87 #define RF6052_REG_S0S1 0xb0 -#define RF6052_REG_UNKNOWN_DF 0xdf +#define RF6052_REG_GAIN_CCA 0xdf #define RF6052_REG_UNKNOWN_ED 0xed #define RF6052_REG_WE_LUT 0xef #define RF6052_REG_GAIN_CTRL 0xf5 -- cgit v1.2.3 From d84b1a6708eec06b6cd9d33c5e0177bbd6ba4813 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 15 May 2023 11:07:10 -0700 Subject: bpf: fix calculation of subseq_idx during precision backtracking Subsequent instruction index (subseq_idx) is an index of an instruction that was verified/executed by verifier after the currently processed instruction. It is maintained during precision backtracking processing and is used to detect various subprog calling conditions. This patch fixes the bug with incorrectly resetting subseq_idx to -1 when going from child state to parent state during backtracking. If we don't maintain correct subseq_idx we can misidentify subprog calls leading to precision tracking bugs. One such case was triggered by test_global_funcs/global_func9 test where global subprog call happened to be the very last instruction in parent state, leading to subseq_idx==-1, triggering WARN_ONCE: [ 36.045754] verifier backtracking bug [ 36.045764] WARNING: CPU: 13 PID: 2073 at kernel/bpf/verifier.c:3503 __mark_chain_precision+0xcc6/0xde0 [ 36.046819] Modules linked in: aesni_intel(E) crypto_simd(E) cryptd(E) kvm_intel(E) kvm(E) irqbypass(E) i2c_piix4(E) serio_raw(E) i2c_core(E) crc32c_intel) [ 36.048040] CPU: 13 PID: 2073 Comm: test_progs Tainted: G W OE 6.3.0-07976-g4d585f48ee6b-dirty #972 [ 36.048783] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 [ 36.049648] RIP: 0010:__mark_chain_precision+0xcc6/0xde0 [ 36.050038] Code: 3d 82 c6 05 bb 35 32 02 01 e8 66 21 ec ff 0f 0b b8 f2 ff ff ff e9 30 f5 ff ff 48 c7 c7 f3 61 3d 82 4c 89 0c 24 e8 4a 21 ec ff <0f> 0b 4c0 With the fix precision tracking across multiple states works correctly now: mark_precise: frame0: last_idx 45 first_idx 38 subseq_idx -1 mark_precise: frame0: regs=r8 stack= before 44: (61) r7 = *(u32 *)(r10 -4) mark_precise: frame0: regs=r8 stack= before 43: (85) call pc+41 mark_precise: frame0: regs=r8 stack= before 42: (07) r1 += -48 mark_precise: frame0: regs=r8 stack= before 41: (bf) r1 = r10 mark_precise: frame0: regs=r8 stack= before 40: (63) *(u32 *)(r10 -48) = r1 mark_precise: frame0: regs=r8 stack= before 39: (b4) w1 = 0 mark_precise: frame0: regs=r8 stack= before 38: (85) call pc+38 mark_precise: frame0: parent state regs=r8 stack=: R0_w=scalar() R1_w=map_value(off=4,ks=4,vs=8,imm=0) R6=1 R7_w=scalar() R8_r=P0 R10=fpm mark_precise: frame0: last_idx 36 first_idx 28 subseq_idx 38 mark_precise: frame0: regs=r8 stack= before 36: (18) r1 = 0xffff888104f2ed14 mark_precise: frame0: regs=r8 stack= before 35: (85) call pc+33 mark_precise: frame0: regs=r8 stack= before 33: (18) r1 = 0xffff888104f2ed10 mark_precise: frame0: regs=r8 stack= before 32: (85) call pc+36 mark_precise: frame0: regs=r8 stack= before 31: (07) r1 += -4 mark_precise: frame0: regs=r8 stack= before 30: (bf) r1 = r10 mark_precise: frame0: regs=r8 stack= before 29: (63) *(u32 *)(r10 -4) = r7 mark_precise: frame0: regs=r8 stack= before 28: (4c) w7 |= w0 mark_precise: frame0: parent state regs=r8 stack=: R0_rw=scalar() R6=1 R7_rw=scalar() R8_rw=P0 R10=fp0 fp-48_r=mmmmmmmm mark_precise: frame0: last_idx 27 first_idx 16 subseq_idx 28 mark_precise: frame0: regs=r8 stack= before 27: (85) call pc+31 mark_precise: frame0: regs=r8 stack= before 26: (b7) r1 = 0 mark_precise: frame0: regs=r8 stack= before 25: (b7) r8 = 0 Note how subseq_idx starts out as -1, then is preserved as 38 and then 28 as we go up the parent state chain. Reported-by: Alexei Starovoitov Fixes: fde2a3882bd0 ("bpf: support precision propagation in the presence of subprogs") Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230515180710.1535018-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5c636276d907..f597491259ab 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3864,10 +3864,11 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) struct bpf_verifier_state *st = env->cur_state; int first_idx = st->first_insn_idx; int last_idx = env->insn_idx; + int subseq_idx = -1; struct bpf_func_state *func; struct bpf_reg_state *reg; bool skip_first = true; - int i, prev_i, fr, err; + int i, fr, err; if (!env->bpf_capable) return 0; @@ -3897,8 +3898,8 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) u32 history = st->jmp_history_cnt; if (env->log.level & BPF_LOG_LEVEL2) { - verbose(env, "mark_precise: frame%d: last_idx %d first_idx %d\n", - bt->frame, last_idx, first_idx); + verbose(env, "mark_precise: frame%d: last_idx %d first_idx %d subseq_idx %d \n", + bt->frame, last_idx, first_idx, subseq_idx); } if (last_idx < 0) { @@ -3930,12 +3931,12 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) return -EFAULT; } - for (i = last_idx, prev_i = -1;;) { + for (i = last_idx;;) { if (skip_first) { err = 0; skip_first = false; } else { - err = backtrack_insn(env, i, prev_i, bt); + err = backtrack_insn(env, i, subseq_idx, bt); } if (err == -ENOTSUPP) { mark_all_scalars_precise(env, env->cur_state); @@ -3952,7 +3953,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) return 0; if (i == first_idx) break; - prev_i = i; + subseq_idx = i; i = get_prev_insn_idx(st, i, &history); if (i >= env->prog->len) { /* This can happen if backtracking reached insn 0 @@ -4031,6 +4032,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) if (bt_empty(bt)) return 0; + subseq_idx = first_idx; last_idx = st->last_insn_idx; first_idx = st->first_insn_idx; } -- cgit v1.2.3 From 04cb8453a91c7c22f60ddadb6cef0d19abb33bb5 Mon Sep 17 00:00:00 2001 From: Alan Maguire Date: Fri, 12 May 2023 12:31:34 +0100 Subject: bpftool: JIT limited misreported as negative value on aarch64 On aarch64, "bpftool feature" reports an incorrect BPF JIT limit: $ sudo /sbin/bpftool feature Scanning system configuration... bpf() syscall restricted to privileged users JIT compiler is enabled JIT compiler hardening is disabled JIT compiler kallsyms exports are enabled for root skipping kernel config, can't open file: No such file or directory Global memory limit for JIT compiler for unprivileged users is -201326592 bytes This is because /proc/sys/net/core/bpf_jit_limit reports $ sudo cat /proc/sys/net/core/bpf_jit_limit 68169519595520 ...and an int is assumed in read_procfs(). Change read_procfs() to return a long to avoid negative value reporting. Fixes: 7a4522bbef0c ("tools: bpftool: add probes for /proc/ eBPF parameters") Reported-by: Nicky Veitch Signed-off-by: Alan Maguire Signed-off-by: Daniel Borkmann Acked-by: Jiri Olsa Acked-by: Quentin Monnet Link: https://lore.kernel.org/bpf/20230512113134.58996-1-alan.maguire@oracle.com --- tools/bpf/bpftool/feature.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index da16e6a27ccc..0675d6a46413 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -167,12 +167,12 @@ static int get_vendor_id(int ifindex) return strtol(buf, NULL, 0); } -static int read_procfs(const char *path) +static long read_procfs(const char *path) { char *endptr, *line = NULL; size_t len = 0; FILE *fd; - int res; + long res; fd = fopen(path, "r"); if (!fd) @@ -194,7 +194,7 @@ static int read_procfs(const char *path) static void probe_unprivileged_disabled(void) { - int res; + long res; /* No support for C-style ouptut */ @@ -216,14 +216,14 @@ static void probe_unprivileged_disabled(void) printf("Unable to retrieve required privileges for bpf() syscall\n"); break; default: - printf("bpf() syscall restriction has unknown value %d\n", res); + printf("bpf() syscall restriction has unknown value %ld\n", res); } } } static void probe_jit_enable(void) { - int res; + long res; /* No support for C-style ouptut */ @@ -245,7 +245,7 @@ static void probe_jit_enable(void) printf("Unable to retrieve JIT-compiler status\n"); break; default: - printf("JIT-compiler status has unknown value %d\n", + printf("JIT-compiler status has unknown value %ld\n", res); } } @@ -253,7 +253,7 @@ static void probe_jit_enable(void) static void probe_jit_harden(void) { - int res; + long res; /* No support for C-style ouptut */ @@ -275,7 +275,7 @@ static void probe_jit_harden(void) printf("Unable to retrieve JIT hardening status\n"); break; default: - printf("JIT hardening status has unknown value %d\n", + printf("JIT hardening status has unknown value %ld\n", res); } } @@ -283,7 +283,7 @@ static void probe_jit_harden(void) static void probe_jit_kallsyms(void) { - int res; + long res; /* No support for C-style ouptut */ @@ -302,14 +302,14 @@ static void probe_jit_kallsyms(void) printf("Unable to retrieve JIT kallsyms export status\n"); break; default: - printf("JIT kallsyms exports status has unknown value %d\n", res); + printf("JIT kallsyms exports status has unknown value %ld\n", res); } } } static void probe_jit_limit(void) { - int res; + long res; /* No support for C-style ouptut */ @@ -322,7 +322,7 @@ static void probe_jit_limit(void) printf("Unable to retrieve global memory limit for JIT compiler for unprivileged users\n"); break; default: - printf("Global memory limit for JIT compiler for unprivileged users is %d bytes\n", res); + printf("Global memory limit for JIT compiler for unprivileged users is %ld bytes\n", res); } } } -- cgit v1.2.3 From 90564f1e3dd66052af29e2c29cba3dc98b6604d0 Mon Sep 17 00:00:00 2001 From: Florent Revest Date: Thu, 11 May 2023 16:05:07 +0200 Subject: bpf, arm64: Support struct arguments in the BPF trampoline This extends the BPF trampoline JIT to support attachment to functions that take small structures (up to 128bit) as argument. This is trivially achieved by saving/restoring a number of "argument registers" rather than a number of arguments. The AAPCS64 section 6.8.2 describes the parameter passing ABI. "Composite types" (like C structs) below 16 bytes (as enforced by the BPF verifier) are provided as part of the 8 argument registers as explained in the section C.12. Signed-off-by: Florent Revest Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Acked-by: Xu Kuohai Link: https://lore.kernel.org/bpf/20230511140507.514888-1-revest@chromium.org --- arch/arm64/net/bpf_jit_comp.c | 55 ++++++++++++++-------------- tools/testing/selftests/bpf/DENYLIST.aarch64 | 1 - 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index b26da8efa616..145b540ec34f 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1731,21 +1731,21 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_links *tl, } } -static void save_args(struct jit_ctx *ctx, int args_off, int nargs) +static void save_args(struct jit_ctx *ctx, int args_off, int nregs) { int i; - for (i = 0; i < nargs; i++) { + for (i = 0; i < nregs; i++) { emit(A64_STR64I(i, A64_SP, args_off), ctx); args_off += 8; } } -static void restore_args(struct jit_ctx *ctx, int args_off, int nargs) +static void restore_args(struct jit_ctx *ctx, int args_off, int nregs) { int i; - for (i = 0; i < nargs; i++) { + for (i = 0; i < nregs; i++) { emit(A64_LDR64I(i, A64_SP, args_off), ctx); args_off += 8; } @@ -1764,7 +1764,7 @@ static void restore_args(struct jit_ctx *ctx, int args_off, int nargs) */ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, struct bpf_tramp_links *tlinks, void *orig_call, - int nargs, u32 flags) + int nregs, u32 flags) { int i; int stack_size; @@ -1772,7 +1772,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, int regs_off; int retval_off; int args_off; - int nargs_off; + int nregs_off; int ip_off; int run_ctx_off; struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; @@ -1795,11 +1795,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, * SP + retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or * BPF_TRAMP_F_RET_FENTRY_RET * - * [ argN ] + * [ arg reg N ] * [ ... ] - * SP + args_off [ arg1 ] + * SP + args_off [ arg reg 1 ] * - * SP + nargs_off [ args count ] + * SP + nregs_off [ arg regs count ] * * SP + ip_off [ traced function ] BPF_TRAMP_F_IP_ARG flag * @@ -1816,13 +1816,13 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, if (flags & BPF_TRAMP_F_IP_ARG) stack_size += 8; - nargs_off = stack_size; + nregs_off = stack_size; /* room for args count */ stack_size += 8; args_off = stack_size; /* room for args */ - stack_size += nargs * 8; + stack_size += nregs * 8; /* room for return value */ retval_off = stack_size; @@ -1865,12 +1865,12 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, emit(A64_STR64I(A64_R(10), A64_SP, ip_off), ctx); } - /* save args count*/ - emit(A64_MOVZ(1, A64_R(10), nargs, 0), ctx); - emit(A64_STR64I(A64_R(10), A64_SP, nargs_off), ctx); + /* save arg regs count*/ + emit(A64_MOVZ(1, A64_R(10), nregs, 0), ctx); + emit(A64_STR64I(A64_R(10), A64_SP, nregs_off), ctx); - /* save args */ - save_args(ctx, args_off, nargs); + /* save arg regs */ + save_args(ctx, args_off, nregs); /* save callee saved registers */ emit(A64_STR64I(A64_R(19), A64_SP, regs_off), ctx); @@ -1897,7 +1897,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, } if (flags & BPF_TRAMP_F_CALL_ORIG) { - restore_args(ctx, args_off, nargs); + restore_args(ctx, args_off, nregs); /* call original func */ emit(A64_LDR64I(A64_R(10), A64_SP, retaddr_off), ctx); emit(A64_ADR(A64_LR, AARCH64_INSN_SIZE * 2), ctx); @@ -1926,7 +1926,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, } if (flags & BPF_TRAMP_F_RESTORE_REGS) - restore_args(ctx, args_off, nargs); + restore_args(ctx, args_off, nregs); /* restore callee saved register x19 and x20 */ emit(A64_LDR64I(A64_R(19), A64_SP, regs_off), ctx); @@ -1967,24 +1967,25 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *orig_call) { int i, ret; - int nargs = m->nr_args; + int nregs = m->nr_args; int max_insns = ((long)image_end - (long)image) / AARCH64_INSN_SIZE; struct jit_ctx ctx = { .image = NULL, .idx = 0, }; - /* the first 8 arguments are passed by registers */ - if (nargs > 8) - return -ENOTSUPP; - - /* don't support struct argument */ + /* extra registers needed for struct argument */ for (i = 0; i < MAX_BPF_FUNC_ARGS; i++) { + /* The arg_size is at most 16 bytes, enforced by the verifier. */ if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG) - return -ENOTSUPP; + nregs += (m->arg_size[i] + 7) / 8 - 1; } - ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nargs, flags); + /* the first 8 registers are used for arguments */ + if (nregs > 8) + return -ENOTSUPP; + + ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags); if (ret < 0) return ret; @@ -1995,7 +1996,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, ctx.idx = 0; jit_fill_hole(image, (unsigned int)(image_end - image)); - ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nargs, flags); + ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags); if (ret > 0 && validate_code(&ctx) < 0) ret = -EINVAL; diff --git a/tools/testing/selftests/bpf/DENYLIST.aarch64 b/tools/testing/selftests/bpf/DENYLIST.aarch64 index cd42e2825bd2..08adc805878b 100644 --- a/tools/testing/selftests/bpf/DENYLIST.aarch64 +++ b/tools/testing/selftests/bpf/DENYLIST.aarch64 @@ -10,4 +10,3 @@ kprobe_multi_test/link_api_addrs # link_fd unexpected link_fd: a kprobe_multi_test/link_api_syms # link_fd unexpected link_fd: actual -95 < expected 0 kprobe_multi_test/skel_api # libbpf: failed to load BPF skeleton 'kprobe_multi': -3 module_attach # prog 'kprobe_multi': failed to auto-attach: -95 -tracing_struct # tracing_struct__attach unexpected error: -524 (errno 524) -- cgit v1.2.3 From 47e79cbeea4b3891ad476047f4c68543eb51c8e0 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Mon, 15 May 2023 13:08:48 +0000 Subject: bpf: Remove bpf trampoline selector After commit e21aa341785c ("bpf: Fix fexit trampoline."), the selector is only used to indicate how many times the bpf trampoline image are updated and been displayed in the trampoline ksym name. After the trampoline is freed, the selector will start from 0 again. So the selector is a useless value to the user. We can remove it. If the user want to check whether the bpf trampoline image has been updated or not, the user can compare the address. Each time the trampoline image is updated, the address will change consequently. Jiri also pointed out another issue that perf is still using the old name "bpf_trampoline_%lu", so this change can fix the issue in perf. Fixes: e21aa341785c ("bpf: Fix fexit trampoline.") Signed-off-by: Yafang Shao Signed-off-by: Daniel Borkmann Acked-by: Song Liu Cc: Jiri Olsa Link: https://lore.kernel.org/bpf/ZFvOOlrmHiY9AgXE@krava Link: https://lore.kernel.org/bpf/20230515130849.57502-3-laoar.shao@gmail.com --- include/linux/bpf.h | 1 - kernel/bpf/trampoline.c | 11 ++++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 456f33b9d205..36e4b2d8cca2 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1125,7 +1125,6 @@ struct bpf_trampoline { int progs_cnt[BPF_TRAMP_MAX]; /* Executable image of trampoline */ struct bpf_tramp_image *cur_image; - u64 selector; struct module *mod; }; diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index ac021bc43a66..84850e66ce3d 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -344,7 +344,7 @@ static void bpf_tramp_image_put(struct bpf_tramp_image *im) call_rcu_tasks_trace(&im->rcu, __bpf_tramp_image_put_rcu_tasks); } -static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key, u32 idx) +static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key) { struct bpf_tramp_image *im; struct bpf_ksym *ksym; @@ -371,7 +371,7 @@ static struct bpf_tramp_image *bpf_tramp_image_alloc(u64 key, u32 idx) ksym = &im->ksym; INIT_LIST_HEAD_RCU(&ksym->lnode); - snprintf(ksym->name, KSYM_NAME_LEN, "bpf_trampoline_%llu_%u", key, idx); + snprintf(ksym->name, KSYM_NAME_LEN, "bpf_trampoline_%llu", key); bpf_image_ksym_add(image, ksym); return im; @@ -401,11 +401,10 @@ static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut err = unregister_fentry(tr, tr->cur_image->image); bpf_tramp_image_put(tr->cur_image); tr->cur_image = NULL; - tr->selector = 0; goto out; } - im = bpf_tramp_image_alloc(tr->key, tr->selector); + im = bpf_tramp_image_alloc(tr->key); if (IS_ERR(im)) { err = PTR_ERR(im); goto out; @@ -442,8 +441,7 @@ again: set_memory_rox((long)im->image, 1); - WARN_ON(tr->cur_image && tr->selector == 0); - WARN_ON(!tr->cur_image && tr->selector); + WARN_ON(tr->cur_image && total == 0); if (tr->cur_image) /* progs already running at this address */ err = modify_fentry(tr, tr->cur_image->image, im->image, lock_direct_mutex); @@ -473,7 +471,6 @@ again: if (tr->cur_image) bpf_tramp_image_put(tr->cur_image); tr->cur_image = im; - tr->selector++; out: /* If any error happens, restore previous flags */ if (err) -- cgit v1.2.3 From 03ef5a4b322f342453a135ca8f376c09fd379024 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:07 +0200 Subject: can: at91_can: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Claudiu Beznea Link: https://lore.kernel.org/r/20230512212725.143824-2-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/at91_can.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 199cb200f2bd..4621266851ed 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -1346,7 +1346,7 @@ static int at91_can_probe(struct platform_device *pdev) return err; } -static int at91_can_remove(struct platform_device *pdev) +static void at91_can_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct at91_priv *priv = netdev_priv(dev); @@ -1362,8 +1362,6 @@ static int at91_can_remove(struct platform_device *pdev) clk_put(priv->clk); free_candev(dev); - - return 0; } static const struct platform_device_id at91_can_id_table[] = { @@ -1381,7 +1379,7 @@ MODULE_DEVICE_TABLE(platform, at91_can_id_table); static struct platform_driver at91_can_driver = { .probe = at91_can_probe, - .remove = at91_can_remove, + .remove_new = at91_can_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(at91_can_dt_ids), -- cgit v1.2.3 From cba8ed7f00434484d494cd75ef2ea8fc7fc4e0b1 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:08 +0200 Subject: can: bxcan: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-3-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/bxcan.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/bxcan.c b/drivers/net/can/bxcan.c index 7b285eeb08a1..99a4b599a655 100644 --- a/drivers/net/can/bxcan.c +++ b/drivers/net/can/bxcan.c @@ -1021,7 +1021,7 @@ out_free_candev: return err; } -static int bxcan_remove(struct platform_device *pdev) +static void bxcan_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct bxcan_priv *priv = netdev_priv(ndev); @@ -1030,7 +1030,6 @@ static int bxcan_remove(struct platform_device *pdev) clk_disable_unprepare(priv->clk); can_rx_offload_del(&priv->offload); free_candev(ndev); - return 0; } static int __maybe_unused bxcan_suspend(struct device *dev) @@ -1082,7 +1081,7 @@ static struct platform_driver bxcan_driver = { .of_match_table = bxcan_of_match, }, .probe = bxcan_probe, - .remove = bxcan_remove, + .remove_new = bxcan_remove, }; module_platform_driver(bxcan_driver); -- cgit v1.2.3 From 1708caf4c47da8d61b6f5848d74e0a6d285449c2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:09 +0200 Subject: can: c_can: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-4-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/c_can/c_can_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index 03ccb7cfacaf..925930b6c4ca 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -410,7 +410,7 @@ exit: return ret; } -static int c_can_plat_remove(struct platform_device *pdev) +static void c_can_plat_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct c_can_priv *priv = netdev_priv(dev); @@ -418,8 +418,6 @@ static int c_can_plat_remove(struct platform_device *pdev) unregister_c_can_dev(dev); pm_runtime_disable(priv->device); free_c_can_dev(dev); - - return 0; } #ifdef CONFIG_PM @@ -487,7 +485,7 @@ static struct platform_driver c_can_plat_driver = { .of_match_table = c_can_of_table, }, .probe = c_can_plat_probe, - .remove = c_can_plat_remove, + .remove_new = c_can_plat_remove, .suspend = c_can_suspend, .resume = c_can_resume, .id_table = c_can_id_table, -- cgit v1.2.3 From 88da17436973e463bed59bea79771fb03a21555e Mon Sep 17 00:00:00 2001 From: Ji-Ze Hong Date: Tue, 9 May 2023 15:38:21 +0800 Subject: can: usb: f81604: add Fintek F81604 support This patch adds support for Fintek USB to 2CAN controller. Changelog: v7: https://lore.kernel.org/all/20230509073821.25289-1-peter_hong@fintek.com.tw 1. Fix consistency of coding style for "break" in f81604_register_urbs(). 2. Remove goto statement in f81604_open(). v6: https://lore.kernel.org/all/20230505022317.22417-1-peter_hong@fintek.com.tw 1. Remove non-used define and change constant mask to GENMASK(). 2. Move some variables declaration from function start to block start. 3. Move some variables initization into declaration. 4. Change variable "id" in f81604_start_xmit() only for CAN ID usage. v5: https://lore.kernel.org/all/20230420024403.13830-1-peter_hong@fintek.com.tw 1. Change all u8 *buff to struct f81604_int_data/f81604_can_frame. 2. Change all netdev->dev_id to netdev->dev_port. 3. Remove over design for f81604_process_rx_packet(). This device only report a frame at once, so the f81604_process_rx_packet() are reduced to process 1 frame. v4: https://lore.kernel.org/all/20230413084253.1524-1-peter_hong@fintek.com.tw 1. Remove f81604_prepare_urbs/f81604_remove_urbs() and alloc URB/buffer dynamically in f81604_register_urbs(), using "urbs_anchor" for manage all rx/int URBs. 2. Add F81604 to MAINTAINERS list. 3. Change handle_clear_reg_work/handle_clear_overrun_work to single clear_reg_work and using bitwise "clear_flags" to record it. 4. Move __f81604_set_termination in front of f81604_probe() to avoid rarely racing condition. 5. Add __aligned to struct f81604_int_data / f81604_sff / f81604_eff. 6. Add aligned operations in f81604_start_xmit/f81604_process_rx_packet(). 7. Change lots of CANBUS functions first parameter from struct usb_device* to struct f81604_port_priv *priv. But remain f81604_write / f81604_read / f81604_update_bits() as struct usb_device* for __f81604_set_termination() in probe() stage. 8. Simplify f81604_read_int_callback() and separate into f81604_handle_tx / f81604_handle_can_bus_errors() functions. v3: https://lore.kernel.org/all/20230327051048.11589-1-peter_hong@fintek.com.tw 1. Change CAN clock to using MEGA units. 2. Remove USB set/get retry, only remain SJA1000 reset/operation retry. 3. Fix all numberic constant to define. 4. Add terminator control. (only 0 & 120 ohm) 5. Using struct data to represent INT/TX/RX endpoints data instead byte arrays. 6. Error message reports changed from %d to %pe for mnemotechnic values. 7. Some bit operations are changed to FIELD_PREP(). 8. Separate TX functions from f81604_read_int_callback(). 9. cf->can_id |= CAN_ERR_CNT in f81604_read_int_callback to report valid TX/RX error counts. 10. Move f81604_prepare_urbs/f81604_remove_urbs() from CAN open/close() to USB probe/disconnect(). 11. coding style refactoring. v2: https://lore.kernel.org/all/20230321081152.26510-1-peter_hong@fintek.com.tw 1. coding style refactoring. 2. some const number are defined to describe itself. 3. fix wrong usage for can_get_echo_skb() in f81604_write_bulk_callback(). v1: https://lore.kernel.org/all/20230317093352.3979-1-peter_hong@fintek.com.tw Signed-off-by: Ji-Ze Hong (Peter Hong) Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230509073821.25289-1-peter_hong@fintek.com.tw [mkl: add changelog, fix printf format] Signed-off-by: Marc Kleine-Budde --- MAINTAINERS | 6 + drivers/net/can/usb/Kconfig | 12 + drivers/net/can/usb/Makefile | 1 + drivers/net/can/usb/f81604.c | 1201 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1220 insertions(+) create mode 100644 drivers/net/can/usb/f81604.c diff --git a/MAINTAINERS b/MAINTAINERS index e2fd64c2ebdc..a83be7caa468 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7966,6 +7966,12 @@ S: Maintained F: drivers/hwmon/f75375s.c F: include/linux/f75375s.h +FINTEK F81604 USB to 2xCANBUS DEVICE DRIVER +M: Ji-Ze Hong (Peter Hong) +L: linux-can@vger.kernel.org +S: Maintained +F: drivers/net/can/usb/f81604.c + FIREWIRE AUDIO DRIVERS and IEC 61883-1/6 PACKET STREAMING ENGINE M: Clemens Ladisch M: Takashi Sakamoto diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index 445504ababce..58fcd2b34820 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -38,6 +38,18 @@ config CAN_ETAS_ES58X To compile this driver as a module, choose M here: the module will be called etas_es58x. +config CAN_F81604 + tristate "Fintek F81604 USB to 2CAN interface" + help + This driver supports the Fintek F81604 USB to 2CAN interface. + The device can support CAN2.0A/B protocol and also support + 2 output pins to control external terminator (optional). + + To compile this driver as a module, choose M here: the module will + be called f81604. + + (see also https://www.fintek.com.tw). + config CAN_GS_USB tristate "Geschwister Schneider UG and candleLight compatible interfaces" help diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile index 1ea16be5743b..8b11088e9a59 100644 --- a/drivers/net/can/usb/Makefile +++ b/drivers/net/can/usb/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o obj-$(CONFIG_CAN_ESD_USB) += esd_usb.o obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x/ +obj-$(CONFIG_CAN_F81604) += f81604.o obj-$(CONFIG_CAN_GS_USB) += gs_usb.o obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb/ obj-$(CONFIG_CAN_MCBA_USB) += mcba_usb.o diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c new file mode 100644 index 000000000000..ec8cef7fd2d5 --- /dev/null +++ b/drivers/net/can/usb/f81604.c @@ -0,0 +1,1201 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Fintek F81604 USB-to-2CAN controller driver. + * + * Copyright (C) 2023 Ji-Ze Hong (Peter Hong) + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* vendor and product id */ +#define F81604_VENDOR_ID 0x2c42 +#define F81604_PRODUCT_ID 0x1709 +#define F81604_CAN_CLOCK (12 * MEGA) +#define F81604_MAX_DEV 2 +#define F81604_SET_DEVICE_RETRY 10 + +#define F81604_USB_TIMEOUT 2000 +#define F81604_SET_GET_REGISTER 0xA0 +#define F81604_PORT_OFFSET 0x1000 +#define F81604_MAX_RX_URBS 4 + +#define F81604_CMD_DATA 0x00 + +#define F81604_DLC_LEN_MASK GENMASK(3, 0) +#define F81604_DLC_EFF_BIT BIT(7) +#define F81604_DLC_RTR_BIT BIT(6) + +#define F81604_SFF_SHIFT 5 +#define F81604_EFF_SHIFT 3 + +#define F81604_BRP_MASK GENMASK(5, 0) +#define F81604_SJW_MASK GENMASK(7, 6) + +#define F81604_SEG1_MASK GENMASK(3, 0) +#define F81604_SEG2_MASK GENMASK(6, 4) + +#define F81604_CLEAR_ALC 0 +#define F81604_CLEAR_ECC 1 +#define F81604_CLEAR_OVERRUN 2 + +/* device setting */ +#define F81604_CTRL_MODE_REG 0x80 +#define F81604_TX_ONESHOT (0x03 << 3) +#define F81604_TX_NORMAL (0x01 << 3) +#define F81604_RX_AUTO_RELEASE_BUF BIT(1) +#define F81604_INT_WHEN_CHANGE BIT(0) + +#define F81604_TERMINATOR_REG 0x105 +#define F81604_CAN0_TERM BIT(2) +#define F81604_CAN1_TERM BIT(3) + +#define F81604_TERMINATION_DISABLED CAN_TERMINATION_DISABLED +#define F81604_TERMINATION_ENABLED 120 + +/* SJA1000 registers - manual section 6.4 (Pelican Mode) */ +#define F81604_SJA1000_MOD 0x00 +#define F81604_SJA1000_CMR 0x01 +#define F81604_SJA1000_IR 0x03 +#define F81604_SJA1000_IER 0x04 +#define F81604_SJA1000_ALC 0x0B +#define F81604_SJA1000_ECC 0x0C +#define F81604_SJA1000_RXERR 0x0E +#define F81604_SJA1000_TXERR 0x0F +#define F81604_SJA1000_ACCC0 0x10 +#define F81604_SJA1000_ACCM0 0x14 +#define F81604_MAX_FILTER_CNT 4 + +/* Common registers - manual section 6.5 */ +#define F81604_SJA1000_BTR0 0x06 +#define F81604_SJA1000_BTR1 0x07 +#define F81604_SJA1000_BTR1_SAMPLE_TRIPLE BIT(7) +#define F81604_SJA1000_OCR 0x08 +#define F81604_SJA1000_CDR 0x1F + +/* mode register */ +#define F81604_SJA1000_MOD_RM 0x01 +#define F81604_SJA1000_MOD_LOM 0x02 +#define F81604_SJA1000_MOD_STM 0x04 + +/* commands */ +#define F81604_SJA1000_CMD_CDO 0x08 + +/* interrupt sources */ +#define F81604_SJA1000_IRQ_BEI 0x80 +#define F81604_SJA1000_IRQ_ALI 0x40 +#define F81604_SJA1000_IRQ_EPI 0x20 +#define F81604_SJA1000_IRQ_DOI 0x08 +#define F81604_SJA1000_IRQ_EI 0x04 +#define F81604_SJA1000_IRQ_TI 0x02 +#define F81604_SJA1000_IRQ_RI 0x01 +#define F81604_SJA1000_IRQ_ALL 0xFF +#define F81604_SJA1000_IRQ_OFF 0x00 + +/* status register content */ +#define F81604_SJA1000_SR_BS 0x80 +#define F81604_SJA1000_SR_ES 0x40 +#define F81604_SJA1000_SR_TCS 0x08 + +/* ECC register */ +#define F81604_SJA1000_ECC_SEG 0x1F +#define F81604_SJA1000_ECC_DIR 0x20 +#define F81604_SJA1000_ECC_BIT 0x00 +#define F81604_SJA1000_ECC_FORM 0x40 +#define F81604_SJA1000_ECC_STUFF 0x80 +#define F81604_SJA1000_ECC_MASK 0xc0 + +/* ALC register */ +#define F81604_SJA1000_ALC_MASK 0x1f + +/* table of devices that work with this driver */ +static const struct usb_device_id f81604_table[] = { + { USB_DEVICE(F81604_VENDOR_ID, F81604_PRODUCT_ID) }, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, f81604_table); + +static const struct ethtool_ops f81604_ethtool_ops = { + .get_ts_info = ethtool_op_get_ts_info, +}; + +static const u16 f81604_termination[] = { F81604_TERMINATION_DISABLED, + F81604_TERMINATION_ENABLED }; + +struct f81604_priv { + struct net_device *netdev[F81604_MAX_DEV]; +}; + +struct f81604_port_priv { + struct can_priv can; + struct net_device *netdev; + struct sk_buff *echo_skb; + + unsigned long clear_flags; + struct work_struct clear_reg_work; + + struct usb_device *dev; + struct usb_interface *intf; + + struct usb_anchor urbs_anchor; +}; + +/* Interrupt endpoint data format: + * Byte 0: Status register. + * Byte 1: Interrupt register. + * Byte 2: Interrupt enable register. + * Byte 3: Arbitration lost capture(ALC) register. + * Byte 4: Error code capture(ECC) register. + * Byte 5: Error warning limit register. + * Byte 6: RX error counter register. + * Byte 7: TX error counter register. + * Byte 8: Reserved. + */ +struct f81604_int_data { + u8 sr; + u8 isrc; + u8 ier; + u8 alc; + u8 ecc; + u8 ewlr; + u8 rxerr; + u8 txerr; + u8 val; +} __packed __aligned(4); + +struct f81604_sff { + __be16 id; + u8 data[CAN_MAX_DLEN]; +} __packed __aligned(2); + +struct f81604_eff { + __be32 id; + u8 data[CAN_MAX_DLEN]; +} __packed __aligned(2); + +struct f81604_can_frame { + u8 cmd; + + /* According for F81604 DLC define: + * bit 3~0: data length (0~8) + * bit6: is RTR flag. + * bit7: is EFF frame. + */ + u8 dlc; + + union { + struct f81604_sff sff; + struct f81604_eff eff; + }; +} __packed __aligned(2); + +static const u8 bulk_in_addr[F81604_MAX_DEV] = { 2, 4 }; +static const u8 bulk_out_addr[F81604_MAX_DEV] = { 1, 3 }; +static const u8 int_in_addr[F81604_MAX_DEV] = { 1, 3 }; + +static int f81604_write(struct usb_device *dev, u16 reg, u8 data) +{ + int ret; + + ret = usb_control_msg_send(dev, 0, F81604_SET_GET_REGISTER, + USB_TYPE_VENDOR | USB_DIR_OUT, 0, reg, + &data, sizeof(data), F81604_USB_TIMEOUT, + GFP_KERNEL); + if (ret) + dev_err(&dev->dev, "%s: reg: %x data: %x failed: %pe\n", + __func__, reg, data, ERR_PTR(ret)); + + return ret; +} + +static int f81604_read(struct usb_device *dev, u16 reg, u8 *data) +{ + int ret; + + ret = usb_control_msg_recv(dev, 0, F81604_SET_GET_REGISTER, + USB_TYPE_VENDOR | USB_DIR_IN, 0, reg, data, + sizeof(*data), F81604_USB_TIMEOUT, + GFP_KERNEL); + + if (ret < 0) + dev_err(&dev->dev, "%s: reg: %x failed: %pe\n", __func__, reg, + ERR_PTR(ret)); + + return ret; +} + +static int f81604_update_bits(struct usb_device *dev, u16 reg, u8 mask, + u8 data) +{ + int ret; + u8 tmp; + + ret = f81604_read(dev, reg, &tmp); + if (ret) + return ret; + + tmp &= ~mask; + tmp |= (mask & data); + + return f81604_write(dev, reg, tmp); +} + +static int f81604_sja1000_write(struct f81604_port_priv *priv, u16 reg, + u8 data) +{ + int port = priv->netdev->dev_port; + int real_reg; + + real_reg = reg + F81604_PORT_OFFSET * port + F81604_PORT_OFFSET; + return f81604_write(priv->dev, real_reg, data); +} + +static int f81604_sja1000_read(struct f81604_port_priv *priv, u16 reg, + u8 *data) +{ + int port = priv->netdev->dev_port; + int real_reg; + + real_reg = reg + F81604_PORT_OFFSET * port + F81604_PORT_OFFSET; + return f81604_read(priv->dev, real_reg, data); +} + +static int f81604_set_reset_mode(struct f81604_port_priv *priv) +{ + int ret, i; + u8 tmp; + + /* disable interrupts */ + ret = f81604_sja1000_write(priv, F81604_SJA1000_IER, + F81604_SJA1000_IRQ_OFF); + if (ret) + return ret; + + for (i = 0; i < F81604_SET_DEVICE_RETRY; i++) { + ret = f81604_sja1000_read(priv, F81604_SJA1000_MOD, &tmp); + if (ret) + return ret; + + /* check reset bit */ + if (tmp & F81604_SJA1000_MOD_RM) { + priv->can.state = CAN_STATE_STOPPED; + return 0; + } + + /* reset chip */ + ret = f81604_sja1000_write(priv, F81604_SJA1000_MOD, + F81604_SJA1000_MOD_RM); + if (ret) + return ret; + } + + return -EPERM; +} + +static int f81604_set_normal_mode(struct f81604_port_priv *priv) +{ + u8 tmp, ier = 0; + u8 mod_reg = 0; + int ret, i; + + for (i = 0; i < F81604_SET_DEVICE_RETRY; i++) { + ret = f81604_sja1000_read(priv, F81604_SJA1000_MOD, &tmp); + if (ret) + return ret; + + /* check reset bit */ + if ((tmp & F81604_SJA1000_MOD_RM) == 0) { + priv->can.state = CAN_STATE_ERROR_ACTIVE; + /* enable interrupts, RI handled by bulk-in */ + ier = F81604_SJA1000_IRQ_ALL & ~F81604_SJA1000_IRQ_RI; + if (!(priv->can.ctrlmode & + CAN_CTRLMODE_BERR_REPORTING)) + ier &= ~F81604_SJA1000_IRQ_BEI; + + return f81604_sja1000_write(priv, F81604_SJA1000_IER, + ier); + } + + /* set chip to normal mode */ + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + mod_reg |= F81604_SJA1000_MOD_LOM; + if (priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK) + mod_reg |= F81604_SJA1000_MOD_STM; + + ret = f81604_sja1000_write(priv, F81604_SJA1000_MOD, mod_reg); + if (ret) + return ret; + } + + return -EPERM; +} + +static int f81604_chipset_init(struct f81604_port_priv *priv) +{ + int i, ret; + + /* set clock divider and output control register */ + ret = f81604_sja1000_write(priv, F81604_SJA1000_CDR, + CDR_CBP | CDR_PELICAN); + if (ret) + return ret; + + /* set acceptance filter (accept all) */ + for (i = 0; i < F81604_MAX_FILTER_CNT; ++i) { + ret = f81604_sja1000_write(priv, F81604_SJA1000_ACCC0 + i, 0); + if (ret) + return ret; + } + + for (i = 0; i < F81604_MAX_FILTER_CNT; ++i) { + ret = f81604_sja1000_write(priv, F81604_SJA1000_ACCM0 + i, + 0xFF); + if (ret) + return ret; + } + + return f81604_sja1000_write(priv, F81604_SJA1000_OCR, + OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL | + OCR_MODE_NORMAL); +} + +static void f81604_process_rx_packet(struct net_device *netdev, + struct f81604_can_frame *frame) +{ + struct net_device_stats *stats = &netdev->stats; + struct can_frame *cf; + struct sk_buff *skb; + + if (frame->cmd != F81604_CMD_DATA) + return; + + skb = alloc_can_skb(netdev, &cf); + if (!skb) { + stats->rx_dropped++; + return; + } + + cf->len = can_cc_dlc2len(frame->dlc & F81604_DLC_LEN_MASK); + + if (frame->dlc & F81604_DLC_EFF_BIT) { + cf->can_id = get_unaligned_be32(&frame->eff.id) >> + F81604_EFF_SHIFT; + cf->can_id |= CAN_EFF_FLAG; + + if (!(frame->dlc & F81604_DLC_RTR_BIT)) + memcpy(cf->data, frame->eff.data, cf->len); + } else { + cf->can_id = get_unaligned_be16(&frame->sff.id) >> + F81604_SFF_SHIFT; + + if (!(frame->dlc & F81604_DLC_RTR_BIT)) + memcpy(cf->data, frame->sff.data, cf->len); + } + + if (frame->dlc & F81604_DLC_RTR_BIT) + cf->can_id |= CAN_RTR_FLAG; + else + stats->rx_bytes += cf->len; + + stats->rx_packets++; + netif_rx(skb); +} + +static void f81604_read_bulk_callback(struct urb *urb) +{ + struct f81604_can_frame *frame = urb->transfer_buffer; + struct net_device *netdev = urb->context; + int ret; + + if (!netif_device_present(netdev)) + return; + + if (urb->status) + netdev_info(netdev, "%s: URB aborted %pe\n", __func__, + ERR_PTR(urb->status)); + + switch (urb->status) { + case 0: /* success */ + break; + + case -ENOENT: + case -EPIPE: + case -EPROTO: + case -ESHUTDOWN: + return; + + default: + goto resubmit_urb; + } + + if (urb->actual_length != sizeof(*frame)) { + netdev_warn(netdev, "URB length %u not equal to %zu\n", + urb->actual_length, sizeof(*frame)); + goto resubmit_urb; + } + + f81604_process_rx_packet(netdev, frame); + +resubmit_urb: + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret == -ENODEV) + netif_device_detach(netdev); + else if (ret) + netdev_err(netdev, + "%s: failed to resubmit read bulk urb: %pe\n", + __func__, ERR_PTR(ret)); +} + +static void f81604_handle_tx(struct f81604_port_priv *priv, + struct f81604_int_data *data) +{ + struct net_device *netdev = priv->netdev; + struct net_device_stats *stats = &netdev->stats; + + /* transmission buffer released */ + if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT && + !(data->sr & F81604_SJA1000_SR_TCS)) { + stats->tx_errors++; + can_free_echo_skb(netdev, 0, NULL); + } else { + /* transmission complete */ + stats->tx_bytes += can_get_echo_skb(netdev, 0, NULL); + stats->tx_packets++; + } + + netif_wake_queue(netdev); +} + +static void f81604_handle_can_bus_errors(struct f81604_port_priv *priv, + struct f81604_int_data *data) +{ + enum can_state can_state = priv->can.state; + struct net_device *netdev = priv->netdev; + struct net_device_stats *stats = &netdev->stats; + struct can_frame *cf; + struct sk_buff *skb; + + /* Note: ALC/ECC will not auto clear by read here, must be cleared by + * read register (via clear_reg_work). + */ + + skb = alloc_can_err_skb(netdev, &cf); + if (skb) { + cf->can_id |= CAN_ERR_CNT; + cf->data[6] = data->txerr; + cf->data[7] = data->rxerr; + } + + if (data->isrc & F81604_SJA1000_IRQ_DOI) { + /* data overrun interrupt */ + netdev_dbg(netdev, "data overrun interrupt\n"); + + if (skb) { + cf->can_id |= CAN_ERR_CRTL; + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; + } + + stats->rx_over_errors++; + stats->rx_errors++; + + set_bit(F81604_CLEAR_OVERRUN, &priv->clear_flags); + } + + if (data->isrc & F81604_SJA1000_IRQ_EI) { + /* error warning interrupt */ + netdev_dbg(netdev, "error warning interrupt\n"); + + if (data->sr & F81604_SJA1000_SR_BS) + can_state = CAN_STATE_BUS_OFF; + else if (data->sr & F81604_SJA1000_SR_ES) + can_state = CAN_STATE_ERROR_WARNING; + else + can_state = CAN_STATE_ERROR_ACTIVE; + } + + if (data->isrc & F81604_SJA1000_IRQ_BEI) { + /* bus error interrupt */ + 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; + + /* set error type */ + switch (data->ecc & F81604_SJA1000_ECC_MASK) { + case F81604_SJA1000_ECC_BIT: + cf->data[2] |= CAN_ERR_PROT_BIT; + break; + case F81604_SJA1000_ECC_FORM: + cf->data[2] |= CAN_ERR_PROT_FORM; + break; + case F81604_SJA1000_ECC_STUFF: + cf->data[2] |= CAN_ERR_PROT_STUFF; + break; + default: + break; + } + + /* set error location */ + cf->data[3] = data->ecc & F81604_SJA1000_ECC_SEG; + + /* Error occurred during transmission? */ + if ((data->ecc & F81604_SJA1000_ECC_DIR) == 0) + cf->data[2] |= CAN_ERR_PROT_TX; + } + + set_bit(F81604_CLEAR_ECC, &priv->clear_flags); + } + + if (data->isrc & F81604_SJA1000_IRQ_EPI) { + if (can_state == CAN_STATE_ERROR_PASSIVE) + can_state = CAN_STATE_ERROR_WARNING; + else + can_state = CAN_STATE_ERROR_PASSIVE; + + /* error passive interrupt */ + netdev_dbg(netdev, "error passive interrupt: %d\n", can_state); + } + + if (data->isrc & F81604_SJA1000_IRQ_ALI) { + /* arbitration lost interrupt */ + netdev_dbg(netdev, "arbitration lost interrupt\n"); + + priv->can.can_stats.arbitration_lost++; + + if (skb) { + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] = data->alc & F81604_SJA1000_ALC_MASK; + } + + set_bit(F81604_CLEAR_ALC, &priv->clear_flags); + } + + if (can_state != priv->can.state) { + enum can_state tx_state, rx_state; + + tx_state = data->txerr >= data->rxerr ? can_state : 0; + rx_state = data->txerr <= data->rxerr ? can_state : 0; + + can_change_state(netdev, cf, tx_state, rx_state); + + if (can_state == CAN_STATE_BUS_OFF) + can_bus_off(netdev); + } + + if (priv->clear_flags) + schedule_work(&priv->clear_reg_work); + + if (skb) + netif_rx(skb); +} + +static void f81604_read_int_callback(struct urb *urb) +{ + struct f81604_int_data *data = urb->transfer_buffer; + struct net_device *netdev = urb->context; + struct f81604_port_priv *priv; + int ret; + + priv = netdev_priv(netdev); + + if (!netif_device_present(netdev)) + return; + + if (urb->status) + netdev_info(netdev, "%s: Int URB aborted: %pe\n", __func__, + ERR_PTR(urb->status)); + + switch (urb->status) { + case 0: /* success */ + break; + + case -ENOENT: + case -EPIPE: + case -EPROTO: + case -ESHUTDOWN: + return; + + default: + goto resubmit_urb; + } + + /* handle Errors */ + if (data->isrc & (F81604_SJA1000_IRQ_DOI | F81604_SJA1000_IRQ_EI | + F81604_SJA1000_IRQ_BEI | F81604_SJA1000_IRQ_EPI | + F81604_SJA1000_IRQ_ALI)) + f81604_handle_can_bus_errors(priv, data); + + /* handle TX */ + if (priv->can.state != CAN_STATE_BUS_OFF && + (data->isrc & F81604_SJA1000_IRQ_TI)) + f81604_handle_tx(priv, data); + +resubmit_urb: + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret == -ENODEV) + netif_device_detach(netdev); + else if (ret) + netdev_err(netdev, "%s: failed to resubmit int urb: %pe\n", + __func__, ERR_PTR(ret)); +} + +static void f81604_unregister_urbs(struct f81604_port_priv *priv) +{ + usb_kill_anchored_urbs(&priv->urbs_anchor); +} + +static int f81604_register_urbs(struct f81604_port_priv *priv) +{ + struct net_device *netdev = priv->netdev; + struct f81604_int_data *int_data; + int id = netdev->dev_port; + struct urb *int_urb; + int rx_urb_cnt; + int ret; + + for (rx_urb_cnt = 0; rx_urb_cnt < F81604_MAX_RX_URBS; ++rx_urb_cnt) { + struct f81604_can_frame *frame; + struct urb *rx_urb; + + rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rx_urb) { + ret = -ENOMEM; + break; + } + + frame = kmalloc(sizeof(*frame), GFP_KERNEL); + if (!frame) { + usb_free_urb(rx_urb); + ret = -ENOMEM; + break; + } + + usb_fill_bulk_urb(rx_urb, priv->dev, + usb_rcvbulkpipe(priv->dev, bulk_in_addr[id]), + frame, sizeof(*frame), + f81604_read_bulk_callback, netdev); + + rx_urb->transfer_flags |= URB_FREE_BUFFER; + usb_anchor_urb(rx_urb, &priv->urbs_anchor); + + ret = usb_submit_urb(rx_urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(rx_urb); + usb_free_urb(rx_urb); + break; + } + + /* Drop reference, USB core will take care of freeing it */ + usb_free_urb(rx_urb); + } + + if (rx_urb_cnt == 0) { + netdev_warn(netdev, "%s: submit rx urb failed: %pe\n", + __func__, ERR_PTR(ret)); + + goto error; + } + + int_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!int_urb) { + ret = -ENOMEM; + goto error; + } + + int_data = kmalloc(sizeof(*int_data), GFP_KERNEL); + if (!int_data) { + usb_free_urb(int_urb); + ret = -ENOMEM; + goto error; + } + + usb_fill_int_urb(int_urb, priv->dev, + usb_rcvintpipe(priv->dev, int_in_addr[id]), int_data, + sizeof(*int_data), f81604_read_int_callback, netdev, + 1); + + int_urb->transfer_flags |= URB_FREE_BUFFER; + usb_anchor_urb(int_urb, &priv->urbs_anchor); + + ret = usb_submit_urb(int_urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(int_urb); + usb_free_urb(int_urb); + + netdev_warn(netdev, "%s: submit int urb failed: %pe\n", + __func__, ERR_PTR(ret)); + goto error; + } + + /* Drop reference, USB core will take care of freeing it */ + usb_free_urb(int_urb); + + return 0; + +error: + f81604_unregister_urbs(priv); + return ret; +} + +static int f81604_start(struct net_device *netdev) +{ + struct f81604_port_priv *priv = netdev_priv(netdev); + int ret; + u8 mode; + u8 tmp; + + mode = F81604_RX_AUTO_RELEASE_BUF | F81604_INT_WHEN_CHANGE; + + /* Set TR/AT mode */ + if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) + mode |= F81604_TX_ONESHOT; + else + mode |= F81604_TX_NORMAL; + + ret = f81604_sja1000_write(priv, F81604_CTRL_MODE_REG, mode); + if (ret) + return ret; + + /* set reset mode */ + ret = f81604_set_reset_mode(priv); + if (ret) + return ret; + + ret = f81604_chipset_init(priv); + if (ret) + return ret; + + /* Clear error counters and error code capture */ + ret = f81604_sja1000_write(priv, F81604_SJA1000_TXERR, 0); + if (ret) + return ret; + + ret = f81604_sja1000_write(priv, F81604_SJA1000_RXERR, 0); + if (ret) + return ret; + + /* Read clear for ECC/ALC/IR register */ + ret = f81604_sja1000_read(priv, F81604_SJA1000_ECC, &tmp); + if (ret) + return ret; + + ret = f81604_sja1000_read(priv, F81604_SJA1000_ALC, &tmp); + if (ret) + return ret; + + ret = f81604_sja1000_read(priv, F81604_SJA1000_IR, &tmp); + if (ret) + return ret; + + ret = f81604_register_urbs(priv); + if (ret) + return ret; + + ret = f81604_set_normal_mode(priv); + if (ret) { + f81604_unregister_urbs(priv); + return ret; + } + + return 0; +} + +static int f81604_set_bittiming(struct net_device *dev) +{ + struct f81604_port_priv *priv = netdev_priv(dev); + struct can_bittiming *bt = &priv->can.bittiming; + u8 btr0, btr1; + int ret; + + btr0 = FIELD_PREP(F81604_BRP_MASK, bt->brp - 1) | + FIELD_PREP(F81604_SJW_MASK, bt->sjw - 1); + + btr1 = FIELD_PREP(F81604_SEG1_MASK, + bt->prop_seg + bt->phase_seg1 - 1) | + FIELD_PREP(F81604_SEG2_MASK, bt->phase_seg2 - 1); + + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) + btr1 |= F81604_SJA1000_BTR1_SAMPLE_TRIPLE; + + ret = f81604_sja1000_write(priv, F81604_SJA1000_BTR0, btr0); + if (ret) { + netdev_warn(dev, "%s: Set BTR0 failed: %pe\n", __func__, + ERR_PTR(ret)); + return ret; + } + + ret = f81604_sja1000_write(priv, F81604_SJA1000_BTR1, btr1); + if (ret) { + netdev_warn(dev, "%s: Set BTR1 failed: %pe\n", __func__, + ERR_PTR(ret)); + return ret; + } + + return 0; +} + +static int f81604_set_mode(struct net_device *netdev, enum can_mode mode) +{ + int ret; + + switch (mode) { + case CAN_MODE_START: + ret = f81604_start(netdev); + if (!ret && netif_queue_stopped(netdev)) + netif_wake_queue(netdev); + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static void f81604_write_bulk_callback(struct urb *urb) +{ + struct net_device *netdev = urb->context; + + if (!netif_device_present(netdev)) + return; + + if (urb->status) + netdev_info(netdev, "%s: Tx URB error: %pe\n", __func__, + ERR_PTR(urb->status)); +} + +static void f81604_clear_reg_work(struct work_struct *work) +{ + struct f81604_port_priv *priv; + u8 tmp; + + priv = container_of(work, struct f81604_port_priv, clear_reg_work); + + /* dummy read for clear Arbitration lost capture(ALC) register. */ + if (test_and_clear_bit(F81604_CLEAR_ALC, &priv->clear_flags)) + f81604_sja1000_read(priv, F81604_SJA1000_ALC, &tmp); + + /* dummy read for clear Error code capture(ECC) register. */ + if (test_and_clear_bit(F81604_CLEAR_ECC, &priv->clear_flags)) + f81604_sja1000_read(priv, F81604_SJA1000_ECC, &tmp); + + /* dummy write for clear data overrun flag. */ + if (test_and_clear_bit(F81604_CLEAR_OVERRUN, &priv->clear_flags)) + f81604_sja1000_write(priv, F81604_SJA1000_CMR, + F81604_SJA1000_CMD_CDO); +} + +static netdev_tx_t f81604_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct can_frame *cf = (struct can_frame *)skb->data; + struct f81604_port_priv *priv = netdev_priv(netdev); + struct net_device_stats *stats = &netdev->stats; + struct f81604_can_frame *frame; + struct urb *write_urb; + int ret; + + if (can_dev_dropped_skb(netdev, skb)) + return NETDEV_TX_OK; + + netif_stop_queue(netdev); + + write_urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!write_urb) + goto nomem_urb; + + frame = kzalloc(sizeof(*frame), GFP_ATOMIC); + if (!frame) + goto nomem_buf; + + usb_fill_bulk_urb(write_urb, priv->dev, + usb_sndbulkpipe(priv->dev, + bulk_out_addr[netdev->dev_port]), + frame, sizeof(*frame), f81604_write_bulk_callback, + priv->netdev); + + write_urb->transfer_flags |= URB_FREE_BUFFER; + + frame->cmd = F81604_CMD_DATA; + frame->dlc = cf->len; + + if (cf->can_id & CAN_RTR_FLAG) + frame->dlc |= F81604_DLC_RTR_BIT; + + if (cf->can_id & CAN_EFF_FLAG) { + u32 id = (cf->can_id & CAN_EFF_MASK) << F81604_EFF_SHIFT; + + put_unaligned_be32(id, &frame->eff.id); + + frame->dlc |= F81604_DLC_EFF_BIT; + + if (!(cf->can_id & CAN_RTR_FLAG)) + memcpy(&frame->eff.data, cf->data, cf->len); + } else { + u32 id = (cf->can_id & CAN_SFF_MASK) << F81604_SFF_SHIFT; + + put_unaligned_be16(id, &frame->sff.id); + + if (!(cf->can_id & CAN_RTR_FLAG)) + memcpy(&frame->sff.data, cf->data, cf->len); + } + + can_put_echo_skb(skb, netdev, 0, 0); + + ret = usb_submit_urb(write_urb, GFP_ATOMIC); + if (ret) { + netdev_err(netdev, "%s: failed to resubmit tx bulk urb: %pe\n", + __func__, ERR_PTR(ret)); + + can_free_echo_skb(netdev, 0, NULL); + stats->tx_dropped++; + stats->tx_errors++; + + if (ret == -ENODEV) + netif_device_detach(netdev); + else + netif_wake_queue(netdev); + } + + /* let usb core take care of this urb */ + usb_free_urb(write_urb); + + return NETDEV_TX_OK; + +nomem_buf: + usb_free_urb(write_urb); + +nomem_urb: + dev_kfree_skb(skb); + stats->tx_dropped++; + stats->tx_errors++; + netif_wake_queue(netdev); + + return NETDEV_TX_OK; +} + +static int f81604_get_berr_counter(const struct net_device *netdev, + struct can_berr_counter *bec) +{ + struct f81604_port_priv *priv = netdev_priv(netdev); + u8 txerr, rxerr; + int ret; + + ret = f81604_sja1000_read(priv, F81604_SJA1000_TXERR, &txerr); + if (ret) + return ret; + + ret = f81604_sja1000_read(priv, F81604_SJA1000_RXERR, &rxerr); + if (ret) + return ret; + + bec->txerr = txerr; + bec->rxerr = rxerr; + + return 0; +} + +/* Open USB device */ +static int f81604_open(struct net_device *netdev) +{ + int ret; + + ret = open_candev(netdev); + if (ret) + return ret; + + ret = f81604_start(netdev); + if (ret) { + if (ret == -ENODEV) + netif_device_detach(netdev); + + close_candev(netdev); + return ret; + } + + netif_start_queue(netdev); + return 0; +} + +/* Close USB device */ +static int f81604_close(struct net_device *netdev) +{ + struct f81604_port_priv *priv = netdev_priv(netdev); + + f81604_set_reset_mode(priv); + + netif_stop_queue(netdev); + cancel_work_sync(&priv->clear_reg_work); + close_candev(netdev); + + f81604_unregister_urbs(priv); + + return 0; +} + +static const struct net_device_ops f81604_netdev_ops = { + .ndo_open = f81604_open, + .ndo_stop = f81604_close, + .ndo_start_xmit = f81604_start_xmit, + .ndo_change_mtu = can_change_mtu, +}; + +static const struct can_bittiming_const f81604_bittiming_const = { + .name = KBUILD_MODNAME, + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 64, + .brp_inc = 1, +}; + +/* Called by the usb core when driver is unloaded or device is removed */ +static void f81604_disconnect(struct usb_interface *intf) +{ + struct f81604_priv *priv = usb_get_intfdata(intf); + int i; + + for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) { + if (!priv->netdev[i]) + continue; + + unregister_netdev(priv->netdev[i]); + free_candev(priv->netdev[i]); + } +} + +static int __f81604_set_termination(struct usb_device *dev, int idx, u16 term) +{ + u8 mask, data = 0; + + if (idx == 0) + mask = F81604_CAN0_TERM; + else + mask = F81604_CAN1_TERM; + + if (term) + data = mask; + + return f81604_update_bits(dev, F81604_TERMINATOR_REG, mask, data); +} + +static int f81604_set_termination(struct net_device *netdev, u16 term) +{ + struct f81604_port_priv *port_priv = netdev_priv(netdev); + + ASSERT_RTNL(); + + return __f81604_set_termination(port_priv->dev, netdev->dev_port, + term); +} + +static int f81604_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct net_device *netdev; + struct f81604_priv *priv; + int i, ret; + + priv = devm_kzalloc(&intf->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + usb_set_intfdata(intf, priv); + + for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) { + ret = __f81604_set_termination(dev, i, 0); + if (ret) { + dev_err(&intf->dev, + "Setting termination of CH#%d failed: %pe\n", + i, ERR_PTR(ret)); + return ret; + } + } + + for (i = 0; i < ARRAY_SIZE(priv->netdev); ++i) { + struct f81604_port_priv *port_priv; + + netdev = alloc_candev(sizeof(*port_priv), 1); + if (!netdev) { + dev_err(&intf->dev, "Couldn't alloc candev: %d\n", i); + ret = -ENOMEM; + + goto failure_cleanup; + } + + port_priv = netdev_priv(netdev); + + INIT_WORK(&port_priv->clear_reg_work, f81604_clear_reg_work); + init_usb_anchor(&port_priv->urbs_anchor); + + port_priv->intf = intf; + port_priv->dev = dev; + port_priv->netdev = netdev; + port_priv->can.clock.freq = F81604_CAN_CLOCK; + + port_priv->can.termination_const = f81604_termination; + port_priv->can.termination_const_cnt = + ARRAY_SIZE(f81604_termination); + port_priv->can.bittiming_const = &f81604_bittiming_const; + port_priv->can.do_set_bittiming = f81604_set_bittiming; + port_priv->can.do_set_mode = f81604_set_mode; + port_priv->can.do_set_termination = f81604_set_termination; + port_priv->can.do_get_berr_counter = f81604_get_berr_counter; + port_priv->can.ctrlmode_supported = + CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | + CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_BERR_REPORTING | + CAN_CTRLMODE_PRESUME_ACK; + + netdev->ethtool_ops = &f81604_ethtool_ops; + netdev->netdev_ops = &f81604_netdev_ops; + netdev->flags |= IFF_ECHO; + netdev->dev_port = i; + + SET_NETDEV_DEV(netdev, &intf->dev); + + ret = register_candev(netdev); + if (ret) { + netdev_err(netdev, "register CAN device failed: %pe\n", + ERR_PTR(ret)); + free_candev(netdev); + + goto failure_cleanup; + } + + priv->netdev[i] = netdev; + } + + return 0; + +failure_cleanup: + f81604_disconnect(intf); + return ret; +} + +static struct usb_driver f81604_driver = { + .name = KBUILD_MODNAME, + .probe = f81604_probe, + .disconnect = f81604_disconnect, + .id_table = f81604_table, +}; + +module_usb_driver(f81604_driver); + +MODULE_AUTHOR("Ji-Ze Hong (Peter Hong) "); +MODULE_DESCRIPTION("Fintek F81604 USB to 2xCANBUS"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 938100762293641ba1359b2a3cd6d2134ffaa8f2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:10 +0200 Subject: can: cc770_isa: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-5-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/cc770/cc770_isa.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/cc770/cc770_isa.c b/drivers/net/can/cc770/cc770_isa.c index 8f6dccd5a587..22009440a983 100644 --- a/drivers/net/can/cc770/cc770_isa.c +++ b/drivers/net/can/cc770/cc770_isa.c @@ -285,7 +285,7 @@ exit: return err; } -static int cc770_isa_remove(struct platform_device *pdev) +static void cc770_isa_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct cc770_priv *priv = netdev_priv(dev); @@ -303,13 +303,11 @@ static int cc770_isa_remove(struct platform_device *pdev) release_region(port[idx], CC770_IOSIZE); } free_cc770dev(dev); - - return 0; } static struct platform_driver cc770_isa_driver = { .probe = cc770_isa_probe, - .remove = cc770_isa_remove, + .remove_new = cc770_isa_remove, .driver = { .name = KBUILD_MODNAME, }, -- cgit v1.2.3 From cca7d85ad80cda5658acac06bb99461329c41d70 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Sat, 6 May 2023 16:07:25 +0800 Subject: can: bxcan: Remove unnecessary print function dev_err() The print function dev_err() is redundant because platform_get_irq_byname() already prints an error. ./drivers/net/can/bxcan.c:970:2-9: line 970 is redundant because platform_get_irq() already prints an error. ./drivers/net/can/bxcan.c:964:2-9: line 964 is redundant because platform_get_irq() already prints an error. ./drivers/net/can/bxcan.c:958:2-9: line 958 is redundant because platform_get_irq() already prints an error. Reported-by: Abaci Robot Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=4878 Signed-off-by: Jiapeng Chong Reviewed-by: Simon Horman Link: https://lore.kernel.org/all/20230506080725.68401-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/bxcan.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/net/can/bxcan.c b/drivers/net/can/bxcan.c index e26ccd41e3cb..7b285eeb08a1 100644 --- a/drivers/net/can/bxcan.c +++ b/drivers/net/can/bxcan.c @@ -954,22 +954,16 @@ static int bxcan_probe(struct platform_device *pdev) } rx_irq = platform_get_irq_byname(pdev, "rx0"); - if (rx_irq < 0) { - dev_err(dev, "failed to get rx0 irq\n"); + if (rx_irq < 0) return rx_irq; - } tx_irq = platform_get_irq_byname(pdev, "tx"); - if (tx_irq < 0) { - dev_err(dev, "failed to get tx irq\n"); + if (tx_irq < 0) return tx_irq; - } sce_irq = platform_get_irq_byname(pdev, "sce"); - if (sce_irq < 0) { - dev_err(dev, "failed to get sce irq\n"); + if (sce_irq < 0) return sce_irq; - } ndev = alloc_candev(sizeof(struct bxcan_priv), BXCAN_TX_MB_NUM); if (!ndev) { -- cgit v1.2.3 From 86eb8a19b477a878779c0e9d2888580ed14a59b6 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:11 +0200 Subject: can: cc770_platform: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-6-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/cc770/cc770_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c index 8dcc32e4e30e..13bcfba05f18 100644 --- a/drivers/net/can/cc770/cc770_platform.c +++ b/drivers/net/can/cc770/cc770_platform.c @@ -230,7 +230,7 @@ exit_release_mem: return err; } -static int cc770_platform_remove(struct platform_device *pdev) +static void cc770_platform_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct cc770_priv *priv = netdev_priv(dev); @@ -242,8 +242,6 @@ static int cc770_platform_remove(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(mem->start, resource_size(mem)); - - return 0; } static const struct of_device_id cc770_platform_table[] = { @@ -259,7 +257,7 @@ static struct platform_driver cc770_platform_driver = { .of_match_table = cc770_platform_table, }, .probe = cc770_platform_probe, - .remove = cc770_platform_remove, + .remove_new = cc770_platform_remove, }; module_platform_driver(cc770_platform_driver); -- cgit v1.2.3 From 6882011e8854c6cb227770fccb57ed70a88a716f Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sun, 23 Apr 2023 13:06:39 +0200 Subject: can: length: make header self contained Include the headers that "can/length.h" depends on. Fixes: bdd2e413192d ("can: dev: move length related code into seperate file") Link: https://lore.kernel.org/all/20230509122854.350426-1-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- include/linux/can/length.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/can/length.h b/include/linux/can/length.h index 6995092b774e..69336549d24f 100644 --- a/include/linux/can/length.h +++ b/include/linux/can/length.h @@ -6,6 +6,9 @@ #ifndef _CAN_LENGTH_H #define _CAN_LENGTH_H +#include +#include + /* * Size of a Classical CAN Standard Frame * -- cgit v1.2.3 From 45413bf759193d9c677746b5e52b96d60d9fa94f Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:12 +0200 Subject: can: ctucanfd: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Pavel Pisa Link: https://lore.kernel.org/r/20230512212725.143824-7-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ctucanfd/ctucanfd_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/ctucanfd/ctucanfd_platform.c b/drivers/net/can/ctucanfd/ctucanfd_platform.c index a17561d97192..55bb10b157b4 100644 --- a/drivers/net/can/ctucanfd/ctucanfd_platform.c +++ b/drivers/net/can/ctucanfd/ctucanfd_platform.c @@ -86,7 +86,7 @@ err: * This function frees all the resources allocated to the device. * Return: 0 always */ -static int ctucan_platform_remove(struct platform_device *pdev) +static void ctucan_platform_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct ctucan_priv *priv = netdev_priv(ndev); @@ -97,8 +97,6 @@ static int ctucan_platform_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); netif_napi_del(&priv->napi); free_candev(ndev); - - return 0; } static SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume); @@ -113,7 +111,7 @@ MODULE_DEVICE_TABLE(of, ctucan_of_match); static struct platform_driver ctucanfd_driver = { .probe = ctucan_platform_probe, - .remove = ctucan_platform_remove, + .remove_new = ctucan_platform_remove, .driver = { .name = DRV_NAME, .pm = &ctucan_platform_pm_ops, -- cgit v1.2.3 From 55216590c9cf545f15e443953fe97cd8fe52407b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:13 +0200 Subject: can: flexcan: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-8-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan/flexcan-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c index 6d638c93977b..ff0fc18baf13 100644 --- a/drivers/net/can/flexcan/flexcan-core.c +++ b/drivers/net/can/flexcan/flexcan-core.c @@ -2218,7 +2218,7 @@ static int flexcan_probe(struct platform_device *pdev) return err; } -static int flexcan_remove(struct platform_device *pdev) +static void flexcan_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); @@ -2227,8 +2227,6 @@ static int flexcan_remove(struct platform_device *pdev) unregister_flexcandev(dev); pm_runtime_disable(&pdev->dev); free_candev(dev); - - return 0; } static int __maybe_unused flexcan_suspend(struct device *device) @@ -2379,7 +2377,7 @@ static struct platform_driver flexcan_driver = { .of_match_table = flexcan_of_match, }, .probe = flexcan_probe, - .remove = flexcan_remove, + .remove_new = flexcan_remove, .id_table = flexcan_id_table, }; -- cgit v1.2.3 From 6aa62362f14d07d7541fb723b0365d7f513a9090 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:14 +0200 Subject: can: grcan: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-9-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/grcan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index 4bedcc3eea0d..3174efdae271 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -1696,7 +1696,7 @@ exit_error: return err; } -static int grcan_remove(struct platform_device *ofdev) +static void grcan_remove(struct platform_device *ofdev) { struct net_device *dev = platform_get_drvdata(ofdev); struct grcan_priv *priv = netdev_priv(dev); @@ -1706,8 +1706,6 @@ static int grcan_remove(struct platform_device *ofdev) irq_dispose_mapping(dev->irq); netif_napi_del(&priv->napi); free_candev(dev); - - return 0; } static const struct of_device_id grcan_match[] = { @@ -1726,7 +1724,7 @@ static struct platform_driver grcan_driver = { .of_match_table = grcan_match, }, .probe = grcan_probe, - .remove = grcan_remove, + .remove_new = grcan_remove, }; module_platform_driver(grcan_driver); -- cgit v1.2.3 From a5095a9810187b30d57b8c565024972eae7b7025 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:15 +0200 Subject: can: ifi_canfd: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-10-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ifi_canfd/ifi_canfd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index 07eaf724a572..1d6642c94f2f 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -1013,15 +1013,13 @@ err_reg: return ret; } -static int ifi_canfd_plat_remove(struct platform_device *pdev) +static void ifi_canfd_plat_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); unregister_candev(ndev); platform_set_drvdata(pdev, NULL); free_candev(ndev); - - return 0; } static const struct of_device_id ifi_canfd_of_table[] = { @@ -1036,7 +1034,7 @@ static struct platform_driver ifi_canfd_plat_driver = { .of_match_table = ifi_canfd_of_table, }, .probe = ifi_canfd_plat_probe, - .remove = ifi_canfd_plat_remove, + .remove_new = ifi_canfd_plat_remove, }; module_platform_driver(ifi_canfd_plat_driver); -- cgit v1.2.3 From 3ac96f45aac6b35af20f860bed4976023b0589f0 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:16 +0200 Subject: can: janz-ican3: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-11-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/janz-ican3.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 0732a5092141..d048ea565b89 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -2023,7 +2023,7 @@ out_return: return ret; } -static int ican3_remove(struct platform_device *pdev) +static void ican3_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct ican3_dev *mod = netdev_priv(ndev); @@ -2042,8 +2042,6 @@ static int ican3_remove(struct platform_device *pdev) iounmap(mod->dpm); free_candev(ndev); - - return 0; } static struct platform_driver ican3_driver = { @@ -2051,7 +2049,7 @@ static struct platform_driver ican3_driver = { .name = DRV_NAME, }, .probe = ican3_probe, - .remove = ican3_remove, + .remove_new = ican3_remove, }; module_platform_driver(ican3_driver); -- cgit v1.2.3 From 2d7c33d032ffec3b57b2c7841ad26b392bbe30b9 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:17 +0200 Subject: can: m_can: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-12-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c index 9c1dcf838006..94dc82644113 100644 --- a/drivers/net/can/m_can/m_can_platform.c +++ b/drivers/net/can/m_can/m_can_platform.c @@ -164,7 +164,7 @@ static __maybe_unused int m_can_resume(struct device *dev) return m_can_class_resume(dev); } -static int m_can_plat_remove(struct platform_device *pdev) +static void m_can_plat_remove(struct platform_device *pdev) { struct m_can_plat_priv *priv = platform_get_drvdata(pdev); struct m_can_classdev *mcan_class = &priv->cdev; @@ -172,8 +172,6 @@ static int m_can_plat_remove(struct platform_device *pdev) m_can_class_unregister(mcan_class); m_can_class_free_dev(mcan_class->net); - - return 0; } static int __maybe_unused m_can_runtime_suspend(struct device *dev) @@ -223,7 +221,7 @@ static struct platform_driver m_can_plat_driver = { .pm = &m_can_pmops, }, .probe = m_can_plat_probe, - .remove = m_can_plat_remove, + .remove_new = m_can_plat_remove, }; module_platform_driver(m_can_plat_driver); -- cgit v1.2.3 From 36157299e67bd11effcb961fd7ffb67f16e9f4e3 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:18 +0200 Subject: can: mscan: mpc5xxx_can: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-13-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/mscan/mpc5xxx_can.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index b0ed798ae70f..4837df6efa92 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -349,7 +349,7 @@ exit_unmap_mem: return err; } -static int mpc5xxx_can_remove(struct platform_device *ofdev) +static void mpc5xxx_can_remove(struct platform_device *ofdev) { const struct of_device_id *match; const struct mpc5xxx_can_data *data; @@ -365,8 +365,6 @@ static int mpc5xxx_can_remove(struct platform_device *ofdev) iounmap(priv->reg_base); irq_dispose_mapping(dev->irq); free_candev(dev); - - return 0; } #ifdef CONFIG_PM @@ -437,7 +435,7 @@ static struct platform_driver mpc5xxx_can_driver = { .of_match_table = mpc5xxx_can_table, }, .probe = mpc5xxx_can_probe, - .remove = mpc5xxx_can_remove, + .remove_new = mpc5xxx_can_remove, #ifdef CONFIG_PM .suspend = mpc5xxx_can_suspend, .resume = mpc5xxx_can_resume, -- cgit v1.2.3 From ae08f87afff708ad5414f29eab00fec2e9fa155e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:19 +0200 Subject: can: rcar: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert these drivers from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230512212725.143824-14-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rcar/rcar_can.c | 5 ++--- drivers/net/can/rcar/rcar_canfd.c | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c index cc43c9c5e38c..f5aa5dbacaf2 100644 --- a/drivers/net/can/rcar/rcar_can.c +++ b/drivers/net/can/rcar/rcar_can.c @@ -824,7 +824,7 @@ fail: return err; } -static int rcar_can_remove(struct platform_device *pdev) +static void rcar_can_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct rcar_can_priv *priv = netdev_priv(ndev); @@ -832,7 +832,6 @@ static int rcar_can_remove(struct platform_device *pdev) unregister_candev(ndev); netif_napi_del(&priv->napi); free_candev(ndev); - return 0; } static int __maybe_unused rcar_can_suspend(struct device *dev) @@ -908,7 +907,7 @@ static struct platform_driver rcar_can_driver = { .pm = &rcar_can_pm_ops, }, .probe = rcar_can_probe, - .remove = rcar_can_remove, + .remove_new = rcar_can_remove, }; module_platform_driver(rcar_can_driver); diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index 963c42f43755..e4d748913439 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -2078,7 +2078,7 @@ fail_dev: return err; } -static int rcar_canfd_remove(struct platform_device *pdev) +static void rcar_canfd_remove(struct platform_device *pdev) { struct rcar_canfd_global *gpriv = platform_get_drvdata(pdev); u32 ch; @@ -2096,8 +2096,6 @@ static int rcar_canfd_remove(struct platform_device *pdev) clk_disable_unprepare(gpriv->clkp); reset_control_assert(gpriv->rstc1); reset_control_assert(gpriv->rstc2); - - return 0; } static int __maybe_unused rcar_canfd_suspend(struct device *dev) @@ -2130,7 +2128,7 @@ static struct platform_driver rcar_canfd_driver = { .pm = &rcar_canfd_pm_ops, }, .probe = rcar_canfd_probe, - .remove = rcar_canfd_remove, + .remove_new = rcar_canfd_remove, }; module_platform_driver(rcar_canfd_driver); -- cgit v1.2.3 From 0367b598afbe81ba9b4881f923e0aeb8c7babdea Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:20 +0200 Subject: can: sja1000_isa: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-15-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000_isa.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c index db3e767d5320..fca5a9a1d857 100644 --- a/drivers/net/can/sja1000/sja1000_isa.c +++ b/drivers/net/can/sja1000/sja1000_isa.c @@ -223,7 +223,7 @@ exit: return err; } -static int sja1000_isa_remove(struct platform_device *pdev) +static void sja1000_isa_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct sja1000_priv *priv = netdev_priv(dev); @@ -241,13 +241,11 @@ static int sja1000_isa_remove(struct platform_device *pdev) release_region(port[idx], SJA1000_IOSIZE); } free_sja1000dev(dev); - - return 0; } static struct platform_driver sja1000_isa_driver = { .probe = sja1000_isa_probe, - .remove = sja1000_isa_remove, + .remove_new = sja1000_isa_remove, .driver = { .name = DRV_NAME, }, -- cgit v1.2.3 From bc79adfbd1fd02738ca956da1715634c0e643b5f Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:21 +0200 Subject: can: sja1000_platform: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-16-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000_platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 6779d5357069..b4889b5746e5 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -317,19 +317,17 @@ static int sp_probe(struct platform_device *pdev) return err; } -static int sp_remove(struct platform_device *pdev) +static void sp_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); unregister_sja1000dev(dev); free_sja1000dev(dev); - - return 0; } static struct platform_driver sp_driver = { .probe = sp_probe, - .remove = sp_remove, + .remove_new = sp_remove, .driver = { .name = DRV_NAME, .of_match_table = sp_of_table, -- cgit v1.2.3 From 737aec8a8f13019642255276da1a55d8c969db51 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:22 +0200 Subject: can: softing: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-17-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/softing/softing_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index c72f505d29fe..bd25137062c5 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -729,7 +729,7 @@ static const struct attribute_group softing_pdev_group = { /* * platform driver */ -static int softing_pdev_remove(struct platform_device *pdev) +static void softing_pdev_remove(struct platform_device *pdev) { struct softing *card = platform_get_drvdata(pdev); int j; @@ -747,7 +747,6 @@ static int softing_pdev_remove(struct platform_device *pdev) iounmap(card->dpram); kfree(card); - return 0; } static int softing_pdev_probe(struct platform_device *pdev) @@ -855,7 +854,7 @@ static struct platform_driver softing_driver = { .name = KBUILD_MODNAME, }, .probe = softing_pdev_probe, - .remove = softing_pdev_remove, + .remove_new = softing_pdev_remove, }; module_platform_driver(softing_driver); -- cgit v1.2.3 From aaa278e646c036961c69b65ec97cd69f92ddbc2e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:23 +0200 Subject: can: sun4i_can: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Gerhard Bertelsmann Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20230512212725.143824-18-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sun4i_can.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index 2b78f9197681..0827830bbf28 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c @@ -791,14 +791,12 @@ static const struct of_device_id sun4ican_of_match[] = { MODULE_DEVICE_TABLE(of, sun4ican_of_match); -static int sun4ican_remove(struct platform_device *pdev) +static void sun4ican_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); unregister_netdev(dev); free_candev(dev); - - return 0; } static int sun4ican_probe(struct platform_device *pdev) @@ -901,7 +899,7 @@ static struct platform_driver sun4i_can_driver = { .of_match_table = sun4ican_of_match, }, .probe = sun4ican_probe, - .remove = sun4ican_remove, + .remove_new = sun4ican_remove, }; module_platform_driver(sun4i_can_driver); -- cgit v1.2.3 From 9587b93b775545cc4b0d9815caa7d75dea4a9d0d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:24 +0200 Subject: can: ti_hecc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-19-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ti_hecc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 27700f72eac2..9bab0b4cc449 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -963,7 +963,7 @@ probe_exit_candev: return err; } -static int ti_hecc_remove(struct platform_device *pdev) +static void ti_hecc_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct ti_hecc_priv *priv = netdev_priv(ndev); @@ -973,8 +973,6 @@ static int ti_hecc_remove(struct platform_device *pdev) clk_put(priv->clk); can_rx_offload_del(&priv->offload); free_candev(ndev); - - return 0; } #ifdef CONFIG_PM @@ -1028,7 +1026,7 @@ static struct platform_driver ti_hecc_driver = { .of_match_table = ti_hecc_dt_ids, }, .probe = ti_hecc_probe, - .remove = ti_hecc_remove, + .remove_new = ti_hecc_remove, .suspend = ti_hecc_suspend, .resume = ti_hecc_resume, }; -- cgit v1.2.3 From 0816e1dd5ea8ee78ca31f9e94eb0025a7b13f636 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 May 2023 23:27:25 +0200 Subject: can: xilinx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230512212725.143824-20-u.kleine-koenig@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/xilinx_can.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 43c812ea1de0..797c69a0314d 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -1898,20 +1898,18 @@ err: * This function frees all the resources allocated to the device. * Return: 0 always */ -static int xcan_remove(struct platform_device *pdev) +static void xcan_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); unregister_candev(ndev); pm_runtime_disable(&pdev->dev); free_candev(ndev); - - return 0; } static struct platform_driver xcan_driver = { .probe = xcan_probe, - .remove = xcan_remove, + .remove_new = xcan_remove, .driver = { .name = DRIVER_NAME, .pm = &xcan_dev_pm_ops, -- cgit v1.2.3 From 108598c39eefbedc9882273ac0df96127a629220 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Mon, 15 May 2023 13:08:47 +0000 Subject: bpf: Fix memleak due to fentry attach failure If it fails to attach fentry, the allocated bpf trampoline image will be left in the system. That can be verified by checking /proc/kallsyms. This meamleak can be verified by a simple bpf program as follows: SEC("fentry/trap_init") int fentry_run() { return 0; } It will fail to attach trap_init because this function is freed after kernel init, and then we can find the trampoline image is left in the system by checking /proc/kallsyms. $ tail /proc/kallsyms ffffffffc0613000 t bpf_trampoline_6442453466_1 [bpf] ffffffffc06c3000 t bpf_trampoline_6442453466_1 [bpf] $ bpftool btf dump file /sys/kernel/btf/vmlinux | grep "FUNC 'trap_init'" [2522] FUNC 'trap_init' type_id=119 linkage=static $ echo $((6442453466 & 0x7fffffff)) 2522 Note that there are two left bpf trampoline images, that is because the libbpf will fallback to raw tracepoint if -EINVAL is returned. Fixes: e21aa341785c ("bpf: Fix fexit trampoline.") Signed-off-by: Yafang Shao Signed-off-by: Daniel Borkmann Acked-by: Song Liu Cc: Jiri Olsa Link: https://lore.kernel.org/bpf/20230515130849.57502-2-laoar.shao@gmail.com --- kernel/bpf/trampoline.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c index 84850e66ce3d..78acf28d4873 100644 --- a/kernel/bpf/trampoline.c +++ b/kernel/bpf/trampoline.c @@ -251,11 +251,8 @@ bpf_trampoline_get_progs(const struct bpf_trampoline *tr, int *total, bool *ip_a return tlinks; } -static void __bpf_tramp_image_put_deferred(struct work_struct *work) +static void bpf_tramp_image_free(struct bpf_tramp_image *im) { - struct bpf_tramp_image *im; - - im = container_of(work, struct bpf_tramp_image, work); bpf_image_ksym_del(&im->ksym); bpf_jit_free_exec(im->image); bpf_jit_uncharge_modmem(PAGE_SIZE); @@ -263,6 +260,14 @@ static void __bpf_tramp_image_put_deferred(struct work_struct *work) kfree_rcu(im, rcu); } +static void __bpf_tramp_image_put_deferred(struct work_struct *work) +{ + struct bpf_tramp_image *im; + + im = container_of(work, struct bpf_tramp_image, work); + bpf_tramp_image_free(im); +} + /* callback, fexit step 3 or fentry step 2 */ static void __bpf_tramp_image_put_rcu(struct rcu_head *rcu) { @@ -437,7 +442,7 @@ again: &tr->func.model, tr->flags, tlinks, tr->func.addr); if (err < 0) - goto out; + goto out_free; set_memory_rox((long)im->image, 1); @@ -466,7 +471,7 @@ again: } #endif if (err) - goto out; + goto out_free; if (tr->cur_image) bpf_tramp_image_put(tr->cur_image); @@ -477,6 +482,10 @@ out: tr->flags = orig_flags; kfree(tlinks); return err; + +out_free: + bpf_tramp_image_free(im); + goto out; } static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog) -- cgit v1.2.3 From 8b33485128ad932f807f4535e0b440733d8b5808 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 15 May 2023 13:01:07 +0800 Subject: net: skbuff: update comment about pfmemalloc propagating __skb_fill_page_desc_noacc() is not doing any pfmemalloc propagating, and yet it has a comment about that, commit 84ce071e38a6 ("net: introduce __skb_fill_page_desc_noacc") may have accidentally moved it to __skb_fill_page_desc_noacc(), so move it back to __skb_fill_page_desc() which is supposed to be doing pfmemalloc propagating. Signed-off-by: Yunsheng Lin CC: Pavel Begunkov Reviewed-by: Pavel Begunkov Link: https://lore.kernel.org/r/20230515050107.46397-1-linyunsheng@huawei.com Signed-off-by: Paolo Abeni --- include/linux/skbuff.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 00e8c435fa1a..4b8d55247198 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2426,11 +2426,6 @@ static inline void __skb_fill_page_desc_noacc(struct skb_shared_info *shinfo, { skb_frag_t *frag = &shinfo->frags[i]; - /* - * Propagate page pfmemalloc to the skb if we can. The problem is - * that not all callers have unique ownership of the page but rely - * on page_is_pfmemalloc doing the right thing(tm). - */ skb_frag_fill_page_desc(frag, page, off, size); } @@ -2463,6 +2458,11 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size) { __skb_fill_page_desc_noacc(skb_shinfo(skb), i, page, off, size); + + /* Propagate page pfmemalloc to the skb if we can. The problem is + * that not all callers have unique ownership of the page but rely + * on page_is_pfmemalloc doing the right thing(tm). + */ page = compound_head(page); if (page_is_pfmemalloc(page)) skb->pfmemalloc = true; -- cgit v1.2.3 From 613a014191f584556a96e070d0767761912ccf61 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Mon, 15 May 2023 13:07:11 +0700 Subject: net: bonding: Add SPDX identifier to remaining files Previous batches of SPDX conversion missed bond_main.c and bonding_priv.h because these files doesn't mention intended GPL version. Add SPDX identifier to these files, assuming GPL 1.0+. Cc: Thomas Davis Cc: Christophe JAILLET Cc: Stephen Hemminger Reviewed-by: Simon Horman Signed-off-by: Bagas Sanjaya Signed-off-by: Paolo Abeni --- drivers/net/bonding/bond_main.c | 3 ++- drivers/net/bonding/bonding_priv.h | 4 +--- include/net/bonding.h | 4 +--- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index ebf61c19dcef..fce81fafbedd 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1,8 +1,9 @@ +// SPDX-License-Identifier: GPL-1.0+ /* * originally based on the dummy device. * * Copyright 1999, Thomas Davis, tadavis@lbl.gov. - * Licensed under the GPL. Based on dummy.c, and eql.c devices. + * Based on dummy.c, and eql.c devices. * * bonding.c: an Ethernet Bonding driver * diff --git a/drivers/net/bonding/bonding_priv.h b/drivers/net/bonding/bonding_priv.h index 48cdf3a49a7d..fef6288c6944 100644 --- a/drivers/net/bonding/bonding_priv.h +++ b/drivers/net/bonding/bonding_priv.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-1.0+ */ /* * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. * @@ -7,9 +8,6 @@ * BUT, I'm the one who modified it for ethernet, so: * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - * */ #ifndef _BONDING_PRIV_H diff --git a/include/net/bonding.h b/include/net/bonding.h index 0efef2a952b7..d46af0571758 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-1.0+ */ /* * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. * @@ -7,9 +8,6 @@ * BUT, I'm the one who modified it for ethernet, so: * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - * */ #ifndef _NET_BONDING_H -- cgit v1.2.3 From dc3eb2f4ec09e90b77ee8c28f73912b022462e8e Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Mon, 15 May 2023 13:07:12 +0700 Subject: net: ethernet: 8390: Convert unversioned GPL notice to SPDX license identifier Replace boilerplate notice for unversioned GPL to SPDX tag for GPL 1.0+. For ne2k-pci.c, only add SPDX tag and keep the boilerplate instead, since the boilerplate notes that it must be preserved. Cc: David A. Hinds Cc: Donald Becker Cc: Alan Cox Cc: Geert Uytterhoeven Cc: Richard Fontana Signed-off-by: Bagas Sanjaya Signed-off-by: Paolo Abeni --- drivers/net/ethernet/8390/8390.h | 2 ++ drivers/net/ethernet/8390/axnet_cs.c | 6 +++--- drivers/net/ethernet/8390/lib8390.c | 5 ++--- drivers/net/ethernet/8390/mac8390.c | 6 ++---- drivers/net/ethernet/8390/ne.c | 4 +--- drivers/net/ethernet/8390/ne2k-pci.c | 1 + drivers/net/ethernet/8390/pcnet_cs.c | 5 ++--- drivers/net/ethernet/8390/smc-ultra.c | 4 +--- drivers/net/ethernet/8390/wd.c | 4 +--- 9 files changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/8390/8390.h b/drivers/net/ethernet/8390/8390.h index e52264465998..f784a6e2ab0e 100644 --- a/drivers/net/ethernet/8390/8390.h +++ b/drivers/net/ethernet/8390/8390.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-1.0+ */ + /* Generic NS8390 register definitions. */ /* This file is part of Donald Becker's 8390 drivers, and is distributed diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c index 78f985885547..fea489af72fb 100644 --- a/drivers/net/ethernet/8390/axnet_cs.c +++ b/drivers/net/ethernet/8390/axnet_cs.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-1.0+ + /*====================================================================== A PCMCIA ethernet driver for Asix AX88190-based cards @@ -17,9 +19,7 @@ Written 1992,1993 by Donald Becker. Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may be used and - distributed according to the terms of the GNU General Public License, - incorporated herein by reference. + Director, National Security Agency. Donald Becker may be reached at becker@scyld.com ======================================================================*/ diff --git a/drivers/net/ethernet/8390/lib8390.c b/drivers/net/ethernet/8390/lib8390.c index e84021282edf..84aeb8054304 100644 --- a/drivers/net/ethernet/8390/lib8390.c +++ b/drivers/net/ethernet/8390/lib8390.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-1.0+ + /* 8390.c: A general NS8390 ethernet driver core for linux. */ /* Written 1992-94 by Donald Becker. @@ -5,9 +7,6 @@ Copyright 1993 United States Government as represented by the Director, National Security Agency. - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 410 Severn Ave., Suite 210 diff --git a/drivers/net/ethernet/8390/mac8390.c b/drivers/net/ethernet/8390/mac8390.c index 7fb819b9b89a..4a0a095a1a8a 100644 --- a/drivers/net/ethernet/8390/mac8390.c +++ b/drivers/net/ethernet/8390/mac8390.c @@ -1,11 +1,9 @@ +// SPDX-License-Identifier: GPL-1.0+ /* mac8390.c: New driver for 8390-based Nubus (or Nubus-alike) Ethernet cards on Linux */ /* Based on the former daynaport.c driver, by Alan Cox. Some code taken from or inspired by skeleton.c by Donald Becker, acenic.c by - Jes Sorensen, and ne2k-pci.c by Donald Becker and Paul Gortmaker. - - This software may be used and distributed according to the terms of - the GNU Public License, incorporated herein by reference. */ + Jes Sorensen, and ne2k-pci.c by Donald Becker and Paul Gortmaker. */ /* 2000-02-28: support added for Dayna and Kinetics cards by A.G.deWijn@phys.uu.nl */ diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index 0a9118b8be0c..cb04a3071f92 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-1.0+ /* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */ /* Written 1992-94 by Donald Becker. @@ -5,9 +6,6 @@ Copyright 1993 United States Government as represented by the Director, National Security Agency. - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c index 6a0a2039600a..2c6bd36d2f31 100644 --- a/drivers/net/ethernet/8390/ne2k-pci.c +++ b/drivers/net/ethernet/8390/ne2k-pci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-1.0+ /* A Linux device driver for PCI NE2000 clones. * * Authors and other copyright holders: diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c index 0f07fe03da98..9bd5e991f1e5 100644 --- a/drivers/net/ethernet/8390/pcnet_cs.c +++ b/drivers/net/ethernet/8390/pcnet_cs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-1.0+ /*====================================================================== A PCMCIA ethernet driver for NS8390-based cards @@ -17,9 +18,7 @@ Written 1992,1993 by Donald Becker. Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may be used and - distributed according to the terms of the GNU General Public License, - incorporated herein by reference. + Director, National Security Agency. Donald Becker may be reached at becker@scyld.com Based also on Keith Moore's changes to Don Becker's code, for IBM diff --git a/drivers/net/ethernet/8390/smc-ultra.c b/drivers/net/ethernet/8390/smc-ultra.c index 6e62c37c9400..ae10b7de41e8 100644 --- a/drivers/net/ethernet/8390/smc-ultra.c +++ b/drivers/net/ethernet/8390/smc-ultra.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-1.0+ /* smc-ultra.c: A SMC Ultra ethernet driver for linux. */ /* This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards. @@ -7,9 +8,6 @@ Copyright 1993 United States Government as represented by the Director, National Security Agency. - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 410 Severn Ave., Suite 210 diff --git a/drivers/net/ethernet/8390/wd.c b/drivers/net/ethernet/8390/wd.c index 5b00c452bede..9a36667d00b6 100644 --- a/drivers/net/ethernet/8390/wd.c +++ b/drivers/net/ethernet/8390/wd.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-1.0+ /* wd.c: A WD80x3 ethernet driver for linux. */ /* Written 1993-94 by Donald Becker. @@ -5,9 +6,6 @@ Copyright 1993 United States Government as represented by the Director, National Security Agency. - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation 410 Severn Ave., Suite 210 -- cgit v1.2.3 From 9f07af05d0e4255ae9da2dfe240484a73433c5e4 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Mon, 15 May 2023 13:07:13 +0700 Subject: net: ethernet: 8390: Replace GPL 2.0 boilerplate with SPDX identifier The boilerplate refers to COPYING in the top-level directory of kernel tree. Replace it with corresponding SPDX license identifier. Cc: Donald Becker Cc: Peter De Schrijver Cc: Topi Kanerva Cc: Alain Malek Cc: Bruce Abbott Cc: Geert Uytterhoeven Cc: Richard Fontana Acked-by: Greg Ungerer Signed-off-by: Bagas Sanjaya Signed-off-by: Paolo Abeni --- drivers/net/ethernet/8390/apne.c | 7 +------ drivers/net/ethernet/8390/hydra.c | 6 ++---- drivers/net/ethernet/8390/mcf8390.c | 4 +--- drivers/net/ethernet/8390/stnic.c | 5 +---- drivers/net/ethernet/8390/zorro8390.c | 7 +------ 5 files changed, 6 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/8390/apne.c b/drivers/net/ethernet/8390/apne.c index 991ad953aa79..a09f383dd249 100644 --- a/drivers/net/ethernet/8390/apne.c +++ b/drivers/net/ethernet/8390/apne.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200 * @@ -19,12 +20,6 @@ * * ---------------------------------------------------------------------------- * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of the Linux - * distribution for more details. - * - * ---------------------------------------------------------------------------- - * */ diff --git a/drivers/net/ethernet/8390/hydra.c b/drivers/net/ethernet/8390/hydra.c index 1df7601af86a..24f49a8ff903 100644 --- a/drivers/net/ethernet/8390/hydra.c +++ b/drivers/net/ethernet/8390/hydra.c @@ -1,10 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only + /* New Hydra driver using generic 8390 core */ /* Based on old hydra driver by Topi Kanerva (topi@susanna.oulu.fi) */ -/* This file is subject to the terms and conditions of the GNU General */ -/* Public License. See the file COPYING in the main directory of the */ -/* Linux distribution for more details. */ - /* Peter De Schrijver (p2@mind.be) */ /* Oldenburg 2000 */ diff --git a/drivers/net/ethernet/8390/mcf8390.c b/drivers/net/ethernet/8390/mcf8390.c index 8a7918d33419..217838b28220 100644 --- a/drivers/net/ethernet/8390/mcf8390.c +++ b/drivers/net/ethernet/8390/mcf8390.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Support for ColdFire CPU based boards using a NS8390 Ethernet device. * @@ -5,9 +6,6 @@ * * (C) Copyright 2012, Greg Ungerer * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of the Linux - * distribution for more details. */ #include diff --git a/drivers/net/ethernet/8390/stnic.c b/drivers/net/ethernet/8390/stnic.c index bd89ca8a92df..265976e3b64a 100644 --- a/drivers/net/ethernet/8390/stnic.c +++ b/drivers/net/ethernet/8390/stnic.c @@ -1,8 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* stnic.c : A SH7750 specific part of driver for NS DP83902A ST-NIC. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. * * Copyright (C) 1999 kaz Kojima */ diff --git a/drivers/net/ethernet/8390/zorro8390.c b/drivers/net/ethernet/8390/zorro8390.c index e8b4fe813a08..d70390e9d03d 100644 --- a/drivers/net/ethernet/8390/zorro8390.c +++ b/drivers/net/ethernet/8390/zorro8390.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Amiga Linux/m68k and Linux/PPC Zorro NS8390 Ethernet Driver * @@ -9,12 +10,6 @@ * * --------------------------------------------------------------------------- * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of the Linux - * distribution for more details. - * - * --------------------------------------------------------------------------- - * * The Ariadne II and X-Surf are Zorro-II boards containing Realtek RTL8019AS * Ethernet Controllers. */ -- cgit v1.2.3 From 9ac40d080befb4a0501e42ce31bdaa596f2b0f05 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Mon, 15 May 2023 13:07:14 +0700 Subject: net: ethernet: i825xx: Replace unversioned GPL (GPL 1.0) notice with SPDX identifier Replace unversioned GPL boilerplate notice with corresponding SPDX license identifier, which is GPL 1.0+. Cc: Donald Becker Cc: Richard Hirst Cc: Sam Creasey Signed-off-by: Bagas Sanjaya Signed-off-by: Paolo Abeni --- drivers/net/ethernet/i825xx/82596.c | 5 ++--- drivers/net/ethernet/i825xx/lasi_82596.c | 5 ++--- drivers/net/ethernet/i825xx/lib82596.c | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/i825xx/82596.c b/drivers/net/ethernet/i825xx/82596.c index 3ee89ae496d0..773d7aa29ef5 100644 --- a/drivers/net/ethernet/i825xx/82596.c +++ b/drivers/net/ethernet/i825xx/82596.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-1.0+ /* 82596.c: A generic 82596 ethernet driver for linux. */ /* Based on Apricot.c @@ -31,9 +32,7 @@ Driver skeleton Written 1993 by Donald Becker. Copyright 1993 United States Government as represented by the Director, - National Security Agency. This software may only be used and distributed - according to the terms of the GNU General Public License as modified by SRC, - incorporated herein by reference. + National Security Agency. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 diff --git a/drivers/net/ethernet/i825xx/lasi_82596.c b/drivers/net/ethernet/i825xx/lasi_82596.c index 0af70094aba3..3e53e0c243ba 100644 --- a/drivers/net/ethernet/i825xx/lasi_82596.c +++ b/drivers/net/ethernet/i825xx/lasi_82596.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-1.0+ /* lasi_82596.c -- driver for the intel 82596 ethernet controller, as munged into HPPA boxen . @@ -59,9 +60,7 @@ Driver skeleton Written 1993 by Donald Becker. Copyright 1993 United States Government as represented by the Director, - National Security Agency. This software may only be used and distributed - according to the terms of the GNU General Public License as modified by SRC, - incorporated herein by reference. + National Security Agency. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 diff --git a/drivers/net/ethernet/i825xx/lib82596.c b/drivers/net/ethernet/i825xx/lib82596.c index ca2fb303fcc6..67d248a7a6f4 100644 --- a/drivers/net/ethernet/i825xx/lib82596.c +++ b/drivers/net/ethernet/i825xx/lib82596.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-1.0+ /* lasi_82596.c -- driver for the intel 82596 ethernet controller, as munged into HPPA boxen . @@ -59,9 +60,7 @@ Driver skeleton Written 1993 by Donald Becker. Copyright 1993 United States Government as represented by the Director, - National Security Agency. This software may only be used and distributed - according to the terms of the GNU General Public License as modified by SRC, - incorporated herein by reference. + National Security Agency. The author may be reached as becker@scyld.com, or C/O Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 -- cgit v1.2.3 From 4f693a8f5617f23aeedf0d6a91a516901eccf88b Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Mon, 15 May 2023 13:07:15 +0700 Subject: net: ethernet: i825xx: sun3_8256: Add SPDX license identifier The boilerplate reads that sun3_8256 driver is an extension to Linux kernel core, hence add SPDX license identifier for GPL 2.0. Cc: Greg Kroah-Hartman Cc: Michael Hipp Cc: Sam Creasey Signed-off-by: Bagas Sanjaya Signed-off-by: Paolo Abeni --- drivers/net/ethernet/i825xx/sun3_82586.c | 1 + drivers/net/ethernet/i825xx/sun3_82586.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/i825xx/sun3_82586.c b/drivers/net/ethernet/i825xx/sun3_82586.c index 3909c6a0af89..5e27470c6b1e 100644 --- a/drivers/net/ethernet/i825xx/sun3_82586.c +++ b/drivers/net/ethernet/i825xx/sun3_82586.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Sun3 i82586 Ethernet driver * diff --git a/drivers/net/ethernet/i825xx/sun3_82586.h b/drivers/net/ethernet/i825xx/sun3_82586.h index d82eca563266..d8e249d704a7 100644 --- a/drivers/net/ethernet/i825xx/sun3_82586.h +++ b/drivers/net/ethernet/i825xx/sun3_82586.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Intel i82586 Ethernet definitions * -- cgit v1.2.3 From 38e97a98e371c615f67d144ee9e4f7087c0a41e8 Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Mon, 15 May 2023 21:03:12 +0200 Subject: ice: move interrupt related code to separate file Keep interrupt handling code in a dedicated file. This helps keep driver structured better and prepares for more functionality added to this file. Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Piotr Raczynski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/Makefile | 1 + drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_irq.c | 226 ++++++++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_irq.h | 10 ++ drivers/net/ethernet/intel/ice/ice_main.c | 218 ---------------------------- 5 files changed, 238 insertions(+), 218 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_irq.c create mode 100644 drivers/net/ethernet/intel/ice/ice_irq.h diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 5d89392f969b..817977e3039d 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -18,6 +18,7 @@ ice-y := ice_main.o \ ice_txrx_lib.o \ ice_txrx.o \ ice_fltr.o \ + ice_irq.o \ ice_pf_vsi_vlan_ops.o \ ice_vsi_vlan_ops.o \ ice_vsi_vlan_lib.o \ diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index aa32111afd6e..4dc4c6bec081 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -74,6 +74,7 @@ #include "ice_lag.h" #include "ice_vsi_vlan_ops.h" #include "ice_gnss.h" +#include "ice_irq.h" #define ICE_BAR0 0 #define ICE_REQ_DESC_MULTIPLE 32 diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c new file mode 100644 index 000000000000..1fc7daec9732 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_irq.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2023, Intel Corporation. */ + +#include "ice.h" +#include "ice_lib.h" +#include "ice_irq.h" + +/** + * ice_reduce_msix_usage - Reduce usage of MSI-X vectors + * @pf: board private structure + * @v_remain: number of remaining MSI-X vectors to be distributed + * + * Reduce the usage of MSI-X vectors when entire request cannot be fulfilled. + * pf->num_lan_msix and pf->num_rdma_msix values are set based on number of + * remaining vectors. + */ +static void ice_reduce_msix_usage(struct ice_pf *pf, int v_remain) +{ + int v_rdma; + + if (!ice_is_rdma_ena(pf)) { + pf->num_lan_msix = v_remain; + return; + } + + /* RDMA needs at least 1 interrupt in addition to AEQ MSIX */ + v_rdma = ICE_RDMA_NUM_AEQ_MSIX + 1; + + if (v_remain < ICE_MIN_LAN_TXRX_MSIX + ICE_MIN_RDMA_MSIX) { + dev_warn(ice_pf_to_dev(pf), "Not enough MSI-X vectors to support RDMA.\n"); + clear_bit(ICE_FLAG_RDMA_ENA, pf->flags); + + pf->num_rdma_msix = 0; + pf->num_lan_msix = ICE_MIN_LAN_TXRX_MSIX; + } else if ((v_remain < ICE_MIN_LAN_TXRX_MSIX + v_rdma) || + (v_remain - v_rdma < v_rdma)) { + /* Support minimum RDMA and give remaining vectors to LAN MSIX + */ + pf->num_rdma_msix = ICE_MIN_RDMA_MSIX; + pf->num_lan_msix = v_remain - ICE_MIN_RDMA_MSIX; + } else { + /* Split remaining MSIX with RDMA after accounting for AEQ MSIX + */ + pf->num_rdma_msix = (v_remain - ICE_RDMA_NUM_AEQ_MSIX) / 2 + + ICE_RDMA_NUM_AEQ_MSIX; + pf->num_lan_msix = v_remain - pf->num_rdma_msix; + } +} + +/** + * ice_ena_msix_range - Request a range of MSIX vectors from the OS + * @pf: board private structure + * + * Compute the number of MSIX vectors wanted and request from the OS. Adjust + * device usage if there are not enough vectors. Return the number of vectors + * reserved or negative on failure. + */ +static int ice_ena_msix_range(struct ice_pf *pf) +{ + int num_cpus, hw_num_msix, v_other, v_wanted, v_actual; + struct device *dev = ice_pf_to_dev(pf); + int err, i; + + hw_num_msix = pf->hw.func_caps.common_cap.num_msix_vectors; + num_cpus = num_online_cpus(); + + /* LAN miscellaneous handler */ + v_other = ICE_MIN_LAN_OICR_MSIX; + + /* Flow Director */ + if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) + v_other += ICE_FDIR_MSIX; + + /* switchdev */ + v_other += ICE_ESWITCH_MSIX; + + v_wanted = v_other; + + /* LAN traffic */ + pf->num_lan_msix = num_cpus; + v_wanted += pf->num_lan_msix; + + /* RDMA auxiliary driver */ + if (ice_is_rdma_ena(pf)) { + pf->num_rdma_msix = num_cpus + ICE_RDMA_NUM_AEQ_MSIX; + v_wanted += pf->num_rdma_msix; + } + + if (v_wanted > hw_num_msix) { + int v_remain; + + dev_warn(dev, "not enough device MSI-X vectors. wanted = %d, available = %d\n", + v_wanted, hw_num_msix); + + if (hw_num_msix < ICE_MIN_MSIX) { + err = -ERANGE; + goto exit_err; + } + + v_remain = hw_num_msix - v_other; + if (v_remain < ICE_MIN_LAN_TXRX_MSIX) { + v_other = ICE_MIN_MSIX - ICE_MIN_LAN_TXRX_MSIX; + v_remain = ICE_MIN_LAN_TXRX_MSIX; + } + + ice_reduce_msix_usage(pf, v_remain); + v_wanted = pf->num_lan_msix + pf->num_rdma_msix + v_other; + + dev_notice(dev, "Reducing request to %d MSI-X vectors for LAN traffic.\n", + pf->num_lan_msix); + if (ice_is_rdma_ena(pf)) + dev_notice(dev, "Reducing request to %d MSI-X vectors for RDMA.\n", + pf->num_rdma_msix); + } + + pf->msix_entries = devm_kcalloc(dev, v_wanted, + sizeof(*pf->msix_entries), GFP_KERNEL); + if (!pf->msix_entries) { + err = -ENOMEM; + goto exit_err; + } + + for (i = 0; i < v_wanted; i++) + pf->msix_entries[i].entry = i; + + /* actually reserve the vectors */ + v_actual = pci_enable_msix_range(pf->pdev, pf->msix_entries, + ICE_MIN_MSIX, v_wanted); + if (v_actual < 0) { + dev_err(dev, "unable to reserve MSI-X vectors\n"); + err = v_actual; + goto msix_err; + } + + if (v_actual < v_wanted) { + dev_warn(dev, "not enough OS MSI-X vectors. requested = %d, obtained = %d\n", + v_wanted, v_actual); + + if (v_actual < ICE_MIN_MSIX) { + /* error if we can't get minimum vectors */ + pci_disable_msix(pf->pdev); + err = -ERANGE; + goto msix_err; + } else { + int v_remain = v_actual - v_other; + + if (v_remain < ICE_MIN_LAN_TXRX_MSIX) + v_remain = ICE_MIN_LAN_TXRX_MSIX; + + ice_reduce_msix_usage(pf, v_remain); + + dev_notice(dev, "Enabled %d MSI-X vectors for LAN traffic.\n", + pf->num_lan_msix); + + if (ice_is_rdma_ena(pf)) + dev_notice(dev, "Enabled %d MSI-X vectors for RDMA.\n", + pf->num_rdma_msix); + } + } + + return v_actual; + +msix_err: + devm_kfree(dev, pf->msix_entries); + +exit_err: + pf->num_rdma_msix = 0; + pf->num_lan_msix = 0; + return err; +} + +/** + * ice_dis_msix - Disable MSI-X interrupt setup in OS + * @pf: board private structure + */ +static void ice_dis_msix(struct ice_pf *pf) +{ + pci_disable_msix(pf->pdev); + devm_kfree(ice_pf_to_dev(pf), pf->msix_entries); + pf->msix_entries = NULL; +} + +/** + * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme + * @pf: board private structure + */ +void ice_clear_interrupt_scheme(struct ice_pf *pf) +{ + ice_dis_msix(pf); + + if (pf->irq_tracker) { + devm_kfree(ice_pf_to_dev(pf), pf->irq_tracker); + pf->irq_tracker = NULL; + } +} + +/** + * ice_init_interrupt_scheme - Determine proper interrupt scheme + * @pf: board private structure to initialize + */ +int ice_init_interrupt_scheme(struct ice_pf *pf) +{ + int vectors; + + vectors = ice_ena_msix_range(pf); + + if (vectors < 0) + return vectors; + + /* set up vector assignment tracking */ + pf->irq_tracker = devm_kzalloc(ice_pf_to_dev(pf), + struct_size(pf->irq_tracker, list, + vectors), + GFP_KERNEL); + if (!pf->irq_tracker) { + ice_dis_msix(pf); + return -ENOMEM; + } + + /* populate SW interrupts pool with number of OS granted IRQs. */ + pf->num_avail_sw_msix = (u16)vectors; + pf->irq_tracker->num_entries = (u16)vectors; + pf->irq_tracker->end = pf->irq_tracker->num_entries; + + return 0; +} diff --git a/drivers/net/ethernet/intel/ice/ice_irq.h b/drivers/net/ethernet/intel/ice/ice_irq.h new file mode 100644 index 000000000000..82475162ab70 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_irq.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (C) 2023, Intel Corporation. */ + +#ifndef _ICE_IRQ_H_ +#define _ICE_IRQ_H_ + +int ice_init_interrupt_scheme(struct ice_pf *pf); +void ice_clear_interrupt_scheme(struct ice_pf *pf); + +#endif diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index a1f7c8edc22f..c377bacc5e2e 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3900,224 +3900,6 @@ static int ice_init_pf(struct ice_pf *pf) return 0; } -/** - * ice_reduce_msix_usage - Reduce usage of MSI-X vectors - * @pf: board private structure - * @v_remain: number of remaining MSI-X vectors to be distributed - * - * Reduce the usage of MSI-X vectors when entire request cannot be fulfilled. - * pf->num_lan_msix and pf->num_rdma_msix values are set based on number of - * remaining vectors. - */ -static void ice_reduce_msix_usage(struct ice_pf *pf, int v_remain) -{ - int v_rdma; - - if (!ice_is_rdma_ena(pf)) { - pf->num_lan_msix = v_remain; - return; - } - - /* RDMA needs at least 1 interrupt in addition to AEQ MSIX */ - v_rdma = ICE_RDMA_NUM_AEQ_MSIX + 1; - - if (v_remain < ICE_MIN_LAN_TXRX_MSIX + ICE_MIN_RDMA_MSIX) { - dev_warn(ice_pf_to_dev(pf), "Not enough MSI-X vectors to support RDMA.\n"); - clear_bit(ICE_FLAG_RDMA_ENA, pf->flags); - - pf->num_rdma_msix = 0; - pf->num_lan_msix = ICE_MIN_LAN_TXRX_MSIX; - } else if ((v_remain < ICE_MIN_LAN_TXRX_MSIX + v_rdma) || - (v_remain - v_rdma < v_rdma)) { - /* Support minimum RDMA and give remaining vectors to LAN MSIX */ - pf->num_rdma_msix = ICE_MIN_RDMA_MSIX; - pf->num_lan_msix = v_remain - ICE_MIN_RDMA_MSIX; - } else { - /* Split remaining MSIX with RDMA after accounting for AEQ MSIX - */ - pf->num_rdma_msix = (v_remain - ICE_RDMA_NUM_AEQ_MSIX) / 2 + - ICE_RDMA_NUM_AEQ_MSIX; - pf->num_lan_msix = v_remain - pf->num_rdma_msix; - } -} - -/** - * ice_ena_msix_range - Request a range of MSIX vectors from the OS - * @pf: board private structure - * - * Compute the number of MSIX vectors wanted and request from the OS. Adjust - * device usage if there are not enough vectors. Return the number of vectors - * reserved or negative on failure. - */ -static int ice_ena_msix_range(struct ice_pf *pf) -{ - int num_cpus, hw_num_msix, v_other, v_wanted, v_actual; - struct device *dev = ice_pf_to_dev(pf); - int err, i; - - hw_num_msix = pf->hw.func_caps.common_cap.num_msix_vectors; - num_cpus = num_online_cpus(); - - /* LAN miscellaneous handler */ - v_other = ICE_MIN_LAN_OICR_MSIX; - - /* Flow Director */ - if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) - v_other += ICE_FDIR_MSIX; - - /* switchdev */ - v_other += ICE_ESWITCH_MSIX; - - v_wanted = v_other; - - /* LAN traffic */ - pf->num_lan_msix = num_cpus; - v_wanted += pf->num_lan_msix; - - /* RDMA auxiliary driver */ - if (ice_is_rdma_ena(pf)) { - pf->num_rdma_msix = num_cpus + ICE_RDMA_NUM_AEQ_MSIX; - v_wanted += pf->num_rdma_msix; - } - - if (v_wanted > hw_num_msix) { - int v_remain; - - dev_warn(dev, "not enough device MSI-X vectors. wanted = %d, available = %d\n", - v_wanted, hw_num_msix); - - if (hw_num_msix < ICE_MIN_MSIX) { - err = -ERANGE; - goto exit_err; - } - - v_remain = hw_num_msix - v_other; - if (v_remain < ICE_MIN_LAN_TXRX_MSIX) { - v_other = ICE_MIN_MSIX - ICE_MIN_LAN_TXRX_MSIX; - v_remain = ICE_MIN_LAN_TXRX_MSIX; - } - - ice_reduce_msix_usage(pf, v_remain); - v_wanted = pf->num_lan_msix + pf->num_rdma_msix + v_other; - - dev_notice(dev, "Reducing request to %d MSI-X vectors for LAN traffic.\n", - pf->num_lan_msix); - if (ice_is_rdma_ena(pf)) - dev_notice(dev, "Reducing request to %d MSI-X vectors for RDMA.\n", - pf->num_rdma_msix); - } - - pf->msix_entries = devm_kcalloc(dev, v_wanted, - sizeof(*pf->msix_entries), GFP_KERNEL); - if (!pf->msix_entries) { - err = -ENOMEM; - goto exit_err; - } - - for (i = 0; i < v_wanted; i++) - pf->msix_entries[i].entry = i; - - /* actually reserve the vectors */ - v_actual = pci_enable_msix_range(pf->pdev, pf->msix_entries, - ICE_MIN_MSIX, v_wanted); - if (v_actual < 0) { - dev_err(dev, "unable to reserve MSI-X vectors\n"); - err = v_actual; - goto msix_err; - } - - if (v_actual < v_wanted) { - dev_warn(dev, "not enough OS MSI-X vectors. requested = %d, obtained = %d\n", - v_wanted, v_actual); - - if (v_actual < ICE_MIN_MSIX) { - /* error if we can't get minimum vectors */ - pci_disable_msix(pf->pdev); - err = -ERANGE; - goto msix_err; - } else { - int v_remain = v_actual - v_other; - - if (v_remain < ICE_MIN_LAN_TXRX_MSIX) - v_remain = ICE_MIN_LAN_TXRX_MSIX; - - ice_reduce_msix_usage(pf, v_remain); - - dev_notice(dev, "Enabled %d MSI-X vectors for LAN traffic.\n", - pf->num_lan_msix); - - if (ice_is_rdma_ena(pf)) - dev_notice(dev, "Enabled %d MSI-X vectors for RDMA.\n", - pf->num_rdma_msix); - } - } - - return v_actual; - -msix_err: - devm_kfree(dev, pf->msix_entries); - -exit_err: - pf->num_rdma_msix = 0; - pf->num_lan_msix = 0; - return err; -} - -/** - * ice_dis_msix - Disable MSI-X interrupt setup in OS - * @pf: board private structure - */ -static void ice_dis_msix(struct ice_pf *pf) -{ - pci_disable_msix(pf->pdev); - devm_kfree(ice_pf_to_dev(pf), pf->msix_entries); - pf->msix_entries = NULL; -} - -/** - * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme - * @pf: board private structure - */ -static void ice_clear_interrupt_scheme(struct ice_pf *pf) -{ - ice_dis_msix(pf); - - if (pf->irq_tracker) { - devm_kfree(ice_pf_to_dev(pf), pf->irq_tracker); - pf->irq_tracker = NULL; - } -} - -/** - * ice_init_interrupt_scheme - Determine proper interrupt scheme - * @pf: board private structure to initialize - */ -static int ice_init_interrupt_scheme(struct ice_pf *pf) -{ - int vectors; - - vectors = ice_ena_msix_range(pf); - - if (vectors < 0) - return vectors; - - /* set up vector assignment tracking */ - pf->irq_tracker = devm_kzalloc(ice_pf_to_dev(pf), - struct_size(pf->irq_tracker, list, vectors), - GFP_KERNEL); - if (!pf->irq_tracker) { - ice_dis_msix(pf); - return -ENOMEM; - } - - /* populate SW interrupts pool with number of OS granted IRQs. */ - pf->num_avail_sw_msix = (u16)vectors; - pf->irq_tracker->num_entries = (u16)vectors; - pf->irq_tracker->end = pf->irq_tracker->num_entries; - - return 0; -} - /** * ice_is_wol_supported - check if WoL is supported * @hw: pointer to hardware info -- cgit v1.2.3 From afe87cfe820e74cc5fc59359445bcfd93ff0ab07 Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Mon, 15 May 2023 21:03:13 +0200 Subject: ice: use pci_irq_vector helper function Currently, driver gets interrupt number directly from ice_pf::msix_entries array. Use helper function dedicated to do just that. While at it use a variable to store interrupt number in ice_free_irq_msix_misc instead of calling the helper function twice. Reviewed-by: Michal Swiatkowski Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Piotr Raczynski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_arfs.c | 2 +- drivers/net/ethernet/intel/ice/ice_lib.c | 4 ++-- drivers/net/ethernet/intel/ice/ice_main.c | 12 ++++++------ drivers/net/ethernet/intel/ice/ice_ptp.c | 2 +- drivers/net/ethernet/intel/ice/ice_xsk.c | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_arfs.c b/drivers/net/ethernet/intel/ice/ice_arfs.c index fba178e07600..e81797344f5e 100644 --- a/drivers/net/ethernet/intel/ice/ice_arfs.c +++ b/drivers/net/ethernet/intel/ice/ice_arfs.c @@ -616,7 +616,7 @@ int ice_set_cpu_rx_rmap(struct ice_vsi *vsi) base_idx = vsi->base_vector; ice_for_each_q_vector(vsi, i) if (irq_cpu_rmap_add(netdev->rx_cpu_rmap, - pf->msix_entries[base_idx + i].vector)) { + pci_irq_vector(pf->pdev, base_idx + i))) { ice_free_cpu_rx_rmap(vsi); return -EINVAL; } diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 450317dfcca7..79e1557f77e8 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -3056,7 +3056,7 @@ void ice_vsi_free_irq(struct ice_vsi *vsi) u16 vector = i + base; int irq_num; - irq_num = pf->msix_entries[vector].vector; + irq_num = pci_irq_vector(pf->pdev, vector); /* free only the irqs that were actually requested */ if (!vsi->q_vectors[i] || @@ -3235,7 +3235,7 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi) return; ice_for_each_q_vector(vsi, i) - synchronize_irq(pf->msix_entries[i + base].vector); + synchronize_irq(pci_irq_vector(pf->pdev, i + base)); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index c377bacc5e2e..c103be660a9c 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2501,7 +2501,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) for (vector = 0; vector < q_vectors; vector++) { struct ice_q_vector *q_vector = vsi->q_vectors[vector]; - irq_num = pf->msix_entries[base + vector].vector; + irq_num = pci_irq_vector(pf->pdev, base + vector); if (q_vector->tx.tx_ring && q_vector->rx.rx_ring) { snprintf(q_vector->name, sizeof(q_vector->name) - 1, @@ -2557,7 +2557,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) free_q_irqs: while (vector) { vector--; - irq_num = pf->msix_entries[base + vector].vector; + irq_num = pci_irq_vector(pf->pdev, base + vector); if (!IS_ENABLED(CONFIG_RFS_ACCEL)) irq_set_affinity_notifier(irq_num, NULL); irq_set_affinity_hint(irq_num, NULL); @@ -3234,6 +3234,7 @@ static void ice_dis_ctrlq_interrupts(struct ice_hw *hw) */ static void ice_free_irq_msix_misc(struct ice_pf *pf) { + int misc_irq_num = pci_irq_vector(pf->pdev, pf->oicr_idx); struct ice_hw *hw = &pf->hw; ice_dis_ctrlq_interrupts(hw); @@ -3243,9 +3244,8 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf) ice_flush(hw); if (pf->msix_entries) { - synchronize_irq(pf->msix_entries[pf->oicr_idx].vector); - devm_free_irq(ice_pf_to_dev(pf), - pf->msix_entries[pf->oicr_idx].vector, pf); + synchronize_irq(misc_irq_num); + devm_free_irq(ice_pf_to_dev(pf), misc_irq_num, pf); } pf->num_avail_sw_msix += 1; @@ -3317,7 +3317,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) pf->oicr_idx = (u16)oicr_idx; err = devm_request_threaded_irq(dev, - pf->msix_entries[pf->oicr_idx].vector, + pci_irq_vector(pf->pdev, pf->oicr_idx), ice_misc_intr, ice_misc_intr_thread_fn, 0, pf->int_name, pf); if (err) { diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index ac6f06f9a2ed..972d4f6fd615 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -911,7 +911,7 @@ ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx) spin_unlock(&tx->lock); /* wait for potentially outstanding interrupt to complete */ - synchronize_irq(pf->msix_entries[pf->oicr_idx].vector); + synchronize_irq(pci_irq_vector(pf->pdev, pf->oicr_idx)); ice_ptp_flush_tx_tracker(pf, tx); diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index d1e489da7363..4102416d7a41 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -107,7 +107,7 @@ ice_qvec_dis_irq(struct ice_vsi *vsi, struct ice_rx_ring *rx_ring, wr32(hw, GLINT_DYN_CTL(q_vector->reg_idx), 0); ice_flush(hw); - synchronize_irq(pf->msix_entries[v_idx + base].vector); + synchronize_irq(pci_irq_vector(pf->pdev, v_idx + base)); } } -- cgit v1.2.3 From 05018936a1fe07b92a612d1fd1511224ba8a1a34 Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Mon, 15 May 2023 21:03:14 +0200 Subject: ice: use preferred MSIX allocation api Move away from using pci_enable_msix_range/pci_disable_msix and use pci_alloc_irq_vectors/pci_free_irq_vectors instead. As a result stop tracking msix_entries since with newer API entries are handled by MSIX core. However, due to current design of communication with RDMA driver which accesses ice_pf::msix_entries directly, keep using the array just for RDMA driver use. Reviewed-by: Michal Swiatkowski Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Piotr Raczynski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_idc.c | 29 ++++++++++++++++++++-- drivers/net/ethernet/intel/ice/ice_irq.c | 40 +++++++------------------------ drivers/net/ethernet/intel/ice/ice_main.c | 6 ++--- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c index e6bc2285071e..1000759505d7 100644 --- a/drivers/net/ethernet/intel/ice/ice_idc.c +++ b/drivers/net/ethernet/intel/ice/ice_idc.c @@ -235,14 +235,33 @@ EXPORT_SYMBOL_GPL(ice_get_qos_params); static int ice_reserve_rdma_qvector(struct ice_pf *pf) { if (ice_is_rdma_ena(pf)) { - int index; + int index, i; index = ice_get_res(pf, pf->irq_tracker, pf->num_rdma_msix, ICE_RES_RDMA_VEC_ID); if (index < 0) return index; + + pf->msix_entries = kcalloc(pf->num_rdma_msix, + sizeof(*pf->msix_entries), + GFP_KERNEL); + if (!pf->msix_entries) { + ice_free_res(pf->irq_tracker, pf->rdma_base_vector, + ICE_RES_RDMA_VEC_ID); + return -ENOMEM; + } + pf->num_avail_sw_msix -= pf->num_rdma_msix; - pf->rdma_base_vector = (u16)index; + + /* RDMA is the only user of pf->msix_entries array */ + pf->rdma_base_vector = 0; + + for (i = 0; i < pf->num_rdma_msix; i++, index++) { + struct msix_entry *entry = &pf->msix_entries[i]; + + entry->entry = index; + entry->vector = pci_irq_vector(pf->pdev, index); + } } return 0; } @@ -253,6 +272,12 @@ static int ice_reserve_rdma_qvector(struct ice_pf *pf) */ static void ice_free_rdma_qvector(struct ice_pf *pf) { + if (!pf->msix_entries) + return; + + kfree(pf->msix_entries); + pf->msix_entries = NULL; + pf->num_avail_sw_msix -= pf->num_rdma_msix; ice_free_res(pf->irq_tracker, pf->rdma_base_vector, ICE_RES_RDMA_VEC_ID); diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c index 1fc7daec9732..f61be5d76373 100644 --- a/drivers/net/ethernet/intel/ice/ice_irq.c +++ b/drivers/net/ethernet/intel/ice/ice_irq.c @@ -59,7 +59,7 @@ static int ice_ena_msix_range(struct ice_pf *pf) { int num_cpus, hw_num_msix, v_other, v_wanted, v_actual; struct device *dev = ice_pf_to_dev(pf); - int err, i; + int err; hw_num_msix = pf->hw.func_caps.common_cap.num_msix_vectors; num_cpus = num_online_cpus(); @@ -113,23 +113,13 @@ static int ice_ena_msix_range(struct ice_pf *pf) pf->num_rdma_msix); } - pf->msix_entries = devm_kcalloc(dev, v_wanted, - sizeof(*pf->msix_entries), GFP_KERNEL); - if (!pf->msix_entries) { - err = -ENOMEM; - goto exit_err; - } - - for (i = 0; i < v_wanted; i++) - pf->msix_entries[i].entry = i; - /* actually reserve the vectors */ - v_actual = pci_enable_msix_range(pf->pdev, pf->msix_entries, - ICE_MIN_MSIX, v_wanted); + v_actual = pci_alloc_irq_vectors(pf->pdev, ICE_MIN_MSIX, v_wanted, + PCI_IRQ_MSIX); if (v_actual < 0) { dev_err(dev, "unable to reserve MSI-X vectors\n"); err = v_actual; - goto msix_err; + goto exit_err; } if (v_actual < v_wanted) { @@ -138,9 +128,9 @@ static int ice_ena_msix_range(struct ice_pf *pf) if (v_actual < ICE_MIN_MSIX) { /* error if we can't get minimum vectors */ - pci_disable_msix(pf->pdev); + pci_free_irq_vectors(pf->pdev); err = -ERANGE; - goto msix_err; + goto exit_err; } else { int v_remain = v_actual - v_other; @@ -160,33 +150,19 @@ static int ice_ena_msix_range(struct ice_pf *pf) return v_actual; -msix_err: - devm_kfree(dev, pf->msix_entries); - exit_err: pf->num_rdma_msix = 0; pf->num_lan_msix = 0; return err; } -/** - * ice_dis_msix - Disable MSI-X interrupt setup in OS - * @pf: board private structure - */ -static void ice_dis_msix(struct ice_pf *pf) -{ - pci_disable_msix(pf->pdev); - devm_kfree(ice_pf_to_dev(pf), pf->msix_entries); - pf->msix_entries = NULL; -} - /** * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme * @pf: board private structure */ void ice_clear_interrupt_scheme(struct ice_pf *pf) { - ice_dis_msix(pf); + pci_free_irq_vectors(pf->pdev); if (pf->irq_tracker) { devm_kfree(ice_pf_to_dev(pf), pf->irq_tracker); @@ -213,7 +189,7 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) vectors), GFP_KERNEL); if (!pf->irq_tracker) { - ice_dis_msix(pf); + pci_free_irq_vectors(pf->pdev); return -ENOMEM; } diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index c103be660a9c..ce8cd49ae10c 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3243,10 +3243,8 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf) wr32(hw, PFINT_OICR_ENA, 0); ice_flush(hw); - if (pf->msix_entries) { - synchronize_irq(misc_irq_num); - devm_free_irq(ice_pf_to_dev(pf), misc_irq_num, pf); - } + synchronize_irq(misc_irq_num); + devm_free_irq(ice_pf_to_dev(pf), misc_irq_num, pf); pf->num_avail_sw_msix += 1; ice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID); -- cgit v1.2.3 From 369bb5a2a9a76ab6ea2945962d09baa21b4e1a4f Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Mon, 15 May 2023 21:03:15 +0200 Subject: ice: refactor VF control VSI interrupt handling All VF control VSIs share the same interrupt vector. Currently, a helper function dedicated for that directly sets ice_vsi::base_vector. Use helper that returns pointer to first found VF control VSI instead. Reviewed-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Rafal Romanowski Signed-off-by: Piotr Raczynski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 85 +++++++---------------------- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 32 +++++++++++ drivers/net/ethernet/intel/ice/ice_vf_lib.h | 7 +++ 3 files changed, 58 insertions(+), 66 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 79e1557f77e8..25511240685d 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1473,36 +1473,6 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id) return ice_search_res(res, needed, id); } -/** - * ice_get_vf_ctrl_res - Get VF control VSI resource - * @pf: pointer to the PF structure - * @vsi: the VSI to allocate a resource for - * - * Look up whether another VF has already allocated the control VSI resource. - * If so, re-use this resource so that we share it among all VFs. - * - * Otherwise, allocate the resource and return it. - */ -static int ice_get_vf_ctrl_res(struct ice_pf *pf, struct ice_vsi *vsi) -{ - struct ice_vf *vf; - unsigned int bkt; - int base; - - rcu_read_lock(); - ice_for_each_vf_rcu(pf, bkt, vf) { - if (vf != vsi->vf && vf->ctrl_vsi_idx != ICE_NO_VSI) { - base = pf->vsi[vf->ctrl_vsi_idx]->base_vector; - rcu_read_unlock(); - return base; - } - } - rcu_read_unlock(); - - return ice_get_res(pf, pf->irq_tracker, vsi->num_q_vectors, - ICE_RES_VF_CTRL_VEC_ID); -} - /** * ice_vsi_setup_vector_base - Set up the base vector for the given VSI * @vsi: ptr to the VSI @@ -1516,8 +1486,8 @@ static int ice_get_vf_ctrl_res(struct ice_pf *pf, struct ice_vsi *vsi) static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; + u16 num_q_vectors, id; struct device *dev; - u16 num_q_vectors; int base; dev = ice_pf_to_dev(pf); @@ -1536,12 +1506,20 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) num_q_vectors = vsi->num_q_vectors; /* reserve slots from OS requested IRQs */ if (vsi->type == ICE_VSI_CTRL && vsi->vf) { - base = ice_get_vf_ctrl_res(pf, vsi); + struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi); + + /* reuse VF control VSI interrupt vector */ + if (ctrl_vsi) { + vsi->base_vector = ctrl_vsi->base_vector; + return 0; + } + + id = ICE_RES_VF_CTRL_VEC_ID; } else { - base = ice_get_res(pf, pf->irq_tracker, num_q_vectors, - vsi->idx); + id = vsi->idx; } + base = ice_get_res(pf, pf->irq_tracker, num_q_vectors, id); if (base < 0) { dev_err(dev, "%d MSI-X interrupts available. %s %d failed to get %d MSI-X vectors\n", ice_get_free_res_count(pf->irq_tracker), @@ -2611,37 +2589,6 @@ static void ice_set_agg_vsi(struct ice_vsi *vsi) vsi->agg_node->num_vsis); } -/** - * ice_free_vf_ctrl_res - Free the VF control VSI resource - * @pf: pointer to PF structure - * @vsi: the VSI to free resources for - * - * Check if the VF control VSI resource is still in use. If no VF is using it - * any more, release the VSI resource. Otherwise, leave it to be cleaned up - * once no other VF uses it. - */ -static void ice_free_vf_ctrl_res(struct ice_pf *pf, struct ice_vsi *vsi) -{ - struct ice_vf *vf; - unsigned int bkt; - - rcu_read_lock(); - ice_for_each_vf_rcu(pf, bkt, vf) { - if (vf != vsi->vf && vf->ctrl_vsi_idx != ICE_NO_VSI) { - rcu_read_unlock(); - return; - } - } - rcu_read_unlock(); - - /* No other VFs left that have control VSI. It is now safe to reclaim - * SW interrupts back to the common pool. - */ - ice_free_res(pf->irq_tracker, vsi->base_vector, - ICE_RES_VF_CTRL_VEC_ID); - pf->num_avail_sw_msix += vsi->num_q_vectors; -} - static int ice_vsi_cfg_tc_lan(struct ice_pf *pf, struct ice_vsi *vsi) { u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; @@ -2916,7 +2863,13 @@ void ice_vsi_decfg(struct ice_vsi *vsi) * cleared in the same manner. */ if (vsi->type == ICE_VSI_CTRL && vsi->vf) { - ice_free_vf_ctrl_res(pf, vsi); + struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi); + + if (!ctrl_vsi) { + ice_free_res(pf->irq_tracker, vsi->base_vector, + ICE_RES_VF_CTRL_VEC_ID); + pf->num_avail_sw_msix += vsi->num_q_vectors; + } } else if (vsi->type != ICE_VSI_VF) { /* reclaim SW interrupts back to the common pool */ ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx); diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 89fd6982df09..68142facc85d 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -1310,3 +1310,35 @@ void ice_vf_set_initialized(struct ice_vf *vf) set_bit(ICE_VF_STATE_INIT, vf->vf_states); memset(&vf->vlan_v2_caps, 0, sizeof(vf->vlan_v2_caps)); } + +/** + * ice_get_vf_ctrl_vsi - Get first VF control VSI pointer + * @pf: the PF private structure + * @vsi: pointer to the VSI + * + * Return first found VF control VSI other than the vsi + * passed by parameter. This function is used to determine + * whether new resources have to be allocated for control VSI + * or they can be shared with existing one. + * + * Return found VF control VSI pointer other itself. Return + * NULL Otherwise. + * + */ +struct ice_vsi *ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi) +{ + struct ice_vsi *ctrl_vsi = NULL; + struct ice_vf *vf; + unsigned int bkt; + + rcu_read_lock(); + ice_for_each_vf_rcu(pf, bkt, vf) { + if (vf != vsi->vf && vf->ctrl_vsi_idx != ICE_NO_VSI) { + ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx]; + break; + } + } + + rcu_read_unlock(); + return ctrl_vsi; +} diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h index e3cda6fb71ab..48fea6fa0362 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h @@ -226,6 +226,7 @@ int ice_vf_clear_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m); int ice_reset_vf(struct ice_vf *vf, u32 flags); void ice_reset_all_vfs(struct ice_pf *pf); +struct ice_vsi *ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi); #else /* CONFIG_PCI_IOV */ static inline struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id) { @@ -290,6 +291,12 @@ static inline int ice_reset_vf(struct ice_vf *vf, u32 flags) static inline void ice_reset_all_vfs(struct ice_pf *pf) { } + +static inline struct ice_vsi * +ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi) +{ + return NULL; +} #endif /* !CONFIG_PCI_IOV */ #endif /* _ICE_VF_LIB_H_ */ -- cgit v1.2.3 From 524012c69ee1421d4a343291a0cfc1998ccba99a Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Mon, 15 May 2023 21:03:16 +0200 Subject: ice: remove redundant SRIOV code Remove redundant code from ice_get_max_valid_res_idx that has no effect. ice_pf::irq_tracker is initialized during driver probe, there is no reason to check it again. Also it is not possible for pf::sriov_base_vector to be lower than the tracker length, remove WARN_ON that will never happen. Get rid of ice_get_max_valid_res_idx helper function completely since it can never return negative value. Reviewed-by: Jacob Keller Reviewed-by: Michal Swiatkowski Reviewed-by: Simon Horman Tested-by: Rafal Romanowski Signed-off-by: Piotr Raczynski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_sriov.c | 36 ------------------------------ 1 file changed, 36 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index f1dca59bd844..65f971b74717 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -135,18 +135,9 @@ static void ice_dis_vf_mappings(struct ice_vf *vf) */ static int ice_sriov_free_msix_res(struct ice_pf *pf) { - struct ice_res_tracker *res; - if (!pf) return -EINVAL; - res = pf->irq_tracker; - if (!res) - return -EINVAL; - - /* give back irq_tracker resources used */ - WARN_ON(pf->sriov_base_vector < res->num_entries); - pf->sriov_base_vector = 0; return 0; @@ -409,29 +400,6 @@ int ice_calc_vf_reg_idx(struct ice_vf *vf, struct ice_q_vector *q_vector) q_vector->v_idx + 1; } -/** - * ice_get_max_valid_res_idx - Get the max valid resource index - * @res: pointer to the resource to find the max valid index for - * - * Start from the end of the ice_res_tracker and return right when we find the - * first res->list entry with the ICE_RES_VALID_BIT set. This function is only - * valid for SR-IOV because it is the only consumer that manipulates the - * res->end and this is always called when res->end is set to res->num_entries. - */ -static int ice_get_max_valid_res_idx(struct ice_res_tracker *res) -{ - int i; - - if (!res) - return -EINVAL; - - for (i = res->num_entries - 1; i >= 0; i--) - if (res->list[i] & ICE_RES_VALID_BIT) - return i; - - return 0; -} - /** * ice_sriov_set_msix_res - Set any used MSIX resources * @pf: pointer to PF structure @@ -490,7 +458,6 @@ static int ice_sriov_set_msix_res(struct ice_pf *pf, u16 num_msix_needed) */ static int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs) { - int max_valid_res_idx = ice_get_max_valid_res_idx(pf->irq_tracker); u16 num_msix_per_vf, num_txq, num_rxq, avail_qs; int msix_avail_per_vf, msix_avail_for_sriov; struct device *dev = ice_pf_to_dev(pf); @@ -501,9 +468,6 @@ static int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs) if (!num_vfs) return -EINVAL; - if (max_valid_res_idx < 0) - return -ENOSPC; - /* determine MSI-X resources per VF */ msix_avail_for_sriov = pf->hw.func_caps.common_cap.num_msix_vectors - pf->irq_tracker->num_entries; -- cgit v1.2.3 From 4aad5335969f25c4dc966a15c5497db3718538bb Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Mon, 15 May 2023 21:03:17 +0200 Subject: ice: add individual interrupt allocation Currently interrupt allocations, depending on a feature are distributed in batches. Also, after allocation there is a series of operations that distributes per irq settings through that batch of interrupts. Although driver does not yet support dynamic interrupt allocation, keep allocated interrupts in a pool and add allocation abstraction logic to make code more flexible. Keep per interrupt information in the ice_q_vector structure, which yields ice_vsi::base_vector redundant. Also, as a result there are a few functions that can be removed. Reviewed-by: Jacob Keller Reviewed-by: Michal Swiatkowski Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Piotr Raczynski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 11 +- drivers/net/ethernet/intel/ice/ice_arfs.c | 5 +- drivers/net/ethernet/intel/ice/ice_base.c | 50 +++++- drivers/net/ethernet/intel/ice/ice_ethtool.c | 2 +- drivers/net/ethernet/intel/ice/ice_idc.c | 45 +++--- drivers/net/ethernet/intel/ice/ice_irq.c | 46 +++++- drivers/net/ethernet/intel/ice/ice_irq.h | 3 + drivers/net/ethernet/intel/ice/ice_lib.c | 228 +++------------------------ drivers/net/ethernet/intel/ice/ice_lib.h | 4 +- drivers/net/ethernet/intel/ice/ice_main.c | 44 +++--- drivers/net/ethernet/intel/ice/ice_ptp.c | 2 +- drivers/net/ethernet/intel/ice/ice_sriov.c | 2 +- drivers/net/ethernet/intel/ice/ice_xsk.c | 5 +- 13 files changed, 165 insertions(+), 282 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 4dc4c6bec081..d8dde291491e 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -105,10 +105,6 @@ #define ICE_Q_WAIT_MAX_RETRY (5 * ICE_Q_WAIT_RETRY_LIMIT) #define ICE_MAX_LG_RSS_QS 256 #define ICE_RES_VALID_BIT 0x8000 -#define ICE_RES_MISC_VEC_ID (ICE_RES_VALID_BIT - 1) -#define ICE_RES_RDMA_VEC_ID (ICE_RES_MISC_VEC_ID - 1) -/* All VF control VSIs share the same IRQ, so assign a unique ID for them */ -#define ICE_RES_VF_CTRL_VEC_ID (ICE_RES_RDMA_VEC_ID - 1) #define ICE_INVAL_Q_INDEX 0xffff #define ICE_MAX_RXQS_PER_TC 256 /* Used when setting VSI context per TC Rx queues */ @@ -349,7 +345,6 @@ struct ice_vsi { u32 rx_buf_failed; u32 rx_page_failed; u16 num_q_vectors; - u16 base_vector; /* IRQ base for OS reserved vectors */ enum ice_vsi_type type; u16 vsi_num; /* HW (absolute) index of this VSI */ u16 idx; /* software index in pf->vsi[] */ @@ -480,6 +475,7 @@ struct ice_q_vector { char name[ICE_INT_NAME_STR_LEN]; u16 total_events; /* net_dim(): number of interrupts processed */ + struct msi_map irq; } ____cacheline_internodealigned_in_smp; enum ice_pf_flags { @@ -584,8 +580,7 @@ struct ice_pf { u32 hw_csum_rx_error; u32 oicr_err_reg; - u16 oicr_idx; /* Other interrupt cause MSIX vector index */ - u16 num_avail_sw_msix; /* remaining MSIX SW vectors left unclaimed */ + struct msi_map oicr_irq; /* Other interrupt cause MSIX vector */ u16 max_pf_txqs; /* Total Tx queues PF wide */ u16 max_pf_rxqs; /* Total Rx queues PF wide */ u16 num_lan_msix; /* Total MSIX vectors for base driver */ @@ -671,7 +666,7 @@ ice_irq_dynamic_ena(struct ice_hw *hw, struct ice_vsi *vsi, struct ice_q_vector *q_vector) { u32 vector = (vsi && q_vector) ? q_vector->reg_idx : - ((struct ice_pf *)hw->back)->oicr_idx; + ((struct ice_pf *)hw->back)->oicr_irq.index; int itr = ICE_ITR_NONE; u32 val; diff --git a/drivers/net/ethernet/intel/ice/ice_arfs.c b/drivers/net/ethernet/intel/ice/ice_arfs.c index e81797344f5e..cca0e753f38f 100644 --- a/drivers/net/ethernet/intel/ice/ice_arfs.c +++ b/drivers/net/ethernet/intel/ice/ice_arfs.c @@ -596,7 +596,7 @@ int ice_set_cpu_rx_rmap(struct ice_vsi *vsi) { struct net_device *netdev; struct ice_pf *pf; - int base_idx, i; + int i; if (!vsi || vsi->type != ICE_VSI_PF) return 0; @@ -613,10 +613,9 @@ int ice_set_cpu_rx_rmap(struct ice_vsi *vsi) if (unlikely(!netdev->rx_cpu_rmap)) return -EINVAL; - base_idx = vsi->base_vector; ice_for_each_q_vector(vsi, i) if (irq_cpu_rmap_add(netdev->rx_cpu_rmap, - pci_irq_vector(pf->pdev, base_idx + i))) { + vsi->q_vectors[i]->irq.virq)) { ice_free_cpu_rx_rmap(vsi); return -EINVAL; } diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 1911d644dfa8..cb0913cb9741 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -103,10 +103,10 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx) { struct ice_pf *pf = vsi->back; struct ice_q_vector *q_vector; + int err; /* allocate q_vector */ - q_vector = devm_kzalloc(ice_pf_to_dev(pf), sizeof(*q_vector), - GFP_KERNEL); + q_vector = kzalloc(sizeof(*q_vector), GFP_KERNEL); if (!q_vector) return -ENOMEM; @@ -118,9 +118,34 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx) q_vector->rx.itr_mode = ITR_DYNAMIC; q_vector->tx.type = ICE_TX_CONTAINER; q_vector->rx.type = ICE_RX_CONTAINER; + q_vector->irq.index = -ENOENT; - if (vsi->type == ICE_VSI_VF) + if (vsi->type == ICE_VSI_VF) { + q_vector->reg_idx = ice_calc_vf_reg_idx(vsi->vf, q_vector); goto out; + } else if (vsi->type == ICE_VSI_CTRL && vsi->vf) { + struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi); + + if (ctrl_vsi) { + if (unlikely(!ctrl_vsi->q_vectors)) { + err = -ENOENT; + goto err_free_q_vector; + } + + q_vector->irq = ctrl_vsi->q_vectors[0]->irq; + goto skip_alloc; + } + } + + q_vector->irq = ice_alloc_irq(pf); + if (q_vector->irq.index < 0) { + err = -ENOMEM; + goto err_free_q_vector; + } + +skip_alloc: + q_vector->reg_idx = q_vector->irq.index; + /* only set affinity_mask if the CPU is online */ if (cpu_online(v_idx)) cpumask_set_cpu(v_idx, &q_vector->affinity_mask); @@ -137,6 +162,11 @@ out: vsi->q_vectors[v_idx] = q_vector; return 0; + +err_free_q_vector: + kfree(q_vector); + + return err; } /** @@ -168,7 +198,19 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) if (vsi->netdev) netif_napi_del(&q_vector->napi); - devm_kfree(dev, q_vector); + /* release MSIX interrupt if q_vector had interrupt allocated */ + if (q_vector->irq.index < 0) + goto free_q_vector; + + /* only free last VF ctrl vsi interrupt */ + if (vsi->type == ICE_VSI_CTRL && vsi->vf && + ice_get_vf_ctrl_vsi(pf, vsi)) + goto free_q_vector; + + ice_free_irq(pf, q_vector->irq); + +free_q_vector: + kfree(q_vector); vsi->q_vectors[v_idx] = NULL; } diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index f86e814354a3..8407c7175cf6 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -956,7 +956,7 @@ static u64 ice_intr_test(struct net_device *netdev) netdev_info(netdev, "interrupt test\n"); - wr32(&pf->hw, GLINT_DYN_CTL(pf->oicr_idx), + wr32(&pf->hw, GLINT_DYN_CTL(pf->oicr_irq.index), GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M | GLINT_DYN_CTL_SWINT_TRIG_M); diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c index 1000759505d7..bc016bb4440c 100644 --- a/drivers/net/ethernet/intel/ice/ice_idc.c +++ b/drivers/net/ethernet/intel/ice/ice_idc.c @@ -229,38 +229,33 @@ void ice_get_qos_params(struct ice_pf *pf, struct iidc_qos_params *qos) EXPORT_SYMBOL_GPL(ice_get_qos_params); /** - * ice_reserve_rdma_qvector - Reserve vector resources for RDMA driver + * ice_alloc_rdma_qvectors - Allocate vector resources for RDMA driver * @pf: board private structure to initialize */ -static int ice_reserve_rdma_qvector(struct ice_pf *pf) +static int ice_alloc_rdma_qvectors(struct ice_pf *pf) { if (ice_is_rdma_ena(pf)) { - int index, i; - - index = ice_get_res(pf, pf->irq_tracker, pf->num_rdma_msix, - ICE_RES_RDMA_VEC_ID); - if (index < 0) - return index; + int i; pf->msix_entries = kcalloc(pf->num_rdma_msix, sizeof(*pf->msix_entries), GFP_KERNEL); - if (!pf->msix_entries) { - ice_free_res(pf->irq_tracker, pf->rdma_base_vector, - ICE_RES_RDMA_VEC_ID); + if (!pf->msix_entries) return -ENOMEM; - } - - pf->num_avail_sw_msix -= pf->num_rdma_msix; /* RDMA is the only user of pf->msix_entries array */ pf->rdma_base_vector = 0; - for (i = 0; i < pf->num_rdma_msix; i++, index++) { + for (i = 0; i < pf->num_rdma_msix; i++) { struct msix_entry *entry = &pf->msix_entries[i]; + struct msi_map map; - entry->entry = index; - entry->vector = pci_irq_vector(pf->pdev, index); + map = ice_alloc_irq(pf); + if (map.index < 0) + break; + + entry->entry = map.index; + entry->vector = map.virq; } } return 0; @@ -272,15 +267,21 @@ static int ice_reserve_rdma_qvector(struct ice_pf *pf) */ static void ice_free_rdma_qvector(struct ice_pf *pf) { + int i; + if (!pf->msix_entries) return; + for (i = 0; i < pf->num_rdma_msix; i++) { + struct msi_map map; + + map.index = pf->msix_entries[i].entry; + map.virq = pf->msix_entries[i].vector; + ice_free_irq(pf, map); + } + kfree(pf->msix_entries); pf->msix_entries = NULL; - - pf->num_avail_sw_msix -= pf->num_rdma_msix; - ice_free_res(pf->irq_tracker, pf->rdma_base_vector, - ICE_RES_RDMA_VEC_ID); } /** @@ -382,7 +383,7 @@ int ice_init_rdma(struct ice_pf *pf) } /* Reserve vector resources */ - ret = ice_reserve_rdma_qvector(pf); + ret = ice_alloc_rdma_qvectors(pf); if (ret < 0) { dev_err(dev, "failed to reserve vectors for RDMA\n"); goto err_reserve_rdma_qvector; diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c index f61be5d76373..ca1a1de26766 100644 --- a/drivers/net/ethernet/intel/ice/ice_irq.c +++ b/drivers/net/ethernet/intel/ice/ice_irq.c @@ -194,9 +194,53 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) } /* populate SW interrupts pool with number of OS granted IRQs. */ - pf->num_avail_sw_msix = (u16)vectors; pf->irq_tracker->num_entries = (u16)vectors; pf->irq_tracker->end = pf->irq_tracker->num_entries; return 0; } + +/** + * ice_alloc_irq - Allocate new interrupt vector + * @pf: board private structure + * + * Allocate new interrupt vector for a given owner id. + * return struct msi_map with interrupt details and track + * allocated interrupt appropriately. + * + * This function mimics individual interrupt allocation, + * even interrupts are actually already allocated with + * pci_alloc_irq_vectors. Individual allocation helps + * to track interrupts and simplifies interrupt related + * handling. + * + * On failure, return map with negative .index. The caller + * is expected to check returned map index. + * + */ +struct msi_map ice_alloc_irq(struct ice_pf *pf) +{ + struct msi_map map = { .index = -ENOENT }; + int entry; + + entry = ice_get_res(pf, pf->irq_tracker); + if (entry < 0) + return map; + + map.index = entry; + map.virq = pci_irq_vector(pf->pdev, map.index); + + return map; +} + +/** + * ice_free_irq - Free interrupt vector + * @pf: board private structure + * @map: map with interrupt details + * + * Remove allocated interrupt from the interrupt tracker + */ +void ice_free_irq(struct ice_pf *pf, struct msi_map map) +{ + ice_free_res(pf->irq_tracker, map.index); +} diff --git a/drivers/net/ethernet/intel/ice/ice_irq.h b/drivers/net/ethernet/intel/ice/ice_irq.h index 82475162ab70..26e80dfe22b5 100644 --- a/drivers/net/ethernet/intel/ice/ice_irq.h +++ b/drivers/net/ethernet/intel/ice/ice_irq.h @@ -7,4 +7,7 @@ int ice_init_interrupt_scheme(struct ice_pf *pf); void ice_clear_interrupt_scheme(struct ice_pf *pf); +struct msi_map ice_alloc_irq(struct ice_pf *pf); +void ice_free_irq(struct ice_pf *pf, struct msi_map map); + #endif diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 25511240685d..fe908cf6da6a 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1374,162 +1374,45 @@ out: * ice_free_res - free a block of resources * @res: pointer to the resource * @index: starting index previously returned by ice_get_res - * @id: identifier to track owner * * Returns number of resources freed */ -int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id) +int ice_free_res(struct ice_res_tracker *res, u16 index) { - int count = 0; - int i; - if (!res || index >= res->end) return -EINVAL; - id |= ICE_RES_VALID_BIT; - for (i = index; i < res->end && res->list[i] == id; i++) { - res->list[i] = 0; - count++; - } - - return count; -} - -/** - * ice_search_res - Search the tracker for a block of resources - * @res: pointer to the resource - * @needed: size of the block needed - * @id: identifier to track owner - * - * Returns the base item index of the block, or -ENOMEM for error - */ -static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id) -{ - u16 start = 0, end = 0; - - if (needed > res->end) - return -ENOMEM; - - id |= ICE_RES_VALID_BIT; - - do { - /* skip already allocated entries */ - if (res->list[end++] & ICE_RES_VALID_BIT) { - start = end; - if ((start + needed) > res->end) - break; - } - - if (end == (start + needed)) { - int i = start; - - /* there was enough, so assign it to the requestor */ - while (i != end) - res->list[i++] = id; - - return start; - } - } while (end < res->end); - - return -ENOMEM; -} - -/** - * ice_get_free_res_count - Get free count from a resource tracker - * @res: Resource tracker instance - */ -static u16 ice_get_free_res_count(struct ice_res_tracker *res) -{ - u16 i, count = 0; + res->list[index] = 0; - for (i = 0; i < res->end; i++) - if (!(res->list[i] & ICE_RES_VALID_BIT)) - count++; - - return count; + return 0; } /** - * ice_get_res - get a block of resources + * ice_get_res - get a resource from the tracker * @pf: board private structure * @res: pointer to the resource - * @needed: size of the block needed - * @id: identifier to track owner * - * Returns the base item index of the block, or negative for error + * Returns the item index, or negative for error */ int -ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id) +ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res) { - if (!res || !pf) - return -EINVAL; + u16 i; - if (!needed || needed > res->num_entries || id >= ICE_RES_VALID_BIT) { - dev_err(ice_pf_to_dev(pf), "param err: needed=%d, num_entries = %d id=0x%04x\n", - needed, res->num_entries, id); + if (!res || !pf) return -EINVAL; - } - - return ice_search_res(res, needed, id); -} - -/** - * ice_vsi_setup_vector_base - Set up the base vector for the given VSI - * @vsi: ptr to the VSI - * - * This should only be called after ice_vsi_alloc_def() which allocates the - * corresponding SW VSI structure and initializes num_queue_pairs for the - * newly allocated VSI. - * - * Returns 0 on success or negative on failure - */ -static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - u16 num_q_vectors, id; - struct device *dev; - int base; - dev = ice_pf_to_dev(pf); - /* SRIOV doesn't grab irq_tracker entries for each VSI */ - if (vsi->type == ICE_VSI_VF) - return 0; - if (vsi->type == ICE_VSI_CHNL) - return 0; - - if (vsi->base_vector) { - dev_dbg(dev, "VSI %d has non-zero base vector %d\n", - vsi->vsi_num, vsi->base_vector); - return -EEXIST; - } - - num_q_vectors = vsi->num_q_vectors; - /* reserve slots from OS requested IRQs */ - if (vsi->type == ICE_VSI_CTRL && vsi->vf) { - struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi); - - /* reuse VF control VSI interrupt vector */ - if (ctrl_vsi) { - vsi->base_vector = ctrl_vsi->base_vector; - return 0; - } + /* skip already allocated entries */ + for (i = 0; i < res->end; i++) + if (!(res->list[i] & ICE_RES_VALID_BIT)) + break; - id = ICE_RES_VF_CTRL_VEC_ID; + if (i < res->end) { + res->list[i] = ICE_RES_VALID_BIT; + return i; } else { - id = vsi->idx; - } - - base = ice_get_res(pf, pf->irq_tracker, num_q_vectors, id); - if (base < 0) { - dev_err(dev, "%d MSI-X interrupts available. %s %d failed to get %d MSI-X vectors\n", - ice_get_free_res_count(pf->irq_tracker), - ice_vsi_type_str(vsi->type), vsi->idx, num_q_vectors); - return -ENOENT; + return -ENOMEM; } - vsi->base_vector = (u16)base; - pf->num_avail_sw_msix -= num_q_vectors; - - return 0; } /** @@ -2387,50 +2270,6 @@ static void ice_vsi_set_tc_cfg(struct ice_vsi *vsi) ice_vsi_set_dcb_tc_cfg(vsi); } -/** - * ice_vsi_set_q_vectors_reg_idx - set the HW register index for all q_vectors - * @vsi: VSI to set the q_vectors register index on - */ -static int -ice_vsi_set_q_vectors_reg_idx(struct ice_vsi *vsi) -{ - u16 i; - - if (!vsi || !vsi->q_vectors) - return -EINVAL; - - ice_for_each_q_vector(vsi, i) { - struct ice_q_vector *q_vector = vsi->q_vectors[i]; - - if (!q_vector) { - dev_err(ice_pf_to_dev(vsi->back), "Failed to set reg_idx on q_vector %d VSI %d\n", - i, vsi->vsi_num); - goto clear_reg_idx; - } - - if (vsi->type == ICE_VSI_VF) { - struct ice_vf *vf = vsi->vf; - - q_vector->reg_idx = ice_calc_vf_reg_idx(vf, q_vector); - } else { - q_vector->reg_idx = - q_vector->v_idx + vsi->base_vector; - } - } - - return 0; - -clear_reg_idx: - ice_for_each_q_vector(vsi, i) { - struct ice_q_vector *q_vector = vsi->q_vectors[i]; - - if (q_vector) - q_vector->reg_idx = 0; - } - - return -EINVAL; -} - /** * ice_cfg_sw_lldp - Config switch rules for LLDP packet handling * @vsi: the VSI being configured @@ -2675,14 +2514,6 @@ ice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params) if (ret) goto unroll_vsi_init; - ret = ice_vsi_setup_vector_base(vsi); - if (ret) - goto unroll_alloc_q_vector; - - ret = ice_vsi_set_q_vectors_reg_idx(vsi); - if (ret) - goto unroll_vector_base; - ret = ice_vsi_alloc_rings(vsi); if (ret) goto unroll_vector_base; @@ -2733,10 +2564,6 @@ ice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params) if (ret) goto unroll_alloc_q_vector; - ret = ice_vsi_set_q_vectors_reg_idx(vsi); - if (ret) - goto unroll_vector_base; - ret = ice_vsi_alloc_ring_stats(vsi); if (ret) goto unroll_vector_base; @@ -2769,8 +2596,6 @@ ice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params) unroll_vector_base: /* reclaim SW interrupts back to the common pool */ - ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx); - pf->num_avail_sw_msix += vsi->num_q_vectors; unroll_alloc_q_vector: ice_vsi_free_q_vectors(vsi); unroll_vsi_init: @@ -2862,20 +2687,6 @@ void ice_vsi_decfg(struct ice_vsi *vsi) * many interrupts each VF needs. SR-IOV MSIX resources are also * cleared in the same manner. */ - if (vsi->type == ICE_VSI_CTRL && vsi->vf) { - struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi); - - if (!ctrl_vsi) { - ice_free_res(pf->irq_tracker, vsi->base_vector, - ICE_RES_VF_CTRL_VEC_ID); - pf->num_avail_sw_msix += vsi->num_q_vectors; - } - } else if (vsi->type != ICE_VSI_VF) { - /* reclaim SW interrupts back to the common pool */ - ice_free_res(pf->irq_tracker, vsi->base_vector, vsi->idx); - pf->num_avail_sw_msix += vsi->num_q_vectors; - vsi->base_vector = 0; - } if (vsi->type == ICE_VSI_VF && vsi->agg_node && vsi->agg_node->valid) @@ -2992,7 +2803,6 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi) void ice_vsi_free_irq(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; - int base = vsi->base_vector; int i; if (!vsi->q_vectors || !vsi->irqs_ready) @@ -3006,10 +2816,9 @@ void ice_vsi_free_irq(struct ice_vsi *vsi) ice_free_cpu_rx_rmap(vsi); ice_for_each_q_vector(vsi, i) { - u16 vector = i + base; int irq_num; - irq_num = pci_irq_vector(pf->pdev, vector); + irq_num = vsi->q_vectors[i]->irq.virq; /* free only the irqs that were actually requested */ if (!vsi->q_vectors[i] || @@ -3141,7 +2950,6 @@ void ice_dis_vsi(struct ice_vsi *vsi, bool locked) */ void ice_vsi_dis_irq(struct ice_vsi *vsi) { - int base = vsi->base_vector; struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; u32 val; @@ -3188,7 +2996,7 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi) return; ice_for_each_q_vector(vsi, i) - synchronize_irq(pci_irq_vector(pf->pdev, i + base)); + synchronize_irq(vsi->q_vectors[i]->irq.virq); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 75221478f2dc..2f52f9e32858 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -104,10 +104,10 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked); void ice_vsi_decfg(struct ice_vsi *vsi); void ice_dis_vsi(struct ice_vsi *vsi, bool locked); -int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id); +int ice_free_res(struct ice_res_tracker *res, u16 index); int -ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id); +ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res); int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags); int ice_vsi_cfg(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index ce8cd49ae10c..efc621c0bd6c 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2490,7 +2490,6 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) { int q_vectors = vsi->num_q_vectors; struct ice_pf *pf = vsi->back; - int base = vsi->base_vector; struct device *dev; int rx_int_idx = 0; int tx_int_idx = 0; @@ -2501,7 +2500,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) for (vector = 0; vector < q_vectors; vector++) { struct ice_q_vector *q_vector = vsi->q_vectors[vector]; - irq_num = pci_irq_vector(pf->pdev, base + vector); + irq_num = q_vector->irq.virq; if (q_vector->tx.tx_ring && q_vector->rx.rx_ring) { snprintf(q_vector->name, sizeof(q_vector->name) - 1, @@ -2555,9 +2554,8 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) return 0; free_q_irqs: - while (vector) { - vector--; - irq_num = pci_irq_vector(pf->pdev, base + vector); + while (vector--) { + irq_num = vsi->q_vectors[vector]->irq.virq; if (!IS_ENABLED(CONFIG_RFS_ACCEL)) irq_set_affinity_notifier(irq_num, NULL); irq_set_affinity_hint(irq_num, NULL); @@ -3047,7 +3045,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf) wr32(hw, PFINT_OICR_ENA, val); /* SW_ITR_IDX = 0, but don't change INTENA */ - wr32(hw, GLINT_DYN_CTL(pf->oicr_idx), + wr32(hw, GLINT_DYN_CTL(pf->oicr_irq.index), GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M); } @@ -3234,7 +3232,7 @@ static void ice_dis_ctrlq_interrupts(struct ice_hw *hw) */ static void ice_free_irq_msix_misc(struct ice_pf *pf) { - int misc_irq_num = pci_irq_vector(pf->pdev, pf->oicr_idx); + int misc_irq_num = pf->oicr_irq.virq; struct ice_hw *hw = &pf->hw; ice_dis_ctrlq_interrupts(hw); @@ -3246,8 +3244,7 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf) synchronize_irq(misc_irq_num); devm_free_irq(ice_pf_to_dev(pf), misc_irq_num, pf); - pf->num_avail_sw_msix += 1; - ice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID); + ice_free_irq(pf, pf->oicr_irq); } /** @@ -3293,7 +3290,8 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) { struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; - int oicr_idx, err = 0; + struct msi_map oicr_irq; + int err = 0; if (!pf->int_name[0]) snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc", @@ -3307,30 +3305,26 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) goto skip_req_irq; /* reserve one vector in irq_tracker for misc interrupts */ - oicr_idx = ice_get_res(pf, pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); - if (oicr_idx < 0) - return oicr_idx; - - pf->num_avail_sw_msix -= 1; - pf->oicr_idx = (u16)oicr_idx; - - err = devm_request_threaded_irq(dev, - pci_irq_vector(pf->pdev, pf->oicr_idx), - ice_misc_intr, ice_misc_intr_thread_fn, - 0, pf->int_name, pf); + oicr_irq = ice_alloc_irq(pf); + if (oicr_irq.index < 0) + return oicr_irq.index; + + pf->oicr_irq = oicr_irq; + err = devm_request_threaded_irq(dev, pf->oicr_irq.virq, ice_misc_intr, + ice_misc_intr_thread_fn, 0, + pf->int_name, pf); if (err) { dev_err(dev, "devm_request_threaded_irq for %s failed: %d\n", pf->int_name, err); - ice_free_res(pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); - pf->num_avail_sw_msix += 1; + ice_free_irq(pf, pf->oicr_irq); return err; } skip_req_irq: ice_ena_misc_vector(pf); - ice_ena_ctrlq_interrupts(hw, pf->oicr_idx); - wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_idx), + ice_ena_ctrlq_interrupts(hw, pf->oicr_irq.index); + wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_irq.index), ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S); ice_flush(hw); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 972d4f6fd615..d4b6c997141d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -911,7 +911,7 @@ ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx) spin_unlock(&tx->lock); /* wait for potentially outstanding interrupt to complete */ - synchronize_irq(pci_irq_vector(pf->pdev, pf->oicr_idx)); + synchronize_irq(pf->oicr_irq.virq); ice_ptp_flush_tx_tracker(pf, tx); diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 65f971b74717..0fc2b26a2fa6 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -835,7 +835,7 @@ static int ice_ena_vfs(struct ice_pf *pf, u16 num_vfs) int ret; /* Disable global interrupt 0 so we don't try to handle the VFLR. */ - wr32(hw, GLINT_DYN_CTL(pf->oicr_idx), + wr32(hw, GLINT_DYN_CTL(pf->oicr_irq.index), ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S); set_bit(ICE_OICR_INTR_DIS, pf->state); ice_flush(hw); diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index 4102416d7a41..a7fe2b4ce655 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -90,7 +90,6 @@ ice_qvec_dis_irq(struct ice_vsi *vsi, struct ice_rx_ring *rx_ring, { struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; - int base = vsi->base_vector; u16 reg; u32 val; @@ -103,11 +102,9 @@ ice_qvec_dis_irq(struct ice_vsi *vsi, struct ice_rx_ring *rx_ring, wr32(hw, QINT_RQCTL(reg), val); if (q_vector) { - u16 v_idx = q_vector->v_idx; - wr32(hw, GLINT_DYN_CTL(q_vector->reg_idx), 0); ice_flush(hw); - synchronize_irq(pci_irq_vector(pf->pdev, v_idx + base)); + synchronize_irq(q_vector->irq.virq); } } -- cgit v1.2.3 From cfebc0a36ea5518d6b32a6999da5accf0a94fafa Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Mon, 15 May 2023 21:03:18 +0200 Subject: ice: track interrupt vectors with xarray Replace custom interrupt tracker with generic xarray data structure. Remove all code responsible for searching for a new entry with xa_alloc, which always tries to allocate at the lowes possible index. As a result driver is always using a contiguous region of the MSIX vector table. New tracker keeps ice_irq_entry entries in xarray as opaque for the rest of the driver hiding the entry details from the caller. Reviewed-by: Jacob Keller Reviewed-by: Michal Swiatkowski Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Piotr Raczynski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 9 +-- drivers/net/ethernet/intel/ice/ice_irq.c | 101 ++++++++++++++++++++++------- drivers/net/ethernet/intel/ice/ice_irq.h | 9 +++ drivers/net/ethernet/intel/ice/ice_lib.c | 45 ------------- drivers/net/ethernet/intel/ice/ice_lib.h | 5 -- drivers/net/ethernet/intel/ice/ice_sriov.c | 4 +- 6 files changed, 89 insertions(+), 84 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index d8dde291491e..8541d986ec7f 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -104,7 +104,6 @@ #define ICE_Q_WAIT_RETRY_LIMIT 10 #define ICE_Q_WAIT_MAX_RETRY (5 * ICE_Q_WAIT_RETRY_LIMIT) #define ICE_MAX_LG_RSS_QS 256 -#define ICE_RES_VALID_BIT 0x8000 #define ICE_INVAL_Q_INDEX 0xffff #define ICE_MAX_RXQS_PER_TC 256 /* Used when setting VSI context per TC Rx queues */ @@ -242,12 +241,6 @@ struct ice_tc_cfg { struct ice_tc_info tc_info[ICE_MAX_TRAFFIC_CLASS]; }; -struct ice_res_tracker { - u16 num_entries; - u16 end; - u16 list[]; -}; - struct ice_qs_cfg { struct mutex *qs_mutex; /* will be assigned to &pf->avail_q_mutex */ unsigned long *pf_map; @@ -536,7 +529,7 @@ struct ice_pf { /* OS reserved IRQ details */ struct msix_entry *msix_entries; - struct ice_res_tracker *irq_tracker; + struct ice_irq_tracker irq_tracker; /* First MSIX vector used by SR-IOV VFs. Calculated by subtracting the * number of MSIX vectors needed for all SR-IOV VFs from the number of * MSIX vectors allowed on this PF. diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c index ca1a1de26766..1713347c577f 100644 --- a/drivers/net/ethernet/intel/ice/ice_irq.c +++ b/drivers/net/ethernet/intel/ice/ice_irq.c @@ -5,6 +5,75 @@ #include "ice_lib.h" #include "ice_irq.h" +/** + * ice_init_irq_tracker - initialize interrupt tracker + * @pf: board private structure + * @max_vectors: maximum number of vectors that tracker can hold + */ +static void +ice_init_irq_tracker(struct ice_pf *pf, unsigned int max_vectors) +{ + pf->irq_tracker.num_entries = max_vectors; + xa_init_flags(&pf->irq_tracker.entries, XA_FLAGS_ALLOC); +} + +/** + * ice_deinit_irq_tracker - free xarray tracker + * @pf: board private structure + */ +static void ice_deinit_irq_tracker(struct ice_pf *pf) +{ + xa_destroy(&pf->irq_tracker.entries); +} + +/** + * ice_free_irq_res - free a block of resources + * @pf: board private structure + * @index: starting index previously returned by ice_get_res + */ +static void ice_free_irq_res(struct ice_pf *pf, u16 index) +{ + struct ice_irq_entry *entry; + + entry = xa_erase(&pf->irq_tracker.entries, index); + kfree(entry); +} + +/** + * ice_get_irq_res - get an interrupt resource + * @pf: board private structure + * + * Allocate new irq entry in the free slot of the tracker. Since xarray + * is used, always allocate new entry at the lowest possible index. Set + * proper allocation limit for maximum tracker entries. + * + * Returns allocated irq entry or NULL on failure. + */ +static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf) +{ + struct xa_limit limit = { .max = pf->irq_tracker.num_entries, + .min = 0 }; + struct ice_irq_entry *entry; + unsigned int index; + int ret; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return NULL; + + ret = xa_alloc(&pf->irq_tracker.entries, &index, entry, limit, + GFP_KERNEL); + + if (ret) { + kfree(entry); + entry = NULL; + } else { + entry->index = index; + } + + return entry; +} + /** * ice_reduce_msix_usage - Reduce usage of MSI-X vectors * @pf: board private structure @@ -163,11 +232,7 @@ exit_err: void ice_clear_interrupt_scheme(struct ice_pf *pf) { pci_free_irq_vectors(pf->pdev); - - if (pf->irq_tracker) { - devm_kfree(ice_pf_to_dev(pf), pf->irq_tracker); - pf->irq_tracker = NULL; - } + ice_deinit_irq_tracker(pf); } /** @@ -183,19 +248,7 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) if (vectors < 0) return vectors; - /* set up vector assignment tracking */ - pf->irq_tracker = devm_kzalloc(ice_pf_to_dev(pf), - struct_size(pf->irq_tracker, list, - vectors), - GFP_KERNEL); - if (!pf->irq_tracker) { - pci_free_irq_vectors(pf->pdev); - return -ENOMEM; - } - - /* populate SW interrupts pool with number of OS granted IRQs. */ - pf->irq_tracker->num_entries = (u16)vectors; - pf->irq_tracker->end = pf->irq_tracker->num_entries; + ice_init_irq_tracker(pf, vectors); return 0; } @@ -221,13 +274,13 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) struct msi_map ice_alloc_irq(struct ice_pf *pf) { struct msi_map map = { .index = -ENOENT }; - int entry; + struct ice_irq_entry *entry; - entry = ice_get_res(pf, pf->irq_tracker); - if (entry < 0) + entry = ice_get_irq_res(pf); + if (!entry) return map; - map.index = entry; + map.index = entry->index; map.virq = pci_irq_vector(pf->pdev, map.index); return map; @@ -238,9 +291,9 @@ struct msi_map ice_alloc_irq(struct ice_pf *pf) * @pf: board private structure * @map: map with interrupt details * - * Remove allocated interrupt from the interrupt tracker + * Remove allocated interrupt from the interrupt tracker. */ void ice_free_irq(struct ice_pf *pf, struct msi_map map) { - ice_free_res(pf->irq_tracker, map.index); + ice_free_irq_res(pf, map.index); } diff --git a/drivers/net/ethernet/intel/ice/ice_irq.h b/drivers/net/ethernet/intel/ice/ice_irq.h index 26e80dfe22b5..da5cdb1f0d3a 100644 --- a/drivers/net/ethernet/intel/ice/ice_irq.h +++ b/drivers/net/ethernet/intel/ice/ice_irq.h @@ -4,6 +4,15 @@ #ifndef _ICE_IRQ_H_ #define _ICE_IRQ_H_ +struct ice_irq_entry { + unsigned int index; +}; + +struct ice_irq_tracker { + struct xarray entries; + u16 num_entries; /* total vectors available */ +}; + int ice_init_interrupt_scheme(struct ice_pf *pf); void ice_clear_interrupt_scheme(struct ice_pf *pf); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index fe908cf6da6a..387bb9cbafbe 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1370,51 +1370,6 @@ out: return ret; } -/** - * ice_free_res - free a block of resources - * @res: pointer to the resource - * @index: starting index previously returned by ice_get_res - * - * Returns number of resources freed - */ -int ice_free_res(struct ice_res_tracker *res, u16 index) -{ - if (!res || index >= res->end) - return -EINVAL; - - res->list[index] = 0; - - return 0; -} - -/** - * ice_get_res - get a resource from the tracker - * @pf: board private structure - * @res: pointer to the resource - * - * Returns the item index, or negative for error - */ -int -ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res) -{ - u16 i; - - if (!res || !pf) - return -EINVAL; - - /* skip already allocated entries */ - for (i = 0; i < res->end; i++) - if (!(res->list[i] & ICE_RES_VALID_BIT)) - break; - - if (i < res->end) { - res->list[i] = ICE_RES_VALID_BIT; - return i; - } else { - return -ENOMEM; - } -} - /** * ice_vsi_clear_rings - Deallocates the Tx and Rx rings for VSI * @vsi: the VSI having rings deallocated diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 2f52f9e32858..e985766e6bb5 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -104,11 +104,6 @@ int ice_ena_vsi(struct ice_vsi *vsi, bool locked); void ice_vsi_decfg(struct ice_vsi *vsi); void ice_dis_vsi(struct ice_vsi *vsi, bool locked); -int ice_free_res(struct ice_res_tracker *res, u16 index); - -int -ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res); - int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags); int ice_vsi_cfg(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params); diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 0fc2b26a2fa6..195105ce9039 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -418,7 +418,7 @@ int ice_calc_vf_reg_idx(struct ice_vf *vf, struct ice_q_vector *q_vector) static int ice_sriov_set_msix_res(struct ice_pf *pf, u16 num_msix_needed) { u16 total_vectors = pf->hw.func_caps.common_cap.num_msix_vectors; - int vectors_used = pf->irq_tracker->num_entries; + int vectors_used = pf->irq_tracker.num_entries; int sriov_base_vector; sriov_base_vector = total_vectors - num_msix_needed; @@ -470,7 +470,7 @@ static int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs) /* determine MSI-X resources per VF */ msix_avail_for_sriov = pf->hw.func_caps.common_cap.num_msix_vectors - - pf->irq_tracker->num_entries; + pf->irq_tracker.num_entries; msix_avail_per_vf = msix_avail_for_sriov / num_vfs; if (msix_avail_per_vf >= ICE_NUM_VF_MSIX_MED) { num_msix_per_vf = ICE_NUM_VF_MSIX_MED; -- cgit v1.2.3 From 011670cc340cbc1131677fe233b1a52acee969ee Mon Sep 17 00:00:00 2001 From: Piotr Raczynski Date: Mon, 15 May 2023 21:03:19 +0200 Subject: ice: add dynamic interrupt allocation Currently driver can only allocate interrupt vectors during init phase by calling pci_alloc_irq_vectors. Change that and make use of new pci_msix_alloc_irq_at/pci_msix_free_irq API and enable to allocate and free more interrupts after MSIX has been enabled. Since not all platforms supports dynamic allocation, check it with pci_msix_can_alloc_dyn. Extend the tracker to keep track how many interrupts are allocated initially so when all such vectors are already used, additional interrupts are automatically allocated dynamically. Remember each interrupt allocation method to then free appropriately. Since some features may require interrupts allocated dynamically add appropriate VSI flag and take it into account when allocating new interrupt. Reviewed-by: Michal Swiatkowski Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Piotr Raczynski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 3 + drivers/net/ethernet/intel/ice/ice_base.c | 2 +- drivers/net/ethernet/intel/ice/ice_idc.c | 2 +- drivers/net/ethernet/intel/ice/ice_irq.c | 109 +++++++++++++++++++++++++---- drivers/net/ethernet/intel/ice/ice_irq.h | 5 +- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- drivers/net/ethernet/intel/ice/ice_sriov.c | 5 +- 7 files changed, 107 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 8541d986ec7f..d637032c8139 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -338,6 +338,9 @@ struct ice_vsi { u32 rx_buf_failed; u32 rx_page_failed; u16 num_q_vectors; + /* tell if only dynamic irq allocation is allowed */ + bool irq_dyn_alloc; + enum ice_vsi_type type; u16 vsi_num; /* HW (absolute) index of this VSI */ u16 idx; /* software index in pf->vsi[] */ diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index cb0913cb9741..4a12316f7b46 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -137,7 +137,7 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx) } } - q_vector->irq = ice_alloc_irq(pf); + q_vector->irq = ice_alloc_irq(pf, vsi->irq_dyn_alloc); if (q_vector->irq.index < 0) { err = -ENOMEM; goto err_free_q_vector; diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c index bc016bb4440c..145b27f2a4ce 100644 --- a/drivers/net/ethernet/intel/ice/ice_idc.c +++ b/drivers/net/ethernet/intel/ice/ice_idc.c @@ -250,7 +250,7 @@ static int ice_alloc_rdma_qvectors(struct ice_pf *pf) struct msix_entry *entry = &pf->msix_entries[i]; struct msi_map map; - map = ice_alloc_irq(pf); + map = ice_alloc_irq(pf, false); if (map.index < 0) break; diff --git a/drivers/net/ethernet/intel/ice/ice_irq.c b/drivers/net/ethernet/intel/ice/ice_irq.c index 1713347c577f..ad82ff7d1995 100644 --- a/drivers/net/ethernet/intel/ice/ice_irq.c +++ b/drivers/net/ethernet/intel/ice/ice_irq.c @@ -9,11 +9,14 @@ * ice_init_irq_tracker - initialize interrupt tracker * @pf: board private structure * @max_vectors: maximum number of vectors that tracker can hold + * @num_static: number of preallocated interrupts */ static void -ice_init_irq_tracker(struct ice_pf *pf, unsigned int max_vectors) +ice_init_irq_tracker(struct ice_pf *pf, unsigned int max_vectors, + unsigned int num_static) { pf->irq_tracker.num_entries = max_vectors; + pf->irq_tracker.num_static = num_static; xa_init_flags(&pf->irq_tracker.entries, XA_FLAGS_ALLOC); } @@ -42,6 +45,7 @@ static void ice_free_irq_res(struct ice_pf *pf, u16 index) /** * ice_get_irq_res - get an interrupt resource * @pf: board private structure + * @dyn_only: force entry to be dynamically allocated * * Allocate new irq entry in the free slot of the tracker. Since xarray * is used, always allocate new entry at the lowest possible index. Set @@ -49,10 +53,11 @@ static void ice_free_irq_res(struct ice_pf *pf, u16 index) * * Returns allocated irq entry or NULL on failure. */ -static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf) +static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf, bool dyn_only) { struct xa_limit limit = { .max = pf->irq_tracker.num_entries, .min = 0 }; + unsigned int num_static = pf->irq_tracker.num_static; struct ice_irq_entry *entry; unsigned int index; int ret; @@ -61,6 +66,10 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf) if (!entry) return NULL; + /* skip preallocated entries if the caller says so */ + if (dyn_only) + limit.min = num_static; + ret = xa_alloc(&pf->irq_tracker.entries, &index, entry, limit, GFP_KERNEL); @@ -69,6 +78,7 @@ static struct ice_irq_entry *ice_get_irq_res(struct ice_pf *pf) entry = NULL; } else { entry->index = index; + entry->dynamic = index >= num_static; } return entry; @@ -241,14 +251,20 @@ void ice_clear_interrupt_scheme(struct ice_pf *pf) */ int ice_init_interrupt_scheme(struct ice_pf *pf) { - int vectors; + int total_vectors = pf->hw.func_caps.common_cap.num_msix_vectors; + int vectors, max_vectors; vectors = ice_ena_msix_range(pf); if (vectors < 0) - return vectors; + return -ENOMEM; + + if (pci_msix_can_alloc_dyn(pf->pdev)) + max_vectors = total_vectors; + else + max_vectors = vectors; - ice_init_irq_tracker(pf, vectors); + ice_init_irq_tracker(pf, max_vectors, vectors); return 0; } @@ -256,33 +272,55 @@ int ice_init_interrupt_scheme(struct ice_pf *pf) /** * ice_alloc_irq - Allocate new interrupt vector * @pf: board private structure + * @dyn_only: force dynamic allocation of the interrupt * * Allocate new interrupt vector for a given owner id. * return struct msi_map with interrupt details and track * allocated interrupt appropriately. * - * This function mimics individual interrupt allocation, - * even interrupts are actually already allocated with - * pci_alloc_irq_vectors. Individual allocation helps - * to track interrupts and simplifies interrupt related - * handling. + * This function reserves new irq entry from the irq_tracker. + * if according to the tracker information all interrupts that + * were allocated with ice_pci_alloc_irq_vectors are already used + * and dynamically allocated interrupts are supported then new + * interrupt will be allocated with pci_msix_alloc_irq_at. + * + * Some callers may only support dynamically allocated interrupts. + * This is indicated with dyn_only flag. * * On failure, return map with negative .index. The caller * is expected to check returned map index. * */ -struct msi_map ice_alloc_irq(struct ice_pf *pf) +struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_only) { + int sriov_base_vector = pf->sriov_base_vector; struct msi_map map = { .index = -ENOENT }; + struct device *dev = ice_pf_to_dev(pf); struct ice_irq_entry *entry; - entry = ice_get_irq_res(pf); + entry = ice_get_irq_res(pf, dyn_only); if (!entry) return map; - map.index = entry->index; - map.virq = pci_irq_vector(pf->pdev, map.index); + /* fail if we're about to violate SRIOV vectors space */ + if (sriov_base_vector && entry->index >= sriov_base_vector) + goto exit_free_res; + + if (pci_msix_can_alloc_dyn(pf->pdev) && entry->dynamic) { + map = pci_msix_alloc_irq_at(pf->pdev, entry->index, NULL); + if (map.index < 0) + goto exit_free_res; + dev_dbg(dev, "allocated new irq at index %d\n", map.index); + } else { + map.index = entry->index; + map.virq = pci_irq_vector(pf->pdev, map.index); + } + + return map; +exit_free_res: + dev_err(dev, "Could not allocate irq at idx %d\n", entry->index); + ice_free_irq_res(pf, entry->index); return map; } @@ -291,9 +329,50 @@ struct msi_map ice_alloc_irq(struct ice_pf *pf) * @pf: board private structure * @map: map with interrupt details * - * Remove allocated interrupt from the interrupt tracker. + * Remove allocated interrupt from the interrupt tracker. If interrupt was + * allocated dynamically, free respective interrupt vector. */ void ice_free_irq(struct ice_pf *pf, struct msi_map map) { + struct ice_irq_entry *entry; + + entry = xa_load(&pf->irq_tracker.entries, map.index); + + if (!entry) { + dev_err(ice_pf_to_dev(pf), "Failed to get MSIX interrupt entry at index %d", + map.index); + return; + } + + dev_dbg(ice_pf_to_dev(pf), "Free irq at index %d\n", map.index); + + if (entry->dynamic) + pci_msix_free_irq(pf->pdev, map); + ice_free_irq_res(pf, map.index); } + +/** + * ice_get_max_used_msix_vector - Get the max used interrupt vector + * @pf: board private structure + * + * Return index of maximum used interrupt vectors with respect to the + * beginning of the MSIX table. Take into account that some interrupts + * may have been dynamically allocated after MSIX was initially enabled. + */ +int ice_get_max_used_msix_vector(struct ice_pf *pf) +{ + unsigned long start, index, max_idx; + void *entry; + + /* Treat all preallocated interrupts as used */ + start = pf->irq_tracker.num_static; + max_idx = start - 1; + + xa_for_each_start(&pf->irq_tracker.entries, index, entry, start) { + if (index > max_idx) + max_idx = index; + } + + return max_idx; +} diff --git a/drivers/net/ethernet/intel/ice/ice_irq.h b/drivers/net/ethernet/intel/ice/ice_irq.h index da5cdb1f0d3a..f35efc08575e 100644 --- a/drivers/net/ethernet/intel/ice/ice_irq.h +++ b/drivers/net/ethernet/intel/ice/ice_irq.h @@ -6,17 +6,20 @@ struct ice_irq_entry { unsigned int index; + bool dynamic; /* allocation type flag */ }; struct ice_irq_tracker { struct xarray entries; u16 num_entries; /* total vectors available */ + u16 num_static; /* preallocated entries */ }; int ice_init_interrupt_scheme(struct ice_pf *pf); void ice_clear_interrupt_scheme(struct ice_pf *pf); -struct msi_map ice_alloc_irq(struct ice_pf *pf); +struct msi_map ice_alloc_irq(struct ice_pf *pf, bool dyn_only); void ice_free_irq(struct ice_pf *pf, struct msi_map map); +int ice_get_max_used_msix_vector(struct ice_pf *pf); #endif diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index efc621c0bd6c..62e91512aeab 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3305,7 +3305,7 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) goto skip_req_irq; /* reserve one vector in irq_tracker for misc interrupts */ - oicr_irq = ice_alloc_irq(pf); + oicr_irq = ice_alloc_irq(pf, false); if (oicr_irq.index < 0) return oicr_irq.index; diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 195105ce9039..80c643fb9f2f 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -418,7 +418,7 @@ int ice_calc_vf_reg_idx(struct ice_vf *vf, struct ice_q_vector *q_vector) static int ice_sriov_set_msix_res(struct ice_pf *pf, u16 num_msix_needed) { u16 total_vectors = pf->hw.func_caps.common_cap.num_msix_vectors; - int vectors_used = pf->irq_tracker.num_entries; + int vectors_used = ice_get_max_used_msix_vector(pf); int sriov_base_vector; sriov_base_vector = total_vectors - num_msix_needed; @@ -458,6 +458,7 @@ static int ice_sriov_set_msix_res(struct ice_pf *pf, u16 num_msix_needed) */ static int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs) { + int vectors_used = ice_get_max_used_msix_vector(pf); u16 num_msix_per_vf, num_txq, num_rxq, avail_qs; int msix_avail_per_vf, msix_avail_for_sriov; struct device *dev = ice_pf_to_dev(pf); @@ -470,7 +471,7 @@ static int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs) /* determine MSI-X resources per VF */ msix_avail_for_sriov = pf->hw.func_caps.common_cap.num_msix_vectors - - pf->irq_tracker.num_entries; + vectors_used; msix_avail_per_vf = msix_avail_for_sriov / num_vfs; if (msix_avail_per_vf >= ICE_NUM_VF_MSIX_MED) { num_msix_per_vf = ICE_NUM_VF_MSIX_MED; -- cgit v1.2.3 From e7480a44d7c4ce4691fa6bcdb0318f0d81fe4b12 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 16 May 2023 20:41:12 -0700 Subject: Revert "net: Remove low_thresh in ip defrag" This reverts commit b2cbac9b9b28730e9e53be20b6cdf979d3b9f27e. We have multiple reports of obvious breakage from this patch. Reported-by: Ido Schimmel Link: https://lore.kernel.org/all/ZGIRWjNcfqI8yY8W@shredder/ Link: https://lore.kernel.org/all/CADJHv_sDK=0RrMA2FTZQV5fw7UQ+qY=HG21Wu5qb0V9vvx5w6A@mail.gmail.com/ Reported-by: syzbot+a5e719ac7c268e414c95@syzkaller.appspotmail.com Reported-by: syzbot+a03fd670838d927d9cd8@syzkaller.appspotmail.com Fixes: b2cbac9b9b28 ("net: Remove low_thresh in ip defrag") Link: https://lore.kernel.org/r/20230517034112.1261835-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/networking/nf_conntrack-sysctl.rst | 1 - include/net/inet_frag.h | 1 + net/ieee802154/6lowpan/reassembly.c | 9 +++++---- net/ipv4/ip_fragment.c | 13 ++++++++----- net/ipv6/netfilter/nf_conntrack_reasm.c | 9 +++++---- net/ipv6/reassembly.c | 9 +++++---- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Documentation/networking/nf_conntrack-sysctl.rst b/Documentation/networking/nf_conntrack-sysctl.rst index 9ca356bc7217..8b1045c3b59e 100644 --- a/Documentation/networking/nf_conntrack-sysctl.rst +++ b/Documentation/networking/nf_conntrack-sysctl.rst @@ -55,7 +55,6 @@ nf_conntrack_frag6_high_thresh - INTEGER nf_conntrack_frag6_low_thresh is reached. nf_conntrack_frag6_low_thresh - INTEGER - (Obsolete since linux-4.17) default 196608 See nf_conntrack_frag6_low_thresh diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 8543e740891a..325ad893f624 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -13,6 +13,7 @@ struct fqdir { /* sysctls */ long high_thresh; + long low_thresh; int timeout; int max_dist; struct inet_frags *f; diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c index 3ba4c0f27af9..a91283d1e5bf 100644 --- a/net/ieee802154/6lowpan/reassembly.c +++ b/net/ieee802154/6lowpan/reassembly.c @@ -318,7 +318,7 @@ err: } #ifdef CONFIG_SYSCTL -static unsigned long lowpanfrag_low_thresh_unuesd = IPV6_FRAG_LOW_THRESH; + static struct ctl_table lowpan_frags_ns_ctl_table[] = { { .procname = "6lowpanfrag_high_thresh", @@ -374,9 +374,9 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net) } table[0].data = &ieee802154_lowpan->fqdir->high_thresh; - table[0].extra1 = &lowpanfrag_low_thresh_unuesd; - table[1].data = &lowpanfrag_low_thresh_unuesd; - table[1].extra2 = &ieee802154_lowpan->fqdir->high_thresh; + table[0].extra1 = &ieee802154_lowpan->fqdir->low_thresh; + table[1].data = &ieee802154_lowpan->fqdir->low_thresh; + table[1].extra2 = &ieee802154_lowpan->fqdir->high_thresh; table[2].data = &ieee802154_lowpan->fqdir->timeout; hdr = register_net_sysctl(net, "net/ieee802154/6lowpan", table); @@ -451,6 +451,7 @@ static int __net_init lowpan_frags_init_net(struct net *net) return res; ieee802154_lowpan->fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH; + ieee802154_lowpan->fqdir->low_thresh = IPV6_FRAG_LOW_THRESH; ieee802154_lowpan->fqdir->timeout = IPV6_FRAG_TIMEOUT; res = lowpan_frags_ns_sysctl_register(net); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 0db5eb3dec83..69c00ffdcf3e 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -553,7 +553,7 @@ EXPORT_SYMBOL(ip_check_defrag); #ifdef CONFIG_SYSCTL static int dist_min; -static unsigned long ipfrag_low_thresh_unused; + static struct ctl_table ip4_frags_ns_ctl_table[] = { { .procname = "ipfrag_high_thresh", @@ -609,9 +609,9 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net) } table[0].data = &net->ipv4.fqdir->high_thresh; - table[0].extra1 = &ipfrag_low_thresh_unused; - table[1].data = &ipfrag_low_thresh_unused; - table[1].extra2 = &net->ipv4.fqdir->high_thresh; + table[0].extra1 = &net->ipv4.fqdir->low_thresh; + table[1].data = &net->ipv4.fqdir->low_thresh; + table[1].extra2 = &net->ipv4.fqdir->high_thresh; table[2].data = &net->ipv4.fqdir->timeout; table[3].data = &net->ipv4.fqdir->max_dist; @@ -674,9 +674,12 @@ static int __net_init ipv4_frags_init_net(struct net *net) * A 64K fragment consumes 129736 bytes (44*2944)+200 * (1500 truesize == 2944, sizeof(struct ipq) == 200) * - * We will commit 4MB at one time. Should we cross that limit. + * We will commit 4MB at one time. Should we cross that limit + * we will prune down to 3MB, making room for approx 8 big 64K + * fragments 8x128k. */ net->ipv4.fqdir->high_thresh = 4 * 1024 * 1024; + net->ipv4.fqdir->low_thresh = 3 * 1024 * 1024; /* * Important NOTE! Fragment queue must be destroyed before MSL expires. * RFC791 is wrong proposing to prolongate timer each fragment arrival diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index dc8a2854e7f3..d13240f13607 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -42,7 +42,7 @@ static struct nft_ct_frag6_pernet *nf_frag_pernet(struct net *net) } #ifdef CONFIG_SYSCTL -static unsigned long nf_conntrack_frag6_low_thresh_unused = IPV6_FRAG_LOW_THRESH; + static struct ctl_table nf_ct_frag6_sysctl_table[] = { { .procname = "nf_conntrack_frag6_timeout", @@ -82,10 +82,10 @@ static int nf_ct_frag6_sysctl_register(struct net *net) nf_frag = nf_frag_pernet(net); table[0].data = &nf_frag->fqdir->timeout; - table[1].data = &nf_conntrack_frag6_low_thresh_unused; - table[1].extra2 = &nf_frag->fqdir->high_thresh; + table[1].data = &nf_frag->fqdir->low_thresh; + table[1].extra2 = &nf_frag->fqdir->high_thresh; table[2].data = &nf_frag->fqdir->high_thresh; - table[2].extra1 = &nf_conntrack_frag6_low_thresh_unused; + table[2].extra1 = &nf_frag->fqdir->low_thresh; hdr = register_net_sysctl(net, "net/netfilter", table); if (hdr == NULL) @@ -500,6 +500,7 @@ static int nf_ct_net_init(struct net *net) return res; nf_frag->fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH; + nf_frag->fqdir->low_thresh = IPV6_FRAG_LOW_THRESH; nf_frag->fqdir->timeout = IPV6_FRAG_TIMEOUT; res = nf_ct_frag6_sysctl_register(net); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index eb8373c25675..5bc8a28e67f9 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -416,7 +416,7 @@ static const struct inet6_protocol frag_protocol = { }; #ifdef CONFIG_SYSCTL -static unsigned long ip6_frags_low_thresh_unused = IPV6_FRAG_LOW_THRESH; + static struct ctl_table ip6_frags_ns_ctl_table[] = { { .procname = "ip6frag_high_thresh", @@ -465,9 +465,9 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net) } table[0].data = &net->ipv6.fqdir->high_thresh; - table[0].extra1 = &ip6_frags_low_thresh_unused; - table[1].data = &ip6_frags_low_thresh_unused; - table[1].extra2 = &net->ipv6.fqdir->high_thresh; + table[0].extra1 = &net->ipv6.fqdir->low_thresh; + table[1].data = &net->ipv6.fqdir->low_thresh; + table[1].extra2 = &net->ipv6.fqdir->high_thresh; table[2].data = &net->ipv6.fqdir->timeout; hdr = register_net_sysctl(net, "net/ipv6", table); @@ -536,6 +536,7 @@ static int __net_init ipv6_frags_init_net(struct net *net) return res; net->ipv6.fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH; + net->ipv6.fqdir->low_thresh = IPV6_FRAG_LOW_THRESH; net->ipv6.fqdir->timeout = IPV6_FRAG_TIMEOUT; res = ip6_frags_ns_sysctl_register(net); -- cgit v1.2.3 From 24a86d833bc5509ad34343dd6c649ea11ed1cad3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 15 May 2023 13:48:33 -0700 Subject: selftests/bpf: improve netcnt test robustness Change netcnt to demand at least 10K packets, as we frequently see some stray packet arriving during the test in BPF CI. It seems more important to make sure we haven't lost any packet than enforcing exact number of packets. Cc: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230515204833.2832000-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/netcnt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/netcnt.c b/tools/testing/selftests/bpf/prog_tests/netcnt.c index d3915c58d0e1..c3333edd029f 100644 --- a/tools/testing/selftests/bpf/prog_tests/netcnt.c +++ b/tools/testing/selftests/bpf/prog_tests/netcnt.c @@ -67,12 +67,12 @@ void serial_test_netcnt(void) } /* No packets should be lost */ - ASSERT_EQ(packets, 10000, "packets"); + ASSERT_GE(packets, 10000, "packets"); /* Let's check that bytes counter matches the number of packets * multiplied by the size of ipv6 ICMP packet. */ - ASSERT_EQ(bytes, packets * 104, "bytes"); + ASSERT_GE(bytes, packets * 104, "bytes"); err: if (cg_fd != -1) -- cgit v1.2.3 From de58ef414d8d7a0a635cd331b3b013d8216c4e60 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 16 May 2023 14:49:45 -0700 Subject: selftests/bpf: Fix s390 sock_field test failure llvm patch [1] enabled cross-function optimization for func arguments (ArgumentPromotion) at -O2 level. And this caused s390 sock_fields test failure ([2]). The failure is gone right now as patch [1] was reverted in [3]. But it is possible that patch [3] will be reverted again and then the test failure in [2] will show up again. So it is desirable to fix the failure regardless. The following is an analysis why sock_field test fails with llvm patch [1]. The main problem is in static __noinline bool sk_dst_port__load_word(struct bpf_sock *sk) { __u32 *word = (__u32 *)&sk->dst_port; return word[0] == bpf_htons(0xcafe); } static __noinline bool sk_dst_port__load_half(struct bpf_sock *sk) { __u16 *half = (__u16 *)&sk->dst_port; return half[0] == bpf_htons(0xcafe); } ... int read_sk_dst_port(struct __sk_buff *skb) { ... sk = skb->sk; ... if (!sk_dst_port__load_word(sk)) RET_LOG(); if (!sk_dst_port__load_half(sk)) RET_LOG(); ... } Through some cross-function optimization by ArgumentPromotion optimization, the compiler does: static __noinline bool sk_dst_port__load_word(__u32 word_val) { return word_val == bpf_htons(0xcafe); } static __noinline bool sk_dst_port__load_half(__u16 half_val) { return half_val == bpf_htons(0xcafe); } ... int read_sk_dst_port(struct __sk_buff *skb) { ... sk = skb->sk; ... __u32 *word = (__u32 *)&sk->dst_port; __u32 word_val = word[0]; ... if (!sk_dst_port__load_word(word_val)) RET_LOG(); __u16 half_val = word_val >> 16; if (!sk_dst_port__load_half(half_val)) RET_LOG(); ... } In current uapi bpf.h, we have struct bpf_sock { ... __be16 dst_port; /* network byte order */ __u16 :16; /* zero padding */ ... }; But the old kernel (e.g., 5.6) we have struct bpf_sock { ... __u32 dst_port; /* network byte order */ ... }; So for backward compatability reason, 4-byte load of dst_port is converted to 2-byte load internally. Specifically, 'word_val = word[0]' is replaced by 2-byte load by the verifier and this caused the trouble for later sk_dst_port__load_half() where half_val becomes 0. Typical usr program won't have such a code pattern tiggering the above bug, so let us fix the test failure with source code change. Adding an empty asm volatile statement seems enough to prevent undesired transformation. [1] https://reviews.llvm.org/D148269 [2] https://lore.kernel.org/bpf/e7f2c5e8-a50c-198d-8f95-388165f1e4fd@meta.com/ [3] https://reviews.llvm.org/rG141be5c062ecf22bd287afffd310e8ac4711444a Tested-by: Ilya Leoshkevich Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20230516214945.1013578-1-yhs@fb.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/test_sock_fields.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/progs/test_sock_fields.c b/tools/testing/selftests/bpf/progs/test_sock_fields.c index bbad3c2d9aa5..f75e531bf36f 100644 --- a/tools/testing/selftests/bpf/progs/test_sock_fields.c +++ b/tools/testing/selftests/bpf/progs/test_sock_fields.c @@ -265,7 +265,10 @@ static __noinline bool sk_dst_port__load_word(struct bpf_sock *sk) static __noinline bool sk_dst_port__load_half(struct bpf_sock *sk) { - __u16 *half = (__u16 *)&sk->dst_port; + __u16 *half; + + asm volatile (""); + half = (__u16 *)&sk->dst_port; return half[0] == bpf_htons(0xcafe); } -- cgit v1.2.3 From 10cb8622b6958c2d47961d6a42c76e6c9f1c08f3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:47 +0200 Subject: libbpf: Store zero fd to fd_array for loader kfunc relocation When moving some of the test kfuncs to bpf_testmod I hit an issue when some of the kfuncs that object uses are in module and some in vmlinux. The problem is that both vmlinux and module kfuncs get allocated btf_fd_idx index into fd_array, but we store to it the BTF fd value only for module's kfunc, not vmlinux's one because (it's zero). Then after the program is loaded we check if fd_array[btf_fd_idx] != 0 and close the fd. When the object has kfuncs from both vmlinux and module, the fd from fd_array[btf_fd_idx] from previous load will be stored in there for vmlinux's kfunc, so we close unrelated fd (of the program we just loaded in my case). Fixing this by storing zero to fd_array[btf_fd_idx] for vmlinux kfuncs, so the we won't close stale fd. Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-2-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/gen_loader.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c index 83e8e3bfd8ff..cf3323fd47b8 100644 --- a/tools/lib/bpf/gen_loader.c +++ b/tools/lib/bpf/gen_loader.c @@ -703,17 +703,17 @@ static void emit_relo_kfunc_btf(struct bpf_gen *gen, struct ksym_relo_desc *relo /* obtain fd in BPF_REG_9 */ emit(gen, BPF_MOV64_REG(BPF_REG_9, BPF_REG_7)); emit(gen, BPF_ALU64_IMM(BPF_RSH, BPF_REG_9, 32)); - /* jump to fd_array store if fd denotes module BTF */ - emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2)); - /* set the default value for off */ - emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0)); - /* skip BTF fd store for vmlinux BTF */ - emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 4)); /* load fd_array slot pointer */ emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE, 0, 0, 0, blob_fd_array_off(gen, btf_fd_idx))); - /* store BTF fd in slot */ + /* store BTF fd in slot, 0 for vmlinux */ emit(gen, BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_9, 0)); + /* jump to insn[insn_idx].off store if fd denotes module BTF */ + emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_9, 0, 2)); + /* set the default value for off */ + emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), 0)); + /* skip BTF fd store for vmlinux BTF */ + emit(gen, BPF_JMP_IMM(BPF_JA, 0, 0, 1)); /* store index into insn[insn_idx].off */ emit(gen, BPF_ST_MEM(BPF_H, BPF_REG_8, offsetof(struct bpf_insn, off), btf_fd_idx)); log: -- cgit v1.2.3 From 8e9af82171247e2a8d2c08a3dea709d03884a815 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:48 +0200 Subject: selftests/bpf: Move kfunc exports to bpf_testmod/bpf_testmod_kfunc.h Move all kfunc exports into separate bpf_testmod_kfunc.h header file and include it in tests that need it. We will move all test kfuncs into bpf_testmod in following change, so it's convenient to have declarations in single place. The bpf_testmod_kfunc.h is included by both bpf_testmod and bpf programs that use test kfuncs. As suggested by David, the bpf_testmod_kfunc.h includes vmlinux.h and bpf/bpf_helpers.h for bpf programs build, so the declarations have proper __ksym attribute and we can resolve all the structs. Note in kfunc_call_test_subprog.c we can no longer use the sk_state define from bpf_tcp_helpers.h (because it clashed with vmlinux.h) and we need to address __sk_common.skc_state field directly. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-3-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h | 40 ++++++++++++++++++++++ tools/testing/selftests/bpf/progs/cb_refs.c | 4 +-- tools/testing/selftests/bpf/progs/jit_probe_mem.c | 4 +-- .../selftests/bpf/progs/kfunc_call_destructive.c | 3 +- .../testing/selftests/bpf/progs/kfunc_call_fail.c | 9 +---- .../testing/selftests/bpf/progs/kfunc_call_race.c | 3 +- .../testing/selftests/bpf/progs/kfunc_call_test.c | 17 +-------- .../selftests/bpf/progs/kfunc_call_test_subprog.c | 9 ++--- .../testing/selftests/bpf/progs/local_kptr_stash.c | 5 ++- tools/testing/selftests/bpf/progs/map_kptr.c | 5 +-- tools/testing/selftests/bpf/progs/map_kptr_fail.c | 4 +-- 11 files changed, 52 insertions(+), 51 deletions(-) create mode 100644 tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h new file mode 100644 index 000000000000..f0755135061d --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _BPF_TESTMOD_KFUNC_H +#define _BPF_TESTMOD_KFUNC_H + +#ifndef __KERNEL__ +#include +#include +#else +#define __ksym +#endif + +extern struct prog_test_ref_kfunc * +bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym; +extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; +void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) __ksym; + +extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; +extern int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; +extern int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; +extern int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; +extern void bpf_kfunc_call_int_mem_release(int *p) __ksym; +extern u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; + +extern void bpf_testmod_test_mod_kfunc(int i) __ksym; + +extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, + __u32 c, __u64 d) __ksym; +extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; +extern struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym; +extern long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym; + +extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; +extern void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; +extern void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; +extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; + +extern void bpf_kfunc_call_test_destructive(void) __ksym; + +#endif /* _BPF_TESTMOD_KFUNC_H */ diff --git a/tools/testing/selftests/bpf/progs/cb_refs.c b/tools/testing/selftests/bpf/progs/cb_refs.c index 50f95ec61165..76d661b20e87 100644 --- a/tools/testing/selftests/bpf/progs/cb_refs.c +++ b/tools/testing/selftests/bpf/progs/cb_refs.c @@ -2,6 +2,7 @@ #include #include #include +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct map_value { struct prog_test_ref_kfunc __kptr *ptr; @@ -14,9 +15,6 @@ struct { __uint(max_entries, 16); } array_map SEC(".maps"); -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; - static __noinline int cb1(void *map, void *key, void *value, void *ctx) { void *p = *(void **)ctx; diff --git a/tools/testing/selftests/bpf/progs/jit_probe_mem.c b/tools/testing/selftests/bpf/progs/jit_probe_mem.c index 13f00ca2ed0a..f9789e668297 100644 --- a/tools/testing/selftests/bpf/progs/jit_probe_mem.c +++ b/tools/testing/selftests/bpf/progs/jit_probe_mem.c @@ -3,13 +3,11 @@ #include #include #include +#include "../bpf_testmod/bpf_testmod_kfunc.h" static struct prog_test_ref_kfunc __kptr *v; long total_sum = -1; -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; - SEC("tc") int test_jit_probe_mem(struct __sk_buff *ctx) { diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_destructive.c b/tools/testing/selftests/bpf/progs/kfunc_call_destructive.c index 767472bc5a97..7632d9ecb253 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_destructive.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_destructive.c @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include - -extern void bpf_kfunc_call_test_destructive(void) __ksym; +#include "../bpf_testmod/bpf_testmod_kfunc.h" SEC("tc") int kfunc_destructive_test(void) diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_fail.c b/tools/testing/selftests/bpf/progs/kfunc_call_fail.c index b98313d391c6..4b0b7b79cdfb 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_fail.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_fail.c @@ -2,14 +2,7 @@ /* Copyright (c) 2021 Facebook */ #include #include - -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; -extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; -extern int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; -extern int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern void bpf_kfunc_call_int_mem_release(int *p) __ksym; +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct syscall_test_args { __u8 data[16]; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_race.c b/tools/testing/selftests/bpf/progs/kfunc_call_race.c index 4e8fed75a4e0..d532af07decf 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_race.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_race.c @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include - -extern void bpf_testmod_test_mod_kfunc(int i) __ksym; +#include "../bpf_testmod/bpf_testmod_kfunc.h" SEC("tc") int kfunc_call_fail(struct __sk_buff *ctx) diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test.c b/tools/testing/selftests/bpf/progs/kfunc_call_test.c index 7daa8f5720b9..cf68d1e48a0f 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_test.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test.c @@ -2,22 +2,7 @@ /* Copyright (c) 2021 Facebook */ #include #include - -extern long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym; -extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; -extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, - __u32 c, __u64 d) __ksym; - -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; -extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; -extern void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; -extern void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; -extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; -extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; -extern int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; -extern int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; +#include "../bpf_testmod/bpf_testmod_kfunc.h" SEC("tc") int kfunc_call_test4(struct __sk_buff *skb) diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_subprog.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_subprog.c index c1fdecabeabf..2380c75e74ce 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_test_subprog.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_subprog.c @@ -1,13 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2021 Facebook */ -#include -#include -#include "bpf_tcp_helpers.h" +#include "../bpf_testmod/bpf_testmod_kfunc.h" extern const int bpf_prog_active __ksym; -extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, - __u32 c, __u64 d) __ksym; -extern struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym; int active_res = -1; int sk_state_res = -1; @@ -28,7 +23,7 @@ int __noinline f1(struct __sk_buff *skb) if (active) active_res = *active; - sk_state_res = bpf_kfunc_call_test3((struct sock *)sk)->sk_state; + sk_state_res = bpf_kfunc_call_test3((struct sock *)sk)->__sk_common.skc_state; return (__u32)bpf_kfunc_call_test1((struct sock *)sk, 1, 2, 3, 4); } diff --git a/tools/testing/selftests/bpf/progs/local_kptr_stash.c b/tools/testing/selftests/bpf/progs/local_kptr_stash.c index 0ef286da092b..06838083079c 100644 --- a/tools/testing/selftests/bpf/progs/local_kptr_stash.c +++ b/tools/testing/selftests/bpf/progs/local_kptr_stash.c @@ -5,7 +5,8 @@ #include #include #include -#include "bpf_experimental.h" +#include "../bpf_experimental.h" +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct node_data { long key; @@ -32,8 +33,6 @@ struct map_value { */ struct node_data *just_here_because_btf_bug; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; - struct { __uint(type, BPF_MAP_TYPE_ARRAY); __type(key, int); diff --git a/tools/testing/selftests/bpf/progs/map_kptr.c b/tools/testing/selftests/bpf/progs/map_kptr.c index d7150041e5d1..da30f0d59364 100644 --- a/tools/testing/selftests/bpf/progs/map_kptr.c +++ b/tools/testing/selftests/bpf/progs/map_kptr.c @@ -2,6 +2,7 @@ #include #include #include +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct map_value { struct prog_test_ref_kfunc __kptr_untrusted *unref_ptr; @@ -114,10 +115,6 @@ DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_map, hash_of_hash_maps); DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_malloc_map, hash_of_hash_malloc_maps); DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, lru_hash_map, hash_of_lru_hash_maps); -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; -void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) __ksym; - #define WRITE_ONCE(x, val) ((*(volatile typeof(x) *) &(x)) = (val)) static void test_kptr_unref(struct map_value *v) diff --git a/tools/testing/selftests/bpf/progs/map_kptr_fail.c b/tools/testing/selftests/bpf/progs/map_kptr_fail.c index da8c724f839b..450bb373b179 100644 --- a/tools/testing/selftests/bpf/progs/map_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/map_kptr_fail.c @@ -4,6 +4,7 @@ #include #include #include "bpf_misc.h" +#include "../bpf_testmod/bpf_testmod_kfunc.h" struct map_value { char buf[8]; @@ -19,9 +20,6 @@ struct array_map { __uint(max_entries, 1); } array_map SEC(".maps"); -extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; - SEC("?tc") __failure __msg("kptr access size must be BPF_DW") int size_not_bpf_dw(struct __sk_buff *ctx) -- cgit v1.2.3 From 45db310984bfea977177fb5fc0ea23ab430129bd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:49 +0200 Subject: selftests/bpf: Move test_progs helpers to testing_helpers object Moving test_progs helpers to testing_helpers object so they can be used from test_verifier in following changes. Also adding missing ifndef header guard to testing_helpers.h header. Using stderr instead of env.stderr because un/load_bpf_testmod helpers will be used outside test_progs. Also at the point of calling them in test_progs the std files are not hijacked yet and stderr is the same as env.stderr. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-4-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_progs.c | 67 +-------------------------- tools/testing/selftests/bpf/test_progs.h | 1 - tools/testing/selftests/bpf/testing_helpers.c | 63 +++++++++++++++++++++++++ tools/testing/selftests/bpf/testing_helpers.h | 9 ++++ 4 files changed, 74 insertions(+), 66 deletions(-) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 793689dcc170..cebe62d29f8d 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -11,7 +11,6 @@ #include #include #include /* backtrace */ -#include #include /* get_nprocs */ #include #include @@ -629,68 +628,6 @@ out: return err; } -static int finit_module(int fd, const char *param_values, int flags) -{ - return syscall(__NR_finit_module, fd, param_values, flags); -} - -static int delete_module(const char *name, int flags) -{ - return syscall(__NR_delete_module, name, flags); -} - -/* - * Trigger synchronize_rcu() in kernel. - */ -int kern_sync_rcu(void) -{ - return syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0, 0); -} - -static void unload_bpf_testmod(void) -{ - if (kern_sync_rcu()) - fprintf(env.stderr, "Failed to trigger kernel-side RCU sync!\n"); - if (delete_module("bpf_testmod", 0)) { - if (errno == ENOENT) { - if (verbose()) - fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); - return; - } - fprintf(env.stderr, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); - return; - } - if (verbose()) - fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n"); -} - -static int load_bpf_testmod(void) -{ - int fd; - - /* ensure previous instance of the module is unloaded */ - unload_bpf_testmod(); - - if (verbose()) - fprintf(stdout, "Loading bpf_testmod.ko...\n"); - - fd = open("bpf_testmod.ko", O_RDONLY); - if (fd < 0) { - fprintf(env.stderr, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); - return -ENOENT; - } - if (finit_module(fd, "", 0)) { - fprintf(env.stderr, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); - close(fd); - return -EINVAL; - } - close(fd); - - if (verbose()) - fprintf(stdout, "Successfully loaded bpf_testmod.ko.\n"); - return 0; -} - /* extern declarations for test funcs */ #define DEFINE_TEST(name) \ extern void test_##name(void) __weak; \ @@ -1720,7 +1657,7 @@ int main(int argc, char **argv) env.stderr = stderr; env.has_testmod = true; - if (!env.list_test_names && load_bpf_testmod()) { + if (!env.list_test_names && load_bpf_testmod(verbose())) { fprintf(env.stderr, "WARNING! Selftests relying on bpf_testmod.ko will be skipped.\n"); env.has_testmod = false; } @@ -1819,7 +1756,7 @@ int main(int argc, char **argv) close(env.saved_netns_fd); out: if (!env.list_test_names && env.has_testmod) - unload_bpf_testmod(); + unload_bpf_testmod(verbose()); free_test_selector(&env.test_selector); free_test_selector(&env.subtest_selector); diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index 0ed3134333d4..77bd492c6024 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -405,7 +405,6 @@ static inline void *u64_to_ptr(__u64 ptr) int bpf_find_map(const char *test, struct bpf_object *obj, const char *name); int compare_map_keys(int map1_fd, int map2_fd); int compare_stack_ips(int smap_fd, int amap_fd, int stack_trace_len); -int kern_sync_rcu(void); int trigger_module_test_read(int read_sz); int trigger_module_test_write(int write_sz); int write_sysctl(const char *sysctl, const char *value); diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index dc9595ade8de..648c7d3eb319 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -9,6 +9,7 @@ #include #include "test_progs.h" #include "testing_helpers.h" +#include int parse_num_list(const char *s, bool **num_set, int *num_set_len) { @@ -326,3 +327,65 @@ __u64 read_perf_max_sample_freq(void) fclose(f); return sample_freq; } + +static int finit_module(int fd, const char *param_values, int flags) +{ + return syscall(__NR_finit_module, fd, param_values, flags); +} + +static int delete_module(const char *name, int flags) +{ + return syscall(__NR_delete_module, name, flags); +} + +void unload_bpf_testmod(bool verbose) +{ + if (kern_sync_rcu()) + fprintf(stderr, "Failed to trigger kernel-side RCU sync!\n"); + if (delete_module("bpf_testmod", 0)) { + if (errno == ENOENT) { + if (verbose) + fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); + return; + } + fprintf(stderr, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); + return; + } + if (verbose) + fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n"); +} + +int load_bpf_testmod(bool verbose) +{ + int fd; + + /* ensure previous instance of the module is unloaded */ + unload_bpf_testmod(verbose); + + if (verbose) + fprintf(stdout, "Loading bpf_testmod.ko...\n"); + + fd = open("bpf_testmod.ko", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); + return -ENOENT; + } + if (finit_module(fd, "", 0)) { + fprintf(stderr, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); + close(fd); + return -EINVAL; + } + close(fd); + + if (verbose) + fprintf(stdout, "Successfully loaded bpf_testmod.ko.\n"); + return 0; +} + +/* + * Trigger synchronize_rcu() in kernel. + */ +int kern_sync_rcu(void) +{ + return syscall(__NR_membarrier, MEMBARRIER_CMD_SHARED, 0, 0); +} diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index 98f09bbae86f..02e8c4efd028 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -1,5 +1,9 @@ /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ /* Copyright (C) 2020 Facebook, Inc. */ + +#ifndef __TESTING_HELPERS_H +#define __TESTING_HELPERS_H + #include #include #include @@ -25,3 +29,8 @@ int parse_test_list_file(const char *path, bool is_glob_pattern); __u64 read_perf_max_sample_freq(void); +int load_bpf_testmod(bool verbose); +void unload_bpf_testmod(bool verbose); +int kern_sync_rcu(void); + +#endif /* __TESTING_HELPERS_H */ -- cgit v1.2.3 From d18decca69e36480247a73086336f4a44a08e36f Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:50 +0200 Subject: selftests/bpf: Use only stdout in un/load_bpf_testmod functions We are about to use un/load_bpf_testmod functions in couple tests and it's better to print output to stdout, so it's aligned with tests ASSERT macros output, which use stdout as well. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-5-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/testing_helpers.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index 648c7d3eb319..f73bc88f3eb6 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -341,14 +341,14 @@ static int delete_module(const char *name, int flags) void unload_bpf_testmod(bool verbose) { if (kern_sync_rcu()) - fprintf(stderr, "Failed to trigger kernel-side RCU sync!\n"); + fprintf(stdout, "Failed to trigger kernel-side RCU sync!\n"); if (delete_module("bpf_testmod", 0)) { if (errno == ENOENT) { if (verbose) fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); return; } - fprintf(stderr, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); + fprintf(stdout, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); return; } if (verbose) @@ -367,11 +367,11 @@ int load_bpf_testmod(bool verbose) fd = open("bpf_testmod.ko", O_RDONLY); if (fd < 0) { - fprintf(stderr, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); + fprintf(stdout, "Can't find bpf_testmod.ko kernel module: %d\n", -errno); return -ENOENT; } if (finit_module(fd, "", 0)) { - fprintf(stderr, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); + fprintf(stdout, "Failed to load bpf_testmod.ko into the kernel: %d\n", -errno); close(fd); return -EINVAL; } -- cgit v1.2.3 From b58f3f0e6f3cbea56be39d8fb190b37f049505bb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:51 +0200 Subject: selftests/bpf: Do not unload bpf_testmod in load_bpf_testmod Do not unload bpf_testmod in load_bpf_testmod, instead call unload_bpf_testmod separatelly. This way we will be able use un/load_bpf_testmod functions in other tests that un/load bpf_testmod module. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-6-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_progs.c | 11 ++++++++--- tools/testing/selftests/bpf/testing_helpers.c | 3 --- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index cebe62d29f8d..4d582cac2c09 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -1657,9 +1657,14 @@ int main(int argc, char **argv) env.stderr = stderr; env.has_testmod = true; - if (!env.list_test_names && load_bpf_testmod(verbose())) { - fprintf(env.stderr, "WARNING! Selftests relying on bpf_testmod.ko will be skipped.\n"); - env.has_testmod = false; + if (!env.list_test_names) { + /* ensure previous instance of the module is unloaded */ + unload_bpf_testmod(verbose()); + + if (load_bpf_testmod(verbose())) { + fprintf(env.stderr, "WARNING! Selftests relying on bpf_testmod.ko will be skipped.\n"); + env.has_testmod = false; + } } /* initializing tests */ diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index f73bc88f3eb6..e01d7a62306c 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -359,9 +359,6 @@ int load_bpf_testmod(bool verbose) { int fd; - /* ensure previous instance of the module is unloaded */ - unload_bpf_testmod(verbose); - if (verbose) fprintf(stdout, "Loading bpf_testmod.ko...\n"); -- cgit v1.2.3 From 11642eb92b3bc67171b23abff0d062758c5a4730 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:52 +0200 Subject: selftests/bpf: Use un/load_bpf_testmod functions in tests Now that we have un/load_bpf_testmod helpers in testing_helpers.h, we can use it in other tests and save some lines. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-7-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/prog_tests/bpf_mod_race.c | 34 ++++------------------ .../selftests/bpf/prog_tests/module_attach.c | 12 +++----- tools/testing/selftests/bpf/testing_helpers.c | 7 +++-- tools/testing/selftests/bpf/testing_helpers.h | 2 +- 4 files changed, 14 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c b/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c index a4d0cc9d3367..fe2c502e5089 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c @@ -11,6 +11,7 @@ #include "ksym_race.skel.h" #include "bpf_mod_race.skel.h" #include "kfunc_call_race.skel.h" +#include "testing_helpers.h" /* This test crafts a race between btf_try_get_module and do_init_module, and * checks whether btf_try_get_module handles the invocation for a well-formed @@ -44,35 +45,10 @@ enum bpf_test_state { static _Atomic enum bpf_test_state state = _TS_INVALID; -static int sys_finit_module(int fd, const char *param_values, int flags) -{ - return syscall(__NR_finit_module, fd, param_values, flags); -} - -static int sys_delete_module(const char *name, unsigned int flags) -{ - return syscall(__NR_delete_module, name, flags); -} - -static int load_module(const char *mod) -{ - int ret, fd; - - fd = open("bpf_testmod.ko", O_RDONLY); - if (fd < 0) - return fd; - - ret = sys_finit_module(fd, "", 0); - close(fd); - if (ret < 0) - return ret; - return 0; -} - static void *load_module_thread(void *p) { - if (!ASSERT_NEQ(load_module("bpf_testmod.ko"), 0, "load_module_thread must fail")) + if (!ASSERT_NEQ(load_bpf_testmod(false), 0, "load_module_thread must fail")) atomic_store(&state, TS_MODULE_LOAD); else atomic_store(&state, TS_MODULE_LOAD_FAIL); @@ -124,7 +100,7 @@ static void test_bpf_mod_race_config(const struct test_config *config) if (!ASSERT_NEQ(fault_addr, MAP_FAILED, "mmap for uffd registration")) return; - if (!ASSERT_OK(sys_delete_module("bpf_testmod", 0), "unload bpf_testmod")) + if (!ASSERT_OK(unload_bpf_testmod(false), "unload bpf_testmod")) goto end_mmap; skel = bpf_mod_race__open(); @@ -202,8 +178,8 @@ end_destroy: bpf_mod_race__destroy(skel); ASSERT_OK(kern_sync_rcu(), "kern_sync_rcu"); end_module: - sys_delete_module("bpf_testmod", 0); - ASSERT_OK(load_module("bpf_testmod.ko"), "restore bpf_testmod"); + unload_bpf_testmod(false); + ASSERT_OK(load_bpf_testmod(false), "restore bpf_testmod"); end_mmap: munmap(fault_addr, 4096); atomic_store(&state, _TS_INVALID); diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c b/tools/testing/selftests/bpf/prog_tests/module_attach.c index 7fc01ff490db..f53d658ed080 100644 --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c @@ -4,6 +4,7 @@ #include #include #include "test_module_attach.skel.h" +#include "testing_helpers.h" static int duration; @@ -32,11 +33,6 @@ static int trigger_module_test_writable(int *val) return 0; } -static int delete_module(const char *name, int flags) -{ - return syscall(__NR_delete_module, name, flags); -} - void test_module_attach(void) { const int READ_SZ = 456; @@ -93,21 +89,21 @@ void test_module_attach(void) if (!ASSERT_OK_PTR(link, "attach_fentry")) goto cleanup; - ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); bpf_link__destroy(link); link = bpf_program__attach(skel->progs.handle_fexit); if (!ASSERT_OK_PTR(link, "attach_fexit")) goto cleanup; - ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); bpf_link__destroy(link); link = bpf_program__attach(skel->progs.kprobe_multi); if (!ASSERT_OK_PTR(link, "attach_kprobe_multi")) goto cleanup; - ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + ASSERT_ERR(unload_bpf_testmod(false), "unload_bpf_testmod"); bpf_link__destroy(link); cleanup: diff --git a/tools/testing/selftests/bpf/testing_helpers.c b/tools/testing/selftests/bpf/testing_helpers.c index e01d7a62306c..8d994884c7b4 100644 --- a/tools/testing/selftests/bpf/testing_helpers.c +++ b/tools/testing/selftests/bpf/testing_helpers.c @@ -338,7 +338,7 @@ static int delete_module(const char *name, int flags) return syscall(__NR_delete_module, name, flags); } -void unload_bpf_testmod(bool verbose) +int unload_bpf_testmod(bool verbose) { if (kern_sync_rcu()) fprintf(stdout, "Failed to trigger kernel-side RCU sync!\n"); @@ -346,13 +346,14 @@ void unload_bpf_testmod(bool verbose) if (errno == ENOENT) { if (verbose) fprintf(stdout, "bpf_testmod.ko is already unloaded.\n"); - return; + return -1; } fprintf(stdout, "Failed to unload bpf_testmod.ko from kernel: %d\n", -errno); - return; + return -1; } if (verbose) fprintf(stdout, "Successfully unloaded bpf_testmod.ko.\n"); + return 0; } int load_bpf_testmod(bool verbose) diff --git a/tools/testing/selftests/bpf/testing_helpers.h b/tools/testing/selftests/bpf/testing_helpers.h index 02e8c4efd028..5312323881b6 100644 --- a/tools/testing/selftests/bpf/testing_helpers.h +++ b/tools/testing/selftests/bpf/testing_helpers.h @@ -30,7 +30,7 @@ int parse_test_list_file(const char *path, __u64 read_perf_max_sample_freq(void); int load_bpf_testmod(bool verbose); -void unload_bpf_testmod(bool verbose); +int unload_bpf_testmod(bool verbose); int kern_sync_rcu(void); #endif /* __TESTING_HELPERS_H */ -- cgit v1.2.3 From b23b385fa18f2196872bc3337c98ddd221c2827b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:53 +0200 Subject: selftests/bpf: Load bpf_testmod for verifier test Loading bpf_testmod kernel module for verifier test. We will move all the tests kfuncs into bpf_testmod in following change. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-8-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index e4657c5bc3f1..285ea4aba194 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -40,6 +40,7 @@ #include "bpf_util.h" #include "test_btf.h" #include "../../../include/linux/filter.h" +#include "testing_helpers.h" #ifndef ENOTSUPP #define ENOTSUPP 524 @@ -1684,6 +1685,12 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) { int i, passes = 0, errors = 0; + /* ensure previous instance of the module is unloaded */ + unload_bpf_testmod(verbose); + + if (load_bpf_testmod(verbose)) + return EXIT_FAILURE; + for (i = from; i < to; i++) { struct bpf_test *test = &tests[i]; @@ -1711,6 +1718,8 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) } } + unload_bpf_testmod(verbose); + printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes, skips, errors); return errors ? EXIT_FAILURE : EXIT_SUCCESS; -- cgit v1.2.3 From f26ebdd3e4e4e1f5f08522b087ab9ec7216e9a3b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:54 +0200 Subject: selftests/bpf: Allow to use kfunc from testmod.ko in test_verifier Currently the test_verifier allows test to specify kfunc symbol and search for it in the kernel BTF. Adding the possibility to search for kfunc also in bpf_testmod module when it's not found in kernel BTF. To find bpf_testmod btf we need to get back SYS_ADMIN cap. Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-9-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 161 ++++++++++++++++++++++++---- 1 file changed, 139 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 285ea4aba194..71704a38cac3 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -874,8 +874,140 @@ static int create_map_kptr(void) return fd; } +static void set_root(bool set) +{ + __u64 caps; + + if (set) { + if (cap_enable_effective(1ULL << CAP_SYS_ADMIN, &caps)) + perror("cap_disable_effective(CAP_SYS_ADMIN)"); + } else { + if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) + perror("cap_disable_effective(CAP_SYS_ADMIN)"); + } +} + +static __u64 ptr_to_u64(const void *ptr) +{ + return (uintptr_t) ptr; +} + +static struct btf *btf__load_testmod_btf(struct btf *vmlinux) +{ + struct bpf_btf_info info; + __u32 len = sizeof(info); + struct btf *btf = NULL; + char name[64]; + __u32 id = 0; + int err, fd; + + /* Iterate all loaded BTF objects and find bpf_testmod, + * we need SYS_ADMIN cap for that. + */ + set_root(true); + + while (true) { + err = bpf_btf_get_next_id(id, &id); + if (err) { + if (errno == ENOENT) + break; + perror("bpf_btf_get_next_id failed"); + break; + } + + fd = bpf_btf_get_fd_by_id(id); + if (fd < 0) { + if (errno == ENOENT) + continue; + perror("bpf_btf_get_fd_by_id failed"); + break; + } + + memset(&info, 0, sizeof(info)); + info.name_len = sizeof(name); + info.name = ptr_to_u64(name); + len = sizeof(info); + + err = bpf_obj_get_info_by_fd(fd, &info, &len); + if (err) { + close(fd); + perror("bpf_obj_get_info_by_fd failed"); + break; + } + + if (strcmp("bpf_testmod", name)) { + close(fd); + continue; + } + + btf = btf__load_from_kernel_by_id_split(id, vmlinux); + if (!btf) { + close(fd); + break; + } + + /* We need the fd to stay open so it can be used in fd_array. + * The final cleanup call to btf__free will free btf object + * and close the file descriptor. + */ + btf__set_fd(btf, fd); + break; + } + + set_root(false); + return btf; +} + +static struct btf *testmod_btf; +static struct btf *vmlinux_btf; + +static void kfuncs_cleanup(void) +{ + btf__free(testmod_btf); + btf__free(vmlinux_btf); +} + +static void fixup_prog_kfuncs(struct bpf_insn *prog, int *fd_array, + struct kfunc_btf_id_pair *fixup_kfunc_btf_id) +{ + /* Patch in kfunc BTF IDs */ + while (fixup_kfunc_btf_id->kfunc) { + int btf_id = 0; + + /* try to find kfunc in kernel BTF */ + vmlinux_btf = vmlinux_btf ?: btf__load_vmlinux_btf(); + if (vmlinux_btf) { + btf_id = btf__find_by_name_kind(vmlinux_btf, + fixup_kfunc_btf_id->kfunc, + BTF_KIND_FUNC); + btf_id = btf_id < 0 ? 0 : btf_id; + } + + /* kfunc not found in kernel BTF, try bpf_testmod BTF */ + if (!btf_id) { + testmod_btf = testmod_btf ?: btf__load_testmod_btf(vmlinux_btf); + if (testmod_btf) { + btf_id = btf__find_by_name_kind(testmod_btf, + fixup_kfunc_btf_id->kfunc, + BTF_KIND_FUNC); + btf_id = btf_id < 0 ? 0 : btf_id; + if (btf_id) { + /* We put bpf_testmod module fd into fd_array + * and its index 1 into instruction 'off'. + */ + *fd_array = btf__fd(testmod_btf); + prog[fixup_kfunc_btf_id->insn_idx].off = 1; + } + } + } + + prog[fixup_kfunc_btf_id->insn_idx].imm = btf_id; + fixup_kfunc_btf_id++; + } +} + static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, - struct bpf_insn *prog, int *map_fds) + struct bpf_insn *prog, int *map_fds, int *fd_array) { int *fixup_map_hash_8b = test->fixup_map_hash_8b; int *fixup_map_hash_48b = test->fixup_map_hash_48b; @@ -900,7 +1032,6 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, int *fixup_map_ringbuf = test->fixup_map_ringbuf; int *fixup_map_timer = test->fixup_map_timer; int *fixup_map_kptr = test->fixup_map_kptr; - struct kfunc_btf_id_pair *fixup_kfunc_btf_id = test->fixup_kfunc_btf_id; if (test->fill_helper) { test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn)); @@ -1101,25 +1232,7 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, } while (*fixup_map_kptr); } - /* Patch in kfunc BTF IDs */ - if (fixup_kfunc_btf_id->kfunc) { - struct btf *btf; - int btf_id; - - do { - btf_id = 0; - btf = btf__load_vmlinux_btf(); - if (btf) { - btf_id = btf__find_by_name_kind(btf, - fixup_kfunc_btf_id->kfunc, - BTF_KIND_FUNC); - btf_id = btf_id < 0 ? 0 : btf_id; - } - btf__free(btf); - prog[fixup_kfunc_btf_id->insn_idx].imm = btf_id; - fixup_kfunc_btf_id++; - } while (fixup_kfunc_btf_id->kfunc); - } + fixup_prog_kfuncs(prog, fd_array, test->fixup_kfunc_btf_id); } struct libcap { @@ -1446,6 +1559,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, int run_errs, run_successes; int map_fds[MAX_NR_MAPS]; const char *expected_err; + int fd_array[2] = { -1, -1 }; int saved_errno; int fixup_skips; __u32 pflags; @@ -1459,7 +1573,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, if (!prog_type) prog_type = BPF_PROG_TYPE_SOCKET_FILTER; fixup_skips = skips; - do_test_fixup(test, prog_type, prog, map_fds); + do_test_fixup(test, prog_type, prog, map_fds, &fd_array[1]); if (test->fill_insns) { prog = test->fill_insns; prog_len = test->prog_len; @@ -1493,6 +1607,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, else opts.log_level = DEFAULT_LIBBPF_LOG_LEVEL; opts.prog_flags = pflags; + if (fd_array[1] != -1) + opts.fd_array = &fd_array[0]; if ((prog_type == BPF_PROG_TYPE_TRACING || prog_type == BPF_PROG_TYPE_LSM) && test->kfunc) { @@ -1719,6 +1835,7 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) } unload_bpf_testmod(verbose); + kfuncs_cleanup(); printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes, skips, errors); -- cgit v1.2.3 From 6e2b50fa818bea4fc9a2d33f31a9633803a406ff Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:55 +0200 Subject: selftests/bpf: Remove extern from kfuncs declarations There's no need to keep the extern in kfuncs declarations. Suggested-by: David Vernet Acked-by: David Vernet Signed-off-by: Jiri Olsa Link: https://lore.kernel.org/r/20230515133756.1658301-10-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- .../selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h index f0755135061d..57f6166911f8 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h @@ -10,31 +10,31 @@ #define __ksym #endif -extern struct prog_test_ref_kfunc * +struct prog_test_ref_kfunc * bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym; -extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; +void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) __ksym; -extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; -extern int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; -extern int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; -extern void bpf_kfunc_call_int_mem_release(int *p) __ksym; -extern u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; +void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; +int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int rdwr_buf_size) __ksym; +int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; +int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; +void bpf_kfunc_call_int_mem_release(int *p) __ksym; +u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; -extern void bpf_testmod_test_mod_kfunc(int i) __ksym; +void bpf_testmod_test_mod_kfunc(int i) __ksym; -extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, +__u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, __u32 c, __u64 d) __ksym; -extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; -extern struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym; -extern long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym; +int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; +struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym; +long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym; -extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; -extern void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; -extern void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; -extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; +void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; +void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; +void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; +void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; -extern void bpf_kfunc_call_test_destructive(void) __ksym; +void bpf_kfunc_call_test_destructive(void) __ksym; #endif /* _BPF_TESTMOD_KFUNC_H */ -- cgit v1.2.3 From 65eb006d85a2ac0b23464808099726bd826e9877 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 15 May 2023 15:37:56 +0200 Subject: bpf: Move kernel test kfuncs to bpf_testmod Moving kernel test kfuncs into bpf_testmod kernel module, and adding necessary init calls and BTF IDs records. We need to keep following structs in kernel: struct prog_test_ref_kfunc struct prog_test_member (embedded in prog_test_ref_kfunc) The reason is because they need to be marked as rcu safe (check test prog mark_ref_as_untrusted_or_null) and such objects are being required to be defined only in kernel at the moment (see rcu_safe_kptr check in kernel). We need to keep also dtor functions for both objects in kernel: bpf_kfunc_call_test_release bpf_kfunc_call_memb_release We also keep the copy of these struct in bpf_testmod_kfunc.h, because other test functions use them. This is unfortunate, but this is just temporary solution until we are able to these structs them to bpf_testmod completely. As suggested by David adding bpf_testmod.ko make dependency for bpf programs, so they are rebuilt if we change the bpf_testmod.ko module. Also adding missing __bpf_kfunc to bpf_kfunc_call_test4 functions. Signed-off-by: Jiri Olsa Acked-by: David Vernet Link: https://lore.kernel.org/r/20230515133756.1658301-11-jolsa@kernel.org Signed-off-by: Alexei Starovoitov --- net/bpf/test_run.c | 201 --------------------- .../selftests/bpf/bpf_testmod/bpf_testmod.c | 166 +++++++++++++++++ .../selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h | 60 ++++++ 3 files changed, 226 insertions(+), 201 deletions(-) diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 98143b86a9dd..2321bd2f9964 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -561,29 +561,6 @@ __bpf_kfunc int bpf_modify_return_test(int a, int *b) return a + *b; } -__bpf_kfunc u64 bpf_kfunc_call_test1(struct sock *sk, u32 a, u64 b, u32 c, u64 d) -{ - return a + b + c + d; -} - -__bpf_kfunc int bpf_kfunc_call_test2(struct sock *sk, u32 a, u32 b) -{ - return a + b; -} - -__bpf_kfunc struct sock *bpf_kfunc_call_test3(struct sock *sk) -{ - return sk; -} - -long noinline bpf_kfunc_call_test4(signed char a, short b, int c, long d) -{ - /* Provoke the compiler to assume that the caller has sign-extended a, - * b and c on platforms where this is required (e.g. s390x). - */ - return (long)a + (long)b + (long)c + d; -} - int noinline bpf_fentry_shadow_test(int a) { return a + 1; @@ -606,32 +583,6 @@ struct prog_test_ref_kfunc { refcount_t cnt; }; -static struct prog_test_ref_kfunc prog_test_struct = { - .a = 42, - .b = 108, - .next = &prog_test_struct, - .cnt = REFCOUNT_INIT(1), -}; - -__bpf_kfunc struct prog_test_ref_kfunc * -bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) -{ - refcount_inc(&prog_test_struct.cnt); - return &prog_test_struct; -} - -__bpf_kfunc void bpf_kfunc_call_test_offset(struct prog_test_ref_kfunc *p) -{ - WARN_ON_ONCE(1); -} - -__bpf_kfunc struct prog_test_member * -bpf_kfunc_call_memb_acquire(void) -{ - WARN_ON_ONCE(1); - return NULL; -} - __bpf_kfunc void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) { refcount_dec(&p->cnt); @@ -641,134 +592,6 @@ __bpf_kfunc void bpf_kfunc_call_memb_release(struct prog_test_member *p) { } -__bpf_kfunc void bpf_kfunc_call_memb1_release(struct prog_test_member1 *p) -{ - WARN_ON_ONCE(1); -} - -static int *__bpf_kfunc_call_test_get_mem(struct prog_test_ref_kfunc *p, const int size) -{ - if (size > 2 * sizeof(int)) - return NULL; - - return (int *)p; -} - -__bpf_kfunc int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, - const int rdwr_buf_size) -{ - return __bpf_kfunc_call_test_get_mem(p, rdwr_buf_size); -} - -__bpf_kfunc int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, - const int rdonly_buf_size) -{ - return __bpf_kfunc_call_test_get_mem(p, rdonly_buf_size); -} - -/* the next 2 ones can't be really used for testing expect to ensure - * that the verifier rejects the call. - * Acquire functions must return struct pointers, so these ones are - * failing. - */ -__bpf_kfunc int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, - const int rdonly_buf_size) -{ - return __bpf_kfunc_call_test_get_mem(p, rdonly_buf_size); -} - -__bpf_kfunc void bpf_kfunc_call_int_mem_release(int *p) -{ -} - -struct prog_test_pass1 { - int x0; - struct { - int x1; - struct { - int x2; - struct { - int x3; - }; - }; - }; -}; - -struct prog_test_pass2 { - int len; - short arr1[4]; - struct { - char arr2[4]; - unsigned long arr3[8]; - } x; -}; - -struct prog_test_fail1 { - void *p; - int x; -}; - -struct prog_test_fail2 { - int x8; - struct prog_test_pass1 x; -}; - -struct prog_test_fail3 { - int len; - char arr1[2]; - char arr2[]; -}; - -__bpf_kfunc void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_fail1(struct prog_test_fail1 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_fail2(struct prog_test_fail2 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_fail3(struct prog_test_fail3 *p) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_mem_len_pass1(void *mem, int mem__sz) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_mem_len_fail1(void *mem, int len) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_mem_len_fail2(u64 *mem, int len) -{ -} - -__bpf_kfunc void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) -{ - /* p != NULL, but p->cnt could be 0 */ -} - -__bpf_kfunc void bpf_kfunc_call_test_destructive(void) -{ -} - -__bpf_kfunc static u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) -{ - return arg; -} - __diag_pop(); BTF_SET8_START(bpf_test_modify_return_ids) @@ -782,32 +605,8 @@ static const struct btf_kfunc_id_set bpf_test_modify_return_set = { }; BTF_SET8_START(test_sk_check_kfunc_ids) -BTF_ID_FLAGS(func, bpf_kfunc_call_test1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test2) -BTF_ID_FLAGS(func, bpf_kfunc_call_test3) -BTF_ID_FLAGS(func, bpf_kfunc_call_test4) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_acquire, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_kfunc_call_memb_acquire, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_kfunc_call_test_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_kfunc_call_memb_release, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_kfunc_call_memb1_release, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_get_rdwr_mem, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_get_rdonly_mem, KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_acq_rdonly_mem, KF_ACQUIRE | KF_RET_NULL) -BTF_ID_FLAGS(func, bpf_kfunc_call_int_mem_release, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass_ctx) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass2) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail2) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail3) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_pass1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail1) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail2) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_ref, KF_TRUSTED_ARGS | KF_RCU) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_destructive, KF_DESTRUCTIVE) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg) -BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset) BTF_SET8_END(test_sk_check_kfunc_ids) static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size, diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 52785ba671e6..cf216041876c 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -9,6 +9,7 @@ #include #include #include "bpf_testmod.h" +#include "bpf_testmod_kfunc.h" #define CREATE_TRACE_POINTS #include "bpf_testmod-events.h" @@ -289,8 +290,171 @@ static const struct btf_kfunc_id_set bpf_testmod_common_kfunc_set = { .set = &bpf_testmod_common_kfunc_ids, }; +__bpf_kfunc u64 bpf_kfunc_call_test1(struct sock *sk, u32 a, u64 b, u32 c, u64 d) +{ + return a + b + c + d; +} + +__bpf_kfunc int bpf_kfunc_call_test2(struct sock *sk, u32 a, u32 b) +{ + return a + b; +} + +__bpf_kfunc struct sock *bpf_kfunc_call_test3(struct sock *sk) +{ + return sk; +} + +__bpf_kfunc long noinline bpf_kfunc_call_test4(signed char a, short b, int c, long d) +{ + /* Provoke the compiler to assume that the caller has sign-extended a, + * b and c on platforms where this is required (e.g. s390x). + */ + return (long)a + (long)b + (long)c + d; +} + +static struct prog_test_ref_kfunc prog_test_struct = { + .a = 42, + .b = 108, + .next = &prog_test_struct, + .cnt = REFCOUNT_INIT(1), +}; + +__bpf_kfunc struct prog_test_ref_kfunc * +bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) +{ + refcount_inc(&prog_test_struct.cnt); + return &prog_test_struct; +} + +__bpf_kfunc void bpf_kfunc_call_test_offset(struct prog_test_ref_kfunc *p) +{ + WARN_ON_ONCE(1); +} + +__bpf_kfunc struct prog_test_member * +bpf_kfunc_call_memb_acquire(void) +{ + WARN_ON_ONCE(1); + return NULL; +} + +__bpf_kfunc void bpf_kfunc_call_memb1_release(struct prog_test_member1 *p) +{ + WARN_ON_ONCE(1); +} + +static int *__bpf_kfunc_call_test_get_mem(struct prog_test_ref_kfunc *p, const int size) +{ + if (size > 2 * sizeof(int)) + return NULL; + + return (int *)p; +} + +__bpf_kfunc int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, + const int rdwr_buf_size) +{ + return __bpf_kfunc_call_test_get_mem(p, rdwr_buf_size); +} + +__bpf_kfunc int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, + const int rdonly_buf_size) +{ + return __bpf_kfunc_call_test_get_mem(p, rdonly_buf_size); +} + +/* the next 2 ones can't be really used for testing expect to ensure + * that the verifier rejects the call. + * Acquire functions must return struct pointers, so these ones are + * failing. + */ +__bpf_kfunc int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, + const int rdonly_buf_size) +{ + return __bpf_kfunc_call_test_get_mem(p, rdonly_buf_size); +} + +__bpf_kfunc void bpf_kfunc_call_int_mem_release(int *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_fail1(struct prog_test_fail1 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_fail2(struct prog_test_fail2 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_fail3(struct prog_test_fail3 *p) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_mem_len_pass1(void *mem, int mem__sz) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_mem_len_fail1(void *mem, int len) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_mem_len_fail2(u64 *mem, int len) +{ +} + +__bpf_kfunc void bpf_kfunc_call_test_ref(struct prog_test_ref_kfunc *p) +{ + /* p != NULL, but p->cnt could be 0 */ +} + +__bpf_kfunc void bpf_kfunc_call_test_destructive(void) +{ +} + +__bpf_kfunc static u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) +{ + return arg; +} + BTF_SET8_START(bpf_testmod_check_kfunc_ids) BTF_ID_FLAGS(func, bpf_testmod_test_mod_kfunc) +BTF_ID_FLAGS(func, bpf_kfunc_call_test1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test2) +BTF_ID_FLAGS(func, bpf_kfunc_call_test3) +BTF_ID_FLAGS(func, bpf_kfunc_call_test4) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_pass1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_mem_len_fail2) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_acquire, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_memb_acquire, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_memb1_release, KF_RELEASE) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_get_rdwr_mem, KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_get_rdonly_mem, KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_acq_rdonly_mem, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_kfunc_call_int_mem_release, KF_RELEASE) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass_ctx) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass2) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail1) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail2) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail3) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_ref, KF_TRUSTED_ARGS | KF_RCU) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_destructive, KF_DESTRUCTIVE) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_static_unused_arg) +BTF_ID_FLAGS(func, bpf_kfunc_call_test_offset) BTF_SET8_END(bpf_testmod_check_kfunc_ids) static const struct btf_kfunc_id_set bpf_testmod_kfunc_set = { @@ -312,6 +476,8 @@ static int bpf_testmod_init(void) ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &bpf_testmod_common_kfunc_set); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_testmod_kfunc_set); + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_testmod_kfunc_set); + ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_testmod_kfunc_set); if (ret < 0) return ret; if (bpf_fentry_test1(0) < 0) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h index 57f6166911f8..9693c626646b 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h @@ -8,8 +8,62 @@ #include #else #define __ksym +struct prog_test_member1 { + int a; +}; + +struct prog_test_member { + struct prog_test_member1 m; + int c; +}; + +struct prog_test_ref_kfunc { + int a; + int b; + struct prog_test_member memb; + struct prog_test_ref_kfunc *next; + refcount_t cnt; +}; #endif +struct prog_test_pass1 { + int x0; + struct { + int x1; + struct { + int x2; + struct { + int x3; + }; + }; + }; +}; + +struct prog_test_pass2 { + int len; + short arr1[4]; + struct { + char arr2[4]; + unsigned long arr3[8]; + } x; +}; + +struct prog_test_fail1 { + void *p; + int x; +}; + +struct prog_test_fail2 { + int x8; + struct prog_test_pass1 x; +}; + +struct prog_test_fail3 { + int len; + char arr1[2]; + char arr2[]; +}; + struct prog_test_ref_kfunc * bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym; void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; @@ -20,7 +74,13 @@ int *bpf_kfunc_call_test_get_rdwr_mem(struct prog_test_ref_kfunc *p, const int r int *bpf_kfunc_call_test_get_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; int *bpf_kfunc_call_test_acq_rdonly_mem(struct prog_test_ref_kfunc *p, const int rdonly_buf_size) __ksym; void bpf_kfunc_call_int_mem_release(int *p) __ksym; + +/* The bpf_kfunc_call_test_static_unused_arg is defined as static, + * but bpf program compilation needs to see it as global symbol. + */ +#ifndef __KERNEL__ u32 bpf_kfunc_call_test_static_unused_arg(u32 arg, u32 unused) __ksym; +#endif void bpf_testmod_test_mod_kfunc(int i) __ksym; -- cgit v1.2.3 From d2e541494935a659b67e51aa3d1945bb3b799c4e Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:00 +0200 Subject: selftests/xsk: do not change XDP program when not necessary Do not change the XDP program for the Tx thread when not needed. It was erroneously compared to the XDP program for the Rx thread, which is always going to be different, which meant that the code made unnecessary switches to the same program it had before. This did not affect functionality, just performance. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-2-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index f144d0604ddf..f7950af576e1 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -1402,11 +1402,20 @@ static void handler(int signum) pthread_exit(NULL); } -static bool xdp_prog_changed(struct test_spec *test, struct ifobject *ifobj) +static bool xdp_prog_changed_rx(struct test_spec *test) { + struct ifobject *ifobj = test->ifobj_rx; + return ifobj->xdp_prog != test->xdp_prog_rx || ifobj->mode != test->mode; } +static bool xdp_prog_changed_tx(struct test_spec *test) +{ + struct ifobject *ifobj = test->ifobj_tx; + + return ifobj->xdp_prog != test->xdp_prog_tx || ifobj->mode != test->mode; +} + static void xsk_reattach_xdp(struct ifobject *ifobj, struct bpf_program *xdp_prog, struct bpf_map *xskmap, enum test_mode mode) { @@ -1433,13 +1442,13 @@ static void xsk_reattach_xdp(struct ifobject *ifobj, struct bpf_program *xdp_pro static void xsk_attach_xdp_progs(struct test_spec *test, struct ifobject *ifobj_rx, struct ifobject *ifobj_tx) { - if (xdp_prog_changed(test, ifobj_rx)) + if (xdp_prog_changed_rx(test)) xsk_reattach_xdp(ifobj_rx, test->xdp_prog_rx, test->xskmap_rx, test->mode); if (!ifobj_tx || ifobj_tx->shared_umem) return; - if (xdp_prog_changed(test, ifobj_tx)) + if (xdp_prog_changed_tx(test)) xsk_reattach_xdp(ifobj_tx, test->xdp_prog_tx, test->xskmap_tx, test->mode); } -- cgit v1.2.3 From df82d2e89c41d1dc6f02a881f0cddac8252bb441 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:01 +0200 Subject: selftests/xsk: generate simpler packets with variable length Implement support for generating pkts with variable length. Before this patch, they were all 64 bytes, exception for some packets of zero length and some that were too large. This feature will be used to test multi-buffer support for which large packets are needed. The packets are also made simpler, just a valid Ethernet header followed by a sequence number. This so that it will become easier to implement packet generation when each packet consists of multiple fragments. There is also a maintenance burden associated with carrying all this code for generating proper UDP/IP packets, especially since they are not needed. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-3-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 221 +++++-------------------------- tools/testing/selftests/bpf/xskxceiver.h | 17 +-- 2 files changed, 38 insertions(+), 200 deletions(-) diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index f7950af576e1..c13478875fb1 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -76,16 +76,13 @@ #include #include #include -#include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -94,10 +91,8 @@ #include #include #include -#include #include #include -#include #include "xsk_xdp_progs.skel.h" #include "xsk.h" @@ -109,10 +104,6 @@ static const char *MAC1 = "\x00\x0A\x56\x9E\xEE\x62"; static const char *MAC2 = "\x00\x0A\x56\x9E\xEE\x61"; -static const char *IP1 = "192.168.100.162"; -static const char *IP2 = "192.168.100.161"; -static const u16 UDP_PORT1 = 2020; -static const u16 UDP_PORT2 = 2121; static void __exit_with_error(int error, const char *file, const char *func, int line) { @@ -158,101 +149,11 @@ static void memset32_htonl(void *dest, u32 val, u32 size) ptr[i >> 2] = val; } -/* - * Fold a partial checksum - * This function code has been taken from - * Linux kernel include/asm-generic/checksum.h - */ -static __u16 csum_fold(__u32 csum) -{ - u32 sum = (__force u32)csum; - - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); - return (__force __u16)~sum; -} - -/* - * This function code has been taken from - * Linux kernel lib/checksum.c - */ -static u32 from64to32(u64 x) -{ - /* add up 32-bit and 32-bit for 32+c bit */ - x = (x & 0xffffffff) + (x >> 32); - /* add up carry.. */ - x = (x & 0xffffffff) + (x >> 32); - return (u32)x; -} - -/* - * This function code has been taken from - * Linux kernel lib/checksum.c - */ -static __u32 csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum) -{ - unsigned long long s = (__force u32)sum; - - s += (__force u32)saddr; - s += (__force u32)daddr; -#ifdef __BIG_ENDIAN__ - s += proto + len; -#else - s += (proto + len) << 8; -#endif - return (__force __u32)from64to32(s); -} - -/* - * This function has been taken from - * Linux kernel include/asm-generic/checksum.h - */ -static __u16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, __u8 proto, __u32 sum) -{ - return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); -} - -static u16 udp_csum(u32 saddr, u32 daddr, u32 len, u8 proto, u16 *udp_pkt) -{ - u32 csum = 0; - u32 cnt = 0; - - /* udp hdr and data */ - for (; cnt < len; cnt += 2) - csum += udp_pkt[cnt >> 1]; - - return csum_tcpudp_magic(saddr, daddr, len, proto, csum); -} - static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr) { memcpy(eth_hdr->h_dest, ifobject->dst_mac, ETH_ALEN); memcpy(eth_hdr->h_source, ifobject->src_mac, ETH_ALEN); - eth_hdr->h_proto = htons(ETH_P_IP); -} - -static void gen_ip_hdr(struct ifobject *ifobject, struct iphdr *ip_hdr) -{ - ip_hdr->version = IP_PKT_VER; - ip_hdr->ihl = 0x5; - ip_hdr->tos = IP_PKT_TOS; - ip_hdr->tot_len = htons(IP_PKT_SIZE); - ip_hdr->id = 0; - ip_hdr->frag_off = 0; - ip_hdr->ttl = IPDEFTTL; - ip_hdr->protocol = IPPROTO_UDP; - ip_hdr->saddr = ifobject->src_ip; - ip_hdr->daddr = ifobject->dst_ip; - ip_hdr->check = 0; -} - -static void gen_udp_hdr(u32 payload, void *pkt, struct ifobject *ifobject, - struct udphdr *udp_hdr) -{ - udp_hdr->source = htons(ifobject->src_port); - udp_hdr->dest = htons(ifobject->dst_port); - udp_hdr->len = htons(UDP_PKT_SIZE); - memset32_htonl(pkt + PKT_HDR_SIZE, payload, UDP_PKT_DATA_SIZE); + eth_hdr->h_proto = htons(ETH_P_LOOPBACK); } static bool is_umem_valid(struct ifobject *ifobj) @@ -260,13 +161,6 @@ static bool is_umem_valid(struct ifobject *ifobj) return !!ifobj->umem->umem; } -static void gen_udp_csum(struct udphdr *udp_hdr, struct iphdr *ip_hdr) -{ - udp_hdr->check = 0; - udp_hdr->check = - udp_csum(ip_hdr->saddr, ip_hdr->daddr, UDP_PKT_SIZE, IPPROTO_UDP, (u16 *)udp_hdr); -} - static u32 mode_to_xdp_flags(enum test_mode mode) { return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; @@ -697,9 +591,7 @@ static void pkt_stream_receive_half(struct test_spec *test) static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) { struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb); - struct udphdr *udp_hdr; struct ethhdr *eth_hdr; - struct iphdr *ip_hdr; void *data; if (!pkt) @@ -708,14 +600,10 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) return pkt; data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr); - udp_hdr = (struct udphdr *)(data + sizeof(struct ethhdr) + sizeof(struct iphdr)); - ip_hdr = (struct iphdr *)(data + sizeof(struct ethhdr)); - eth_hdr = (struct ethhdr *)data; + eth_hdr = data; - gen_udp_hdr(pkt_nb, data, ifobject, udp_hdr); - gen_ip_hdr(ifobject, ip_hdr); - gen_udp_csum(udp_hdr, ip_hdr); gen_eth_hdr(ifobject, eth_hdr); + memset32_htonl(data + PKT_HDR_SIZE, pkt_nb, pkt->len - PKT_HDR_SIZE); return pkt; } @@ -746,18 +634,11 @@ static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, __pkt_stream_generate_custom(test->ifobj_rx, pkts, nb_pkts); } -static void pkt_dump(void *pkt, u32 len) +static void pkt_dump(void *pkt) { - char s[INET_ADDRSTRLEN]; - struct ethhdr *ethhdr; - struct udphdr *udphdr; - struct iphdr *iphdr; + struct ethhdr *ethhdr = pkt; u32 payload, i; - ethhdr = pkt; - iphdr = pkt + sizeof(*ethhdr); - udphdr = pkt + sizeof(*ethhdr) + sizeof(*iphdr); - /*extract L2 frame */ fprintf(stdout, "DEBUG>> L2: dst mac: "); for (i = 0; i < ETH_ALEN; i++) @@ -767,19 +648,10 @@ static void pkt_dump(void *pkt, u32 len) for (i = 0; i < ETH_ALEN; i++) fprintf(stdout, "%02X", ethhdr->h_source[i]); - /*extract L3 frame */ - fprintf(stdout, "\nDEBUG>> L3: ip_hdr->ihl: %02X\n", iphdr->ihl); - fprintf(stdout, "DEBUG>> L3: ip_hdr->saddr: %s\n", - inet_ntop(AF_INET, &iphdr->saddr, s, sizeof(s))); - fprintf(stdout, "DEBUG>> L3: ip_hdr->daddr: %s\n", - inet_ntop(AF_INET, &iphdr->daddr, s, sizeof(s))); - /*extract L4 frame */ - fprintf(stdout, "DEBUG>> L4: udp_hdr->src: %d\n", ntohs(udphdr->source)); - fprintf(stdout, "DEBUG>> L4: udp_hdr->dst: %d\n", ntohs(udphdr->dest)); /*extract L5 frame */ payload = ntohl(*((u32 *)(pkt + PKT_HDR_SIZE))); - fprintf(stdout, "DEBUG>> L5: payload: %d\n", payload); + fprintf(stdout, "\nDEBUG>> L5: payload: %d\n", payload); fprintf(stdout, "---------------------------------------\n"); } @@ -818,7 +690,7 @@ static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) { void *data = xsk_umem__get_data(buffer, addr); - struct iphdr *iphdr = (struct iphdr *)(data + sizeof(struct ethhdr)); + u32 seqnum; if (!pkt) { ksft_print_msg("[%s] too many packets received\n", __func__); @@ -836,21 +708,13 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) return false; } - if (iphdr->version == IP_PKT_VER && iphdr->tos == IP_PKT_TOS) { - u32 seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); - - if (opt_pkt_dump) - pkt_dump(data, PKT_SIZE); + seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); + if (opt_pkt_dump) + pkt_dump(data); - if (pkt->payload != seqnum) { - ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n", - __func__, pkt->payload, seqnum); - return false; - } - } else { - ksft_print_msg("Invalid frame received: "); - ksft_print_msg("[IP_PKT_VER: %02X], [IP_PKT_TOS: %02X]\n", iphdr->version, - iphdr->tos); + if (pkt->payload != seqnum) { + ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n", + __func__, pkt->payload, seqnum); return false; } @@ -1606,9 +1470,9 @@ static void testapp_stats_tx_invalid_descs(struct test_spec *test) static void testapp_stats_rx_full(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_FULL"); - pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, PKT_SIZE); + pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, - DEFAULT_UMEM_BUFFERS, PKT_SIZE); + DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); if (!test->ifobj_rx->pkt_stream) exit_with_error(ENOMEM); @@ -1621,9 +1485,9 @@ static void testapp_stats_rx_full(struct test_spec *test) static void testapp_stats_fill_empty(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_FILL_EMPTY"); - pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, PKT_SIZE); + pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, - DEFAULT_UMEM_BUFFERS, PKT_SIZE); + DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); if (!test->ifobj_rx->pkt_stream) exit_with_error(ENOMEM); @@ -1659,7 +1523,7 @@ static bool testapp_unaligned(struct test_spec *test) test->ifobj_tx->umem->unaligned_mode = true; test->ifobj_rx->umem->unaligned_mode = true; /* Let half of the packets straddle a buffer boundrary */ - pkt_stream_replace_half(test, PKT_SIZE, -PKT_SIZE / 2); + pkt_stream_replace_half(test, MIN_PKT_SIZE, -MIN_PKT_SIZE / 2); test->ifobj_rx->pkt_stream->use_addr_for_fill = true; testapp_validate_traffic(test); @@ -1668,7 +1532,7 @@ static bool testapp_unaligned(struct test_spec *test) static void testapp_single_pkt(struct test_spec *test) { - struct pkt pkts[] = {{0x1000, PKT_SIZE, 0, true}}; + struct pkt pkts[] = {{0x1000, MIN_PKT_SIZE, 0, true}}; pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); testapp_validate_traffic(test); @@ -1679,25 +1543,25 @@ static void testapp_invalid_desc(struct test_spec *test) u64 umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; struct pkt pkts[] = { /* Zero packet address allowed */ - {0, PKT_SIZE, 0, true}, + {0, MIN_PKT_SIZE, 0, true}, /* Allowed packet */ - {0x1000, PKT_SIZE, 0, true}, + {0x1000, MIN_PKT_SIZE, 0, true}, /* Straddling the start of umem */ - {-2, PKT_SIZE, 0, false}, + {-2, MIN_PKT_SIZE, 0, false}, /* Packet too large */ {0x2000, XSK_UMEM__INVALID_FRAME_SIZE, 0, false}, /* Up to end of umem allowed */ - {umem_size - PKT_SIZE, PKT_SIZE, 0, true}, + {umem_size - MIN_PKT_SIZE, MIN_PKT_SIZE, 0, true}, /* After umem ends */ - {umem_size, PKT_SIZE, 0, false}, + {umem_size, MIN_PKT_SIZE, 0, false}, /* Straddle the end of umem */ - {umem_size - PKT_SIZE / 2, PKT_SIZE, 0, false}, + {umem_size - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, /* Straddle a page boundrary */ - {0x3000 - PKT_SIZE / 2, PKT_SIZE, 0, false}, + {0x3000 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, /* Straddle a 2K boundrary */ - {0x3800 - PKT_SIZE / 2, PKT_SIZE, 0, true}, + {0x3800 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, true}, /* Valid packet for synch so that something is received */ - {0x4000, PKT_SIZE, 0, true}}; + {0x4000, MIN_PKT_SIZE, 0, true}}; if (test->ifobj_tx->umem->unaligned_mode) { /* Crossing a page boundrary allowed */ @@ -1788,24 +1652,13 @@ static void xsk_unload_xdp_programs(struct ifobject *ifobj) } static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac, - const char *dst_ip, const char *src_ip, const u16 dst_port, - const u16 src_port, thread_func_t func_ptr) + thread_func_t func_ptr) { - struct in_addr ip; int err; memcpy(ifobj->dst_mac, dst_mac, ETH_ALEN); memcpy(ifobj->src_mac, src_mac, ETH_ALEN); - inet_aton(dst_ip, &ip); - ifobj->dst_ip = ip.s_addr; - - inet_aton(src_ip, &ip); - ifobj->src_ip = ip.s_addr; - - ifobj->dst_port = dst_port; - ifobj->src_port = src_port; - ifobj->func_ptr = func_ptr; err = xsk_load_xdp_programs(ifobj); @@ -1855,7 +1708,7 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_ test_spec_set_name(test, "RUN_TO_COMPLETION_2K_FRAME_SIZE"); test->ifobj_tx->umem->frame_size = 2048; test->ifobj_rx->umem->frame_size = 2048; - pkt_stream_replace(test, DEFAULT_PKT_CNT, PKT_SIZE); + pkt_stream_replace(test, DEFAULT_PKT_CNT, MIN_PKT_SIZE); testapp_validate_traffic(test); break; case TEST_TYPE_RX_POLL: @@ -1912,8 +1765,8 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_ */ page_size = sysconf(_SC_PAGESIZE); umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; - assert(umem_size % page_size > PKT_SIZE); - assert(umem_size % page_size < page_size - PKT_SIZE); + assert(umem_size % page_size > MIN_PKT_SIZE); + assert(umem_size % page_size < page_size - MIN_PKT_SIZE); testapp_invalid_desc(test); break; } @@ -2039,14 +1892,12 @@ int main(int argc, char **argv) modes++; } - init_iface(ifobj_rx, MAC1, MAC2, IP1, IP2, UDP_PORT1, UDP_PORT2, - worker_testapp_validate_rx); - init_iface(ifobj_tx, MAC2, MAC1, IP2, IP1, UDP_PORT2, UDP_PORT1, - worker_testapp_validate_tx); + init_iface(ifobj_rx, MAC1, MAC2, worker_testapp_validate_rx); + init_iface(ifobj_tx, MAC2, MAC1, worker_testapp_validate_tx); test_spec_init(&test, ifobj_tx, ifobj_rx, 0); - tx_pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, PKT_SIZE); - rx_pkt_stream_default = pkt_stream_generate(ifobj_rx->umem, DEFAULT_PKT_CNT, PKT_SIZE); + tx_pkt_stream_default = pkt_stream_generate(ifobj_tx->umem, DEFAULT_PKT_CNT, MIN_PKT_SIZE); + rx_pkt_stream_default = pkt_stream_generate(ifobj_rx->umem, DEFAULT_PKT_CNT, MIN_PKT_SIZE); if (!tx_pkt_stream_default || !rx_pkt_stream_default) exit_with_error(ENOMEM); test.tx_pkt_stream_default = tx_pkt_stream_default; diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index c535aeab2ca3..8b094718629d 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -35,17 +35,8 @@ #define MAX_SOCKETS 2 #define MAX_TEST_NAME_SIZE 32 #define MAX_TEARDOWN_ITER 10 -#define PKT_HDR_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) + \ - sizeof(struct udphdr)) -#define MIN_ETH_PKT_SIZE 64 -#define ETH_FCS_SIZE 4 -#define MIN_PKT_SIZE (MIN_ETH_PKT_SIZE - ETH_FCS_SIZE) -#define PKT_SIZE (MIN_PKT_SIZE) -#define IP_PKT_SIZE (PKT_SIZE - sizeof(struct ethhdr)) -#define IP_PKT_VER 0x4 -#define IP_PKT_TOS 0x9 -#define UDP_PKT_SIZE (IP_PKT_SIZE - sizeof(struct iphdr)) -#define UDP_PKT_DATA_SIZE (UDP_PKT_SIZE - sizeof(struct udphdr)) +#define PKT_HDR_SIZE (sizeof(struct ethhdr) + 2) /* Just to align the data in the packet */ +#define MIN_PKT_SIZE 64 #define USLEEP_MAX 10000 #define SOCK_RECONF_CTR 10 #define BATCH_SIZE 64 @@ -148,11 +139,7 @@ struct ifobject { struct bpf_program *xdp_prog; enum test_mode mode; int ifindex; - u32 dst_ip; - u32 src_ip; u32 bind_flags; - u16 src_port; - u16 dst_port; bool tx_on; bool rx_on; bool use_poll; -- cgit v1.2.3 From feb973a9094ff92fb8c141be5d2e762f9ab36a7a Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:02 +0200 Subject: selftests/xsk: add varying payload pattern within packet Add a varying payload pattern within the packet. Instead of having just a packet number that is the same for all words in a packet, make each word different in the packet. The upper 16-bits are set to the packet number and the lower 16-bits are the sequence number of the words in this packet. So the 3rd packet's 5th 32-bit word of data will contain the number (2<<32) | 4 as they are numbered from 0. This will make it easier to detect fragments that are out of order when starting to test multi-buffer support. The member payload in the packet is renamed pkt_nb to reflect that it is now only a pkt_nb, not the real payload as seen above. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-4-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 68 +++++++++++++++++++++----------- tools/testing/selftests/bpf/xskxceiver.h | 3 +- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index c13478875fb1..818b7130f932 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -138,15 +138,16 @@ static void report_failure(struct test_spec *test) test->fail = true; } -static void memset32_htonl(void *dest, u32 val, u32 size) +/* The payload is a word consisting of a packet sequence number in the upper + * 16-bits and a intra packet data sequence number in the lower 16 bits. So the 3rd packet's + * 5th word of data will contain the number (2<<16) | 4 as they are numbered from 0. + */ +static void write_payload(void *dest, u32 val, u32 size) { - u32 *ptr = (u32 *)dest; - int i; + u32 *ptr = (u32 *)dest, i; - val = htonl(val); - - for (i = 0; i < (size & (~0x3)); i += 4) - ptr[i >> 2] = val; + for (i = 0; i < size / sizeof(*ptr); i++) + ptr[i] = htonl(val << 16 | i); } static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr) @@ -532,7 +533,7 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb for (i = 0; i < nb_pkts; i++) { pkt_set(umem, &pkt_stream->pkts[i], (i % umem->num_frames) * umem->frame_size, pkt_len); - pkt_stream->pkts[i].payload = i; + pkt_stream->pkts[i].pkt_nb = i; } return pkt_stream; @@ -603,7 +604,7 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) eth_hdr = data; gen_eth_hdr(ifobject, eth_hdr); - memset32_htonl(data + PKT_HDR_SIZE, pkt_nb, pkt->len - PKT_HDR_SIZE); + write_payload(data + PKT_HDR_SIZE, pkt_nb, pkt->len - PKT_HDR_SIZE); return pkt; } @@ -621,7 +622,7 @@ static void __pkt_stream_generate_custom(struct ifobject *ifobj, for (i = 0; i < nb_pkts; i++) { pkt_stream->pkts[i].addr = pkts[i].addr + ifobj->umem->base_addr; pkt_stream->pkts[i].len = pkts[i].len; - pkt_stream->pkts[i].payload = i; + pkt_stream->pkts[i].pkt_nb = i; pkt_stream->pkts[i].valid = pkts[i].valid; } @@ -634,10 +635,24 @@ static void pkt_stream_generate_custom(struct test_spec *test, struct pkt *pkts, __pkt_stream_generate_custom(test->ifobj_rx, pkts, nb_pkts); } -static void pkt_dump(void *pkt) +static void pkt_print_data(u32 *data, u32 cnt) +{ + u32 i; + + for (i = 0; i < cnt; i++) { + u32 seqnum, pkt_nb; + + seqnum = ntohl(*data) & 0xffff; + pkt_nb = ntohl(*data) >> 16; + fprintf(stdout, "%u:%u ", pkt_nb, seqnum); + data++; + } +} + +static void pkt_dump(void *pkt, u32 len) { struct ethhdr *ethhdr = pkt; - u32 payload, i; + u32 i; /*extract L2 frame */ fprintf(stdout, "DEBUG>> L2: dst mac: "); @@ -649,10 +664,15 @@ static void pkt_dump(void *pkt) fprintf(stdout, "%02X", ethhdr->h_source[i]); /*extract L5 frame */ - payload = ntohl(*((u32 *)(pkt + PKT_HDR_SIZE))); - - fprintf(stdout, "\nDEBUG>> L5: payload: %d\n", payload); - fprintf(stdout, "---------------------------------------\n"); + fprintf(stdout, "\nDEBUG>> L5: seqnum: "); + pkt_print_data(pkt + PKT_HDR_SIZE, PKT_DUMP_NB_TO_PRINT); + fprintf(stdout, "...."); + if (len > PKT_DUMP_NB_TO_PRINT * sizeof(u32)) { + fprintf(stdout, "\n.... "); + pkt_print_data(pkt + PKT_HDR_SIZE + len - PKT_DUMP_NB_TO_PRINT * sizeof(u32), + PKT_DUMP_NB_TO_PRINT); + } + fprintf(stdout, "\n---------------------------------------\n"); } static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, u64 addr, @@ -678,9 +698,9 @@ static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) void *data = xsk_umem__get_data(buffer, addr); struct xdp_info *meta = data - sizeof(struct xdp_info); - if (meta->count != pkt->payload) { + if (meta->count != pkt->pkt_nb) { ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%d]\n", - __func__, pkt->payload, meta->count); + __func__, pkt->pkt_nb, meta->count); return false; } @@ -690,7 +710,7 @@ static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) { void *data = xsk_umem__get_data(buffer, addr); - u32 seqnum; + u32 seqnum, pkt_data; if (!pkt) { ksft_print_msg("[%s] too many packets received\n", __func__); @@ -708,13 +728,15 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) return false; } - seqnum = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); + pkt_data = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); + seqnum = pkt_data >> 16; + if (opt_pkt_dump) - pkt_dump(data); + pkt_dump(data, len); - if (pkt->payload != seqnum) { + if (pkt->pkt_nb != seqnum) { ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n", - __func__, pkt->payload, seqnum); + __func__, pkt->pkt_nb, seqnum); return false; } diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 8b094718629d..91022c4876eb 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -48,6 +48,7 @@ #define UMEM_HEADROOM_TEST_SIZE 128 #define XSK_UMEM__INVALID_FRAME_SIZE (XSK_UMEM__DEFAULT_FRAME_SIZE + 1) #define HUGEPAGE_SIZE (2 * 1024 * 1024) +#define PKT_DUMP_NB_TO_PRINT 16 #define print_verbose(x...) do { if (opt_verbose) ksft_print_msg(x); } while (0) @@ -111,7 +112,7 @@ struct xsk_socket_info { struct pkt { u64 addr; u32 len; - u32 payload; + u32 pkt_nb; bool valid; }; -- cgit v1.2.3 From 7a8a6762822a1f5249eec356e7ea31f98161fba0 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:03 +0200 Subject: selftests/xsk: dump packet at error Dump the content of the packet when a test finds that packets are received out of order, the length is wrong, or some other packet error. Use the already existing pkt_dump function for this and call it when the above errors are detected. Get rid of the command line option for dumping packets as it is not useful to print out thousands of good packets followed by the faulty one you would like to see. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-5-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_xsk.sh | 10 +--------- tools/testing/selftests/bpf/xskxceiver.c | 20 ++++++++------------ tools/testing/selftests/bpf/xskxceiver.h | 1 - 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/bpf/test_xsk.sh b/tools/testing/selftests/bpf/test_xsk.sh index 377fb157a57c..c2ad50f26b63 100755 --- a/tools/testing/selftests/bpf/test_xsk.sh +++ b/tools/testing/selftests/bpf/test_xsk.sh @@ -68,9 +68,6 @@ # Run with verbose output: # sudo ./test_xsk.sh -v # -# Run and dump packet contents: -# sudo ./test_xsk.sh -D -# # Set up veth interfaces and leave them up so xskxceiver can be launched in a debugger: # sudo ./test_xsk.sh -d # @@ -81,11 +78,10 @@ ETH="" -while getopts "vDi:d" flag +while getopts "vi:d" flag do case "${flag}" in v) verbose=1;; - D) dump_pkts=1;; d) debug=1;; i) ETH=${OPTARG};; esac @@ -157,10 +153,6 @@ if [[ $verbose -eq 1 ]]; then ARGS+="-v " fi -if [[ $dump_pkts -eq 1 ]]; then - ARGS="-D " -fi - retval=$? test_status $retval "${TEST_NAME}" diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index 818b7130f932..0a8231ed6626 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -275,7 +275,6 @@ out: static struct option long_options[] = { {"interface", required_argument, 0, 'i'}, {"busy-poll", no_argument, 0, 'b'}, - {"dump-pkts", no_argument, 0, 'D'}, {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0} }; @@ -286,7 +285,6 @@ static void usage(const char *prog) " Usage: %s [OPTIONS]\n" " Options:\n" " -i, --interface Use interface\n" - " -D, --dump-pkts Dump packets L2 - L5\n" " -v, --verbose Verbose output\n" " -b, --busy-poll Enable busy poll\n"; @@ -310,7 +308,7 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj opterr = 0; for (;;) { - c = getopt_long(argc, argv, "i:Dvb", long_options, &option_index); + c = getopt_long(argc, argv, "i:vb", long_options, &option_index); if (c == -1) break; @@ -332,9 +330,6 @@ static void parse_command_line(struct ifobject *ifobj_tx, struct ifobject *ifobj interface_nb++; break; - case 'D': - opt_pkt_dump = true; - break; case 'v': opt_verbose = true; break; @@ -714,7 +709,7 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) if (!pkt) { ksft_print_msg("[%s] too many packets received\n", __func__); - return false; + goto error; } if (len < MIN_PKT_SIZE || pkt->len < MIN_PKT_SIZE) { @@ -725,22 +720,23 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) if (pkt->len != len) { ksft_print_msg("[%s] expected length [%d], got length [%d]\n", __func__, pkt->len, len); - return false; + goto error; } pkt_data = ntohl(*((u32 *)(data + PKT_HDR_SIZE))); seqnum = pkt_data >> 16; - if (opt_pkt_dump) - pkt_dump(data, len); - if (pkt->pkt_nb != seqnum) { ksft_print_msg("[%s] expected seqnum [%d], got seqnum [%d]\n", __func__, pkt->pkt_nb, seqnum); - return false; + goto error; } return true; + +error: + pkt_dump(data, len); + return false; } static void kick_tx(struct xsk_socket_info *xsk) diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 91022c4876eb..5e0be9685557 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -85,7 +85,6 @@ enum test_type { TEST_TYPE_MAX }; -static bool opt_pkt_dump; static bool opt_verbose; struct xsk_umem_info { -- cgit v1.2.3 From 69fc03d220a318a4df2c6f0612b17225e71a6069 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:04 +0200 Subject: selftests/xsk: add packet iterator for tx to packet stream Convert the current variable rx_pkt_nb to an iterator that can be used for both Rx and Tx. This to simplify the code and making Tx more like Rx that already has this feature. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-6-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 43 +++++++++++++++++--------------- tools/testing/selftests/bpf/xskxceiver.h | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index 0a8231ed6626..0823890c0709 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -444,24 +444,24 @@ static void test_spec_set_xdp_prog(struct test_spec *test, struct bpf_program *x static void pkt_stream_reset(struct pkt_stream *pkt_stream) { if (pkt_stream) - pkt_stream->rx_pkt_nb = 0; + pkt_stream->current_pkt_nb = 0; } -static struct pkt *pkt_stream_get_pkt(struct pkt_stream *pkt_stream, u32 pkt_nb) +static struct pkt *pkt_stream_get_next_tx_pkt(struct pkt_stream *pkt_stream) { - if (pkt_nb >= pkt_stream->nb_pkts) + if (pkt_stream->current_pkt_nb >= pkt_stream->nb_pkts) return NULL; - return &pkt_stream->pkts[pkt_nb]; + return &pkt_stream->pkts[pkt_stream->current_pkt_nb++]; } static struct pkt *pkt_stream_get_next_rx_pkt(struct pkt_stream *pkt_stream, u32 *pkts_sent) { - while (pkt_stream->rx_pkt_nb < pkt_stream->nb_pkts) { + while (pkt_stream->current_pkt_nb < pkt_stream->nb_pkts) { (*pkts_sent)++; - if (pkt_stream->pkts[pkt_stream->rx_pkt_nb].valid) - return &pkt_stream->pkts[pkt_stream->rx_pkt_nb++]; - pkt_stream->rx_pkt_nb++; + if (pkt_stream->pkts[pkt_stream->current_pkt_nb].valid) + return &pkt_stream->pkts[pkt_stream->current_pkt_nb++]; + pkt_stream->current_pkt_nb++; } return NULL; } @@ -584,9 +584,9 @@ static void pkt_stream_receive_half(struct test_spec *test) pkt_stream->pkts[i].valid = false; } -static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) +static struct pkt *pkt_generate(struct ifobject *ifobject) { - struct pkt *pkt = pkt_stream_get_pkt(ifobject->pkt_stream, pkt_nb); + struct pkt *pkt = pkt_stream_get_next_tx_pkt(ifobject->pkt_stream); struct ethhdr *eth_hdr; void *data; @@ -599,7 +599,7 @@ static struct pkt *pkt_generate(struct ifobject *ifobject, u32 pkt_nb) eth_hdr = data; gen_eth_hdr(ifobject, eth_hdr); - write_payload(data + PKT_HDR_SIZE, pkt_nb, pkt->len - PKT_HDR_SIZE); + write_payload(data + PKT_HDR_SIZE, pkt->pkt_nb, pkt->len - PKT_HDR_SIZE); return pkt; } @@ -883,8 +883,7 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds) return TEST_PASS; } -static int __send_pkts(struct ifobject *ifobject, u32 *pkt_nb, struct pollfd *fds, - bool timeout) +static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeout) { struct xsk_socket_info *xsk = ifobject->xsk; bool use_poll = ifobject->use_poll; @@ -916,14 +915,13 @@ static int __send_pkts(struct ifobject *ifobject, u32 *pkt_nb, struct pollfd *fd for (i = 0; i < BATCH_SIZE; i++) { struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i); - struct pkt *pkt = pkt_generate(ifobject, *pkt_nb); + struct pkt *pkt = pkt_generate(ifobject); if (!pkt) break; tx_desc->addr = pkt->addr; tx_desc->len = pkt->len; - (*pkt_nb)++; if (pkt->valid) valid_pkts++; } @@ -970,15 +968,16 @@ static void wait_for_tx_completion(struct xsk_socket_info *xsk) static int send_pkts(struct test_spec *test, struct ifobject *ifobject) { + struct pkt_stream *pkt_stream = ifobject->pkt_stream; bool timeout = !is_umem_valid(test->ifobj_rx); struct pollfd fds = { }; - u32 pkt_cnt = 0, ret; + u32 ret; fds.fd = xsk_socket__fd(ifobject->xsk->xsk); fds.events = POLLOUT; - while (pkt_cnt < ifobject->pkt_stream->nb_pkts) { - ret = __send_pkts(ifobject, &pkt_cnt, &fds, timeout); + while (pkt_stream->current_pkt_nb < pkt_stream->nb_pkts) { + ret = __send_pkts(ifobject, &fds, timeout); if ((ret || test->fail) && !timeout) return TEST_FAILURE; else if (ret == TEST_PASS && timeout) @@ -1150,7 +1149,7 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream u64 addr; if (pkt_stream->use_addr_for_fill) { - struct pkt *pkt = pkt_stream_get_pkt(pkt_stream, i); + struct pkt *pkt = pkt_stream_get_next_tx_pkt(pkt_stream); if (!pkt) break; @@ -1162,6 +1161,8 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; } xsk_ring_prod__submit(&umem->fq, i); + + pkt_stream_reset(pkt_stream); } static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) @@ -1339,9 +1340,11 @@ static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *i { pthread_t t0, t1; - if (ifobj2) + if (ifobj2) { if (pthread_barrier_init(&barr, NULL, 2)) exit_with_error(errno); + pkt_stream_reset(ifobj2->pkt_stream); + } test->current_step++; pkt_stream_reset(ifobj1->pkt_stream); diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 5e0be9685557..7ea28d844007 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -117,7 +117,7 @@ struct pkt { struct pkt_stream { u32 nb_pkts; - u32 rx_pkt_nb; + u32 current_pkt_nb; struct pkt *pkts; bool use_addr_for_fill; }; -- cgit v1.2.3 From d9f6d9709f87236f9a33de0d42dae8402b812e19 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:05 +0200 Subject: selftests/xsk: store offset in pkt instead of addr Store the offset in struct pkt instead of the address. This is important since address is only meaningful in the context of a packet that is stored in a single umem buffer and thus a single Tx descriptor. If the packet, in contrast need to be represented by multiple buffers in the umem, storing the address makes no sense since the packet will consist of multiple buffers in the umem at various addresses. This change is in preparation for the upcoming multi-buffer support in AF_XDP and the corresponding tests. So instead of indicating the address, we instead indicate the offset of the packet in the first buffer. The actual address of the buffer is allocated from the umem with a new function called umem_alloc_buffer(). This also means we can get rid of the use_fill_for_addr flag as the addresses fed into the fill ring will always be the offset from the pkt specification in the packet stream plus the address of the allocated buffer from the umem. No special casing needed. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-7-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 150 ++++++++++++++++++------------- tools/testing/selftests/bpf/xskxceiver.h | 4 +- 2 files changed, 90 insertions(+), 64 deletions(-) diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index 0823890c0709..d488d859d3a2 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -167,7 +167,13 @@ static u32 mode_to_xdp_flags(enum test_mode mode) return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; } -static int xsk_configure_umem(struct xsk_umem_info *umem, void *buffer, u64 size) +static u64 umem_size(struct xsk_umem_info *umem) +{ + return umem->num_frames * umem->frame_size; +} + +static int xsk_configure_umem(struct ifobject *ifobj, struct xsk_umem_info *umem, void *buffer, + u64 size) { struct xsk_umem_config cfg = { .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, @@ -187,9 +193,31 @@ static int xsk_configure_umem(struct xsk_umem_info *umem, void *buffer, u64 size return ret; umem->buffer = buffer; + if (ifobj->shared_umem && ifobj->rx_on) { + umem->base_addr = umem_size(umem); + umem->next_buffer = umem_size(umem); + } + return 0; } +static u64 umem_alloc_buffer(struct xsk_umem_info *umem) +{ + u64 addr; + + addr = umem->next_buffer; + umem->next_buffer += umem->frame_size; + if (umem->next_buffer >= umem->base_addr + umem_size(umem)) + umem->next_buffer = umem->base_addr; + + return addr; +} + +static void umem_reset_alloc(struct xsk_umem_info *umem) +{ + umem->next_buffer = 0; +} + static void enable_busy_poll(struct xsk_socket_info *xsk) { int sock_opt; @@ -249,7 +277,7 @@ static bool ifobj_zc_avail(struct ifobject *ifobject) exit_with_error(ENOMEM); } umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; - ret = xsk_configure_umem(umem, bufs, umem_sz); + ret = xsk_configure_umem(ifobject, umem, bufs, umem_sz); if (ret) exit_with_error(-ret); @@ -372,9 +400,6 @@ static void __test_spec_init(struct test_spec *test, struct ifobject *ifobj_tx, memset(ifobj->umem, 0, sizeof(*ifobj->umem)); ifobj->umem->num_frames = DEFAULT_UMEM_BUFFERS; ifobj->umem->frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE; - if (ifobj->shared_umem && ifobj->rx_on) - ifobj->umem->base_addr = DEFAULT_UMEM_BUFFERS * - XSK_UMEM__DEFAULT_FRAME_SIZE; for (j = 0; j < MAX_SOCKETS; j++) { memset(&ifobj->xsk_arr[j], 0, sizeof(ifobj->xsk_arr[j])); @@ -506,9 +531,9 @@ static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts) return pkt_stream; } -static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr, u32 len) +static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, int offset, u32 len) { - pkt->addr = addr + umem->base_addr; + pkt->offset = offset; pkt->len = len; if (len > umem->frame_size - XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 2 - umem->frame_headroom) pkt->valid = false; @@ -526,8 +551,7 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb exit_with_error(ENOMEM); for (i = 0; i < nb_pkts; i++) { - pkt_set(umem, &pkt_stream->pkts[i], (i % umem->num_frames) * umem->frame_size, - pkt_len); + pkt_set(umem, &pkt_stream->pkts[i], 0, pkt_len); pkt_stream->pkts[i].pkt_nb = i; } @@ -559,8 +583,7 @@ static void __pkt_stream_replace_half(struct ifobject *ifobj, u32 pkt_len, pkt_stream = pkt_stream_clone(umem, ifobj->pkt_stream); for (i = 1; i < ifobj->pkt_stream->nb_pkts; i += 2) - pkt_set(umem, &pkt_stream->pkts[i], - (i % umem->num_frames) * umem->frame_size + offset, pkt_len); + pkt_set(umem, &pkt_stream->pkts[i], offset, pkt_len); ifobj->pkt_stream = pkt_stream; } @@ -584,24 +607,26 @@ static void pkt_stream_receive_half(struct test_spec *test) pkt_stream->pkts[i].valid = false; } -static struct pkt *pkt_generate(struct ifobject *ifobject) +static u64 pkt_get_addr(struct pkt *pkt, struct xsk_umem_info *umem) +{ + if (!pkt->valid) + return pkt->offset; + return pkt->offset + umem_alloc_buffer(umem); +} + +static void pkt_generate(struct ifobject *ifobject, struct pkt *pkt, u64 addr) { - struct pkt *pkt = pkt_stream_get_next_tx_pkt(ifobject->pkt_stream); struct ethhdr *eth_hdr; void *data; - if (!pkt) - return NULL; if (!pkt->valid || pkt->len < MIN_PKT_SIZE) - return pkt; + return; - data = xsk_umem__get_data(ifobject->umem->buffer, pkt->addr); + data = xsk_umem__get_data(ifobject->umem->buffer, addr); eth_hdr = data; gen_eth_hdr(ifobject, eth_hdr); write_payload(data + PKT_HDR_SIZE, pkt->pkt_nb, pkt->len - PKT_HDR_SIZE); - - return pkt; } static void __pkt_stream_generate_custom(struct ifobject *ifobj, @@ -615,7 +640,7 @@ static void __pkt_stream_generate_custom(struct ifobject *ifobj, exit_with_error(ENOMEM); for (i = 0; i < nb_pkts; i++) { - pkt_stream->pkts[i].addr = pkts[i].addr + ifobj->umem->base_addr; + pkt_stream->pkts[i].offset = pkts[i].offset; pkt_stream->pkts[i].len = pkts[i].len; pkt_stream->pkts[i].pkt_nb = i; pkt_stream->pkts[i].valid = pkts[i].valid; @@ -670,16 +695,16 @@ static void pkt_dump(void *pkt, u32 len) fprintf(stdout, "\n---------------------------------------\n"); } -static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, u64 addr, - u64 pkt_stream_addr) +static bool is_offset_correct(struct xsk_umem_info *umem, struct pkt *pkt, u64 addr) { u32 headroom = umem->unaligned_mode ? 0 : umem->frame_headroom; - u32 offset = addr % umem->frame_size, expected_offset = 0; + u32 offset = addr % umem->frame_size, expected_offset; + int pkt_offset = pkt->valid ? pkt->offset : 0; - if (!pkt_stream->use_addr_for_fill) - pkt_stream_addr = 0; + if (!umem->unaligned_mode) + pkt_offset = 0; - expected_offset += (pkt_stream_addr + headroom + XDP_PACKET_HEADROOM) % umem->frame_size; + expected_offset = (pkt_offset + headroom + XDP_PACKET_HEADROOM) % umem->frame_size; if (offset == expected_offset) return true; @@ -858,7 +883,7 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds) addr = xsk_umem__add_offset_to_addr(addr); if (!is_pkt_valid(pkt, umem->buffer, addr, desc->len) || - !is_offset_correct(umem, pkt_stream, addr, pkt->addr) || + !is_offset_correct(umem, pkt, addr) || (ifobj->use_metadata && !is_metadata_correct(pkt, umem->buffer, addr))) return TEST_FAILURE; @@ -915,15 +940,16 @@ static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeo for (i = 0; i < BATCH_SIZE; i++) { struct xdp_desc *tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx + i); - struct pkt *pkt = pkt_generate(ifobject); + struct pkt *pkt = pkt_stream_get_next_tx_pkt(ifobject->pkt_stream); if (!pkt) break; - tx_desc->addr = pkt->addr; + tx_desc->addr = pkt_get_addr(pkt, ifobject->umem); tx_desc->len = pkt->len; if (pkt->valid) valid_pkts++; + pkt_generate(ifobject, pkt, tx_desc->addr); } pthread_mutex_lock(&pacing_mutex); @@ -1130,11 +1156,12 @@ static void thread_common_ops_tx(struct test_spec *test, struct ifobject *ifobje ifobject->xsk = &ifobject->xsk_arr[0]; ifobject->xskmap = test->ifobj_rx->xskmap; memcpy(ifobject->umem, test->ifobj_rx->umem, sizeof(struct xsk_umem_info)); + ifobject->umem->base_addr = 0; } static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream) { - u32 idx = 0, i, buffers_to_fill; + u32 idx = 0, i, buffers_to_fill, nb_pkts; int ret; if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS) @@ -1145,24 +1172,23 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream ret = xsk_ring_prod__reserve(&umem->fq, buffers_to_fill, &idx); if (ret != buffers_to_fill) exit_with_error(ENOSPC); + for (i = 0; i < buffers_to_fill; i++) { + struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &nb_pkts); u64 addr; - if (pkt_stream->use_addr_for_fill) { - struct pkt *pkt = pkt_stream_get_next_tx_pkt(pkt_stream); - - if (!pkt) - break; - addr = pkt->addr; - } else { - addr = i * umem->frame_size; - } - + if (!pkt) + addr = i * umem->frame_size + umem->base_addr; + else if (pkt->offset >= 0) + addr = pkt->offset % umem->frame_size + umem_alloc_buffer(umem); + else + addr = pkt->offset + umem_alloc_buffer(umem); *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; } xsk_ring_prod__submit(&umem->fq, i); pkt_stream_reset(pkt_stream); + umem_reset_alloc(umem); } static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) @@ -1183,12 +1209,10 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) if (bufs == MAP_FAILED) exit_with_error(errno); - ret = xsk_configure_umem(ifobject->umem, bufs, umem_sz); + ret = xsk_configure_umem(ifobject, ifobject->umem, bufs, umem_sz); if (ret) exit_with_error(-ret); - xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream); - xsk_configure_socket(test, ifobject, ifobject->umem, false); ifobject->xsk = &ifobject->xsk_arr[0]; @@ -1196,6 +1220,8 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) if (!ifobject->rx_on) return; + xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream); + ret = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk); if (ret) exit_with_error(errno); @@ -1543,9 +1569,8 @@ static bool testapp_unaligned(struct test_spec *test) test_spec_set_name(test, "UNALIGNED_MODE"); test->ifobj_tx->umem->unaligned_mode = true; test->ifobj_rx->umem->unaligned_mode = true; - /* Let half of the packets straddle a buffer boundrary */ + /* Let half of the packets straddle a 4K buffer boundary */ pkt_stream_replace_half(test, MIN_PKT_SIZE, -MIN_PKT_SIZE / 2); - test->ifobj_rx->pkt_stream->use_addr_for_fill = true; testapp_validate_traffic(test); return true; @@ -1553,7 +1578,7 @@ static bool testapp_unaligned(struct test_spec *test) static void testapp_single_pkt(struct test_spec *test) { - struct pkt pkts[] = {{0x1000, MIN_PKT_SIZE, 0, true}}; + struct pkt pkts[] = {{0, MIN_PKT_SIZE, 0, true}}; pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); testapp_validate_traffic(test); @@ -1561,42 +1586,43 @@ static void testapp_single_pkt(struct test_spec *test) static void testapp_invalid_desc(struct test_spec *test) { - u64 umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; + struct xsk_umem_info *umem = test->ifobj_tx->umem; + u64 umem_size = umem->num_frames * umem->frame_size; struct pkt pkts[] = { /* Zero packet address allowed */ {0, MIN_PKT_SIZE, 0, true}, /* Allowed packet */ - {0x1000, MIN_PKT_SIZE, 0, true}, + {0, MIN_PKT_SIZE, 0, true}, /* Straddling the start of umem */ {-2, MIN_PKT_SIZE, 0, false}, /* Packet too large */ - {0x2000, XSK_UMEM__INVALID_FRAME_SIZE, 0, false}, + {0, XSK_UMEM__INVALID_FRAME_SIZE, 0, false}, /* Up to end of umem allowed */ - {umem_size - MIN_PKT_SIZE, MIN_PKT_SIZE, 0, true}, + {umem_size - MIN_PKT_SIZE - 2 * umem->frame_size, MIN_PKT_SIZE, 0, true}, /* After umem ends */ {umem_size, MIN_PKT_SIZE, 0, false}, /* Straddle the end of umem */ {umem_size - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, - /* Straddle a page boundrary */ - {0x3000 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, - /* Straddle a 2K boundrary */ - {0x3800 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, true}, + /* Straddle a 4K boundary */ + {0x1000 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, false}, + /* Straddle a 2K boundary */ + {0x800 - MIN_PKT_SIZE / 2, MIN_PKT_SIZE, 0, true}, /* Valid packet for synch so that something is received */ - {0x4000, MIN_PKT_SIZE, 0, true}}; + {0, MIN_PKT_SIZE, 0, true}}; - if (test->ifobj_tx->umem->unaligned_mode) { - /* Crossing a page boundrary allowed */ + if (umem->unaligned_mode) { + /* Crossing a page boundary allowed */ pkts[7].valid = true; } - if (test->ifobj_tx->umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) { - /* Crossing a 2K frame size boundrary not allowed */ + if (umem->frame_size == XSK_UMEM__DEFAULT_FRAME_SIZE / 2) { + /* Crossing a 2K frame size boundary not allowed */ pkts[8].valid = false; } if (test->ifobj_tx->shared_umem) { - pkts[4].addr += umem_size; - pkts[5].addr += umem_size; - pkts[6].addr += umem_size; + pkts[4].offset += umem_size; + pkts[5].offset += umem_size; + pkts[6].offset += umem_size; } pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 7ea28d844007..be4664a38d74 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -91,6 +91,7 @@ struct xsk_umem_info { struct xsk_ring_prod fq; struct xsk_ring_cons cq; struct xsk_umem *umem; + u64 next_buffer; u32 num_frames; u32 frame_headroom; void *buffer; @@ -109,7 +110,7 @@ struct xsk_socket_info { }; struct pkt { - u64 addr; + int offset; u32 len; u32 pkt_nb; bool valid; @@ -119,7 +120,6 @@ struct pkt_stream { u32 nb_pkts; u32 current_pkt_nb; struct pkt *pkts; - bool use_addr_for_fill; }; struct ifobject; -- cgit v1.2.3 From 041b68f688a38865434d7b8fbfe64beb03e54ff2 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:06 +0200 Subject: selftests/xsx: test for huge pages only once Test for hugepages only once at the beginning of the execution of the whole test suite, instead of before each test that needs huge pages. These are the tests that use unaligned mode. As more unaligned tests will be added, so the current system just does not scale. With this change, there are now three possible outcomes of a test run: fail, pass, or skip. To simplify the handling of this, the function testapp_validate_traffic() now returns this value to the main loop. As this function is used by nearly all tests, it meant a small change to most of them. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-8-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 186 +++++++++++++++---------------- tools/testing/selftests/bpf/xskxceiver.h | 2 + 2 files changed, 94 insertions(+), 94 deletions(-) diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index d488d859d3a2..f0d929cb730a 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -1413,6 +1413,12 @@ static int testapp_validate_traffic(struct test_spec *test) struct ifobject *ifobj_rx = test->ifobj_rx; struct ifobject *ifobj_tx = test->ifobj_tx; + if ((ifobj_rx->umem->unaligned_mode && !ifobj_rx->unaligned_supp) || + (ifobj_tx->umem->unaligned_mode && !ifobj_tx->unaligned_supp)) { + ksft_test_result_skip("No huge pages present.\n"); + return TEST_SKIP; + } + xsk_attach_xdp_progs(test, ifobj_rx, ifobj_tx); return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx); } @@ -1422,16 +1428,18 @@ static int testapp_validate_traffic_single_thread(struct test_spec *test, struct return __testapp_validate_traffic(test, ifobj, NULL); } -static void testapp_teardown(struct test_spec *test) +static int testapp_teardown(struct test_spec *test) { int i; test_spec_set_name(test, "TEARDOWN"); for (i = 0; i < MAX_TEARDOWN_ITER; i++) { if (testapp_validate_traffic(test)) - return; + return TEST_FAILURE; test_spec_reset(test); } + + return TEST_PASS; } static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2) @@ -1446,20 +1454,23 @@ static void swap_directions(struct ifobject **ifobj1, struct ifobject **ifobj2) *ifobj2 = tmp_ifobj; } -static void testapp_bidi(struct test_spec *test) +static int testapp_bidi(struct test_spec *test) { + int res; + test_spec_set_name(test, "BIDIRECTIONAL"); test->ifobj_tx->rx_on = true; test->ifobj_rx->tx_on = true; test->total_steps = 2; if (testapp_validate_traffic(test)) - return; + return TEST_FAILURE; print_verbose("Switching Tx/Rx vectors\n"); swap_directions(&test->ifobj_rx, &test->ifobj_tx); - __testapp_validate_traffic(test, test->ifobj_rx, test->ifobj_tx); + res = __testapp_validate_traffic(test, test->ifobj_rx, test->ifobj_tx); swap_directions(&test->ifobj_rx, &test->ifobj_tx); + return res; } static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj_rx) @@ -1476,115 +1487,94 @@ static void swap_xsk_resources(struct ifobject *ifobj_tx, struct ifobject *ifobj exit_with_error(errno); } -static void testapp_bpf_res(struct test_spec *test) +static int testapp_bpf_res(struct test_spec *test) { test_spec_set_name(test, "BPF_RES"); test->total_steps = 2; test->nb_sockets = 2; if (testapp_validate_traffic(test)) - return; + return TEST_FAILURE; swap_xsk_resources(test->ifobj_tx, test->ifobj_rx); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_headroom(struct test_spec *test) +static int testapp_headroom(struct test_spec *test) { test_spec_set_name(test, "UMEM_HEADROOM"); test->ifobj_rx->umem->frame_headroom = UMEM_HEADROOM_TEST_SIZE; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_stats_rx_dropped(struct test_spec *test) +static int testapp_stats_rx_dropped(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_DROPPED"); + if (test->mode == TEST_MODE_ZC) { + ksft_test_result_skip("Can not run RX_DROPPED test for ZC mode\n"); + return TEST_SKIP; + } + pkt_stream_replace_half(test, MIN_PKT_SIZE * 4, 0); test->ifobj_rx->umem->frame_headroom = test->ifobj_rx->umem->frame_size - XDP_PACKET_HEADROOM - MIN_PKT_SIZE * 3; pkt_stream_receive_half(test); test->ifobj_rx->validation_func = validate_rx_dropped; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_stats_tx_invalid_descs(struct test_spec *test) +static int testapp_stats_tx_invalid_descs(struct test_spec *test) { test_spec_set_name(test, "STAT_TX_INVALID"); pkt_stream_replace_half(test, XSK_UMEM__INVALID_FRAME_SIZE, 0); test->ifobj_tx->validation_func = validate_tx_invalid_descs; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_stats_rx_full(struct test_spec *test) +static int testapp_stats_rx_full(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_FULL"); pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); - if (!test->ifobj_rx->pkt_stream) - exit_with_error(ENOMEM); test->ifobj_rx->xsk->rxqsize = DEFAULT_UMEM_BUFFERS; test->ifobj_rx->release_rx = false; test->ifobj_rx->validation_func = validate_rx_full; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_stats_fill_empty(struct test_spec *test) +static int testapp_stats_fill_empty(struct test_spec *test) { test_spec_set_name(test, "STAT_RX_FILL_EMPTY"); pkt_stream_replace(test, DEFAULT_UMEM_BUFFERS + DEFAULT_UMEM_BUFFERS / 2, MIN_PKT_SIZE); test->ifobj_rx->pkt_stream = pkt_stream_generate(test->ifobj_rx->umem, DEFAULT_UMEM_BUFFERS, MIN_PKT_SIZE); - if (!test->ifobj_rx->pkt_stream) - exit_with_error(ENOMEM); test->ifobj_rx->use_fill_ring = false; test->ifobj_rx->validation_func = validate_fill_empty; - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -/* Simple test */ -static bool hugepages_present(struct ifobject *ifobject) +static int testapp_unaligned(struct test_spec *test) { - size_t mmap_sz = 2 * ifobject->umem->num_frames * ifobject->umem->frame_size; - void *bufs; - - bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_HUGE_2MB, -1, 0); - if (bufs == MAP_FAILED) - return false; - - mmap_sz = ceil_u64(mmap_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE; - munmap(bufs, mmap_sz); - return true; -} - -static bool testapp_unaligned(struct test_spec *test) -{ - if (!hugepages_present(test->ifobj_tx)) { - ksft_test_result_skip("No 2M huge pages present.\n"); - return false; - } - test_spec_set_name(test, "UNALIGNED_MODE"); test->ifobj_tx->umem->unaligned_mode = true; test->ifobj_rx->umem->unaligned_mode = true; /* Let half of the packets straddle a 4K buffer boundary */ pkt_stream_replace_half(test, MIN_PKT_SIZE, -MIN_PKT_SIZE / 2); - testapp_validate_traffic(test); - return true; + return testapp_validate_traffic(test); } -static void testapp_single_pkt(struct test_spec *test) +static int testapp_single_pkt(struct test_spec *test) { struct pkt pkts[] = {{0, MIN_PKT_SIZE, 0, true}}; pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_invalid_desc(struct test_spec *test) +static int testapp_invalid_desc(struct test_spec *test) { struct xsk_umem_info *umem = test->ifobj_tx->umem; u64 umem_size = umem->num_frames * umem->frame_size; @@ -1626,10 +1616,10 @@ static void testapp_invalid_desc(struct test_spec *test) } pkt_stream_generate_custom(test, pkts, ARRAY_SIZE(pkts)); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_xdp_drop(struct test_spec *test) +static int testapp_xdp_drop(struct test_spec *test) { struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; @@ -1639,10 +1629,10 @@ static void testapp_xdp_drop(struct test_spec *test) skel_rx->maps.xsk, skel_tx->maps.xsk); pkt_stream_receive_half(test); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_xdp_metadata_count(struct test_spec *test) +static int testapp_xdp_metadata_count(struct test_spec *test) { struct xsk_xdp_progs *skel_rx = test->ifobj_rx->xdp_progs; struct xsk_xdp_progs *skel_tx = test->ifobj_tx->xdp_progs; @@ -1663,10 +1653,10 @@ static void testapp_xdp_metadata_count(struct test_spec *test) if (bpf_map_update_elem(bpf_map__fd(data_map), &key, &count, BPF_ANY)) exit_with_error(errno); - testapp_validate_traffic(test); + return testapp_validate_traffic(test); } -static void testapp_poll_txq_tmout(struct test_spec *test) +static int testapp_poll_txq_tmout(struct test_spec *test) { test_spec_set_name(test, "POLL_TXQ_FULL"); @@ -1674,14 +1664,14 @@ static void testapp_poll_txq_tmout(struct test_spec *test) /* create invalid frame by set umem frame_size and pkt length equal to 2048 */ test->ifobj_tx->umem->frame_size = 2048; pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048); - testapp_validate_traffic_single_thread(test, test->ifobj_tx); + return testapp_validate_traffic_single_thread(test, test->ifobj_tx); } -static void testapp_poll_rxq_tmout(struct test_spec *test) +static int testapp_poll_rxq_tmout(struct test_spec *test) { test_spec_set_name(test, "POLL_RXQ_EMPTY"); test->ifobj_rx->use_poll = true; - testapp_validate_traffic_single_thread(test, test->ifobj_rx); + return testapp_validate_traffic_single_thread(test, test->ifobj_rx); } static int xsk_load_xdp_programs(struct ifobject *ifobj) @@ -1698,6 +1688,22 @@ static void xsk_unload_xdp_programs(struct ifobject *ifobj) xsk_xdp_progs__destroy(ifobj->xdp_progs); } +/* Simple test */ +static bool hugepages_present(void) +{ + size_t mmap_sz = 2 * DEFAULT_UMEM_BUFFERS * XSK_UMEM__DEFAULT_FRAME_SIZE; + void *bufs; + + bufs = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, MAP_HUGE_2MB); + if (bufs == MAP_FAILED) + return false; + + mmap_sz = ceil_u64(mmap_sz, HUGEPAGE_SIZE) * HUGEPAGE_SIZE; + munmap(bufs, mmap_sz); + return true; +} + static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char *src_mac, thread_func_t func_ptr) { @@ -1713,94 +1719,87 @@ static void init_iface(struct ifobject *ifobj, const char *dst_mac, const char * printf("Error loading XDP program\n"); exit_with_error(err); } + + if (hugepages_present()) + ifobj->unaligned_supp = true; } static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_type type) { + int ret = TEST_SKIP; + switch (type) { case TEST_TYPE_STATS_RX_DROPPED: - if (mode == TEST_MODE_ZC) { - ksft_test_result_skip("Can not run RX_DROPPED test for ZC mode\n"); - return; - } - testapp_stats_rx_dropped(test); + ret = testapp_stats_rx_dropped(test); break; case TEST_TYPE_STATS_TX_INVALID_DESCS: - testapp_stats_tx_invalid_descs(test); + ret = testapp_stats_tx_invalid_descs(test); break; case TEST_TYPE_STATS_RX_FULL: - testapp_stats_rx_full(test); + ret = testapp_stats_rx_full(test); break; case TEST_TYPE_STATS_FILL_EMPTY: - testapp_stats_fill_empty(test); + ret = testapp_stats_fill_empty(test); break; case TEST_TYPE_TEARDOWN: - testapp_teardown(test); + ret = testapp_teardown(test); break; case TEST_TYPE_BIDI: - testapp_bidi(test); + ret = testapp_bidi(test); break; case TEST_TYPE_BPF_RES: - testapp_bpf_res(test); + ret = testapp_bpf_res(test); break; case TEST_TYPE_RUN_TO_COMPLETION: test_spec_set_name(test, "RUN_TO_COMPLETION"); - testapp_validate_traffic(test); + ret = testapp_validate_traffic(test); break; case TEST_TYPE_RUN_TO_COMPLETION_SINGLE_PKT: test_spec_set_name(test, "RUN_TO_COMPLETION_SINGLE_PKT"); - testapp_single_pkt(test); + ret = testapp_single_pkt(test); break; case TEST_TYPE_RUN_TO_COMPLETION_2K_FRAME: test_spec_set_name(test, "RUN_TO_COMPLETION_2K_FRAME_SIZE"); test->ifobj_tx->umem->frame_size = 2048; test->ifobj_rx->umem->frame_size = 2048; pkt_stream_replace(test, DEFAULT_PKT_CNT, MIN_PKT_SIZE); - testapp_validate_traffic(test); + ret = testapp_validate_traffic(test); break; case TEST_TYPE_RX_POLL: test->ifobj_rx->use_poll = true; test_spec_set_name(test, "POLL_RX"); - testapp_validate_traffic(test); + ret = testapp_validate_traffic(test); break; case TEST_TYPE_TX_POLL: test->ifobj_tx->use_poll = true; test_spec_set_name(test, "POLL_TX"); - testapp_validate_traffic(test); + ret = testapp_validate_traffic(test); break; case TEST_TYPE_POLL_TXQ_TMOUT: - testapp_poll_txq_tmout(test); + ret = testapp_poll_txq_tmout(test); break; case TEST_TYPE_POLL_RXQ_TMOUT: - testapp_poll_rxq_tmout(test); + ret = testapp_poll_rxq_tmout(test); break; case TEST_TYPE_ALIGNED_INV_DESC: test_spec_set_name(test, "ALIGNED_INV_DESC"); - testapp_invalid_desc(test); + ret = testapp_invalid_desc(test); break; case TEST_TYPE_ALIGNED_INV_DESC_2K_FRAME: test_spec_set_name(test, "ALIGNED_INV_DESC_2K_FRAME_SIZE"); test->ifobj_tx->umem->frame_size = 2048; test->ifobj_rx->umem->frame_size = 2048; - testapp_invalid_desc(test); + ret = testapp_invalid_desc(test); break; case TEST_TYPE_UNALIGNED_INV_DESC: - if (!hugepages_present(test->ifobj_tx)) { - ksft_test_result_skip("No 2M huge pages present.\n"); - return; - } test_spec_set_name(test, "UNALIGNED_INV_DESC"); test->ifobj_tx->umem->unaligned_mode = true; test->ifobj_rx->umem->unaligned_mode = true; - testapp_invalid_desc(test); + ret = testapp_invalid_desc(test); break; case TEST_TYPE_UNALIGNED_INV_DESC_4K1_FRAME: { u64 page_size, umem_size; - if (!hugepages_present(test->ifobj_tx)) { - ksft_test_result_skip("No 2M huge pages present.\n"); - return; - } test_spec_set_name(test, "UNALIGNED_INV_DESC_4K1_FRAME_SIZE"); /* Odd frame size so the UMEM doesn't end near a page boundary. */ test->ifobj_tx->umem->frame_size = 4001; @@ -1814,27 +1813,26 @@ static void run_pkt_test(struct test_spec *test, enum test_mode mode, enum test_ umem_size = test->ifobj_tx->umem->num_frames * test->ifobj_tx->umem->frame_size; assert(umem_size % page_size > MIN_PKT_SIZE); assert(umem_size % page_size < page_size - MIN_PKT_SIZE); - testapp_invalid_desc(test); + ret = testapp_invalid_desc(test); break; } case TEST_TYPE_UNALIGNED: - if (!testapp_unaligned(test)) - return; + ret = testapp_unaligned(test); break; case TEST_TYPE_HEADROOM: - testapp_headroom(test); + ret = testapp_headroom(test); break; case TEST_TYPE_XDP_DROP_HALF: - testapp_xdp_drop(test); + ret = testapp_xdp_drop(test); break; case TEST_TYPE_XDP_METADATA_COUNT: - testapp_xdp_metadata_count(test); + ret = testapp_xdp_metadata_count(test); break; default: break; } - if (!test->fail) + if (ret == TEST_PASS) ksft_test_result_pass("PASS: %s %s%s\n", mode_string(test), busy_poll_string(test), test->name); pkt_stream_restore_default(test); diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index be4664a38d74..00862732e751 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -30,6 +30,7 @@ #define TEST_PASS 0 #define TEST_FAILURE -1 #define TEST_CONTINUE 1 +#define TEST_SKIP 2 #define MAX_INTERFACES 2 #define MAX_INTERFACE_NAME_CHARS 16 #define MAX_SOCKETS 2 @@ -148,6 +149,7 @@ struct ifobject { bool release_rx; bool shared_umem; bool use_metadata; + bool unaligned_supp; u8 dst_mac[ETH_ALEN]; u8 src_mac[ETH_ALEN]; }; -- cgit v1.2.3 From 86e41755b43227858ef04b452c25b9dbcf667622 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:07 +0200 Subject: selftests/xsk: populate fill ring based on frags needed Populate the fill ring based on the number of frags a packet needs. With multi-buffer support, a packet might require more than a single fragment/buffer, so the function xsk_populate_fill_ring() needs to consider how many buffers a packet will consume, and put that many buffers on the fill ring for each packet it should receive. As we are still not sending any multi-buffer packets, the function will only produce one buffer per packet at the moment. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-9-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xsk.h | 5 ++++ tools/testing/selftests/bpf/xskxceiver.c | 48 ++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/bpf/xsk.h b/tools/testing/selftests/bpf/xsk.h index 04ed8b544712..8da8d557768b 100644 --- a/tools/testing/selftests/bpf/xsk.h +++ b/tools/testing/selftests/bpf/xsk.h @@ -134,6 +134,11 @@ static inline void xsk_ring_prod__submit(struct xsk_ring_prod *prod, __u32 nb) __atomic_store_n(prod->producer, *prod->producer + nb, __ATOMIC_RELEASE); } +static inline void xsk_ring_prod__cancel(struct xsk_ring_prod *prod, __u32 nb) +{ + prod->cached_prod -= nb; +} + static inline __u32 xsk_ring_cons__peek(struct xsk_ring_cons *cons, __u32 nb, __u32 *idx) { __u32 entries = xsk_cons_nb_avail(cons, nb); diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index f0d929cb730a..c54f25dcf134 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -531,6 +531,18 @@ static struct pkt_stream *__pkt_stream_alloc(u32 nb_pkts) return pkt_stream; } +static u32 ceil_u32(u32 a, u32 b) +{ + return (a + b - 1) / b; +} + +static u32 pkt_nb_frags(u32 frame_size, struct pkt *pkt) +{ + if (!pkt || !pkt->valid) + return 1; + return ceil_u32(pkt->len, frame_size); +} + static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, int offset, u32 len) { pkt->offset = offset; @@ -1159,9 +1171,11 @@ static void thread_common_ops_tx(struct test_spec *test, struct ifobject *ifobje ifobject->umem->base_addr = 0; } -static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream) +static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream *pkt_stream, + bool fill_up) { - u32 idx = 0, i, buffers_to_fill, nb_pkts; + u32 rx_frame_size = umem->frame_size - XDP_PACKET_HEADROOM; + u32 idx = 0, filled = 0, buffers_to_fill, nb_pkts; int ret; if (umem->num_frames < XSK_RING_PROD__DEFAULT_NUM_DESCS) @@ -1173,19 +1187,29 @@ static void xsk_populate_fill_ring(struct xsk_umem_info *umem, struct pkt_stream if (ret != buffers_to_fill) exit_with_error(ENOSPC); - for (i = 0; i < buffers_to_fill; i++) { + while (filled < buffers_to_fill) { struct pkt *pkt = pkt_stream_get_next_rx_pkt(pkt_stream, &nb_pkts); u64 addr; + u32 i; + + for (i = 0; i < pkt_nb_frags(rx_frame_size, pkt); i++) { + if (!pkt) { + if (!fill_up) + break; + addr = filled * umem->frame_size + umem->base_addr; + } else if (pkt->offset >= 0) { + addr = pkt->offset % umem->frame_size + umem_alloc_buffer(umem); + } else { + addr = pkt->offset + umem_alloc_buffer(umem); + } - if (!pkt) - addr = i * umem->frame_size + umem->base_addr; - else if (pkt->offset >= 0) - addr = pkt->offset % umem->frame_size + umem_alloc_buffer(umem); - else - addr = pkt->offset + umem_alloc_buffer(umem); - *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; + *xsk_ring_prod__fill_addr(&umem->fq, idx++) = addr; + if (++filled >= buffers_to_fill) + break; + } } - xsk_ring_prod__submit(&umem->fq, i); + xsk_ring_prod__submit(&umem->fq, filled); + xsk_ring_prod__cancel(&umem->fq, buffers_to_fill - filled); pkt_stream_reset(pkt_stream); umem_reset_alloc(umem); @@ -1220,7 +1244,7 @@ static void thread_common_ops(struct test_spec *test, struct ifobject *ifobject) if (!ifobject->rx_on) return; - xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream); + xsk_populate_fill_ring(ifobject->umem, ifobject->pkt_stream, ifobject->use_fill_ring); ret = xsk_update_xskmap(ifobject->xskmap, ifobject->xsk->xsk); if (ret) -- cgit v1.2.3 From 2f6eae0df1a80bb636f43f1b954678da0a10fa49 Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:08 +0200 Subject: selftests/xsk: generate data for multi-buffer packets Add the ability to generate data in the packets that are correct for multi-buffer packets. The ethernet header should only go into the first fragment followed by data and the others should only have data. We also need to modify the pkt_dump function so that it knows what fragment has an ethernet header so it can print this. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-10-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 70 ++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index c54f25dcf134..b48017611499 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -142,12 +142,14 @@ static void report_failure(struct test_spec *test) * 16-bits and a intra packet data sequence number in the lower 16 bits. So the 3rd packet's * 5th word of data will contain the number (2<<16) | 4 as they are numbered from 0. */ -static void write_payload(void *dest, u32 val, u32 size) +static void write_payload(void *dest, u32 pkt_nb, u32 start, u32 size) { u32 *ptr = (u32 *)dest, i; - for (i = 0; i < size / sizeof(*ptr); i++) - ptr[i] = htonl(val << 16 | i); + start /= sizeof(*ptr); + size /= sizeof(*ptr); + for (i = 0; i < size; i++) + ptr[i] = htonl(pkt_nb << 16 | (i + start)); } static void gen_eth_hdr(struct ifobject *ifobject, struct ethhdr *eth_hdr) @@ -563,8 +565,10 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb exit_with_error(ENOMEM); for (i = 0; i < nb_pkts; i++) { - pkt_set(umem, &pkt_stream->pkts[i], 0, pkt_len); - pkt_stream->pkts[i].pkt_nb = i; + struct pkt *pkt = &pkt_stream->pkts[i]; + + pkt_set(umem, pkt, 0, pkt_len); + pkt->pkt_nb = i; } return pkt_stream; @@ -626,19 +630,24 @@ static u64 pkt_get_addr(struct pkt *pkt, struct xsk_umem_info *umem) return pkt->offset + umem_alloc_buffer(umem); } -static void pkt_generate(struct ifobject *ifobject, struct pkt *pkt, u64 addr) +static void pkt_generate(struct ifobject *ifobject, u64 addr, u32 len, u32 pkt_nb, + u32 bytes_written) { - struct ethhdr *eth_hdr; - void *data; + void *data = xsk_umem__get_data(ifobject->umem->buffer, addr); - if (!pkt->valid || pkt->len < MIN_PKT_SIZE) + if (len < MIN_PKT_SIZE) return; - data = xsk_umem__get_data(ifobject->umem->buffer, addr); - eth_hdr = data; + if (!bytes_written) { + gen_eth_hdr(ifobject, data); + + len -= PKT_HDR_SIZE; + data += PKT_HDR_SIZE; + } else { + bytes_written -= PKT_HDR_SIZE; + } - gen_eth_hdr(ifobject, eth_hdr); - write_payload(data + PKT_HDR_SIZE, pkt->pkt_nb, pkt->len - PKT_HDR_SIZE); + write_payload(data, pkt_nb, bytes_written, len); } static void __pkt_stream_generate_custom(struct ifobject *ifobj, @@ -681,27 +690,33 @@ static void pkt_print_data(u32 *data, u32 cnt) } } -static void pkt_dump(void *pkt, u32 len) +static void pkt_dump(void *pkt, u32 len, bool eth_header) { struct ethhdr *ethhdr = pkt; - u32 i; + u32 i, *data; - /*extract L2 frame */ - fprintf(stdout, "DEBUG>> L2: dst mac: "); - for (i = 0; i < ETH_ALEN; i++) - fprintf(stdout, "%02X", ethhdr->h_dest[i]); + if (eth_header) { + /*extract L2 frame */ + fprintf(stdout, "DEBUG>> L2: dst mac: "); + for (i = 0; i < ETH_ALEN; i++) + fprintf(stdout, "%02X", ethhdr->h_dest[i]); - fprintf(stdout, "\nDEBUG>> L2: src mac: "); - for (i = 0; i < ETH_ALEN; i++) - fprintf(stdout, "%02X", ethhdr->h_source[i]); + fprintf(stdout, "\nDEBUG>> L2: src mac: "); + for (i = 0; i < ETH_ALEN; i++) + fprintf(stdout, "%02X", ethhdr->h_source[i]); + + data = pkt + PKT_HDR_SIZE; + } else { + data = pkt; + } /*extract L5 frame */ fprintf(stdout, "\nDEBUG>> L5: seqnum: "); - pkt_print_data(pkt + PKT_HDR_SIZE, PKT_DUMP_NB_TO_PRINT); + pkt_print_data(data, PKT_DUMP_NB_TO_PRINT); fprintf(stdout, "...."); if (len > PKT_DUMP_NB_TO_PRINT * sizeof(u32)) { fprintf(stdout, "\n.... "); - pkt_print_data(pkt + PKT_HDR_SIZE + len - PKT_DUMP_NB_TO_PRINT * sizeof(u32), + pkt_print_data(data + len / sizeof(u32) - PKT_DUMP_NB_TO_PRINT, PKT_DUMP_NB_TO_PRINT); } fprintf(stdout, "\n---------------------------------------\n"); @@ -772,7 +787,7 @@ static bool is_pkt_valid(struct pkt *pkt, void *buffer, u64 addr, u32 len) return true; error: - pkt_dump(data, len); + pkt_dump(data, len, true); return false; } @@ -959,9 +974,10 @@ static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeo tx_desc->addr = pkt_get_addr(pkt, ifobject->umem); tx_desc->len = pkt->len; - if (pkt->valid) + if (pkt->valid) { valid_pkts++; - pkt_generate(ifobject, pkt, tx_desc->addr); + pkt_generate(ifobject, tx_desc->addr, tx_desc->len, pkt->pkt_nb, 0); + } } pthread_mutex_lock(&pacing_mutex); -- cgit v1.2.3 From 7cd6df4f5ec278888b4c3ab12b291c2124b46c1c Mon Sep 17 00:00:00 2001 From: Magnus Karlsson Date: Tue, 16 May 2023 12:31:09 +0200 Subject: selftests/xsk: adjust packet pacing for multi-buffer support Modify the packet pacing algorithm so that it works with multi-buffer packets. This algorithm makes sure we do not send too many buffers to the receiving thread so that packets have to be dropped. The previous algorithm made the assumption that each packet only consumes one buffer, but that is not true anymore when multi-buffer support gets added. Instead, we find out what the largest packet size is in the packet stream and assume that each packet will consume this many buffers. This is conservative and overly cautious as there might be smaller packets in the stream that need fewer buffers per packet. But it keeps the algorithm simple. Also simplify it by removing the pthread conditional and just test if there is enough space in the Rx thread before trying to send one more batch. Also makes the tests run faster. Signed-off-by: Magnus Karlsson Link: https://lore.kernel.org/r/20230516103109.3066-11-magnus.karlsson@gmail.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/xskxceiver.c | 48 +++++++++++++++++++------------- tools/testing/selftests/bpf/xskxceiver.h | 2 +- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index b48017611499..218d7f694e5c 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -555,6 +555,11 @@ static void pkt_set(struct xsk_umem_info *umem, struct pkt *pkt, int offset, u32 pkt->valid = true; } +static u32 pkt_get_buffer_len(struct xsk_umem_info *umem, u32 len) +{ + return ceil_u32(len, umem->frame_size) * umem->frame_size; +} + static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb_pkts, u32 pkt_len) { struct pkt_stream *pkt_stream; @@ -564,6 +569,8 @@ static struct pkt_stream *pkt_stream_generate(struct xsk_umem_info *umem, u32 nb if (!pkt_stream) exit_with_error(ENOMEM); + pkt_stream->nb_pkts = nb_pkts; + pkt_stream->max_pkt_len = pkt_len; for (i = 0; i < nb_pkts; i++) { struct pkt *pkt = &pkt_stream->pkts[i]; @@ -661,10 +668,14 @@ static void __pkt_stream_generate_custom(struct ifobject *ifobj, exit_with_error(ENOMEM); for (i = 0; i < nb_pkts; i++) { - pkt_stream->pkts[i].offset = pkts[i].offset; - pkt_stream->pkts[i].len = pkts[i].len; - pkt_stream->pkts[i].pkt_nb = i; - pkt_stream->pkts[i].valid = pkts[i].valid; + struct pkt *pkt = &pkt_stream->pkts[i]; + + pkt->offset = pkts[i].offset; + pkt->len = pkts[i].len; + pkt->pkt_nb = i; + pkt->valid = pkts[i].valid; + if (pkt->len > pkt_stream->max_pkt_len) + pkt_stream->max_pkt_len = pkt->len; } ifobj->pkt_stream = pkt_stream; @@ -926,8 +937,6 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds) pthread_mutex_lock(&pacing_mutex); pkts_in_flight -= pkts_sent; - if (pkts_in_flight < umem->num_frames) - pthread_cond_signal(&pacing_cond); pthread_mutex_unlock(&pacing_mutex); pkts_sent = 0; } @@ -938,10 +947,18 @@ static int receive_pkts(struct test_spec *test, struct pollfd *fds) static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeout) { struct xsk_socket_info *xsk = ifobject->xsk; + struct xsk_umem_info *umem = ifobject->umem; + u32 i, idx = 0, valid_pkts = 0, buffer_len; bool use_poll = ifobject->use_poll; - u32 i, idx = 0, valid_pkts = 0; int ret; + buffer_len = pkt_get_buffer_len(umem, ifobject->pkt_stream->max_pkt_len); + /* pkts_in_flight might be negative if many invalid packets are sent */ + if (pkts_in_flight >= (int)((umem_size(umem) - BATCH_SIZE * buffer_len) / buffer_len)) { + kick_tx(xsk); + return TEST_CONTINUE; + } + while (xsk_ring_prod__reserve(&xsk->tx, BATCH_SIZE, &idx) < BATCH_SIZE) { if (use_poll) { ret = poll(fds, 1, POLL_TMOUT); @@ -972,7 +989,7 @@ static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeo if (!pkt) break; - tx_desc->addr = pkt_get_addr(pkt, ifobject->umem); + tx_desc->addr = pkt_get_addr(pkt, umem); tx_desc->len = pkt->len; if (pkt->valid) { valid_pkts++; @@ -982,11 +999,6 @@ static int __send_pkts(struct ifobject *ifobject, struct pollfd *fds, bool timeo pthread_mutex_lock(&pacing_mutex); pkts_in_flight += valid_pkts; - /* pkts_in_flight might be negative if many invalid packets are sent */ - if (pkts_in_flight >= (int)(ifobject->umem->num_frames - BATCH_SIZE)) { - kick_tx(xsk); - pthread_cond_wait(&pacing_cond, &pacing_mutex); - } pthread_mutex_unlock(&pacing_mutex); xsk_ring_prod__submit(&xsk->tx, i); @@ -1032,9 +1044,11 @@ static int send_pkts(struct test_spec *test, struct ifobject *ifobject) while (pkt_stream->current_pkt_nb < pkt_stream->nb_pkts) { ret = __send_pkts(ifobject, &fds, timeout); + if (ret == TEST_CONTINUE && !test->fail) + continue; if ((ret || test->fail) && !timeout) return TEST_FAILURE; - else if (ret == TEST_PASS && timeout) + if (ret == TEST_PASS && timeout) return ret; } @@ -1319,12 +1333,8 @@ static void *worker_testapp_validate_rx(void *arg) if (!err && ifobject->validation_func) err = ifobject->validation_func(ifobject); - if (err) { + if (err) report_failure(test); - pthread_mutex_lock(&pacing_mutex); - pthread_cond_signal(&pacing_cond); - pthread_mutex_unlock(&pacing_mutex); - } pthread_exit(NULL); } diff --git a/tools/testing/selftests/bpf/xskxceiver.h b/tools/testing/selftests/bpf/xskxceiver.h index 00862732e751..aaf27e067640 100644 --- a/tools/testing/selftests/bpf/xskxceiver.h +++ b/tools/testing/selftests/bpf/xskxceiver.h @@ -121,6 +121,7 @@ struct pkt_stream { u32 nb_pkts; u32 current_pkt_nb; struct pkt *pkts; + u32 max_pkt_len; }; struct ifobject; @@ -173,7 +174,6 @@ struct test_spec { pthread_barrier_t barr; pthread_mutex_t pacing_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t pacing_cond = PTHREAD_COND_INITIALIZER; int pkts_in_flight; -- cgit v1.2.3 From cff36398bd4c7d322d424433db437f3c3391c491 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 16 May 2023 11:04:09 -0700 Subject: bpf: drop unnecessary user-triggerable WARN_ONCE in verifierl log It's trivial for user to trigger "verifier log line truncated" warning, as verifier has a fixed-sized buffer of 1024 bytes (as of now), and there are at least two pieces of user-provided information that can be output through this buffer, and both can be arbitrarily sized by user: - BTF names; - BTF.ext source code lines strings. Verifier log buffer should be properly sized for typical verifier state output. But it's sort-of expected that this buffer won't be long enough in some circumstances. So let's drop the check. In any case code will work correctly, at worst truncating a part of a single line output. Reported-by: syzbot+8b2a08dfbd25fd933d75@syzkaller.appspotmail.com Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230516180409.3549088-1-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/log.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c index 046ddff37a76..850494423530 100644 --- a/kernel/bpf/log.c +++ b/kernel/bpf/log.c @@ -62,9 +62,6 @@ void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt, n = vscnprintf(log->kbuf, BPF_VERIFIER_TMP_LOG_SIZE, fmt, args); - WARN_ONCE(n >= BPF_VERIFIER_TMP_LOG_SIZE - 1, - "verifier log line truncated - local buffer too short\n"); - if (log->level == BPF_LOG_KERNEL) { bool newline = n > 0 && log->kbuf[n - 1] == '\n'; -- cgit v1.2.3 From eea96a3e2c909a055005ac65dde356b36cabc4ed Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Mon, 15 May 2023 17:06:36 +0100 Subject: net/tcp: don't peek at tail for io_uring zc Move tcp_write_queue_tail() to SOCK_ZEROCOPY specific flag as zerocopy setup for msghdr->ubuf_info doesn't need to peek into the last request. Signed-off-by: Pavel Begunkov Reviewed-by: David Ahern Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 4d6392c16b7a..40f591f7fce1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1229,13 +1229,12 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) flags = msg->msg_flags; if ((flags & MSG_ZEROCOPY) && size) { - skb = tcp_write_queue_tail(sk); - if (msg->msg_ubuf) { uarg = msg->msg_ubuf; net_zcopy_get(uarg); zc = sk->sk_route_caps & NETIF_F_SG; } else if (sock_flag(sk, SOCK_ZEROCOPY)) { + skb = tcp_write_queue_tail(sk); uarg = msg_zerocopy_realloc(sk, size, skb_zcopy(skb)); if (!uarg) { err = -ENOBUFS; -- cgit v1.2.3 From a7533584728d366f11b210d0e8a2fad03109c669 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Mon, 15 May 2023 17:06:37 +0100 Subject: net/tcp: optimise io_uring zc ubuf refcounting io_uring keeps a reference to ubuf_info during submission, so if tcp_sendmsg_locked() sees msghdr::msg_ubuf in can be sure the buffer will be kept alive and doesn't need to additionally pin it. Signed-off-by: Pavel Begunkov Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 40f591f7fce1..3d18e295bb2f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1231,7 +1231,6 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) if ((flags & MSG_ZEROCOPY) && size) { if (msg->msg_ubuf) { uarg = msg->msg_ubuf; - net_zcopy_get(uarg); zc = sk->sk_route_caps & NETIF_F_SG; } else if (sock_flag(sk, SOCK_ZEROCOPY)) { skb = tcp_write_queue_tail(sk); @@ -1458,7 +1457,9 @@ out: tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); } out_nopush: - net_zcopy_put(uarg); + /* msg->msg_ubuf is pinned by the caller so we don't take extra refs */ + if (uarg && !msg->msg_ubuf) + net_zcopy_put(uarg); return copied + copied_syn; do_error: @@ -1467,7 +1468,9 @@ do_error: if (copied + copied_syn) goto out; out_err: - net_zcopy_put_abort(uarg, true); + /* msg->msg_ubuf is pinned by the caller so we don't take extra refs */ + if (uarg && !msg->msg_ubuf) + net_zcopy_put_abort(uarg, true); err = sk_stream_error(sk, flags, err); /* make sure we wake any epoll edge trigger waiter */ if (unlikely(tcp_rtx_and_write_queues_empty(sk) && err == -EAGAIN)) { -- cgit v1.2.3 From fa0583c202433c3d359a1b0579f52da16e25e4df Mon Sep 17 00:00:00 2001 From: Yuya Tajima Date: Mon, 15 May 2023 15:34:27 +0000 Subject: seg6: Cleanup duplicates of skb_dst_drop calls In processing IPv6 segment routing header (SRH), several functions call skb_dst_drop before ip6_route_input. However, ip6_route_input calls skb_dst_drop within it, so there is no need to call skb_dst_drop in advance. Signed-off-by: Yuya Tajima Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/ipv6/exthdrs.c | 3 --- net/ipv6/seg6_iptunnel.c | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index a8d961d3a477..04c14fc4b14d 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -458,8 +458,6 @@ looped_back: ipv6_hdr(skb)->daddr = *addr; - skb_dst_drop(skb); - ip6_route_input(skb); if (skb_dst(skb)->error) { @@ -834,7 +832,6 @@ looped_back: *addr = ipv6_hdr(skb)->daddr; ipv6_hdr(skb)->daddr = daddr; - skb_dst_drop(skb); ip6_route_input(skb); if (skb_dst(skb)->error) { skb_push(skb, skb->data - skb_network_header(skb)); diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index 34db881204d2..03b877ff4558 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -470,8 +470,6 @@ static int seg6_input_core(struct net *net, struct sock *sk, dst = dst_cache_get(&slwt->cache); preempt_enable(); - skb_dst_drop(skb); - if (!dst) { ip6_route_input(skb); dst = skb_dst(skb); @@ -482,6 +480,7 @@ static int seg6_input_core(struct net *net, struct sock *sk, preempt_enable(); } } else { + skb_dst_drop(skb); skb_dst_set(skb, dst); } -- cgit v1.2.3 From 40bb2ab49c369b78d1cb37ed63b8a85f3102b239 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 May 2023 14:12:15 +0800 Subject: wifi: rtw89: 8851b: add to read efuse version to recognize hardware version B 8851B hardware version A and B use different firmware, but register version code of these two are the same, so add this helper to read efuse version to determine which version is installed. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230512061220.16544-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/efuse.c | 21 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/efuse.h | 1 + 2 files changed, 22 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c index 7bd4f8558e03..2aaf4d013e46 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.c +++ b/drivers/net/wireless/realtek/rtw89/efuse.c @@ -7,6 +7,10 @@ #include "mac.h" #include "reg.h" +#define EF_FV_OFSET 0x5ea +#define EF_CV_MASK GENMASK(7, 4) +#define EF_CV_INV 15 + enum rtw89_efuse_bank { RTW89_EFUSE_BANK_WIFI, RTW89_EFUSE_BANK_BT, @@ -328,3 +332,20 @@ out_free: return ret; } + +int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *ecv) +{ + int ret; + u8 val; + + ret = rtw89_dump_physical_efuse_map(rtwdev, &val, EF_FV_OFSET, 1, false); + if (ret) + return ret; + + *ecv = u8_get_bits(val, EF_CV_MASK); + if (*ecv == EF_CV_INV) + return -ENOENT; + + return 0; +} +EXPORT_SYMBOL(rtw89_read_efuse_ver); diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h index 622ff95e7476..79071aff28de 100644 --- a/drivers/net/wireless/realtek/rtw89/efuse.h +++ b/drivers/net/wireless/realtek/rtw89/efuse.h @@ -9,5 +9,6 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev); int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev); +int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv); #endif -- cgit v1.2.3 From f03bd0429f9bc2718ee250b05eb48dc081d4f6b7 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 May 2023 14:12:16 +0800 Subject: wifi: rtw89: 8851b: configure GPIO according to RFE type Though 8851BE is a 1x1 chip, but it has two antenna hardware module that needs additional configuration to help choose antenna we are going to use. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230512061220.16544-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 9 ++++ drivers/net/wireless/realtek/rtw89/phy.c | 1 + drivers/net/wireless/realtek/rtw89/reg.h | 9 ++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 64 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + 7 files changed, 86 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index b60cd9852259..fe464b7212f5 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -2799,6 +2799,7 @@ struct rtw89_chip_ops { int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map); int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map); void (*fem_setup)(struct rtw89_dev *rtwdev); + void (*rfe_gpio)(struct rtw89_dev *rtwdev); void (*rfk_init)(struct rtw89_dev *rtwdev); void (*rfk_channel)(struct rtw89_dev *rtwdev); void (*rfk_band_changed)(struct rtw89_dev *rtwdev, @@ -4700,6 +4701,14 @@ static inline void rtw89_chip_fem_setup(struct rtw89_dev *rtwdev) chip->ops->fem_setup(rtwdev); } +static inline void rtw89_chip_rfe_gpio(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->ops->rfe_gpio) + chip->ops->rfe_gpio(rtwdev); +} + static inline void rtw89_chip_bb_sethw(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 568488da3ff1..de0776dfddf7 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -4399,6 +4399,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_phy_cfo_init(rtwdev); rtw89_phy_ul_tb_info_init(rtwdev); rtw89_phy_antdiv_init(rtwdev); + rtw89_chip_rfe_gpio(rtwdev); rtw89_phy_antdiv_set_ant(rtwdev); rtw89_phy_init_rf_nctl(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 21f68787ff10..a15bf3a6687c 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -254,6 +254,10 @@ #define R_AX_EECS_EESK_FUNC_SEL 0x02D8 #define B_AX_PINMUX_EESK_FUNC_SEL_MASK GENMASK(7, 4) +#define R_AX_GPIO16_23_FUNC_SEL 0x02D8 +#define B_AX_PINMUX_GPIO17_FUNC_SEL_MASK GENMASK(7, 4) +#define B_AX_PINMUX_GPIO16_FUNC_SEL_MASK GENMASK(3, 0) + #define R_AX_LED1_FUNC_SEL 0x02DC #define B_AX_PINMUX_EESK_FUNC_SEL_V1_MASK GENMASK(27, 24) #define PINMUX_EESK_FUNC_SEL_BT_LOG 0x1 @@ -3846,6 +3850,7 @@ #define R_RFE_E_A2 0x0334 #define R_RFE_O_SEL_A2 0x0338 #define R_RFE_SEL0_A2 0x033C +#define B_RFE_SEL0_MASK GENMASK(1, 0) #define R_RFE_SEL32_A2 0x0340 #define R_CIRST 0x035c #define B_CIRST_SYN GENMASK(11, 10) @@ -4490,6 +4495,10 @@ #define B_P0_ANTSEL_RX_ORI GENMASK(7, 4) #define R_RFSW_CTRL_ANT0_BASE 0x5870 #define B_RFSW_CTRL_ANT_MAPPING GENMASK(15, 0) +#define R_RFE_SEL0_BASE 0x5880 +#define B_RFE_SEL0_SRC_MASK GENMASK(3, 0) +#define RFE_SEL0_SRC_ANTSEL_0 8 +#define R_RFE_INV0 0x5890 #define R_P0_RFM 0x5894 #define B_P0_RFM_DIS_WL BIT(7) #define B_P0_RFM_TX_OPT BIT(6) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 00cabf92c5a9..047171ead2e9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -72,8 +72,72 @@ static const struct rtw89_xtal_info rtw8851b_xtal_info = { .sc_xi_mask = B_AX_XTAL_SC_XI_A_BLOCK_MASK, }; +static void rtw8851b_set_bb_gpio(struct rtw89_dev *rtwdev, u8 gpio_idx, bool inv, + u8 src_sel) +{ + u32 addr, mask; + + if (gpio_idx >= 32) + return; + + /* 2 continual 32-bit registers for 32 GPIOs, and each GPIO occupies 2 bits */ + addr = R_RFE_SEL0_A2 + (gpio_idx / 16) * sizeof(u32); + mask = B_RFE_SEL0_MASK << (gpio_idx % 16) * 2; + + rtw89_phy_write32_mask(rtwdev, addr, mask, RF_PATH_A); + rtw89_phy_write32_mask(rtwdev, R_RFE_INV0, BIT(gpio_idx), inv); + + /* 4 continual 32-bit registers for 32 GPIOs, and each GPIO occupies 4 bits */ + addr = R_RFE_SEL0_BASE + (gpio_idx / 8) * sizeof(u32); + mask = B_RFE_SEL0_SRC_MASK << (gpio_idx % 8) * 4; + + rtw89_phy_write32_mask(rtwdev, addr, mask, src_sel); +} + +static void rtw8851b_set_mac_gpio(struct rtw89_dev *rtwdev, u8 func) +{ + static const struct rtw89_reg3_def func16 = { + R_AX_GPIO16_23_FUNC_SEL, B_AX_PINMUX_GPIO16_FUNC_SEL_MASK, BIT(3) + }; + static const struct rtw89_reg3_def func17 = { + R_AX_GPIO16_23_FUNC_SEL, B_AX_PINMUX_GPIO17_FUNC_SEL_MASK, BIT(7) >> 4, + }; + const struct rtw89_reg3_def *def; + + switch (func) { + case 16: + def = &func16; + break; + case 17: + def = &func17; + break; + default: + rtw89_warn(rtwdev, "undefined gpio func %d\n", func); + return; + } + + rtw89_write8_mask(rtwdev, def->addr, def->mask, def->data); +} + +static void rtw8851b_rfe_gpio(struct rtw89_dev *rtwdev) +{ + u8 rfe_type = rtwdev->efuse.rfe_type; + + if (rfe_type > 50) + return; + + if (rfe_type % 3 == 2) { + rtw8851b_set_bb_gpio(rtwdev, 16, true, RFE_SEL0_SRC_ANTSEL_0); + rtw8851b_set_bb_gpio(rtwdev, 17, false, RFE_SEL0_SRC_ANTSEL_0); + + rtw8851b_set_mac_gpio(rtwdev, 16); + rtw8851b_set_mac_gpio(rtwdev, 17); + } +} + static const struct rtw89_chip_ops rtw8851b_chip_ops = { .fem_setup = NULL, + .rfe_gpio = rtw8851b_rfe_gpio, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, .h2c_dctl_sec_cam = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 4e6f3bbdc2d8..541ad2f4b0c2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2032,6 +2032,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .read_efuse = rtw8852a_read_efuse, .read_phycap = rtw8852a_read_phycap, .fem_setup = rtw8852a_fem_setup, + .rfe_gpio = NULL, .rfk_init = rtw8852a_rfk_init, .rfk_channel = rtw8852a_rfk_channel, .rfk_band_changed = rtw8852a_rfk_band_changed, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index b1a6b985842b..4e4023f114ec 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2454,6 +2454,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .read_efuse = rtw8852b_read_efuse, .read_phycap = rtw8852b_read_phycap, .fem_setup = NULL, + .rfe_gpio = NULL, .rfk_init = rtw8852b_rfk_init, .rfk_channel = rtw8852b_rfk_channel, .rfk_band_changed = rtw8852b_rfk_band_changed, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index f2e70bda8e48..e4c984c87d6c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2762,6 +2762,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .read_efuse = rtw8852c_read_efuse, .read_phycap = rtw8852c_read_phycap, .fem_setup = NULL, + .rfe_gpio = NULL, .rfk_init = rtw8852c_rfk_init, .rfk_channel = rtw8852c_rfk_channel, .rfk_band_changed = rtw8852c_rfk_band_changed, -- cgit v1.2.3 From 4885b17ebb92b3cc54e1064ffe52f688ca83d5c7 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 May 2023 14:12:17 +0800 Subject: wifi: rtw89: 8851b: add BT coexistence support function Add 8851B specific parameters of BT coexistence. Since 8851B has special two antenna hardware module with antenna diversity, BT coexistence needs to recognize this, so add some fields to store these information for further use. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230512061220.16544-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/coex.c | 7 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 357 ++++++++++++++++++++++++++ 2 files changed, 364 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index acb3fac0c96d..3a586a971e8f 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -127,6 +127,13 @@ static const u32 cxtbl[] = { static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { /* firmware version must be in decreasing order for each chip */ + {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0), + .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, + .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1, + .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, + .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, + .info_buf = 1800, .max_role_num = 6, + }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 047171ead2e9..f7279b8a493b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -72,6 +72,52 @@ static const struct rtw89_xtal_info rtw8851b_xtal_info = { .sc_xi_mask = B_AX_XTAL_SC_XI_A_BLOCK_MASK, }; +static const struct rtw89_btc_rf_trx_para rtw89_btc_8851b_rf_ul[] = { + {255, 0, 0, 7}, /* 0 -> original */ + {255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */ + {255, 0, 0, 7}, /* 2 ->reserved for shared-antenna */ + {255, 0, 0, 7}, /* 3- >reserved for shared-antenna */ + {255, 0, 0, 7}, /* 4 ->reserved for shared-antenna */ + {255, 1, 0, 7}, /* the below id is for non-shared-antenna free-run */ + {6, 1, 0, 7}, + {13, 1, 0, 7}, + {13, 1, 0, 7} +}; + +static const struct rtw89_btc_rf_trx_para rtw89_btc_8851b_rf_dl[] = { + {255, 0, 0, 7}, /* 0 -> original */ + {255, 2, 0, 7}, /* 1 -> reserved for shared-antenna */ + {255, 0, 0, 7}, /* 2 ->reserved for shared-antenna */ + {255, 0, 0, 7}, /* 3- >reserved for shared-antenna */ + {255, 0, 0, 7}, /* 4 ->reserved for shared-antenna */ + {255, 1, 0, 7}, /* the below id is for non-shared-antenna free-run */ + {255, 1, 0, 7}, + {255, 1, 0, 7}, + {255, 1, 0, 7} +}; + +static const struct rtw89_btc_fbtc_mreg rtw89_btc_8851b_mon_reg[] = { + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda24), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda28), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda2c), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda30), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda4c), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda10), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda20), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xda34), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xcef4), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0x8424), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xd200), + RTW89_DEF_FBTC_MREG(REG_MAC, 4, 0xd220), + RTW89_DEF_FBTC_MREG(REG_BB, 4, 0x980), + RTW89_DEF_FBTC_MREG(REG_BB, 4, 0x4738), + RTW89_DEF_FBTC_MREG(REG_BB, 4, 0x4688), + RTW89_DEF_FBTC_MREG(REG_BB, 4, 0x4694), +}; + +static const u8 rtw89_btc_8851b_wl_rssi_thres[BTC_WL_RSSI_THMAX] = {70, 60, 50, 40}; +static const u8 rtw89_btc_8851b_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30, 20}; + static void rtw8851b_set_bb_gpio(struct rtw89_dev *rtwdev, u8 gpio_idx, bool inv, u8 src_sel) { @@ -135,12 +181,313 @@ static void rtw8851b_rfe_gpio(struct rtw89_dev *rtwdev) } } +static void rtw8851b_btc_set_rfe(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_module *module = &btc->mdinfo; + + module->rfe_type = rtwdev->efuse.rfe_type; + module->cv = rtwdev->hal.cv; + module->bt_solo = 0; + module->switch_type = BTC_SWITCH_INTERNAL; + module->ant.isolation = 10; + module->kt_ver_adie = rtwdev->hal.acv; + + if (module->rfe_type == 0) + return; + + /* rfe_type 3*n+1: 1-Ant(shared), + * 3*n+2: 2-Ant+Div(non-shared), + * 3*n+3: 2-Ant+no-Div(non-shared) + */ + module->ant.num = (module->rfe_type % 3 == 1) ? 1 : 2; + /* WL-1ss at S0, btg at s0 (On 1 WL RF) */ + module->ant.single_pos = RF_PATH_A; + module->ant.btg_pos = RF_PATH_A; + module->ant.stream_cnt = 1; + + if (module->ant.num == 1) { + module->ant.type = BTC_ANT_SHARED; + module->bt_pos = BTC_BT_BTG; + module->wa_type = 1; + module->ant.diversity = 0; + } else { /* ant.num == 2 */ + module->ant.type = BTC_ANT_DEDICATED; + module->bt_pos = BTC_BT_ALONE; + module->switch_type = BTC_SWITCH_EXTERNAL; + module->wa_type = 0; + if (module->rfe_type % 3 == 2) + module->ant.diversity = 1; + } +} + +static +void rtw8851b_set_trx_mask(struct rtw89_dev *rtwdev, u8 path, u8 group, u32 val) +{ + if (group > BTC_BT_SS_GROUP) + group--; /* Tx-group=1, Rx-group=2 */ + + if (rtwdev->btc.mdinfo.ant.type == BTC_ANT_SHARED) /* 1-Ant */ + group += 3; + + rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, group); + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, val); +} + +static void rtw8851b_btc_init_cfg(struct rtw89_dev *rtwdev) +{ + static const struct rtw89_mac_ax_coex coex_params = { + .pta_mode = RTW89_MAC_AX_COEX_RTK_MODE, + .direction = RTW89_MAC_AX_COEX_INNER, + }; + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_module *module = &btc->mdinfo; + struct rtw89_btc_ant_info *ant = &module->ant; + u8 path, path_min, path_max; + + /* PTA init */ + rtw89_mac_coex_init(rtwdev, &coex_params); + + /* set WL Tx response = Hi-Pri */ + chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true); + chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true); + + /* for 1-Ant && 1-ss case: only 1-path */ + if (ant->stream_cnt == 1) { + path_min = ant->single_pos; + path_max = path_min; + } else { + path_min = RF_PATH_A; + path_max = RF_PATH_B; + } + + for (path = path_min; path <= path_max; path++) { + /* set rf gnt-debug off */ + rtw89_write_rf(rtwdev, path, RR_WLSEL, RFREG_MASK, 0x0); + + /* set DEBUG_LUT_RFMODE_MASK = 1 to start trx-mask-setup */ + rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, BIT(17)); + + /* if GNT_WL=0 && BT=SS_group --> WL Tx/Rx = THRU */ + rtw8851b_set_trx_mask(rtwdev, path, BTC_BT_SS_GROUP, 0x5ff); + + /* if GNT_WL=0 && BT=Rx_group --> WL-Rx = THRU + WL-Tx = MASK */ + rtw8851b_set_trx_mask(rtwdev, path, BTC_BT_RX_GROUP, 0x5df); + + /* if GNT_WL = 0 && BT = Tx_group --> + * Shared-Ant && BTG-path:WL mask(0x55f), others:WL THRU(0x5ff) + */ + if (ant->type == BTC_ANT_SHARED && ant->btg_pos == path) + rtw8851b_set_trx_mask(rtwdev, path, BTC_BT_TX_GROUP, 0x55f); + else + rtw8851b_set_trx_mask(rtwdev, path, BTC_BT_TX_GROUP, 0x5ff); + + /* set DEBUG_LUT_RFMODE_MASK = 0 to stop trx-mask-setup */ + rtw89_write_rf(rtwdev, path, RR_LUTWE, RFREG_MASK, 0); + } + + /* set PTA break table */ + rtw89_write32(rtwdev, R_BTC_BREAK_TABLE, BTC_BREAK_PARAM); + + /* enable BT counter 0xda40[16,2] = 2b'11 */ + rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN); + + btc->cx.wl.status.map.init_ok = true; +} + +static +void rtw8851b_btc_set_wl_pri(struct rtw89_dev *rtwdev, u8 map, bool state) +{ + u32 bitmap; + u32 reg; + + switch (map) { + case BTC_PRI_MASK_TX_RESP: + reg = R_BTC_BT_COEX_MSK_TABLE; + bitmap = B_BTC_PRI_MASK_TX_RESP_V1; + break; + case BTC_PRI_MASK_BEACON: + reg = R_AX_WL_PRI_MSK; + bitmap = B_AX_PTA_WL_PRI_MASK_BCNQ; + break; + case BTC_PRI_MASK_RX_CCK: + reg = R_BTC_BT_COEX_MSK_TABLE; + bitmap = B_BTC_PRI_MASK_RXCCK_V1; + break; + default: + return; + } + + if (state) + rtw89_write32_set(rtwdev, reg, bitmap); + else + rtw89_write32_clr(rtwdev, reg, bitmap); +} + +union rtw8851b_btc_wl_txpwr_ctrl { + u32 txpwr_val; + struct { + union { + u16 ctrl_all_time; + struct { + s16 data:9; + u16 rsvd:6; + u16 flag:1; + } all_time; + }; + union { + u16 ctrl_gnt_bt; + struct { + s16 data:9; + u16 rsvd:7; + } gnt_bt; + }; + }; +} __packed; + +static void +rtw8851b_btc_set_wl_txpwr_ctrl(struct rtw89_dev *rtwdev, u32 txpwr_val) +{ + union rtw8851b_btc_wl_txpwr_ctrl arg = { .txpwr_val = txpwr_val }; + s32 val; + +#define __write_ctrl(_reg, _msk, _val, _en, _cond) \ +do { \ + u32 _wrt = FIELD_PREP(_msk, _val); \ + BUILD_BUG_ON(!!(_msk & _en)); \ + if (_cond) \ + _wrt |= _en; \ + else \ + _wrt &= ~_en; \ + rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, _reg, \ + _msk | _en, _wrt); \ +} while (0) + + switch (arg.ctrl_all_time) { + case 0xffff: + val = 0; + break; + default: + val = arg.all_time.data; + break; + } + + __write_ctrl(R_AX_PWR_RATE_CTRL, B_AX_FORCE_PWR_BY_RATE_VALUE_MASK, + val, B_AX_FORCE_PWR_BY_RATE_EN, + arg.ctrl_all_time != 0xffff); + + switch (arg.ctrl_gnt_bt) { + case 0xffff: + val = 0; + break; + default: + val = arg.gnt_bt.data; + break; + } + + __write_ctrl(R_AX_PWR_COEXT_CTRL, B_AX_TXAGC_BT_MASK, val, + B_AX_TXAGC_BT_EN, arg.ctrl_gnt_bt != 0xffff); + +#undef __write_ctrl +} + +static +s8 rtw8851b_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val) +{ + val = clamp_t(s8, val, -100, 0) + 100; + val = min(val + 6, 100); /* compensate offset */ + + return val; +} + +static +void rtw8851b_btc_update_bt_cnt(struct rtw89_dev *rtwdev) +{ + /* Feature move to firmware */ +} + +static void rtw8851b_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ant_info *ant = &btc->mdinfo.ant; + + rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWE, RFREG_MASK, 0x80000); + rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWA, RFREG_MASK, 0x1); + rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWD1, RFREG_MASK, 0x110); + + /* set WL standby = Rx for GNT_BT_Tx = 1->0 settle issue */ + if (state) + rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWD0, RFREG_MASK, 0x179c); + else + rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWD0, RFREG_MASK, 0x208); + + rtw89_write_rf(rtwdev, ant->btg_pos, RR_LUTWE, RFREG_MASK, 0x0); +} + +#define LNA2_51B_MA 0x700 + +static const struct rtw89_reg2_def btc_8851b_rf_0[] = {{0x2, 0x0}}; +static const struct rtw89_reg2_def btc_8851b_rf_1[] = {{0x2, 0x1}}; + +static void rtw8851b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) +{ + /* To improve BT ACI in co-rx + * level=0 Default: TIA 1/0= (LNA2,TIAN6) = (7,1)/(5,1) = 21dB/12dB + * level=1 Fix LNA2=5: TIA 1/0= (LNA2,TIAN6) = (5,0)/(5,1) = 18dB/12dB + */ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ant_info *ant = &btc->mdinfo.ant; + const struct rtw89_reg2_def *rf; + u32 n, i, val; + + switch (level) { + case 0: /* original */ + default: + btc->dm.wl_lna2 = 0; + break; + case 1: /* for FDD free-run */ + btc->dm.wl_lna2 = 0; + break; + case 2: /* for BTG Co-Rx*/ + btc->dm.wl_lna2 = 1; + break; + } + + if (btc->dm.wl_lna2 == 0) { + rf = btc_8851b_rf_0; + n = ARRAY_SIZE(btc_8851b_rf_0); + } else { + rf = btc_8851b_rf_1; + n = ARRAY_SIZE(btc_8851b_rf_1); + } + + for (i = 0; i < n; i++, rf++) { + val = rf->data; + /* bit[10] = 1 if non-shared-ant for 8851b */ + if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED) + val |= 0x4; + + rtw89_write_rf(rtwdev, ant->btg_pos, rf->addr, LNA2_51B_MA, val); + } +} + static const struct rtw89_chip_ops rtw8851b_chip_ops = { .fem_setup = NULL, .rfe_gpio = rtw8851b_rfe_gpio, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, .h2c_dctl_sec_cam = NULL, + + .btc_set_rfe = rtw8851b_btc_set_rfe, + .btc_init_cfg = rtw8851b_btc_init_cfg, + .btc_set_wl_pri = rtw8851b_btc_set_wl_pri, + .btc_set_wl_txpwr_ctrl = rtw8851b_btc_set_wl_txpwr_ctrl, + .btc_get_bt_rssi = rtw8851b_btc_get_bt_rssi, + .btc_update_bt_cnt = rtw8851b_btc_update_bt_cnt, + .btc_wl_s1_standby = rtw8851b_btc_wl_s1_standby, + .btc_set_wl_rx_gain = rtw8851b_btc_set_wl_rx_gain, + .btc_set_policy = rtw89_btc_set_policy_v1, }; #ifdef CONFIG_PM @@ -213,6 +560,16 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .scbd = 0x1, .mailbox = 0x1, + .afh_guard_ch = 6, + .wl_rssi_thres = rtw89_btc_8851b_wl_rssi_thres, + .bt_rssi_thres = rtw89_btc_8851b_bt_rssi_thres, + .rssi_tol = 2, + .mon_reg_num = ARRAY_SIZE(rtw89_btc_8851b_mon_reg), + .mon_reg = rtw89_btc_8851b_mon_reg, + .rf_para_ulink_num = ARRAY_SIZE(rtw89_btc_8851b_rf_ul), + .rf_para_ulink = rtw89_btc_8851b_rf_ul, + .rf_para_dlink_num = ARRAY_SIZE(rtw89_btc_8851b_rf_dl), + .rf_para_dlink = rtw89_btc_8851b_rf_dl, .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) | BIT(RTW89_PS_MODE_CLK_GATED), .low_power_hci_modes = 0, -- cgit v1.2.3 From 31df6df89f9394bc544a4ebad62584d56bff1677 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 May 2023 14:12:18 +0800 Subject: wifi: rtw89: 8851b: add basic power on function Add basic functions to power on chip and enable and access BB/RF, as well as reset and hardware settings of BB. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230512061220.16544-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/mac.h | 2 + drivers/net/wireless/realtek/rtw89/reg.h | 17 ++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 327 ++++++++++++++++++++++++++ 3 files changed, 346 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index e340720bbb88..3f9bf9a7d6a0 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1116,6 +1116,8 @@ enum rtw89_mac_xtal_si_offset { XTAL_SI_PWR_CUT = 0x10, #define XTAL_SI_SMALL_PWR_CUT BIT(0) #define XTAL_SI_BIG_PWR_CUT BIT(1) + XTAL_SI_XTAL_DRV = 0x15, +#define XTAL_SI_DRV_LATCH BIT(4) XTAL_SI_XTAL_XMD_2 = 0x24, #define XTAL_SI_LDO_LPS GENMASK(6, 4) XTAL_SI_XTAL_XMD_4 = 0x26, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index a15bf3a6687c..4508641e2abb 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -19,6 +19,8 @@ #define B_AX_FEN_BBRSTB BIT(0) #define R_AX_SYS_PW_CTRL 0x0004 +#define B_AX_SOP_ASWRM BIT(31) +#define B_AX_SOP_PWMM_DSWR BIT(29) #define B_AX_XTAL_OFF_A_DIE BIT(22) #define B_AX_DIS_WLBT_PDNSUSEN_SOPC BIT(18) #define B_AX_RDY_SYSPWR BIT(17) @@ -134,6 +136,8 @@ #define B_AX_PLATFORM_EN BIT(0) #define R_AX_WLLPS_CTRL 0x0090 +#define B_AX_LPSOP_ASWRM BIT(17) +#define B_AX_LPSOP_DSWRM BIT(9) #define B_AX_DIS_WLBT_LPSEN_LOPC BIT(1) #define SW_LPS_OPTION 0x0001A0B2 @@ -222,9 +226,14 @@ #define B_AX_OCP_L1_MASK GENMASK(15, 13) #define B_AX_VOL_L1_MASK GENMASK(3, 0) +#define R_AX_SPSLDO_ON_CTRL1 0x0204 +#define B_AX_FPWMDELAY BIT(3) + #define R_AX_LDO_AON_CTRL0 0x0218 #define B_AX_PD_REGU_L BIT(16) +#define R_AX_SPSANA_ON_CTRL1 0x0224 + #define R_AX_WLAN_XTAL_SI_CTRL 0x0270 #define B_AX_WL_XTAL_SI_CMD_POLL BIT(31) #define B_AX_BT_XTAL_SI_ERR_FLAG BIT(30) @@ -237,6 +246,9 @@ #define B_AX_WL_XTAL_SI_DATA_MASK GENMASK(15, 8) #define B_AX_WL_XTAL_SI_ADDR_MASK GENMASK(7, 0) +#define R_AX_WLAN_XTAL_SI_CONFIG 0x0274 +#define B_AX_XTAL_SI_ADDR_NOT_CHK BIT(0) + #define R_AX_XTAL_ON_CTRL0 0x0280 #define B_AX_XTAL_SC_LPS BIT(31) #define B_AX_XTAL_SC_XO_MASK GENMASK(23, 17) @@ -267,6 +279,10 @@ #define B_AX_EESK_PULL_LOW_EN BIT(17) #define B_AX_EECS_PULL_LOW_EN BIT(16) +#define R_AX_GPIO0_16_EECS_EESK_LED1_PULL_LOW_EN 0x02E4 +#define B_AX_GPIO16_PULL_LOW_EN_V1 BIT(19) +#define B_AX_GPIO10_PULL_LOW_EN BIT(10) + #define R_AX_WLRF_CTRL 0x02F0 #define B_AX_AFC_AFEDIG BIT(17) #define B_AX_WLRF1_CTRL_7 BIT(15) @@ -4497,6 +4513,7 @@ #define B_RFSW_CTRL_ANT_MAPPING GENMASK(15, 0) #define R_RFE_SEL0_BASE 0x5880 #define B_RFE_SEL0_SRC_MASK GENMASK(3, 0) +#define R_RFE_SEL32_BASE 0x5884 #define RFE_SEL0_SRC_ANTSEL_0 8 #define R_RFE_INV0 0x5890 #define R_P0_RFM 0x5894 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index f7279b8a493b..6c86edc74e95 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -3,6 +3,7 @@ */ #include "coex.h" +#include "efuse.h" #include "fw.h" #include "mac.h" #include "phy.h" @@ -118,6 +119,182 @@ static const struct rtw89_btc_fbtc_mreg rtw89_btc_8851b_mon_reg[] = { static const u8 rtw89_btc_8851b_wl_rssi_thres[BTC_WL_RSSI_THMAX] = {70, 60, 50, 40}; static const u8 rtw89_btc_8851b_bt_rssi_thres[BTC_BT_RSSI_THMAX] = {50, 40, 30, 20}; +static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) +{ + u32 val32; + u8 val8; + u32 ret; + + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_AFSM_WLSUS_EN | + B_AX_AFSM_PCIE_SUS_EN); + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_DIS_WLBT_PDNSUSEN_SOPC); + rtw89_write32_set(rtwdev, R_AX_WLLPS_CTRL, B_AX_DIS_WLBT_LPSEN_LOPC); + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APDM_HPDN); + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + + ret = read_poll_timeout(rtw89_read32, val32, val32 & B_AX_RDY_SYSPWR, + 1000, 20000, false, rtwdev, R_AX_SYS_PW_CTRL); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_EN_WLON); + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFN_ONMAC); + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_AX_APFN_ONMAC), + 1000, 20000, false, rtwdev, R_AX_SYS_PW_CTRL); + if (ret) + return ret; + + rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); + rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); + rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); + rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); + + rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); + rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_OFF_WEI, + XTAL_SI_OFF_WEI); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_OFF_EI, + XTAL_SI_OFF_EI); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_RFC2RF); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_PON_WEI, + XTAL_SI_PON_WEI); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_PON_EI, + XTAL_SI_PON_EI); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_SRAM2RFC); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_SRAM_CTRL, 0, XTAL_SI_SRAM_DIS); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_XMD_2, 0, XTAL_SI_LDO_LPS); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_XMD_4, 0, XTAL_SI_LPS_CAP); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XTAL_DRV, 0, XTAL_SI_DRV_LATCH); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); + rtw89_write32_set(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_ISO_EB2CORE); + rtw89_write32_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B15); + + fsleep(1000); + + rtw89_write32_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14); + rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); + rtw89_write32_set(rtwdev, R_AX_GPIO0_16_EECS_EESK_LED1_PULL_LOW_EN, + B_AX_GPIO10_PULL_LOW_EN | B_AX_GPIO16_PULL_LOW_EN_V1); + + if (rtwdev->hal.cv == CHIP_CAV) { + ret = rtw89_read_efuse_ver(rtwdev, &val8); + if (!ret) + rtwdev->hal.cv = val8; + } + + rtw89_write32_clr(rtwdev, R_AX_WLAN_XTAL_SI_CONFIG, + B_AX_XTAL_SI_ADDR_NOT_CHK); + if (rtwdev->hal.cv != CHIP_CAV) { + rtw89_write32_set(rtwdev, R_AX_SPSLDO_ON_CTRL1, B_AX_FPWMDELAY); + rtw89_write32_set(rtwdev, R_AX_SPSANA_ON_CTRL1, B_AX_FPWMDELAY); + } + + rtw89_write32_set(rtwdev, R_AX_DMAC_FUNC_EN, + B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_MPDU_PROC_EN | + B_AX_WD_RLS_EN | B_AX_DLE_WDE_EN | B_AX_TXPKT_CTRL_EN | + B_AX_STA_SCH_EN | B_AX_DLE_PLE_EN | B_AX_PKT_BUF_EN | + B_AX_DMAC_TBL_EN | B_AX_PKT_IN_EN | B_AX_DLE_CPUIO_EN | + B_AX_DISPATCHER_EN | B_AX_BBRPT_EN | B_AX_MAC_SEC_EN | + B_AX_DMACREG_GCKEN); + rtw89_write32_set(rtwdev, R_AX_CMAC_FUNC_EN, + B_AX_CMAC_EN | B_AX_CMAC_TXEN | B_AX_CMAC_RXEN | + B_AX_FORCE_CMACREG_GCKEN | B_AX_PHYINTF_EN | B_AX_CMAC_DMA_EN | + B_AX_PTCLTOP_EN | B_AX_SCHEDULER_EN | B_AX_TMAC_EN | + B_AX_RMAC_EN); + + rtw89_write32_mask(rtwdev, R_AX_EECS_EESK_FUNC_SEL, B_AX_PINMUX_EESK_FUNC_SEL_MASK, + PINMUX_EESK_FUNC_SEL_BT_LOG); + + return 0; +} + +static void rtw8851b_patch_swr_pfm2pwm(struct rtw89_dev *rtwdev) +{ + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_PWMM_DSWR); + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_ASWRM); + rtw89_write32_set(rtwdev, R_AX_WLLPS_CTRL, B_AX_LPSOP_DSWRM); + rtw89_write32_set(rtwdev, R_AX_WLLPS_CTRL, B_AX_LPSOP_ASWRM); +} + +static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) +{ + u32 val32; + u32 ret; + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_RFC2RF, + XTAL_SI_RFC2RF); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_OFF_EI); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_OFF_WEI); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0, XTAL_SI_RF00); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_SRAM2RFC, + XTAL_SI_SRAM2RFC); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_PON_EI); + if (ret) + return ret; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, XTAL_SI_PON_WEI); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_AX_WLAN_XTAL_SI_CONFIG, + B_AX_XTAL_SI_ADDR_NOT_CHK); + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_EN_WLON); + rtw89_write32_clr(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + rtw89_write8_clr(rtwdev, R_AX_SYS_FUNC_EN, B_AX_FEN_BB_GLB_RSTN | B_AX_FEN_BBRSTB); + + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_OFFMAC); + + ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_AX_APFM_OFFMAC), + 1000, 20000, false, rtwdev, R_AX_SYS_PW_CTRL); + if (ret) + return ret; + + rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + + if (rtwdev->hal.cv == CHIP_CAV) { + rtw8851b_patch_swr_pfm2pwm(rtwdev); + } else { + rtw89_write32_set(rtwdev, R_AX_SPSLDO_ON_CTRL1, B_AX_FPWMDELAY); + rtw89_write32_set(rtwdev, R_AX_SPSANA_ON_CTRL1, B_AX_FPWMDELAY); + } + + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + + return 0; +} + static void rtw8851b_set_bb_gpio(struct rtw89_dev *rtwdev, u8 gpio_idx, bool inv, u8 src_sel) { @@ -181,6 +358,96 @@ static void rtw8851b_rfe_gpio(struct rtw89_dev *rtwdev) } } +static void rtw8851b_bb_reset_all(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); + fsleep(1); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); +} + +static void rtw8851b_bb_reset(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, + B_P0_TXPW_RSTB_MANON | B_P0_TXPW_RSTB_TSSI, 0x1); + rtw89_phy_write32_set(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_TRK_EN); + rtw8851b_bb_reset_all(rtwdev, phy_idx); + rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, + B_P0_TXPW_RSTB_MANON | B_P0_TXPW_RSTB_TSSI, 0x3); + rtw89_phy_write32_clr(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_TRK_EN); +} + +static +void rtw8851b_bb_gpio_trsw(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + u8 tx_path_en, u8 trsw_tx, + u8 trsw_rx, u8 trsw_a, u8 trsw_b) +{ + u32 mask_ofst = 16; + u32 val; + + if (path != RF_PATH_A) + return; + + mask_ofst += (tx_path_en * 4 + trsw_tx * 2 + trsw_rx) * 2; + val = u32_encode_bits(trsw_a, B_P0_TRSW_A) | + u32_encode_bits(trsw_b, B_P0_TRSW_B); + + rtw89_phy_write32_mask(rtwdev, R_P0_TRSW, + (B_P0_TRSW_A | B_P0_TRSW_B) << mask_ofst, val); +} + +static void rtw8851b_bb_gpio_init(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_set(rtwdev, R_P0_TRSW, B_P0_TRSW_A); + rtw89_phy_write32_clr(rtwdev, R_P0_TRSW, B_P0_TRSW_X); + rtw89_phy_write32_clr(rtwdev, R_P0_TRSW, B_P0_TRSW_SO_A2); + rtw89_phy_write32(rtwdev, R_RFE_SEL0_BASE, 0x77777777); + rtw89_phy_write32(rtwdev, R_RFE_SEL32_BASE, 0x77777777); + + rtw89_phy_write32(rtwdev, R_RFE_E_A2, 0xffffffff); + rtw89_phy_write32(rtwdev, R_RFE_O_SEL_A2, 0); + rtw89_phy_write32(rtwdev, R_RFE_SEL0_A2, 0); + rtw89_phy_write32(rtwdev, R_RFE_SEL32_A2, 0); + + rtw8851b_bb_gpio_trsw(rtwdev, RF_PATH_A, 0, 0, 0, 0, 1); + rtw8851b_bb_gpio_trsw(rtwdev, RF_PATH_A, 0, 0, 1, 1, 0); + rtw8851b_bb_gpio_trsw(rtwdev, RF_PATH_A, 0, 1, 0, 1, 0); + rtw8851b_bb_gpio_trsw(rtwdev, RF_PATH_A, 0, 1, 1, 1, 0); + rtw8851b_bb_gpio_trsw(rtwdev, RF_PATH_A, 1, 0, 0, 0, 1); + rtw8851b_bb_gpio_trsw(rtwdev, RF_PATH_A, 1, 0, 1, 1, 0); + rtw8851b_bb_gpio_trsw(rtwdev, RF_PATH_A, 1, 1, 0, 1, 0); + rtw8851b_bb_gpio_trsw(rtwdev, RF_PATH_A, 1, 1, 1, 1, 0); +} + +static void rtw8851b_bb_macid_ctrl_init(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + u32 addr; + + for (addr = R_AX_PWR_MACID_LMT_TABLE0; + addr <= R_AX_PWR_MACID_LMT_TABLE127; addr += 4) + rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, 0); +} + +static void rtw8851b_bb_sethw(struct rtw89_dev *rtwdev) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + + rtw89_phy_write32_clr(rtwdev, R_P0_EN_SOUND_WO_NDP, B_P0_EN_SOUND_WO_NDP); + + rtw8851b_bb_macid_ctrl_init(rtwdev, RTW89_PHY_0); + rtw8851b_bb_gpio_init(rtwdev); + + /* read these registers after loading BB parameters */ + gain->offset_base[RTW89_PHY_0] = + rtw89_phy_read32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK); + gain->rssi_base[RTW89_PHY_0] = + rtw89_phy_read32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK); +} + static void rtw8851b_btc_set_rfe(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -472,9 +739,69 @@ static void rtw8851b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) } } +static int rtw8851b_mac_enable_bb_rf(struct rtw89_dev *rtwdev) +{ + int ret; + + rtw89_write8_set(rtwdev, R_AX_SYS_FUNC_EN, + B_AX_FEN_BBRSTB | B_AX_FEN_BB_GLB_RSTN); + rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + rtw89_write32_clr(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + rtw89_write32_set(rtwdev, R_AX_WLRF_CTRL, B_AX_AFC_AFEDIG); + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xC7, + FULL_BIT_MASK); + if (ret) + return ret; + + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xC7, + FULL_BIT_MASK); + if (ret) + return ret; + + rtw89_write8(rtwdev, R_AX_PHYREG_SET, PHYREG_SET_XYN_CYCLE); + + return 0; +} + +static int rtw8851b_mac_disable_bb_rf(struct rtw89_dev *rtwdev) +{ + u8 wl_rfc_s0; + u8 wl_rfc_s1; + int ret; + + rtw89_write8_clr(rtwdev, R_AX_SYS_FUNC_EN, + B_AX_FEN_BBRSTB | B_AX_FEN_BB_GLB_RSTN); + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, &wl_rfc_s0); + if (ret) + return ret; + wl_rfc_s0 &= ~XTAL_SI_RF00S_EN; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, wl_rfc_s0, + FULL_BIT_MASK); + if (ret) + return ret; + + ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, &wl_rfc_s1); + if (ret) + return ret; + wl_rfc_s1 &= ~XTAL_SI_RF10S_EN; + ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, wl_rfc_s1, + FULL_BIT_MASK); + return ret; +} + static const struct rtw89_chip_ops rtw8851b_chip_ops = { + .enable_bb_rf = rtw8851b_mac_enable_bb_rf, + .disable_bb_rf = rtw8851b_mac_disable_bb_rf, + .bb_reset = rtw8851b_bb_reset, + .bb_sethw = rtw8851b_bb_sethw, + .read_rf = rtw89_phy_read_rf_v1, + .write_rf = rtw89_phy_write_rf_v1, .fem_setup = NULL, .rfe_gpio = rtw8851b_rfe_gpio, + .pwr_on_func = rtw8851b_pwr_on_func, + .pwr_off_func = rtw8851b_pwr_off_func, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, .h2c_dctl_sec_cam = NULL, -- cgit v1.2.3 From e948213fb8560f6d6af6058351758f13a35c9f8d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 May 2023 14:12:19 +0800 Subject: wifi: rtw89: 8851b: add set channel function Set MAC/BB/RF registers according to channel we are going to set. In additional, certain channels or bands need more deals, such as enable CCK in 2 GHz band, spur elimination at certain frequencies. The set channel helper is used to save/restore states before/after setting channel, and does reset BB to prevent hardware getting stuck in abnormal state during switching channel and receiving data. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230512061220.16544-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 14 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 703 ++++++++++++++++++++++++++ 2 files changed, 717 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 4508641e2abb..d10c1d4813a3 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3999,6 +3999,7 @@ #define R_S0_HW_SI_DIS 0x1200 #define B_S0_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) #define R_P0_RXCK 0x12A0 +#define B_P0_RXCK_ADJ GENMASK(31, 23) #define B_P0_RXCK_BW3 BIT(30) #define B_P0_TXCK_ALL GENMASK(19, 12) #define B_P0_RXCK_ON BIT(19) @@ -4155,8 +4156,10 @@ #define R_DCFO 0x4264 #define B_DCFO GENMASK(7, 0) #define R_SEG0CSI 0x42AC +#define R_SEG0CSI_V1 0x42B0 #define B_SEG0CSI_IDX GENMASK(10, 0) #define R_SEG0CSI_EN 0x42C4 +#define R_SEG0CSI_EN_V1 0x42C8 #define B_SEG0CSI_EN BIT(23) #define R_BSS_CLR_MAP 0x43ac #define R_BSS_CLR_MAP_V1 0x43B0 @@ -4388,6 +4391,12 @@ #define B_PATH0_BT_BACKOFF_V1 GENMASK(23, 0) #define R_PATH1_BT_BACKOFF_V1 0x4AEC #define B_PATH1_BT_BACKOFF_V1 GENMASK(23, 0) +#define R_PATH0_TX_CFR 0x4B30 +#define B_PATH0_TX_CFR_LGC1 GENMASK(19, 10) +#define B_PATH0_TX_CFR_LGC0 GENMASK(9, 0) +#define R_PATH0_TX_POLAR_CLIPPING 0x4B3C +#define B_PATH0_TX_POLAR_CLIPPING_LGC1 GENMASK(19, 16) +#define B_PATH0_TX_POLAR_CLIPPING_LGC0 GENMASK(15, 12) #define R_PATH0_FRC_FIR_TYPE_V1 0x4C00 #define B_PATH0_FRC_FIR_TYPE_MSK_V1 GENMASK(1, 0) #define R_PATH0_NOTCH 0x4C14 @@ -4843,11 +4852,16 @@ #define R_P0_CFCH_BW1 0xC0D8 #define B_P0_CFCH_EX BIT(13) #define B_P0_CFCH_BW1 GENMASK(8, 5) +#define R_WDADC 0xC0E4 +#define B_WDADC_SEL GENMASK(5, 4) #define R_ADCMOD 0xC0E8 #define B_ADCMOD_LP GENMASK(31, 16) +#define R_DCIM 0xC0EC +#define B_DCIM_FR GENMASK(14, 13) #define R_ADDCK0D 0xC0F0 #define B_ADDCK0D_VAL2 GENMASK(31, 26) #define B_ADDCK0D_VAL GENMASK(25, 16) +#define B_ADDCK_DS BIT(16) #define R_ADDCK0 0xC0F4 #define B_ADDCK0_TRG BIT(11) #define B_ADDCK0_IQ BIT(10) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 6c86edc74e95..898a509454a1 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -9,6 +9,7 @@ #include "phy.h" #include "reg.h" #include "rtw8851b.h" +#include "rtw8851b_rfk.h" #include "rtw8851b_rfk_table.h" #include "rtw8851b_table.h" #include "txrx.h" @@ -358,6 +359,593 @@ static void rtw8851b_rfe_gpio(struct rtw89_dev *rtwdev) } } +static void rtw8851b_set_channel_mac(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + u8 mac_idx) +{ + u32 sub_carr = rtw89_mac_reg_by_idx(R_AX_TX_SUB_CARRIER_VALUE, mac_idx); + u32 chk_rate = rtw89_mac_reg_by_idx(R_AX_TXRATE_CHK, mac_idx); + u32 rf_mod = rtw89_mac_reg_by_idx(R_AX_WMAC_RFMOD, mac_idx); + u8 txsc20 = 0, txsc40 = 0; + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_80: + txsc40 = rtw89_phy_get_txsc(rtwdev, chan, RTW89_CHANNEL_WIDTH_40); + fallthrough; + case RTW89_CHANNEL_WIDTH_40: + txsc20 = rtw89_phy_get_txsc(rtwdev, chan, RTW89_CHANNEL_WIDTH_20); + break; + default: + break; + } + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_80: + rtw89_write8_mask(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK, BIT(1)); + rtw89_write32(rtwdev, sub_carr, txsc20 | (txsc40 << 4)); + break; + case RTW89_CHANNEL_WIDTH_40: + rtw89_write8_mask(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK, BIT(0)); + rtw89_write32(rtwdev, sub_carr, txsc20); + break; + case RTW89_CHANNEL_WIDTH_20: + rtw89_write8_clr(rtwdev, rf_mod, B_AX_WMAC_RFMOD_MASK); + rtw89_write32(rtwdev, sub_carr, 0); + break; + default: + break; + } + + if (chan->channel > 14) { + rtw89_write8_clr(rtwdev, chk_rate, B_AX_BAND_MODE); + rtw89_write8_set(rtwdev, chk_rate, + B_AX_CHECK_CCK_EN | B_AX_RTS_LIMIT_IN_OFDM6); + } else { + rtw89_write8_set(rtwdev, chk_rate, B_AX_BAND_MODE); + rtw89_write8_clr(rtwdev, chk_rate, + B_AX_CHECK_CCK_EN | B_AX_RTS_LIMIT_IN_OFDM6); + } +} + +static const u32 rtw8851b_sco_barker_threshold[14] = { + 0x1cfea, 0x1d0e1, 0x1d1d7, 0x1d2cd, 0x1d3c3, 0x1d4b9, 0x1d5b0, 0x1d6a6, + 0x1d79c, 0x1d892, 0x1d988, 0x1da7f, 0x1db75, 0x1ddc4 +}; + +static const u32 rtw8851b_sco_cck_threshold[14] = { + 0x27de3, 0x27f35, 0x28088, 0x281da, 0x2832d, 0x2847f, 0x285d2, 0x28724, + 0x28877, 0x289c9, 0x28b1c, 0x28c6e, 0x28dc1, 0x290ed +}; + +static void rtw8851b_ctrl_sco_cck(struct rtw89_dev *rtwdev, u8 primary_ch) +{ + u8 ch_element = primary_ch - 1; + + rtw89_phy_write32_mask(rtwdev, R_RXSCOBC, B_RXSCOBC_TH, + rtw8851b_sco_barker_threshold[ch_element]); + rtw89_phy_write32_mask(rtwdev, R_RXSCOCCK, B_RXSCOCCK_TH, + rtw8851b_sco_cck_threshold[ch_element]); +} + +static u8 rtw8851b_sco_mapping(u8 central_ch) +{ + if (central_ch == 1) + return 109; + else if (central_ch >= 2 && central_ch <= 6) + return 108; + else if (central_ch >= 7 && central_ch <= 10) + return 107; + else if (central_ch >= 11 && central_ch <= 14) + return 106; + else if (central_ch == 36 || central_ch == 38) + return 51; + else if (central_ch >= 40 && central_ch <= 58) + return 50; + else if (central_ch >= 60 && central_ch <= 64) + return 49; + else if (central_ch == 100 || central_ch == 102) + return 48; + else if (central_ch >= 104 && central_ch <= 126) + return 47; + else if (central_ch >= 128 && central_ch <= 151) + return 46; + else if (central_ch >= 153 && central_ch <= 177) + return 45; + else + return 0; +} + +struct rtw8851b_bb_gain { + u32 gain_g[BB_PATH_NUM_8851B]; + u32 gain_a[BB_PATH_NUM_8851B]; + u32 gain_mask; +}; + +static const struct rtw8851b_bb_gain bb_gain_lna[LNA_GAIN_NUM] = { + { .gain_g = {0x4678}, .gain_a = {0x45DC}, + .gain_mask = 0x00ff0000 }, + { .gain_g = {0x4678}, .gain_a = {0x45DC}, + .gain_mask = 0xff000000 }, + { .gain_g = {0x467C}, .gain_a = {0x4660}, + .gain_mask = 0x000000ff }, + { .gain_g = {0x467C}, .gain_a = {0x4660}, + .gain_mask = 0x0000ff00 }, + { .gain_g = {0x467C}, .gain_a = {0x4660}, + .gain_mask = 0x00ff0000 }, + { .gain_g = {0x467C}, .gain_a = {0x4660}, + .gain_mask = 0xff000000 }, + { .gain_g = {0x4680}, .gain_a = {0x4664}, + .gain_mask = 0x000000ff }, +}; + +static const struct rtw8851b_bb_gain bb_gain_tia[TIA_GAIN_NUM] = { + { .gain_g = {0x4680}, .gain_a = {0x4664}, + .gain_mask = 0x00ff0000 }, + { .gain_g = {0x4680}, .gain_a = {0x4664}, + .gain_mask = 0xff000000 }, +}; + +static void rtw8851b_set_gain_error(struct rtw89_dev *rtwdev, + enum rtw89_subband subband, + enum rtw89_rf_path path) +{ + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + u8 gain_band = rtw89_subband_to_bb_gain_band(subband); + s32 val; + u32 reg; + u32 mask; + int i; + + for (i = 0; i < LNA_GAIN_NUM; i++) { + if (subband == RTW89_CH_2G) + reg = bb_gain_lna[i].gain_g[path]; + else + reg = bb_gain_lna[i].gain_a[path]; + + mask = bb_gain_lna[i].gain_mask; + val = gain->lna_gain[gain_band][path][i]; + rtw89_phy_write32_mask(rtwdev, reg, mask, val); + } + + for (i = 0; i < TIA_GAIN_NUM; i++) { + if (subband == RTW89_CH_2G) + reg = bb_gain_tia[i].gain_g[path]; + else + reg = bb_gain_tia[i].gain_a[path]; + + mask = bb_gain_tia[i].gain_mask; + val = gain->tia_gain[gain_band][path][i]; + rtw89_phy_write32_mask(rtwdev, reg, mask, val); + } +} + +static void rtw8851b_set_gain_offset(struct rtw89_dev *rtwdev, + enum rtw89_subband subband, + enum rtw89_phy_idx phy_idx) +{ + static const u32 rssi_ofst_addr[] = {R_PATH0_G_TIA1_LNA6_OP1DB_V1}; + static const u32 gain_err_addr[] = {R_P0_AGC_RSVD}; + struct rtw89_phy_efuse_gain *efuse_gain = &rtwdev->efuse_gain; + enum rtw89_gain_offset gain_ofdm_band; + s32 offset_ofdm, offset_cck; + s32 offset_a; + s32 tmp; + u8 path; + + if (!efuse_gain->comp_valid) + goto next; + + for (path = RF_PATH_A; path < BB_PATH_NUM_8851B; path++) { + tmp = efuse_gain->comp[path][subband]; + tmp = clamp_t(s32, tmp << 2, S8_MIN, S8_MAX); + rtw89_phy_write32_mask(rtwdev, gain_err_addr[path], MASKBYTE0, tmp); + } + +next: + if (!efuse_gain->offset_valid) + return; + + gain_ofdm_band = rtw89_subband_to_gain_offset_band_of_ofdm(subband); + + offset_a = -efuse_gain->offset[RF_PATH_A][gain_ofdm_band]; + + tmp = -((offset_a << 2) + (efuse_gain->offset_base[RTW89_PHY_0] >> 2)); + tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); + rtw89_phy_write32_mask(rtwdev, rssi_ofst_addr[RF_PATH_A], B_PATH0_R_G_OFST_MASK, tmp); + + offset_ofdm = -efuse_gain->offset[RF_PATH_A][gain_ofdm_band]; + offset_cck = -efuse_gain->offset[RF_PATH_A][0]; + + tmp = (offset_ofdm << 4) + efuse_gain->offset_base[RTW89_PHY_0]; + tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); + rtw89_phy_write32_idx(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK, tmp, phy_idx); + + tmp = (offset_ofdm << 4) + efuse_gain->rssi_base[RTW89_PHY_0]; + tmp = clamp_t(s32, tmp, S8_MIN, S8_MAX); + rtw89_phy_write32_idx(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK, tmp, phy_idx); + + if (subband == RTW89_CH_2G) { + tmp = (offset_cck << 3) + (efuse_gain->offset_base[RTW89_PHY_0] >> 1); + tmp = clamp_t(s32, tmp, S8_MIN >> 1, S8_MAX >> 1); + rtw89_phy_write32_mask(rtwdev, R_RX_RPL_OFST, + B_RX_RPL_OFST_CCK_MASK, tmp); + } +} + +static +void rtw8851b_set_rxsc_rpl_comp(struct rtw89_dev *rtwdev, enum rtw89_subband subband) +{ + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + u8 band = rtw89_subband_to_bb_gain_band(subband); + u32 val; + + val = u32_encode_bits(gain->rpl_ofst_20[band][RF_PATH_A], B_P0_RPL1_20_MASK) | + u32_encode_bits(gain->rpl_ofst_40[band][RF_PATH_A][0], B_P0_RPL1_40_MASK) | + u32_encode_bits(gain->rpl_ofst_40[band][RF_PATH_A][1], B_P0_RPL1_41_MASK); + val >>= B_P0_RPL1_SHIFT; + rtw89_phy_write32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_MASK, val); + rtw89_phy_write32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_MASK, val); + + val = u32_encode_bits(gain->rpl_ofst_40[band][RF_PATH_A][2], B_P0_RTL2_42_MASK) | + u32_encode_bits(gain->rpl_ofst_80[band][RF_PATH_A][0], B_P0_RTL2_80_MASK) | + u32_encode_bits(gain->rpl_ofst_80[band][RF_PATH_A][1], B_P0_RTL2_81_MASK) | + u32_encode_bits(gain->rpl_ofst_80[band][RF_PATH_A][10], B_P0_RTL2_8A_MASK); + rtw89_phy_write32(rtwdev, R_P0_RPL2, val); + rtw89_phy_write32(rtwdev, R_P1_RPL2, val); + + val = u32_encode_bits(gain->rpl_ofst_80[band][RF_PATH_A][2], B_P0_RTL3_82_MASK) | + u32_encode_bits(gain->rpl_ofst_80[band][RF_PATH_A][3], B_P0_RTL3_83_MASK) | + u32_encode_bits(gain->rpl_ofst_80[band][RF_PATH_A][4], B_P0_RTL3_84_MASK) | + u32_encode_bits(gain->rpl_ofst_80[band][RF_PATH_A][9], B_P0_RTL3_89_MASK); + rtw89_phy_write32(rtwdev, R_P0_RPL3, val); + rtw89_phy_write32(rtwdev, R_P1_RPL3, val); +} + +static void rtw8851b_ctrl_ch(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + u8 subband = chan->subband_type; + u8 central_ch = chan->channel; + bool is_2g = central_ch <= 14; + u8 sco_comp; + + if (is_2g) + rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, + B_PATH0_BAND_SEL_MSK_V1, 1, phy_idx); + else + rtw89_phy_write32_idx(rtwdev, R_PATH0_BAND_SEL_V1, + B_PATH0_BAND_SEL_MSK_V1, 0, phy_idx); + /* SCO compensate FC setting */ + sco_comp = rtw8851b_sco_mapping(central_ch); + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_INV, sco_comp, phy_idx); + + if (chan->band_type == RTW89_BAND_6G) + return; + + /* CCK parameters */ + if (central_ch == 14) { + rtw89_phy_write32_mask(rtwdev, R_TXFIR0, B_TXFIR_C01, 0x3b13ff); + rtw89_phy_write32_mask(rtwdev, R_TXFIR2, B_TXFIR_C23, 0x1c42de); + rtw89_phy_write32_mask(rtwdev, R_TXFIR4, B_TXFIR_C45, 0xfdb0ad); + rtw89_phy_write32_mask(rtwdev, R_TXFIR6, B_TXFIR_C67, 0xf60f6e); + rtw89_phy_write32_mask(rtwdev, R_TXFIR8, B_TXFIR_C89, 0xfd8f92); + rtw89_phy_write32_mask(rtwdev, R_TXFIRA, B_TXFIR_CAB, 0x2d011); + rtw89_phy_write32_mask(rtwdev, R_TXFIRC, B_TXFIR_CCD, 0x1c02c); + rtw89_phy_write32_mask(rtwdev, R_TXFIRE, B_TXFIR_CEF, 0xfff00a); + } else { + rtw89_phy_write32_mask(rtwdev, R_TXFIR0, B_TXFIR_C01, 0x3d23ff); + rtw89_phy_write32_mask(rtwdev, R_TXFIR2, B_TXFIR_C23, 0x29b354); + rtw89_phy_write32_mask(rtwdev, R_TXFIR4, B_TXFIR_C45, 0xfc1c8); + rtw89_phy_write32_mask(rtwdev, R_TXFIR6, B_TXFIR_C67, 0xfdb053); + rtw89_phy_write32_mask(rtwdev, R_TXFIR8, B_TXFIR_C89, 0xf86f9a); + rtw89_phy_write32_mask(rtwdev, R_TXFIRA, B_TXFIR_CAB, 0xfaef92); + rtw89_phy_write32_mask(rtwdev, R_TXFIRC, B_TXFIR_CCD, 0xfe5fcc); + rtw89_phy_write32_mask(rtwdev, R_TXFIRE, B_TXFIR_CEF, 0xffdff5); + } + + rtw8851b_set_gain_error(rtwdev, subband, RF_PATH_A); + rtw8851b_set_gain_offset(rtwdev, subband, phy_idx); + rtw8851b_set_rxsc_rpl_comp(rtwdev, subband); +} + +static void rtw8851b_bw_setting(struct rtw89_dev *rtwdev, u8 bw) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, 0x4); + rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_MUL, 0xf); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_LP, 0xa); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); + + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x1); + rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x1); + break; + case RTW89_CHANNEL_WIDTH_10: + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x1); + rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + break; + case RTW89_CHANNEL_WIDTH_20: + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x2); + rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + break; + case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x2); + rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + break; + case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x0); + rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); + rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + break; + default: + rtw89_warn(rtwdev, "Fail to set ADC\n"); + } +} + +static void rtw8851b_ctrl_bw(struct rtw89_dev *rtwdev, u8 pri_ch, u8 bw, + enum rtw89_phy_idx phy_idx) +{ + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_10: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_20: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, 0x0, phy_idx); + break; + case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, + pri_ch, phy_idx); + /* CCK primary channel */ + if (pri_ch == RTW89_SC_20_UPPER) + rtw89_phy_write32_mask(rtwdev, R_RXSC, B_RXSC_EN, 1); + else + rtw89_phy_write32_mask(rtwdev, R_RXSC, B_RXSC_EN, 0); + + break; + case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_idx(rtwdev, R_FC0_BW_V1, B_FC0_BW_SET, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_SBW, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD_V1, B_CHBW_MOD_PRICH, + pri_ch, phy_idx); + break; + default: + rtw89_warn(rtwdev, "Fail to switch bw (bw:%d, pri ch:%d)\n", bw, + pri_ch); + } + + rtw8851b_bw_setting(rtwdev, bw); +} + +static void rtw8851b_ctrl_cck_en(struct rtw89_dev *rtwdev, bool cck_en) +{ + if (cck_en) { + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0); + rtw89_phy_write32_mask(rtwdev, R_PD_ARBITER_OFF, + B_PD_ARBITER_OFF, 0); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 1); + } else { + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 1); + rtw89_phy_write32_mask(rtwdev, R_PD_ARBITER_OFF, + B_PD_ARBITER_OFF, 1); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK_ADC, B_ENABLE_CCK, 0); + } +} + +static u32 rtw8851b_spur_freq(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + u8 center_chan = chan->channel; + + switch (chan->band_type) { + case RTW89_BAND_5G: + if (center_chan == 151 || center_chan == 153 || + center_chan == 155 || center_chan == 163) + return 5760; + else if (center_chan == 54 || center_chan == 58) + return 5280; + break; + default: + break; + } + + return 0; +} + +#define CARRIER_SPACING_312_5 312500 /* 312.5 kHz */ +#define CARRIER_SPACING_78_125 78125 /* 78.125 kHz */ +#define MAX_TONE_NUM 2048 + +static void rtw8851b_set_csi_tone_idx(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + u32 spur_freq; + s32 freq_diff, csi_idx, csi_tone_idx; + + spur_freq = rtw8851b_spur_freq(rtwdev, chan); + if (spur_freq == 0) { + rtw89_phy_write32_idx(rtwdev, R_SEG0CSI_EN_V1, B_SEG0CSI_EN, + 0, phy_idx); + return; + } + + freq_diff = (spur_freq - chan->freq) * 1000000; + csi_idx = s32_div_u32_round_closest(freq_diff, CARRIER_SPACING_78_125); + s32_div_u32_round_down(csi_idx, MAX_TONE_NUM, &csi_tone_idx); + + rtw89_phy_write32_idx(rtwdev, R_SEG0CSI_V1, B_SEG0CSI_IDX, + csi_tone_idx, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_SEG0CSI_EN_V1, B_SEG0CSI_EN, 1, phy_idx); +} + +static const struct rtw89_nbi_reg_def rtw8851b_nbi_reg_def = { + .notch1_idx = {0x46E4, 0xFF}, + .notch1_frac_idx = {0x46E4, 0xC00}, + .notch1_en = {0x46E4, 0x1000}, + .notch2_idx = {0x47A4, 0xFF}, + .notch2_frac_idx = {0x47A4, 0xC00}, + .notch2_en = {0x47A4, 0x1000}, +}; + +static void rtw8851b_set_nbi_tone_idx(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + const struct rtw89_nbi_reg_def *nbi = &rtw8851b_nbi_reg_def; + s32 nbi_frac_idx, nbi_frac_tone_idx; + s32 nbi_idx, nbi_tone_idx; + bool notch2_chk = false; + u32 spur_freq, fc; + s32 freq_diff; + + spur_freq = rtw8851b_spur_freq(rtwdev, chan); + if (spur_freq == 0) { + rtw89_phy_write32_mask(rtwdev, nbi->notch1_en.addr, + nbi->notch1_en.mask, 0); + rtw89_phy_write32_mask(rtwdev, nbi->notch2_en.addr, + nbi->notch2_en.mask, 0); + return; + } + + fc = chan->freq; + if (chan->band_width == RTW89_CHANNEL_WIDTH_160) { + fc = (spur_freq > fc) ? fc + 40 : fc - 40; + if ((fc > spur_freq && + chan->channel < chan->primary_channel) || + (fc < spur_freq && + chan->channel > chan->primary_channel)) + notch2_chk = true; + } + + freq_diff = (spur_freq - fc) * 1000000; + nbi_idx = s32_div_u32_round_down(freq_diff, CARRIER_SPACING_312_5, + &nbi_frac_idx); + + if (chan->band_width == RTW89_CHANNEL_WIDTH_20) { + s32_div_u32_round_down(nbi_idx + 32, 64, &nbi_tone_idx); + } else { + u16 tone_para = (chan->band_width == RTW89_CHANNEL_WIDTH_40) ? + 128 : 256; + + s32_div_u32_round_down(nbi_idx, tone_para, &nbi_tone_idx); + } + nbi_frac_tone_idx = s32_div_u32_round_closest(nbi_frac_idx, + CARRIER_SPACING_78_125); + + if (chan->band_width == RTW89_CHANNEL_WIDTH_160 && notch2_chk) { + rtw89_phy_write32_mask(rtwdev, nbi->notch2_idx.addr, + nbi->notch2_idx.mask, nbi_tone_idx); + rtw89_phy_write32_mask(rtwdev, nbi->notch2_frac_idx.addr, + nbi->notch2_frac_idx.mask, nbi_frac_tone_idx); + rtw89_phy_write32_mask(rtwdev, nbi->notch2_en.addr, + nbi->notch2_en.mask, 0); + rtw89_phy_write32_mask(rtwdev, nbi->notch2_en.addr, + nbi->notch2_en.mask, 1); + rtw89_phy_write32_mask(rtwdev, nbi->notch1_en.addr, + nbi->notch1_en.mask, 0); + } else { + rtw89_phy_write32_mask(rtwdev, nbi->notch1_idx.addr, + nbi->notch1_idx.mask, nbi_tone_idx); + rtw89_phy_write32_mask(rtwdev, nbi->notch1_frac_idx.addr, + nbi->notch1_frac_idx.mask, nbi_frac_tone_idx); + rtw89_phy_write32_mask(rtwdev, nbi->notch1_en.addr, + nbi->notch1_en.mask, 0); + rtw89_phy_write32_mask(rtwdev, nbi->notch1_en.addr, + nbi->notch1_en.mask, 1); + rtw89_phy_write32_mask(rtwdev, nbi->notch2_en.addr, + nbi->notch2_en.mask, 0); + } +} + +static void rtw8851b_set_cfr(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan) +{ + if (chan->band_type == RTW89_BAND_2G && + chan->band_width == RTW89_CHANNEL_WIDTH_20 && + (chan->channel == 1 || chan->channel == 13)) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_TX_CFR, + B_PATH0_TX_CFR_LGC0, 0xf8); + rtw89_phy_write32_mask(rtwdev, R_PATH0_TX_CFR, + B_PATH0_TX_CFR_LGC1, 0x120); + rtw89_phy_write32_mask(rtwdev, R_PATH0_TX_POLAR_CLIPPING, + B_PATH0_TX_POLAR_CLIPPING_LGC0, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_TX_POLAR_CLIPPING, + B_PATH0_TX_POLAR_CLIPPING_LGC1, 0x3); + } else { + rtw89_phy_write32_mask(rtwdev, R_PATH0_TX_CFR, + B_PATH0_TX_CFR_LGC0, 0x120); + rtw89_phy_write32_mask(rtwdev, R_PATH0_TX_CFR, + B_PATH0_TX_CFR_LGC1, 0x3ff); + rtw89_phy_write32_mask(rtwdev, R_PATH0_TX_POLAR_CLIPPING, + B_PATH0_TX_POLAR_CLIPPING_LGC0, 0x3); + rtw89_phy_write32_mask(rtwdev, R_PATH0_TX_POLAR_CLIPPING, + B_PATH0_TX_POLAR_CLIPPING_LGC1, 0x7); + } +} + +static void rtw8851b_5m_mask(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + u8 pri_ch = chan->pri_ch_idx; + bool mask_5m_low; + bool mask_5m_en; + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_40: + /* Prich=1: Mask 5M High, Prich=2: Mask 5M Low */ + mask_5m_en = true; + mask_5m_low = pri_ch == RTW89_SC_20_LOWER; + break; + case RTW89_CHANNEL_WIDTH_80: + /* Prich=3: Mask 5M High, Prich=4: Mask 5M Low, Else: Disable */ + mask_5m_en = pri_ch == RTW89_SC_20_UPMOST || + pri_ch == RTW89_SC_20_LOWEST; + mask_5m_low = pri_ch == RTW89_SC_20_LOWEST; + break; + default: + mask_5m_en = false; + break; + } + + if (!mask_5m_en) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x0); + rtw89_phy_write32_idx(rtwdev, R_ASSIGN_SBD_OPT_V1, + B_ASSIGN_SBD_OPT_EN_V1, 0x0, phy_idx); + return; + } + + if (mask_5m_low) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_TH, 0x5); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB0, 0x1); + } else { + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_TH, 0x5); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB2, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_5MDET_V1, B_PATH0_5MDET_SB0, 0x0); + } + rtw89_phy_write32_idx(rtwdev, R_ASSIGN_SBD_OPT_V1, + B_ASSIGN_SBD_OPT_EN_V1, 0x1, phy_idx); +} + static void rtw8851b_bb_reset_all(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, B_S0_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); @@ -368,6 +956,26 @@ static void rtw8851b_bb_reset_all(struct rtw89_dev *rtwdev, enum rtw89_phy_idx p rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); } +static void rtw8851b_bb_reset_en(struct rtw89_dev *rtwdev, enum rtw89_band band, + enum rtw89_phy_idx phy_idx, bool en) +{ + if (en) { + rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, + B_S0_HW_SI_DIS_W_R_TRIG, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 1, phy_idx); + if (band == RTW89_BAND_2G) + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x0); + } else { + rtw89_phy_write32_mask(rtwdev, R_RXCCA, B_RXCCA_DIS, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PD_CTRL, B_PD_HIT_DIS, 0x1); + rtw89_phy_write32_idx(rtwdev, R_S0_HW_SI_DIS, + B_S0_HW_SI_DIS_W_R_TRIG, 0x7, phy_idx); + fsleep(1); + rtw89_phy_write32_idx(rtwdev, R_RSTB_ASYNC, B_RSTB_ASYNC_ALL, 0, phy_idx); + } +} + static void rtw8851b_bb_reset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -448,6 +1056,99 @@ static void rtw8851b_bb_sethw(struct rtw89_dev *rtwdev) rtw89_phy_read32_mask(rtwdev, R_P1_RPL1, B_P0_RPL1_BIAS_MASK); } +static void rtw8851b_set_channel_bb(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + u8 band = chan->band_type, chan_idx; + bool cck_en = chan->channel <= 14; + u8 pri_ch_idx = chan->pri_ch_idx; + + if (cck_en) + rtw8851b_ctrl_sco_cck(rtwdev, chan->primary_channel); + + rtw8851b_ctrl_ch(rtwdev, chan, phy_idx); + rtw8851b_ctrl_bw(rtwdev, pri_ch_idx, chan->band_width, phy_idx); + rtw8851b_ctrl_cck_en(rtwdev, cck_en); + rtw8851b_set_nbi_tone_idx(rtwdev, chan); + rtw8851b_set_csi_tone_idx(rtwdev, chan, phy_idx); + + if (chan->band_type == RTW89_BAND_5G) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, + B_PATH0_BT_SHARE_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, + B_PATH0_BTG_PATH_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x0); + rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, + B_BT_DYN_DC_EST_EN_MSK, 0x0); + rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0); + } + + chan_idx = rtw89_encode_chan_idx(rtwdev, chan->primary_channel, band); + rtw89_phy_write32_mask(rtwdev, R_MAC_PIN_SEL, B_CH_IDX_SEG0, chan_idx); + rtw8851b_5m_mask(rtwdev, chan, phy_idx); + rtw8851b_set_cfr(rtwdev, chan); + rtw8851b_bb_reset_all(rtwdev, phy_idx); +} + +static void rtw8851b_set_channel(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_mac_idx mac_idx, + enum rtw89_phy_idx phy_idx) +{ + rtw8851b_set_channel_mac(rtwdev, chan, mac_idx); + rtw8851b_set_channel_bb(rtwdev, chan, phy_idx); + rtw8851b_set_channel_rf(rtwdev, chan, phy_idx); +} + +static void rtw8851b_tssi_cont_en(struct rtw89_dev *rtwdev, bool en, + enum rtw89_rf_path path) +{ + if (en) { + rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, B_P0_TXPW_RSTB_MANON, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_TRK_EN, 0x0); + } else { + rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, B_P0_TXPW_RSTB_MANON, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_TRK_EN, 0x1); + } +} + +static void rtw8851b_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, + u8 phy_idx) +{ + rtw8851b_tssi_cont_en(rtwdev, en, RF_PATH_A); +} + +static void rtw8851b_adc_en(struct rtw89_dev *rtwdev, bool en) +{ + if (en) + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RST, 0x0); + else + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RST, 0xf); +} + +static void rtw8851b_set_channel_help(struct rtw89_dev *rtwdev, bool enter, + struct rtw89_channel_help_params *p, + const struct rtw89_chan *chan, + enum rtw89_mac_idx mac_idx, + enum rtw89_phy_idx phy_idx) +{ + if (enter) { + rtw89_chip_stop_sch_tx(rtwdev, RTW89_MAC_0, &p->tx_en, RTW89_SCH_TX_SEL_ALL); + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, false); + rtw8851b_tssi_cont_en_phyidx(rtwdev, false, RTW89_PHY_0); + rtw8851b_adc_en(rtwdev, false); + fsleep(40); + rtw8851b_bb_reset_en(rtwdev, chan->band_type, phy_idx, false); + } else { + rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true); + rtw8851b_adc_en(rtwdev, true); + rtw8851b_tssi_cont_en_phyidx(rtwdev, true, RTW89_PHY_0); + rtw8851b_bb_reset_en(rtwdev, chan->band_type, phy_idx, true); + rtw89_chip_resume_sch_tx(rtwdev, RTW89_MAC_0, p->tx_en); + } +} + static void rtw8851b_btc_set_rfe(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -798,6 +1499,8 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .bb_sethw = rtw8851b_bb_sethw, .read_rf = rtw89_phy_read_rf_v1, .write_rf = rtw89_phy_write_rf_v1, + .set_channel = rtw8851b_set_channel, + .set_channel_help = rtw8851b_set_channel_help, .fem_setup = NULL, .rfe_gpio = rtw8851b_rfe_gpio, .pwr_on_func = rtw8851b_pwr_on_func, -- cgit v1.2.3 From f4244d7fbc9163a44272c0a9d86fd0784d28f386 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 12 May 2023 14:12:20 +0800 Subject: wifi: rtw89: 8851b: add to parse efuse content Parse efuse content to recognize MAC address, RFE type, XTAL offset and so on. And, parse offset of PHY capability to retrieve TX power calibration data. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230512061220.16544-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 208 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.h | 61 ++++++++ 2 files changed, 269 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 898a509454a1..6ecdd3d3f776 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -296,6 +296,212 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) return 0; } +static void rtw8851b_efuse_parsing(struct rtw89_efuse *efuse, + struct rtw8851b_efuse *map) +{ + ether_addr_copy(efuse->addr, map->e.mac_addr); + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; +} + +static void rtw8851b_efuse_parsing_tssi(struct rtw89_dev *rtwdev, + struct rtw8851b_efuse *map) +{ + struct rtw89_tssi_info *tssi = &rtwdev->tssi; + struct rtw8851b_tssi_offset *ofst[] = {&map->path_a_tssi}; + u8 i, j; + + tssi->thermal[RF_PATH_A] = map->path_a_therm; + + for (i = 0; i < RF_PATH_NUM_8851B; i++) { + memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi, + sizeof(ofst[i]->cck_tssi)); + + for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n", + i, j, tssi->tssi_cck[i][j]); + + memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi, + sizeof(ofst[i]->bw40_tssi)); + memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM, + ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g)); + + for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n", + i, j, tssi->tssi_mcs[i][j]); + } +} + +static bool _decode_efuse_gain(u8 data, s8 *high, s8 *low) +{ + if (high) + *high = sign_extend32(u8_get_bits(data, GENMASK(7, 4)), 3); + if (low) + *low = sign_extend32(u8_get_bits(data, GENMASK(3, 0)), 3); + + return data != 0xff; +} + +static void rtw8851b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev, + struct rtw8851b_efuse *map) +{ + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + bool valid = false; + + valid |= _decode_efuse_gain(map->rx_gain_2g_cck, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK], + NULL); + valid |= _decode_efuse_gain(map->rx_gain_2g_ofdm, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM], + NULL); + valid |= _decode_efuse_gain(map->rx_gain_5g_low, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW], + NULL); + valid |= _decode_efuse_gain(map->rx_gain_5g_mid, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID], + NULL); + valid |= _decode_efuse_gain(map->rx_gain_5g_high, + &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH], + NULL); + + gain->offset_valid = valid; +} + +static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map) +{ + struct rtw89_efuse *efuse = &rtwdev->efuse; + struct rtw8851b_efuse *map; + + map = (struct rtw8851b_efuse *)log_map; + + efuse->country_code[0] = map->country_code[0]; + efuse->country_code[1] = map->country_code[1]; + rtw8851b_efuse_parsing_tssi(rtwdev, map); + rtw8851b_efuse_parsing_gain_offset(rtwdev, map); + + switch (rtwdev->hci.type) { + case RTW89_HCI_TYPE_PCIE: + rtw8851b_efuse_parsing(efuse, map); + break; + default: + return -EOPNOTSUPP; + } + + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); + + return 0; +} + +static void rtw8851b_phycap_parsing_tssi(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + struct rtw89_tssi_info *tssi = &rtwdev->tssi; + static const u32 tssi_trim_addr[RF_PATH_NUM_8851B] = {0x5D6}; + u32 addr = rtwdev->chip->phycap_addr; + bool pg = false; + u32 ofst; + u8 i, j; + + for (i = 0; i < RF_PATH_NUM_8851B; i++) { + for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) { + /* addrs are in decreasing order */ + ofst = tssi_trim_addr[i] - addr - j; + tssi->tssi_trim[i][j] = phycap_map[ofst]; + + if (phycap_map[ofst] != 0xff) + pg = true; + } + } + + if (!pg) { + memset(tssi->tssi_trim, 0, sizeof(tssi->tssi_trim)); + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM] no PG, set all trim info to 0\n"); + } + + for (i = 0; i < RF_PATH_NUM_8851B; i++) + for (j = 0; j < TSSI_TRIM_CH_GROUP_NUM; j++) + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] path=%d idx=%d trim=0x%x addr=0x%x\n", + i, j, tssi->tssi_trim[i][j], + tssi_trim_addr[i] - j); +} + +static void rtw8851b_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + static const u32 thm_trim_addr[RF_PATH_NUM_8851B] = {0x5DF}; + u32 addr = rtwdev->chip->phycap_addr; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8851B; i++) { + info->thermal_trim[i] = phycap_map[thm_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] path=%d thermal_trim=0x%x\n", + i, info->thermal_trim[i]); + + if (info->thermal_trim[i] != 0xff) + info->pg_thermal_trim = true; + } +} + +static void rtw8851b_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, + u8 *phycap_map) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + static const u32 pabias_trim_addr[] = {0x5DE}; + u32 addr = rtwdev->chip->phycap_addr; + u8 i; + + for (i = 0; i < RF_PATH_NUM_8851B; i++) { + info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n", + i, info->pa_bias_trim[i]); + + if (info->pa_bias_trim[i] != 0xff) + info->pg_pa_bias_trim = true; + } +} + +static void rtw8851b_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + static const u32 comp_addrs[][RTW89_SUBBAND_2GHZ_5GHZ_NR] = { + {0x5BB, 0x5BA, 0, 0x5B9, 0x5B8}, + }; + struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain; + u32 phycap_addr = rtwdev->chip->phycap_addr; + bool valid = false; + int path, i; + u8 data; + + for (path = 0; path < BB_PATH_NUM_8851B; path++) + for (i = 0; i < RTW89_SUBBAND_2GHZ_5GHZ_NR; i++) { + if (comp_addrs[path][i] == 0) + continue; + + data = phycap_map[comp_addrs[path][i] - phycap_addr]; + valid |= _decode_efuse_gain(data, NULL, + &gain->comp[path][i]); + } + + gain->comp_valid = valid; +} + +static int rtw8851b_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + rtw8851b_phycap_parsing_tssi(rtwdev, phycap_map); + rtw8851b_phycap_parsing_thermal_trim(rtwdev, phycap_map); + rtw8851b_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); + rtw8851b_phycap_parsing_gain_comp(rtwdev, phycap_map); + + return 0; +} + static void rtw8851b_set_bb_gpio(struct rtw89_dev *rtwdev, u8 gpio_idx, bool inv, u8 src_sel) { @@ -1501,6 +1707,8 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .write_rf = rtw89_phy_write_rf_v1, .set_channel = rtw8851b_set_channel, .set_channel_help = rtw8851b_set_channel_help, + .read_efuse = rtw8851b_read_efuse, + .read_phycap = rtw8851b_read_phycap, .fem_setup = NULL, .rfe_gpio = rtw8851b_rfe_gpio, .pwr_on_func = rtw8851b_pwr_on_func, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.h b/drivers/net/wireless/realtek/rtw89/rtw8851b.h index e34b7d09ad6d..1a5c52654d8a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.h @@ -10,6 +10,67 @@ #define RF_PATH_NUM_8851B 1 #define BB_PATH_NUM_8851B 1 +struct rtw8851bu_efuse { + u8 rsvd[0x88]; + u8 mac_addr[ETH_ALEN]; +}; + +struct rtw8851be_efuse { + u8 mac_addr[ETH_ALEN]; +}; + +struct rtw8851b_tssi_offset { + u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM]; + u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM]; + u8 rsvd[7]; + u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM]; +} __packed; + +struct rtw8851b_efuse { + u8 rsvd[0x210]; + struct rtw8851b_tssi_offset path_a_tssi; + u8 rsvd1[136]; + u8 channel_plan; + u8 xtal_k; + u8 rsvd2; + u8 iqk_lck; + u8 rsvd3[8]; + u8 eeprom_version; + u8 customer_id; + u8 tx_bb_swing_2g; + u8 tx_bb_swing_5g; + u8 tx_cali_pwr_trk_mode; + u8 trx_path_selection; + u8 rfe_type; + u8 country_code[2]; + u8 rsvd4[3]; + u8 path_a_therm; + u8 rsvd5[3]; + u8 rx_gain_2g_ofdm; + u8 rsvd6; + u8 rx_gain_2g_cck; + u8 rsvd7; + u8 rx_gain_5g_low; + u8 rsvd8; + u8 rx_gain_5g_mid; + u8 rsvd9; + u8 rx_gain_5g_high; + u8 rsvd10[35]; + u8 path_a_cck_pwr_idx[6]; + u8 path_a_bw40_1tx_pwr_idx[5]; + u8 path_a_ofdm_1tx_pwr_idx_diff:4; + u8 path_a_bw20_1tx_pwr_idx_diff:4; + u8 path_a_bw20_2tx_pwr_idx_diff:4; + u8 path_a_bw40_2tx_pwr_idx_diff:4; + u8 path_a_cck_2tx_pwr_idx_diff:4; + u8 path_a_ofdm_2tx_pwr_idx_diff:4; + u8 rsvd11[0xf2]; + union { + struct rtw8851bu_efuse u; + struct rtw8851be_efuse e; + }; +} __packed; + extern const struct rtw89_chip_info rtw8851b_chip_info; #endif -- cgit v1.2.3 From fe8a168266eb65d41ebee0b801fffb5278f92a1b Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 13 May 2023 13:44:23 +0800 Subject: wifi: rtw89: 8851b: rfk: add RX DCK RX DCK is receiver DC calibration. With this calibration, we have proper DC offset to reflect correct received signal strength indicator. Do this calibration when bringing up interface and going to run on AP channel. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230513054425.9689-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 111 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 1 + 3 files changed, 113 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index d10c1d4813a3..a16640d07813 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3841,6 +3841,7 @@ #define RR_CAL_RW BIT(19) #define RR_LUTWE2 0xee #define RR_LUTWE2_RTXBW BIT(2) +#define RR_LUTWE2_DIS BIT(6) #define RR_LUTWE 0xef #define RR_LUTWE_LOK BIT(2) #define RR_RFC 0xf0 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 6eb47ed82010..b12f985b0125 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -35,6 +35,17 @@ enum rtw8851b_iqk_type { ID_IQK_RESTORE = 0x10, }; +enum rf_mode { + RF_SHUT_DOWN = 0x0, + RF_STANDBY = 0x1, + RF_TX = 0x2, + RF_RX = 0x3, + RF_TXIQK = 0x4, + RF_DPK = 0x5, + RF_RXK1 = 0x6, + RF_RXK2 = 0x7, +}; + static const u32 g_idxrxgain[RTW8851B_RXK_GROUP_NR] = {0x10e, 0x116, 0x28e, 0x296}; static const u32 g_idxattc2[RTW8851B_RXK_GROUP_NR] = {0x0, 0xf, 0x0, 0xf}; static const u32 g_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x0, 0x1, 0x2, 0x3}; @@ -427,6 +438,91 @@ static void _dac_cal(struct rtw89_dev *rtwdev, bool force) rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]DACK finish!!!\n"); } +static void _rx_dck_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, bool is_afe) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] ==== S%d RX DCK (%s / CH%d / %s / by %s)====\n", path, + chan->band_type == RTW89_BAND_2G ? "2G" : + chan->band_type == RTW89_BAND_5G ? "5G" : "6G", + chan->channel, + chan->band_width == RTW89_CHANNEL_WIDTH_20 ? "20M" : + chan->band_width == RTW89_CHANNEL_WIDTH_40 ? "40M" : "80M", + is_afe ? "AFE" : "RFC"); +} + +static void _rxbb_ofst_swap(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 rf_mode) +{ + u32 val, val_i, val_q; + + val_i = rtw89_read_rf(rtwdev, path, RR_DCK, RR_DCK_S1); + val_q = rtw89_read_rf(rtwdev, path, RR_DCK1, RR_DCK1_S1); + + val = val_q << 4 | val_i; + + rtw89_write_rf(rtwdev, path, RR_LUTWE2, RR_LUTWE2_DIS, 0x1); + rtw89_write_rf(rtwdev, path, RR_LUTWA, RFREG_MASK, rf_mode); + rtw89_write_rf(rtwdev, path, RR_LUTWD0, RFREG_MASK, val); + rtw89_write_rf(rtwdev, path, RR_LUTWE2, RR_LUTWE2_DIS, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] val_i = 0x%x, val_q = 0x%x, 0x3F = 0x%x\n", + val_i, val_q, val); +} + +static void _set_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 rf_mode) +{ + u32 val; + int ret; + + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x0); + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x1); + + ret = read_poll_timeout_atomic(rtw89_read_rf, val, val, + 2, 2000, false, + rtwdev, path, RR_DCK, BIT(8)); + + rtw89_write_rf(rtwdev, path, RR_DCK, RR_DCK_LV, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[RX_DCK] S%d RXDCK finish (ret = %d)\n", + path, ret); + + _rxbb_ofst_swap(rtwdev, path, rf_mode); +} + +static void _rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_afe) +{ + u32 rf_reg5; + u8 path; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[RX_DCK] ****** RXDCK Start (Ver: 0x%x, Cv: %d) ******\n", + 0x2, rtwdev->hal.cv); + + for (path = 0; path < RF_PATH_NUM_8851B; path++) { + _rx_dck_info(rtwdev, phy, path, is_afe); + + rf_reg5 = rtw89_read_rf(rtwdev, path, RR_RSV1, RFREG_MASK); + + if (rtwdev->is_tssi_mode[path]) + rtw89_phy_write32_mask(rtwdev, + R_P0_TSSI_TRK + (path << 13), + B_P0_TSSI_TRK_EN, 0x1); + + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RF_RX); + _set_rx_dck(rtwdev, path, RF_RX); + rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5); + + if (rtwdev->is_tssi_mode[path]) + rtw89_phy_write32_mask(rtwdev, + R_P0_TSSI_TRK + (path << 13), + B_P0_TSSI_TRK_EN, 0x0); + } +} + static void _iqk_sram(struct rtw89_dev *rtwdev, u8 path) { u32 i; @@ -1553,6 +1649,21 @@ void rtw8851b_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_STOP); } +void rtw8851b_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); + u32 tx_en; + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_START); + rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); + _wait_rx_mode(rtwdev, _kpath(rtwdev, phy_idx)); + + _rx_dck(rtwdev, phy_idx, false); + + rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_STOP); +} + static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, enum rtw89_bandwidth bw, bool dav) { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h index d86c630ff47e..a77b3fd7f58a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -11,6 +11,7 @@ void rtw8851b_aack(struct rtw89_dev *rtwdev); void rtw8851b_rck(struct rtw89_dev *rtwdev); void rtw8851b_dack(struct rtw89_dev *rtwdev); void rtw8851b_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8851b_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); -- cgit v1.2.3 From 0194a95cbe721a1eff4af2587b09213b088281b0 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 13 May 2023 13:44:24 +0800 Subject: wifi: rtw89: 8851b: rfk: add DPK DPK is short for digital pre-distortion calibration. It can adjusts digital waveform according to PA linear characteristics dynamically to enhance TX EVM. Do this calibration when we are going to run on AP channel. To prevent power offset out of boundary, it monitors thermal and set proper boundary to register. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230513054425.9689-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 13 + drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 1048 +++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 3 + 3 files changed, 1064 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index a16640d07813..bb609f222019 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3325,6 +3325,10 @@ #define B_AX_TXAGC_BT_EN BIT(1) #define B_AX_TXAGC_BT_MASK GENMASK(11, 3) +#define R_AX_PWR_SWING_OTHER_CTRL0 0xD230 +#define R_AX_PWR_SWING_OTHER_CTRL0_C1 0xF230 +#define B_AX_CFIR_BY_RATE_OFF_MASK GENMASK(17, 0) + #define R_AX_PWR_UL_CTRL0 0xD240 #define R_AX_PWR_UL_CTRL2 0xD248 #define B_AX_PWR_UL_CFO_MASK GENMASK(2, 0) @@ -3755,6 +3759,7 @@ #define RR_RXA_DPK GENMASK(9, 8) #define RR_RXA_LNA 0x8b #define RR_RXA2 0x8c +#define RR_RAA2_SATT GENMASK(15, 13) #define RR_RAA2_SWATT GENMASK(15, 9) #define RR_RXA2_C1 GENMASK(12, 10) #define RR_RXA2_C2 GENMASK(9, 3) @@ -4074,6 +4079,7 @@ #define R_TXAGC_BB 0x1C60 #define B_TXAGC_BB_OFT GENMASK(31, 16) #define B_TXAGC_BB GENMASK(31, 24) +#define B_TXAGC_RF GENMASK(5, 0) #define R_S0_ADDCK 0x1E00 #define B_S0_ADDCK_I GENMASK(9, 0) #define B_S0_ADDCK_Q GENMASK(19, 10) @@ -4647,6 +4653,7 @@ #define R_MDPK_SYNC 0x8070 #define B_MDPK_SYNC_SEL BIT(31) #define B_MDPK_SYNC_MAN GENMASK(31, 28) +#define B_MDPK_SYNC_DMAN GENMASK(30, 28) #define R_MDPK_RX_DCK 0x8074 #define B_MDPK_RX_DCK_EN BIT(31) #define R_KIP_MOD 0x8078 @@ -4655,6 +4662,7 @@ #define R_KIP_SYSCFG 0x8088 #define R_KIP_CLK 0x808C #define R_DPK_IDL 0x809C +#define B_DPK_IDL_SEL GENMASK(10, 9) #define B_DPK_IDL BIT(8) #define R_LDL_NORM 0x80A0 #define B_LDL_NORM_MA BIT(16) @@ -4673,6 +4681,10 @@ #define B_KIP_RPT1_SEL GENMASK(21, 16) #define B_KIP_RPT1_SEL_V1 GENMASK(19, 16) #define R_SRAM_IQRX 0x80D8 +#define R_IDL_MPA 0x80DC +#define B_IDL_DN BIT(31) +#define B_IDL_MD530 BIT(1) +#define B_IDL_MD500 BIT(0) #define R_GAPK 0x80E0 #define B_GAPK_ADR BIT(0) #define R_SRAM_IQRX2 0x80E8 @@ -4760,6 +4772,7 @@ #define B_DPK_GL_A0 GENMASK(31, 28) #define B_DPK_GL_A1 GENMASK(17, 0) #define R_RPT_PER 0x81FC +#define B_RPT_PER_KSET GENMASK(31, 29) #define B_RPT_PER_TSSI GENMASK(28, 16) #define B_RPT_PER_OF GENMASK(15, 8) #define B_RPT_PER_TH GENMASK(5, 0) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index b12f985b0125..ab430d7e782f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -12,12 +12,47 @@ #include "rtw8851b_rfk_table.h" #include "rtw8851b_table.h" +#define DPK_VER_8851B 0x5 +#define DPK_KIP_REG_NUM_8851B 7 +#define DPK_RF_REG_NUM_8851B 4 +#define DPK_KSET_NUM 4 #define RTW8851B_RXK_GROUP_NR 4 #define RTW8851B_TXK_GROUP_NR 1 #define RTW8851B_IQK_VER 0x2a #define RTW8851B_IQK_SS 1 #define RTW8851B_LOK_GRAM 10 +enum dpk_id { + LBK_RXIQK = 0x06, + SYNC = 0x10, + MDPK_IDL = 0x11, + MDPK_MPA = 0x12, + GAIN_LOSS = 0x13, + GAIN_CAL = 0x14, + DPK_RXAGC = 0x15, + KIP_PRESET = 0x16, + KIP_RESTORE = 0x17, + DPK_TXAGC = 0x19, + D_KIP_PRESET = 0x28, + D_TXAGC = 0x29, + D_RXAGC = 0x2a, + D_SYNC = 0x2b, + D_GAIN_LOSS = 0x2c, + D_MDPK_IDL = 0x2d, + D_MDPK_LDL = 0x2e, + D_GAIN_NORM = 0x2f, + D_KIP_THERMAL = 0x30, + D_KIP_RESTORE = 0x31 +}; + +enum dpk_agc_step { + DPK_AGC_STEP_SYNC_DGAIN, + DPK_AGC_STEP_GAIN_LOSS_IDX, + DPK_AGC_STEP_GL_GT_CRITERION, + DPK_AGC_STEP_GL_LT_CRITERION, + DPK_AGC_STEP_SET_TX_GAIN, +}; + enum rtw8851b_iqk_type { ID_TXAGC = 0x0, ID_FLOK_COARSE = 0x1, @@ -68,6 +103,10 @@ static const u32 rtw8851b_backup_rf_regs[] = { #define BACKUP_BB_REGS_NR ARRAY_SIZE(rtw8851b_backup_bb_regs) #define BACKUP_RF_REGS_NR ARRAY_SIZE(rtw8851b_backup_rf_regs) +static const u32 dpk_kip_reg[DPK_KIP_REG_NUM_8851B] = { + 0x813c, 0x8124, 0xc0ec, 0xc0e8, 0xc0c4, 0xc0d4, 0xc0d8}; +static const u32 dpk_rf_reg[DPK_RF_REG_NUM_8851B] = {0xde, 0x8f, 0x5, 0x10005}; + static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { return RF_A; @@ -81,6 +120,24 @@ static void _adc_fifo_rst(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x1111); } +static void _rfk_rf_direct_cntrl(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, bool is_bybb) +{ + if (is_bybb) + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x1); + else + rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0); +} + +static void _rfk_drf_direct_cntrl(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, bool is_bybb) +{ + if (is_bybb) + rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x1); + else + rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x0); +} + static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) { u32 rf_mode; @@ -1546,6 +1603,964 @@ static void _iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool forc _doiqk(rtwdev, force, phy_idx, RF_PATH_A); } +static void _dpk_bkup_kip(struct rtw89_dev *rtwdev, const u32 *reg, + u32 reg_bkup[][DPK_KIP_REG_NUM_8851B], u8 path) +{ + u8 i; + + for (i = 0; i < DPK_KIP_REG_NUM_8851B; i++) { + reg_bkup[path][i] = + rtw89_phy_read32_mask(rtwdev, reg[i] + (path << 8), MASKDWORD); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Backup 0x%x = %x\n", + reg[i] + (path << 8), reg_bkup[path][i]); + } +} + +static void _dpk_bkup_rf(struct rtw89_dev *rtwdev, const u32 *rf_reg, + u32 rf_bkup[][DPK_RF_REG_NUM_8851B], u8 path) +{ + u8 i; + + for (i = 0; i < DPK_RF_REG_NUM_8851B; i++) { + rf_bkup[path][i] = rtw89_read_rf(rtwdev, path, rf_reg[i], RFREG_MASK); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Backup RF S%d 0x%x = %x\n", + path, rf_reg[i], rf_bkup[path][i]); + } +} + +static void _dpk_reload_kip(struct rtw89_dev *rtwdev, const u32 *reg, + u32 reg_bkup[][DPK_KIP_REG_NUM_8851B], u8 path) +{ + u8 i; + + for (i = 0; i < DPK_KIP_REG_NUM_8851B; i++) { + rtw89_phy_write32_mask(rtwdev, reg[i] + (path << 8), MASKDWORD, + reg_bkup[path][i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Reload 0x%x = %x\n", + reg[i] + (path << 8), reg_bkup[path][i]); + } +} + +static void _dpk_reload_rf(struct rtw89_dev *rtwdev, const u32 *rf_reg, + u32 rf_bkup[][DPK_RF_REG_NUM_8851B], u8 path) +{ + u8 i; + + for (i = 0; i < DPK_RF_REG_NUM_8851B; i++) { + rtw89_write_rf(rtwdev, path, rf_reg[i], RFREG_MASK, rf_bkup[path][i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Reload RF S%d 0x%x = %x\n", path, + rf_reg[i], rf_bkup[path][i]); + } +} + +static void _dpk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, enum dpk_id id) +{ + u16 dpk_cmd; + u32 val; + int ret; + + dpk_cmd = ((id << 8) | (0x19 + path * 0x12)); + rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, dpk_cmd); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x55, + 10, 20000, false, + rtwdev, 0xbff8, MASKBYTE0); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] one-shot 1 timeout\n"); + + udelay(1); + + ret = read_poll_timeout_atomic(rtw89_phy_read32_mask, val, val == 0x8000, + 1, 2000, false, + rtwdev, R_RPT_COM, MASKLWORD); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] one-shot 2 timeout\n"); + + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, MASKBYTE0, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] one-shot for %s = 0x%04x\n", + id == 0x28 ? "KIP_PRESET" : + id == 0x29 ? "DPK_TXAGC" : + id == 0x2a ? "DPK_RXAGC" : + id == 0x2b ? "SYNC" : + id == 0x2c ? "GAIN_LOSS" : + id == 0x2d ? "MDPK_IDL" : + id == 0x2f ? "DPK_GAIN_NORM" : + id == 0x31 ? "KIP_RESOTRE" : + id == 0x6 ? "LBK_RXIQK" : "Unknown id", + dpk_cmd); +} + +static void _dpk_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool off) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 kidx = dpk->cur_idx[path]; + u8 off_reverse = off ? 0 : 1; + u8 val; + + val = dpk->is_dpk_enable * off_reverse * dpk->bp[path][kidx].path_ok; + + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), + 0xf0000000, val); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] DPK %s !!!\n", path, + kidx, val == 0 ? "disable" : "enable"); +} + +static void _dpk_init(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + u8 kidx = dpk->cur_idx[path]; + + dpk->bp[path][kidx].path_ok = 0; +} + +static void _dpk_information(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + u8 kidx = dpk->cur_idx[path]; + + dpk->bp[path][kidx].band = chan->band_type; + dpk->bp[path][kidx].ch = chan->band_width; + dpk->bp[path][kidx].bw = chan->channel; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] S%d[%d] (PHY%d): TSSI %s/ DBCC %s/ %s/ CH%d/ %s\n", + path, dpk->cur_idx[path], phy, + rtwdev->is_tssi_mode[path] ? "on" : "off", + rtwdev->dbcc_en ? "on" : "off", + dpk->bp[path][kidx].band == 0 ? "2G" : + dpk->bp[path][kidx].band == 1 ? "5G" : "6G", + dpk->bp[path][kidx].ch, + dpk->bp[path][kidx].bw == 0 ? "20M" : + dpk->bp[path][kidx].bw == 1 ? "40M" : + dpk->bp[path][kidx].bw == 2 ? "80M" : "160M"); +} + +static void _dpk_rxagc_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool turn_on) +{ + if (path == RF_PATH_A) + rtw89_phy_write32_mask(rtwdev, R_P0_AGC_CTL, B_P0_AGC_EN, turn_on); + else + rtw89_phy_write32_mask(rtwdev, R_P1_AGC_CTL, B_P1_AGC_EN, turn_on); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d RXAGC is %s\n", path, + turn_on ? "turn_on" : "turn_off"); +} + +static void _dpk_bb_afe_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(16 + path), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(20 + path), 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(24 + path), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x0); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), MASKDWORD, 0xd801dffd); + + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_bb_afe_defs_tbl); + + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(20 + path), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x1); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d BB/AFE setting\n", path); +} + +static void _dpk_bb_afe_restore(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW + (path << 13), B_P0_NRBW_DBG, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(16 + path), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(20 + path), 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(24 + path), 0x1); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x0); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), MASKDWORD, 0x00000000); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK + (path << 13), B_P0_TXCK_ALL, 0x00); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(16 + path), 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(24 + path), 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d BB/AFE restore\n", path); +} + +static void _dpk_tssi_pause(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool is_pause) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK + (path << 13), + B_P0_TSSI_TRK_EN, is_pause); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d TSSI %s\n", path, + is_pause ? "pause" : "resume"); +} + +static void _dpk_tpg_sel(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + if (dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_80) { + rtw89_phy_write32_mask(rtwdev, R_TPG_MOD, B_TPG_MOD_F, 0x0); + rtw89_phy_write32_mask(rtwdev, R_TPG_SEL, MASKDWORD, 0xffe0fa00); + } else if (dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_40) { + rtw89_phy_write32_mask(rtwdev, R_TPG_MOD, B_TPG_MOD_F, 0x2); + rtw89_phy_write32_mask(rtwdev, R_TPG_SEL, MASKDWORD, 0xff4009e0); + } else { + rtw89_phy_write32_mask(rtwdev, R_TPG_MOD, B_TPG_MOD_F, 0x1); + rtw89_phy_write32_mask(rtwdev, R_TPG_SEL, MASKDWORD, 0xf9f007d0); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] TPG Select for %s\n", + dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_80 ? "80M" : + dpk->bp[path][kidx].bw == RTW89_CHANNEL_WIDTH_40 ? "40M" : "20M"); +} + +static void _dpk_txpwr_bb_force(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, bool force) +{ + rtw89_phy_write32_mask(rtwdev, R_TXPWRB + (path << 13), B_TXPWRB_ON, force); + rtw89_phy_write32_mask(rtwdev, R_TXPWRB_H + (path << 13), B_TXPWRB_RDY, force); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d txpwr_bb_force %s\n", + path, force ? "on" : "off"); +} + +static void _dpk_kip_pwr_clk_onoff(struct rtw89_dev *rtwdev, bool turn_on) +{ + if (turn_on) { + rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000080); + rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x807f030a); + } else { + rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000000); + rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x80000000); + rtw89_phy_write32_mask(rtwdev, R_DPK_WR, BIT(18), 0x1); + } +} + +static void _dpk_kip_control_rfc(struct rtw89_dev *rtwdev, + enum rtw89_rf_path path, bool ctrl_by_kip) +{ + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), + B_IQK_RFC_ON, ctrl_by_kip); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] RFC is controlled by %s\n", + ctrl_by_kip ? "KIP" : "BB"); +} + +static void _dpk_kip_preset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx) +{ + rtw89_phy_write32_mask(rtwdev, R_KIP_MOD, B_KIP_MOD, + rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK)); + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), + B_DPD_SEL, 0x01); + + _dpk_kip_control_rfc(rtwdev, path, true); + _dpk_one_shot(rtwdev, phy, path, D_KIP_PRESET); +} + +static void _dpk_kip_restore(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + _dpk_one_shot(rtwdev, phy, path, D_KIP_RESTORE); + _dpk_kip_control_rfc(rtwdev, path, false); + _dpk_txpwr_bb_force(rtwdev, path, false); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d restore KIP\n", path); +} + +static void _dpk_kset_query(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT + (path << 8), B_KIP_RPT_SEL, 0x10); + + dpk->cur_k_set = + rtw89_phy_read32_mask(rtwdev, R_RPT_PER + (path << 8), B_RPT_PER_KSET) - 1; +} + +static void _dpk_para_query(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) +{ + static const u32 reg[RTW89_DPK_BKUP_NUM][DPK_KSET_NUM] = { + {0x8190, 0x8194, 0x8198, 0x81a4}, + {0x81a8, 0x81c4, 0x81c8, 0x81e8} + }; + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 cur_k_set = dpk->cur_k_set; + u32 para; + + if (cur_k_set >= DPK_KSET_NUM) { + rtw89_warn(rtwdev, "DPK cur_k_set = %d\n", cur_k_set); + cur_k_set = 2; + } + + para = rtw89_phy_read32_mask(rtwdev, reg[kidx][cur_k_set] + (path << 8), + MASKDWORD); + + dpk->bp[path][kidx].txagc_dpk = (para >> 10) & 0x3f; + dpk->bp[path][kidx].ther_dpk = (para >> 26) & 0x3f; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] thermal/ txagc_RF (K%d) = 0x%x/ 0x%x\n", + dpk->cur_k_set, dpk->bp[path][kidx].ther_dpk, + dpk->bp[path][kidx].txagc_dpk); +} + +static bool _dpk_sync_check(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 corr_val, corr_idx, rxbb; + u16 dc_i, dc_q; + u8 rxbb_ov; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x0); + + corr_idx = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_CORI); + corr_val = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_CORV); + dpk->corr_idx[path][kidx] = corr_idx; + dpk->corr_val[path][kidx] = corr_val; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x9); + + dc_i = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCI); + dc_q = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCQ); + + dc_i = abs(sign_extend32(dc_i, 11)); + dc_q = abs(sign_extend32(dc_q, 11)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] S%d Corr_idx/ Corr_val /DC I/Q, = %d / %d / %d / %d\n", + path, corr_idx, corr_val, dc_i, dc_q); + + dpk->dc_i[path][kidx] = dc_i; + dpk->dc_q[path][kidx] = dc_q; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x8); + rxbb = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_RXBB); + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x31); + rxbb_ov = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_RXOV); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] S%d RXBB/ RXAGC_done /RXBB_ovlmt = %d / %d / %d\n", + path, rxbb, + rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DONE), + rxbb_ov); + + if (dc_i > 200 || dc_q > 200 || corr_val < 170) + return true; + else + return false; +} + +static void _dpk_kip_set_txagc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 dbm, + bool set_from_bb) +{ + if (set_from_bb) { + dbm = clamp_t(u8, dbm, 7, 24); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] set S%d txagc to %ddBm\n", path, dbm); + rtw89_phy_write32_mask(rtwdev, R_TXPWRB + (path << 13), + B_TXPWRB_VAL, dbm << 2); + } + + _dpk_one_shot(rtwdev, phy, path, D_TXAGC); + _dpk_kset_query(rtwdev, path); +} + +static bool _dpk_kip_set_rxagc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx) +{ + _dpk_kip_control_rfc(rtwdev, path, false); + rtw89_phy_write32_mask(rtwdev, R_KIP_MOD, B_KIP_MOD, + rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK)); + _dpk_kip_control_rfc(rtwdev, path, true); + + _dpk_one_shot(rtwdev, phy, path, D_RXAGC); + return _dpk_sync_check(rtwdev, path, kidx); +} + +static void _dpk_lbk_rxiqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + u32 rf_11, reg_81cc; + u8 cur_rxbb; + + rtw89_phy_write32_mask(rtwdev, R_DPD_V1 + (path << 8), B_DPD_LBK, 0x1); + rtw89_phy_write32_mask(rtwdev, R_MDPK_RX_DCK, B_MDPK_RX_DCK_EN, 0x1); + + _dpk_kip_control_rfc(rtwdev, path, false); + + cur_rxbb = rtw89_read_rf(rtwdev, path, RR_MOD, RR_MOD_RXB); + rf_11 = rtw89_read_rf(rtwdev, path, RR_TXIG, RFREG_MASK); + reg_81cc = rtw89_phy_read32_mask(rtwdev, R_KIP_IQP + (path << 8), + B_KIP_IQP_SW); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, 0x0); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, 0x3); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, 0xd); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RXB, 0x1f); + + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_IQSW, 0x12); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_SW, 0x3); + + _dpk_kip_control_rfc(rtwdev, path, true); + + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, MASKDWORD, 0x00250025); + + _dpk_one_shot(rtwdev, phy, path, LBK_RXIQK); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d LBK RXIQC = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD)); + + _dpk_kip_control_rfc(rtwdev, path, false); + + rtw89_write_rf(rtwdev, path, RR_TXIG, RFREG_MASK, rf_11); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RXB, cur_rxbb); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP + (path << 8), B_KIP_IQP_SW, reg_81cc); + + rtw89_phy_write32_mask(rtwdev, R_MDPK_RX_DCK, B_MDPK_RX_DCK_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_KPATH_CFG, B_KPATH_CFG_ED, 0x0); + rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_DI, 0x1); + + _dpk_kip_control_rfc(rtwdev, path, true); +} + +static void _dpk_rf_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + if (dpk->bp[path][kidx].band == RTW89_BAND_2G) { + rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASK, 0x50521); + rtw89_write_rf(rtwdev, path, RR_MOD_V1, RR_MOD_MASK, RF_DPK); + rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_ATTC, 0x0); + rtw89_write_rf(rtwdev, path, RR_RXBB, RR_RXBB_ATTR, 0x7); + } else { + rtw89_write_rf(rtwdev, path, RR_MOD, RFREG_MASK, + 0x50521 | BIT(rtwdev->dbcc_en)); + rtw89_write_rf(rtwdev, path, RR_MOD_V1, RR_MOD_MASK, RF_DPK); + rtw89_write_rf(rtwdev, path, RR_RXA2, RR_RAA2_SATT, 0x3); + } + + rtw89_write_rf(rtwdev, path, RR_RCKD, RR_RCKD_BW, 0x1); + rtw89_write_rf(rtwdev, path, RR_BTC, RR_BTC_TXBB, dpk->bp[path][kidx].bw + 1); + rtw89_write_rf(rtwdev, path, RR_BTC, RR_BTC_RXBB, 0x0); + rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_EBW, 0x0); +} + +static void _dpk_bypass_rxiqc(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + rtw89_phy_write32_mask(rtwdev, R_DPD_V1 + (path << 8), B_DPD_LBK, 0x1); + rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, 0x40000002); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Bypass RXIQC\n"); +} + +static u16 _dpk_dgain_read(struct rtw89_dev *rtwdev) +{ + u16 dgain; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x0); + dgain = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_DCI); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] DGain = 0x%x\n", dgain); + + return dgain; +} + +static u8 _dpk_gainloss_read(struct rtw89_dev *rtwdev) +{ + u8 result; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, B_KIP_RPT1_SEL, 0x6); + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG2, B_DPK_CFG2_ST, 0x1); + result = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, B_PRT_COM_GL); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] tmp GL = %d\n", result); + + return result; +} + +static u8 _dpk_gainloss(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx) +{ + _dpk_one_shot(rtwdev, phy, path, D_GAIN_LOSS); + _dpk_kip_set_txagc(rtwdev, phy, path, 0xff, false); + + rtw89_phy_write32_mask(rtwdev, R_DPK_GL + (path << 8), B_DPK_GL_A1, 0xf078); + rtw89_phy_write32_mask(rtwdev, R_DPK_GL + (path << 8), B_DPK_GL_A0, 0x0); + + return _dpk_gainloss_read(rtwdev); +} + +static u8 _dpk_pas_read(struct rtw89_dev *rtwdev, u8 is_check) +{ + u32 val1_i = 0, val1_q = 0, val2_i = 0, val2_q = 0; + u32 val1_sqrt_sum, val2_sqrt_sum; + u8 i; + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT1, MASKBYTE2, 0x06); + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG2, B_DPK_CFG2_ST, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE2, 0x08); + + if (is_check) { + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, 0x00); + val1_i = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKHWORD); + val1_i = abs(sign_extend32(val1_i, 11)); + val1_q = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKLWORD); + val1_q = abs(sign_extend32(val1_q, 11)); + + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, 0x1f); + val2_i = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKHWORD); + val2_i = abs(sign_extend32(val2_i, 11)); + val2_q = rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKLWORD); + val2_q = abs(sign_extend32(val2_q, 11)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] PAS_delta = 0x%x\n", + phy_div(val1_i * val1_i + val1_q * val1_q, + val2_i * val2_i + val2_q * val2_q)); + } else { + for (i = 0; i < 32; i++) { + rtw89_phy_write32_mask(rtwdev, R_DPK_CFG3, MASKBYTE3, i); + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] PAS_Read[%02d]= 0x%08x\n", i, + rtw89_phy_read32_mask(rtwdev, R_RPT_COM, MASKDWORD)); + } + } + + val1_sqrt_sum = val1_i * val1_i + val1_q * val1_q; + val2_sqrt_sum = val2_i * val2_i + val2_q * val2_q; + + if (val1_sqrt_sum < val2_sqrt_sum) + return 2; + else if (val1_sqrt_sum >= val2_sqrt_sum * 8 / 5) + return 1; + else + return 0; +} + +static u8 _dpk_agc(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx, u8 init_xdbm, u8 loss_only) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 tmp_dbm = init_xdbm, tmp_gl_idx = 0; + u8 step = DPK_AGC_STEP_SYNC_DGAIN; + u8 goout = 0, agc_cnt = 0; + bool is_fail = false; + int limit = 200; + u8 tmp_rxbb; + u16 dgain; + + do { + switch (step) { + case DPK_AGC_STEP_SYNC_DGAIN: + is_fail = _dpk_kip_set_rxagc(rtwdev, phy, path, kidx); + + if (is_fail) { + goout = 1; + break; + } + + dgain = _dpk_dgain_read(rtwdev); + + if (dgain > 0x5fc || dgain < 0x556) { + _dpk_one_shot(rtwdev, phy, path, D_SYNC); + dgain = _dpk_dgain_read(rtwdev); + } + + if (agc_cnt == 0) { + if (dpk->bp[path][kidx].band == RTW89_BAND_2G) + _dpk_bypass_rxiqc(rtwdev, path); + else + _dpk_lbk_rxiqk(rtwdev, phy, path); + } + step = DPK_AGC_STEP_GAIN_LOSS_IDX; + break; + + case DPK_AGC_STEP_GAIN_LOSS_IDX: + tmp_gl_idx = _dpk_gainloss(rtwdev, phy, path, kidx); + + if (_dpk_pas_read(rtwdev, true) == 2 && tmp_gl_idx > 0) + step = DPK_AGC_STEP_GL_LT_CRITERION; + else if ((tmp_gl_idx == 0 && _dpk_pas_read(rtwdev, true) == 1) || + tmp_gl_idx >= 7) + step = DPK_AGC_STEP_GL_GT_CRITERION; + else if (tmp_gl_idx == 0) + step = DPK_AGC_STEP_GL_LT_CRITERION; + else + step = DPK_AGC_STEP_SET_TX_GAIN; + break; + + case DPK_AGC_STEP_GL_GT_CRITERION: + if (tmp_dbm <= 7) { + goout = 1; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Txagc@lower bound!!\n"); + } else { + tmp_dbm = max_t(u8, tmp_dbm - 3, 7); + _dpk_kip_set_txagc(rtwdev, phy, path, tmp_dbm, true); + } + step = DPK_AGC_STEP_SYNC_DGAIN; + agc_cnt++; + break; + + case DPK_AGC_STEP_GL_LT_CRITERION: + if (tmp_dbm >= 24) { + goout = 1; + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Txagc@upper bound!!\n"); + } else { + tmp_dbm = min_t(u8, tmp_dbm + 2, 24); + _dpk_kip_set_txagc(rtwdev, phy, path, tmp_dbm, true); + } + step = DPK_AGC_STEP_SYNC_DGAIN; + agc_cnt++; + break; + + case DPK_AGC_STEP_SET_TX_GAIN: + _dpk_kip_control_rfc(rtwdev, path, false); + tmp_rxbb = rtw89_read_rf(rtwdev, path, RR_MOD, RR_MOD_RXB); + tmp_rxbb = min_t(u8, tmp_rxbb + tmp_gl_idx, 0x1f); + + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_RXB, tmp_rxbb); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Adjust RXBB (%+d) = 0x%x\n", + tmp_gl_idx, tmp_rxbb); + _dpk_kip_control_rfc(rtwdev, path, true); + goout = 1; + break; + default: + goout = 1; + break; + } + } while (!goout && agc_cnt < 6 && limit-- > 0); + + return is_fail; +} + +static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, u8 order) +{ + switch (order) { + case 0: /* (5,3,1) */ + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DPK_IDL, B_DPK_IDL_SEL, 0x2); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x4); + rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_DMAN, 0x1); + break; + case 1: /* (5,3,0) */ + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DPK_IDL, B_DPK_IDL_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_DMAN, 0x0); + break; + case 2: /* (5,0,0) */ + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, 0x2); + rtw89_phy_write32_mask(rtwdev, R_DPK_IDL, B_DPK_IDL_SEL, 0x0); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_DMAN, 0x0); + break; + case 3: /* (7,3,1) */ + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, 0x3); + rtw89_phy_write32_mask(rtwdev, R_DPK_IDL, B_DPK_IDL_SEL, 0x3); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x4); + rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_DMAN, 0x1); + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] Wrong MDPD order!!(0x%x)\n", order); + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] Set %s for IDL\n", + order == 0x0 ? "(5,3,1)" : + order == 0x1 ? "(5,3,0)" : + order == 0x2 ? "(5,0,0)" : "(7,3,1)"); +} + +static void _dpk_idl_mpa(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx) +{ + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_MA, 0x1); + + if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_MD500) == 0x1) + _dpk_set_mdpd_para(rtwdev, 0x2); + else if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_MD530) == 0x1) + _dpk_set_mdpd_para(rtwdev, 0x1); + else + _dpk_set_mdpd_para(rtwdev, 0x0); + + rtw89_phy_write32_mask(rtwdev, R_DPK_IDL, B_DPK_IDL, 0x0); + fsleep(1000); + + _dpk_one_shot(rtwdev, phy, path, D_MDPK_IDL); +} + +static u8 _dpk_order_convert(struct rtw89_dev *rtwdev) +{ + u32 order; + u8 val; + + order = rtw89_phy_read32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP); + + switch (order) { + case 0: /* (5,3,1) */ + val = 0x6; + break; + case 1: /* (5,3,0) */ + val = 0x2; + break; + case 2: /* (5,0,0) */ + val = 0x0; + break; + default: + val = 0xff; + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] convert MDPD order to 0x%x\n", val); + + return val; +} + +static void _dpk_gain_normalize(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx, bool is_execute) +{ + static const u32 reg[RTW89_DPK_BKUP_NUM][DPK_KSET_NUM] = { + {0x8190, 0x8194, 0x8198, 0x81a4}, + {0x81a8, 0x81c4, 0x81c8, 0x81e8} + }; + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 cur_k_set = dpk->cur_k_set; + + if (cur_k_set >= DPK_KSET_NUM) { + rtw89_warn(rtwdev, "DPK cur_k_set = %d\n", cur_k_set); + cur_k_set = 2; + } + + if (is_execute) { + rtw89_phy_write32_mask(rtwdev, R_DPK_GN + (path << 8), + B_DPK_GN_AG, 0x200); + rtw89_phy_write32_mask(rtwdev, R_DPK_GN + (path << 8), + B_DPK_GN_EN, 0x3); + + _dpk_one_shot(rtwdev, phy, path, D_GAIN_NORM); + } else { + rtw89_phy_write32_mask(rtwdev, reg[kidx][cur_k_set] + (path << 8), + 0x0000007F, 0x5b); + } + + dpk->bp[path][kidx].gs = + rtw89_phy_read32_mask(rtwdev, reg[kidx][cur_k_set] + (path << 8), + 0x0000007F); +} + +static void _dpk_on(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, u8 kidx) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + + rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_MDPD, 0x1); + rtw89_phy_write32_mask(rtwdev, R_LOAD_COEF + (path << 8), B_LOAD_COEF_MDPD, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), + B_DPD_ORDER, _dpk_order_convert(rtwdev)); + + dpk->bp[path][kidx].path_ok = + dpk->bp[path][kidx].path_ok | BIT(dpk->cur_k_set); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] path_ok = 0x%x\n", + path, kidx, dpk->bp[path][kidx].path_ok); + + rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), + B_DPD_MEN, dpk->bp[path][kidx].path_ok); + + _dpk_gain_normalize(rtwdev, phy, path, kidx, false); +} + +static bool _dpk_main(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 kidx = dpk->cur_idx[path]; + u8 init_xdbm = 17; + bool is_fail; + + if (dpk->bp[path][kidx].band != RTW89_BAND_2G) + init_xdbm = 15; + + _dpk_kip_control_rfc(rtwdev, path, false); + _rfk_rf_direct_cntrl(rtwdev, path, false); + rtw89_write_rf(rtwdev, path, RR_BBDC, RFREG_MASK, 0x03ffd); + + _dpk_rf_setting(rtwdev, path, kidx); + _set_rx_dck(rtwdev, path, RF_DPK); + + _dpk_kip_pwr_clk_onoff(rtwdev, true); + _dpk_kip_preset(rtwdev, phy, path, kidx); + _dpk_txpwr_bb_force(rtwdev, path, true); + _dpk_kip_set_txagc(rtwdev, phy, path, init_xdbm, true); + _dpk_tpg_sel(rtwdev, path, kidx); + is_fail = _dpk_agc(rtwdev, phy, path, kidx, init_xdbm, false); + if (is_fail) + goto _error; + + _dpk_idl_mpa(rtwdev, phy, path, kidx); + _dpk_para_query(rtwdev, path, kidx); + + _dpk_on(rtwdev, phy, path, kidx); +_error: + _dpk_kip_control_rfc(rtwdev, path, false); + rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RF_RX); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d]_K%d %s\n", path, kidx, + dpk->cur_k_set, is_fail ? "need Check" : "is Success"); + + return is_fail; +} + +static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, + enum rtw89_phy_idx phy, u8 kpath) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u32 kip_bkup[RF_PATH_NUM_8851B][DPK_KIP_REG_NUM_8851B] = {}; + u32 rf_bkup[RF_PATH_NUM_8851B][DPK_RF_REG_NUM_8851B] = {}; + bool is_fail; + u8 path; + + for (path = 0; path < RF_PATH_NUM_8851B; path++) + dpk->cur_idx[path] = 0; + + for (path = 0; path < RF_PATH_NUM_8851B; path++) { + if (!(kpath & BIT(path))) + continue; + _dpk_bkup_kip(rtwdev, dpk_kip_reg, kip_bkup, path); + _dpk_bkup_rf(rtwdev, dpk_rf_reg, rf_bkup, path); + _dpk_information(rtwdev, phy, path); + _dpk_init(rtwdev, path); + + if (rtwdev->is_tssi_mode[path]) + _dpk_tssi_pause(rtwdev, path, true); + } + + for (path = 0; path < RF_PATH_NUM_8851B; path++) { + if (!(kpath & BIT(path))) + continue; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] ========= S%d[%d] DPK Start =========\n", + path, dpk->cur_idx[path]); + + _dpk_rxagc_onoff(rtwdev, path, false); + _rfk_drf_direct_cntrl(rtwdev, path, false); + _dpk_bb_afe_setting(rtwdev, path); + + is_fail = _dpk_main(rtwdev, phy, path); + _dpk_onoff(rtwdev, path, is_fail); + } + + for (path = 0; path < RF_PATH_NUM_8851B; path++) { + if (!(kpath & BIT(path))) + continue; + + _dpk_kip_restore(rtwdev, phy, path); + _dpk_reload_kip(rtwdev, dpk_kip_reg, kip_bkup, path); + _dpk_reload_rf(rtwdev, dpk_rf_reg, rf_bkup, path); + _dpk_bb_afe_restore(rtwdev, path); + _dpk_rxagc_onoff(rtwdev, path, true); + + if (rtwdev->is_tssi_mode[path]) + _dpk_tssi_pause(rtwdev, path, false); + } + + _dpk_kip_pwr_clk_onoff(rtwdev, false); +} + +static void _dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool force) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[DPK] ****** 8851B DPK Start (Ver: 0x%x, Cv: %d) ******\n", + DPK_VER_8851B, rtwdev->hal.cv); + + _dpk_cal_select(rtwdev, force, phy, _kpath(rtwdev, phy)); +} + +static void _dpk_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + s8 txagc_bb, txagc_bb_tp, txagc_ofst; + s16 pwsf_tssi_ofst; + s8 delta_ther = 0; + u8 path, kidx; + u8 txagc_rf; + u8 cur_ther; + + for (path = 0; path < RF_PATH_NUM_8851B; path++) { + kidx = dpk->cur_idx[path]; + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] ================[S%d[%d] (CH %d)]================\n", + path, kidx, dpk->bp[path][kidx].ch); + + txagc_rf = rtw89_phy_read32_mask(rtwdev, R_TXAGC_BB + (path << 13), + B_TXAGC_RF); + txagc_bb = rtw89_phy_read32_mask(rtwdev, R_TXAGC_BB + (path << 13), + MASKBYTE2); + txagc_bb_tp = rtw89_phy_read32_mask(rtwdev, R_TXAGC_BTP + (path << 13), + B_TXAGC_BTP); + + rtw89_phy_write32_mask(rtwdev, R_KIP_RPT + (path << 8), + B_KIP_RPT_SEL, 0xf); + cur_ther = rtw89_phy_read32_mask(rtwdev, R_RPT_PER + (path << 8), + B_RPT_PER_TH); + txagc_ofst = rtw89_phy_read32_mask(rtwdev, R_RPT_PER + (path << 8), + B_RPT_PER_OF); + pwsf_tssi_ofst = rtw89_phy_read32_mask(rtwdev, R_RPT_PER + (path << 8), + B_RPT_PER_TSSI); + pwsf_tssi_ofst = sign_extend32(pwsf_tssi_ofst, 12); + + delta_ther = cur_ther - dpk->bp[path][kidx].ther_dpk; + + delta_ther = delta_ther * 2 / 3; + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] extra delta_ther = %d (0x%x / 0x%x@k)\n", + delta_ther, cur_ther, dpk->bp[path][kidx].ther_dpk); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] delta_txagc = %d (0x%x / 0x%x@k)\n", + txagc_rf - dpk->bp[path][kidx].txagc_dpk, + txagc_rf, dpk->bp[path][kidx].txagc_dpk); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] txagc_offset / pwsf_tssi_ofst = 0x%x / %+d\n", + txagc_ofst, pwsf_tssi_ofst); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] txagc_bb_tp / txagc_bb = 0x%x / 0x%x\n", + txagc_bb_tp, txagc_bb); + + if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_DN) == 0x0 && + txagc_rf != 0) { + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[DPK_TRK] New pwsf = 0x%x\n", 0x78 - delta_ther); + + rtw89_phy_write32_mask(rtwdev, + R_DPD_BND + (path << 8) + (kidx << 2), + 0x07FC0000, 0x78 - delta_ther); + } + } +} + static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) { u32 rf_reg5; @@ -1581,6 +2596,17 @@ static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) rtw89_read_rf(rtwdev, path, RR_RCKC, RFREG_MASK)); } +static void rtw8851b_by_rate_dpd(struct rtw89_dev *rtwdev) +{ + rtw89_write32_mask(rtwdev, R_AX_PWR_SWING_OTHER_CTRL0, + B_AX_CFIR_BY_RATE_OFF_MASK, 0x21861); +} + +void rtw8851b_dpk_init(struct rtw89_dev *rtwdev) +{ + rtw8851b_by_rate_dpd(rtwdev); +} + void rtw8851b_aack(struct rtw89_dev *rtwdev) { u32 tmp05, ib[4]; @@ -1664,6 +2690,28 @@ void rtw8851b_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_RXDCK, BTC_WRFK_STOP); } +void rtw8851b_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + u8 phy_map = rtw89_btc_phymap(rtwdev, phy_idx, 0); + u32 tx_en; + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_DPK, BTC_WRFK_START); + rtw89_chip_stop_sch_tx(rtwdev, phy_idx, &tx_en, RTW89_SCH_TX_SEL_ALL); + _wait_rx_mode(rtwdev, _kpath(rtwdev, phy_idx)); + + rtwdev->dpk.is_dpk_enable = true; + rtwdev->dpk.is_dpk_reload_en = false; + _dpk(rtwdev, phy_idx, false); + + rtw89_chip_resume_sch_tx(rtwdev, phy_idx, tx_en); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_DPK, BTC_WRFK_STOP); +} + +void rtw8851b_dpk_track(struct rtw89_dev *rtwdev) +{ + _dpk_track(rtwdev); +} + static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, enum rtw89_bandwidth bw, bool dav) { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h index a77b3fd7f58a..ce3bc8d405ab 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -12,6 +12,9 @@ void rtw8851b_rck(struct rtw89_dev *rtwdev); void rtw8851b_dack(struct rtw89_dev *rtwdev); void rtw8851b_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8851b_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8851b_dpk_init(struct rtw89_dev *rtwdev); +void rtw8851b_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); +void rtw8851b_dpk_track(struct rtw89_dev *rtwdev); void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); -- cgit v1.2.3 From 3f2da9fc17f66af17a1349d4d32f6a6ba245b94d Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Sat, 13 May 2023 13:44:25 +0800 Subject: wifi: rtw89: 8851b: rfk: add TSSI TSSI is transmitter signal strength indication, which is a close-loop hardware circuit to feedback actual transmitting power as a reference for next transmission. When we setup channel to connect an AP, it does full calibration. When switching bands or channels, it needs to reset hardware status to prevent use wrong feedback of previous transmission. To do TX power compensation reflecting current temperature, it loads tables of compensation values into registers according to channel and band group. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230513054425.9689-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 617 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 4 + 2 files changed, 621 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index ab430d7e782f..d58d6935e7b8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -21,6 +21,9 @@ #define RTW8851B_IQK_VER 0x2a #define RTW8851B_IQK_SS 1 #define RTW8851B_LOK_GRAM 10 +#define RTW8851B_TSSI_PATH_NR 1 + +#define _TSSI_DE_MASK GENMASK(21, 12) enum dpk_id { LBK_RXIQK = 0x06, @@ -81,6 +84,14 @@ enum rf_mode { RF_RXK2 = 0x7, }; +static const u32 _tssi_de_cck_long[RF_PATH_NUM_8851B] = {0x5858}; +static const u32 _tssi_de_cck_short[RF_PATH_NUM_8851B] = {0x5860}; +static const u32 _tssi_de_mcs_20m[RF_PATH_NUM_8851B] = {0x5838}; +static const u32 _tssi_de_mcs_40m[RF_PATH_NUM_8851B] = {0x5840}; +static const u32 _tssi_de_mcs_80m[RF_PATH_NUM_8851B] = {0x5848}; +static const u32 _tssi_de_mcs_80m_80m[RF_PATH_NUM_8851B] = {0x5850}; +static const u32 _tssi_de_mcs_5m[RF_PATH_NUM_8851B] = {0x5828}; +static const u32 _tssi_de_mcs_10m[RF_PATH_NUM_8851B] = {0x5830}; static const u32 g_idxrxgain[RTW8851B_RXK_GROUP_NR] = {0x10e, 0x116, 0x28e, 0x296}; static const u32 g_idxattc2[RTW8851B_RXK_GROUP_NR] = {0x0, 0xf, 0x0, 0xf}; static const u32 g_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x0, 0x1, 0x2, 0x3}; @@ -2596,6 +2607,521 @@ static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) rtw89_read_rf(rtwdev, path, RR_RCKC, RFREG_MASK)); } +static void _tssi_set_sys(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + enum rtw89_band band = chan->band_type; + + rtw89_rfk_parser(rtwdev, &rtw8851b_tssi_sys_defs_tbl); + + rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, + &rtw8851b_tssi_sys_a_defs_2g_tbl, + &rtw8851b_tssi_sys_a_defs_5g_tbl); +} + +static void _tssi_ini_txpwr_ctrl_bb(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_tssi_init_txpwr_defs_a_tbl); +} + +static void _tssi_ini_txpwr_ctrl_bb_he_tb(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_tssi_init_txpwr_he_tb_defs_a_tbl); +} + +static void _tssi_set_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_tssi_dck_defs_a_tbl); +} + +static void _tssi_set_tmeter_tbl(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ +#define RTW8851B_TSSI_GET_VAL(ptr, idx) \ +({ \ + s8 *__ptr = (ptr); \ + u8 __idx = (idx), __i, __v; \ + u32 __val = 0; \ + for (__i = 0; __i < 4; __i++) { \ + __v = (__ptr[__idx + __i]); \ + __val |= (__v << (8 * __i)); \ + } \ + __val; \ +}) + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 ch = chan->channel; + u8 subband = chan->subband_type; + const s8 *thm_up_a = NULL; + const s8 *thm_down_a = NULL; + u8 thermal = 0xff; + s8 thm_ofst[64] = {0}; + u32 tmp = 0; + u8 i, j; + + switch (subband) { + default: + case RTW89_CH_2G: + thm_up_a = rtw89_8851b_trk_cfg.delta_swingidx_2ga_p; + thm_down_a = rtw89_8851b_trk_cfg.delta_swingidx_2ga_n; + break; + case RTW89_CH_5G_BAND_1: + thm_up_a = rtw89_8851b_trk_cfg.delta_swingidx_5ga_p[0]; + thm_down_a = rtw89_8851b_trk_cfg.delta_swingidx_5ga_n[0]; + break; + case RTW89_CH_5G_BAND_3: + thm_up_a = rtw89_8851b_trk_cfg.delta_swingidx_5ga_p[1]; + thm_down_a = rtw89_8851b_trk_cfg.delta_swingidx_5ga_n[1]; + break; + case RTW89_CH_5G_BAND_4: + thm_up_a = rtw89_8851b_trk_cfg.delta_swingidx_5ga_p[2]; + thm_down_a = rtw89_8851b_trk_cfg.delta_swingidx_5ga_n[2]; + break; + } + + if (path == RF_PATH_A) { + thermal = tssi_info->thermal[RF_PATH_A]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] ch=%d thermal_pathA=0x%x\n", ch, thermal); + + rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER_DIS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER_TRK, 0x1); + + if (thermal == 0xff) { + rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER, 32); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_VAL, 32); + + for (i = 0; i < 64; i += 4) { + rtw89_phy_write32(rtwdev, R_P0_TSSI_BASE + i, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] write 0x%x val=0x%08x\n", + R_P0_TSSI_BASE + i, 0x0); + } + + } else { + rtw89_phy_write32_mask(rtwdev, R_P0_TMETER, B_P0_TMETER, + thermal); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, B_P0_RFCTM_VAL, + thermal); + + i = 0; + for (j = 0; j < 32; j++) + thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? + -thm_down_a[i++] : + -thm_down_a[DELTA_SWINGIDX_SIZE - 1]; + + i = 1; + for (j = 63; j >= 32; j--) + thm_ofst[j] = i < DELTA_SWINGIDX_SIZE ? + thm_up_a[i++] : + thm_up_a[DELTA_SWINGIDX_SIZE - 1]; + + for (i = 0; i < 64; i += 4) { + tmp = RTW8851B_TSSI_GET_VAL(thm_ofst, i); + rtw89_phy_write32(rtwdev, R_P0_TSSI_BASE + i, tmp); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] write 0x%x val=0x%08x\n", + 0x5c00 + i, tmp); + } + } + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, R_P0_RFCTM_RDY, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_RFCTM, R_P0_RFCTM_RDY, 0x0); + } +#undef RTW8851B_TSSI_GET_VAL +} + +static void _tssi_set_dac_gain_tbl(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_tssi_dac_gain_defs_a_tbl); +} + +static void _tssi_slope_cal_org(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + enum rtw89_band band = chan->band_type; + + rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, + &rtw8851b_tssi_slope_a_defs_2g_tbl, + &rtw8851b_tssi_slope_a_defs_5g_tbl); +} + +static void _tssi_alignment_default(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path, bool all) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + enum rtw89_band band = chan->band_type; + + rtw89_rfk_parser_by_cond(rtwdev, band == RTW89_BAND_2G, + &rtw8851b_tssi_align_a_2g_defs_tbl, + &rtw8851b_tssi_align_a_5g_defs_tbl); +} + +static void _tssi_set_tssi_slope(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_tssi_slope_defs_a_tbl); +} + +static void _tssi_set_tssi_track(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_tssi_track_defs_a_tbl); +} + +static void _tssi_set_txagc_offset_mv_avg(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + rtw89_rfk_parser(rtwdev, &rtw8851b_tssi_mv_avg_defs_a_tbl); +} + +static void _tssi_enable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + _tssi_set_tssi_track(rtwdev, phy, RF_PATH_A); + _tssi_set_txagc_offset_mv_avg(rtwdev, phy, RF_PATH_A); + + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TSSI_MV_CLR, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, B_P0_TSSI_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, B_P0_TSSI_EN, 0x1); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_TXGA_V1, RR_TXGA_V1_TRK_EN, 0x1); + + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_RFC, 0x3); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT, 0xc0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x1); + + rtwdev->is_tssi_mode[RF_PATH_A] = true; +} + +static void _tssi_disable(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_AVG, B_P0_TSSI_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_MV_AVG, B_P0_TSSI_MV_CLR, 0x1); + + rtwdev->is_tssi_mode[RF_PATH_A] = false; +} + +static u32 _tssi_get_cck_group(struct rtw89_dev *rtwdev, u8 ch) +{ + switch (ch) { + case 1 ... 2: + return 0; + case 3 ... 5: + return 1; + case 6 ... 8: + return 2; + case 9 ... 11: + return 3; + case 12 ... 13: + return 4; + case 14: + return 5; + } + + return 0; +} + +#define TSSI_EXTRA_GROUP_BIT (BIT(31)) +#define TSSI_EXTRA_GROUP(idx) (TSSI_EXTRA_GROUP_BIT | (idx)) +#define IS_TSSI_EXTRA_GROUP(group) ((group) & TSSI_EXTRA_GROUP_BIT) +#define TSSI_EXTRA_GET_GROUP_IDX1(group) ((group) & ~TSSI_EXTRA_GROUP_BIT) +#define TSSI_EXTRA_GET_GROUP_IDX2(group) (TSSI_EXTRA_GET_GROUP_IDX1(group) + 1) + +static u32 _tssi_get_ofdm_group(struct rtw89_dev *rtwdev, u8 ch) +{ + switch (ch) { + case 1 ... 2: + return 0; + case 3 ... 5: + return 1; + case 6 ... 8: + return 2; + case 9 ... 11: + return 3; + case 12 ... 14: + return 4; + case 36 ... 40: + return 5; + case 41 ... 43: + return TSSI_EXTRA_GROUP(5); + case 44 ... 48: + return 6; + case 49 ... 51: + return TSSI_EXTRA_GROUP(6); + case 52 ... 56: + return 7; + case 57 ... 59: + return TSSI_EXTRA_GROUP(7); + case 60 ... 64: + return 8; + case 100 ... 104: + return 9; + case 105 ... 107: + return TSSI_EXTRA_GROUP(9); + case 108 ... 112: + return 10; + case 113 ... 115: + return TSSI_EXTRA_GROUP(10); + case 116 ... 120: + return 11; + case 121 ... 123: + return TSSI_EXTRA_GROUP(11); + case 124 ... 128: + return 12; + case 129 ... 131: + return TSSI_EXTRA_GROUP(12); + case 132 ... 136: + return 13; + case 137 ... 139: + return TSSI_EXTRA_GROUP(13); + case 140 ... 144: + return 14; + case 149 ... 153: + return 15; + case 154 ... 156: + return TSSI_EXTRA_GROUP(15); + case 157 ... 161: + return 16; + case 162 ... 164: + return TSSI_EXTRA_GROUP(16); + case 165 ... 169: + return 17; + case 170 ... 172: + return TSSI_EXTRA_GROUP(17); + case 173 ... 177: + return 18; + } + + return 0; +} + +static u32 _tssi_get_trim_group(struct rtw89_dev *rtwdev, u8 ch) +{ + switch (ch) { + case 1 ... 8: + return 0; + case 9 ... 14: + return 1; + case 36 ... 48: + return 2; + case 52 ... 64: + return 3; + case 100 ... 112: + return 4; + case 116 ... 128: + return 5; + case 132 ... 144: + return 6; + case 149 ... 177: + return 7; + } + + return 0; +} + +static s8 _tssi_get_ofdm_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u32 gidx, gidx_1st, gidx_2nd; + u8 ch = chan->channel; + s8 de_1st; + s8 de_2nd; + s8 val; + + gidx = _tssi_get_ofdm_group(rtwdev, ch); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs group_idx=0x%x\n", path, gidx); + + if (IS_TSSI_EXTRA_GROUP(gidx)) { + gidx_1st = TSSI_EXTRA_GET_GROUP_IDX1(gidx); + gidx_2nd = TSSI_EXTRA_GET_GROUP_IDX2(gidx); + de_1st = tssi_info->tssi_mcs[path][gidx_1st]; + de_2nd = tssi_info->tssi_mcs[path][gidx_2nd]; + val = (de_1st + de_2nd) / 2; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs de=%d 1st=%d 2nd=%d\n", + path, val, de_1st, de_2nd); + } else { + val = tssi_info->tssi_mcs[path][gidx]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs de=%d\n", path, val); + } + + return val; +} + +static s8 _tssi_get_ofdm_trim_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, + enum rtw89_rf_path path) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u32 tgidx, tgidx_1st, tgidx_2nd; + u8 ch = chan->channel; + s8 tde_1st; + s8 tde_2nd; + s8 val; + + tgidx = _tssi_get_trim_group(rtwdev, ch); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_group_idx=0x%x\n", + path, tgidx); + + if (IS_TSSI_EXTRA_GROUP(tgidx)) { + tgidx_1st = TSSI_EXTRA_GET_GROUP_IDX1(tgidx); + tgidx_2nd = TSSI_EXTRA_GET_GROUP_IDX2(tgidx); + tde_1st = tssi_info->tssi_trim[path][tgidx_1st]; + tde_2nd = tssi_info->tssi_trim[path][tgidx_2nd]; + val = (tde_1st + tde_2nd) / 2; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_de=%d 1st=%d 2nd=%d\n", + path, val, tde_1st, tde_2nd); + } else { + val = tssi_info->tssi_trim[path][tgidx]; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs trim_de=%d\n", + path, val); + } + + return val; +} + +static void _tssi_set_efuse_to_de(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 ch = chan->channel; + u8 gidx; + s8 ofdm_de; + s8 trim_de; + s32 val; + u32 i; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "[TSSI][TRIM]: phy=%d ch=%d\n", + phy, ch); + + for (i = RF_PATH_A; i < RTW8851B_TSSI_PATH_NR; i++) { + gidx = _tssi_get_cck_group(rtwdev, ch); + trim_de = _tssi_get_ofdm_trim_de(rtwdev, phy, i); + val = tssi_info->tssi_cck[i][gidx] + trim_de; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d cck[%d]=0x%x trim=0x%x\n", + i, gidx, tssi_info->tssi_cck[i][gidx], trim_de); + + rtw89_phy_write32_mask(rtwdev, _tssi_de_cck_long[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_cck_short[i], _TSSI_DE_MASK, val); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] Set TSSI CCK DE 0x%x[21:12]=0x%x\n", + _tssi_de_cck_long[i], + rtw89_phy_read32_mask(rtwdev, _tssi_de_cck_long[i], + _TSSI_DE_MASK)); + + ofdm_de = _tssi_get_ofdm_de(rtwdev, phy, i); + trim_de = _tssi_get_ofdm_trim_de(rtwdev, phy, i); + val = ofdm_de + trim_de; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI][TRIM]: path=%d mcs=0x%x trim=0x%x\n", + i, ofdm_de, trim_de); + + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_20m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_40m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_80m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_80m_80m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_5m[i], _TSSI_DE_MASK, val); + rtw89_phy_write32_mask(rtwdev, _tssi_de_mcs_10m[i], _TSSI_DE_MASK, val); + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, + "[TSSI] Set TSSI MCS DE 0x%x[21:12]=0x%x\n", + _tssi_de_mcs_20m[i], + rtw89_phy_read32_mask(rtwdev, _tssi_de_mcs_20m[i], + _TSSI_DE_MASK)); + } +} + +static void _tssi_alimentk_dump_result(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) +{ + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[TSSI PA K]\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n" + "0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n0x%x = 0x%08x\n", + R_TSSI_PA_K1 + (path << 13), + rtw89_phy_read32_mask(rtwdev, R_TSSI_PA_K1 + (path << 13), MASKDWORD), + R_TSSI_PA_K2 + (path << 13), + rtw89_phy_read32_mask(rtwdev, R_TSSI_PA_K2 + (path << 13), MASKDWORD), + R_P0_TSSI_ALIM1 + (path << 13), + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD), + R_P0_TSSI_ALIM3 + (path << 13), + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD), + R_TSSI_PA_K5 + (path << 13), + rtw89_phy_read32_mask(rtwdev, R_TSSI_PA_K5 + (path << 13), MASKDWORD), + R_P0_TSSI_ALIM2 + (path << 13), + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD), + R_P0_TSSI_ALIM4 + (path << 13), + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD), + R_TSSI_PA_K8 + (path << 13), + rtw89_phy_read32_mask(rtwdev, R_TSSI_PA_K8 + (path << 13), MASKDWORD)); +} + +static void _tssi_alimentk_done(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, enum rtw89_rf_path path) +{ + struct rtw89_tssi_info *tssi_info = &rtwdev->tssi; + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 channel = chan->channel; + u8 band; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======>%s phy=%d path=%d\n", __func__, phy, path); + + if (channel >= 1 && channel <= 14) + band = TSSI_ALIMK_2G; + else if (channel >= 36 && channel <= 64) + band = TSSI_ALIMK_5GL; + else if (channel >= 100 && channel <= 144) + band = TSSI_ALIMK_5GM; + else if (channel >= 149 && channel <= 177) + band = TSSI_ALIMK_5GH; + else + band = TSSI_ALIMK_2G; + + if (tssi_info->alignment_done[path][band]) { + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM1 + (path << 13), MASKDWORD, + tssi_info->alignment_value[path][band][0]); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM3 + (path << 13), MASKDWORD, + tssi_info->alignment_value[path][band][1]); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM2 + (path << 13), MASKDWORD, + tssi_info->alignment_value[path][band][2]); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_ALIM4 + (path << 13), MASKDWORD, + tssi_info->alignment_value[path][band][3]); + } + + _tssi_alimentk_dump_result(rtwdev, path); +} + static void rtw8851b_by_rate_dpd(struct rtw89_dev *rtwdev) { rtw89_write32_mask(rtwdev, R_AX_PWR_SWING_OTHER_CTRL0, @@ -2712,6 +3238,97 @@ void rtw8851b_dpk_track(struct rtw89_dev *rtwdev) _dpk_track(rtwdev); } +void rtw8851b_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_en) +{ + u8 phy_map = rtw89_btc_phymap(rtwdev, phy, RF_A); + u8 i; + + rtw89_debug(rtwdev, RTW89_DBG_TSSI, "[TSSI] %s: phy=%d\n", __func__, phy); + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); + + _tssi_disable(rtwdev, phy); + + for (i = RF_PATH_A; i < RF_PATH_NUM_8851B; i++) { + _tssi_set_sys(rtwdev, phy, i); + _tssi_ini_txpwr_ctrl_bb(rtwdev, phy, i); + _tssi_ini_txpwr_ctrl_bb_he_tb(rtwdev, phy, i); + _tssi_set_dck(rtwdev, phy, i); + _tssi_set_tmeter_tbl(rtwdev, phy, i); + _tssi_set_dac_gain_tbl(rtwdev, phy, i); + _tssi_slope_cal_org(rtwdev, phy, i); + _tssi_alignment_default(rtwdev, phy, i, true); + _tssi_set_tssi_slope(rtwdev, phy, i); + } + + _tssi_enable(rtwdev, phy); + _tssi_set_efuse_to_de(rtwdev, phy); + + rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_STOP); +} + +void rtw8851b_tssi_scan(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 channel = chan->channel; + u32 i; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======>%s phy=%d channel=%d\n", __func__, phy, channel); + + _tssi_disable(rtwdev, phy); + + for (i = RF_PATH_A; i < RF_PATH_NUM_8851B; i++) { + _tssi_set_sys(rtwdev, phy, i); + _tssi_set_tmeter_tbl(rtwdev, phy, i); + _tssi_slope_cal_org(rtwdev, phy, i); + _tssi_alignment_default(rtwdev, phy, i, true); + } + + _tssi_enable(rtwdev, phy); + _tssi_set_efuse_to_de(rtwdev, phy); +} + +static void rtw8851b_tssi_default_txagc(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy, bool enable) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u8 channel = chan->channel; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "======> %s ch=%d\n", + __func__, channel); + + if (enable) + return; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======>%s 1 SCAN_END Set 0x5818[7:0]=0x%x\n", + __func__, + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT)); + + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT, 0xc0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT_EN, 0x1); + + _tssi_alimentk_done(rtwdev, phy, RF_PATH_A); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======>%s 2 SCAN_END Set 0x5818[7:0]=0x%x\n", + __func__, + rtw89_phy_read32_mask(rtwdev, R_P0_TSSI_TRK, B_P0_TSSI_OFT)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "======> %s SCAN_END\n", __func__); +} + +void rtw8851b_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, + enum rtw89_phy_idx phy_idx) +{ + if (scan_start) + rtw8851b_tssi_default_txagc(rtwdev, phy_idx, true); + else + rtw8851b_tssi_default_txagc(rtwdev, phy_idx, false); +} + static void _bw_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, enum rtw89_bandwidth bw, bool dav) { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h index ce3bc8d405ab..bf0c79d58a71 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -15,6 +15,10 @@ void rtw8851b_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void rtw8851b_dpk_init(struct rtw89_dev *rtwdev); void rtw8851b_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); void rtw8851b_dpk_track(struct rtw89_dev *rtwdev); +void rtw8851b_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool hwtx_en); +void rtw8851b_tssi_scan(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); +void rtw8851b_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, + enum rtw89_phy_idx phy_idx); void rtw8851b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); -- cgit v1.2.3 From 030d71fd93b1f0fe6e844c1d790f70c80d828c79 Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Tue, 16 May 2023 17:10:31 +0530 Subject: octeontx2-pf: mcs: Support VLAN in clear text Detect whether macsec secy is running on top of VLAN which implies transmitting VLAN tag in clear text before macsec SecTag. In this case configure hardware to insert SecTag after VLAN tag. Signed-off-by: Subbaraya Sundeep Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c | 8 ++++++-- drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c index b59532cf53ce..6e2fb24be8c1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c @@ -426,13 +426,16 @@ static int cn10k_mcs_write_tx_secy(struct otx2_nic *pfvf, struct mcs_secy_plcy_write_req *req; struct mbox *mbox = &pfvf->mbox; struct macsec_tx_sc *sw_tx_sc; - /* Insert SecTag after 12 bytes (DA+SA)*/ - u8 tag_offset = 12; u8 sectag_tci = 0; + u8 tag_offset; u64 policy; u8 cipher; int ret; + /* Insert SecTag after 12 bytes (DA+SA) or 16 bytes + * if VLAN tag needs to be sent in clear text. + */ + tag_offset = txsc->vlan_dev ? 16 : 12; sw_tx_sc = &secy->tx_sc; mutex_lock(&mbox->lock); @@ -1163,6 +1166,7 @@ static int cn10k_mdo_add_secy(struct macsec_context *ctx) txsc->encoding_sa = secy->tx_sc.encoding_sa; txsc->last_validate_frames = secy->validate_frames; txsc->last_replay_protect = secy->replay_protect; + txsc->vlan_dev = is_vlan_dev(ctx->netdev); list_add(&txsc->entry, &cfg->txsc_list); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 0f2b2a901225..b2267c8bec37 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -419,6 +419,7 @@ struct cn10k_mcs_txsc { u8 encoding_sa; u8 salt[CN10K_MCS_SA_PER_SC][MACSEC_SALT_LEN]; ssci_t ssci[CN10K_MCS_SA_PER_SC]; + bool vlan_dev; /* macsec running on VLAN ? */ }; struct cn10k_mcs_rxsc { -- cgit v1.2.3 From 1fd2c3f93c3e232290a25a8ef8a48d0fb6c702ad Mon Sep 17 00:00:00 2001 From: Aishwarya R Date: Tue, 9 May 2023 20:07:23 +0300 Subject: wifi: ath12k: increase vdev setup timeout When vdev start/stop happens, response from firmware is received with delay and hence there is a timeout before VDEV can be up/down. Also, with maximum peers connected and when vdev stop occurs, firmware will take time to clean up all the peers and vap queues. In such cases as well, vdev start/stop response is sent by firmware with delay. Increase the vdev setup timeout as recommended by firmware team. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0-02903-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aishwarya R Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230428091041.20033-1-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 3 +++ drivers/net/wireless/ath/ath12k/wmi.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 86408480c202..d814d74bc168 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -771,6 +771,9 @@ static int ath12k_mac_vdev_setup_sync(struct ath12k *ar) if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) return -ESHUTDOWN; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev setup timeout %d\n", + ATH12K_VDEV_SETUP_TIMEOUT_HZ); + if (!wait_for_completion_timeout(&ar->vdev_setup_done, ATH12K_VDEV_SETUP_TIMEOUT_HZ)) return -ETIMEDOUT; diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 08a8c9e0f59f..5cae2522fc7c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2682,7 +2682,7 @@ struct ath12k_wmi_ssid_params { u8 ssid[ATH12K_WMI_SSID_LEN]; } __packed; -#define ATH12K_VDEV_SETUP_TIMEOUT_HZ (1 * HZ) +#define ATH12K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) struct wmi_vdev_start_request_cmd { __le32 tlv_header; -- cgit v1.2.3 From 570eec3d40505c30babbe3b8f85a38496c975ab2 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Tue, 9 May 2023 20:07:23 +0300 Subject: wifi: ath11k: Relocate the func ath11k_mac_bitrate_mask_num_ht_rates() and change hweight16 to hweight8 Relocate the function ath11k_mac_bitrate_mask_num_ht_rates() definition to call this function from other functions which helps to avoid the compilation error (function not defined). ht_mcs[] is 1 byte array and it is enough to use hweight8() instead of hweight16(). Hence, fixed the same. Tested on: Compile tested only. Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230504092033.3542456-2-quic_mkenna@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index a164b57dcf30..33620a7a444b 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -4337,6 +4337,20 @@ exit: return ret; } +static int +ath11k_mac_bitrate_mask_num_ht_rates(struct ath11k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int num_rates = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) + num_rates += hweight8(mask->control[band].ht_mcs[i]); + + return num_rates; +} + static int ath11k_mac_bitrate_mask_num_vht_rates(struct ath11k *ar, enum nl80211_band band, @@ -7791,20 +7805,6 @@ static void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v ath11k_mac_flush_tx_complete(ar); } -static int -ath11k_mac_bitrate_mask_num_ht_rates(struct ath11k *ar, - enum nl80211_band band, - const struct cfg80211_bitrate_mask *mask) -{ - int num_rates = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) - num_rates += hweight16(mask->control[band].ht_mcs[i]); - - return num_rates; -} - static bool ath11k_mac_has_single_legacy_rate(struct ath11k *ar, enum nl80211_band band, -- cgit v1.2.3 From df8e3729ffc0aa645839693f74ee7b6d999cdf64 Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Tue, 9 May 2023 20:07:24 +0300 Subject: wifi: ath11k: Send HT fixed rate in WMI peer fixed param Due to the firmware behavior with HT fixed rate setting, HT fixed rate MCS with NSS > 1 are treated as NSS = 1 HT rates in the firmware and enables the HT fixed rate of NSS = 1. This leads to HT fixed rate is always configured for NSS = 1 even though the user sets NSS = 2 or > 1 HT fixed MCS in the set bitrate command. Currently HT fixed MCS is sent via WMI peer assoc command. Fix this issue, by sending the HT fixed rate MCS in WMI peer fixed param instead of sending in peer assoc command. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230504092033.3542456-3-quic_mkenna@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 63 +++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 33620a7a444b..c947d1c8d8c1 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -4480,6 +4480,54 @@ ath11k_mac_set_peer_he_fixed_rate(struct ath11k_vif *arvif, return ret; } +static int +ath11k_mac_set_peer_ht_fixed_rate(struct ath11k_vif *arvif, + struct ieee80211_sta *sta, + const struct cfg80211_bitrate_mask *mask, + enum nl80211_band band) +{ + struct ath11k *ar = arvif->ar; + u8 ht_rate, nss = 0; + u32 rate_code; + int ret, i; + + lockdep_assert_held(&ar->conf_mutex); + + for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) { + if (hweight8(mask->control[band].ht_mcs[i]) == 1) { + nss = i + 1; + ht_rate = ffs(mask->control[band].ht_mcs[i]) - 1; + } + } + + if (!nss) { + ath11k_warn(ar->ab, "No single HT Fixed rate found to set for %pM", + sta->addr); + return -EINVAL; + } + + /* Avoid updating invalid nss as fixed rate*/ + if (nss > sta->deflink.rx_nss) + return -EINVAL; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "Setting Fixed HT Rate for peer %pM. Device will not switch to any other selected rates", + sta->addr); + + rate_code = ATH11K_HW_RATE_CODE(ht_rate, nss - 1, + WMI_RATE_PREAMBLE_HT); + ret = ath11k_wmi_set_peer_param(ar, sta->addr, + arvif->vdev_id, + WMI_PEER_PARAM_FIXED_RATE, + rate_code); + if (ret) + ath11k_warn(ar->ab, + "failed to update STA %pM HT Fixed Rate %d: %d\n", + sta->addr, rate_code, ret); + + return ret; +} + static int ath11k_station_assoc(struct ath11k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -4491,7 +4539,7 @@ static int ath11k_station_assoc(struct ath11k *ar, struct cfg80211_chan_def def; enum nl80211_band band; struct cfg80211_bitrate_mask *mask; - u8 num_vht_rates, num_he_rates; + u8 num_ht_rates, num_vht_rates, num_he_rates; lockdep_assert_held(&ar->conf_mutex); @@ -4519,6 +4567,7 @@ static int ath11k_station_assoc(struct ath11k *ar, num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask); num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask); + num_ht_rates = ath11k_mac_bitrate_mask_num_ht_rates(ar, band, mask); /* If single VHT/HE rate is configured (by set_bitrate_mask()), * peer_assoc will disable VHT/HE. This is now enabled by a peer specific @@ -4535,6 +4584,11 @@ static int ath11k_station_assoc(struct ath11k *ar, band); if (ret) return ret; + } else if (sta->deflink.ht_cap.ht_supported && num_ht_rates == 1) { + ret = ath11k_mac_set_peer_ht_fixed_rate(arvif, sta, mask, + band); + if (ret) + return ret; } /* Re-assoc is run only to update supported rates for given station. It @@ -4608,7 +4662,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) const u16 *vht_mcs_mask; const u16 *he_mcs_mask; u32 changed, bw, nss, smps, bw_prev; - int err, num_vht_rates, num_he_rates; + int err, num_ht_rates, num_vht_rates, num_he_rates; const struct cfg80211_bitrate_mask *mask; struct peer_assoc_params peer_arg; enum wmi_phy_mode peer_phymode; @@ -4724,6 +4778,8 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { mask = &arvif->bitrate_mask; + num_ht_rates = ath11k_mac_bitrate_mask_num_ht_rates(ar, band, + mask); num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask); num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, @@ -4746,6 +4802,9 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) } else if (sta->deflink.he_cap.has_he && num_he_rates == 1) { ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask, band); + } else if (sta->deflink.ht_cap.ht_supported && num_ht_rates == 1) { + ath11k_mac_set_peer_ht_fixed_rate(arvif, sta, mask, + band); } else { /* If the peer is non-VHT/HE or no fixed VHT/HE rate * is provided in the new bitrate mask we set the -- cgit v1.2.3 From 96ba44c637b0d30535374f328186a370accab208 Mon Sep 17 00:00:00 2001 From: Jaco Kroon Date: Wed, 17 May 2023 10:00:03 +0200 Subject: net/pppoe: make number of hash bits configurable When running large numbers of pppoe connections, a bucket size of 16 may be too small and 256 may be more appropriate. This sacrifices some RAM but should result in faster processing of incoming PPPoE frames. On our systems we run upwards of 150 PPPoE connections at any point in time, and we suspect we're starting to see the effects of this small number of buckets. The legal values according to pppoe.c is anything that when 8 is divided by that results in a modulo of 0, ie, 1, 2, 4 and 8. The size of the per-underlying-interface structure is: sizeof(rwlock_t) + sizeof(pppox_sock*) * PPPOE_HASH_SIZE. Assuming a 64-bit pointer this will result in just over a 2KiB structure for PPPOE_HASH_BITS=8, which will likely result in a 4KiB allocation, which for us at least is acceptable. Not sure what the minimum allocation size is, and thus if values of 1 and 2 truly make sense. Default results in historic sizing and behaviour. Signed-off-by: Jaco Kroon Signed-off-by: David S. Miller --- drivers/net/ppp/Kconfig | 34 ++++++++++++++++++++++++++++++++++ drivers/net/ppp/pppoe.c | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig index ac4d162d9455..2fbcae31fc02 100644 --- a/drivers/net/ppp/Kconfig +++ b/drivers/net/ppp/Kconfig @@ -129,6 +129,40 @@ config PPPOE which contains instruction on how to use this driver (under the heading "Kernel mode PPPoE"). +choice + prompt "Number of PPPoE hash bits" + default PPPOE_HASH_BITS_4 + depends on PPPOE + help + Select the number of bits used for hashing PPPoE interfaces. + + Larger sizes reduces the risk of hash collisions at the cost + of slightly increased memory usage. + + This hash table is on a per outer ethernet interface. + +config PPPOE_HASH_BITS_2 + bool "1 bit (2 buckets)" + +config PPPOE_HASH_BITS_2 + bool "2 bits (4 buckets)" + +config PPPOE_HASH_BITS_4 + bool "4 bits (16 buckets)" + +config PPPOE_HASH_BITS_8 + bool "8 bits (256 buckets)" + +endchoice + +config PPPOE_HASH_BITS + int + default 1 if PPPOE_HASH_BITS_1 + default 2 if PPPOE_HASH_BITS_2 + default 4 if PPPOE_HASH_BITS_4 + default 8 if PPPOE_HASH_BITS_8 + default 4 + config PPTP tristate "PPP over IPv4 (PPTP)" depends on PPP && NET_IPGRE_DEMUX diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index ce2cbb5903d7..3b79c603b936 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -80,7 +80,7 @@ #include -#define PPPOE_HASH_BITS 4 +#define PPPOE_HASH_BITS CONFIG_PPPOE_HASH_BITS #define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS) #define PPPOE_HASH_MASK (PPPOE_HASH_SIZE - 1) -- cgit v1.2.3 From af2eab1a824349cfb0f6a720ad06eea48e9e6b74 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 17 May 2023 10:26:02 +0200 Subject: dt-bindings: net: nxp,sja1105: document spi-cpol/cpha Some boards use SJA1105 Ethernet Switch with SPI CPHA, while ones with SJA1110 use SPI CPOL, so document this to fix dtbs_check warnings: arch/arm64/boot/dts/freescale/fsl-lx2160a-bluebox3.dtb: ethernet-switch@0: Unevaluated properties are not allowed ('spi-cpol' was unexpected) Reviewed-by: Conor Dooley Reviewed-by: Vladimir Oltean Signed-off-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- .../devicetree/bindings/net/dsa/nxp,sja1105.yaml | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml index 9a64ed658745..4d5f5cc6d031 100644 --- a/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml +++ b/Documentation/devicetree/bindings/net/dsa/nxp,sja1105.yaml @@ -12,10 +12,6 @@ description: cs_sck_delay of 500ns. Ensuring that this SPI timing requirement is observed depends on the SPI bus master driver. -allOf: - - $ref: dsa.yaml#/$defs/ethernet-ports - - $ref: /schemas/spi/spi-peripheral-props.yaml# - maintainers: - Vladimir Oltean @@ -36,6 +32,9 @@ properties: reg: maxItems: 1 + spi-cpha: true + spi-cpol: true + # Optional container node for the 2 internal MDIO buses of the SJA1110 # (one for the internal 100base-T1 PHYs and the other for the single # 100base-TX PHY). The "reg" property does not have physical significance. @@ -109,6 +108,30 @@ $defs: 1860, 1880, 1900, 1920, 1940, 1960, 1980, 2000, 2020, 2040, 2060, 2080, 2100, 2120, 2140, 2160, 2180, 2200, 2220, 2240, 2260] +allOf: + - $ref: dsa.yaml#/$defs/ethernet-ports + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: + properties: + compatible: + enum: + - nxp,sja1105e + - nxp,sja1105p + - nxp,sja1105q + - nxp,sja1105r + - nxp,sja1105s + - nxp,sja1105t + then: + properties: + spi-cpol: false + required: + - spi-cpha + else: + properties: + spi-cpha: false + required: + - spi-cpol + unevaluatedProperties: false examples: @@ -120,6 +143,7 @@ examples: ethernet-switch@1 { reg = <0x1>; compatible = "nxp,sja1105t"; + spi-cpha; ethernet-ports { #address-cells = <1>; -- cgit v1.2.3 From f04a32b2c5b539e3c097cb5c7c1df12a8f4a0cf0 Mon Sep 17 00:00:00 2001 From: Alexey Gladkov Date: Wed, 17 May 2023 11:49:46 +0200 Subject: selftests/bpf: Do not use sign-file as testcase The sign-file utility (from scripts/) is used in prog_tests/verify_pkcs7_sig.c, but the utility should not be called as a test. Executing this utility produces the following error: selftests: /linux/tools/testing/selftests/bpf: urandom_read ok 16 selftests: /linux/tools/testing/selftests/bpf: urandom_read selftests: /linux/tools/testing/selftests/bpf: sign-file not ok 17 selftests: /linux/tools/testing/selftests/bpf: sign-file # exit=2 Also, urandom_read is mistakenly used as a test. It does not lead to an error, but should be moved over to TEST_GEN_FILES as well. The empty TEST_CUSTOM_PROGS can then be removed. Fixes: fc97590668ae ("selftests/bpf: Add test for bpf_verify_pkcs7_signature() kfunc") Signed-off-by: Alexey Gladkov Signed-off-by: Daniel Borkmann Reviewed-by: Roberto Sassu Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/ZEuWFk3QyML9y5QQ@example.org Link: https://lore.kernel.org/bpf/88e3ab23029d726a2703adcf6af8356f7a2d3483.1684316821.git.legion@kernel.org --- tools/testing/selftests/bpf/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index c49e5403ad0e..cd2426cca3d0 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -88,8 +88,7 @@ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ xskxceiver xdp_redirect_multi xdp_synproxy veristat xdp_hw_metadata \ xdp_features -TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read $(OUTPUT)/sign-file -TEST_GEN_FILES += liburandom_read.so +TEST_GEN_FILES += liburandom_read.so urandom_read sign-file # Emit succinct information message describing current building step # $1 - generic step name (e.g., CC, LINK, etc); -- cgit v1.2.3 From 2a36c26fe3b8e2cf39e15e80ba1abc889a75da4f Mon Sep 17 00:00:00 2001 From: Pengcheng Yang Date: Sat, 6 May 2023 11:07:19 +0800 Subject: bpftool: Support bpffs mountpoint as pin path for prog loadall Currently, when using prog loadall and the pin path is a bpffs mountpoint, bpffs will be repeatedly mounted to the parent directory of the bpffs mountpoint path. For example, a `bpftool prog loadall test.o /sys/fs/bpf` will trigger this. Signed-off-by: Pengcheng Yang Signed-off-by: Daniel Borkmann Reviewed-by: Quentin Monnet Link: https://lore.kernel.org/bpf/1683342439-3677-1-git-send-email-yangpc@wangsu.com --- tools/bpf/bpftool/common.c | 9 ++++++--- tools/bpf/bpftool/iter.c | 2 +- tools/bpf/bpftool/main.h | 2 +- tools/bpf/bpftool/prog.c | 2 +- tools/bpf/bpftool/struct_ops.c | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index 1360c82ae732..cc6e6aae2447 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c @@ -68,7 +68,7 @@ void p_info(const char *fmt, ...) va_end(ap); } -static bool is_bpffs(char *path) +static bool is_bpffs(const char *path) { struct statfs st_fs; @@ -244,13 +244,16 @@ int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type) return fd; } -int mount_bpffs_for_pin(const char *name) +int mount_bpffs_for_pin(const char *name, bool is_dir) { char err_str[ERR_MAX_LEN]; char *file; char *dir; int err = 0; + if (is_dir && is_bpffs(name)) + return err; + file = malloc(strlen(name) + 1); if (!file) { p_err("mem alloc failed"); @@ -286,7 +289,7 @@ int do_pin_fd(int fd, const char *name) { int err; - err = mount_bpffs_for_pin(name); + err = mount_bpffs_for_pin(name, false); if (err) return err; diff --git a/tools/bpf/bpftool/iter.c b/tools/bpf/bpftool/iter.c index 9a1d2365a297..6b0e5202ca7a 100644 --- a/tools/bpf/bpftool/iter.c +++ b/tools/bpf/bpftool/iter.c @@ -76,7 +76,7 @@ static int do_pin(int argc, char **argv) goto close_obj; } - err = mount_bpffs_for_pin(path); + err = mount_bpffs_for_pin(path, false); if (err) goto close_link; diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index a49534d7eafa..b8bb08d10dec 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -142,7 +142,7 @@ const char *get_fd_type_name(enum bpf_obj_type type); char *get_fdinfo(int fd, const char *key); int open_obj_pinned(const char *path, bool quiet); int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type); -int mount_bpffs_for_pin(const char *name); +int mount_bpffs_for_pin(const char *name, bool is_dir); int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(int *, char ***)); int do_pin_fd(int fd, const char *name); diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 91b6075b2db3..1f736dc29824 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -1739,7 +1739,7 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) goto err_close_obj; } - err = mount_bpffs_for_pin(pinfile); + err = mount_bpffs_for_pin(pinfile, !first_prog_only); if (err) goto err_close_obj; diff --git a/tools/bpf/bpftool/struct_ops.c b/tools/bpf/bpftool/struct_ops.c index 57c3da70aa31..3ebc9fe91e0e 100644 --- a/tools/bpf/bpftool/struct_ops.c +++ b/tools/bpf/bpftool/struct_ops.c @@ -509,7 +509,7 @@ static int do_register(int argc, char **argv) if (argc == 1) linkdir = GET_ARG(); - if (linkdir && mount_bpffs_for_pin(linkdir)) { + if (linkdir && mount_bpffs_for_pin(linkdir, true)) { p_err("can't mount bpffs for pinning"); return -1; } -- cgit v1.2.3 From 8819495a754e71d3c3fde991c26ad832af995136 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Tue, 9 May 2023 18:08:45 +0000 Subject: bpf, docs: Shift operations are defined to use a mask Update the documentation regarding shift operations to explain the use of a mask, since otherwise shifting by a value out of range (like negative) is undefined. Signed-off-by: Dave Thaler Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230509180845.1236-1-dthaler1968@googlemail.com --- Documentation/bpf/instruction-set.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/bpf/instruction-set.rst b/Documentation/bpf/instruction-set.rst index 492980ece1ab..6644842cd3ea 100644 --- a/Documentation/bpf/instruction-set.rst +++ b/Documentation/bpf/instruction-set.rst @@ -163,13 +163,13 @@ BPF_MUL 0x20 dst \*= src BPF_DIV 0x30 dst = (src != 0) ? (dst / src) : 0 BPF_OR 0x40 dst \|= src BPF_AND 0x50 dst &= src -BPF_LSH 0x60 dst <<= src -BPF_RSH 0x70 dst >>= src +BPF_LSH 0x60 dst <<= (src & mask) +BPF_RSH 0x70 dst >>= (src & mask) BPF_NEG 0x80 dst = ~src BPF_MOD 0x90 dst = (src != 0) ? (dst % src) : dst BPF_XOR 0xa0 dst ^= src BPF_MOV 0xb0 dst = src -BPF_ARSH 0xc0 sign extending shift right +BPF_ARSH 0xc0 sign extending dst >>= (src & mask) BPF_END 0xd0 byte swap operations (see `Byte swap instructions`_ below) ======== ===== ========================================================== @@ -204,6 +204,9 @@ for ``BPF_ALU64``, 'imm' is first sign extended to 64 bits and the result interpreted as an unsigned 64-bit value. There are no instructions for signed division or modulo. +Shift operations use a mask of 0x3F (63) for 64-bit operations and 0x1F (31) +for 32-bit operations. + Byte swap instructions ~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 12852f8e0f70d9a5263e2834c5483268b08b5e9c Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 16 May 2023 21:04:04 -0700 Subject: selftests/bpf: Fix dynptr/test_dynptr_is_null With latest llvm17, dynptr/test_dynptr_is_null subtest failed in my testing VM. The failure log looks like below: All error logs: tester_init:PASS:tester_log_buf 0 nsec process_subtest:PASS:obj_open_mem 0 nsec process_subtest:PASS:Can't alloc specs array 0 nsec verify_success:PASS:dynptr_success__open 0 nsec verify_success:PASS:bpf_object__find_program_by_name 0 nsec verify_success:PASS:dynptr_success__load 0 nsec verify_success:PASS:bpf_program__attach 0 nsec verify_success:FAIL:err unexpected err: actual 4 != expected 0 #65/9 dynptr/test_dynptr_is_null:FAIL The error happens for bpf prog test_dynptr_is_null in dynptr_success.c: if (bpf_dynptr_is_null(&ptr2)) { err = 4; goto exit; } The bpf_dynptr_is_null(&ptr) unexpectedly returned a non-zero value and the control went to the error path. Digging further, I found the root cause is due to function signature difference between kernel and user space. In kernel, we have ... __bpf_kfunc bool bpf_dynptr_is_null(struct bpf_dynptr_kern *ptr) ... while in bpf_kfuncs.h we have: extern int bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; The kernel bpf_dynptr_is_null disasm code: ffffffff812f1a90 : ffffffff812f1a90: f3 0f 1e fa endbr64 ffffffff812f1a94: 0f 1f 44 00 00 nopl (%rax,%rax) ffffffff812f1a99: 53 pushq %rbx ffffffff812f1a9a: 48 89 fb movq %rdi, %rbx ffffffff812f1a9d: e8 ae 29 17 00 callq 0xffffffff81464450 <__asan_load8_noabort> ffffffff812f1aa2: 48 83 3b 00 cmpq $0x0, (%rbx) ffffffff812f1aa6: 0f 94 c0 sete %al ffffffff812f1aa9: 5b popq %rbx ffffffff812f1aaa: c3 retq Note that only 1-byte register %al is set and the other 7-bytes are not touched. In bpf program, the asm code for the above bpf_dynptr_is_null(&ptr2): 266: 85 10 00 00 ff ff ff ff call -0x1 267: b4 01 00 00 04 00 00 00 w1 = 0x4 268: 16 00 03 00 00 00 00 00 if w0 == 0x0 goto +0x3 Basically, 4-byte subregister is tested. This might cause error as the value other than the lowest byte might not be 0. This patch fixed the issue by using the identical func prototype across kernel and selftest user space. The fixed bpf asm code: 267: 85 10 00 00 ff ff ff ff call -0x1 268: 54 00 00 00 01 00 00 00 w0 &= 0x1 269: b4 01 00 00 04 00 00 00 w1 = 0x4 270: 16 00 03 00 00 00 00 00 if w0 == 0x0 goto +0x3 Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230517040404.4023912-1-yhs@fb.com --- tools/testing/selftests/bpf/bpf_kfuncs.h | 2 +- tools/testing/selftests/bpf/progs/dynptr_fail.c | 1 + tools/testing/selftests/bpf/progs/dynptr_success.c | 1 + tools/testing/selftests/bpf/progs/test_xdp_dynptr.c | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index f3c41f8902a0..821c25b7d0df 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -36,7 +36,7 @@ extern void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *ptr, __u32 offset, void *buffer, __u32 buffer__szk) __ksym; extern int bpf_dynptr_adjust(const struct bpf_dynptr *ptr, __u32 start, __u32 end) __ksym; -extern int bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; +extern bool bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; extern int bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym; extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym; diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c index c2f0e18af951..7ce7e827d5f0 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/tools/testing/selftests/bpf/progs/dynptr_success.c b/tools/testing/selftests/bpf/progs/dynptr_success.c index 0c053976f8f9..5985920d162e 100644 --- a/tools/testing/selftests/bpf/progs/dynptr_success.c +++ b/tools/testing/selftests/bpf/progs/dynptr_success.c @@ -2,6 +2,7 @@ /* Copyright (c) 2022 Facebook */ #include +#include #include #include #include "bpf_misc.h" diff --git a/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c b/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c index 25ee4a22e48d..78c368e71797 100644 --- a/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c +++ b/tools/testing/selftests/bpf/progs/test_xdp_dynptr.c @@ -2,6 +2,7 @@ /* Copyright (c) 2022 Meta */ #include #include +#include #include #include #include -- cgit v1.2.3 From effcf62416240e5ec0eded0ea2644c48d2c7c9f1 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 16 May 2023 21:04:09 -0700 Subject: selftests/bpf: Make bpf_dynptr_is_rdonly() prototyype consistent with kernel Currently kernel kfunc bpf_dynptr_is_rdonly() has prototype ... __bpf_kfunc bool bpf_dynptr_is_rdonly(struct bpf_dynptr_kern *ptr) ... while selftests bpf_kfuncs.h has: extern int bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; Such a mismatch might cause problems although currently it is okay in selftests. Fix it to prevent future potential surprise. Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230517040409.4024618-1-yhs@fb.com --- tools/testing/selftests/bpf/bpf_kfuncs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/bpf_kfuncs.h b/tools/testing/selftests/bpf/bpf_kfuncs.h index 821c25b7d0df..642dda0e758a 100644 --- a/tools/testing/selftests/bpf/bpf_kfuncs.h +++ b/tools/testing/selftests/bpf/bpf_kfuncs.h @@ -37,7 +37,7 @@ extern void *bpf_dynptr_slice_rdwr(const struct bpf_dynptr *ptr, __u32 offset, extern int bpf_dynptr_adjust(const struct bpf_dynptr *ptr, __u32 start, __u32 end) __ksym; extern bool bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym; -extern int bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; +extern bool bpf_dynptr_is_rdonly(const struct bpf_dynptr *ptr) __ksym; extern __u32 bpf_dynptr_size(const struct bpf_dynptr *ptr) __ksym; extern int bpf_dynptr_clone(const struct bpf_dynptr *ptr, struct bpf_dynptr *clone__init) __ksym; -- cgit v1.2.3 From 578fb0926c127d1b11b01b0102605efde9be9f41 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Wed, 26 Apr 2023 11:50:45 -0700 Subject: ice: update ICE_PHY_TYPE_HIGH_MAX_INDEX ICE_PHY_TYPE_HIGH_MAX_INDEX should be the maximum index value and not the length/number of ICE_PHY_TYPE_HIGH. This is not an issue because this define is only used when calling ice_get_link_speed_based_on_phy_type(), which will return ICE_AQ_LINK_SPEED_UNKNOWN for any invalid index. The caller of ice_get_link_speed_based_on_phy_type(), ice_update_phy_type() checks that the return value is a valid link speed before using it and ICE_AQ_LINK_SPEED_UNKNOWN is not. However, update the define to reflect the correct value. Signed-off-by: Paul Greenwalt Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 838d9b274d68..63d3e1dcbba5 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1087,7 +1087,7 @@ struct ice_aqc_get_phy_caps { #define ICE_PHY_TYPE_HIGH_100G_CAUI2 BIT_ULL(2) #define ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC BIT_ULL(3) #define ICE_PHY_TYPE_HIGH_100G_AUI2 BIT_ULL(4) -#define ICE_PHY_TYPE_HIGH_MAX_INDEX 5 +#define ICE_PHY_TYPE_HIGH_MAX_INDEX 4 struct ice_aqc_get_phy_caps_data { __le64 phy_type_low; /* Use values from ICE_PHY_TYPE_LOW_* */ -- cgit v1.2.3 From 9136e1f1e5c3f3409b09764556f33fd6353cad60 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Wed, 26 Apr 2023 11:50:46 -0700 Subject: ice: refactor PHY type to ethtool link mode Refactor ice_phy_type_to_ethtool to use phy_type_[low|high]_lkup table to map PHY type to AQ link speed and ethtool link mode. This removes complexity and simplifies future changes. Signed-off-by: Paul Greenwalt Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 309 +++------------------------ drivers/net/ethernet/intel/ice/ice_ethtool.h | 105 +++++++++ 3 files changed, 141 insertions(+), 274 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_ethtool.h diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index d637032c8139..8b016511561f 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 8407c7175cf6..8d5cbbd0b3d5 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -4,6 +4,7 @@ /* ethtool support for ice */ #include "ice.h" +#include "ice_ethtool.h" #include "ice_flow.h" #include "ice_fltr.h" #include "ice_lib.h" @@ -1658,15 +1659,26 @@ ice_mask_min_supported_speeds(struct ice_hw *hw, *phy_types_low &= ~ICE_PHY_TYPE_LOW_MASK_MIN_1G; } -#define ice_ethtool_advertise_link_mode(aq_link_speed, ethtool_link_mode) \ - do { \ - if (req_speeds & (aq_link_speed) || \ - (!req_speeds && \ - (advert_phy_type_lo & phy_type_mask_lo || \ - advert_phy_type_hi & phy_type_mask_hi))) \ - ethtool_link_ksettings_add_link_mode(ks, advertising,\ - ethtool_link_mode); \ - } while (0) +/** + * ice_linkmode_set_bit - set link mode bit + * @phy_to_ethtool: PHY type to ethtool link mode struct to set + * @ks: ethtool link ksettings struct to fill out + * @req_speeds: speed requested by user + * @advert_phy_type: advertised PHY type + * @phy_type: PHY type + */ +static void +ice_linkmode_set_bit(const struct ice_phy_type_to_ethtool *phy_to_ethtool, + struct ethtool_link_ksettings *ks, u32 req_speeds, + u64 advert_phy_type, u32 phy_type) +{ + linkmode_set_bit(phy_to_ethtool->link_mode, ks->link_modes.supported); + + if (req_speeds & phy_to_ethtool->aq_link_speed || + (!req_speeds && advert_phy_type & BIT(phy_type))) + linkmode_set_bit(phy_to_ethtool->link_mode, + ks->link_modes.advertising); +} /** * ice_phy_type_to_ethtool - convert the phy_types to ethtool link modes @@ -1682,11 +1694,10 @@ ice_phy_type_to_ethtool(struct net_device *netdev, struct ice_pf *pf = vsi->back; u64 advert_phy_type_lo = 0; u64 advert_phy_type_hi = 0; - u64 phy_type_mask_lo = 0; - u64 phy_type_mask_hi = 0; u64 phy_types_high = 0; u64 phy_types_low = 0; - u16 req_speeds; + u32 req_speeds; + u32 i; req_speeds = vsi->port_info->phy.link_info.req_speeds; @@ -1743,272 +1754,22 @@ ice_phy_type_to_ethtool(struct net_device *netdev, advert_phy_type_hi = vsi->port_info->phy.phy_type_high; } - ethtool_link_ksettings_zero_link_mode(ks, supported); - ethtool_link_ksettings_zero_link_mode(ks, advertising); - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_100BASE_TX | - ICE_PHY_TYPE_LOW_100M_SGMII; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 100baseT_Full); - - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100MB, - 100baseT_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_1000BASE_T | - ICE_PHY_TYPE_LOW_1G_SGMII; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 1000baseT_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_1000MB, - 1000baseT_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_1000BASE_KX; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 1000baseKX_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_1000MB, - 1000baseKX_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_1000BASE_SX | - ICE_PHY_TYPE_LOW_1000BASE_LX; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 1000baseX_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_1000MB, - 1000baseX_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_2500BASE_T; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 2500baseT_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_2500MB, - 2500baseT_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_2500BASE_X | - ICE_PHY_TYPE_LOW_2500BASE_KX; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 2500baseX_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_2500MB, - 2500baseX_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_5GBASE_T | - ICE_PHY_TYPE_LOW_5GBASE_KR; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 5000baseT_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_5GB, - 5000baseT_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_10GBASE_T | - ICE_PHY_TYPE_LOW_10G_SFI_DA | - ICE_PHY_TYPE_LOW_10G_SFI_AOC_ACC | - ICE_PHY_TYPE_LOW_10G_SFI_C2C; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 10000baseT_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_10GB, - 10000baseT_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_10GBASE_KR_CR1; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 10000baseKR_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_10GB, - 10000baseKR_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_10GBASE_SR; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 10000baseSR_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_10GB, - 10000baseSR_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_10GBASE_LR; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 10000baseLR_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_10GB, - 10000baseLR_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_25GBASE_T | - ICE_PHY_TYPE_LOW_25GBASE_CR | - ICE_PHY_TYPE_LOW_25GBASE_CR_S | - ICE_PHY_TYPE_LOW_25GBASE_CR1 | - ICE_PHY_TYPE_LOW_25G_AUI_AOC_ACC | - ICE_PHY_TYPE_LOW_25G_AUI_C2C; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 25000baseCR_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_25GB, - 25000baseCR_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_25GBASE_SR | - ICE_PHY_TYPE_LOW_25GBASE_LR; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 25000baseSR_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_25GB, - 25000baseSR_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_25GBASE_KR | - ICE_PHY_TYPE_LOW_25GBASE_KR_S | - ICE_PHY_TYPE_LOW_25GBASE_KR1; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 25000baseKR_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_25GB, - 25000baseKR_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_40GBASE_KR4; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 40000baseKR4_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_40GB, - 40000baseKR4_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_40GBASE_CR4 | - ICE_PHY_TYPE_LOW_40G_XLAUI_AOC_ACC | - ICE_PHY_TYPE_LOW_40G_XLAUI; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 40000baseCR4_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_40GB, - 40000baseCR4_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_40GBASE_SR4; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 40000baseSR4_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_40GB, - 40000baseSR4_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_40GBASE_LR4; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 40000baseLR4_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_40GB, - 40000baseLR4_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_50GBASE_CR2 | - ICE_PHY_TYPE_LOW_50G_LAUI2_AOC_ACC | - ICE_PHY_TYPE_LOW_50G_LAUI2 | - ICE_PHY_TYPE_LOW_50G_AUI2_AOC_ACC | - ICE_PHY_TYPE_LOW_50G_AUI2 | - ICE_PHY_TYPE_LOW_50GBASE_CP | - ICE_PHY_TYPE_LOW_50GBASE_SR | - ICE_PHY_TYPE_LOW_50G_AUI1_AOC_ACC | - ICE_PHY_TYPE_LOW_50G_AUI1; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 50000baseCR2_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_50GB, - 50000baseCR2_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_50GBASE_KR2 | - ICE_PHY_TYPE_LOW_50GBASE_KR_PAM4; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 50000baseKR2_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_50GB, - 50000baseKR2_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_50GBASE_SR2 | - ICE_PHY_TYPE_LOW_50GBASE_LR2 | - ICE_PHY_TYPE_LOW_50GBASE_FR | - ICE_PHY_TYPE_LOW_50GBASE_LR; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 50000baseSR2_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_50GB, - 50000baseSR2_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_100GBASE_CR4 | - ICE_PHY_TYPE_LOW_100G_CAUI4_AOC_ACC | - ICE_PHY_TYPE_LOW_100G_CAUI4 | - ICE_PHY_TYPE_LOW_100G_AUI4_AOC_ACC | - ICE_PHY_TYPE_LOW_100G_AUI4 | - ICE_PHY_TYPE_LOW_100GBASE_CR_PAM4; - phy_type_mask_hi = ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC | - ICE_PHY_TYPE_HIGH_100G_CAUI2 | - ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC | - ICE_PHY_TYPE_HIGH_100G_AUI2; - if (phy_types_low & phy_type_mask_lo || - phy_types_high & phy_type_mask_hi) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 100000baseCR4_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, - 100000baseCR4_Full); - } - - if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_CP2) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 100000baseCR2_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, - 100000baseCR2_Full); - } - - if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_SR4) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 100000baseSR4_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, - 100000baseSR4_Full); - } - - if (phy_types_low & ICE_PHY_TYPE_LOW_100GBASE_SR2) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 100000baseSR2_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, - 100000baseSR2_Full); - } - - phy_type_mask_lo = ICE_PHY_TYPE_LOW_100GBASE_LR4 | - ICE_PHY_TYPE_LOW_100GBASE_DR; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 100000baseLR4_ER4_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, - 100000baseLR4_ER4_Full); - } + linkmode_zero(ks->link_modes.supported); + linkmode_zero(ks->link_modes.advertising); - phy_type_mask_lo = ICE_PHY_TYPE_LOW_100GBASE_KR4 | - ICE_PHY_TYPE_LOW_100GBASE_KR_PAM4; - if (phy_types_low & phy_type_mask_lo) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 100000baseKR4_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, - 100000baseKR4_Full); + for (i = 0; i < BITS_PER_TYPE(u64); i++) { + if (phy_types_low & BIT_ULL(i)) + ice_linkmode_set_bit(&phy_type_low_lkup[i], ks, + req_speeds, advert_phy_type_lo, + i); } - if (phy_types_high & ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4) { - ethtool_link_ksettings_add_link_mode(ks, supported, - 100000baseKR2_Full); - ice_ethtool_advertise_link_mode(ICE_AQ_LINK_SPEED_100GB, - 100000baseKR2_Full); + for (i = 0; i < BITS_PER_TYPE(u64); i++) { + if (phy_types_high & BIT_ULL(i)) + ice_linkmode_set_bit(&phy_type_high_lkup[i], ks, + req_speeds, advert_phy_type_hi, + i); } - } #define TEST_SET_BITS_TIMEOUT 50 diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.h b/drivers/net/ethernet/intel/ice/ice_ethtool.h new file mode 100644 index 000000000000..00043ea9469a --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2023 Intel Corporation */ + +#ifndef _ICE_ETHTOOL_H_ +#define _ICE_ETHTOOL_H_ + +struct ice_phy_type_to_ethtool { + u64 aq_link_speed; + u8 link_mode; +}; + +/* Macro to make PHY type to Ethtool link mode table entry. + * The index is the PHY type. + */ +#define ICE_PHY_TYPE(LINK_SPEED, ETHTOOL_LINK_MODE) {\ + .aq_link_speed = ICE_AQ_LINK_SPEED_##LINK_SPEED, \ + .link_mode = ETHTOOL_LINK_MODE_##ETHTOOL_LINK_MODE##_BIT, \ +} + +/* Lookup table mapping PHY type low to link speed and Ethtool link modes. + * Array index corresponds to HW PHY type bit, see + * ice_adminq_cmd.h:ICE_PHY_TYPE_LOW_*. + */ +static const struct ice_phy_type_to_ethtool +phy_type_low_lkup[] = { + [0] = ICE_PHY_TYPE(100MB, 100baseT_Full), + [1] = ICE_PHY_TYPE(100MB, 100baseT_Full), + [2] = ICE_PHY_TYPE(1000MB, 1000baseT_Full), + [3] = ICE_PHY_TYPE(1000MB, 1000baseX_Full), + [4] = ICE_PHY_TYPE(1000MB, 1000baseX_Full), + [5] = ICE_PHY_TYPE(1000MB, 1000baseKX_Full), + [6] = ICE_PHY_TYPE(1000MB, 1000baseT_Full), + [7] = ICE_PHY_TYPE(2500MB, 2500baseT_Full), + [8] = ICE_PHY_TYPE(2500MB, 2500baseX_Full), + [9] = ICE_PHY_TYPE(2500MB, 2500baseX_Full), + [10] = ICE_PHY_TYPE(5GB, 5000baseT_Full), + [11] = ICE_PHY_TYPE(5GB, 5000baseT_Full), + [12] = ICE_PHY_TYPE(10GB, 10000baseT_Full), + [13] = ICE_PHY_TYPE(10GB, 10000baseT_Full), + [14] = ICE_PHY_TYPE(10GB, 10000baseSR_Full), + [15] = ICE_PHY_TYPE(10GB, 10000baseLR_Full), + [16] = ICE_PHY_TYPE(10GB, 10000baseKR_Full), + [17] = ICE_PHY_TYPE(10GB, 10000baseT_Full), + [18] = ICE_PHY_TYPE(10GB, 10000baseKR_Full), + [19] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), + [20] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), + [21] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), + [22] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), + [23] = ICE_PHY_TYPE(25GB, 25000baseSR_Full), + [24] = ICE_PHY_TYPE(25GB, 25000baseSR_Full), + [25] = ICE_PHY_TYPE(25GB, 25000baseKR_Full), + [26] = ICE_PHY_TYPE(25GB, 25000baseKR_Full), + [27] = ICE_PHY_TYPE(25GB, 25000baseKR_Full), + [28] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), + [29] = ICE_PHY_TYPE(25GB, 25000baseKR_Full), + [30] = ICE_PHY_TYPE(40GB, 40000baseCR4_Full), + [31] = ICE_PHY_TYPE(40GB, 40000baseSR4_Full), + [32] = ICE_PHY_TYPE(40GB, 40000baseLR4_Full), + [33] = ICE_PHY_TYPE(40GB, 40000baseKR4_Full), + [34] = ICE_PHY_TYPE(40GB, 40000baseCR4_Full), + [35] = ICE_PHY_TYPE(40GB, 40000baseCR4_Full), + [36] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [37] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), + [38] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), + [39] = ICE_PHY_TYPE(50GB, 50000baseKR2_Full), + [40] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [41] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [42] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [43] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [44] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [45] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [46] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), + [47] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), + [48] = ICE_PHY_TYPE(50GB, 50000baseKR2_Full), + [49] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [50] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [51] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [52] = ICE_PHY_TYPE(100GB, 100000baseSR4_Full), + [53] = ICE_PHY_TYPE(100GB, 100000baseLR4_ER4_Full), + [54] = ICE_PHY_TYPE(100GB, 100000baseKR4_Full), + [55] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [56] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [57] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [58] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [59] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [60] = ICE_PHY_TYPE(100GB, 100000baseKR4_Full), + [61] = ICE_PHY_TYPE(100GB, 100000baseCR2_Full), + [62] = ICE_PHY_TYPE(100GB, 100000baseSR2_Full), + [63] = ICE_PHY_TYPE(100GB, 100000baseLR4_ER4_Full), +}; + +/* Lookup table mapping PHY type high to link speed and Ethtool link modes. + * Array index corresponds to HW PHY type bit, see + * ice_adminq_cmd.h:ICE_PHY_TYPE_HIGH_* + */ +static const struct ice_phy_type_to_ethtool +phy_type_high_lkup[] = { + [0] = ICE_PHY_TYPE(100GB, 100000baseKR2_Full), + [1] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [2] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [3] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [4] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), +}; + +#endif /* !_ICE_ETHTOOL_H_ */ -- cgit v1.2.3 From 49eb1c1f2f05fe948b209ad359283355d3428d89 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Wed, 26 Apr 2023 11:50:47 -0700 Subject: ice: update PHY type to ethtool link mode mapping Some link modes can be more accurately reported due to newer link mode values that have been added to the kernel; update those PHY type to report modes that better reflect the link mode. Signed-off-by: Paul Greenwalt Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_ethtool.h | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.h b/drivers/net/ethernet/intel/ice/ice_ethtool.h index 00043ea9469a..b403ee79cd5e 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.h +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.h @@ -36,11 +36,11 @@ phy_type_low_lkup[] = { [10] = ICE_PHY_TYPE(5GB, 5000baseT_Full), [11] = ICE_PHY_TYPE(5GB, 5000baseT_Full), [12] = ICE_PHY_TYPE(10GB, 10000baseT_Full), - [13] = ICE_PHY_TYPE(10GB, 10000baseT_Full), + [13] = ICE_PHY_TYPE(10GB, 10000baseCR_Full), [14] = ICE_PHY_TYPE(10GB, 10000baseSR_Full), [15] = ICE_PHY_TYPE(10GB, 10000baseLR_Full), [16] = ICE_PHY_TYPE(10GB, 10000baseKR_Full), - [17] = ICE_PHY_TYPE(10GB, 10000baseT_Full), + [17] = ICE_PHY_TYPE(10GB, 10000baseCR_Full), [18] = ICE_PHY_TYPE(10GB, 10000baseKR_Full), [19] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), [20] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), @@ -51,36 +51,36 @@ phy_type_low_lkup[] = { [25] = ICE_PHY_TYPE(25GB, 25000baseKR_Full), [26] = ICE_PHY_TYPE(25GB, 25000baseKR_Full), [27] = ICE_PHY_TYPE(25GB, 25000baseKR_Full), - [28] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), - [29] = ICE_PHY_TYPE(25GB, 25000baseKR_Full), + [28] = ICE_PHY_TYPE(25GB, 25000baseSR_Full), + [29] = ICE_PHY_TYPE(25GB, 25000baseCR_Full), [30] = ICE_PHY_TYPE(40GB, 40000baseCR4_Full), [31] = ICE_PHY_TYPE(40GB, 40000baseSR4_Full), [32] = ICE_PHY_TYPE(40GB, 40000baseLR4_Full), [33] = ICE_PHY_TYPE(40GB, 40000baseKR4_Full), - [34] = ICE_PHY_TYPE(40GB, 40000baseCR4_Full), + [34] = ICE_PHY_TYPE(40GB, 40000baseSR4_Full), [35] = ICE_PHY_TYPE(40GB, 40000baseCR4_Full), [36] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), [37] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), [38] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), [39] = ICE_PHY_TYPE(50GB, 50000baseKR2_Full), - [40] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [40] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), [41] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), - [42] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [42] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), [43] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), - [44] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), - [45] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), - [46] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), - [47] = ICE_PHY_TYPE(50GB, 50000baseSR2_Full), - [48] = ICE_PHY_TYPE(50GB, 50000baseKR2_Full), - [49] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), - [50] = ICE_PHY_TYPE(50GB, 50000baseCR2_Full), + [44] = ICE_PHY_TYPE(50GB, 50000baseCR_Full), + [45] = ICE_PHY_TYPE(50GB, 50000baseSR_Full), + [46] = ICE_PHY_TYPE(50GB, 50000baseLR_ER_FR_Full), + [47] = ICE_PHY_TYPE(50GB, 50000baseLR_ER_FR_Full), + [48] = ICE_PHY_TYPE(50GB, 50000baseKR_Full), + [49] = ICE_PHY_TYPE(50GB, 50000baseSR_Full), + [50] = ICE_PHY_TYPE(50GB, 50000baseCR_Full), [51] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), [52] = ICE_PHY_TYPE(100GB, 100000baseSR4_Full), [53] = ICE_PHY_TYPE(100GB, 100000baseLR4_ER4_Full), [54] = ICE_PHY_TYPE(100GB, 100000baseKR4_Full), [55] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), [56] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), - [57] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [57] = ICE_PHY_TYPE(100GB, 100000baseSR4_Full), [58] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), [59] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), [60] = ICE_PHY_TYPE(100GB, 100000baseKR4_Full), @@ -96,10 +96,10 @@ phy_type_low_lkup[] = { static const struct ice_phy_type_to_ethtool phy_type_high_lkup[] = { [0] = ICE_PHY_TYPE(100GB, 100000baseKR2_Full), - [1] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), - [2] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), - [3] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), - [4] = ICE_PHY_TYPE(100GB, 100000baseCR4_Full), + [1] = ICE_PHY_TYPE(100GB, 100000baseSR2_Full), + [2] = ICE_PHY_TYPE(100GB, 100000baseCR2_Full), + [3] = ICE_PHY_TYPE(100GB, 100000baseSR2_Full), + [4] = ICE_PHY_TYPE(100GB, 100000baseCR2_Full), }; #endif /* !_ICE_ETHTOOL_H_ */ -- cgit v1.2.3 From 1c769b1a303f7a3b447fc7244340b77823bdbfdc Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Tue, 16 May 2023 13:30:55 +0200 Subject: ice: Remove LAG+SRIOV mutual exclusion There was a change previously to stop SR-IOV and LAG from existing on the same interface. This was to prevent the violation of LACP (Link Aggregation Control Protocol). The method to achieve this was to add a no-op Rx handler onto the netdev when SR-IOV VFs were present, thus blocking bonding, bridging, etc from claiming the interface by adding its own Rx handler. Also, when an interface was added into a aggregate, then the SR-IOV capability was set to false. There are some users that have in house solutions using both SR-IOV and bridging/bonding that this method interferes with (e.g. creating duplicate VFs on the bonded interfaces and failing between them when the interface fails over). It makes more sense to provide the most functionality possible, the restriction on co-existence of these features will be removed. No additional functionality is currently being provided beyond what existed before the co-existence restriction was put into place. It is up to the end user to not implement a solution that would interfere with existing network protocols. Reviewed-by: Michal Swiatkowski Signed-off-by: Dave Ertman Signed-off-by: Wojciech Drewek Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- .../device_drivers/ethernet/intel/ice.rst | 18 -------- drivers/net/ethernet/intel/ice/ice.h | 19 -------- drivers/net/ethernet/intel/ice/ice_lag.c | 12 ----- drivers/net/ethernet/intel/ice/ice_lag.h | 54 ---------------------- drivers/net/ethernet/intel/ice/ice_lib.c | 2 - drivers/net/ethernet/intel/ice/ice_sriov.c | 4 -- 6 files changed, 109 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst index 69695e5511f4..e4d065c55ea8 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst @@ -84,24 +84,6 @@ Once the VM shuts down, or otherwise releases the VF, the command will complete. -Important notes for SR-IOV and Link Aggregation ------------------------------------------------ -Link Aggregation is mutually exclusive with SR-IOV. - -- If Link Aggregation is active, SR-IOV VFs cannot be created on the PF. -- If SR-IOV is active, you cannot set up Link Aggregation on the interface. - -Bridging and MACVLAN are also affected by this. If you wish to use bridging or -MACVLAN with SR-IOV, you must set up bridging or MACVLAN before enabling -SR-IOV. If you are using bridging or MACVLAN in conjunction with SR-IOV, and -you want to remove the interface from the bridge or MACVLAN, you must follow -these steps: - -1. Destroy SR-IOV VFs if they exist -2. Remove the interface from the bridge or MACVLAN -3. Recreate SRIOV VFs as needed - - Additional Features and Configurations ====================================== diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 8b016511561f..b4bca1d964a9 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -814,25 +814,6 @@ static inline bool ice_is_switchdev_running(struct ice_pf *pf) return pf->switchdev.is_running; } -/** - * ice_set_sriov_cap - enable SRIOV in PF flags - * @pf: PF struct - */ -static inline void ice_set_sriov_cap(struct ice_pf *pf) -{ - if (pf->hw.func_caps.common_cap.sr_iov_1_1) - set_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags); -} - -/** - * ice_clear_sriov_cap - disable SRIOV in PF flags - * @pf: PF struct - */ -static inline void ice_clear_sriov_cap(struct ice_pf *pf) -{ - clear_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags); -} - #define ICE_FD_STAT_CTR_BLOCK_COUNT 256 #define ICE_FD_STAT_PF_IDX(base_idx) \ ((base_idx) * ICE_FD_STAT_CTR_BLOCK_COUNT) diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index ee5b36941ba3..5a7753bda324 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -6,15 +6,6 @@ #include "ice.h" #include "ice_lag.h" -/** - * ice_lag_nop_handler - no-op Rx handler to disable LAG - * @pskb: pointer to skb pointer - */ -rx_handler_result_t ice_lag_nop_handler(struct sk_buff __always_unused **pskb) -{ - return RX_HANDLER_PASS; -} - /** * ice_lag_set_primary - set PF LAG state as Primary * @lag: LAG info struct @@ -158,7 +149,6 @@ ice_lag_link(struct ice_lag *lag, struct netdev_notifier_changeupper_info *info) lag->upper_netdev = upper; } - ice_clear_sriov_cap(pf); ice_clear_rdma_cap(pf); lag->bonded = true; @@ -205,7 +195,6 @@ ice_lag_unlink(struct ice_lag *lag, } lag->peer_netdev = NULL; - ice_set_sriov_cap(pf); ice_set_rdma_cap(pf); lag->bonded = false; lag->role = ICE_LAG_NONE; @@ -229,7 +218,6 @@ static void ice_lag_unregister(struct ice_lag *lag, struct net_device *netdev) if (lag->upper_netdev) { dev_put(lag->upper_netdev); lag->upper_netdev = NULL; - ice_set_sriov_cap(pf); ice_set_rdma_cap(pf); } /* perform some cleanup in case we come back */ diff --git a/drivers/net/ethernet/intel/ice/ice_lag.h b/drivers/net/ethernet/intel/ice/ice_lag.h index 51b5cf467ce2..2c373676c42f 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.h +++ b/drivers/net/ethernet/intel/ice/ice_lag.h @@ -25,63 +25,9 @@ struct ice_lag { struct notifier_block notif_block; u8 bonded:1; /* currently bonded */ u8 primary:1; /* this is primary */ - u8 handler:1; /* did we register a rx_netdev_handler */ - /* each thing blocking bonding will increment this value by one. - * If this value is zero, then bonding is allowed. - */ - u16 dis_lag; u8 role; }; int ice_init_lag(struct ice_pf *pf); void ice_deinit_lag(struct ice_pf *pf); -rx_handler_result_t ice_lag_nop_handler(struct sk_buff **pskb); - -/** - * ice_disable_lag - increment LAG disable count - * @lag: LAG struct - */ -static inline void ice_disable_lag(struct ice_lag *lag) -{ - /* If LAG this PF is not already disabled, disable it */ - rtnl_lock(); - if (!netdev_is_rx_handler_busy(lag->netdev)) { - if (!netdev_rx_handler_register(lag->netdev, - ice_lag_nop_handler, - NULL)) - lag->handler = true; - } - rtnl_unlock(); - lag->dis_lag++; -} - -/** - * ice_enable_lag - decrement disable count for a PF - * @lag: LAG struct - * - * Decrement the disable counter for a port, and if that count reaches - * zero, then remove the no-op Rx handler from that netdev - */ -static inline void ice_enable_lag(struct ice_lag *lag) -{ - if (lag->dis_lag) - lag->dis_lag--; - if (!lag->dis_lag && lag->handler) { - rtnl_lock(); - netdev_rx_handler_unregister(lag->netdev); - rtnl_unlock(); - lag->handler = false; - } -} - -/** - * ice_is_lag_dis - is LAG disabled - * @lag: LAG struct - * - * Return true if bonding is disabled - */ -static inline bool ice_is_lag_dis(struct ice_lag *lag) -{ - return !!(lag->dis_lag); -} #endif /* _ICE_LAG_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 387bb9cbafbe..3de9556b89ac 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2707,8 +2707,6 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_vsi_cfg_params *params) return vsi; err_vsi_cfg: - if (params->type == ICE_VSI_VF) - ice_enable_lag(pf->lag); ice_vsi_free(vsi); return NULL; diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 80c643fb9f2f..a7e7debb1428 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -979,8 +979,6 @@ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs) if (!num_vfs) { if (!pci_vfs_assigned(pdev)) { ice_free_vfs(pf); - if (pf->lag) - ice_enable_lag(pf->lag); return 0; } @@ -992,8 +990,6 @@ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs) if (err) return err; - if (pf->lag) - ice_disable_lag(pf->lag); return num_vfs; } -- cgit v1.2.3 From ebdf098a0e1be8081dc5c92948f9a12eebf53638 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 11 May 2023 09:43:06 -0700 Subject: MAINTAINERS: update Intel Ethernet links Freshen up some links, and remove the non-kernel related Sourceforge link. Signed-off-by: Jesse Brandeburg Signed-off-by: Tony Nguyen --- MAINTAINERS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a83be7caa468..041e3e8e8d52 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10336,9 +10336,8 @@ M: Jesse Brandeburg M: Tony Nguyen L: intel-wired-lan@lists.osuosl.org (moderated for non-subscribers) S: Supported -W: http://www.intel.com/support/feedback.htm -W: http://e1000.sourceforge.net/ -Q: http://patchwork.ozlabs.org/project/intel-wired-lan/list/ +W: https://www.intel.com/content/www/us/en/support.html +Q: https://patchwork.ozlabs.org/project/intel-wired-lan/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue.git F: Documentation/networking/device_drivers/ethernet/intel/ -- cgit v1.2.3 From fe6559fab328972a2c8687d322fa54ab6d08f209 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 15 May 2023 13:23:46 -0600 Subject: net: libwx: Replace zero-length array with flexible-array member Zero-length arrays as fake flexible arrays are deprecated, and we are moving towards adopting C99 flexible-array members instead. Transform zero-length array into flexible-array member in struct wx_q_vector. Link: https://github.com/KSPP/linux/issues/21 Link: https://github.com/KSPP/linux/issues/286 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Signed-off-by: Gustavo A. R. Silva Reviewed-by: Simon Horman Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/ZGKGwtsobVZecWa4@work Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 32f952d93009..cbe7f184b50e 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -598,7 +598,7 @@ struct wx_q_vector { char name[IFNAMSIZ + 17]; /* for dynamic allocation of rings associated with this q_vector */ - struct wx_ring ring[0] ____cacheline_internodealigned_in_smp; + struct wx_ring ring[] ____cacheline_internodealigned_in_smp; }; enum wx_isb_idx { -- cgit v1.2.3 From b1cf7a5615157e958c2bdac9aa981676c07a10d9 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 15 May 2023 13:22:48 -0600 Subject: mlxfw: Replace zero-length array with DECLARE_FLEX_ARRAY() helper Zero-length arrays are deprecated and we are moving towards adopting C99 flexible-array members, instead. So, replace zero-length arrays declarations alone in structs with the new DECLARE_FLEX_ARRAY() helper macro. This helper allows for flexible-array members alone in structs. Link: https://github.com/KSPP/linux/issues/193 Link: https://github.com/KSPP/linux/issues/285 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Signed-off-by: Gustavo A. R. Silva Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/ZGKGiBxP0zHo6XSK@work Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h index b001e5258091..47f6cc0401c3 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_mfa2_format.h @@ -44,7 +44,7 @@ MLXFW_MFA2_TLV(multi, struct mlxfw_mfa2_tlv_multi, MLXFW_MFA2_TLV_MULTI_PART); struct mlxfw_mfa2_tlv_psid { - u8 psid[0]; + DECLARE_FLEX_ARRAY(u8, psid); } __packed; MLXFW_MFA2_TLV_VARSIZE(psid, struct mlxfw_mfa2_tlv_psid, -- cgit v1.2.3 From b50a8b0d57ab1ef11492171e98a030f48682eac3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 May 2023 18:04:16 +0200 Subject: net: openvswitch: Use struct_size() Use struct_size() instead of hand writing it. This is less verbose and more informative. Signed-off-by: Christophe JAILLET Acked-by: Eelco Chaudron Link: https://lore.kernel.org/r/e7746fbbd62371d286081d5266e88bbe8d3fe9f0.1683388991.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jakub Kicinski --- net/openvswitch/meter.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/openvswitch/meter.c b/net/openvswitch/meter.c index f2698d2316df..c4ebf810e4b1 100644 --- a/net/openvswitch/meter.c +++ b/net/openvswitch/meter.c @@ -69,9 +69,7 @@ static struct dp_meter_instance *dp_meter_instance_alloc(const u32 size) { struct dp_meter_instance *ti; - ti = kvzalloc(sizeof(*ti) + - sizeof(struct dp_meter *) * size, - GFP_KERNEL); + ti = kvzalloc(struct_size(ti, dp_meters, size), GFP_KERNEL); if (!ti) return NULL; -- cgit v1.2.3 From a4878eeae39048e6abe85891c714b49dc13fc08c Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 12 May 2023 14:19:47 +0200 Subject: netfilter: nf_tables: relax set/map validation checks Its currently not allowed to perform queries on a map, for example: table t { map m { typeof ip saddr : meta mark .. chain c { ip saddr @m counter will fail, because kernel requires that userspace provides a destination register when the referenced set is a map. However, internally there is no real distinction between sets and maps, maps are just sets where each key is associated with a value. Relax this so that maps can be used just like sets. This allows to have rules that query if a given key exists without making use of the associated value. This also permits != checks which don't work for map lookups. When no destination reg is given for a map, then permit this for named maps. Data and dump paths need to be updated to consider priv->dreg_set instead of the 'set-is-a-map' check. Checks in reduce and validate callbacks are not changed, this can be relaxed later if a need arises. Signed-off-by: Florian Westphal --- net/netfilter/nft_lookup.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index 03ef4fdaa460..29ac48cdd6db 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c @@ -19,6 +19,7 @@ struct nft_lookup { struct nft_set *set; u8 sreg; u8 dreg; + bool dreg_set; bool invert; struct nft_set_binding binding; }; @@ -75,7 +76,7 @@ void nft_lookup_eval(const struct nft_expr *expr, } if (ext) { - if (set->flags & NFT_SET_MAP) + if (priv->dreg_set) nft_data_copy(®s->data[priv->dreg], nft_set_ext_data(ext), set->dlen); @@ -122,11 +123,8 @@ static int nft_lookup_init(const struct nft_ctx *ctx, if (flags & ~NFT_LOOKUP_F_INV) return -EINVAL; - if (flags & NFT_LOOKUP_F_INV) { - if (set->flags & NFT_SET_MAP) - return -EINVAL; + if (flags & NFT_LOOKUP_F_INV) priv->invert = true; - } } if (tb[NFTA_LOOKUP_DREG] != NULL) { @@ -140,8 +138,17 @@ static int nft_lookup_init(const struct nft_ctx *ctx, set->dlen); if (err < 0) return err; - } else if (set->flags & NFT_SET_MAP) - return -EINVAL; + priv->dreg_set = true; + } else if (set->flags & NFT_SET_MAP) { + /* Map given, but user asks for lookup only (i.e. to + * ignore value assoicated with key). + * + * This makes no sense for anonymous maps since they are + * scoped to the rule, but for named sets this can be useful. + */ + if (set->flags & NFT_SET_ANONYMOUS) + return -EINVAL; + } priv->binding.flags = set->flags & NFT_SET_MAP; @@ -188,7 +195,7 @@ static int nft_lookup_dump(struct sk_buff *skb, goto nla_put_failure; if (nft_dump_register(skb, NFTA_LOOKUP_SREG, priv->sreg)) goto nla_put_failure; - if (priv->set->flags & NFT_SET_MAP) + if (priv->dreg_set) if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg)) goto nla_put_failure; if (nla_put_be32(skb, NFTA_LOOKUP_FLAGS, htonl(flags))) -- cgit v1.2.3 From d4b7f29eb85c93893bc27388b37709efbc3c9a0e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 11 May 2023 22:45:35 +0200 Subject: netfilter: nf_tables: always increment set element count At this time, set->nelems counter only increments when the set has a maximum size. All set elements decrement the counter unconditionally, this is confusing. Increment the counter unconditionally to make this symmetrical. This would also allow changing the set maximum size after set creation in a later patch. Signed-off-by: Florian Westphal --- net/netfilter/nf_tables_api.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 59fb8320ab4d..7a61de80a8d1 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6541,10 +6541,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, goto err_element_clash; } - if (!(flags & NFT_SET_ELEM_CATCHALL) && set->size && - !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) { - err = -ENFILE; - goto err_set_full; + if (!(flags & NFT_SET_ELEM_CATCHALL)) { + unsigned int max = set->size ? set->size + set->ndeact : UINT_MAX; + + if (!atomic_add_unless(&set->nelems, 1, max)) { + err = -ENFILE; + goto err_set_full; + } } nft_trans_elem(trans) = elem; -- cgit v1.2.3 From b9f9a485fb0eb80b0e2b90410b28cbb9b0e85687 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Tue, 9 May 2023 22:19:45 +0100 Subject: netfilter: nft_exthdr: add boolean DCCP option matching The xt_dccp iptables module supports the matching of DCCP packets based on the presence or absence of DCCP options. Extend nft_exthdr to add this functionality to nftables. Link: https://bugzilla.netfilter.org/show_bug.cgi?id=930 Signed-off-by: Jeremy Sowden Signed-off-by: Florian Westphal --- include/uapi/linux/netfilter/nf_tables.h | 2 + net/netfilter/nft_exthdr.c | 106 +++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index c4d4d8e42dc8..e059dc2644df 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -859,12 +859,14 @@ enum nft_exthdr_flags { * @NFT_EXTHDR_OP_TCP: match against tcp options * @NFT_EXTHDR_OP_IPV4: match against ipv4 options * @NFT_EXTHDR_OP_SCTP: match against sctp chunks + * @NFT_EXTHDR_OP_DCCP: match against dccp otions */ enum nft_exthdr_op { NFT_EXTHDR_OP_IPV6, NFT_EXTHDR_OP_TCPOPT, NFT_EXTHDR_OP_IPV4, NFT_EXTHDR_OP_SCTP, + NFT_EXTHDR_OP_DCCP, __NFT_EXTHDR_OP_MAX }; #define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1) diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c index a54a7f772cec..671474e59817 100644 --- a/net/netfilter/nft_exthdr.c +++ b/net/netfilter/nft_exthdr.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -406,6 +407,82 @@ err: regs->verdict.code = NFT_BREAK; } +static void nft_exthdr_dccp_eval(const struct nft_expr *expr, + struct nft_regs *regs, + const struct nft_pktinfo *pkt) +{ + struct nft_exthdr *priv = nft_expr_priv(expr); + unsigned int thoff, dataoff, optoff, optlen, i; + u32 *dest = ®s->data[priv->dreg]; + const struct dccp_hdr *dh; + struct dccp_hdr _dh; + + if (pkt->tprot != IPPROTO_DCCP || pkt->fragoff) + goto err; + + thoff = nft_thoff(pkt); + + dh = skb_header_pointer(pkt->skb, thoff, sizeof(_dh), &_dh); + if (!dh) + goto err; + + dataoff = dh->dccph_doff * sizeof(u32); + optoff = __dccp_hdr_len(dh); + if (dataoff <= optoff) + goto err; + + optlen = dataoff - optoff; + + for (i = 0; i < optlen; ) { + /* Options 0 (DCCPO_PADDING) - 31 (DCCPO_MAX_RESERVED) are 1B in + * the length; the remaining options are at least 2B long. In + * all cases, the first byte contains the option type. In + * multi-byte options, the second byte contains the option + * length, which must be at least two: 1 for the type plus 1 for + * the length plus 0-253 for any following option data. We + * aren't interested in the option data, only the type and the + * length, so we don't need to read more than two bytes at a + * time. + */ + unsigned int buflen = optlen - i; + u8 buf[2], *bufp; + u8 type, len; + + if (buflen > sizeof(buf)) + buflen = sizeof(buf); + + bufp = skb_header_pointer(pkt->skb, thoff + optoff + i, buflen, + &buf); + if (!bufp) + goto err; + + type = bufp[0]; + + if (type == priv->type) { + *dest = 1; + return; + } + + if (type <= DCCPO_MAX_RESERVED) { + i++; + continue; + } + + if (buflen < 2) + goto err; + + len = bufp[1]; + + if (len < 2) + goto err; + + i += len; + } + +err: + *dest = 0; +} + static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = { [NFTA_EXTHDR_DREG] = { .type = NLA_U32 }, [NFTA_EXTHDR_TYPE] = { .type = NLA_U8 }, @@ -557,6 +634,22 @@ static int nft_exthdr_ipv4_init(const struct nft_ctx *ctx, return 0; } +static int nft_exthdr_dccp_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]) +{ + struct nft_exthdr *priv = nft_expr_priv(expr); + int err = nft_exthdr_init(ctx, expr, tb); + + if (err < 0) + return err; + + if (!(priv->flags & NFT_EXTHDR_F_PRESENT)) + return -EOPNOTSUPP; + + return 0; +} + static int nft_exthdr_dump_common(struct sk_buff *skb, const struct nft_exthdr *priv) { if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type)) @@ -686,6 +779,15 @@ static const struct nft_expr_ops nft_exthdr_sctp_ops = { .reduce = nft_exthdr_reduce, }; +static const struct nft_expr_ops nft_exthdr_dccp_ops = { + .type = &nft_exthdr_type, + .size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)), + .eval = nft_exthdr_dccp_eval, + .init = nft_exthdr_dccp_init, + .dump = nft_exthdr_dump, + .reduce = nft_exthdr_reduce, +}; + static const struct nft_expr_ops * nft_exthdr_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) @@ -720,6 +822,10 @@ nft_exthdr_select_ops(const struct nft_ctx *ctx, if (tb[NFTA_EXTHDR_DREG]) return &nft_exthdr_sctp_ops; break; + case NFT_EXTHDR_OP_DCCP: + if (tb[NFTA_EXTHDR_DREG]) + return &nft_exthdr_dccp_ops; + break; } return ERR_PTR(-EOPNOTSUPP); -- cgit v1.2.3 From 61e03e912da8212c3de2529054502e8388dfd484 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 8 May 2023 18:53:14 +0200 Subject: netfilter: Reorder fields in 'struct nf_conntrack_expect' Group some variables based on their sizes to reduce holes. On x86_64, this shrinks the size of 'struct nf_conntrack_expect' from 264 to 256 bytes. This structure deserve a dedicated cache, so reducing its size looks nice. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Florian Westphal --- include/net/netfilter/nf_conntrack_expect.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 0855b60fba17..cf0d81be5a96 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -26,6 +26,15 @@ struct nf_conntrack_expect { struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple_mask mask; + /* Usage count. */ + refcount_t use; + + /* Flags */ + unsigned int flags; + + /* Expectation class */ + unsigned int class; + /* Function to call after setup and insertion */ void (*expectfn)(struct nf_conn *new, struct nf_conntrack_expect *this); @@ -39,15 +48,6 @@ struct nf_conntrack_expect { /* Timer function; deletes the expectation. */ struct timer_list timeout; - /* Usage count. */ - refcount_t use; - - /* Flags */ - unsigned int flags; - - /* Expectation class */ - unsigned int class; - #if IS_ENABLED(CONFIG_NF_NAT) union nf_inet_addr saved_addr; /* This is the original per-proto part, used to map the -- cgit v1.2.3 From a2a0ffb0846895923991aa87e022dc228d53c125 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 5 May 2023 23:26:34 +0200 Subject: netfilter: nft_set_pipapo: Use struct_size() Use struct_size() instead of hand writing it. This is less verbose and more informative. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Florian Westphal --- net/netfilter/nft_set_pipapo.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 06d46d182634..34c684e121d3 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -1274,8 +1274,7 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old) struct nft_pipapo_match *new; int i; - new = kmalloc(sizeof(*new) + sizeof(*dst) * old->field_count, - GFP_KERNEL); + new = kmalloc(struct_size(new, f, old->field_count), GFP_KERNEL); if (!new) return ERR_PTR(-ENOMEM); @@ -2059,8 +2058,7 @@ static int nft_pipapo_init(const struct nft_set *set, if (field_count > NFT_PIPAPO_MAX_FIELDS) return -EINVAL; - m = kmalloc(sizeof(*priv->match) + sizeof(*f) * field_count, - GFP_KERNEL); + m = kmalloc(struct_size(m, f, field_count), GFP_KERNEL); if (!m) return -ENOMEM; -- cgit v1.2.3 From d671fd82eaa9bceedd48ea2b0679a9a6bbcd6532 Mon Sep 17 00:00:00 2001 From: Faicker Mo Date: Sun, 23 Apr 2023 10:29:57 +0800 Subject: netfilter: conntrack: allow insertion clash of gre protocol NVGRE tunnel is used in the VM-to-VM communications. The VM packets are encapsulated in NVGRE and sent from the host. For NVGRE there are two tuples(outer sip and outer dip) in the host conntrack item. Insertion clashes are more likely to happen if the concurrent connections are sent from the VM. Signed-off-by: Faicker Mo Signed-off-by: Florian Westphal --- net/netfilter/nf_conntrack_proto_gre.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 728eeb0aea87..ad6f0ca40cd2 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -296,6 +296,7 @@ void nf_conntrack_gre_init_net(struct net *net) /* protocol helper struct */ const struct nf_conntrack_l4proto nf_conntrack_l4proto_gre = { .l4proto = IPPROTO_GRE, + .allow_clash = true, #ifdef CONFIG_NF_CONNTRACK_PROCFS .print_conntrack = gre_print_conntrack, #endif -- cgit v1.2.3 From fa502c86566680ac62bc28ec883a069bf7a2aa5e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 May 2023 07:35:33 +0200 Subject: netfilter: flowtable: simplify route logic Grab reference to dst from skbuff earlier to simplify route caching. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- include/net/netfilter/nf_flow_table.h | 4 ++-- net/netfilter/nf_flow_table_core.c | 24 +++--------------------- net/netfilter/nft_flow_offload.c | 12 ++++++++---- 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index ebb28ec5b6fa..546fc4a9b939 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -263,8 +263,8 @@ nf_flow_table_offload_del_cb(struct nf_flowtable *flow_table, up_write(&flow_table->flow_block_lock); } -int flow_offload_route_init(struct flow_offload *flow, - const struct nf_flow_route *route); +void flow_offload_route_init(struct flow_offload *flow, + const struct nf_flow_route *route); int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow); void flow_offload_refresh(struct nf_flowtable *flow_table, diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 04bd0ed4d2ae..b46dd897f2c5 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -125,9 +125,6 @@ static int flow_offload_fill_route(struct flow_offload *flow, break; case FLOW_OFFLOAD_XMIT_XFRM: case FLOW_OFFLOAD_XMIT_NEIGH: - if (!dst_hold_safe(route->tuple[dir].dst)) - return -1; - flow_tuple->dst_cache = dst; flow_tuple->dst_cookie = flow_offload_dst_cookie(flow_tuple); break; @@ -148,27 +145,12 @@ static void nft_flow_dst_release(struct flow_offload *flow, dst_release(flow->tuplehash[dir].tuple.dst_cache); } -int flow_offload_route_init(struct flow_offload *flow, +void flow_offload_route_init(struct flow_offload *flow, const struct nf_flow_route *route) { - int err; - - err = flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_ORIGINAL); - if (err < 0) - return err; - - err = flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_REPLY); - if (err < 0) - goto err_route_reply; - + flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_ORIGINAL); + flow_offload_fill_route(flow, route, FLOW_OFFLOAD_DIR_REPLY); flow->type = NF_FLOW_OFFLOAD_ROUTE; - - return 0; - -err_route_reply: - nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_ORIGINAL); - - return err; } EXPORT_SYMBOL_GPL(flow_offload_route_init); diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index e860d8fe0e5e..5ef9146e74ad 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c @@ -250,9 +250,14 @@ static int nft_flow_route(const struct nft_pktinfo *pkt, break; } + if (!dst_hold_safe(this_dst)) + return -ENOENT; + nf_route(nft_net(pkt), &other_dst, &fl, false, nft_pf(pkt)); - if (!other_dst) + if (!other_dst) { + dst_release(this_dst); return -ENOENT; + } nft_default_forward_path(route, this_dst, dir); nft_default_forward_path(route, other_dst, !dir); @@ -349,8 +354,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, if (!flow) goto err_flow_alloc; - if (flow_offload_route_init(flow, &route) < 0) - goto err_flow_add; + flow_offload_route_init(flow, &route); if (tcph) { ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; @@ -361,12 +365,12 @@ static void nft_flow_offload_eval(const struct nft_expr *expr, if (ret < 0) goto err_flow_add; - dst_release(route.tuple[!dir].dst); return; err_flow_add: flow_offload_free(flow); err_flow_alloc: + dst_release(route.tuple[dir].dst); dst_release(route.tuple[!dir].dst); err_flow_route: clear_bit(IPS_OFFLOAD_BIT, &ct->status); -- cgit v1.2.3 From a10fa0b489d627911895b64c6530636748dd7911 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 May 2023 07:35:34 +0200 Subject: netfilter: flowtable: split IPv4 datapath in helper functions Add context structure and helper functions to look up for a matching IPv4 entry in the flowtable and to forward packets. No functional changes are intended. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- net/netfilter/nf_flow_table_ip.c | 119 +++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 42 deletions(-) diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index 19efba1e51ef..3fb476167d1d 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -163,38 +163,43 @@ static void nf_flow_tuple_encap(struct sk_buff *skb, } } -static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev, - struct flow_offload_tuple *tuple, u32 *hdrsize, - u32 offset) +struct nf_flowtable_ctx { + const struct net_device *in; + u32 offset; + u32 hdrsize; +}; + +static int nf_flow_tuple_ip(struct nf_flowtable_ctx *ctx, struct sk_buff *skb, + struct flow_offload_tuple *tuple) { struct flow_ports *ports; unsigned int thoff; struct iphdr *iph; u8 ipproto; - if (!pskb_may_pull(skb, sizeof(*iph) + offset)) + if (!pskb_may_pull(skb, sizeof(*iph) + ctx->offset)) return -1; - iph = (struct iphdr *)(skb_network_header(skb) + offset); + iph = (struct iphdr *)(skb_network_header(skb) + ctx->offset); thoff = (iph->ihl * 4); if (ip_is_fragment(iph) || unlikely(ip_has_options(thoff))) return -1; - thoff += offset; + thoff += ctx->offset; ipproto = iph->protocol; switch (ipproto) { case IPPROTO_TCP: - *hdrsize = sizeof(struct tcphdr); + ctx->hdrsize = sizeof(struct tcphdr); break; case IPPROTO_UDP: - *hdrsize = sizeof(struct udphdr); + ctx->hdrsize = sizeof(struct udphdr); break; #ifdef CONFIG_NF_CT_PROTO_GRE case IPPROTO_GRE: - *hdrsize = sizeof(struct gre_base_hdr); + ctx->hdrsize = sizeof(struct gre_base_hdr); break; #endif default: @@ -204,7 +209,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev, if (iph->ttl <= 1) return -1; - if (!pskb_may_pull(skb, thoff + *hdrsize)) + if (!pskb_may_pull(skb, thoff + ctx->hdrsize)) return -1; switch (ipproto) { @@ -224,13 +229,13 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev, } } - iph = (struct iphdr *)(skb_network_header(skb) + offset); + iph = (struct iphdr *)(skb_network_header(skb) + ctx->offset); tuple->src_v4.s_addr = iph->saddr; tuple->dst_v4.s_addr = iph->daddr; tuple->l3proto = AF_INET; tuple->l4proto = ipproto; - tuple->iifidx = dev->ifindex; + tuple->iifidx = ctx->in->ifindex; nf_flow_tuple_encap(skb, tuple); return 0; @@ -336,58 +341,56 @@ static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb, return NF_STOLEN; } -unsigned int -nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, - const struct nf_hook_state *state) +static struct flow_offload_tuple_rhash * +nf_flow_offload_lookup(struct nf_flowtable_ctx *ctx, + struct nf_flowtable *flow_table, struct sk_buff *skb) { - struct flow_offload_tuple_rhash *tuplehash; - struct nf_flowtable *flow_table = priv; struct flow_offload_tuple tuple = {}; - enum flow_offload_tuple_dir dir; - struct flow_offload *flow; - struct net_device *outdev; - u32 hdrsize, offset = 0; - unsigned int thoff, mtu; - struct rtable *rt; - struct iphdr *iph; - __be32 nexthop; - int ret; if (skb->protocol != htons(ETH_P_IP) && - !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IP), &offset)) - return NF_ACCEPT; + !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IP), &ctx->offset)) + return NULL; - if (nf_flow_tuple_ip(skb, state->in, &tuple, &hdrsize, offset) < 0) - return NF_ACCEPT; + if (nf_flow_tuple_ip(ctx, skb, &tuple) < 0) + return NULL; - tuplehash = flow_offload_lookup(flow_table, &tuple); - if (tuplehash == NULL) - return NF_ACCEPT; + return flow_offload_lookup(flow_table, &tuple); +} + +static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx, + struct nf_flowtable *flow_table, + struct flow_offload_tuple_rhash *tuplehash, + struct sk_buff *skb) +{ + enum flow_offload_tuple_dir dir; + struct flow_offload *flow; + unsigned int thoff, mtu; + struct iphdr *iph; dir = tuplehash->tuple.dir; flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); - mtu = flow->tuplehash[dir].tuple.mtu + offset; + mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset; if (unlikely(nf_flow_exceeds_mtu(skb, mtu))) - return NF_ACCEPT; + return 0; - iph = (struct iphdr *)(skb_network_header(skb) + offset); - thoff = (iph->ihl * 4) + offset; + iph = (struct iphdr *)(skb_network_header(skb) + ctx->offset); + thoff = (iph->ihl * 4) + ctx->offset; if (nf_flow_state_check(flow, iph->protocol, skb, thoff)) - return NF_ACCEPT; + return 0; if (!nf_flow_dst_check(&tuplehash->tuple)) { flow_offload_teardown(flow); - return NF_ACCEPT; + return 0; } - if (skb_try_make_writable(skb, thoff + hdrsize)) - return NF_DROP; + if (skb_try_make_writable(skb, thoff + ctx->hdrsize)) + return -1; flow_offload_refresh(flow_table, flow); nf_flow_encap_pop(skb, tuplehash); - thoff -= offset; + thoff -= ctx->offset; iph = ip_hdr(skb); nf_flow_nat_ip(flow, skb, thoff, dir, iph); @@ -398,6 +401,35 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, if (flow_table->flags & NF_FLOWTABLE_COUNTER) nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len); + return 1; +} + +unsigned int +nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct flow_offload_tuple_rhash *tuplehash; + struct nf_flowtable *flow_table = priv; + enum flow_offload_tuple_dir dir; + struct nf_flowtable_ctx ctx = { + .in = state->in, + }; + struct flow_offload *flow; + struct net_device *outdev; + struct rtable *rt; + __be32 nexthop; + int ret; + + tuplehash = nf_flow_offload_lookup(&ctx, flow_table, skb); + if (!tuplehash) + return NF_ACCEPT; + + ret = nf_flow_offload_forward(&ctx, flow_table, tuplehash, skb); + if (ret < 0) + return NF_DROP; + else if (ret == 0) + return NF_ACCEPT; + if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) { rt = (struct rtable *)tuplehash->tuple.dst_cache; memset(skb->cb, 0, sizeof(struct inet_skb_parm)); @@ -406,6 +438,9 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb, return nf_flow_xmit_xfrm(skb, state, &rt->dst); } + dir = tuplehash->tuple.dir; + flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); + switch (tuplehash->tuple.xmit_type) { case FLOW_OFFLOAD_XMIT_NEIGH: rt = (struct rtable *)tuplehash->tuple.dst_cache; -- cgit v1.2.3 From e05b5362166b18a224c30502e81416e4d622d3e4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 11 May 2023 07:35:35 +0200 Subject: netfilter: flowtable: split IPv6 datapath in helper functions Add context structure and helper functions to look up for a matching IPv6 entry in the flowtable and to forward packets. No functional changes are intended. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Florian Westphal --- net/netfilter/nf_flow_table_ip.c | 112 +++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 41 deletions(-) diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index 3fb476167d1d..d248763917ad 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -570,32 +570,31 @@ static void nf_flow_nat_ipv6(const struct flow_offload *flow, } } -static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, - struct flow_offload_tuple *tuple, u32 *hdrsize, - u32 offset) +static int nf_flow_tuple_ipv6(struct nf_flowtable_ctx *ctx, struct sk_buff *skb, + struct flow_offload_tuple *tuple) { struct flow_ports *ports; struct ipv6hdr *ip6h; unsigned int thoff; u8 nexthdr; - thoff = sizeof(*ip6h) + offset; + thoff = sizeof(*ip6h) + ctx->offset; if (!pskb_may_pull(skb, thoff)) return -1; - ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset); + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + ctx->offset); nexthdr = ip6h->nexthdr; switch (nexthdr) { case IPPROTO_TCP: - *hdrsize = sizeof(struct tcphdr); + ctx->hdrsize = sizeof(struct tcphdr); break; case IPPROTO_UDP: - *hdrsize = sizeof(struct udphdr); + ctx->hdrsize = sizeof(struct udphdr); break; #ifdef CONFIG_NF_CT_PROTO_GRE case IPPROTO_GRE: - *hdrsize = sizeof(struct gre_base_hdr); + ctx->hdrsize = sizeof(struct gre_base_hdr); break; #endif default: @@ -605,7 +604,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, if (ip6h->hop_limit <= 1) return -1; - if (!pskb_may_pull(skb, thoff + *hdrsize)) + if (!pskb_may_pull(skb, thoff + ctx->hdrsize)) return -1; switch (nexthdr) { @@ -625,65 +624,47 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev, } } - ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset); + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + ctx->offset); tuple->src_v6 = ip6h->saddr; tuple->dst_v6 = ip6h->daddr; tuple->l3proto = AF_INET6; tuple->l4proto = nexthdr; - tuple->iifidx = dev->ifindex; + tuple->iifidx = ctx->in->ifindex; nf_flow_tuple_encap(skb, tuple); return 0; } -unsigned int -nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, - const struct nf_hook_state *state) +static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx, + struct nf_flowtable *flow_table, + struct flow_offload_tuple_rhash *tuplehash, + struct sk_buff *skb) { - struct flow_offload_tuple_rhash *tuplehash; - struct nf_flowtable *flow_table = priv; - struct flow_offload_tuple tuple = {}; enum flow_offload_tuple_dir dir; - const struct in6_addr *nexthop; struct flow_offload *flow; - struct net_device *outdev; unsigned int thoff, mtu; - u32 hdrsize, offset = 0; struct ipv6hdr *ip6h; - struct rt6_info *rt; - int ret; - - if (skb->protocol != htons(ETH_P_IPV6) && - !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IPV6), &offset)) - return NF_ACCEPT; - - if (nf_flow_tuple_ipv6(skb, state->in, &tuple, &hdrsize, offset) < 0) - return NF_ACCEPT; - - tuplehash = flow_offload_lookup(flow_table, &tuple); - if (tuplehash == NULL) - return NF_ACCEPT; dir = tuplehash->tuple.dir; flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); - mtu = flow->tuplehash[dir].tuple.mtu + offset; + mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset; if (unlikely(nf_flow_exceeds_mtu(skb, mtu))) - return NF_ACCEPT; + return 0; - ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset); - thoff = sizeof(*ip6h) + offset; + ip6h = (struct ipv6hdr *)(skb_network_header(skb) + ctx->offset); + thoff = sizeof(*ip6h) + ctx->offset; if (nf_flow_state_check(flow, ip6h->nexthdr, skb, thoff)) - return NF_ACCEPT; + return 0; if (!nf_flow_dst_check(&tuplehash->tuple)) { flow_offload_teardown(flow); - return NF_ACCEPT; + return 0; } - if (skb_try_make_writable(skb, thoff + hdrsize)) - return NF_DROP; + if (skb_try_make_writable(skb, thoff + ctx->hdrsize)) + return -1; flow_offload_refresh(flow_table, flow); @@ -698,6 +679,52 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, if (flow_table->flags & NF_FLOWTABLE_COUNTER) nf_ct_acct_update(flow->ct, tuplehash->tuple.dir, skb->len); + return 1; +} + +static struct flow_offload_tuple_rhash * +nf_flow_offload_ipv6_lookup(struct nf_flowtable_ctx *ctx, + struct nf_flowtable *flow_table, + struct sk_buff *skb) +{ + struct flow_offload_tuple tuple = {}; + + if (skb->protocol != htons(ETH_P_IPV6) && + !nf_flow_skb_encap_protocol(skb, htons(ETH_P_IPV6), &ctx->offset)) + return NULL; + + if (nf_flow_tuple_ipv6(ctx, skb, &tuple) < 0) + return NULL; + + return flow_offload_lookup(flow_table, &tuple); +} + +unsigned int +nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct flow_offload_tuple_rhash *tuplehash; + struct nf_flowtable *flow_table = priv; + enum flow_offload_tuple_dir dir; + struct nf_flowtable_ctx ctx = { + .in = state->in, + }; + const struct in6_addr *nexthop; + struct flow_offload *flow; + struct net_device *outdev; + struct rt6_info *rt; + int ret; + + tuplehash = nf_flow_offload_ipv6_lookup(&ctx, flow_table, skb); + if (tuplehash == NULL) + return NF_ACCEPT; + + ret = nf_flow_offload_ipv6_forward(&ctx, flow_table, tuplehash, skb); + if (ret < 0) + return NF_DROP; + else if (ret == 0) + return NF_ACCEPT; + if (unlikely(tuplehash->tuple.xmit_type == FLOW_OFFLOAD_XMIT_XFRM)) { rt = (struct rt6_info *)tuplehash->tuple.dst_cache; memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); @@ -706,6 +733,9 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, return nf_flow_xmit_xfrm(skb, state, &rt->dst); } + dir = tuplehash->tuple.dir; + flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); + switch (tuplehash->tuple.xmit_type) { case FLOW_OFFLOAD_XMIT_NEIGH: rt = (struct rt6_info *)tuplehash->tuple.dst_cache; -- cgit v1.2.3 From 1fd22211354a94cb5afa7d7dab1a8e2c5ec1eed8 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 16 May 2023 22:14:02 +0200 Subject: net: lan966x: Add registers to configure PCP, DEI, DSCP Add the registers that are needed to configure the PCP, DEI and DSCP of the switch both at ingress and also at egress. Reviewed-by: Daniel Machon Reviewed-by: Piotr Raczynski Signed-off-by: Horatiu Vultur Signed-off-by: Paolo Abeni --- .../net/ethernet/microchip/lan966x/lan966x_regs.h | 132 +++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h index 222039180276..4b553927d2e0 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_regs.h @@ -283,6 +283,18 @@ enum lan966x_target { #define ANA_VLAN_CFG_VLAN_POP_CNT_GET(x)\ FIELD_GET(ANA_VLAN_CFG_VLAN_POP_CNT, x) +#define ANA_VLAN_CFG_VLAN_PCP GENMASK(15, 13) +#define ANA_VLAN_CFG_VLAN_PCP_SET(x)\ + FIELD_PREP(ANA_VLAN_CFG_VLAN_PCP, x) +#define ANA_VLAN_CFG_VLAN_PCP_GET(x)\ + FIELD_GET(ANA_VLAN_CFG_VLAN_PCP, x) + +#define ANA_VLAN_CFG_VLAN_DEI BIT(12) +#define ANA_VLAN_CFG_VLAN_DEI_SET(x)\ + FIELD_PREP(ANA_VLAN_CFG_VLAN_DEI, x) +#define ANA_VLAN_CFG_VLAN_DEI_GET(x)\ + FIELD_GET(ANA_VLAN_CFG_VLAN_DEI, x) + #define ANA_VLAN_CFG_VLAN_VID GENMASK(11, 0) #define ANA_VLAN_CFG_VLAN_VID_SET(x)\ FIELD_PREP(ANA_VLAN_CFG_VLAN_VID, x) @@ -316,6 +328,39 @@ enum lan966x_target { #define ANA_DROP_CFG_DROP_MC_SMAC_ENA_GET(x)\ FIELD_GET(ANA_DROP_CFG_DROP_MC_SMAC_ENA, x) +/* ANA:PORT:QOS_CFG */ +#define ANA_QOS_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 8, 0, 1, 4) + +#define ANA_QOS_CFG_DP_DEFAULT_VAL BIT(8) +#define ANA_QOS_CFG_DP_DEFAULT_VAL_SET(x)\ + FIELD_PREP(ANA_QOS_CFG_DP_DEFAULT_VAL, x) +#define ANA_QOS_CFG_DP_DEFAULT_VAL_GET(x)\ + FIELD_GET(ANA_QOS_CFG_DP_DEFAULT_VAL, x) + +#define ANA_QOS_CFG_QOS_DEFAULT_VAL GENMASK(7, 5) +#define ANA_QOS_CFG_QOS_DEFAULT_VAL_SET(x)\ + FIELD_PREP(ANA_QOS_CFG_QOS_DEFAULT_VAL, x) +#define ANA_QOS_CFG_QOS_DEFAULT_VAL_GET(x)\ + FIELD_GET(ANA_QOS_CFG_QOS_DEFAULT_VAL, x) + +#define ANA_QOS_CFG_QOS_DSCP_ENA BIT(4) +#define ANA_QOS_CFG_QOS_DSCP_ENA_SET(x)\ + FIELD_PREP(ANA_QOS_CFG_QOS_DSCP_ENA, x) +#define ANA_QOS_CFG_QOS_DSCP_ENA_GET(x)\ + FIELD_GET(ANA_QOS_CFG_QOS_DSCP_ENA, x) + +#define ANA_QOS_CFG_QOS_PCP_ENA BIT(3) +#define ANA_QOS_CFG_QOS_PCP_ENA_SET(x)\ + FIELD_PREP(ANA_QOS_CFG_QOS_PCP_ENA, x) +#define ANA_QOS_CFG_QOS_PCP_ENA_GET(x)\ + FIELD_GET(ANA_QOS_CFG_QOS_PCP_ENA, x) + +#define ANA_QOS_CFG_DSCP_REWR_CFG GENMASK(1, 0) +#define ANA_QOS_CFG_DSCP_REWR_CFG_SET(x)\ + FIELD_PREP(ANA_QOS_CFG_DSCP_REWR_CFG, x) +#define ANA_QOS_CFG_DSCP_REWR_CFG_GET(x)\ + FIELD_GET(ANA_QOS_CFG_DSCP_REWR_CFG, x) + /* ANA:PORT:VCAP_CFG */ #define ANA_VCAP_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 12, 0, 1, 4) @@ -415,6 +460,21 @@ enum lan966x_target { #define ANA_VCAP_S2_CFG_OAM_DIS_GET(x)\ FIELD_GET(ANA_VCAP_S2_CFG_OAM_DIS, x) +/* ANA:PORT:QOS_PCP_DEI_MAP_CFG */ +#define ANA_PCP_DEI_CFG(g, r) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 32, r, 16, 4) + +#define ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL BIT(3) +#define ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL_SET(x)\ + FIELD_PREP(ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL, x) +#define ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL_GET(x)\ + FIELD_GET(ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL, x) + +#define ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL GENMASK(2, 0) +#define ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL_SET(x)\ + FIELD_PREP(ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL, x) +#define ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL_GET(x)\ + FIELD_GET(ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL, x) + /* ANA:PORT:CPU_FWD_CFG */ #define ANA_CPU_FWD_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 96, 0, 1, 4) @@ -478,6 +538,15 @@ enum lan966x_target { #define ANA_PORT_CFG_PORTID_VAL_GET(x)\ FIELD_GET(ANA_PORT_CFG_PORTID_VAL, x) +/* ANA:COMMON:DSCP_REWR_CFG */ +#define ANA_DSCP_REWR_CFG(r) __REG(TARGET_ANA, 0, 1, 31232, 0, 1, 552, 332, r, 16, 4) + +#define ANA_DSCP_REWR_CFG_DSCP_QOS_REWR_VAL GENMASK(5, 0) +#define ANA_DSCP_REWR_CFG_DSCP_QOS_REWR_VAL_SET(x)\ + FIELD_PREP(ANA_DSCP_REWR_CFG_DSCP_QOS_REWR_VAL, x) +#define ANA_DSCP_REWR_CFG_DSCP_QOS_REWR_VAL_GET(x)\ + FIELD_GET(ANA_DSCP_REWR_CFG_DSCP_QOS_REWR_VAL, x) + /* ANA:PORT:POL_CFG */ #define ANA_POL_CFG(g) __REG(TARGET_ANA, 0, 1, 28672, g, 9, 128, 116, 0, 1, 4) @@ -547,6 +616,33 @@ enum lan966x_target { #define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA_GET(x)\ FIELD_GET(ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA, x) +/* ANA:COMMON:DSCP_CFG */ +#define ANA_DSCP_CFG(r) __REG(TARGET_ANA, 0, 1, 31232, 0, 1, 552, 76, r, 64, 4) + +#define ANA_DSCP_CFG_DP_DSCP_VAL BIT(11) +#define ANA_DSCP_CFG_DP_DSCP_VAL_SET(x)\ + FIELD_PREP(ANA_DSCP_CFG_DP_DSCP_VAL, x) +#define ANA_DSCP_CFG_DP_DSCP_VAL_GET(x)\ + FIELD_GET(ANA_DSCP_CFG_DP_DSCP_VAL, x) + +#define ANA_DSCP_CFG_QOS_DSCP_VAL GENMASK(10, 8) +#define ANA_DSCP_CFG_QOS_DSCP_VAL_SET(x)\ + FIELD_PREP(ANA_DSCP_CFG_QOS_DSCP_VAL, x) +#define ANA_DSCP_CFG_QOS_DSCP_VAL_GET(x)\ + FIELD_GET(ANA_DSCP_CFG_QOS_DSCP_VAL, x) + +#define ANA_DSCP_CFG_DSCP_TRUST_ENA BIT(1) +#define ANA_DSCP_CFG_DSCP_TRUST_ENA_SET(x)\ + FIELD_PREP(ANA_DSCP_CFG_DSCP_TRUST_ENA, x) +#define ANA_DSCP_CFG_DSCP_TRUST_ENA_GET(x)\ + FIELD_GET(ANA_DSCP_CFG_DSCP_TRUST_ENA, x) + +#define ANA_DSCP_CFG_DSCP_REWR_ENA BIT(0) +#define ANA_DSCP_CFG_DSCP_REWR_ENA_SET(x)\ + FIELD_PREP(ANA_DSCP_CFG_DSCP_REWR_ENA, x) +#define ANA_DSCP_CFG_DSCP_REWR_ENA_GET(x)\ + FIELD_GET(ANA_DSCP_CFG_DSCP_REWR_ENA, x) + /* ANA:POL:POL_PIR_CFG */ #define ANA_POL_PIR_CFG(g) __REG(TARGET_ANA, 0, 1, 16384, g, 345, 32, 0, 0, 1, 4) @@ -1468,6 +1564,18 @@ enum lan966x_target { #define REW_TAG_CFG_TAG_TPID_CFG_GET(x)\ FIELD_GET(REW_TAG_CFG_TAG_TPID_CFG, x) +#define REW_TAG_CFG_TAG_PCP_CFG GENMASK(3, 2) +#define REW_TAG_CFG_TAG_PCP_CFG_SET(x)\ + FIELD_PREP(REW_TAG_CFG_TAG_PCP_CFG, x) +#define REW_TAG_CFG_TAG_PCP_CFG_GET(x)\ + FIELD_GET(REW_TAG_CFG_TAG_PCP_CFG, x) + +#define REW_TAG_CFG_TAG_DEI_CFG GENMASK(1, 0) +#define REW_TAG_CFG_TAG_DEI_CFG_SET(x)\ + FIELD_PREP(REW_TAG_CFG_TAG_DEI_CFG, x) +#define REW_TAG_CFG_TAG_DEI_CFG_GET(x)\ + FIELD_GET(REW_TAG_CFG_TAG_DEI_CFG, x) + /* REW:PORT:PORT_CFG */ #define REW_PORT_CFG(g) __REG(TARGET_REW, 0, 1, 0, g, 10, 128, 8, 0, 1, 4) @@ -1483,6 +1591,30 @@ enum lan966x_target { #define REW_PORT_CFG_NO_REWRITE_GET(x)\ FIELD_GET(REW_PORT_CFG_NO_REWRITE, x) +/* REW:PORT:DSCP_CFG */ +#define REW_DSCP_CFG(g) __REG(TARGET_REW, 0, 1, 0, g, 10, 128, 12, 0, 1, 4) + +#define REW_DSCP_CFG_DSCP_REWR_CFG GENMASK(1, 0) +#define REW_DSCP_CFG_DSCP_REWR_CFG_SET(x)\ + FIELD_PREP(REW_DSCP_CFG_DSCP_REWR_CFG, x) +#define REW_DSCP_CFG_DSCP_REWR_CFG_GET(x)\ + FIELD_GET(REW_DSCP_CFG_DSCP_REWR_CFG, x) + +/* REW:PORT:PCP_DEI_QOS_MAP_CFG */ +#define REW_PCP_DEI_CFG(g, r) __REG(TARGET_REW, 0, 1, 0, g, 10, 128, 16, r, 16, 4) + +#define REW_PCP_DEI_CFG_DEI_QOS_VAL BIT(3) +#define REW_PCP_DEI_CFG_DEI_QOS_VAL_SET(x)\ + FIELD_PREP(REW_PCP_DEI_CFG_DEI_QOS_VAL, x) +#define REW_PCP_DEI_CFG_DEI_QOS_VAL_GET(x)\ + FIELD_GET(REW_PCP_DEI_CFG_DEI_QOS_VAL, x) + +#define REW_PCP_DEI_CFG_PCP_QOS_VAL GENMASK(2, 0) +#define REW_PCP_DEI_CFG_PCP_QOS_VAL_SET(x)\ + FIELD_PREP(REW_PCP_DEI_CFG_PCP_QOS_VAL, x) +#define REW_PCP_DEI_CFG_PCP_QOS_VAL_GET(x)\ + FIELD_GET(REW_PCP_DEI_CFG_PCP_QOS_VAL, x) + /* REW:COMMON:STAT_CFG */ #define REW_STAT_CFG __REG(TARGET_REW, 0, 1, 3072, 0, 1, 528, 520, 0, 1, 4) -- cgit v1.2.3 From a83e463036ef491ba0f7b99f82a12c902a285245 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 16 May 2023 22:14:03 +0200 Subject: net: lan966x: Add support for offloading pcp table Add support for offloading pcp app entries. Lan966x has 8 priority queues per port and for each priority it also has a drop precedence. Reviewed-by: Daniel Machon Reviewed-by: Piotr Raczynski Signed-off-by: Horatiu Vultur Signed-off-by: Paolo Abeni --- drivers/net/ethernet/microchip/lan966x/Kconfig | 11 +++ drivers/net/ethernet/microchip/lan966x/Makefile | 1 + .../net/ethernet/microchip/lan966x/lan966x_dcb.c | 103 +++++++++++++++++++++ .../net/ethernet/microchip/lan966x/lan966x_main.c | 2 + .../net/ethernet/microchip/lan966x/lan966x_main.h | 25 +++++ .../net/ethernet/microchip/lan966x/lan966x_port.c | 30 ++++++ 6 files changed, 172 insertions(+) create mode 100644 drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c diff --git a/drivers/net/ethernet/microchip/lan966x/Kconfig b/drivers/net/ethernet/microchip/lan966x/Kconfig index 571e6d4da1e9..f9ebffc04eb8 100644 --- a/drivers/net/ethernet/microchip/lan966x/Kconfig +++ b/drivers/net/ethernet/microchip/lan966x/Kconfig @@ -10,3 +10,14 @@ config LAN966X_SWITCH select VCAP help This driver supports the Lan966x network switch device. + +config LAN966X_DCB + bool "Data Center Bridging (DCB) support" + depends on LAN966X_SWITCH && DCB + default y + help + Say Y here if you want to use Data Center Bridging (DCB) in the + driver. This can be used to assign priority to traffic, based on + DSCP and PCP. + + If unsure, set to Y. diff --git a/drivers/net/ethernet/microchip/lan966x/Makefile b/drivers/net/ethernet/microchip/lan966x/Makefile index 7b0cda4ffa6b..3b6ac331691d 100644 --- a/drivers/net/ethernet/microchip/lan966x/Makefile +++ b/drivers/net/ethernet/microchip/lan966x/Makefile @@ -15,6 +15,7 @@ lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \ lan966x_xdp.o lan966x_vcap_impl.o lan966x_vcap_ag_api.o \ lan966x_tc_flower.o lan966x_goto.o +lan966x-switch-$(CONFIG_LAN966X_DCB) += lan966x_dcb.o lan966x-switch-$(CONFIG_DEBUG_FS) += lan966x_vcap_debugfs.o # Provide include files diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c new file mode 100644 index 000000000000..e0d49421812f --- /dev/null +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include "lan966x_main.h" + +static void lan966x_dcb_app_update(struct net_device *dev, bool enable) +{ + struct lan966x_port *port = netdev_priv(dev); + struct lan966x_port_qos qos = {0}; + struct dcb_app app_itr; + + /* Get pcp ingress mapping */ + for (int i = 0; i < ARRAY_SIZE(qos.pcp.map); i++) { + app_itr.selector = DCB_APP_SEL_PCP; + app_itr.protocol = i; + qos.pcp.map[i] = dcb_getapp(dev, &app_itr); + } + + qos.pcp.enable = enable; + lan966x_port_qos_set(port, &qos); +} + +static int lan966x_dcb_app_validate(struct net_device *dev, + const struct dcb_app *app) +{ + int err = 0; + + switch (app->selector) { + /* Pcp checks */ + case DCB_APP_SEL_PCP: + if (app->protocol >= LAN966X_PORT_QOS_PCP_DEI_COUNT) + err = -EINVAL; + else if (app->priority >= NUM_PRIO_QUEUES) + err = -ERANGE; + break; + default: + err = -EINVAL; + break; + } + + if (err) + netdev_err(dev, "Invalid entry: %d:%d\n", app->protocol, + app->priority); + + return err; +} + +static int lan966x_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app) +{ + int err; + + err = dcb_ieee_delapp(dev, app); + if (err < 0) + return err; + + lan966x_dcb_app_update(dev, false); + + return 0; +} + +static int lan966x_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app) +{ + struct dcb_app app_itr; + int err; + u8 prio; + + err = lan966x_dcb_app_validate(dev, app); + if (err) + return err; + + /* Delete current mapping, if it exists */ + prio = dcb_getapp(dev, app); + if (prio) { + app_itr = *app; + app_itr.priority = prio; + dcb_ieee_delapp(dev, &app_itr); + } + + err = dcb_ieee_setapp(dev, app); + if (err) + return err; + + lan966x_dcb_app_update(dev, true); + + return 0; +} + +static const struct dcbnl_rtnl_ops lan966x_dcbnl_ops = { + .ieee_setapp = lan966x_dcb_ieee_setapp, + .ieee_delapp = lan966x_dcb_ieee_delapp, +}; + +void lan966x_dcb_init(struct lan966x *lan966x) +{ + for (int p = 0; p < lan966x->num_phys_ports; ++p) { + struct lan966x_port *port; + + port = lan966x->ports[p]; + if (!port) + continue; + + port->dev->dcbnl_ops = &lan966x_dcbnl_ops; + } +} diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index 2b6e046e1d10..5f01b21acdd1 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -1213,6 +1213,8 @@ static int lan966x_probe(struct platform_device *pdev) if (err) goto cleanup_fdma; + lan966x_dcb_init(lan966x); + return 0; cleanup_fdma: diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h index 882d5a08e7d5..b9ca47ab6e8b 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h @@ -104,6 +104,11 @@ #define LAN966X_VCAP_CID_ES0_L0 VCAP_CID_EGRESS_L0 /* ES0 lookup 0 */ #define LAN966X_VCAP_CID_ES0_MAX (VCAP_CID_EGRESS_L1 - 1) /* ES0 Max */ +#define LAN966X_PORT_QOS_PCP_COUNT 8 +#define LAN966X_PORT_QOS_DEI_COUNT 8 +#define LAN966X_PORT_QOS_PCP_DEI_COUNT \ + (LAN966X_PORT_QOS_PCP_COUNT + LAN966X_PORT_QOS_DEI_COUNT) + /* MAC table entry types. * ENTRYTYPE_NORMAL is subject to aging. * ENTRYTYPE_LOCKED is not subject to aging. @@ -392,6 +397,15 @@ struct lan966x_port_tc { struct flow_stats mirror_stat; }; +struct lan966x_port_qos_pcp { + u8 map[LAN966X_PORT_QOS_PCP_DEI_COUNT]; + bool enable; +}; + +struct lan966x_port_qos { + struct lan966x_port_qos_pcp pcp; +}; + struct lan966x_port { struct net_device *dev; struct lan966x *lan966x; @@ -456,6 +470,9 @@ int lan966x_port_pcs_set(struct lan966x_port *port, struct lan966x_port_config *config); void lan966x_port_init(struct lan966x_port *port); +void lan966x_port_qos_set(struct lan966x_port *port, + struct lan966x_port_qos *qos); + int lan966x_mac_ip_learn(struct lan966x *lan966x, bool cpu_copy, const unsigned char mac[ETH_ALEN], @@ -680,6 +697,14 @@ int lan966x_goto_port_del(struct lan966x_port *port, unsigned long goto_id, struct netlink_ext_ack *extack); +#ifdef CONFIG_LAN966X_DCB +void lan966x_dcb_init(struct lan966x *lan966x); +#else +static inline void lan966x_dcb_init(struct lan966x *lan966x) +{ +} +#endif + static inline void __iomem *lan_addr(void __iomem *base[], int id, int tinst, int tcnt, int gbase, int ginst, diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c index 0050fcb988b7..0cee8127c48e 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c @@ -394,6 +394,36 @@ int lan966x_port_pcs_set(struct lan966x_port *port, return 0; } +static void lan966x_port_qos_pcp_set(struct lan966x_port *port, + struct lan966x_port_qos_pcp *qos) +{ + u8 *pcp_itr = qos->map; + u8 pcp, dp; + + lan_rmw(ANA_QOS_CFG_QOS_PCP_ENA_SET(qos->enable), + ANA_QOS_CFG_QOS_PCP_ENA, + port->lan966x, ANA_QOS_CFG(port->chip_port)); + + /* Map PCP and DEI to priority */ + for (int i = 0; i < ARRAY_SIZE(qos->map); i++) { + pcp = *(pcp_itr + i); + dp = (i < LAN966X_PORT_QOS_PCP_COUNT) ? 0 : 1; + + lan_rmw(ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL_SET(pcp) | + ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL_SET(dp), + ANA_PCP_DEI_CFG_QOS_PCP_DEI_VAL | + ANA_PCP_DEI_CFG_DP_PCP_DEI_VAL, + port->lan966x, + ANA_PCP_DEI_CFG(port->chip_port, i)); + } +} + +void lan966x_port_qos_set(struct lan966x_port *port, + struct lan966x_port_qos *qos) +{ + lan966x_port_qos_pcp_set(port, &qos->pcp); +} + void lan966x_port_init(struct lan966x_port *port) { struct lan966x_port_config *config = &port->config; -- cgit v1.2.3 From 10c71a97eeeb0fb703225203059d2aeac79acb2a Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 16 May 2023 22:14:04 +0200 Subject: net: lan966x: Add support for apptrust Make use of set/getapptrust() to implement per-selector trust and trust order. Reviewed-by: Daniel Machon Signed-off-by: Horatiu Vultur Signed-off-by: Paolo Abeni --- .../net/ethernet/microchip/lan966x/lan966x_dcb.c | 118 ++++++++++++++++++++- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c index e0d49421812f..d6210c70171e 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c @@ -2,7 +2,49 @@ #include "lan966x_main.h" -static void lan966x_dcb_app_update(struct net_device *dev, bool enable) +enum lan966x_dcb_apptrust_values { + LAN966X_DCB_APPTRUST_EMPTY, + LAN966X_DCB_APPTRUST_DSCP, + LAN966X_DCB_APPTRUST_PCP, + LAN966X_DCB_APPTRUST_DSCP_PCP, + __LAN966X_DCB_APPTRUST_MAX +}; + +static const struct lan966x_dcb_apptrust { + u8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1]; + int nselectors; +} *lan966x_port_apptrust[NUM_PHYS_PORTS]; + +static const char *lan966x_dcb_apptrust_names[__LAN966X_DCB_APPTRUST_MAX] = { + [LAN966X_DCB_APPTRUST_EMPTY] = "empty", + [LAN966X_DCB_APPTRUST_DSCP] = "dscp", + [LAN966X_DCB_APPTRUST_PCP] = "pcp", + [LAN966X_DCB_APPTRUST_DSCP_PCP] = "dscp pcp" +}; + +/* Lan966x supported apptrust policies */ +static const struct lan966x_dcb_apptrust + lan966x_dcb_apptrust_policies[__LAN966X_DCB_APPTRUST_MAX] = { + /* Empty *must* be first */ + [LAN966X_DCB_APPTRUST_EMPTY] = { { 0 }, 0 }, + [LAN966X_DCB_APPTRUST_DSCP] = { { IEEE_8021QAZ_APP_SEL_DSCP }, 1 }, + [LAN966X_DCB_APPTRUST_PCP] = { { DCB_APP_SEL_PCP }, 1 }, + [LAN966X_DCB_APPTRUST_DSCP_PCP] = { { IEEE_8021QAZ_APP_SEL_DSCP, + DCB_APP_SEL_PCP }, 2 }, +}; + +static bool lan966x_dcb_apptrust_contains(int portno, u8 selector) +{ + const struct lan966x_dcb_apptrust *conf = lan966x_port_apptrust[portno]; + + for (int i = 0; i < conf->nselectors; i++) + if (conf->selectors[i] == selector) + return true; + + return false; +} + +static void lan966x_dcb_app_update(struct net_device *dev) { struct lan966x_port *port = netdev_priv(dev); struct lan966x_port_qos qos = {0}; @@ -15,7 +57,10 @@ static void lan966x_dcb_app_update(struct net_device *dev, bool enable) qos.pcp.map[i] = dcb_getapp(dev, &app_itr); } - qos.pcp.enable = enable; + /* Enable use of pcp for queue classification */ + if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP)) + qos.pcp.enable = true; + lan966x_port_qos_set(port, &qos); } @@ -52,7 +97,7 @@ static int lan966x_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app) if (err < 0) return err; - lan966x_dcb_app_update(dev, false); + lan966x_dcb_app_update(dev); return 0; } @@ -79,7 +124,67 @@ static int lan966x_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app) if (err) return err; - lan966x_dcb_app_update(dev, true); + lan966x_dcb_app_update(dev); + + return 0; +} + +static int lan966x_dcb_apptrust_validate(struct net_device *dev, + u8 *selectors, + int nselectors) +{ + for (int i = 0; i < ARRAY_SIZE(lan966x_dcb_apptrust_policies); i++) { + bool match; + + if (lan966x_dcb_apptrust_policies[i].nselectors != nselectors) + continue; + + match = true; + for (int j = 0; j < nselectors; j++) { + if (lan966x_dcb_apptrust_policies[i].selectors[j] != + *(selectors + j)) { + match = false; + break; + } + } + if (match) + return i; + } + + netdev_err(dev, "Valid apptrust configurations are:\n"); + for (int i = 0; i < ARRAY_SIZE(lan966x_dcb_apptrust_names); i++) + pr_info("order: %s\n", lan966x_dcb_apptrust_names[i]); + + return -EOPNOTSUPP; +} + +static int lan966x_dcb_setapptrust(struct net_device *dev, + u8 *selectors, + int nselectors) +{ + struct lan966x_port *port = netdev_priv(dev); + int idx; + + idx = lan966x_dcb_apptrust_validate(dev, selectors, nselectors); + if (idx < 0) + return idx; + + lan966x_port_apptrust[port->chip_port] = &lan966x_dcb_apptrust_policies[idx]; + lan966x_dcb_app_update(dev); + + return 0; +} + +static int lan966x_dcb_getapptrust(struct net_device *dev, u8 *selectors, + int *nselectors) +{ + struct lan966x_port *port = netdev_priv(dev); + const struct lan966x_dcb_apptrust *trust; + + trust = lan966x_port_apptrust[port->chip_port]; + + memcpy(selectors, trust->selectors, trust->nselectors); + *nselectors = trust->nselectors; return 0; } @@ -87,6 +192,8 @@ static int lan966x_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app) static const struct dcbnl_rtnl_ops lan966x_dcbnl_ops = { .ieee_setapp = lan966x_dcb_ieee_setapp, .ieee_delapp = lan966x_dcb_ieee_delapp, + .dcbnl_setapptrust = lan966x_dcb_setapptrust, + .dcbnl_getapptrust = lan966x_dcb_getapptrust, }; void lan966x_dcb_init(struct lan966x *lan966x) @@ -99,5 +206,8 @@ void lan966x_dcb_init(struct lan966x *lan966x) continue; port->dev->dcbnl_ops = &lan966x_dcbnl_ops; + + lan966x_port_apptrust[port->chip_port] = + &lan966x_dcb_apptrust_policies[LAN966X_DCB_APPTRUST_DSCP_PCP]; } } -- cgit v1.2.3 From 0c88d98108c615d9a8c1325857d44792c8924b16 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 16 May 2023 22:14:05 +0200 Subject: net: lan966x: Add support for offloading dscp table Add support for offloading dscp app entries. The dscp values are global for all lan966x ports. Reviewed-by: Daniel Machon Signed-off-by: Horatiu Vultur Signed-off-by: Paolo Abeni --- .../net/ethernet/microchip/lan966x/lan966x_dcb.c | 59 ++++++++++++++++++++-- .../net/ethernet/microchip/lan966x/lan966x_main.h | 8 +++ .../net/ethernet/microchip/lan966x/lan966x_port.c | 26 ++++++++++ 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c index d6210c70171e..17cec9ec5ed2 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c @@ -57,19 +57,62 @@ static void lan966x_dcb_app_update(struct net_device *dev) qos.pcp.map[i] = dcb_getapp(dev, &app_itr); } + /* Get dscp ingress mapping */ + for (int i = 0; i < ARRAY_SIZE(qos.dscp.map); i++) { + app_itr.selector = IEEE_8021QAZ_APP_SEL_DSCP; + app_itr.protocol = i; + qos.dscp.map[i] = dcb_getapp(dev, &app_itr); + } + /* Enable use of pcp for queue classification */ if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP)) qos.pcp.enable = true; + /* Enable use of dscp for queue classification */ + if (lan966x_dcb_apptrust_contains(port->chip_port, IEEE_8021QAZ_APP_SEL_DSCP)) + qos.dscp.enable = true; + lan966x_port_qos_set(port, &qos); } +/* DSCP mapping is global for all ports, so set and delete app entries are + * replicated for each port. + */ +static int lan966x_dcb_ieee_dscp_setdel(struct net_device *dev, + struct dcb_app *app, + int (*setdel)(struct net_device *, + struct dcb_app *)) +{ + struct lan966x_port *port = netdev_priv(dev); + struct lan966x *lan966x = port->lan966x; + int err; + + for (int i = 0; i < NUM_PHYS_PORTS; i++) { + port = lan966x->ports[i]; + if (!port) + continue; + + err = setdel(port->dev, app); + if (err) + return err; + } + + return 0; +} + static int lan966x_dcb_app_validate(struct net_device *dev, const struct dcb_app *app) { int err = 0; switch (app->selector) { + /* Dscp checks */ + case IEEE_8021QAZ_APP_SEL_DSCP: + if (app->protocol >= LAN966X_PORT_QOS_DSCP_COUNT) + err = -EINVAL; + else if (app->priority >= NUM_PRIO_QUEUES) + err = -ERANGE; + break; /* Pcp checks */ case DCB_APP_SEL_PCP: if (app->protocol >= LAN966X_PORT_QOS_PCP_DEI_COUNT) @@ -93,8 +136,12 @@ static int lan966x_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app) { int err; - err = dcb_ieee_delapp(dev, app); - if (err < 0) + if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP) + err = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_ieee_delapp); + else + err = dcb_ieee_delapp(dev, app); + + if (err) return err; lan966x_dcb_app_update(dev); @@ -117,10 +164,14 @@ static int lan966x_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app) if (prio) { app_itr = *app; app_itr.priority = prio; - dcb_ieee_delapp(dev, &app_itr); + lan966x_dcb_ieee_delapp(dev, &app_itr); } - err = dcb_ieee_setapp(dev, app); + if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP) + err = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_ieee_setapp); + else + err = dcb_ieee_setapp(dev, app); + if (err) return err; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h index b9ca47ab6e8b..8213440e0867 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h @@ -109,6 +109,8 @@ #define LAN966X_PORT_QOS_PCP_DEI_COUNT \ (LAN966X_PORT_QOS_PCP_COUNT + LAN966X_PORT_QOS_DEI_COUNT) +#define LAN966X_PORT_QOS_DSCP_COUNT 64 + /* MAC table entry types. * ENTRYTYPE_NORMAL is subject to aging. * ENTRYTYPE_LOCKED is not subject to aging. @@ -402,8 +404,14 @@ struct lan966x_port_qos_pcp { bool enable; }; +struct lan966x_port_qos_dscp { + u8 map[LAN966X_PORT_QOS_DSCP_COUNT]; + bool enable; +}; + struct lan966x_port_qos { struct lan966x_port_qos_pcp pcp; + struct lan966x_port_qos_dscp dscp; }; struct lan966x_port { diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c index 0cee8127c48e..11c552e87ee4 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c @@ -418,10 +418,36 @@ static void lan966x_port_qos_pcp_set(struct lan966x_port *port, } } +static void lan966x_port_qos_dscp_set(struct lan966x_port *port, + struct lan966x_port_qos_dscp *qos) +{ + struct lan966x *lan966x = port->lan966x; + + /* Enable/disable dscp for qos classification. */ + lan_rmw(ANA_QOS_CFG_QOS_DSCP_ENA_SET(qos->enable), + ANA_QOS_CFG_QOS_DSCP_ENA, + lan966x, ANA_QOS_CFG(port->chip_port)); + + /* Map each dscp value to priority and dp */ + for (int i = 0; i < ARRAY_SIZE(qos->map); i++) + lan_rmw(ANA_DSCP_CFG_DP_DSCP_VAL_SET(0) | + ANA_DSCP_CFG_QOS_DSCP_VAL_SET(*(qos->map + i)), + ANA_DSCP_CFG_DP_DSCP_VAL | + ANA_DSCP_CFG_QOS_DSCP_VAL, + lan966x, ANA_DSCP_CFG(i)); + + /* Set per-dscp trust */ + for (int i = 0; i < ARRAY_SIZE(qos->map); i++) + lan_rmw(ANA_DSCP_CFG_DSCP_TRUST_ENA_SET(qos->enable), + ANA_DSCP_CFG_DSCP_TRUST_ENA, + lan966x, ANA_DSCP_CFG(i)); +} + void lan966x_port_qos_set(struct lan966x_port *port, struct lan966x_port_qos *qos) { lan966x_port_qos_pcp_set(port, &qos->pcp); + lan966x_port_qos_dscp_set(port, &qos->dscp); } void lan966x_port_init(struct lan966x_port *port) -- cgit v1.2.3 From f8ba50ea13fb38da26aea8e1cba2ab30493e2c71 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 16 May 2023 22:14:06 +0200 Subject: net: lan966x: Add support for offloading default prio Add support for offloading default prio. Reviewed-by: Daniel Machon Reviewed-by: Piotr Raczynski Signed-off-by: Horatiu Vultur Signed-off-by: Paolo Abeni --- .../net/ethernet/microchip/lan966x/lan966x_dcb.c | 12 ++++++++++++ .../net/ethernet/microchip/lan966x/lan966x_main.h | 1 + .../net/ethernet/microchip/lan966x/lan966x_port.c | 21 +++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c index 17cec9ec5ed2..273e3bfb2389 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c @@ -64,6 +64,11 @@ static void lan966x_dcb_app_update(struct net_device *dev) qos.dscp.map[i] = dcb_getapp(dev, &app_itr); } + /* Get default prio */ + qos.default_prio = dcb_ieee_getapp_default_prio_mask(dev); + if (qos.default_prio) + qos.default_prio = fls(qos.default_prio) - 1; + /* Enable use of pcp for queue classification */ if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP)) qos.pcp.enable = true; @@ -106,6 +111,13 @@ static int lan966x_dcb_app_validate(struct net_device *dev, int err = 0; switch (app->selector) { + /* Default priority checks */ + case IEEE_8021QAZ_APP_SEL_ETHERTYPE: + if (app->protocol) + err = -EINVAL; + else if (app->priority >= NUM_PRIO_QUEUES) + err = -ERANGE; + break; /* Dscp checks */ case IEEE_8021QAZ_APP_SEL_DSCP: if (app->protocol >= LAN966X_PORT_QOS_DSCP_COUNT) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h index 8213440e0867..53711d538016 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h @@ -412,6 +412,7 @@ struct lan966x_port_qos_dscp { struct lan966x_port_qos { struct lan966x_port_qos_pcp pcp; struct lan966x_port_qos_dscp dscp; + u8 default_prio; }; struct lan966x_port { diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c index 11c552e87ee4..a6608876b71e 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c @@ -443,11 +443,32 @@ static void lan966x_port_qos_dscp_set(struct lan966x_port *port, lan966x, ANA_DSCP_CFG(i)); } +static int lan966x_port_qos_default_set(struct lan966x_port *port, + struct lan966x_port_qos *qos) +{ + /* Set default prio and dp level */ + lan_rmw(ANA_QOS_CFG_DP_DEFAULT_VAL_SET(0) | + ANA_QOS_CFG_QOS_DEFAULT_VAL_SET(qos->default_prio), + ANA_QOS_CFG_DP_DEFAULT_VAL | + ANA_QOS_CFG_QOS_DEFAULT_VAL, + port->lan966x, ANA_QOS_CFG(port->chip_port)); + + /* Set default pcp and dei for untagged frames */ + lan_rmw(ANA_VLAN_CFG_VLAN_DEI_SET(0) | + ANA_VLAN_CFG_VLAN_PCP_SET(0), + ANA_VLAN_CFG_VLAN_DEI | + ANA_VLAN_CFG_VLAN_PCP, + port->lan966x, ANA_VLAN_CFG(port->chip_port)); + + return 0; +} + void lan966x_port_qos_set(struct lan966x_port *port, struct lan966x_port_qos *qos) { lan966x_port_qos_pcp_set(port, &qos->pcp); lan966x_port_qos_dscp_set(port, &qos->dscp); + lan966x_port_qos_default_set(port, qos); } void lan966x_port_init(struct lan966x_port *port) -- cgit v1.2.3 From 363f98b96a43f11cb4c6e4d69199d656d2e5b373 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 16 May 2023 22:14:07 +0200 Subject: net: lan966x: Add support for PCP rewrite Add support for rewrite of PCP and DEI value, based on QoS and DP level. The DCB rewrite table is queried for mappings between priority and PCP/DEI. The classified DP level is then encoded in the DEI bit, if a mapping for DEI exists. Reviewed-by: Daniel Machon Signed-off-by: Horatiu Vultur Signed-off-by: Paolo Abeni --- .../net/ethernet/microchip/lan966x/lan966x_dcb.c | 61 +++++++++++++++++++++- .../net/ethernet/microchip/lan966x/lan966x_main.h | 10 ++++ .../net/ethernet/microchip/lan966x/lan966x_port.c | 37 +++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c index 273e3bfb2389..0ea650943653 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c @@ -46,9 +46,11 @@ static bool lan966x_dcb_apptrust_contains(int portno, u8 selector) static void lan966x_dcb_app_update(struct net_device *dev) { + struct dcb_rewr_prio_pcp_map pcp_rewr_map = {0}; struct lan966x_port *port = netdev_priv(dev); struct lan966x_port_qos qos = {0}; struct dcb_app app_itr; + bool pcp_rewr = false; /* Get pcp ingress mapping */ for (int i = 0; i < ARRAY_SIZE(qos.pcp.map); i++) { @@ -69,10 +71,24 @@ static void lan966x_dcb_app_update(struct net_device *dev) if (qos.default_prio) qos.default_prio = fls(qos.default_prio) - 1; + /* Get pcp rewrite mapping */ + dcb_getrewr_prio_pcp_mask_map(dev, &pcp_rewr_map); + for (int i = 0; i < ARRAY_SIZE(pcp_rewr_map.map); i++) { + if (!pcp_rewr_map.map[i]) + continue; + + pcp_rewr = true; + qos.pcp_rewr.map[i] = fls(pcp_rewr_map.map[i]) - 1; + } + /* Enable use of pcp for queue classification */ - if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP)) + if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP)) { qos.pcp.enable = true; + if (pcp_rewr) + qos.pcp_rewr.enable = true; + } + /* Enable use of dscp for queue classification */ if (lan966x_dcb_apptrust_contains(port->chip_port, IEEE_8021QAZ_APP_SEL_DSCP)) qos.dscp.enable = true; @@ -252,11 +268,54 @@ static int lan966x_dcb_getapptrust(struct net_device *dev, u8 *selectors, return 0; } +static int lan966x_dcb_delrewr(struct net_device *dev, struct dcb_app *app) +{ + int err; + + err = dcb_delrewr(dev, app); + if (err < 0) + return err; + + lan966x_dcb_app_update(dev); + + return 0; +} + +static int lan966x_dcb_setrewr(struct net_device *dev, struct dcb_app *app) +{ + struct dcb_app app_itr; + u16 proto; + int err; + + err = lan966x_dcb_app_validate(dev, app); + if (err) + goto out; + + /* Delete current mapping, if it exists. */ + proto = dcb_getrewr(dev, app); + if (proto) { + app_itr = *app; + app_itr.protocol = proto; + lan966x_dcb_delrewr(dev, &app_itr); + } + + err = dcb_setrewr(dev, app); + if (err) + goto out; + + lan966x_dcb_app_update(dev); + +out: + return err; +} + static const struct dcbnl_rtnl_ops lan966x_dcbnl_ops = { .ieee_setapp = lan966x_dcb_ieee_setapp, .ieee_delapp = lan966x_dcb_ieee_delapp, .dcbnl_setapptrust = lan966x_dcb_setapptrust, .dcbnl_getapptrust = lan966x_dcb_getapptrust, + .dcbnl_setrewr = lan966x_dcb_setrewr, + .dcbnl_delrewr = lan966x_dcb_delrewr, }; void lan966x_dcb_init(struct lan966x *lan966x) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h index 53711d538016..16b0149ac2b5 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h @@ -111,6 +111,10 @@ #define LAN966X_PORT_QOS_DSCP_COUNT 64 +/* Port PCP rewrite mode */ +#define LAN966X_PORT_REW_TAG_CTRL_CLASSIFIED 0 +#define LAN966X_PORT_REW_TAG_CTRL_MAPPED 2 + /* MAC table entry types. * ENTRYTYPE_NORMAL is subject to aging. * ENTRYTYPE_LOCKED is not subject to aging. @@ -409,9 +413,15 @@ struct lan966x_port_qos_dscp { bool enable; }; +struct lan966x_port_qos_pcp_rewr { + u16 map[NUM_PRIO_QUEUES]; + bool enable; +}; + struct lan966x_port_qos { struct lan966x_port_qos_pcp pcp; struct lan966x_port_qos_dscp dscp; + struct lan966x_port_qos_pcp_rewr pcp_rewr; u8 default_prio; }; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c index a6608876b71e..6887746d081f 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c @@ -463,12 +463,49 @@ static int lan966x_port_qos_default_set(struct lan966x_port *port, return 0; } +static void lan966x_port_qos_pcp_rewr_set(struct lan966x_port *port, + struct lan966x_port_qos_pcp_rewr *qos) +{ + u8 mode = LAN966X_PORT_REW_TAG_CTRL_CLASSIFIED; + u8 pcp, dei; + + if (qos->enable) + mode = LAN966X_PORT_REW_TAG_CTRL_MAPPED; + + /* Map the values only if it is enabled otherwise will be the classified + * value + */ + lan_rmw(REW_TAG_CFG_TAG_PCP_CFG_SET(mode) | + REW_TAG_CFG_TAG_DEI_CFG_SET(mode), + REW_TAG_CFG_TAG_PCP_CFG | + REW_TAG_CFG_TAG_DEI_CFG, + port->lan966x, REW_TAG_CFG(port->chip_port)); + + /* Map each value to pcp and dei */ + for (int i = 0; i < ARRAY_SIZE(qos->map); i++) { + pcp = qos->map[i]; + if (pcp > LAN966X_PORT_QOS_PCP_COUNT) + dei = 1; + else + dei = 0; + + lan_rmw(REW_PCP_DEI_CFG_DEI_QOS_VAL_SET(dei) | + REW_PCP_DEI_CFG_PCP_QOS_VAL_SET(pcp), + REW_PCP_DEI_CFG_DEI_QOS_VAL | + REW_PCP_DEI_CFG_PCP_QOS_VAL, + port->lan966x, + REW_PCP_DEI_CFG(port->chip_port, + i + dei * LAN966X_PORT_QOS_PCP_COUNT)); + } +} + void lan966x_port_qos_set(struct lan966x_port *port, struct lan966x_port_qos *qos) { lan966x_port_qos_pcp_set(port, &qos->pcp); lan966x_port_qos_dscp_set(port, &qos->dscp); lan966x_port_qos_default_set(port, qos); + lan966x_port_qos_pcp_rewr_set(port, &qos->pcp_rewr); } void lan966x_port_init(struct lan966x_port *port) -- cgit v1.2.3 From d38ddd56d90eb156b2708637403fd8a936c0113a Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Tue, 16 May 2023 22:14:08 +0200 Subject: net: lan966x: Add support for DSCP rewrite Add support for DSCP rewrite in lan966x driver. On egress DSCP is rewritten from either classified DSCP, or frame DSCP. Classified DSCP is determined by the Analyzer Classifier on ingress, and is mapped from classified QoS class and DP level. Classification of DSCP is by default enabled for all ports. It is required that DSCP is trusted for the egress port *and* rewrite table is not empty, in order to rewrite DSCP based on classified DSCP, otherwise DSCP is always rewritten from frame DSCP. Reviewed-by: Daniel Machon Signed-off-by: Horatiu Vultur Signed-off-by: Paolo Abeni --- .../net/ethernet/microchip/lan966x/lan966x_dcb.c | 36 ++++++++++++++++++++-- .../net/ethernet/microchip/lan966x/lan966x_main.h | 13 ++++++++ .../net/ethernet/microchip/lan966x/lan966x_port.c | 35 +++++++++++++++++++++ 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c index 0ea650943653..ed2d96d7908e 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_dcb.c @@ -46,10 +46,12 @@ static bool lan966x_dcb_apptrust_contains(int portno, u8 selector) static void lan966x_dcb_app_update(struct net_device *dev) { + struct dcb_ieee_app_prio_map dscp_rewr_map = {0}; struct dcb_rewr_prio_pcp_map pcp_rewr_map = {0}; struct lan966x_port *port = netdev_priv(dev); struct lan966x_port_qos qos = {0}; struct dcb_app app_itr; + bool dscp_rewr = false; bool pcp_rewr = false; /* Get pcp ingress mapping */ @@ -81,6 +83,16 @@ static void lan966x_dcb_app_update(struct net_device *dev) qos.pcp_rewr.map[i] = fls(pcp_rewr_map.map[i]) - 1; } + /* Get dscp rewrite mapping */ + dcb_getrewr_prio_dscp_mask_map(dev, &dscp_rewr_map); + for (int i = 0; i < ARRAY_SIZE(dscp_rewr_map.map); i++) { + if (!dscp_rewr_map.map[i]) + continue; + + dscp_rewr = true; + qos.dscp_rewr.map[i] = fls64(dscp_rewr_map.map[i]) - 1; + } + /* Enable use of pcp for queue classification */ if (lan966x_dcb_apptrust_contains(port->chip_port, DCB_APP_SEL_PCP)) { qos.pcp.enable = true; @@ -90,9 +102,13 @@ static void lan966x_dcb_app_update(struct net_device *dev) } /* Enable use of dscp for queue classification */ - if (lan966x_dcb_apptrust_contains(port->chip_port, IEEE_8021QAZ_APP_SEL_DSCP)) + if (lan966x_dcb_apptrust_contains(port->chip_port, IEEE_8021QAZ_APP_SEL_DSCP)) { qos.dscp.enable = true; + if (dscp_rewr) + qos.dscp_rewr.enable = true; + } + lan966x_port_qos_set(port, &qos); } @@ -272,7 +288,11 @@ static int lan966x_dcb_delrewr(struct net_device *dev, struct dcb_app *app) { int err; - err = dcb_delrewr(dev, app); + if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP) + err = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_delrewr); + else + err = dcb_delrewr(dev, app); + if (err < 0) return err; @@ -299,7 +319,11 @@ static int lan966x_dcb_setrewr(struct net_device *dev, struct dcb_app *app) lan966x_dcb_delrewr(dev, &app_itr); } - err = dcb_setrewr(dev, app); + if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP) + err = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_setrewr); + else + err = dcb_setrewr(dev, app); + if (err) goto out; @@ -331,5 +355,11 @@ void lan966x_dcb_init(struct lan966x *lan966x) lan966x_port_apptrust[port->chip_port] = &lan966x_dcb_apptrust_policies[LAN966X_DCB_APPTRUST_DSCP_PCP]; + + /* Enable DSCP classification based on classified QoS class and + * DP, for all DSCP values, for all ports. + */ + lan966x_port_qos_dscp_rewr_mode_set(port, + LAN966X_PORT_QOS_REWR_DSCP_ALL); } } diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h index 16b0149ac2b5..27f272831ea5 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.h +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.h @@ -115,6 +115,11 @@ #define LAN966X_PORT_REW_TAG_CTRL_CLASSIFIED 0 #define LAN966X_PORT_REW_TAG_CTRL_MAPPED 2 +/* Port DSCP rewrite mode */ +#define LAN966X_PORT_REW_DSCP_FRAME 0 +#define LAN966X_PORT_REW_DSCP_ANALIZER 1 +#define LAN966X_PORT_QOS_REWR_DSCP_ALL 3 + /* MAC table entry types. * ENTRYTYPE_NORMAL is subject to aging. * ENTRYTYPE_LOCKED is not subject to aging. @@ -418,10 +423,16 @@ struct lan966x_port_qos_pcp_rewr { bool enable; }; +struct lan966x_port_qos_dscp_rewr { + u16 map[LAN966X_PORT_QOS_DSCP_COUNT]; + bool enable; +}; + struct lan966x_port_qos { struct lan966x_port_qos_pcp pcp; struct lan966x_port_qos_dscp dscp; struct lan966x_port_qos_pcp_rewr pcp_rewr; + struct lan966x_port_qos_dscp_rewr dscp_rewr; u8 default_prio; }; @@ -491,6 +502,8 @@ void lan966x_port_init(struct lan966x_port *port); void lan966x_port_qos_set(struct lan966x_port *port, struct lan966x_port_qos *qos); +void lan966x_port_qos_dscp_rewr_mode_set(struct lan966x_port *port, + int mode); int lan966x_mac_ip_learn(struct lan966x *lan966x, bool cpu_copy, diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c index 6887746d081f..92108d354051 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c @@ -499,6 +499,40 @@ static void lan966x_port_qos_pcp_rewr_set(struct lan966x_port *port, } } +static void lan966x_port_qos_dscp_rewr_set(struct lan966x_port *port, + struct lan966x_port_qos_dscp_rewr *qos) +{ + u16 dscp; + u8 mode; + + if (qos->enable) + mode = LAN966X_PORT_REW_DSCP_ANALIZER; + else + mode = LAN966X_PORT_REW_DSCP_FRAME; + + /* Enable the rewrite otherwise will use the values from the frame */ + lan_rmw(REW_DSCP_CFG_DSCP_REWR_CFG_SET(mode), + REW_DSCP_CFG_DSCP_REWR_CFG, + port->lan966x, REW_DSCP_CFG(port->chip_port)); + + /* Map each classified Qos class and DP to classified DSCP value */ + for (int i = 0; i < ARRAY_SIZE(qos->map); i++) { + dscp = qos->map[i]; + + lan_rmw(ANA_DSCP_REWR_CFG_DSCP_QOS_REWR_VAL_SET(dscp), + ANA_DSCP_REWR_CFG_DSCP_QOS_REWR_VAL, + port->lan966x, ANA_DSCP_REWR_CFG(i)); + } +} + +void lan966x_port_qos_dscp_rewr_mode_set(struct lan966x_port *port, + int mode) +{ + lan_rmw(ANA_QOS_CFG_DSCP_REWR_CFG_SET(mode), + ANA_QOS_CFG_DSCP_REWR_CFG, + port->lan966x, ANA_QOS_CFG(port->chip_port)); +} + void lan966x_port_qos_set(struct lan966x_port *port, struct lan966x_port_qos *qos) { @@ -506,6 +540,7 @@ void lan966x_port_qos_set(struct lan966x_port *port, lan966x_port_qos_dscp_set(port, &qos->dscp); lan966x_port_qos_default_set(port, qos); lan966x_port_qos_pcp_rewr_set(port, &qos->pcp_rewr); + lan966x_port_qos_dscp_rewr_set(port, &qos->dscp_rewr); } void lan966x_port_init(struct lan966x_port *port) -- cgit v1.2.3 From 95b681485563c64585de78662ee52d06b7fa47d9 Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Wed, 12 Apr 2023 09:36:11 +0200 Subject: igc: Avoid transmit queue timeout for XDP High XDP load triggers the netdev watchdog: |NETDEV WATCHDOG: enp3s0 (igc): transmit queue 2 timed out The reason is the Tx queue transmission start (txq->trans_start) is not updated in XDP code path. Therefore, add it for all XDP transmission functions. Signed-off-by: Kurt Kanzenbach Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 38d113b48111..c5ef1edcf548 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2411,6 +2411,8 @@ static int igc_xdp_xmit_back(struct igc_adapter *adapter, struct xdp_buff *xdp) nq = txring_txq(ring); __netif_tx_lock(nq, cpu); + /* Avoid transmit queue timeout since we share it with the slow path */ + txq_trans_cond_update(nq); res = igc_xdp_init_tx_descriptor(ring, xdpf); __netif_tx_unlock(nq); return res; @@ -2829,6 +2831,9 @@ static void igc_xdp_xmit_zc(struct igc_ring *ring) __netif_tx_lock(nq, cpu); + /* Avoid transmit queue timeout since we share it with the slow path */ + txq_trans_cond_update(nq); + budget = igc_desc_unused(ring); while (xsk_tx_peek_desc(pool, &xdp_desc) && budget--) { @@ -6354,6 +6359,9 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames, __netif_tx_lock(nq, cpu); + /* Avoid transmit queue timeout since we share it with the slow path */ + txq_trans_cond_update(nq); + drops = 0; for (i = 0; i < num_frames; i++) { int err; -- cgit v1.2.3 From 7271522b729b80d9581f4b3debef0e942d3a1049 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 28 Apr 2023 16:00:09 -0400 Subject: igb: Define igb_pm_ops conditionally on CONFIG_PM For s390, gcc with W=1 reports drivers/net/ethernet/intel/igb/igb_main.c:186:32: error: 'igb_pm_ops' defined but not used [-Werror=unused-const-variable=] 186 | static const struct dev_pm_ops igb_pm_ops = { | ^~~~~~~~~~ The only use of igb_pm_ops is conditional on CONFIG_PM. The definition of igb_pm_ops should also be conditional on CONFIG_PM Signed-off-by: Tom Rix Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igb/igb_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 58872a4c2540..c5cdb880774d 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -183,11 +183,13 @@ static int igb_resume(struct device *); static int igb_runtime_suspend(struct device *dev); static int igb_runtime_resume(struct device *dev); static int igb_runtime_idle(struct device *dev); +#ifdef CONFIG_PM static const struct dev_pm_ops igb_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(igb_suspend, igb_resume) SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume, igb_runtime_idle) }; +#endif static void igb_shutdown(struct pci_dev *); static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs); #ifdef CONFIG_IGB_DCA -- cgit v1.2.3 From c4dc8dc32bd1fa0ed04d25f2e4004d854c163c39 Mon Sep 17 00:00:00 2001 From: Baozhu Ni Date: Wed, 17 May 2023 09:27:26 +0800 Subject: e1000e: Add @adapter description to kdoc Provide a description for the kernel doc of the @adapter of e1000e_trigger_lsc() Signed-off-by: Baozhu Ni Reviewed-by: Simon Horman Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index bd7ef59b1f2e..771a3c909c45 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4198,7 +4198,7 @@ void e1000e_reset(struct e1000_adapter *adapter) /** * e1000e_trigger_lsc - trigger an LSC interrupt - * @adapter: + * @adapter: board private structure * * Fire a link status change interrupt to start the watchdog. **/ -- cgit v1.2.3 From 418c1214741cf3ac5e420382a85c4f8a40586024 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 17 May 2023 11:37:47 +0100 Subject: net: sfp: add helper to modify signal states There are a couple of locations in the code where we modify sfp->state, and then call sfp_set_state(, sfp->state) to update the outputs/soft state to control the module. Provide a helper which takes a mask and new state so that this is encapsulated in one location. Reviewed-by: Simon Horman Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 89636dc71e48..c97a87393fdb 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -734,6 +734,12 @@ static void sfp_set_state(struct sfp *sfp, unsigned int state) sfp_soft_set_state(sfp, state); } +static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set) +{ + sfp->state = (sfp->state & ~mask) | set; + sfp_set_state(sfp, sfp->state); +} + static unsigned int sfp_check(void *buf, size_t len) { u8 *p, check; @@ -1537,16 +1543,14 @@ static void sfp_module_tx_disable(struct sfp *sfp) { dev_dbg(sfp->dev, "tx disable %u -> %u\n", sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 1); - sfp->state |= SFP_F_TX_DISABLE; - sfp_set_state(sfp, sfp->state); + sfp_mod_state(sfp, SFP_F_TX_DISABLE, SFP_F_TX_DISABLE); } static void sfp_module_tx_enable(struct sfp *sfp) { dev_dbg(sfp->dev, "tx disable %u -> %u\n", sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 0); - sfp->state &= ~SFP_F_TX_DISABLE; - sfp_set_state(sfp, sfp->state); + sfp_mod_state(sfp, SFP_F_TX_DISABLE, 0); } #if IS_ENABLED(CONFIG_DEBUG_FS) -- cgit v1.2.3 From d47e5a430dfd8b15739a118e4a2add5fa90347fd Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 17 May 2023 11:37:52 +0100 Subject: net: sfp: move rtnl lock to cover reading state As preparation to moving st_mutex inside rtnl_lock, we need to first move the rtnl lock to cover reading the state. Reviewed-by: Simon Horman Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index c97a87393fdb..3fc703e4dd21 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -2601,6 +2601,7 @@ static void sfp_check_state(struct sfp *sfp) unsigned int state, i, changed; mutex_lock(&sfp->st_mutex); + rtnl_lock(); state = sfp_get_state(sfp); changed = state ^ sfp->state; if (sfp->tx_fault_ignore) @@ -2616,7 +2617,6 @@ static void sfp_check_state(struct sfp *sfp) state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); sfp->state = state; - rtnl_lock(); if (changed & SFP_F_PRESENT) sfp_sm_event(sfp, state & SFP_F_PRESENT ? SFP_E_INSERT : SFP_E_REMOVE); -- cgit v1.2.3 From a9fe964e7aaeb3fc06a91c21269d0ac8b5afcea8 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 17 May 2023 11:37:57 +0100 Subject: net: sfp: swap order of rtnl and st_mutex locks Swap the order of the rtnl and st_mutex locks - st_mutex is now nested beneath rtnl lock instead of rtnl being beneath st_mutex. This will allow us to hold st_mutex only while manipulating the module's hardware or software control state. Reviewed-by: Simon Horman Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 3fc703e4dd21..ffb6c37dac96 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -2600,8 +2600,8 @@ static void sfp_check_state(struct sfp *sfp) { unsigned int state, i, changed; - mutex_lock(&sfp->st_mutex); rtnl_lock(); + mutex_lock(&sfp->st_mutex); state = sfp_get_state(sfp); changed = state ^ sfp->state; if (sfp->tx_fault_ignore) @@ -2628,8 +2628,8 @@ static void sfp_check_state(struct sfp *sfp) if (changed & SFP_F_LOS) sfp_sm_event(sfp, state & SFP_F_LOS ? SFP_E_LOS_HIGH : SFP_E_LOS_LOW); - rtnl_unlock(); mutex_unlock(&sfp->st_mutex); + rtnl_unlock(); } static irqreturn_t sfp_irq(int irq, void *data) -- cgit v1.2.3 From 97a492050aa5e15507fd7b8774e7adaf8d6e4bb5 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 17 May 2023 11:38:02 +0100 Subject: net: sfp: move sm_mutex into sfp_check_state() Provide an unlocked version of sfp_sm_event() which can be used by sfp_check_state() to avoid having to keep re-taking the lock if several signals have changed state. Reviewed-by: Simon Horman Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index ffb6c37dac96..e5cd36e3a421 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -2456,10 +2456,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) } } -static void sfp_sm_event(struct sfp *sfp, unsigned int event) +static void __sfp_sm_event(struct sfp *sfp, unsigned int event) { - mutex_lock(&sfp->sm_mutex); - dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n", mod_state_to_str(sfp->sm_mod_state), dev_state_to_str(sfp->sm_dev_state), @@ -2474,7 +2472,12 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) mod_state_to_str(sfp->sm_mod_state), dev_state_to_str(sfp->sm_dev_state), sm_state_to_str(sfp->sm_state)); +} +static void sfp_sm_event(struct sfp *sfp, unsigned int event) +{ + mutex_lock(&sfp->sm_mutex); + __sfp_sm_event(sfp, event); mutex_unlock(&sfp->sm_mutex); } @@ -2617,17 +2620,19 @@ static void sfp_check_state(struct sfp *sfp) state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); sfp->state = state; + mutex_lock(&sfp->sm_mutex); if (changed & SFP_F_PRESENT) - sfp_sm_event(sfp, state & SFP_F_PRESENT ? - SFP_E_INSERT : SFP_E_REMOVE); + __sfp_sm_event(sfp, state & SFP_F_PRESENT ? + SFP_E_INSERT : SFP_E_REMOVE); if (changed & SFP_F_TX_FAULT) - sfp_sm_event(sfp, state & SFP_F_TX_FAULT ? - SFP_E_TX_FAULT : SFP_E_TX_CLEAR); + __sfp_sm_event(sfp, state & SFP_F_TX_FAULT ? + SFP_E_TX_FAULT : SFP_E_TX_CLEAR); if (changed & SFP_F_LOS) - sfp_sm_event(sfp, state & SFP_F_LOS ? - SFP_E_LOS_HIGH : SFP_E_LOS_LOW); + __sfp_sm_event(sfp, state & SFP_F_LOS ? + SFP_E_LOS_HIGH : SFP_E_LOS_LOW); + mutex_unlock(&sfp->sm_mutex); mutex_unlock(&sfp->st_mutex); rtnl_unlock(); } -- cgit v1.2.3 From 1974fd3bf0f04589dea1a4a76273bbc8fd5760f6 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 17 May 2023 11:38:07 +0100 Subject: net: sfp: change st_mutex locking Change st_mutex's use within SFP such that it only protects the various state members, as it was originally supposed to, and isn't held while making various calls outside the driver. Reviewed-by: Simon Horman Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 56 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index e5cd36e3a421..bf7dac9977e1 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -242,10 +242,17 @@ struct sfp { bool need_poll; + /* Access rules: + * state_hw_drive: st_mutex held + * state_hw_mask: st_mutex held + * state_soft_mask: st_mutex held + * state: st_mutex held unless reading input bits + */ struct mutex st_mutex; /* Protects state */ unsigned int state_hw_mask; unsigned int state_soft_mask; unsigned int state; + struct delayed_work poll; struct delayed_work timeout; struct mutex sm_mutex; /* Protects state machine */ @@ -692,7 +699,6 @@ static void sfp_soft_start_poll(struct sfp *sfp) const struct sfp_eeprom_id *id = &sfp->id; unsigned int mask = 0; - sfp->state_soft_mask = 0; if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE) mask |= SFP_F_TX_DISABLE; if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT) @@ -700,19 +706,26 @@ static void sfp_soft_start_poll(struct sfp *sfp) if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS) mask |= SFP_F_LOS; + mutex_lock(&sfp->st_mutex); // Poll the soft state for hardware pins we want to ignore sfp->state_soft_mask = ~sfp->state_hw_mask & mask; if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && !sfp->need_poll) mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); + mutex_unlock(&sfp->st_mutex); } static void sfp_soft_stop_poll(struct sfp *sfp) { + mutex_lock(&sfp->st_mutex); sfp->state_soft_mask = 0; + mutex_unlock(&sfp->st_mutex); } +/* sfp_get_state() - must be called with st_mutex held, or in the + * initialisation path. + */ static unsigned int sfp_get_state(struct sfp *sfp) { unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT); @@ -725,6 +738,9 @@ static unsigned int sfp_get_state(struct sfp *sfp) return state; } +/* sfp_set_state() - must be called with st_mutex held, or in the + * initialisation path. + */ static void sfp_set_state(struct sfp *sfp, unsigned int state) { sfp->set_state(sfp, state); @@ -736,8 +752,10 @@ static void sfp_set_state(struct sfp *sfp, unsigned int state) static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set) { + mutex_lock(&sfp->st_mutex); sfp->state = (sfp->state & ~mask) | set; sfp_set_state(sfp, sfp->state); + mutex_unlock(&sfp->st_mutex); } static unsigned int sfp_check(void *buf, size_t len) @@ -1603,16 +1621,18 @@ static void sfp_debugfs_exit(struct sfp *sfp) static void sfp_module_tx_fault_reset(struct sfp *sfp) { - unsigned int state = sfp->state; - - if (state & SFP_F_TX_DISABLE) - return; + unsigned int state; - sfp_set_state(sfp, state | SFP_F_TX_DISABLE); + mutex_lock(&sfp->st_mutex); + state = sfp->state; + if (!(state & SFP_F_TX_DISABLE)) { + sfp_set_state(sfp, state | SFP_F_TX_DISABLE); - udelay(T_RESET_US); + udelay(T_RESET_US); - sfp_set_state(sfp, state); + sfp_set_state(sfp, state); + } + mutex_unlock(&sfp->st_mutex); } /* SFP state machine */ @@ -1957,6 +1977,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) /* SFP module inserted - read I2C data */ struct sfp_eeprom_id id; bool cotsworks_sfbg; + unsigned int mask; bool cotsworks; u8 check; int ret; @@ -2096,14 +2117,13 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) if (ret < 0) return ret; - /* Initialise state bits to use from hardware */ - sfp->state_hw_mask = SFP_F_PRESENT; + mask = SFP_F_PRESENT; if (sfp->gpio[GPIO_TX_DISABLE]) - sfp->state_hw_mask |= SFP_F_TX_DISABLE; + mask |= SFP_F_TX_DISABLE; if (sfp->gpio[GPIO_TX_FAULT]) - sfp->state_hw_mask |= SFP_F_TX_FAULT; + mask |= SFP_F_TX_FAULT; if (sfp->gpio[GPIO_LOS]) - sfp->state_hw_mask |= SFP_F_LOS; + mask |= SFP_F_LOS; sfp->module_t_start_up = T_START_UP; sfp->module_t_wait = T_WAIT; @@ -2121,8 +2141,14 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) sfp->mdio_protocol = MDIO_I2C_NONE; sfp->quirk = sfp_lookup_quirk(&id); + + mutex_lock(&sfp->st_mutex); + /* Initialise state bits to use from hardware */ + sfp->state_hw_mask = mask; + if (sfp->quirk && sfp->quirk->fixup) sfp->quirk->fixup(sfp); + mutex_unlock(&sfp->st_mutex); return 0; } @@ -2619,6 +2645,7 @@ static void sfp_check_state(struct sfp *sfp) state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); sfp->state = state; + mutex_unlock(&sfp->st_mutex); mutex_lock(&sfp->sm_mutex); if (changed & SFP_F_PRESENT) @@ -2633,7 +2660,6 @@ static void sfp_check_state(struct sfp *sfp) __sfp_sm_event(sfp, state & SFP_F_LOS ? SFP_E_LOS_HIGH : SFP_E_LOS_LOW); mutex_unlock(&sfp->sm_mutex); - mutex_unlock(&sfp->st_mutex); rtnl_unlock(); } @@ -2652,6 +2678,8 @@ static void sfp_poll(struct work_struct *work) sfp_check_state(sfp); + // st_mutex doesn't need to be held here for state_soft_mask, + // it's unimportant if we race while reading this. if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) || sfp->need_poll) mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); -- cgit v1.2.3 From dc18582211b34bce8250ddf3cac2a2230e192120 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 17 May 2023 11:38:12 +0100 Subject: net: sfp: add support for setting signalling rate Add support to the SFP layer to allow phylink to set the signalling rate for a SFP module. The rate given will be in units of kilo-baud (1000 baud). Reviewed-by: Simon Horman Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 24 ++++++++++++++++++++++++ drivers/net/phy/sfp-bus.c | 20 ++++++++++++++++++++ drivers/net/phy/sfp.c | 5 +++++ drivers/net/phy/sfp.h | 1 + include/linux/sfp.h | 6 ++++++ 5 files changed, 56 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index dc9a740b1ff7..f2106d17847a 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -156,6 +156,23 @@ static const char *phylink_an_mode_str(unsigned int mode) return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; } +static unsigned int phylink_interface_signal_rate(phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: /* 1.25Mbd */ + return 1250; + case PHY_INTERFACE_MODE_2500BASEX: /* 3.125Mbd */ + return 3125; + case PHY_INTERFACE_MODE_5GBASER: /* 5.15625Mbd */ + return 5156; + case PHY_INTERFACE_MODE_10GBASER: /* 10.3125Mbd */ + return 10313; + default: + return 0; + } +} + /** * phylink_interface_max_speed() - get the maximum speed of a phy interface * @interface: phy interface mode defined by &typedef phy_interface_t @@ -1025,6 +1042,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, { struct phylink_pcs *pcs = NULL; bool pcs_changed = false; + unsigned int rate_kbd; int err; phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); @@ -1084,6 +1102,12 @@ static void phylink_major_config(struct phylink *pl, bool restart, ERR_PTR(err)); } + if (pl->sfp_bus) { + rate_kbd = phylink_interface_signal_rate(state->interface); + if (rate_kbd) + sfp_upstream_set_signal_rate(pl->sfp_bus, rate_kbd); + } + phylink_pcs_poll_start(pl); } diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index 9372e5a4cadc..e8dd47bffe43 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -575,6 +575,26 @@ static void sfp_upstream_clear(struct sfp_bus *bus) bus->upstream = NULL; } +/** + * sfp_upstream_set_signal_rate() - set data signalling rate + * @bus: a pointer to the &struct sfp_bus structure for the sfp module + * @rate_kbd: signalling rate in units of 1000 baud + * + * Configure the rate select settings on the SFP module for the signalling + * rate (not the same as the data rate). + * + * Locks that may be held: + * Phylink's state_mutex + * rtnl lock + * SFP's sm_mutex + */ +void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd) +{ + if (bus->registered) + bus->socket_ops->set_signal_rate(bus->sfp, rate_kbd); +} +EXPORT_SYMBOL_GPL(sfp_upstream_set_signal_rate); + /** * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode * @fwnode: firmware node for the parent device (MAC or PHY) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index bf7dac9977e1..34bf724c00c7 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -2527,6 +2527,10 @@ static void sfp_stop(struct sfp *sfp) sfp_sm_event(sfp, SFP_E_DEV_DOWN); } +static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd) +{ +} + static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo) { /* locking... and check module is present */ @@ -2611,6 +2615,7 @@ static const struct sfp_socket_ops sfp_module_ops = { .detach = sfp_detach, .start = sfp_start, .stop = sfp_stop, + .set_signal_rate = sfp_set_signal_rate, .module_info = sfp_module_info, .module_eeprom = sfp_module_eeprom, .module_eeprom_by_page = sfp_module_eeprom_by_page, diff --git a/drivers/net/phy/sfp.h b/drivers/net/phy/sfp.h index 6cf1643214d3..c7cb50d10099 100644 --- a/drivers/net/phy/sfp.h +++ b/drivers/net/phy/sfp.h @@ -19,6 +19,7 @@ struct sfp_socket_ops { void (*detach)(struct sfp *sfp); void (*start)(struct sfp *sfp); void (*stop)(struct sfp *sfp); + void (*set_signal_rate)(struct sfp *sfp, unsigned int rate_kbd); int (*module_info)(struct sfp *sfp, struct ethtool_modinfo *modinfo); int (*module_eeprom)(struct sfp *sfp, struct ethtool_eeprom *ee, u8 *data); diff --git a/include/linux/sfp.h b/include/linux/sfp.h index ef06a195b3c2..2f66e03e9dbd 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h @@ -556,6 +556,7 @@ int sfp_get_module_eeprom_by_page(struct sfp_bus *bus, struct netlink_ext_ack *extack); void sfp_upstream_start(struct sfp_bus *bus); void sfp_upstream_stop(struct sfp_bus *bus); +void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd); void sfp_bus_put(struct sfp_bus *bus); struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode); int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, @@ -615,6 +616,11 @@ static inline void sfp_upstream_stop(struct sfp_bus *bus) { } +static inline void sfp_upstream_set_signal_rate(struct sfp_bus *bus, + unsigned int rate_kbd) +{ +} + static inline void sfp_bus_put(struct sfp_bus *bus) { } -- cgit v1.2.3 From fc082b39d0a29891ab4b54c88a40f42385103f71 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 17 May 2023 11:38:17 +0100 Subject: net: sfp: add support for rate selection Add support for parsing the rate select thresholds and switching of the RS0 and RS1 signals to the transceiver. This is complicated by various revisions of SFF-8472 and interaction of SFF-8431, SFF-8079 and INF-8074. Reviewed-by: Simon Horman Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 212 ++++++++++++++++++++++++++++++++++++++++++++------ include/linux/sfp.h | 8 ++ 2 files changed, 196 insertions(+), 24 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 34bf724c00c7..4799976a1609 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -24,14 +24,18 @@ enum { GPIO_LOS, GPIO_TX_FAULT, GPIO_TX_DISABLE, - GPIO_RATE_SELECT, + GPIO_RS0, + GPIO_RS1, GPIO_MAX, SFP_F_PRESENT = BIT(GPIO_MODDEF0), SFP_F_LOS = BIT(GPIO_LOS), SFP_F_TX_FAULT = BIT(GPIO_TX_FAULT), SFP_F_TX_DISABLE = BIT(GPIO_TX_DISABLE), - SFP_F_RATE_SELECT = BIT(GPIO_RATE_SELECT), + SFP_F_RS0 = BIT(GPIO_RS0), + SFP_F_RS1 = BIT(GPIO_RS1), + + SFP_F_OUTPUTS = SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1, SFP_E_INSERT = 0, SFP_E_REMOVE, @@ -148,6 +152,7 @@ static const char *gpio_names[] = { "tx-fault", "tx-disable", "rate-select0", + "rate-select1", }; static const enum gpiod_flags gpio_flags[] = { @@ -156,6 +161,7 @@ static const enum gpiod_flags gpio_flags[] = { GPIOD_IN, GPIOD_ASIS, GPIOD_ASIS, + GPIOD_ASIS, }; /* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a @@ -249,6 +255,7 @@ struct sfp { * state: st_mutex held unless reading input bits */ struct mutex st_mutex; /* Protects state */ + unsigned int state_hw_drive; unsigned int state_hw_mask; unsigned int state_soft_mask; unsigned int state; @@ -269,6 +276,10 @@ struct sfp { unsigned int module_t_start_up; unsigned int module_t_wait; + unsigned int rate_kbd; + unsigned int rs_threshold_kbd; + unsigned int rs_state_mask; + bool have_a2; bool tx_fault_ignore; @@ -319,7 +330,7 @@ static bool sfp_module_supported(const struct sfp_eeprom_id *id) static const struct sff_data sfp_data = { .gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT | - SFP_F_TX_DISABLE | SFP_F_RATE_SELECT, + SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1, .module_supported = sfp_module_supported, }; @@ -507,20 +518,37 @@ static unsigned int sff_gpio_get_state(struct sfp *sfp) static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state) { - if (state & SFP_F_PRESENT) { - /* If the module is present, drive the signals */ - if (sfp->gpio[GPIO_TX_DISABLE]) + unsigned int drive; + + if (state & SFP_F_PRESENT) + /* If the module is present, drive the requested signals */ + drive = sfp->state_hw_drive; + else + /* Otherwise, let them float to the pull-ups */ + drive = 0; + + if (sfp->gpio[GPIO_TX_DISABLE]) { + if (drive & SFP_F_TX_DISABLE) gpiod_direction_output(sfp->gpio[GPIO_TX_DISABLE], state & SFP_F_TX_DISABLE); - if (state & SFP_F_RATE_SELECT) - gpiod_direction_output(sfp->gpio[GPIO_RATE_SELECT], - state & SFP_F_RATE_SELECT); - } else { - /* Otherwise, let them float to the pull-ups */ - if (sfp->gpio[GPIO_TX_DISABLE]) + else gpiod_direction_input(sfp->gpio[GPIO_TX_DISABLE]); - if (state & SFP_F_RATE_SELECT) - gpiod_direction_input(sfp->gpio[GPIO_RATE_SELECT]); + } + + if (sfp->gpio[GPIO_RS0]) { + if (drive & SFP_F_RS0) + gpiod_direction_output(sfp->gpio[GPIO_RS0], + state & SFP_F_RS0); + else + gpiod_direction_input(sfp->gpio[GPIO_RS0]); + } + + if (sfp->gpio[GPIO_RS1]) { + if (drive & SFP_F_RS1) + gpiod_direction_output(sfp->gpio[GPIO_RS1], + state & SFP_F_RS1); + else + gpiod_direction_input(sfp->gpio[GPIO_RS1]); } } @@ -682,16 +710,33 @@ static unsigned int sfp_soft_get_state(struct sfp *sfp) return state & sfp->state_soft_mask; } -static void sfp_soft_set_state(struct sfp *sfp, unsigned int state) +static void sfp_soft_set_state(struct sfp *sfp, unsigned int state, + unsigned int soft) { - u8 mask = SFP_STATUS_TX_DISABLE_FORCE; + u8 mask = 0; u8 val = 0; + if (soft & SFP_F_TX_DISABLE) + mask |= SFP_STATUS_TX_DISABLE_FORCE; if (state & SFP_F_TX_DISABLE) val |= SFP_STATUS_TX_DISABLE_FORCE; + if (soft & SFP_F_RS0) + mask |= SFP_STATUS_RS0_SELECT; + if (state & SFP_F_RS0) + val |= SFP_STATUS_RS0_SELECT; + + if (mask) + sfp_modify_u8(sfp, true, SFP_STATUS, mask, val); - sfp_modify_u8(sfp, true, SFP_STATUS, mask, val); + val = mask = 0; + if (soft & SFP_F_RS1) + mask |= SFP_EXT_STATUS_RS1_SELECT; + if (state & SFP_F_RS1) + val |= SFP_EXT_STATUS_RS1_SELECT; + + if (mask) + sfp_modify_u8(sfp, true, SFP_EXT_STATUS, mask, val); } static void sfp_soft_start_poll(struct sfp *sfp) @@ -705,6 +750,8 @@ static void sfp_soft_start_poll(struct sfp *sfp) mask |= SFP_F_TX_FAULT; if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS) mask |= SFP_F_LOS; + if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RATE_SELECT) + mask |= sfp->rs_state_mask; mutex_lock(&sfp->st_mutex); // Poll the soft state for hardware pins we want to ignore @@ -743,11 +790,13 @@ static unsigned int sfp_get_state(struct sfp *sfp) */ static void sfp_set_state(struct sfp *sfp, unsigned int state) { + unsigned int soft; + sfp->set_state(sfp, state); - if (state & SFP_F_PRESENT && - sfp->state_soft_mask & SFP_F_TX_DISABLE) - sfp_soft_set_state(sfp, state); + soft = sfp->state_soft_mask & SFP_F_OUTPUTS; + if (state & SFP_F_PRESENT && soft) + sfp_soft_set_state(sfp, state, soft); } static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set) @@ -1589,10 +1638,15 @@ static int sfp_debug_state_show(struct seq_file *s, void *data) sfp->sm_fault_retries); seq_printf(s, "PHY probe remaining retries: %d\n", sfp->sm_phy_retries); + seq_printf(s, "Signalling rate: %u kBd\n", sfp->rate_kbd); + seq_printf(s, "Rate select threshold: %u kBd\n", + sfp->rs_threshold_kbd); seq_printf(s, "moddef0: %d\n", !!(sfp->state & SFP_F_PRESENT)); seq_printf(s, "rx_los: %d\n", !!(sfp->state & SFP_F_LOS)); seq_printf(s, "tx_fault: %d\n", !!(sfp->state & SFP_F_TX_FAULT)); seq_printf(s, "tx_disable: %d\n", !!(sfp->state & SFP_F_TX_DISABLE)); + seq_printf(s, "rs0: %d\n", !!(sfp->state & SFP_F_RS0)); + seq_printf(s, "rs1: %d\n", !!(sfp->state & SFP_F_RS1)); return 0; } DEFINE_SHOW_ATTRIBUTE(sfp_debug_state); @@ -1898,6 +1952,95 @@ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable) return 0; } +static void sfp_module_parse_rate_select(struct sfp *sfp) +{ + u8 rate_id; + + sfp->rs_threshold_kbd = 0; + sfp->rs_state_mask = 0; + + if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_RATE_SELECT))) + /* No support for RateSelect */ + return; + + /* Default to INF-8074 RateSelect operation. The signalling threshold + * rate is not well specified, so always select "Full Bandwidth", but + * SFF-8079 reveals that it is understood that RS0 will be low for + * 1.0625Gb/s and high for 2.125Gb/s. Choose a value half-way between. + * This method exists prior to SFF-8472. + */ + sfp->rs_state_mask = SFP_F_RS0; + sfp->rs_threshold_kbd = 1594; + + /* Parse the rate identifier, which is complicated due to history: + * SFF-8472 rev 9.5 marks this field as reserved. + * SFF-8079 references SFF-8472 rev 9.5 and defines bit 0. SFF-8472 + * compliance is not required. + * SFF-8472 rev 10.2 defines this field using values 0..4 + * SFF-8472 rev 11.0 redefines this field with bit 0 for SFF-8079 + * and even values. + */ + rate_id = sfp->id.base.rate_id; + if (rate_id == 0) + /* Unspecified */ + return; + + /* SFF-8472 rev 10.0..10.4 did not account for SFF-8079 using bit 0, + * and allocated value 3 to SFF-8431 independent tx/rx rate select. + * Convert this to a SFF-8472 rev 11.0 rate identifier. + */ + if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 && + sfp->id.ext.sff8472_compliance < SFP_SFF8472_COMPLIANCE_REV11_0 && + rate_id == 3) + rate_id = SFF_RID_8431; + + if (rate_id & SFF_RID_8079) { + /* SFF-8079 RateSelect / Application Select in conjunction with + * SFF-8472 rev 9.5. SFF-8079 defines rate_id as a bitfield + * with only bit 0 used, which takes precedence over SFF-8472. + */ + if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_APP_SELECT_SFF8079)) { + /* SFF-8079 Part 1 - rate selection between Fibre + * Channel 1.0625/2.125/4.25 Gbd modes. Note that RS0 + * is high for 2125, so we have to subtract 1 to + * include it. + */ + sfp->rs_threshold_kbd = 2125 - 1; + sfp->rs_state_mask = SFP_F_RS0; + } + return; + } + + /* SFF-8472 rev 9.5 does not define the rate identifier */ + if (sfp->id.ext.sff8472_compliance <= SFP_SFF8472_COMPLIANCE_REV9_5) + return; + + /* SFF-8472 rev 11.0 defines rate_id as a numerical value which will + * always have bit 0 clear due to SFF-8079's bitfield usage of rate_id. + */ + switch (rate_id) { + case SFF_RID_8431_RX_ONLY: + sfp->rs_threshold_kbd = 4250; + sfp->rs_state_mask = SFP_F_RS0; + break; + + case SFF_RID_8431_TX_ONLY: + sfp->rs_threshold_kbd = 4250; + sfp->rs_state_mask = SFP_F_RS1; + break; + + case SFF_RID_8431: + sfp->rs_threshold_kbd = 4250; + sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1; + break; + + case SFF_RID_10G8G: + sfp->rs_threshold_kbd = 9000; + sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1; + break; + } +} + /* GPON modules based on Realtek RTL8672 and RTL9601C chips (e.g. V-SOL * V2801F, CarlitoxxPro CPGOS03-0490, Ubiquiti U-Fiber Instant, ...) do * not support multibyte reads from the EEPROM. Each multi-byte read @@ -2117,6 +2260,8 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) if (ret < 0) return ret; + sfp_module_parse_rate_select(sfp); + mask = SFP_F_PRESENT; if (sfp->gpio[GPIO_TX_DISABLE]) mask |= SFP_F_TX_DISABLE; @@ -2124,6 +2269,10 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) mask |= SFP_F_TX_FAULT; if (sfp->gpio[GPIO_LOS]) mask |= SFP_F_LOS; + if (sfp->gpio[GPIO_RS0]) + mask |= SFP_F_RS0; + if (sfp->gpio[GPIO_RS1]) + mask |= SFP_F_RS1; sfp->module_t_start_up = T_START_UP; sfp->module_t_wait = T_WAIT; @@ -2146,6 +2295,9 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) /* Initialise state bits to use from hardware */ sfp->state_hw_mask = mask; + /* We want to drive the rate select pins that the module is using */ + sfp->state_hw_drive |= sfp->rs_state_mask; + if (sfp->quirk && sfp->quirk->fixup) sfp->quirk->fixup(sfp); mutex_unlock(&sfp->st_mutex); @@ -2162,6 +2314,7 @@ static void sfp_sm_mod_remove(struct sfp *sfp) memset(&sfp->id, 0, sizeof(sfp->id)); sfp->module_power_mW = 0; + sfp->state_hw_drive = SFP_F_TX_DISABLE; sfp->have_a2 = false; dev_info(sfp->dev, "module removed\n"); @@ -2529,6 +2682,16 @@ static void sfp_stop(struct sfp *sfp) static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd) { + unsigned int set; + + sfp->rate_kbd = rate_kbd; + + if (rate_kbd > sfp->rs_threshold_kbd) + set = sfp->rs_state_mask; + else + set = 0; + + sfp_mod_state(sfp, SFP_F_RS0 | SFP_F_RS1, set); } static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo) @@ -2648,7 +2811,7 @@ static void sfp_check_state(struct sfp *sfp) dev_dbg(sfp->dev, "%s %u -> %u\n", gpio_names[i], !!(sfp->state & BIT(i)), !!(state & BIT(i))); - state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT); + state |= sfp->state & SFP_F_OUTPUTS; sfp->state = state; mutex_unlock(&sfp->st_mutex); @@ -2790,6 +2953,7 @@ static int sfp_probe(struct platform_device *pdev) } sfp->state_hw_mask = SFP_F_PRESENT; + sfp->state_hw_drive = SFP_F_TX_DISABLE; sfp->get_state = sfp_gpio_get_state; sfp->set_state = sfp_gpio_set_state; @@ -2815,9 +2979,9 @@ static int sfp_probe(struct platform_device *pdev) */ sfp->state = sfp_get_state(sfp) | SFP_F_TX_DISABLE; - if (sfp->gpio[GPIO_RATE_SELECT] && - gpiod_get_value_cansleep(sfp->gpio[GPIO_RATE_SELECT])) - sfp->state |= SFP_F_RATE_SELECT; + if (sfp->gpio[GPIO_RS0] && + gpiod_get_value_cansleep(sfp->gpio[GPIO_RS0])) + sfp->state |= SFP_F_RS0; sfp_set_state(sfp, sfp->state); sfp_module_tx_disable(sfp); if (sfp->state & SFP_F_PRESENT) { diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 2f66e03e9dbd..9346cd44814d 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h @@ -342,6 +342,12 @@ enum { SFP_ENCODING = 11, SFP_BR_NOMINAL = 12, SFP_RATE_ID = 13, + SFF_RID_8079 = 0x01, + SFF_RID_8431_RX_ONLY = 0x02, + SFF_RID_8431_TX_ONLY = 0x04, + SFF_RID_8431 = 0x06, + SFF_RID_10G8G = 0x0e, + SFP_LINK_LEN_SM_KM = 14, SFP_LINK_LEN_SM_100M = 15, SFP_LINK_LEN_50UM_OM2_10M = 16, @@ -465,6 +471,7 @@ enum { SFP_STATUS = 110, SFP_STATUS_TX_DISABLE = BIT(7), SFP_STATUS_TX_DISABLE_FORCE = BIT(6), + SFP_STATUS_RS0_SELECT = BIT(3), SFP_STATUS_TX_FAULT = BIT(2), SFP_STATUS_RX_LOS = BIT(1), SFP_ALARM0 = 112, @@ -496,6 +503,7 @@ enum { SFP_WARN1_RXPWR_LOW = BIT(6), SFP_EXT_STATUS = 118, + SFP_EXT_STATUS_RS1_SELECT = BIT(3), SFP_EXT_STATUS_PWRLVL_SELECT = BIT(0), SFP_VSL = 120, -- cgit v1.2.3 From 711bdd5141d81ab21dbe0a533024d594210d5ba4 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 17 May 2023 12:16:14 -0700 Subject: inet: factor out locked section of inet_accept() in a new helper No functional changes intended. The new helper will be used by the MPTCP protocol in the next patch to avoid duplicating a few LoC. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski --- include/net/inet_common.h | 2 ++ net/ipv4/af_inet.c | 32 +++++++++++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/include/net/inet_common.h b/include/net/inet_common.h index cec453c18f1d..77f4b0ef5b92 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -31,6 +31,8 @@ int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags); int inet_accept(struct socket *sock, struct socket *newsock, int flags, bool kern); +void __inet_accept(struct socket *sock, struct socket *newsock, + struct sock *newsk); int inet_send_prepare(struct sock *sk); int inet_sendmsg(struct socket *sock, struct msghdr *msg, size_t size); ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c4aab3aacbd8..946650036c7f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -730,6 +730,20 @@ int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, } EXPORT_SYMBOL(inet_stream_connect); +void __inet_accept(struct socket *sock, struct socket *newsock, struct sock *newsk) +{ + sock_rps_record_flow(newsk); + WARN_ON(!((1 << newsk->sk_state) & + (TCPF_ESTABLISHED | TCPF_SYN_RECV | + TCPF_CLOSE_WAIT | TCPF_CLOSE))); + + if (test_bit(SOCK_SUPPORT_ZC, &sock->flags)) + set_bit(SOCK_SUPPORT_ZC, &newsock->flags); + sock_graft(newsk, newsock); + + newsock->state = SS_CONNECTED; +} + /* * Accept a pending connection. The TCP layer now gives BSD semantics. */ @@ -743,24 +757,12 @@ int inet_accept(struct socket *sock, struct socket *newsock, int flags, /* IPV6_ADDRFORM can change sk->sk_prot under us. */ sk2 = READ_ONCE(sk1->sk_prot)->accept(sk1, flags, &err, kern); if (!sk2) - goto do_err; + return err; lock_sock(sk2); - - sock_rps_record_flow(sk2); - WARN_ON(!((1 << sk2->sk_state) & - (TCPF_ESTABLISHED | TCPF_SYN_RECV | - TCPF_CLOSE_WAIT | TCPF_CLOSE))); - - if (test_bit(SOCK_SUPPORT_ZC, &sock->flags)) - set_bit(SOCK_SUPPORT_ZC, &newsock->flags); - sock_graft(sk2, newsock); - - newsock->state = SS_CONNECTED; - err = 0; + __inet_accept(sock, newsock, sk2); release_sock(sk2); -do_err: - return err; + return 0; } EXPORT_SYMBOL(inet_accept); -- cgit v1.2.3 From e76c8ef5cc5b77debe711717f61a3fbf24904873 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 17 May 2023 12:16:15 -0700 Subject: mptcp: refactor mptcp_stream_accept() Rewrite the mptcp socket accept op, leveraging the new __inet_accept() helper. This way we can avoid acquiring the new socket lock twice and we can avoid a couple of indirect calls. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 08dc53f56bc2..2d331b2d62b7 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3747,6 +3747,7 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock, { struct mptcp_sock *msk = mptcp_sk(sock->sk); struct socket *ssock; + struct sock *newsk; int err; pr_debug("msk=%p", msk); @@ -3758,17 +3759,20 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock, if (!ssock) return -EINVAL; - err = ssock->ops->accept(sock, newsock, flags, kern); - if (err == 0 && !mptcp_is_tcpsk(newsock->sk)) { - struct mptcp_sock *msk = mptcp_sk(newsock->sk); + newsk = mptcp_accept(sock->sk, flags, &err, kern); + if (!newsk) + return err; + + lock_sock(newsk); + + __inet_accept(sock, newsock, newsk); + if (!mptcp_is_tcpsk(newsock->sk)) { + struct mptcp_sock *msk = mptcp_sk(newsk); struct mptcp_subflow_context *subflow; - struct sock *newsk = newsock->sk; set_bit(SOCK_CUSTOM_SOCKOPT, &newsock->flags); msk->in_accept_queue = 0; - lock_sock(newsk); - /* set ssk->sk_socket of accept()ed flows to mptcp socket. * This is needed so NOSPACE flag can be set from tcp stack. */ @@ -3789,11 +3793,10 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock, if (unlikely(list_empty(&msk->conn_list))) inet_sk_state_store(newsk, TCP_CLOSE); } - - release_sock(newsk); } + release_sock(newsk); - return err; + return 0; } static __poll_t mptcp_check_writeable(struct mptcp_sock *msk) -- cgit v1.2.3 From 45b1a1227a7aaa99254551c513406c7aa904e968 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 17 May 2023 12:16:16 -0700 Subject: mptcp: introduces more address related mibs Currently we don't track explicitly a few events related to address management suboption handling; this patch adds new mibs for ADD_ADDR and RM_ADDR options tx and for missed tx events due to internal storage exhaustion. The self-tests must be updated to properly handle different mibs with the same/shared prefix. Additionally removes a couple of warning tracking the loss event. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/378 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski --- net/mptcp/mib.c | 6 ++++++ net/mptcp/mib.h | 18 ++++++++++++++++++ net/mptcp/options.c | 5 ++++- net/mptcp/pm.c | 6 ++++-- tools/testing/selftests/net/mptcp/mptcp_join.sh | 4 ++-- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index 0dac2863c6e1..a0990c365a2e 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -34,7 +34,11 @@ static const struct snmp_mib mptcp_snmp_list[] = { SNMP_MIB_ITEM("NoDSSInWindow", MPTCP_MIB_NODSSWINDOW), SNMP_MIB_ITEM("DuplicateData", MPTCP_MIB_DUPDATA), SNMP_MIB_ITEM("AddAddr", MPTCP_MIB_ADDADDR), + SNMP_MIB_ITEM("AddAddrTx", MPTCP_MIB_ADDADDRTX), + SNMP_MIB_ITEM("AddAddrTxDrop", MPTCP_MIB_ADDADDRTXDROP), SNMP_MIB_ITEM("EchoAdd", MPTCP_MIB_ECHOADD), + SNMP_MIB_ITEM("EchoAddTx", MPTCP_MIB_ECHOADDTX), + SNMP_MIB_ITEM("EchoAddTxDrop", MPTCP_MIB_ECHOADDTXDROP), SNMP_MIB_ITEM("PortAdd", MPTCP_MIB_PORTADD), SNMP_MIB_ITEM("AddAddrDrop", MPTCP_MIB_ADDADDRDROP), SNMP_MIB_ITEM("MPJoinPortSynRx", MPTCP_MIB_JOINPORTSYNRX), @@ -44,6 +48,8 @@ static const struct snmp_mib mptcp_snmp_list[] = { SNMP_MIB_ITEM("MismatchPortAckRx", MPTCP_MIB_MISMATCHPORTACKRX), SNMP_MIB_ITEM("RmAddr", MPTCP_MIB_RMADDR), SNMP_MIB_ITEM("RmAddrDrop", MPTCP_MIB_RMADDRDROP), + SNMP_MIB_ITEM("RmAddrTx", MPTCP_MIB_RMADDRTX), + SNMP_MIB_ITEM("RmAddrTxDrop", MPTCP_MIB_RMADDRTXDROP), SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW), SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX), SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX), diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index 2be3596374f4..cae71d947252 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -27,7 +27,15 @@ enum linux_mptcp_mib_field { MPTCP_MIB_NODSSWINDOW, /* Segments not in MPTCP windows */ MPTCP_MIB_DUPDATA, /* Segments discarded due to duplicate DSS */ MPTCP_MIB_ADDADDR, /* Received ADD_ADDR with echo-flag=0 */ + MPTCP_MIB_ADDADDRTX, /* Sent ADD_ADDR with echo-flag=0 */ + MPTCP_MIB_ADDADDRTXDROP, /* ADD_ADDR with echo-flag=0 not send due to + * resource exhaustion + */ MPTCP_MIB_ECHOADD, /* Received ADD_ADDR with echo-flag=1 */ + MPTCP_MIB_ECHOADDTX, /* Send ADD_ADDR with echo-flag=1 */ + MPTCP_MIB_ECHOADDTXDROP, /* ADD_ADDR with echo-flag=1 not send due + * to resource exhaustion + */ MPTCP_MIB_PORTADD, /* Received ADD_ADDR with a port-number */ MPTCP_MIB_ADDADDRDROP, /* Dropped incoming ADD_ADDR */ MPTCP_MIB_JOINPORTSYNRX, /* Received a SYN MP_JOIN with a different port-number */ @@ -37,6 +45,8 @@ enum linux_mptcp_mib_field { MPTCP_MIB_MISMATCHPORTACKRX, /* Received an ACK MP_JOIN with a mismatched port-number */ MPTCP_MIB_RMADDR, /* Received RM_ADDR */ MPTCP_MIB_RMADDRDROP, /* Dropped incoming RM_ADDR */ + MPTCP_MIB_RMADDRTX, /* Sent RM_ADDR */ + MPTCP_MIB_RMADDRTXDROP, /* RM_ADDR not sent due to resource exhaustion */ MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */ MPTCP_MIB_MPPRIOTX, /* Transmit a MP_PRIO */ MPTCP_MIB_MPPRIORX, /* Received a MP_PRIO */ @@ -63,6 +73,14 @@ struct mptcp_mib { unsigned long mibs[LINUX_MIB_MPTCP_MAX]; }; +static inline void MPTCP_ADD_STATS(struct net *net, + enum linux_mptcp_mib_field field, + int val) +{ + if (likely(net->mib.mptcp_statistics)) + SNMP_ADD_STATS(net->mib.mptcp_statistics, field, val); +} + static inline void MPTCP_INC_STATS(struct net *net, enum linux_mptcp_mib_field field) { diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 19a01b6566f1..8a8083207be4 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -687,9 +687,12 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff * } opts->suboptions |= OPTION_MPTCP_ADD_ADDR; if (!echo) { + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRTX); opts->ahmac = add_addr_generate_hmac(msk->local_key, msk->remote_key, &opts->addr); + } else { + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADDTX); } pr_debug("addr_id=%d, ahmac=%llu, echo=%d, port=%d", opts->addr.id, opts->ahmac, echo, ntohs(opts->addr.port)); @@ -723,7 +726,7 @@ static bool mptcp_established_options_rm_addr(struct sock *sk, for (i = 0; i < opts->rm_list.nr; i++) pr_debug("rm_list_ids[%d]=%d", i, opts->rm_list.ids[i]); - + MPTCP_ADD_STATS(sock_net(sk), MPTCP_MIB_RMADDRTX, opts->rm_list.nr); return true; } diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 78c924506e83..7d03b5fd8200 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -26,7 +26,8 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk, if (add_addr & (echo ? BIT(MPTCP_ADD_ADDR_ECHO) : BIT(MPTCP_ADD_ADDR_SIGNAL))) { - pr_warn("addr_signal error, add_addr=%d, echo=%d", add_addr, echo); + MPTCP_INC_STATS(sock_net((struct sock *)msk), + echo ? MPTCP_MIB_ECHOADDTXDROP : MPTCP_MIB_ADDADDRTXDROP); return -EINVAL; } @@ -48,7 +49,8 @@ int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_ pr_debug("msk=%p, rm_list_nr=%d", msk, rm_list->nr); if (rm_addr) { - pr_warn("addr_signal error, rm_addr=%d", rm_addr); + MPTCP_ADD_STATS(sock_net((struct sock *)msk), + MPTCP_MIB_RMADDRTXDROP, rm_list->nr); return -EINVAL; } diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 26310c17b4c6..0886ed2c59ea 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1492,7 +1492,7 @@ chk_add_nr() fi echo -n " - echo " - count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtEchoAdd | awk '{print $2}') + count=$(ip netns exec $ns1 nstat -as MPTcpExtEchoAdd | grep MPTcpExtEchoAdd | awk '{print $2}') [ -z "$count" ] && count=0 if [ "$count" != "$echo_nr" ]; then echo "[fail] got $count ADD_ADDR echo[s] expected $echo_nr" @@ -1614,7 +1614,7 @@ chk_rm_nr() fi printf "%-${nr_blank}s %s" " " "rm " - count=$(ip netns exec $addr_ns nstat -as | grep MPTcpExtRmAddr | awk '{print $2}') + count=$(ip netns exec $addr_ns nstat -as MPTcpExtRmAddr | grep MPTcpExtRmAddr | awk '{print $2}') [ -z "$count" ] && count=0 if [ "$count" != "$rm_addr_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr" -- cgit v1.2.3 From 0639fa230a21062567222bd99f2996e9da6c232c Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 17 May 2023 12:16:17 -0700 Subject: selftests: mptcp: add explicit check for new mibs Instead of duplicating the all existing TX check with the TX side, add the new ones on selected test cases. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 62 +++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 0886ed2c59ea..ca5bd2c3434a 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1585,6 +1585,44 @@ chk_add_nr() [ "${dump_stats}" = 1 ] && dump_stats } +chk_add_tx_nr() +{ + local add_tx_nr=$1 + local echo_tx_nr=$2 + local dump_stats + local timeout + local count + + timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout) + + printf "%-${nr_blank}s %s" " " "add TX" + count=$(ip netns exec $ns1 nstat -as MPTcpExtAddAddrTx | grep MPTcpExtAddAddrTx | awk '{print $2}') + [ -z "$count" ] && count=0 + + # if the test configured a short timeout tolerate greater then expected + # add addrs options, due to retransmissions + if [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then + echo "[fail] got $count ADD_ADDR[s] TX, expected $add_tx_nr" + fail_test + dump_stats=1 + else + echo -n "[ ok ]" + fi + + echo -n " - echo TX " + count=$(ip netns exec $ns2 nstat -as MPTcpExtEchoAddTx | grep MPTcpExtEchoAddTx | awk '{print $2}') + [ -z "$count" ] && count=0 + if [ "$count" != "$echo_tx_nr" ]; then + echo "[fail] got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr" + fail_test + dump_stats=1 + else + echo "[ ok ]" + fi + + [ "${dump_stats}" = 1 ] && dump_stats +} + chk_rm_nr() { local rm_addr_nr=$1 @@ -1660,6 +1698,26 @@ chk_rm_nr() echo "$extra_msg" } +chk_rm_tx_nr() +{ + local rm_addr_tx_nr=$1 + + printf "%-${nr_blank}s %s" " " "rm TX " + count=$(ip netns exec $ns2 nstat -as MPTcpExtRmAddrTx | grep MPTcpExtRmAddrTx | awk '{print $2}') + [ -z "$count" ] && count=0 + if [ "$count" != "$rm_addr_tx_nr" ]; then + echo "[fail] got $count RM_ADDR[s] expected $rm_addr_tx_nr" + fail_test + dump_stats=1 + else + echo -n "[ ok ]" + fi + + [ "${dump_stats}" = 1 ] && dump_stats + + echo "$extra_msg" +} + chk_prio_nr() { local mp_prio_nr_tx=$1 @@ -1939,6 +1997,7 @@ signal_address_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 + chk_add_tx_nr 1 1 chk_add_nr 1 1 fi @@ -2120,6 +2179,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow chk_join_nr 1 1 1 + chk_add_tx_nr 4 4 chk_add_nr 4 0 fi @@ -2165,6 +2225,7 @@ remove_tests() pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow run_tests $ns1 $ns2 10.0.1.1 0 0 -1 slow chk_join_nr 1 1 1 + chk_rm_tx_nr 1 chk_rm_nr 1 1 fi @@ -2263,6 +2324,7 @@ remove_tests() pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow chk_join_nr 3 3 3 + chk_rm_tx_nr 0 chk_rm_nr 0 3 simult fi -- cgit v1.2.3 From 985de45923e29087a2dcf34bb71f24641d6cc55f Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 17 May 2023 12:16:18 -0700 Subject: selftests: mptcp: centralize stats dumping If a test case fails, the mptcp_join.sh script can dump the netns MIBs multiple times, leading to confusing output. Let's dump such info only once per test-case, when needed. This additionally allow removing some code duplication. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Mat Martineau Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 66 ++----------------------- 1 file changed, 5 insertions(+), 61 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index ca5bd2c3434a..e74d3074ef90 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -34,6 +34,7 @@ evts_ns1="" evts_ns2="" evts_ns1_pid=0 evts_ns2_pid=0 +stats_dumped=0 declare -A all_tests declare -a only_tests_ids @@ -87,6 +88,7 @@ init_partial() fi done + stats_dumped=0 check_invert=0 validate_checksum=$checksum FAILING_LINKS="" @@ -347,6 +349,9 @@ fail_test() { ret=1 failed_tests[${TEST_COUNT}]="${TEST_NAME}" + + [ "${stats_dumped}" = 0 ] && dump_stats + stats_dumped=1 } get_failed_tests_ids() @@ -1120,7 +1125,6 @@ chk_csum_nr() local csum_ns1=${1:-0} local csum_ns2=${2:-0} local count - local dump_stats local extra_msg="" local allow_multi_errors_ns1=0 local allow_multi_errors_ns2=0 @@ -1144,7 +1148,6 @@ chk_csum_nr() { [ "$count" -lt $csum_ns1 ] && [ $allow_multi_errors_ns1 -eq 1 ]; }; then echo "[fail] got $count data checksum error[s] expected $csum_ns1" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1158,11 +1161,9 @@ chk_csum_nr() { [ "$count" -lt $csum_ns2 ] && [ $allow_multi_errors_ns2 -eq 1 ]; }; then echo "[fail] got $count data checksum error[s] expected $csum_ns2" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats echo "$extra_msg" } @@ -1173,7 +1174,6 @@ chk_fail_nr() local fail_rx=$2 local ns_invert=${3:-""} local count - local dump_stats local ns_tx=$ns1 local ns_rx=$ns2 local extra_msg="" @@ -1205,7 +1205,6 @@ chk_fail_nr() { [ "$count" -gt "$fail_tx" ] && [ $allow_tx_lost -eq 1 ]; }; then echo "[fail] got $count MP_FAIL[s] TX expected $fail_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1220,13 +1219,10 @@ chk_fail_nr() { [ "$count" -gt "$fail_rx" ] && [ $allow_rx_lost -eq 1 ]; }; then echo "[fail] got $count MP_FAIL[s] RX expected $fail_rx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1236,7 +1232,6 @@ chk_fclose_nr() local fclose_rx=$2 local ns_invert=$3 local count - local dump_stats local ns_tx=$ns2 local ns_rx=$ns1 local extra_msg=" " @@ -1254,7 +1249,6 @@ chk_fclose_nr() if [ "$count" != "$fclose_tx" ]; then echo "[fail] got $count MP_FASTCLOSE[s] TX expected $fclose_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1266,13 +1260,10 @@ chk_fclose_nr() if [ "$count" != "$fclose_rx" ]; then echo "[fail] got $count MP_FASTCLOSE[s] RX expected $fclose_rx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1282,7 +1273,6 @@ chk_rst_nr() local rst_rx=$2 local ns_invert=${3:-""} local count - local dump_stats local ns_tx=$ns1 local ns_rx=$ns2 local extra_msg="" @@ -1299,7 +1289,6 @@ chk_rst_nr() if [ $count -lt $rst_tx ]; then echo "[fail] got $count MP_RST[s] TX expected $rst_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1310,13 +1299,10 @@ chk_rst_nr() if [ "$count" -lt "$rst_rx" ]; then echo "[fail] got $count MP_RST[s] RX expected $rst_rx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1325,7 +1311,6 @@ chk_infi_nr() local infi_tx=$1 local infi_rx=$2 local count - local dump_stats printf "%-${nr_blank}s %s" " " "itx" count=$(ip netns exec $ns2 nstat -as | grep InfiniteMapTx | awk '{print $2}') @@ -1333,7 +1318,6 @@ chk_infi_nr() if [ "$count" != "$infi_tx" ]; then echo "[fail] got $count infinite map[s] TX expected $infi_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1344,12 +1328,9 @@ chk_infi_nr() if [ "$count" != "$infi_rx" ]; then echo "[fail] got $count infinite map[s] RX expected $infi_rx" fail_test - dump_stats=1 else echo "[ ok ]" fi - - [ "${dump_stats}" = 1 ] && dump_stats } chk_join_nr() @@ -1364,7 +1345,6 @@ chk_join_nr() local infi_nr=${8:-0} local corrupted_pkts=${9:-0} local count - local dump_stats local with_cookie local title="${TEST_NAME}" @@ -1378,7 +1358,6 @@ chk_join_nr() if [ "$count" != "$syn_nr" ]; then echo "[fail] got $count JOIN[s] syn expected $syn_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1396,7 +1375,6 @@ chk_join_nr() else echo "[fail] got $count JOIN[s] synack expected $syn_ack_nr" fail_test - dump_stats=1 fi else echo -n "[ ok ]" @@ -1408,11 +1386,9 @@ chk_join_nr() if [ "$count" != "$ack_nr" ]; then echo "[fail] got $count JOIN[s] ack expected $ack_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats if [ $validate_checksum -eq 1 ]; then chk_csum_nr $csum_ns1 $csum_ns2 chk_fail_nr $fail_nr $fail_nr @@ -1472,7 +1448,6 @@ chk_add_nr() local mis_syn_nr=${7:-0} local mis_ack_nr=${8:-0} local count - local dump_stats local timeout timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout) @@ -1486,7 +1461,6 @@ chk_add_nr() if [ "$count" != "$add_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_nr" ]; }; then echo "[fail] got $count ADD_ADDR[s] expected $add_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1497,7 +1471,6 @@ chk_add_nr() if [ "$count" != "$echo_nr" ]; then echo "[fail] got $count ADD_ADDR echo[s] expected $echo_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1509,7 +1482,6 @@ chk_add_nr() if [ "$count" != "$port_nr" ]; then echo "[fail] got $count ADD_ADDR[s] with a port-number expected $port_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi @@ -1522,7 +1494,6 @@ chk_add_nr() echo "[fail] got $count JOIN[s] syn with a different \ port-number expected $syn_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1535,7 +1506,6 @@ chk_add_nr() echo "[fail] got $count JOIN[s] synack with a different \ port-number expected $syn_ack_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1548,7 +1518,6 @@ chk_add_nr() echo "[fail] got $count JOIN[s] ack with a different \ port-number expected $ack_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi @@ -1561,7 +1530,6 @@ chk_add_nr() echo "[fail] got $count JOIN[s] syn with a mismatched \ port-number expected $mis_syn_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1574,22 +1542,18 @@ chk_add_nr() echo "[fail] got $count JOIN[s] ack with a mismatched \ port-number expected $mis_ack_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi else echo "" fi - - [ "${dump_stats}" = 1 ] && dump_stats } chk_add_tx_nr() { local add_tx_nr=$1 local echo_tx_nr=$2 - local dump_stats local timeout local count @@ -1604,7 +1568,6 @@ chk_add_tx_nr() if [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then echo "[fail] got $count ADD_ADDR[s] TX, expected $add_tx_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1615,12 +1578,9 @@ chk_add_tx_nr() if [ "$count" != "$echo_tx_nr" ]; then echo "[fail] got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr" fail_test - dump_stats=1 else echo "[ ok ]" fi - - [ "${dump_stats}" = 1 ] && dump_stats } chk_rm_nr() @@ -1630,7 +1590,6 @@ chk_rm_nr() local invert local simult local count - local dump_stats local addr_ns=$ns1 local subflow_ns=$ns2 local extra_msg="" @@ -1657,7 +1616,6 @@ chk_rm_nr() if [ "$count" != "$rm_addr_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1681,20 +1639,16 @@ chk_rm_nr() else echo "[fail] got $count RM_SUBFLOW[s] expected in range [$rm_subflow_nr:$((rm_subflow_nr*2))]" fail_test - dump_stats=1 fi return fi if [ "$count" != "$rm_subflow_nr" ]; then echo "[fail] got $count RM_SUBFLOW[s] expected $rm_subflow_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1708,13 +1662,10 @@ chk_rm_tx_nr() if [ "$count" != "$rm_addr_tx_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_tx_nr" fail_test - dump_stats=1 else echo -n "[ ok ]" fi - [ "${dump_stats}" = 1 ] && dump_stats - echo "$extra_msg" } @@ -1723,7 +1674,6 @@ chk_prio_nr() local mp_prio_nr_tx=$1 local mp_prio_nr_rx=$2 local count - local dump_stats printf "%-${nr_blank}s %s" " " "ptx" count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}') @@ -1731,7 +1681,6 @@ chk_prio_nr() if [ "$count" != "$mp_prio_nr_tx" ]; then echo "[fail] got $count MP_PRIO[s] TX expected $mp_prio_nr_tx" fail_test - dump_stats=1 else echo -n "[ ok ]" fi @@ -1742,12 +1691,9 @@ chk_prio_nr() if [ "$count" != "$mp_prio_nr_rx" ]; then echo "[fail] got $count MP_PRIO[s] RX expected $mp_prio_nr_rx" fail_test - dump_stats=1 else echo "[ ok ]" fi - - [ "${dump_stats}" = 1 ] && dump_stats } chk_subflow_nr() @@ -1779,7 +1725,6 @@ chk_subflow_nr() ss -N $ns1 -tOni ss -N $ns1 -tOni | grep token ip -n $ns1 mptcp endpoint - dump_stats fi } @@ -1819,7 +1764,6 @@ chk_mptcp_info() if [ "$dump_stats" = 1 ]; then ss -N $ns1 -inmHM ss -N $ns2 -inmHM - dump_stats fi } -- cgit v1.2.3 From 20d5e0ef252a151ea6585cfccf32def81a624666 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 18 May 2023 22:30:49 +0200 Subject: net: arc: Make arc_emac_remove() return void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function returns zero unconditionally. Change it to return void instead which simplifies its callers as error handing becomes unnecessary. Signed-off-by: Uwe Kleine-König Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/arc/emac.h | 2 +- drivers/net/ethernet/arc/emac_arc.c | 6 +++--- drivers/net/ethernet/arc/emac_main.c | 4 +--- drivers/net/ethernet/arc/emac_rockchip.c | 5 ++--- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h index d820ae03a966..0e244f0e25fd 100644 --- a/drivers/net/ethernet/arc/emac.h +++ b/drivers/net/ethernet/arc/emac.h @@ -220,6 +220,6 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask) int arc_mdio_probe(struct arc_emac_priv *priv); int arc_mdio_remove(struct arc_emac_priv *priv); int arc_emac_probe(struct net_device *ndev, int interface); -int arc_emac_remove(struct net_device *ndev); +void arc_emac_remove(struct net_device *ndev); #endif /* ARC_EMAC_H */ diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c index 800620b8f10d..ce3147e886a1 100644 --- a/drivers/net/ethernet/arc/emac_arc.c +++ b/drivers/net/ethernet/arc/emac_arc.c @@ -61,11 +61,11 @@ out_netdev: static int emac_arc_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); - int err; - err = arc_emac_remove(ndev); + arc_emac_remove(ndev); free_netdev(ndev); - return err; + + return 0; } static const struct of_device_id emac_arc_dt_ids[] = { diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index ba0646b3b122..2b427d8a1831 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -1008,7 +1008,7 @@ out_put_node: } EXPORT_SYMBOL_GPL(arc_emac_probe); -int arc_emac_remove(struct net_device *ndev) +void arc_emac_remove(struct net_device *ndev) { struct arc_emac_priv *priv = netdev_priv(ndev); @@ -1019,8 +1019,6 @@ int arc_emac_remove(struct net_device *ndev) if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); - - return 0; } EXPORT_SYMBOL_GPL(arc_emac_remove); diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c index 1c9ca3bcb871..509101112279 100644 --- a/drivers/net/ethernet/arc/emac_rockchip.c +++ b/drivers/net/ethernet/arc/emac_rockchip.c @@ -248,9 +248,8 @@ static int emac_rockchip_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct rockchip_priv_data *priv = netdev_priv(ndev); - int err; - err = arc_emac_remove(ndev); + arc_emac_remove(ndev); clk_disable_unprepare(priv->refclk); @@ -261,7 +260,7 @@ static int emac_rockchip_remove(struct platform_device *pdev) clk_disable_unprepare(priv->macclk); free_netdev(ndev); - return err; + return 0; } static struct platform_driver emac_rockchip_driver = { -- cgit v1.2.3 From ecd01b69a5f8edda731d8a7cfe33c9ffa0c85700 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Fri, 7 Apr 2023 18:52:15 +0200 Subject: ice: define meta data to match in switch Add description for each meta data. Redefine tunnel mask to match only tunneled MAC and tunneled VLAN. It shouldn't try to match other flags (previously it was 0xff, it is redundant). VLAN mask was 0xd000, change it to 0xf000. 4 last bits are flags depending on the same field in packets (VLAN tag). Because of that, It isn't harmful to match also on ITAG. Group all MDID and MDID offsets into enums to keep things organized. Signed-off-by: Michal Swiatkowski Reviewed-by: Piotr Raczynski Reviewed-by: Simon Horman Reviewed-by: Leon Romanovsky Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_protocol_type.h | 186 +++++++++++++++++++-- drivers/net/ethernet/intel/ice/ice_switch.c | 11 +- drivers/net/ethernet/intel/ice/ice_vlan_mode.c | 2 +- 3 files changed, 183 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_protocol_type.h b/drivers/net/ethernet/intel/ice/ice_protocol_type.h index 02a4e1cf624e..8a84f106bd4d 100644 --- a/drivers/net/ethernet/intel/ice/ice_protocol_type.h +++ b/drivers/net/ethernet/intel/ice/ice_protocol_type.h @@ -115,17 +115,7 @@ enum ice_prot_id { #define ICE_L2TPV3_HW 104 #define ICE_UDP_OF_HW 52 /* UDP Tunnels */ -#define ICE_META_DATA_ID_HW 255 /* this is used for tunnel and VLAN type */ -#define ICE_MDID_SIZE 2 - -#define ICE_TUN_FLAG_MDID 21 -#define ICE_TUN_FLAG_MDID_OFF (ICE_MDID_SIZE * ICE_TUN_FLAG_MDID) -#define ICE_TUN_FLAG_MASK 0xFF - -#define ICE_VLAN_FLAG_MDID 20 -#define ICE_VLAN_FLAG_MDID_OFF (ICE_MDID_SIZE * ICE_VLAN_FLAG_MDID) -#define ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK 0xD000 #define ICE_TUN_FLAG_FV_IND 2 @@ -230,6 +220,181 @@ struct ice_nvgre_hdr { __be32 tni_flow; }; +/* Metadata information + * + * Not all MDIDs can be used by switch block. It depends on package version. + * + * MDID 16 (Rx offset) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | A | B | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * A = Source port where the transaction came from (3b). + * + * B = Destination TC of the packet. The TC is relative to a port (5b). + * + * MDID 17 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PTYPE | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * PTYPE = Encodes the packet type (10b). + * + * MDID 18 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Packet length | R | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Packet length = Length of the packet in bytes + * (packet always carriers CRC) (14b). + * R = Reserved (2b). + * + * MDID 19 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Source VSI | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Source VSI = Source VSI of packet loopbacked in switch (for egress) (10b). + * + * MDID 20 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |A|B|C|D|E|F|R|R|G|H|I|J|K|L|M|N| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * A = DSI - set for DSI RX pkts. + * B = ipsec_decrypted - invalid on NIC. + * C = marker - this is a marker packet. + * D = from_network - for TX sets to 0 + * for RX: + * * 1 - packet is from external link + * * 0 - packet source is from internal + * E = source_interface_is_rx - reflect the physical interface from where the + * packet was received: + * * 1 - Rx + * * 0 - Tx + * F = from_mng - The bit signals that the packet's origin is the management. + * G = ucast - Outer L2 MAC address is unicast. + * H = mcast - Outer L2 MAC address is multicast. + * I = bcast - Outer L2 MAC address is broadcast. + * J = second_outer_mac_present - 2 outer MAC headers are present in the packet. + * K = STAG or BVLAN - Outer L2 header has STAG (ethernet type 0x88a8) or + * BVLAN (ethernet type 0x88a8). + * L = ITAG - Outer L2 header has ITAG *ethernet type 0x88e7) + * M = EVLAN (0x8100) - Outer L2 header has EVLAN (ethernet type 0x8100) + * N = EVLAN (0x9100) - Outer L2 header has EVLAN (ethernet type 0x9100) + */ +#define ICE_PKT_VLAN_STAG BIT(12) +#define ICE_PKT_VLAN_ITAG BIT(13) +#define ICE_PKT_VLAN_EVLAN (BIT(14) | BIT(15)) +#define ICE_PKT_VLAN_MASK (ICE_PKT_VLAN_STAG | ICE_PKT_VLAN_ITAG | \ + ICE_PKT_VLAN_EVLAN) +/* MDID 21 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |A|B|C|D|E|F|G|H|I|J|R|R|K|L|M|N| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * A = VLAN (0x8100) - Outer L2 header has VLAN (ethernet type 0x8100) + * B = NSHoE - Outer L2 header has NSH (ethernet type 0x894f) + * C = MPLS (0x8847) - There is at least 1 MPLS tag in the outer header + * (ethernet type 0x8847) + * D = MPLS (0x8848) - There is at least 1 MPLS tag in the outer header + * (ethernet type 0x8848) + * E = multi MPLS - There is more than a single MPLS tag in the outer header + * F = inner MPLS - There is inner MPLS tag in the packet + * G = tunneled MAC - Set if the packet includes a tunneled MAC + * H = tunneled VLAN - Same as VLAN, but for a tunneled header + * I = pkt_is_frag - Packet is fragmented (ipv4 or ipv6) + * J = ipv6_ext - The packet has routing or destination ipv6 extension in inner + * or outer ipv6 headers + * K = RoCE - UDP packet detected as RoCEv2 + * L = UDP_XSUM_0 - Set to 1 if L4 checksum is 0 in a UDP packet + * M = ESP - This is a ESP packet + * N = NAT_ESP - This is a ESP packet encapsulated in UDP NAT + */ +#define ICE_PKT_TUNNEL_MAC BIT(6) +#define ICE_PKT_TUNNEL_VLAN BIT(7) +#define ICE_PKT_TUNNEL_MASK (ICE_PKT_TUNNEL_MAC | ICE_PKT_TUNNEL_VLAN) + +/* MDID 22 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |A|B|C|D|E|F| G |H|I|J| K |L|M| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * A = fin - fin flag in tcp header + * B = sync - sync flag in tcp header + * C = rst - rst flag in tcp header + * D = psh - psh flag in tcp header + * E = ack - ack flag in tcp header + * F = urg - urg flag in tcp header + * G = tunnel type (3b) - Flags used to decode tunnel type: + * * b000 - not a VXLAN/Geneve/GRE tunnel + * * b001 - VXLAN-GPE + * * b010 - VXLAN (non-GPE) + * * b011 - Geneve + * * b100 - GRE (no key, no xsum) + * * b101 - GREK (key, no xsum) + * * b110 - GREC (no key, xsum) + * * b111 - GREKC (key, xsum) + * H = UDP_GRE - Packet is UDP (VXLAN or VLAN_GPE or Geneve or MPLSoUDP or GRE) + * tunnel + * I = OAM - VXLAN/Geneve/tunneled NSH packet with the OAM bit set + * J = tunneled NSH - Packet has NSHoGRE or NSHoUDP + * K = switch (2b) - Direction on switch + * * b00 - normal + * * b01 - TX force only LAN + * * b10 - TX disable LAN + * * b11 - direct to VSI + * L = swpe - Represents SWPE bit in TX command + * M = sw_cmd - Switch command + * + * MDID 23 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |A|B|C|D| R |E|F|R| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * A = MAC error - Produced by MAC according to L2 error conditions + * B = PPRS no offload - FIFO overflow in PPRS or any problematic condition in + * PPRS ANA + * C = abort - Set when malicious packet is detected + * D = partial analysis - ANA's analysing got cut in the middle + * (header > 504B etc.) + * E = FLM - Flow director hit indication + * F = FDLONG - Flow direector long bucket indication + * + */ +#define ICE_MDID_SIZE 2 +#define ICE_META_DATA_ID_HW 255 + +enum ice_hw_metadata_id { + ICE_SOURCE_PORT_MDID = 16, + ICE_PTYPE_MDID = 17, + ICE_PACKET_LENGTH_MDID = 18, + ICE_SOURCE_VSI_MDID = 19, + ICE_PKT_VLAN_MDID = 20, + ICE_PKT_TUNNEL_MDID = 21, + ICE_PKT_TCP_MDID = 22, + ICE_PKT_ERROR_MDID = 23, +}; + +enum ice_hw_metadata_offset { + ICE_SOURCE_PORT_MDID_OFFSET = ICE_MDID_SIZE * ICE_SOURCE_PORT_MDID, + ICE_PTYPE_MDID_OFFSET = ICE_MDID_SIZE * ICE_PTYPE_MDID, + ICE_PACKET_LENGTH_MDID_OFFSET = ICE_MDID_SIZE * ICE_PACKET_LENGTH_MDID, + ICE_SOURCE_VSI_MDID_OFFSET = ICE_MDID_SIZE * ICE_SOURCE_VSI_MDID, + ICE_PKT_VLAN_MDID_OFFSET = ICE_MDID_SIZE * ICE_PKT_VLAN_MDID, + ICE_PKT_TUNNEL_MDID_OFFSET = ICE_MDID_SIZE * ICE_PKT_TUNNEL_MDID, + ICE_PKT_TCP_MDID_OFFSET = ICE_MDID_SIZE * ICE_PKT_TCP_MDID, + ICE_PKT_ERROR_MDID_OFFSET = ICE_MDID_SIZE * ICE_PKT_ERROR_MDID, +}; + +struct ice_hw_metadata { + __be16 source_port; + __be16 ptype; + __be16 packet_length; + __be16 source_vsi; + __be16 flags[4]; +}; + union ice_prot_hdr { struct ice_ether_hdr eth_hdr; struct ice_ethtype_hdr ethertype; @@ -243,6 +408,7 @@ union ice_prot_hdr { struct ice_udp_gtp_hdr gtp_hdr; struct ice_pppoe_hdr pppoe_hdr; struct ice_l2tpv3_sess_hdr l2tpv3_sess_hdr; + struct ice_hw_metadata metadata; }; /* This is mapping table entry that maps every word within a given protocol diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 46b36851af46..5c3f266fa80f 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -5268,7 +5268,7 @@ static bool ice_tun_type_match_word(enum ice_sw_tunnel_type tun_type, u16 *mask) case ICE_SW_TUN_NVGRE: case ICE_SW_TUN_GTPU: case ICE_SW_TUN_GTPC: - *mask = ICE_TUN_FLAG_MASK; + *mask = ICE_PKT_TUNNEL_MASK; return true; default: @@ -5297,7 +5297,8 @@ ice_add_special_words(struct ice_adv_rule_info *rinfo, u8 word = lkup_exts->n_val_words++; lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW; - lkup_exts->fv_words[word].off = ICE_TUN_FLAG_MDID_OFF; + lkup_exts->fv_words[word].off = + ICE_PKT_TUNNEL_MDID_OFFSET; lkup_exts->field_mask[word] = mask; } else { return -ENOSPC; @@ -5309,9 +5310,9 @@ ice_add_special_words(struct ice_adv_rule_info *rinfo, u8 word = lkup_exts->n_val_words++; lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW; - lkup_exts->fv_words[word].off = ICE_VLAN_FLAG_MDID_OFF; - lkup_exts->field_mask[word] = - ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK; + lkup_exts->fv_words[word].off = + ICE_PKT_VLAN_MDID_OFFSET; + lkup_exts->field_mask[word] = ICE_PKT_VLAN_MASK; } else { return -ENOSPC; } diff --git a/drivers/net/ethernet/intel/ice/ice_vlan_mode.c b/drivers/net/ethernet/intel/ice/ice_vlan_mode.c index bcda2e004807..1279c1ffe31c 100644 --- a/drivers/net/ethernet/intel/ice/ice_vlan_mode.c +++ b/drivers/net/ethernet/intel/ice/ice_vlan_mode.c @@ -219,7 +219,7 @@ static struct ice_update_recipe_lkup_idx_params ice_dvm_dflt_recipes[] = { .rid = ICE_SW_LKUP_VLAN, .fv_idx = ICE_PKT_FLAGS_0_TO_15_FV_IDX, .ignore_valid = false, - .mask = ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK, + .mask = ICE_PKT_VLAN_MASK, .mask_valid = true, .lkup_idx = ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX, }, -- cgit v1.2.3 From 40fd749245f2ee32874e563051957cc614cf11e4 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Fri, 7 Apr 2023 18:52:16 +0200 Subject: ice: remove redundant Rx field from rule info Information about the direction is currently stored in sw_act.flag. There is no need to duplicate it in another field. Setting direction flag doesn't mean that there is a match criteria for direction in rule. It is only a information for HW from where switch id should be collected (VSI or port). In current implementation of advance rule handling, without matching for direction meta data, we can always set one the same flag and everything will work the same. Ability to match on direction meta data will be added in follow up patches. Recipe 0, 3 and 9 loaded from package has direction match criteria, but they are handled in other function. Move ice_adv_rule_info fields to avoid holes. Signed-off-by: Michal Swiatkowski Reviewed-by: Piotr Raczynski Reviewed-by: Simon Horman Reviewed-by: Leon Romanovsky Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 1 - drivers/net/ethernet/intel/ice/ice_switch.c | 22 +++++++++++----------- drivers/net/ethernet/intel/ice/ice_switch.h | 8 +++----- drivers/net/ethernet/intel/ice/ice_tc_lib.c | 5 ----- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index f6dd3f8fd936..2c80d57331d0 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -39,7 +39,6 @@ ice_eswitch_add_vf_mac_rule(struct ice_pf *pf, struct ice_vf *vf, const u8 *mac) rule_info.sw_act.flag |= ICE_FLTR_TX; rule_info.sw_act.vsi_handle = ctrl_vsi->idx; rule_info.sw_act.fltr_act = ICE_FWD_TO_Q; - rule_info.rx = false; rule_info.sw_act.fwd_id.q_id = hw->func_caps.common_cap.rxq_first_id + ctrl_vsi->rxq_map[vf->vf_id]; rule_info.flags_info.act |= ICE_SINGLE_ACT_LB_ENABLE; diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 5c3f266fa80f..e806dfe69b90 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -6121,8 +6121,7 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) rinfo->sw_act.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); - if (rinfo->sw_act.flag & ICE_FLTR_TX) - rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); + rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid); if (status) @@ -6190,19 +6189,20 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, goto err_ice_add_adv_rule; } - /* set the rule LOOKUP type based on caller specified 'Rx' - * instead of hardcoding it to be either LOOKUP_TX/RX + /* If there is no matching criteria for direction there + * is only one difference between Rx and Tx: + * - get switch id base on VSI number from source field (Tx) + * - get switch id base on port number (Rx) * - * for 'Rx' set the source to be the port number - * for 'Tx' set the source to be the source HW VSI number (determined - * by caller) + * If matching on direction metadata is chose rule direction is + * extracted from type value set here. */ - if (rinfo->rx) { - s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); - s_rule->src = cpu_to_le16(hw->port_info->lport); - } else { + if (rinfo->sw_act.flag & ICE_FLTR_TX) { s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_TX); s_rule->src = cpu_to_le16(rinfo->sw_act.src); + } else { + s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX); + s_rule->src = cpu_to_le16(hw->port_info->lport); } s_rule->recipe_id = cpu_to_le16(rid); diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 68d8e8a6a189..8e77868d6dca 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -10,7 +10,6 @@ #define ICE_DFLT_VSI_INVAL 0xff #define ICE_FLTR_RX BIT(0) #define ICE_FLTR_TX BIT(1) -#define ICE_FLTR_TX_RX (ICE_FLTR_RX | ICE_FLTR_TX) #define ICE_VSI_INVAL_ID 0xffff #define ICE_INVAL_Q_HANDLE 0xFFFF @@ -188,11 +187,10 @@ struct ice_adv_rule_flags_info { struct ice_adv_rule_info { enum ice_sw_tunnel_type tun_type; - struct ice_sw_act_ctrl sw_act; - u32 priority; - u8 rx; /* true means LOOKUP_RX otherwise LOOKUP_TX */ - u16 fltr_rule_id; u16 vlan_type; + u16 fltr_rule_id; + u32 priority; + struct ice_sw_act_ctrl sw_act; struct ice_adv_rule_flags_info flags_info; }; diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c index d1a31f236d26..2b1a34586f47 100644 --- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c @@ -698,12 +698,10 @@ ice_eswitch_add_tc_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr) if (fltr->direction == ICE_ESWITCH_FLTR_INGRESS) { rule_info.sw_act.flag |= ICE_FLTR_RX; rule_info.sw_act.src = hw->pf_id; - rule_info.rx = true; rule_info.flags_info.act = ICE_SINGLE_ACT_LB_ENABLE; } else { rule_info.sw_act.flag |= ICE_FLTR_TX; rule_info.sw_act.src = vsi->idx; - rule_info.rx = false; rule_info.flags_info.act = ICE_SINGLE_ACT_LAN_ENABLE; } @@ -910,7 +908,6 @@ ice_add_tc_flower_adv_fltr(struct ice_vsi *vsi, rule_info.sw_act.vsi_handle = dest_vsi->idx; rule_info.priority = ICE_SWITCH_FLTR_PRIO_VSI; rule_info.sw_act.src = hw->pf_id; - rule_info.rx = true; dev_dbg(dev, "add switch rule for TC:%u vsi_idx:%u, lkups_cnt:%u\n", tc_fltr->action.fwd.tc.tc_class, rule_info.sw_act.vsi_handle, lkups_cnt); @@ -921,7 +918,6 @@ ice_add_tc_flower_adv_fltr(struct ice_vsi *vsi, rule_info.sw_act.vsi_handle = dest_vsi->idx; rule_info.priority = ICE_SWITCH_FLTR_PRIO_QUEUE; rule_info.sw_act.src = hw->pf_id; - rule_info.rx = true; dev_dbg(dev, "add switch rule action to forward to queue:%u (HW queue %u), lkups_cnt:%u\n", tc_fltr->action.fwd.q.queue, tc_fltr->action.fwd.q.hw_queue, lkups_cnt); @@ -929,7 +925,6 @@ ice_add_tc_flower_adv_fltr(struct ice_vsi *vsi, case ICE_DROP_PACKET: rule_info.sw_act.flag |= ICE_FLTR_RX; rule_info.sw_act.src = hw->pf_id; - rule_info.rx = true; rule_info.priority = ICE_SWITCH_FLTR_PRIO_VSI; break; default: -- cgit v1.2.3 From 17c6d8357da1ae6a5d92c15efe68f877c3e8b968 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Fri, 7 Apr 2023 18:52:17 +0200 Subject: ice: specify field names in ice_prot_ext init Anonymous initializers are now discouraged. Define ICE_PROTCOL_ENTRY macro to rewrite anonymous initializers to named one. No functional changes here. Suggested-by: Alexander Lobakin Signed-off-by: Michal Swiatkowski Reviewed-by: Simon Horman Reviewed-by: Leon Romanovsky Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_switch.c | 51 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index e806dfe69b90..baa61a2b82f0 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -4540,6 +4540,11 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, return status; } +#define ICE_PROTOCOL_ENTRY(id, ...) { \ + .prot_type = id, \ + .offs = {__VA_ARGS__}, \ +} + /* This is mapping table entry that maps every word within a given protocol * structure to the real byte offset as per the specification of that * protocol header. @@ -4550,29 +4555,29 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, * structure is added to that union. */ static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = { - { ICE_MAC_OFOS, { 0, 2, 4, 6, 8, 10, 12 } }, - { ICE_MAC_IL, { 0, 2, 4, 6, 8, 10, 12 } }, - { ICE_ETYPE_OL, { 0 } }, - { ICE_ETYPE_IL, { 0 } }, - { ICE_VLAN_OFOS, { 2, 0 } }, - { ICE_IPV4_OFOS, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } }, - { ICE_IPV4_IL, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 } }, - { ICE_IPV6_OFOS, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, - 26, 28, 30, 32, 34, 36, 38 } }, - { ICE_IPV6_IL, { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, - 26, 28, 30, 32, 34, 36, 38 } }, - { ICE_TCP_IL, { 0, 2 } }, - { ICE_UDP_OF, { 0, 2 } }, - { ICE_UDP_ILOS, { 0, 2 } }, - { ICE_VXLAN, { 8, 10, 12, 14 } }, - { ICE_GENEVE, { 8, 10, 12, 14 } }, - { ICE_NVGRE, { 0, 2, 4, 6 } }, - { ICE_GTP, { 8, 10, 12, 14, 16, 18, 20, 22 } }, - { ICE_GTP_NO_PAY, { 8, 10, 12, 14 } }, - { ICE_PPPOE, { 0, 2, 4, 6 } }, - { ICE_L2TPV3, { 0, 2, 4, 6, 8, 10 } }, - { ICE_VLAN_EX, { 2, 0 } }, - { ICE_VLAN_IN, { 2, 0 } }, + ICE_PROTOCOL_ENTRY(ICE_MAC_OFOS, 0, 2, 4, 6, 8, 10, 12), + ICE_PROTOCOL_ENTRY(ICE_MAC_IL, 0, 2, 4, 6, 8, 10, 12), + ICE_PROTOCOL_ENTRY(ICE_ETYPE_OL, 0), + ICE_PROTOCOL_ENTRY(ICE_ETYPE_IL, 0), + ICE_PROTOCOL_ENTRY(ICE_VLAN_OFOS, 2, 0), + ICE_PROTOCOL_ENTRY(ICE_IPV4_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18), + ICE_PROTOCOL_ENTRY(ICE_IPV4_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18), + ICE_PROTOCOL_ENTRY(ICE_IPV6_OFOS, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, + 20, 22, 24, 26, 28, 30, 32, 34, 36, 38), + ICE_PROTOCOL_ENTRY(ICE_IPV6_IL, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, + 22, 24, 26, 28, 30, 32, 34, 36, 38), + ICE_PROTOCOL_ENTRY(ICE_TCP_IL, 0, 2), + ICE_PROTOCOL_ENTRY(ICE_UDP_OF, 0, 2), + ICE_PROTOCOL_ENTRY(ICE_UDP_ILOS, 0, 2), + ICE_PROTOCOL_ENTRY(ICE_VXLAN, 8, 10, 12, 14), + ICE_PROTOCOL_ENTRY(ICE_GENEVE, 8, 10, 12, 14), + ICE_PROTOCOL_ENTRY(ICE_NVGRE, 0, 2, 4, 6), + ICE_PROTOCOL_ENTRY(ICE_GTP, 8, 10, 12, 14, 16, 18, 20, 22), + ICE_PROTOCOL_ENTRY(ICE_GTP_NO_PAY, 8, 10, 12, 14), + ICE_PROTOCOL_ENTRY(ICE_PPPOE, 0, 2, 4, 6), + ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10), + ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0), + ICE_PROTOCOL_ENTRY(ICE_VLAN_IN, 2, 0), }; static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { -- cgit v1.2.3 From 03592a14b9383bbe1c0d56e7ac4005cea10e711a Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Fri, 7 Apr 2023 18:52:18 +0200 Subject: ice: allow matching on meta data Add meta data matching criteria in the same place as protocol matching criteria. There is no need to add meta data as special words after parsing all lookups. Trade meta data in the same why as other lookups. The one difference between meta data lookups and protocol lookups is that meta data doesn't impact how the packets looks like. Because of that ignore it when filling testing packet. Match on tunnel type meta data always if tunnel type is different than TNL_LAST. Signed-off-by: Michal Swiatkowski Reviewed-by: Piotr Raczynski Reviewed-by: Simon Horman Reviewed-by: Leon Romanovsky Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_protocol_type.h | 8 ++ drivers/net/ethernet/intel/ice/ice_switch.c | 158 ++++++++------------- drivers/net/ethernet/intel/ice/ice_switch.h | 4 + drivers/net/ethernet/intel/ice/ice_tc_lib.c | 29 +++- drivers/net/ethernet/intel/ice/ice_tc_lib.h | 1 + 5 files changed, 95 insertions(+), 105 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_protocol_type.h b/drivers/net/ethernet/intel/ice/ice_protocol_type.h index 8a84f106bd4d..ed0ab8177c61 100644 --- a/drivers/net/ethernet/intel/ice/ice_protocol_type.h +++ b/drivers/net/ethernet/intel/ice/ice_protocol_type.h @@ -47,6 +47,7 @@ enum ice_protocol_type { ICE_L2TPV3, ICE_VLAN_EX, ICE_VLAN_IN, + ICE_HW_METADATA, ICE_VXLAN_GPE, ICE_SCTP_IL, ICE_PROTOCOL_LAST @@ -387,6 +388,13 @@ enum ice_hw_metadata_offset { ICE_PKT_ERROR_MDID_OFFSET = ICE_MDID_SIZE * ICE_PKT_ERROR_MDID, }; +enum ice_pkt_flags { + ICE_PKT_FLAGS_VLAN = 0, + ICE_PKT_FLAGS_TUNNEL = 1, + ICE_PKT_FLAGS_TCP = 2, + ICE_PKT_FLAGS_ERROR = 3, +}; + struct ice_hw_metadata { __be16 source_port; __be16 ptype; diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index baa61a2b82f0..9578bd0a2d65 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -4578,6 +4578,15 @@ static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = { ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10), ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0), ICE_PROTOCOL_ENTRY(ICE_VLAN_IN, 2, 0), + ICE_PROTOCOL_ENTRY(ICE_HW_METADATA, + ICE_SOURCE_PORT_MDID_OFFSET, + ICE_PTYPE_MDID_OFFSET, + ICE_PACKET_LENGTH_MDID_OFFSET, + ICE_SOURCE_VSI_MDID_OFFSET, + ICE_PKT_VLAN_MDID_OFFSET, + ICE_PKT_TUNNEL_MDID_OFFSET, + ICE_PKT_TCP_MDID_OFFSET, + ICE_PKT_ERROR_MDID_OFFSET), }; static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { @@ -4602,6 +4611,7 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { { ICE_L2TPV3, ICE_L2TPV3_HW }, { ICE_VLAN_EX, ICE_VLAN_OF_HW }, { ICE_VLAN_IN, ICE_VLAN_OL_HW }, + { ICE_HW_METADATA, ICE_META_DATA_ID_HW }, }; /** @@ -5260,72 +5270,6 @@ ice_create_recipe_group(struct ice_hw *hw, struct ice_sw_recipe *rm, return status; } -/** - * ice_tun_type_match_word - determine if tun type needs a match mask - * @tun_type: tunnel type - * @mask: mask to be used for the tunnel - */ -static bool ice_tun_type_match_word(enum ice_sw_tunnel_type tun_type, u16 *mask) -{ - switch (tun_type) { - case ICE_SW_TUN_GENEVE: - case ICE_SW_TUN_VXLAN: - case ICE_SW_TUN_NVGRE: - case ICE_SW_TUN_GTPU: - case ICE_SW_TUN_GTPC: - *mask = ICE_PKT_TUNNEL_MASK; - return true; - - default: - *mask = 0; - return false; - } -} - -/** - * ice_add_special_words - Add words that are not protocols, such as metadata - * @rinfo: other information regarding the rule e.g. priority and action info - * @lkup_exts: lookup word structure - * @dvm_ena: is double VLAN mode enabled - */ -static int -ice_add_special_words(struct ice_adv_rule_info *rinfo, - struct ice_prot_lkup_ext *lkup_exts, bool dvm_ena) -{ - u16 mask; - - /* If this is a tunneled packet, then add recipe index to match the - * tunnel bit in the packet metadata flags. - */ - if (ice_tun_type_match_word(rinfo->tun_type, &mask)) { - if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) { - u8 word = lkup_exts->n_val_words++; - - lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW; - lkup_exts->fv_words[word].off = - ICE_PKT_TUNNEL_MDID_OFFSET; - lkup_exts->field_mask[word] = mask; - } else { - return -ENOSPC; - } - } - - if (rinfo->vlan_type != 0 && dvm_ena) { - if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) { - u8 word = lkup_exts->n_val_words++; - - lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW; - lkup_exts->fv_words[word].off = - ICE_PKT_VLAN_MDID_OFFSET; - lkup_exts->field_mask[word] = ICE_PKT_VLAN_MASK; - } else { - return -ENOSPC; - } - } - - return 0; -} - /* ice_get_compat_fv_bitmap - Get compatible field vector bitmap for rule * @hw: pointer to hardware structure * @rinfo: other information regarding the rule e.g. priority and action info @@ -5439,13 +5383,6 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, if (status) goto err_unroll; - /* Create any special protocol/offset pairs, such as looking at tunnel - * bits by extracting metadata - */ - status = ice_add_special_words(rinfo, lkup_exts, ice_is_dvm_ena(hw)); - if (status) - goto err_unroll; - /* Group match words into recipes using preferred recipe grouping * criteria. */ @@ -5731,6 +5668,10 @@ ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, * was already checked when search for the dummy packet */ type = lkups[i].type; + /* metadata isn't present in the packet */ + if (type == ICE_HW_METADATA) + continue; + for (j = 0; offsets[j].type != ICE_PROTOCOL_LAST; j++) { if (type == offsets[j].type) { offset = offsets[j].offset; @@ -5866,16 +5807,21 @@ ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type, /** * ice_fill_adv_packet_vlan - fill dummy packet with VLAN tag type + * @hw: pointer to hw structure * @vlan_type: VLAN tag type * @pkt: dummy packet to fill in * @offsets: offset info for the dummy packet */ static int -ice_fill_adv_packet_vlan(u16 vlan_type, u8 *pkt, +ice_fill_adv_packet_vlan(struct ice_hw *hw, u16 vlan_type, u8 *pkt, const struct ice_dummy_pkt_offsets *offsets) { u16 i; + /* Check if there is something to do */ + if (!vlan_type || !ice_is_dvm_ena(hw)) + return 0; + /* Find VLAN header and insert VLAN TPID */ for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) { if (offsets[i].type == ICE_VLAN_OFOS || @@ -5894,6 +5840,15 @@ ice_fill_adv_packet_vlan(u16 vlan_type, u8 *pkt, return -EIO; } +static bool ice_rules_equal(const struct ice_adv_rule_info *first, + const struct ice_adv_rule_info *second) +{ + return first->sw_act.flag == second->sw_act.flag && + first->tun_type == second->tun_type && + first->vlan_type == second->vlan_type && + first->src_vsi == second->src_vsi; +} + /** * ice_find_adv_rule_entry - Search a rule entry * @hw: pointer to the hardware structure @@ -5927,9 +5882,7 @@ ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, lkups_matched = false; break; } - if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag && - rinfo->tun_type == list_itr->rule_info.tun_type && - rinfo->vlan_type == list_itr->rule_info.vlan_type && + if (ice_rules_equal(rinfo, &list_itr->rule_info) && lkups_matched) return list_itr; } @@ -6045,6 +5998,20 @@ ice_adv_add_update_vsi_list(struct ice_hw *hw, return status; } +void ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup) +{ + lkup->type = ICE_HW_METADATA; + lkup->m_u.metadata.flags[ICE_PKT_FLAGS_TUNNEL] = + cpu_to_be16(ICE_PKT_TUNNEL_MASK); +} + +void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup) +{ + lkup->type = ICE_HW_METADATA; + lkup->m_u.metadata.flags[ICE_PKT_FLAGS_VLAN] = + cpu_to_be16(ICE_PKT_VLAN_MASK); +} + /** * ice_add_adv_rule - helper function to create an advanced switch rule * @hw: pointer to the hardware structure @@ -6126,7 +6093,11 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI) rinfo->sw_act.fwd_id.hw_vsi_id = ice_get_hw_vsi_num(hw, vsi_handle); - rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); + + if (rinfo->src_vsi) + rinfo->sw_act.src = ice_get_hw_vsi_num(hw, rinfo->src_vsi); + else + rinfo->sw_act.src = ice_get_hw_vsi_num(hw, vsi_handle); status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid); if (status) @@ -6217,22 +6188,16 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, if (status) goto err_ice_add_adv_rule; - if (rinfo->tun_type != ICE_NON_TUN && - rinfo->tun_type != ICE_SW_TUN_AND_NON_TUN) { - status = ice_fill_adv_packet_tun(hw, rinfo->tun_type, - s_rule->hdr_data, - profile->offsets); - if (status) - goto err_ice_add_adv_rule; - } + status = ice_fill_adv_packet_tun(hw, rinfo->tun_type, s_rule->hdr_data, + profile->offsets); + if (status) + goto err_ice_add_adv_rule; - if (rinfo->vlan_type != 0 && ice_is_dvm_ena(hw)) { - status = ice_fill_adv_packet_vlan(rinfo->vlan_type, - s_rule->hdr_data, - profile->offsets); - if (status) - goto err_ice_add_adv_rule; - } + status = ice_fill_adv_packet_vlan(hw, rinfo->vlan_type, + s_rule->hdr_data, + profile->offsets); + if (status) + goto err_ice_add_adv_rule; status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule, rule_buf_sz, 1, ice_aqc_opc_add_sw_rules, @@ -6475,13 +6440,6 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, return -EIO; } - /* Create any special protocol/offset pairs, such as looking at tunnel - * bits by extracting metadata - */ - status = ice_add_special_words(rinfo, &lkup_exts, ice_is_dvm_ena(hw)); - if (status) - return status; - rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type); /* If did not find a recipe that match the existing criteria */ if (rid == ICE_MAX_NUM_RECIPES) diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index 8e77868d6dca..bbd759f94187 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -186,10 +186,12 @@ struct ice_adv_rule_flags_info { }; struct ice_adv_rule_info { + /* Store metadata values in rule info */ enum ice_sw_tunnel_type tun_type; u16 vlan_type; u16 fltr_rule_id; u32 priority; + u16 src_vsi; struct ice_sw_act_ctrl sw_act; struct ice_adv_rule_flags_info flags_info; }; @@ -340,6 +342,8 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, u16 counter_id); /* Switch/bridge related commands */ +void ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup); +void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup); int ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, struct ice_adv_rule_info *rinfo, diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c index 2b1a34586f47..b54052ef6050 100644 --- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c @@ -54,6 +54,10 @@ ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers, if (flags & (ICE_TC_FLWR_FIELD_VLAN | ICE_TC_FLWR_FIELD_VLAN_PRIO)) lkups_cnt++; + /* is VLAN TPID specified */ + if (flags & ICE_TC_FLWR_FIELD_VLAN_TPID) + lkups_cnt++; + /* is CVLAN specified? */ if (flags & (ICE_TC_FLWR_FIELD_CVLAN | ICE_TC_FLWR_FIELD_CVLAN_PRIO)) lkups_cnt++; @@ -80,6 +84,10 @@ ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers, ICE_TC_FLWR_FIELD_SRC_L4_PORT)) lkups_cnt++; + /* matching for tunneled packets in metadata */ + if (fltr->tunnel_type != TNL_LAST) + lkups_cnt++; + return lkups_cnt; } @@ -320,6 +328,10 @@ ice_tc_fill_tunnel_outer(u32 flags, struct ice_tc_flower_fltr *fltr, i++; } + /* always fill matching on tunneled packets in metadata */ + ice_rule_add_tunnel_metadata(&list[i]); + i++; + return i; } @@ -390,10 +402,6 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags, /* copy VLAN info */ if (flags & (ICE_TC_FLWR_FIELD_VLAN | ICE_TC_FLWR_FIELD_VLAN_PRIO)) { - vlan_tpid = be16_to_cpu(headers->vlan_hdr.vlan_tpid); - rule_info->vlan_type = - ice_check_supported_vlan_tpid(vlan_tpid); - if (flags & ICE_TC_FLWR_FIELD_CVLAN) list[i].type = ICE_VLAN_EX; else @@ -418,6 +426,15 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags, i++; } + if (flags & ICE_TC_FLWR_FIELD_VLAN_TPID) { + vlan_tpid = be16_to_cpu(headers->vlan_hdr.vlan_tpid); + rule_info->vlan_type = + ice_check_supported_vlan_tpid(vlan_tpid); + + ice_rule_add_vlan_metadata(&list[i]); + i++; + } + if (flags & (ICE_TC_FLWR_FIELD_CVLAN | ICE_TC_FLWR_FIELD_CVLAN_PRIO)) { list[i].type = ICE_VLAN_IN; @@ -1455,8 +1472,10 @@ ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi, VLAN_PRIO_MASK); } - if (match.mask->vlan_tpid) + if (match.mask->vlan_tpid) { headers->vlan_hdr.vlan_tpid = match.key->vlan_tpid; + fltr->flags |= ICE_TC_FLWR_FIELD_VLAN_TPID; + } } if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) { diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.h b/drivers/net/ethernet/intel/ice/ice_tc_lib.h index 8d5e22ac7023..8bbc1a62bdb1 100644 --- a/drivers/net/ethernet/intel/ice/ice_tc_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.h @@ -33,6 +33,7 @@ #define ICE_TC_FLWR_FIELD_L2TPV3_SESSID BIT(26) #define ICE_TC_FLWR_FIELD_VLAN_PRIO BIT(27) #define ICE_TC_FLWR_FIELD_CVLAN_PRIO BIT(28) +#define ICE_TC_FLWR_FIELD_VLAN_TPID BIT(29) #define ICE_TC_FLOWER_MASK_32 0xFFFFFFFF -- cgit v1.2.3 From 0ef4479d13af4c5516920520d9cf7bcfe801b353 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Fri, 7 Apr 2023 18:52:19 +0200 Subject: ice: use src VSI instead of src MAC in slow-path The use of a source MAC to direct packets from the VF to the corresponding port representor is only ok if there is only one MAC on a VF. To support this functionality when the number of MACs on a VF is greater, it is necessary to match a source VSI instead of a source MAC. Let's use the new switch API that allows matching on metadata. If MAC isn't used in match criteria there is no need to handle adding rule after virtchnl command. Instead add new rule while port representor is being configured. Remove rule_added field, checking for sp_rule can be used instead. Remove also checking for switchdev running in deleting rule as it can be called from unroll context when running flag isn't set. Checking for sp_rule covers both context (with and without running flag). Rules are added in eswitch configuration flow, so there is no need to have replay function. Signed-off-by: Michal Swiatkowski Reviewed-by: Piotr Raczynski Reviewed-by: Simon Horman Reviewed-by: Leon Romanovsky Tested-by: Sujai Buvaneswaran Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_eswitch.c | 83 +++++++--------------- drivers/net/ethernet/intel/ice/ice_eswitch.h | 14 ---- drivers/net/ethernet/intel/ice/ice_protocol_type.h | 5 +- drivers/net/ethernet/intel/ice/ice_repr.c | 17 ----- drivers/net/ethernet/intel/ice/ice_repr.h | 5 +- drivers/net/ethernet/intel/ice/ice_switch.c | 6 ++ drivers/net/ethernet/intel/ice/ice_switch.h | 1 + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 3 - drivers/net/ethernet/intel/ice/ice_virtchnl.c | 8 --- 9 files changed, 40 insertions(+), 102 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c index 2c80d57331d0..ad0a007b7398 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.c +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c @@ -10,16 +10,15 @@ #include "ice_tc_lib.h" /** - * ice_eswitch_add_vf_mac_rule - add adv rule with VF's MAC + * ice_eswitch_add_vf_sp_rule - add adv rule with VF's VSI index * @pf: pointer to PF struct * @vf: pointer to VF struct - * @mac: VF's MAC address * * This function adds advanced rule that forwards packets with - * VF's MAC address (src MAC) to the corresponding switchdev ctrl VSI queue. + * VF's VSI index to the corresponding switchdev ctrl VSI queue. */ -int -ice_eswitch_add_vf_mac_rule(struct ice_pf *pf, struct ice_vf *vf, const u8 *mac) +static int +ice_eswitch_add_vf_sp_rule(struct ice_pf *pf, struct ice_vf *vf) { struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi; struct ice_adv_rule_info rule_info = { 0 }; @@ -32,11 +31,9 @@ ice_eswitch_add_vf_mac_rule(struct ice_pf *pf, struct ice_vf *vf, const u8 *mac) if (!list) return -ENOMEM; - list[0].type = ICE_MAC_OFOS; - ether_addr_copy(list[0].h_u.eth_hdr.src_addr, mac); - eth_broadcast_addr(list[0].m_u.eth_hdr.src_addr); + ice_rule_add_src_vsi_metadata(list); - rule_info.sw_act.flag |= ICE_FLTR_TX; + rule_info.sw_act.flag = ICE_FLTR_TX; rule_info.sw_act.vsi_handle = ctrl_vsi->idx; rule_info.sw_act.fltr_act = ICE_FWD_TO_Q; rule_info.sw_act.fwd_id.q_id = hw->func_caps.common_cap.rxq_first_id + @@ -44,63 +41,31 @@ ice_eswitch_add_vf_mac_rule(struct ice_pf *pf, struct ice_vf *vf, const u8 *mac) rule_info.flags_info.act |= ICE_SINGLE_ACT_LB_ENABLE; rule_info.flags_info.act_valid = true; rule_info.tun_type = ICE_SW_TUN_AND_NON_TUN; + rule_info.src_vsi = vf->lan_vsi_idx; err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info, - vf->repr->mac_rule); + &vf->repr->sp_rule); if (err) - dev_err(ice_pf_to_dev(pf), "Unable to add VF mac rule in switchdev mode for VF %d", + dev_err(ice_pf_to_dev(pf), "Unable to add VF slow-path rule in switchdev mode for VF %d", vf->vf_id); - else - vf->repr->rule_added = true; kfree(list); return err; } /** - * ice_eswitch_replay_vf_mac_rule - replay adv rule with VF's MAC - * @vf: pointer to vF struct - * - * This function replays VF's MAC rule after reset. - */ -void ice_eswitch_replay_vf_mac_rule(struct ice_vf *vf) -{ - int err; - - if (!ice_is_switchdev_running(vf->pf)) - return; - - if (is_valid_ether_addr(vf->hw_lan_addr)) { - err = ice_eswitch_add_vf_mac_rule(vf->pf, vf, - vf->hw_lan_addr); - if (err) { - dev_err(ice_pf_to_dev(vf->pf), "Failed to add MAC %pM for VF %d\n, error %d\n", - vf->hw_lan_addr, vf->vf_id, err); - return; - } - vf->num_mac++; - - ether_addr_copy(vf->dev_lan_addr, vf->hw_lan_addr); - } -} - -/** - * ice_eswitch_del_vf_mac_rule - delete adv rule with VF's MAC + * ice_eswitch_del_vf_sp_rule - delete adv rule with VF's VSI index * @vf: pointer to the VF struct * - * Delete the advanced rule that was used to forward packets with the VF's MAC - * address (src MAC) to the corresponding switchdev ctrl VSI queue. + * Delete the advanced rule that was used to forward packets with the VF's VSI + * index to the corresponding switchdev ctrl VSI queue. */ -void ice_eswitch_del_vf_mac_rule(struct ice_vf *vf) +static void ice_eswitch_del_vf_sp_rule(struct ice_vf *vf) { - if (!ice_is_switchdev_running(vf->pf)) - return; - - if (!vf->repr->rule_added) + if (!vf->repr) return; - ice_rem_adv_rule_by_id(&vf->pf->hw, vf->repr->mac_rule); - vf->repr->rule_added = false; + ice_rem_adv_rule_by_id(&vf->pf->hw, &vf->repr->sp_rule); } /** @@ -236,6 +201,7 @@ ice_eswitch_release_reprs(struct ice_pf *pf, struct ice_vsi *ctrl_vsi) ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof); metadata_dst_free(vf->repr->dst); vf->repr->dst = NULL; + ice_eswitch_del_vf_sp_rule(vf); ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, ICE_FWD_TO_VSI); @@ -263,25 +229,30 @@ static int ice_eswitch_setup_reprs(struct ice_pf *pf) vf->repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL); if (!vf->repr->dst) { - ice_fltr_add_mac_and_broadcast(vsi, - vf->hw_lan_addr, + ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, + ICE_FWD_TO_VSI); + goto err; + } + + if (ice_eswitch_add_vf_sp_rule(pf, vf)) { + ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, ICE_FWD_TO_VSI); goto err; } if (ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof)) { - ice_fltr_add_mac_and_broadcast(vsi, - vf->hw_lan_addr, + ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, ICE_FWD_TO_VSI); + ice_eswitch_del_vf_sp_rule(vf); metadata_dst_free(vf->repr->dst); vf->repr->dst = NULL; goto err; } if (ice_vsi_add_vlan_zero(vsi)) { - ice_fltr_add_mac_and_broadcast(vsi, - vf->hw_lan_addr, + ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, ICE_FWD_TO_VSI); + ice_eswitch_del_vf_sp_rule(vf); metadata_dst_free(vf->repr->dst); vf->repr->dst = NULL; ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof); diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.h b/drivers/net/ethernet/intel/ice/ice_eswitch.h index 6a413331572b..b18bf83a2f5b 100644 --- a/drivers/net/ethernet/intel/ice/ice_eswitch.h +++ b/drivers/net/ethernet/intel/ice/ice_eswitch.h @@ -20,11 +20,6 @@ bool ice_is_eswitch_mode_switchdev(struct ice_pf *pf); void ice_eswitch_update_repr(struct ice_vsi *vsi); void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf); -int -ice_eswitch_add_vf_mac_rule(struct ice_pf *pf, struct ice_vf *vf, - const u8 *mac); -void ice_eswitch_replay_vf_mac_rule(struct ice_vf *vf); -void ice_eswitch_del_vf_mac_rule(struct ice_vf *vf); void ice_eswitch_set_target_vsi(struct sk_buff *skb, struct ice_tx_offload_params *off); @@ -34,15 +29,6 @@ ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev); static inline void ice_eswitch_release(struct ice_pf *pf) { } static inline void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf) { } -static inline void ice_eswitch_replay_vf_mac_rule(struct ice_vf *vf) { } -static inline void ice_eswitch_del_vf_mac_rule(struct ice_vf *vf) { } - -static inline int -ice_eswitch_add_vf_mac_rule(struct ice_pf *pf, struct ice_vf *vf, - const u8 *mac) -{ - return -EOPNOTSUPP; -} static inline void ice_eswitch_set_target_vsi(struct sk_buff *skb, diff --git a/drivers/net/ethernet/intel/ice/ice_protocol_type.h b/drivers/net/ethernet/intel/ice/ice_protocol_type.h index ed0ab8177c61..6a9364761165 100644 --- a/drivers/net/ethernet/intel/ice/ice_protocol_type.h +++ b/drivers/net/ethernet/intel/ice/ice_protocol_type.h @@ -256,7 +256,10 @@ struct ice_nvgre_hdr { * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Source VSI = Source VSI of packet loopbacked in switch (for egress) (10b). - * + */ +#define ICE_MDID_SOURCE_VSI_MASK GENMASK(9, 0) + +/* * MDID 20 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |A|B|C|D|E|F|R|R|G|H|I|J|K|L|M|N| diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index fd1f8b0ad0ab..e30e12321abd 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -298,14 +298,6 @@ static int ice_repr_add(struct ice_vf *vf) if (!repr) return -ENOMEM; -#ifdef CONFIG_ICE_SWITCHDEV - repr->mac_rule = kzalloc(sizeof(*repr->mac_rule), GFP_KERNEL); - if (!repr->mac_rule) { - err = -ENOMEM; - goto err_alloc_rule; - } -#endif - repr->netdev = alloc_etherdev(sizeof(struct ice_netdev_priv)); if (!repr->netdev) { err = -ENOMEM; @@ -351,11 +343,6 @@ err_alloc_q_vector: free_netdev(repr->netdev); repr->netdev = NULL; err_alloc: -#ifdef CONFIG_ICE_SWITCHDEV - kfree(repr->mac_rule); - repr->mac_rule = NULL; -err_alloc_rule: -#endif kfree(repr); vf->repr = NULL; return err; @@ -376,10 +363,6 @@ static void ice_repr_rem(struct ice_vf *vf) ice_devlink_destroy_vf_port(vf); free_netdev(vf->repr->netdev); vf->repr->netdev = NULL; -#ifdef CONFIG_ICE_SWITCHDEV - kfree(vf->repr->mac_rule); - vf->repr->mac_rule = NULL; -#endif kfree(vf->repr); vf->repr = NULL; diff --git a/drivers/net/ethernet/intel/ice/ice_repr.h b/drivers/net/ethernet/intel/ice/ice_repr.h index 378a45bfa256..9c2a6f496b3b 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.h +++ b/drivers/net/ethernet/intel/ice/ice_repr.h @@ -13,9 +13,8 @@ struct ice_repr { struct net_device *netdev; struct metadata_dst *dst; #ifdef CONFIG_ICE_SWITCHDEV - /* info about slow path MAC rule */ - struct ice_rule_query_data *mac_rule; - u8 rule_added; + /* info about slow path rule */ + struct ice_rule_query_data sp_rule; #endif }; diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 9578bd0a2d65..2ea9e1ae5517 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -6012,6 +6012,12 @@ void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup) cpu_to_be16(ICE_PKT_VLAN_MASK); } +void ice_rule_add_src_vsi_metadata(struct ice_adv_lkup_elem *lkup) +{ + lkup->type = ICE_HW_METADATA; + lkup->m_u.metadata.source_vsi = cpu_to_be16(ICE_MDID_SOURCE_VSI_MASK); +} + /** * ice_add_adv_rule - helper function to create an advanced switch rule * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index bbd759f94187..c84b56fe84a5 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -344,6 +344,7 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items, /* Switch/bridge related commands */ void ice_rule_add_tunnel_metadata(struct ice_adv_lkup_elem *lkup); void ice_rule_add_vlan_metadata(struct ice_adv_lkup_elem *lkup); +void ice_rule_add_src_vsi_metadata(struct ice_adv_lkup_elem *lkup); int ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, u16 lkups_cnt, struct ice_adv_rule_info *rinfo, diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index e441968a70ae..b26ce4425f45 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -689,8 +689,6 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags) */ ice_vf_clear_all_promisc_modes(vf, vsi); - ice_eswitch_del_vf_mac_rule(vf); - ice_vf_fdir_exit(vf); ice_vf_fdir_init(vf); /* clean VF control VSI when resetting VF since it should be setup @@ -716,7 +714,6 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags) } ice_eswitch_update_repr(vsi); - ice_eswitch_replay_vf_mac_rule(vf); /* if the VF has been reset allow it to come up again */ ice_mbx_clear_malvf(&vf->mbx_info); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index f4a524f80b11..efbc2968a7bf 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -3730,7 +3730,6 @@ static int ice_vc_repr_add_mac(struct ice_vf *vf, u8 *msg) for (i = 0; i < al->num_elements; i++) { u8 *mac_addr = al->list[i].addr; - int result; if (!is_unicast_ether_addr(mac_addr) || ether_addr_equal(mac_addr, vf->hw_lan_addr)) @@ -3742,13 +3741,6 @@ static int ice_vc_repr_add_mac(struct ice_vf *vf, u8 *msg) goto handle_mac_exit; } - result = ice_eswitch_add_vf_mac_rule(pf, vf, mac_addr); - if (result) { - dev_err(ice_pf_to_dev(pf), "Failed to add MAC %pM for VF %d\n, error %d\n", - mac_addr, vf->vf_id, result); - goto handle_mac_exit; - } - ice_vfhw_mac_add(vf, &al->list[i]); vf->num_mac++; break; -- cgit v1.2.3 From e859e429511afb21d3f784bd0ccdf500d40b73ef Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Wed, 17 May 2023 10:31:25 +0000 Subject: bpf: Show target_{obj,btf}_id in tracing link fdinfo The target_btf_id can help us understand which kernel function is linked by a tracing prog. The target_btf_id and target_obj_id have already been exposed to userspace, so we just need to show them. The result as follows, $ cat /proc/10673/fdinfo/10 pos: 0 flags: 02000000 mnt_id: 15 ino: 2094 link_type: tracing link_id: 2 prog_tag: a04f5eef06a7f555 prog_id: 13 attach_type: 24 target_obj_id: 1 target_btf_id: 13964 Signed-off-by: Yafang Shao Acked-by: Song Liu Link: https://lore.kernel.org/r/20230517103126.68372-2-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 909c112ef537..b2621089904b 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2968,10 +2968,17 @@ static void bpf_tracing_link_show_fdinfo(const struct bpf_link *link, { struct bpf_tracing_link *tr_link = container_of(link, struct bpf_tracing_link, link.link); + u32 target_btf_id, target_obj_id; + bpf_trampoline_unpack_key(tr_link->trampoline->key, + &target_obj_id, &target_btf_id); seq_printf(seq, - "attach_type:\t%d\n", - tr_link->attach_type); + "attach_type:\t%d\n" + "target_obj_id:\t%u\n" + "target_btf_id:\t%u\n", + tr_link->attach_type, + target_obj_id, + target_btf_id); } static int bpf_tracing_link_fill_link_info(const struct bpf_link *link, -- cgit v1.2.3 From d7e45eb4802bbb3343624711e43d23b22fe7cc55 Mon Sep 17 00:00:00 2001 From: Yafang Shao Date: Wed, 17 May 2023 10:31:26 +0000 Subject: bpftool: Show target_{obj,btf}_id in tracing link info The target_btf_id can help us understand which kernel function is linked by a tracing prog. The target_btf_id and target_obj_id have already been exposed to userspace, so we just need to show them. The result as follows, $ tools/bpf/bpftool/bpftool link show 2: tracing prog 13 prog_type tracing attach_type trace_fentry target_obj_id 1 target_btf_id 13964 pids trace(10673) $ tools/bpf/bpftool/bpftool link show -j [{"id":2,"type":"tracing","prog_id":13,"prog_type":"tracing","attach_type":"trace_fentry","target_obj_id":1,"target_btf_id":13964,"pids":[{"pid":10673,"comm":"trace"}]}] Signed-off-by: Yafang Shao Acked-by: Song Liu Link: https://lore.kernel.org/r/20230517103126.68372-3-laoar.shao@gmail.com Signed-off-by: Alexei Starovoitov --- tools/bpf/bpftool/link.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/bpf/bpftool/link.c b/tools/bpf/bpftool/link.c index 243b74e18e51..2d786072ed0d 100644 --- a/tools/bpf/bpftool/link.c +++ b/tools/bpf/bpftool/link.c @@ -195,6 +195,8 @@ static int show_link_close_json(int fd, struct bpf_link_info *info) show_link_attach_type_json(info->tracing.attach_type, json_wtr); + jsonw_uint_field(json_wtr, "target_obj_id", info->tracing.target_obj_id); + jsonw_uint_field(json_wtr, "target_btf_id", info->tracing.target_btf_id); break; case BPF_LINK_TYPE_CGROUP: jsonw_lluint_field(json_wtr, "cgroup_id", @@ -375,6 +377,10 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info) printf("\n\tprog_type %u ", prog_info.type); show_link_attach_type_plain(info->tracing.attach_type); + if (info->tracing.target_obj_id || info->tracing.target_btf_id) + printf("\n\ttarget_obj_id %u target_btf_id %u ", + info->tracing.target_obj_id, + info->tracing.target_btf_id); break; case BPF_LINK_TYPE_CGROUP: printf("\n\tcgroup_id %zu ", (size_t)info->cgroup.cgroup_id); -- cgit v1.2.3 From c511822fe2c96478d86b6bc3404bb45ebad7556b Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Wed, 22 Mar 2023 13:27:43 +0200 Subject: net/mlx5: Remove redundant esw multiport validate function The function didn't validate the value and doesn't require value validation as it will always be valid true or false values. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 4b607785d694..0e07971e024a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -464,27 +464,6 @@ static int mlx5_devlink_esw_multiport_get(struct devlink *devlink, u32 id, ctx->val.vbool = mlx5_lag_is_mpesw(dev); return 0; } - -static int mlx5_devlink_esw_multiport_validate(struct devlink *devlink, u32 id, - union devlink_param_value val, - struct netlink_ext_ack *extack) -{ - struct mlx5_core_dev *dev = devlink_priv(devlink); - - if (!MLX5_ESWITCH_MANAGER(dev)) { - NL_SET_ERR_MSG_MOD(extack, "E-Switch is unsupported"); - return -EOPNOTSUPP; - } - - if (mlx5_eswitch_mode(dev) != MLX5_ESWITCH_OFFLOADS) { - NL_SET_ERR_MSG_MOD(extack, - "E-Switch must be in switchdev mode"); - return -EBUSY; - } - - return 0; -} - #endif static int mlx5_devlink_eq_depth_validate(struct devlink *devlink, u32 id, @@ -563,7 +542,7 @@ static const struct devlink_param mlx5_devlink_params[] = { BIT(DEVLINK_PARAM_CMODE_RUNTIME), mlx5_devlink_esw_multiport_get, mlx5_devlink_esw_multiport_set, - mlx5_devlink_esw_multiport_validate), + NULL), #endif DEVLINK_PARAM_GENERIC(IO_EQ_SIZE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL, mlx5_devlink_eq_depth_validate), -- cgit v1.2.3 From 2abe501751ed8dbd390be5c2f8d51125e3662814 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Thu, 23 Mar 2023 10:01:38 +0200 Subject: net/mlx5: E-Switch, Remove redundant check The call to mlx5_eswitch_enable() also does the same check and if E-Switch not supported it returns 0 without any change. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index 20d7662c10fb..f07d00929162 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -74,9 +74,6 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) struct mlx5_core_sriov *sriov = &dev->priv.sriov; int err, vf, num_msix_count; - if (!MLX5_ESWITCH_MANAGER(dev)) - goto enable_vfs_hca; - err = mlx5_eswitch_enable(dev->priv.eswitch, num_vfs); if (err) { mlx5_core_warn(dev, @@ -84,7 +81,6 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) return err; } -enable_vfs_hca: num_msix_count = mlx5_get_default_msix_vec_count(dev, num_vfs); for (vf = 0; vf < num_vfs; vf++) { /* Notify the VF before its enablement to let it set -- cgit v1.2.3 From edab80b89337b826566ff7fdbbc8ae2dcfb22fee Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Tue, 31 Jan 2023 12:06:45 +0200 Subject: net/mlx5e: E-Switch, Remove flow_source check for metadata matching There is no reason to check for flow_source cap to allow metadata matching. When flow_source match is being used the flow_source cap is being checked. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 69215ffb9999..ecd12a0c6f07 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2827,9 +2827,6 @@ bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw) MLX5_FDB_TO_VPORT_REG_C_0)) return false; - if (!MLX5_CAP_ESW_FLOWTABLE(esw->dev, flow_source)) - return false; - return true; } -- cgit v1.2.3 From 806815bf3c1d885e686ddc0e75d941078dcf56ae Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Thu, 30 Mar 2023 12:25:25 +0300 Subject: net/mlx5e: Remove redundant __func__ arg from fs_err() calls fs_err() already logs the function name. remote the arg so the function name will not be logged twice. Signed-off-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_fs.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c index 33bfe4d7338b..934b0d5ce1b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c @@ -283,7 +283,7 @@ static int __mlx5e_add_vlan_rule(struct mlx5e_flow_steering *fs, if (IS_ERR(*rule_p)) { err = PTR_ERR(*rule_p); *rule_p = NULL; - fs_err(fs, "%s: add rule failed\n", __func__); + fs_err(fs, "add rule failed\n"); } return err; @@ -395,8 +395,7 @@ int mlx5e_add_vlan_trap(struct mlx5e_flow_steering *fs, int trap_id, int tir_num if (IS_ERR(rule)) { err = PTR_ERR(rule); fs->vlan->trap_rule = NULL; - fs_err(fs, "%s: add VLAN trap rule failed, err %d\n", - __func__, err); + fs_err(fs, "add VLAN trap rule failed, err %d\n", err); return err; } fs->vlan->trap_rule = rule; @@ -421,8 +420,7 @@ int mlx5e_add_mac_trap(struct mlx5e_flow_steering *fs, int trap_id, int tir_num) if (IS_ERR(rule)) { err = PTR_ERR(rule); fs->l2.trap_rule = NULL; - fs_err(fs, "%s: add MAC trap rule failed, err %d\n", - __func__, err); + fs_err(fs, "add MAC trap rule failed, err %d\n", err); return err; } fs->l2.trap_rule = rule; @@ -763,7 +761,7 @@ static int mlx5e_add_promisc_rule(struct mlx5e_flow_steering *fs) if (IS_ERR(*rule_p)) { err = PTR_ERR(*rule_p); *rule_p = NULL; - fs_err(fs, "%s: add promiscuous rule failed\n", __func__); + fs_err(fs, "add promiscuous rule failed\n"); } kvfree(spec); return err; @@ -995,7 +993,7 @@ static int mlx5e_add_l2_flow_rule(struct mlx5e_flow_steering *fs, ai->rule = mlx5_add_flow_rules(ft, spec, &flow_act, &dest, 1); if (IS_ERR(ai->rule)) { - fs_err(fs, "%s: add l2 rule(mac:%pM) failed\n", __func__, mv_dmac); + fs_err(fs, "add l2 rule(mac:%pM) failed\n", mv_dmac); err = PTR_ERR(ai->rule); ai->rule = NULL; } -- cgit v1.2.3 From c97c9fe48ae3ccca75fb6001a3bd2bfcb094dbd7 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 2 Apr 2023 14:13:25 +0300 Subject: net/mlx5e: E-Switch, Update when to set other vport context Other vport context should be set if vport number is not 0. In case of ECPF, vport 0 represents the host PF representor so also need to set other vport context. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c index 45b839116212..d599e50af346 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c @@ -35,7 +35,8 @@ esw_acl_table_create(struct mlx5_eswitch *esw, struct mlx5_vport *vport, int ns, } ft_attr.max_fte = size; - ft_attr.flags = MLX5_FLOW_TABLE_OTHER_VPORT; + if (vport_num || mlx5_core_is_ecpf(esw->dev)) + ft_attr.flags = MLX5_FLOW_TABLE_OTHER_VPORT; acl = mlx5_create_vport_flow_table(root_ns, &ft_attr, vport_num); if (IS_ERR(acl)) { err = PTR_ERR(acl); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 901c53751b0a..bf97a593d1d4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -113,7 +113,8 @@ static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport, opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT); MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1); MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport); - MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1); + if (vport || mlx5_core_is_ecpf(dev)) + MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1); nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in, in, nic_vport_context); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index ba7e3df22413..bc66b078a8a1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -288,7 +288,8 @@ int mlx5_query_nic_vport_mac_list(struct mlx5_core_dev *dev, MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT); MLX5_SET(query_nic_vport_context_in, in, allowed_list_type, list_type); MLX5_SET(query_nic_vport_context_in, in, vport_number, vport); - MLX5_SET(query_nic_vport_context_in, in, other_vport, 1); + if (vport || mlx5_core_is_ecpf(dev)) + MLX5_SET(query_nic_vport_context_in, in, other_vport, 1); err = mlx5_cmd_exec(dev, in, sizeof(in), out, out_sz); if (err) -- cgit v1.2.3 From 99db5669f6635a9719beb2e78ebf5887cde03a26 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 2 Apr 2023 14:19:54 +0300 Subject: net/mlx5e: E-Switch, Allow get vport api if esw exists We could have an esw manager device which is not a vport group manager. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index bf97a593d1d4..692cea3a6383 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -92,7 +92,7 @@ mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num) { struct mlx5_vport *vport; - if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager)) + if (!esw) return ERR_PTR(-EPERM); vport = xa_load(&esw->vports, vport_num); -- cgit v1.2.3 From 29bcb6e4fe7072ccea2a1c8b357ffd8e88f334bb Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 2 Apr 2023 13:59:08 +0300 Subject: net/mlx5e: E-Switch, Use metadata for vport matching in send-to-vport rules Like other rules use metadata matching if supported instead of source_port. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 62 +++++++++++++++------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index ecd12a0c6f07..66a522d08be1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -838,6 +838,7 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw, struct mlx5_flow_handle *flow_rule; struct mlx5_flow_spec *spec; void *misc; + u16 vport; spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) { @@ -847,20 +848,43 @@ mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *on_esw, misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn); - /* source vport is the esw manager */ - MLX5_SET(fte_match_set_misc, misc, source_port, from_esw->manager_vport); - if (MLX5_CAP_ESW(on_esw->dev, merged_eswitch)) - MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id, - MLX5_CAP_GEN(from_esw->dev, vhca_id)); misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn); - MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); - if (MLX5_CAP_ESW(on_esw->dev, merged_eswitch)) - MLX5_SET_TO_ONES(fte_match_set_misc, misc, - source_eswitch_owner_vhca_id); spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS; + + /* source vport is the esw manager */ + vport = from_esw->manager_vport; + + if (mlx5_eswitch_vport_match_metadata_enabled(on_esw)) { + misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2); + MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0, + mlx5_eswitch_get_vport_metadata_for_match(from_esw, vport)); + + misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters_2); + MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0, + mlx5_eswitch_get_vport_metadata_mask()); + + spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_2; + } else { + misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); + MLX5_SET(fte_match_set_misc, misc, source_port, vport); + + if (MLX5_CAP_ESW(on_esw->dev, merged_eswitch)) + MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id, + MLX5_CAP_GEN(from_esw->dev, vhca_id)); + + misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); + MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); + + if (MLX5_CAP_ESW(on_esw->dev, merged_eswitch)) + MLX5_SET_TO_ONES(fte_match_set_misc, misc, + source_eswitch_owner_vhca_id); + + spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS; + } + dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT; dest.vport.num = rep->vport; dest.vport.vhca_id = MLX5_CAP_GEN(rep->esw->dev, vhca_id); @@ -1270,7 +1294,8 @@ esw_add_restore_rule(struct mlx5_eswitch *esw, u32 tag) #define MAX_SQ_NVPORTS 32 static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw, - u32 *flow_group_in) + u32 *flow_group_in, + int match_params) { void *match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, @@ -1279,7 +1304,7 @@ static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw, if (mlx5_eswitch_vport_match_metadata_enabled(esw)) { MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, - MLX5_MATCH_MISC_PARAMETERS_2); + MLX5_MATCH_MISC_PARAMETERS_2 | match_params); MLX5_SET(fte_match_param, match_criteria, misc_parameters_2.metadata_reg_c_0, @@ -1287,7 +1312,7 @@ static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw, } else { MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, - MLX5_MATCH_MISC_PARAMETERS); + MLX5_MATCH_MISC_PARAMETERS | match_params); MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port); @@ -1463,14 +1488,13 @@ esw_create_send_to_vport_group(struct mlx5_eswitch *esw, memset(flow_group_in, 0, inlen); - MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, - MLX5_MATCH_MISC_PARAMETERS); + esw_set_flow_group_source_port(esw, flow_group_in, MLX5_MATCH_MISC_PARAMETERS); match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); - MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn); - MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port); - if (MLX5_CAP_ESW(esw->dev, merged_eswitch)) { + + if (!mlx5_eswitch_vport_match_metadata_enabled(esw) && + MLX5_CAP_ESW(esw->dev, merged_eswitch)) { MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_eswitch_owner_vhca_id); MLX5_SET(create_flow_group_in, flow_group_in, @@ -1558,7 +1582,7 @@ esw_create_peer_esw_miss_group(struct mlx5_eswitch *esw, memset(flow_group_in, 0, inlen); - esw_set_flow_group_source_port(esw, flow_group_in); + esw_set_flow_group_source_port(esw, flow_group_in, 0); if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) { match_criteria = MLX5_ADDR_OF(create_flow_group_in, @@ -1845,7 +1869,7 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw) return -ENOMEM; /* create vport rx group */ - esw_set_flow_group_source_port(esw, flow_group_in); + esw_set_flow_group_source_port(esw, flow_group_in, 0); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1); -- cgit v1.2.3 From 6cb9318a2534b7081eb9f375a720972f811665f6 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Thu, 20 Apr 2023 12:14:41 +0300 Subject: net/mlx5: Remove redundant vport_group_manager cap check It's enough to check for esw_manager cap for get the esw flow table caps. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 7bb7be01225a..fb2035a5ec99 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -196,14 +196,11 @@ int mlx5_query_hca_caps(struct mlx5_core_dev *dev) return err; } - if (MLX5_CAP_GEN(dev, vport_group_manager) && - MLX5_ESWITCH_MANAGER(dev)) { + if (MLX5_ESWITCH_MANAGER(dev)) { err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH_FLOW_TABLE); if (err) return err; - } - if (MLX5_ESWITCH_MANAGER(dev)) { err = mlx5_core_get_caps(dev, MLX5_CAP_ESWITCH); if (err) return err; -- cgit v1.2.3 From bea416c7e970399b438b801a9f3ffa24c4ddf855 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 23 Apr 2023 10:53:18 +0300 Subject: net/mlx5e: E-Switch, Check device is PF when stopping esw offloads Checking sriov is done on the pci device so it can return true on other devices like SF but nothing should be done in this case. Add a check that the device is PF. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 66a522d08be1..44b5d1359155 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -3301,7 +3301,7 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw, /* If changing from switchdev to legacy mode without sriov enabled, * no need to create legacy fdb. */ - if (!mlx5_sriov_is_enabled(esw->dev)) + if (!mlx5_core_is_pf(esw->dev) || !mlx5_sriov_is_enabled(esw->dev)) return 0; err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS); -- cgit v1.2.3 From 292243d13b1821434599fef7b4ea62110ea771c1 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 23 Apr 2023 15:24:00 +0300 Subject: net/mlx5e: E-Switch: move debug print of adding mac to correct place Move the debug print inside the if clause that actually does the change. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 692cea3a6383..3e3963424285 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -310,11 +310,12 @@ static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) fdb_add: /* SRIOV is enabled: Forward UC MAC to vport */ - if (esw->fdb_table.legacy.fdb && esw->mode == MLX5_ESWITCH_LEGACY) + if (esw->fdb_table.legacy.fdb && esw->mode == MLX5_ESWITCH_LEGACY) { vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport); - esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n", - vport, mac, vaddr->flow_rule); + esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n", + vport, mac, vaddr->flow_rule); + } return 0; } -- cgit v1.2.3 From 3d7c5f78b8cef1376de95443632212f9042d7e78 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Thu, 20 Apr 2023 12:19:25 +0300 Subject: net/mlx5e: E-Switch, Add a check that log_max_l2_table is valid If log_max_l2_table is 0 there is no really room for one L2 address. and should be treated as not supported. Do the check in MPFS init and for vport context events which both used to update L2 address. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 6 +++++- drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 3e3963424285..9b71819e049a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -712,6 +712,9 @@ void esw_vport_change_handle_locked(struct mlx5_vport *vport) struct mlx5_eswitch *esw = dev->priv.eswitch; u8 mac[ETH_ALEN]; + if (!MLX5_CAP_GEN(dev, log_max_l2_table)) + return; + mlx5_query_nic_vport_mac_address(dev, vport->vport, true, mac); esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n", vport->vport, mac); @@ -948,7 +951,8 @@ void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, u16 vport_num) vport->enabled = false; /* Disable events from this vport */ - arm_vport_context_events_cmd(esw->dev, vport->vport, 0); + if (MLX5_CAP_GEN(esw->dev, log_max_l2_table)) + arm_vport_context_events_cmd(esw->dev, vport->vport, 0); if (!mlx5_esw_is_manager_vport(esw, vport->vport) && MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c index 8ff16318e32d..4450091e181a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mpfs.c @@ -99,7 +99,7 @@ int mlx5_mpfs_init(struct mlx5_core_dev *dev) int l2table_size = 1 << MLX5_CAP_GEN(dev, log_max_l2_table); struct mlx5_mpfs *mpfs; - if (!MLX5_ESWITCH_MANAGER(dev)) + if (!MLX5_ESWITCH_MANAGER(dev) || l2table_size == 1) return 0; mpfs = kzalloc(sizeof(*mpfs), GFP_KERNEL); -- cgit v1.2.3 From c24246d07a942887fb62cd76229c89efdee6d948 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Mon, 24 Apr 2023 12:11:13 +0300 Subject: net/mlx5: E-Switch, Use RoCE version 2 for loopback traffic Could be port initializing eswitch doesn't support RoCE version 1 but all ports should support RoCE version 2. Signed-off-by: Roi Dayan Reviewed-by: Maor Gottlieb Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/rdma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c index 540cf05f6373..15bb562b3846 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c @@ -115,7 +115,7 @@ free: static void mlx5_rdma_del_roce_addr(struct mlx5_core_dev *dev) { - mlx5_core_roce_gid_set(dev, 0, 0, 0, + mlx5_core_roce_gid_set(dev, 0, MLX5_ROCE_VERSION_2, 0, NULL, NULL, false, 0, 1); } @@ -135,7 +135,7 @@ static int mlx5_rdma_add_roce_addr(struct mlx5_core_dev *dev) mlx5_rdma_make_default_gid(dev, &gid); return mlx5_core_roce_gid_set(dev, 0, - MLX5_ROCE_VERSION_1, + MLX5_ROCE_VERSION_2, 0, gid.raw, mac, false, 0, 1); } -- cgit v1.2.3 From 7eb197fd83a355214346feddd55fe3336125953f Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Mon, 24 Apr 2023 12:15:54 +0300 Subject: net/mlx5: E-Switch, Use metadata matching for RoCE loopback rule Use metadata matching for RoCE loopback rule if device is configured to use metadata for source port matching. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 8 ++++ .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 46 +++++++++++++--------- drivers/net/ethernet/mellanox/mlx5/core/rdma.c | 20 ++-------- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 1a042c981713..6c5c05c414fb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -683,6 +683,14 @@ mlx5_esw_vporttbl_put(struct mlx5_eswitch *esw, struct mlx5_vport_tbl_attr *attr struct mlx5_flow_handle * esw_add_restore_rule(struct mlx5_eswitch *esw, u32 tag); +void mlx5_esw_set_flow_group_source_port(struct mlx5_eswitch *esw, + u32 *flow_group_in, + int match_params); + +void mlx5_esw_set_spec_source_port(struct mlx5_eswitch *esw, + u16 vport, + struct mlx5_flow_spec *spec); + int esw_offloads_load_rep(struct mlx5_eswitch *esw, u16 vport_num); void esw_offloads_unload_rep(struct mlx5_eswitch *esw, u16 vport_num); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 44b5d1359155..76db72f339d6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1293,9 +1293,10 @@ esw_add_restore_rule(struct mlx5_eswitch *esw, u32 tag) #define MAX_PF_SQ 256 #define MAX_SQ_NVPORTS 32 -static void esw_set_flow_group_source_port(struct mlx5_eswitch *esw, - u32 *flow_group_in, - int match_params) +void +mlx5_esw_set_flow_group_source_port(struct mlx5_eswitch *esw, + u32 *flow_group_in, + int match_params) { void *match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, @@ -1488,7 +1489,7 @@ esw_create_send_to_vport_group(struct mlx5_eswitch *esw, memset(flow_group_in, 0, inlen); - esw_set_flow_group_source_port(esw, flow_group_in, MLX5_MATCH_MISC_PARAMETERS); + mlx5_esw_set_flow_group_source_port(esw, flow_group_in, MLX5_MATCH_MISC_PARAMETERS); match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn); @@ -1582,7 +1583,7 @@ esw_create_peer_esw_miss_group(struct mlx5_eswitch *esw, memset(flow_group_in, 0, inlen); - esw_set_flow_group_source_port(esw, flow_group_in, 0); + mlx5_esw_set_flow_group_source_port(esw, flow_group_in, 0); if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) { match_criteria = MLX5_ADDR_OF(create_flow_group_in, @@ -1869,7 +1870,7 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw) return -ENOMEM; /* create vport rx group */ - esw_set_flow_group_source_port(esw, flow_group_in, 0); + mlx5_esw_set_flow_group_source_port(esw, flow_group_in, 0); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1); @@ -1939,21 +1940,13 @@ static void esw_destroy_vport_rx_drop_group(struct mlx5_eswitch *esw) mlx5_destroy_flow_group(esw->offloads.vport_rx_drop_group); } -struct mlx5_flow_handle * -mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, u16 vport, - struct mlx5_flow_destination *dest) +void +mlx5_esw_set_spec_source_port(struct mlx5_eswitch *esw, + u16 vport, + struct mlx5_flow_spec *spec) { - struct mlx5_flow_act flow_act = {0}; - struct mlx5_flow_handle *flow_rule; - struct mlx5_flow_spec *spec; void *misc; - spec = kvzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) { - flow_rule = ERR_PTR(-ENOMEM); - goto out; - } - if (mlx5_eswitch_vport_match_metadata_enabled(esw)) { misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters_2); MLX5_SET(fte_match_set_misc2, misc, metadata_reg_c_0, @@ -1973,6 +1966,23 @@ mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, u16 vport, spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS; } +} + +struct mlx5_flow_handle * +mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, u16 vport, + struct mlx5_flow_destination *dest) +{ + struct mlx5_flow_act flow_act = {0}; + struct mlx5_flow_handle *flow_rule; + struct mlx5_flow_spec *spec; + + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) { + flow_rule = ERR_PTR(-ENOMEM); + goto out; + } + + mlx5_esw_set_spec_source_port(esw, vport, spec); flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c index 15bb562b3846..a42f6cd99b74 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/rdma.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/rdma.c @@ -30,9 +30,8 @@ static int mlx5_rdma_enable_roce_steering(struct mlx5_core_dev *dev) struct mlx5_flow_spec *spec; struct mlx5_flow_table *ft; struct mlx5_flow_group *fg; - void *match_criteria; + struct mlx5_eswitch *esw; u32 *flow_group_in; - void *misc; int err; if (!(MLX5_CAP_FLOWTABLE_RDMA_RX(dev, ft_support) && @@ -63,12 +62,8 @@ static int mlx5_rdma_enable_roce_steering(struct mlx5_core_dev *dev) goto free; } - MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, - MLX5_MATCH_MISC_PARAMETERS); - match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, - match_criteria); - MLX5_SET_TO_ONES(fte_match_param, match_criteria, - misc_parameters.source_port); + esw = dev->priv.eswitch; + mlx5_esw_set_flow_group_source_port(esw, flow_group_in, 0); fg = mlx5_create_flow_group(ft, flow_group_in); if (IS_ERR(fg)) { @@ -77,14 +72,7 @@ static int mlx5_rdma_enable_roce_steering(struct mlx5_core_dev *dev) goto destroy_flow_table; } - spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS; - misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, - misc_parameters); - MLX5_SET(fte_match_set_misc, misc, source_port, - dev->priv.eswitch->manager_vport); - misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, - misc_parameters); - MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); + mlx5_esw_set_spec_source_port(esw, esw->manager_vport, spec); flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW; flow_rule = mlx5_add_flow_rules(ft, spec, &flow_act, NULL, 0); -- cgit v1.2.3 From 0279b5454c0e8344f30fcac90db76cf17b6b76c7 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Tue, 2 May 2023 12:44:47 +0300 Subject: net/mlx5: devlink, Only show PF related devlink warning when needed Limit the PF related warning to show if device is actually a PF. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 0e07971e024a..bfaec67abf0d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -162,9 +162,8 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, return -EOPNOTSUPP; } - if (pci_num_vf(pdev)) { + if (mlx5_core_is_pf(dev) && pci_num_vf(pdev)) NL_SET_ERR_MSG_MOD(extack, "reload while VFs are present is unfavorable"); - } switch (action) { case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: -- cgit v1.2.3 From f5d87b47a1d9dc14c048c84935397d97833ac706 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 23 Apr 2023 13:39:57 +0300 Subject: net/mlx5e: E-Switch, Initialize E-Switch for eswitch manager Initialize eswitch instance for a function which is eswitch manager but not a vport group manager. Signed-off-by: Roi Dayan Reviewed-by: Maor Dickman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 9b71819e049a..31956cd9d1bb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1622,7 +1622,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) struct mlx5_eswitch *esw; int err; - if (!MLX5_VPORT_MANAGER(dev)) + if (!MLX5_VPORT_MANAGER(dev) && !MLX5_ESWITCH_MANAGER(dev)) return 0; esw = kzalloc(sizeof(*esw), GFP_KERNEL); @@ -1692,7 +1692,7 @@ abort: void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) { - if (!esw || !MLX5_VPORT_MANAGER(esw->dev)) + if (!esw) return; esw_info(esw->dev, "cleanup\n"); -- cgit v1.2.3 From 9378096e8a656fb5c4099b26b1370c56f056eab9 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:49 +0000 Subject: bpf: tcp: Avoid taking fast sock lock in iterator This is a preparatory commit to replace `lock_sock_fast` with `lock_sock`,and facilitate BPF programs executed from the TCP sockets iterator to be able to destroy TCP sockets using the bpf_sock_destroy kfunc (implemented in follow-up commits). Previously, BPF TCP iterator was acquiring the sock lock with BH disabled. This led to scenarios where the sockets hash table bucket lock can be acquired with BH enabled in some path versus disabled in other. In such situation, kernel issued a warning since it thinks that in the BH enabled path the same bucket lock *might* be acquired again in the softirq context (BH disabled), which will lead to a potential dead lock. Since bpf_sock_destroy also happens in a process context, the potential deadlock warning is likely a false alarm. Here is a snippet of annotated stack trace that motivated this change: ``` Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&h->lhash2[i].lock); local_bh_disable(); lock(&h->lhash2[i].lock); kernel imagined possible scenario: local_bh_disable(); /* Possible softirq */ lock(&h->lhash2[i].lock); *** Potential Deadlock *** process context: lock_acquire+0xcd/0x330 _raw_spin_lock+0x33/0x40 ------> Acquire (bucket) lhash2.lock with BH enabled __inet_hash+0x4b/0x210 inet_csk_listen_start+0xe6/0x100 inet_listen+0x95/0x1d0 __sys_listen+0x69/0xb0 __x64_sys_listen+0x14/0x20 do_syscall_64+0x3c/0x90 entry_SYSCALL_64_after_hwframe+0x72/0xdc bpf_sock_destroy run from iterator: lock_acquire+0xcd/0x330 _raw_spin_lock+0x33/0x40 ------> Acquire (bucket) lhash2.lock with BH disabled inet_unhash+0x9a/0x110 tcp_set_state+0x6a/0x210 tcp_abort+0x10d/0x200 bpf_prog_6793c5ca50c43c0d_iter_tcp6_server+0xa4/0xa9 bpf_iter_run_prog+0x1ff/0x340 ------> lock_sock_fast that acquires sock lock with BH disabled bpf_iter_tcp_seq_show+0xca/0x190 bpf_seq_read+0x177/0x450 ``` Also, Yonghong reported a deadlock for non-listening TCP sockets that this change resolves. Previously, `lock_sock_fast` held the sock spin lock with BH which was again being acquired in `tcp_abort`: ``` watchdog: BUG: soft lockup - CPU#0 stuck for 86s! [test_progs:2331] RIP: 0010:queued_spin_lock_slowpath+0xd8/0x500 Call Trace: _raw_spin_lock+0x84/0x90 tcp_abort+0x13c/0x1f0 bpf_prog_88539c5453a9dd47_iter_tcp6_client+0x82/0x89 bpf_iter_run_prog+0x1aa/0x2c0 ? preempt_count_sub+0x1c/0xd0 ? from_kuid_munged+0x1c8/0x210 bpf_iter_tcp_seq_show+0x14e/0x1b0 bpf_seq_read+0x36c/0x6a0 bpf_iter_tcp_seq_show lock_sock_fast __lock_sock_fast spin_lock_bh(&sk->sk_lock.slock); /* * Fast path return with bottom halves disabled and * sock::sk_lock.slock held.* */ ... tcp_abort local_bh_disable(); spin_lock(&((sk)->sk_lock.slock)); // from bh_lock_sock(sk) ``` With the switch to `lock_sock`, it calls `spin_unlock_bh` before returning: ``` lock_sock lock_sock_nested spin_lock_bh(&sk->sk_lock.slock); : spin_unlock_bh(&sk->sk_lock.slock); ``` Acked-by: Yonghong Song Acked-by: Stanislav Fomichev Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-2-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- net/ipv4/tcp_ipv4.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index db24ed8f8509..6e945199709b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2962,7 +2962,6 @@ static int bpf_iter_tcp_seq_show(struct seq_file *seq, void *v) struct bpf_iter_meta meta; struct bpf_prog *prog; struct sock *sk = v; - bool slow; uid_t uid; int ret; @@ -2970,7 +2969,7 @@ static int bpf_iter_tcp_seq_show(struct seq_file *seq, void *v) return 0; if (sk_fullsock(sk)) - slow = lock_sock_fast(sk); + lock_sock(sk); if (unlikely(sk_unhashed(sk))) { ret = SEQ_SKIP; @@ -2994,7 +2993,7 @@ static int bpf_iter_tcp_seq_show(struct seq_file *seq, void *v) unlock: if (sk_fullsock(sk)) - unlock_sock_fast(sk, slow); + release_sock(sk); return ret; } -- cgit v1.2.3 From f44b1c515833c59701c86f92d47b4edd478fb0f3 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:50 +0000 Subject: udp: seq_file: Helper function to match socket attributes This is a preparatory commit to refactor code that matches socket attributes in iterators to a helper function, and use it in the proc fs iterator. Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-3-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- net/ipv4/udp.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index aa32afd871ee..9d56a96672c6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2988,6 +2988,16 @@ EXPORT_SYMBOL(udp_prot); /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS +static unsigned short seq_file_family(const struct seq_file *seq); +static bool seq_sk_match(struct seq_file *seq, const struct sock *sk) +{ + unsigned short family = seq_file_family(seq); + + /* AF_UNSPEC is used as a match all */ + return ((family == AF_UNSPEC || family == sk->sk_family) && + net_eq(sock_net(sk), seq_file_net(seq))); +} + static struct udp_table *udp_get_table_afinfo(struct udp_seq_afinfo *afinfo, struct net *net) { @@ -3018,10 +3028,7 @@ static struct sock *udp_get_first(struct seq_file *seq, int start) spin_lock_bh(&hslot->lock); sk_for_each(sk, &hslot->head) { - if (!net_eq(sock_net(sk), net)) - continue; - if (afinfo->family == AF_UNSPEC || - sk->sk_family == afinfo->family) + if (seq_sk_match(seq, sk)) goto found; } spin_unlock_bh(&hslot->lock); @@ -3045,9 +3052,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) do { sk = sk_next(sk); - } while (sk && (!net_eq(sock_net(sk), net) || - (afinfo->family != AF_UNSPEC && - sk->sk_family != afinfo->family))); + } while (sk && !seq_sk_match(seq, sk)); if (!sk) { udptable = udp_get_table_afinfo(afinfo, net); @@ -3210,6 +3215,21 @@ static const struct seq_operations bpf_iter_udp_seq_ops = { }; #endif +static unsigned short seq_file_family(const struct seq_file *seq) +{ + const struct udp_seq_afinfo *afinfo; + +#ifdef CONFIG_BPF_SYSCALL + /* BPF iterator: bpf programs to filter sockets. */ + if (seq->op == &bpf_iter_udp_seq_ops) + return AF_UNSPEC; +#endif + + /* Proc fs iterator */ + afinfo = pde_data(file_inode(seq->file)); + return afinfo->family; +} + const struct seq_operations udp_seq_ops = { .start = udp_seq_start, .next = udp_seq_next, -- cgit v1.2.3 From 7625d2e9741c1f6e08ee79c28a1e27bbb5071805 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:51 +0000 Subject: bpf: udp: Encapsulate logic to get udp table This is a preparatory commit that encapsulates the logic to get udp table in iterator inside udp_get_table_afinfo, and renames the function to `udp_get_table_seq` accordingly. Suggested-by: Martin KaFai Lau Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-4-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- net/ipv4/udp.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9d56a96672c6..9dc98ac9a292 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2998,9 +2998,16 @@ static bool seq_sk_match(struct seq_file *seq, const struct sock *sk) net_eq(sock_net(sk), seq_file_net(seq))); } -static struct udp_table *udp_get_table_afinfo(struct udp_seq_afinfo *afinfo, - struct net *net) +static struct udp_table *udp_get_table_seq(struct seq_file *seq, + struct net *net) { + const struct udp_iter_state *state = seq->private; + const struct udp_seq_afinfo *afinfo; + + if (state->bpf_seq_afinfo) + return net->ipv4.udp_table; + + afinfo = pde_data(file_inode(seq->file)); return afinfo->udp_table ? : net->ipv4.udp_table; } @@ -3008,16 +3015,10 @@ static struct sock *udp_get_first(struct seq_file *seq, int start) { struct udp_iter_state *state = seq->private; struct net *net = seq_file_net(seq); - struct udp_seq_afinfo *afinfo; struct udp_table *udptable; struct sock *sk; - if (state->bpf_seq_afinfo) - afinfo = state->bpf_seq_afinfo; - else - afinfo = pde_data(file_inode(seq->file)); - - udptable = udp_get_table_afinfo(afinfo, net); + udptable = udp_get_table_seq(seq, net); for (state->bucket = start; state->bucket <= udptable->mask; ++state->bucket) { @@ -3042,20 +3043,14 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) { struct udp_iter_state *state = seq->private; struct net *net = seq_file_net(seq); - struct udp_seq_afinfo *afinfo; struct udp_table *udptable; - if (state->bpf_seq_afinfo) - afinfo = state->bpf_seq_afinfo; - else - afinfo = pde_data(file_inode(seq->file)); - do { sk = sk_next(sk); } while (sk && !seq_sk_match(seq, sk)); if (!sk) { - udptable = udp_get_table_afinfo(afinfo, net); + udptable = udp_get_table_seq(seq, net); if (state->bucket <= udptable->mask) spin_unlock_bh(&udptable->hash[state->bucket].lock); @@ -3101,15 +3096,9 @@ EXPORT_SYMBOL(udp_seq_next); void udp_seq_stop(struct seq_file *seq, void *v) { struct udp_iter_state *state = seq->private; - struct udp_seq_afinfo *afinfo; struct udp_table *udptable; - if (state->bpf_seq_afinfo) - afinfo = state->bpf_seq_afinfo; - else - afinfo = pde_data(file_inode(seq->file)); - - udptable = udp_get_table_afinfo(afinfo, seq_file_net(seq)); + udptable = udp_get_table_seq(seq, seq_file_net(seq)); if (state->bucket <= udptable->mask) spin_unlock_bh(&udptable->hash[state->bucket].lock); -- cgit v1.2.3 From e4fe1bf13e09019578b9b93b942fff3d76ed5793 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:52 +0000 Subject: udp: seq_file: Remove bpf_seq_afinfo from udp_iter_state This is a preparatory commit to remove the field. The field was previously shared between proc fs and BPF UDP socket iterators. As the follow-up commits will decouple the implementation for the iterators, remove the field. As for BPF socket iterator, filtering of sockets is exepected to be done in BPF programs. Suggested-by: Martin KaFai Lau Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-5-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- include/net/udp.h | 1 - net/ipv4/udp.c | 27 +++++++-------------------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/include/net/udp.h b/include/net/udp.h index de4b528522bb..5cad44318d71 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -437,7 +437,6 @@ struct udp_seq_afinfo { struct udp_iter_state { struct seq_net_private p; int bucket; - struct udp_seq_afinfo *bpf_seq_afinfo; }; void *udp_seq_start(struct seq_file *seq, loff_t *pos); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9dc98ac9a292..0053386e938e 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2998,14 +2998,18 @@ static bool seq_sk_match(struct seq_file *seq, const struct sock *sk) net_eq(sock_net(sk), seq_file_net(seq))); } +#ifdef CONFIG_BPF_SYSCALL +static const struct seq_operations bpf_iter_udp_seq_ops; +#endif static struct udp_table *udp_get_table_seq(struct seq_file *seq, struct net *net) { - const struct udp_iter_state *state = seq->private; const struct udp_seq_afinfo *afinfo; - if (state->bpf_seq_afinfo) +#ifdef CONFIG_BPF_SYSCALL + if (seq->op == &bpf_iter_udp_seq_ops) return net->ipv4.udp_table; +#endif afinfo = pde_data(file_inode(seq->file)); return afinfo->udp_table ? : net->ipv4.udp_table; @@ -3429,28 +3433,11 @@ DEFINE_BPF_ITER_FUNC(udp, struct bpf_iter_meta *meta, static int bpf_iter_init_udp(void *priv_data, struct bpf_iter_aux_info *aux) { - struct udp_iter_state *st = priv_data; - struct udp_seq_afinfo *afinfo; - int ret; - - afinfo = kmalloc(sizeof(*afinfo), GFP_USER | __GFP_NOWARN); - if (!afinfo) - return -ENOMEM; - - afinfo->family = AF_UNSPEC; - afinfo->udp_table = NULL; - st->bpf_seq_afinfo = afinfo; - ret = bpf_iter_init_seq_net(priv_data, aux); - if (ret) - kfree(afinfo); - return ret; + return bpf_iter_init_seq_net(priv_data, aux); } static void bpf_iter_fini_udp(void *priv_data) { - struct udp_iter_state *st = priv_data; - - kfree(st->bpf_seq_afinfo); bpf_iter_fini_seq_net(priv_data); } -- cgit v1.2.3 From c96dac8d369ffd713a45f4e5c30f23c47a1671f0 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:53 +0000 Subject: bpf: udp: Implement batching for sockets iterator Batch UDP sockets from BPF iterator that allows for overlapping locking semantics in BPF/kernel helpers executed in BPF programs. This facilitates BPF socket destroy kfunc (introduced by follow-up patches) to execute from BPF iterator programs. Previously, BPF iterators acquired the sock lock and sockets hash table bucket lock while executing BPF programs. This prevented BPF helpers that again acquire these locks to be executed from BPF iterators. With the batching approach, we acquire a bucket lock, batch all the bucket sockets, and then release the bucket lock. This enables BPF or kernel helpers to skip sock locking when invoked in the supported BPF contexts. The batching logic is similar to the logic implemented in TCP iterator: https://lore.kernel.org/bpf/20210701200613.1036157-1-kafai@fb.com/. Suggested-by: Martin KaFai Lau Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-6-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- net/ipv4/udp.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 199 insertions(+), 6 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0053386e938e..0c999aa5ab30 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -3155,6 +3155,143 @@ struct bpf_iter__udp { int bucket __aligned(8); }; +struct bpf_udp_iter_state { + struct udp_iter_state state; + unsigned int cur_sk; + unsigned int end_sk; + unsigned int max_sk; + int offset; + struct sock **batch; + bool st_bucket_done; +}; + +static int bpf_iter_udp_realloc_batch(struct bpf_udp_iter_state *iter, + unsigned int new_batch_sz); +static struct sock *bpf_iter_udp_batch(struct seq_file *seq) +{ + struct bpf_udp_iter_state *iter = seq->private; + struct udp_iter_state *state = &iter->state; + struct net *net = seq_file_net(seq); + struct udp_table *udptable; + unsigned int batch_sks = 0; + bool resized = false; + struct sock *sk; + + /* The current batch is done, so advance the bucket. */ + if (iter->st_bucket_done) { + state->bucket++; + iter->offset = 0; + } + + udptable = udp_get_table_seq(seq, net); + +again: + /* New batch for the next bucket. + * Iterate over the hash table to find a bucket with sockets matching + * the iterator attributes, and return the first matching socket from + * the bucket. The remaining matched sockets from the bucket are batched + * before releasing the bucket lock. This allows BPF programs that are + * called in seq_show to acquire the bucket lock if needed. + */ + iter->cur_sk = 0; + iter->end_sk = 0; + iter->st_bucket_done = false; + batch_sks = 0; + + for (; state->bucket <= udptable->mask; state->bucket++) { + struct udp_hslot *hslot2 = &udptable->hash2[state->bucket]; + + if (hlist_empty(&hslot2->head)) { + iter->offset = 0; + continue; + } + + spin_lock_bh(&hslot2->lock); + udp_portaddr_for_each_entry(sk, &hslot2->head) { + if (seq_sk_match(seq, sk)) { + /* Resume from the last iterated socket at the + * offset in the bucket before iterator was stopped. + */ + if (iter->offset) { + --iter->offset; + continue; + } + if (iter->end_sk < iter->max_sk) { + sock_hold(sk); + iter->batch[iter->end_sk++] = sk; + } + batch_sks++; + } + } + spin_unlock_bh(&hslot2->lock); + + if (iter->end_sk) + break; + + /* Reset the current bucket's offset before moving to the next bucket. */ + iter->offset = 0; + } + + /* All done: no batch made. */ + if (!iter->end_sk) + return NULL; + + if (iter->end_sk == batch_sks) { + /* Batching is done for the current bucket; return the first + * socket to be iterated from the batch. + */ + iter->st_bucket_done = true; + goto done; + } + if (!resized && !bpf_iter_udp_realloc_batch(iter, batch_sks * 3 / 2)) { + resized = true; + /* After allocating a larger batch, retry one more time to grab + * the whole bucket. + */ + state->bucket--; + goto again; + } +done: + return iter->batch[0]; +} + +static void *bpf_iter_udp_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct bpf_udp_iter_state *iter = seq->private; + struct sock *sk; + + /* Whenever seq_next() is called, the iter->cur_sk is + * done with seq_show(), so unref the iter->cur_sk. + */ + if (iter->cur_sk < iter->end_sk) { + sock_put(iter->batch[iter->cur_sk++]); + ++iter->offset; + } + + /* After updating iter->cur_sk, check if there are more sockets + * available in the current bucket batch. + */ + if (iter->cur_sk < iter->end_sk) + sk = iter->batch[iter->cur_sk]; + else + /* Prepare a new batch. */ + sk = bpf_iter_udp_batch(seq); + + ++*pos; + return sk; +} + +static void *bpf_iter_udp_seq_start(struct seq_file *seq, loff_t *pos) +{ + /* bpf iter does not support lseek, so it always + * continue from where it was stop()-ped. + */ + if (*pos) + return bpf_iter_udp_batch(seq); + + return SEQ_START_TOKEN; +} + static int udp_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta, struct udp_sock *udp_sk, uid_t uid, int bucket) { @@ -3175,18 +3312,37 @@ static int bpf_iter_udp_seq_show(struct seq_file *seq, void *v) struct bpf_prog *prog; struct sock *sk = v; uid_t uid; + int ret; if (v == SEQ_START_TOKEN) return 0; + lock_sock(sk); + + if (unlikely(sk_unhashed(sk))) { + ret = SEQ_SKIP; + goto unlock; + } + uid = from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)); meta.seq = seq; prog = bpf_iter_get_info(&meta, false); - return udp_prog_seq_show(prog, &meta, v, uid, state->bucket); + ret = udp_prog_seq_show(prog, &meta, v, uid, state->bucket); + +unlock: + release_sock(sk); + return ret; +} + +static void bpf_iter_udp_put_batch(struct bpf_udp_iter_state *iter) +{ + while (iter->cur_sk < iter->end_sk) + sock_put(iter->batch[iter->cur_sk++]); } static void bpf_iter_udp_seq_stop(struct seq_file *seq, void *v) { + struct bpf_udp_iter_state *iter = seq->private; struct bpf_iter_meta meta; struct bpf_prog *prog; @@ -3197,12 +3353,15 @@ static void bpf_iter_udp_seq_stop(struct seq_file *seq, void *v) (void)udp_prog_seq_show(prog, &meta, v, 0, 0); } - udp_seq_stop(seq, v); + if (iter->cur_sk < iter->end_sk) { + bpf_iter_udp_put_batch(iter); + iter->st_bucket_done = false; + } } static const struct seq_operations bpf_iter_udp_seq_ops = { - .start = udp_seq_start, - .next = udp_seq_next, + .start = bpf_iter_udp_seq_start, + .next = bpf_iter_udp_seq_next, .stop = bpf_iter_udp_seq_stop, .show = bpf_iter_udp_seq_show, }; @@ -3431,21 +3590,55 @@ static struct pernet_operations __net_initdata udp_sysctl_ops = { DEFINE_BPF_ITER_FUNC(udp, struct bpf_iter_meta *meta, struct udp_sock *udp_sk, uid_t uid, int bucket) +static int bpf_iter_udp_realloc_batch(struct bpf_udp_iter_state *iter, + unsigned int new_batch_sz) +{ + struct sock **new_batch; + + new_batch = kvmalloc_array(new_batch_sz, sizeof(*new_batch), + GFP_USER | __GFP_NOWARN); + if (!new_batch) + return -ENOMEM; + + bpf_iter_udp_put_batch(iter); + kvfree(iter->batch); + iter->batch = new_batch; + iter->max_sk = new_batch_sz; + + return 0; +} + +#define INIT_BATCH_SZ 16 + static int bpf_iter_init_udp(void *priv_data, struct bpf_iter_aux_info *aux) { - return bpf_iter_init_seq_net(priv_data, aux); + struct bpf_udp_iter_state *iter = priv_data; + int ret; + + ret = bpf_iter_init_seq_net(priv_data, aux); + if (ret) + return ret; + + ret = bpf_iter_udp_realloc_batch(iter, INIT_BATCH_SZ); + if (ret) + bpf_iter_fini_seq_net(priv_data); + + return ret; } static void bpf_iter_fini_udp(void *priv_data) { + struct bpf_udp_iter_state *iter = priv_data; + bpf_iter_fini_seq_net(priv_data); + kvfree(iter->batch); } static const struct bpf_iter_seq_info udp_seq_info = { .seq_ops = &bpf_iter_udp_seq_ops, .init_seq_private = bpf_iter_init_udp, .fini_seq_private = bpf_iter_fini_udp, - .seq_priv_size = sizeof(struct udp_iter_state), + .seq_priv_size = sizeof(struct bpf_udp_iter_state), }; static struct bpf_iter_reg udp_reg_info = { -- cgit v1.2.3 From e924e80ee6a39bc28d2ef8f51e19d336a98e3be0 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:54 +0000 Subject: bpf: Add kfunc filter function to 'struct btf_kfunc_id_set' This commit adds the ability to filter kfuncs to certain BPF program types. This is required to limit bpf_sock_destroy kfunc implemented in follow-up commits to programs with attach type 'BPF_TRACE_ITER'. The commit adds a callback filter to 'struct btf_kfunc_id_set'. The filter has access to the `bpf_prog` construct including its properties such as `expected_attached_type`. Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-7-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- include/linux/btf.h | 18 ++++++++------ kernel/bpf/btf.c | 65 ++++++++++++++++++++++++++++++++++++++++++--------- kernel/bpf/verifier.c | 7 +++--- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/include/linux/btf.h b/include/linux/btf.h index 508199e38415..cac9f304e27a 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -98,10 +98,14 @@ struct btf_type; union bpf_attr; struct btf_show; struct btf_id_set; +struct bpf_prog; + +typedef int (*btf_kfunc_filter_t)(const struct bpf_prog *prog, u32 kfunc_id); struct btf_kfunc_id_set { struct module *owner; struct btf_id_set8 *set; + btf_kfunc_filter_t filter; }; struct btf_id_dtor_kfunc { @@ -479,7 +483,6 @@ static inline void *btf_id_set8_contains(const struct btf_id_set8 *set, u32 id) return bsearch(&id, set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func); } -struct bpf_prog; struct bpf_verifier_log; #ifdef CONFIG_BPF_SYSCALL @@ -487,10 +490,10 @@ const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); const char *btf_name_by_offset(const struct btf *btf, u32 offset); struct btf *btf_parse_vmlinux(void); struct btf *bpf_prog_get_target_btf(const struct bpf_prog *prog); -u32 *btf_kfunc_id_set_contains(const struct btf *btf, - enum bpf_prog_type prog_type, - u32 kfunc_btf_id); -u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id); +u32 *btf_kfunc_id_set_contains(const struct btf *btf, u32 kfunc_btf_id, + const struct bpf_prog *prog); +u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id, + const struct bpf_prog *prog); int register_btf_kfunc_id_set(enum bpf_prog_type prog_type, const struct btf_kfunc_id_set *s); int register_btf_fmodret_id_set(const struct btf_kfunc_id_set *kset); @@ -517,8 +520,9 @@ static inline const char *btf_name_by_offset(const struct btf *btf, return NULL; } static inline u32 *btf_kfunc_id_set_contains(const struct btf *btf, - enum bpf_prog_type prog_type, - u32 kfunc_btf_id) + u32 kfunc_btf_id, + struct bpf_prog *prog) + { return NULL; } diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 6b682b8e4b50..947f0b83bfad 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -222,10 +222,17 @@ enum btf_kfunc_hook { enum { BTF_KFUNC_SET_MAX_CNT = 256, BTF_DTOR_KFUNC_MAX_CNT = 256, + BTF_KFUNC_FILTER_MAX_CNT = 16, +}; + +struct btf_kfunc_hook_filter { + btf_kfunc_filter_t filters[BTF_KFUNC_FILTER_MAX_CNT]; + u32 nr_filters; }; struct btf_kfunc_set_tab { struct btf_id_set8 *sets[BTF_KFUNC_HOOK_MAX]; + struct btf_kfunc_hook_filter hook_filters[BTF_KFUNC_HOOK_MAX]; }; struct btf_id_dtor_kfunc_tab { @@ -7669,9 +7676,12 @@ static int btf_check_kfunc_protos(struct btf *btf, u32 func_id, u32 func_flags) /* Kernel Function (kfunc) BTF ID set registration API */ static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook, - struct btf_id_set8 *add_set) + const struct btf_kfunc_id_set *kset) { + struct btf_kfunc_hook_filter *hook_filter; + struct btf_id_set8 *add_set = kset->set; bool vmlinux_set = !btf_is_module(btf); + bool add_filter = !!kset->filter; struct btf_kfunc_set_tab *tab; struct btf_id_set8 *set; u32 set_cnt; @@ -7686,6 +7696,24 @@ static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook, return 0; tab = btf->kfunc_set_tab; + + if (tab && add_filter) { + u32 i; + + hook_filter = &tab->hook_filters[hook]; + for (i = 0; i < hook_filter->nr_filters; i++) { + if (hook_filter->filters[i] == kset->filter) { + add_filter = false; + break; + } + } + + if (add_filter && hook_filter->nr_filters == BTF_KFUNC_FILTER_MAX_CNT) { + ret = -E2BIG; + goto end; + } + } + if (!tab) { tab = kzalloc(sizeof(*tab), GFP_KERNEL | __GFP_NOWARN); if (!tab) @@ -7708,7 +7736,7 @@ static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook, */ if (!vmlinux_set) { tab->sets[hook] = add_set; - return 0; + goto do_add_filter; } /* In case of vmlinux sets, there may be more than one set being @@ -7750,6 +7778,11 @@ static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook, sort(set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func, NULL); +do_add_filter: + if (add_filter) { + hook_filter = &tab->hook_filters[hook]; + hook_filter->filters[hook_filter->nr_filters++] = kset->filter; + } return 0; end: btf_free_kfunc_set_tab(btf); @@ -7758,15 +7791,22 @@ end: static u32 *__btf_kfunc_id_set_contains(const struct btf *btf, enum btf_kfunc_hook hook, - u32 kfunc_btf_id) + u32 kfunc_btf_id, + const struct bpf_prog *prog) { + struct btf_kfunc_hook_filter *hook_filter; struct btf_id_set8 *set; - u32 *id; + u32 *id, i; if (hook >= BTF_KFUNC_HOOK_MAX) return NULL; if (!btf->kfunc_set_tab) return NULL; + hook_filter = &btf->kfunc_set_tab->hook_filters[hook]; + for (i = 0; i < hook_filter->nr_filters; i++) { + if (hook_filter->filters[i](prog, kfunc_btf_id)) + return NULL; + } set = btf->kfunc_set_tab->sets[hook]; if (!set) return NULL; @@ -7821,23 +7861,25 @@ static int bpf_prog_type_to_kfunc_hook(enum bpf_prog_type prog_type) * protection for looking up a well-formed btf->kfunc_set_tab. */ u32 *btf_kfunc_id_set_contains(const struct btf *btf, - enum bpf_prog_type prog_type, - u32 kfunc_btf_id) + u32 kfunc_btf_id, + const struct bpf_prog *prog) { + enum bpf_prog_type prog_type = resolve_prog_type(prog); enum btf_kfunc_hook hook; u32 *kfunc_flags; - kfunc_flags = __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_COMMON, kfunc_btf_id); + kfunc_flags = __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_COMMON, kfunc_btf_id, prog); if (kfunc_flags) return kfunc_flags; hook = bpf_prog_type_to_kfunc_hook(prog_type); - return __btf_kfunc_id_set_contains(btf, hook, kfunc_btf_id); + return __btf_kfunc_id_set_contains(btf, hook, kfunc_btf_id, prog); } -u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id) +u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id, + const struct bpf_prog *prog) { - return __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_FMODRET, kfunc_btf_id); + return __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_FMODRET, kfunc_btf_id, prog); } static int __register_btf_kfunc_id_set(enum btf_kfunc_hook hook, @@ -7868,7 +7910,8 @@ static int __register_btf_kfunc_id_set(enum btf_kfunc_hook hook, goto err_out; } - ret = btf_populate_kfunc_set(btf, hook, kset->set); + ret = btf_populate_kfunc_set(btf, hook, kset); + err_out: btf_put(btf); return ret; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f597491259ab..af70dad655ab 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10939,7 +10939,7 @@ static int fetch_kfunc_meta(struct bpf_verifier_env *env, *kfunc_name = func_name; func_proto = btf_type_by_id(desc_btf, func->type); - kfunc_flags = btf_kfunc_id_set_contains(desc_btf, resolve_prog_type(env->prog), func_id); + kfunc_flags = btf_kfunc_id_set_contains(desc_btf, func_id, env->prog); if (!kfunc_flags) { return -EACCES; } @@ -19010,7 +19010,8 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, * in the fmodret id set with the KF_SLEEPABLE flag. */ else { - u32 *flags = btf_kfunc_is_modify_return(btf, btf_id); + u32 *flags = btf_kfunc_is_modify_return(btf, btf_id, + prog); if (flags && (*flags & KF_SLEEPABLE)) ret = 0; @@ -19038,7 +19039,7 @@ int bpf_check_attach_target(struct bpf_verifier_log *log, return -EINVAL; } ret = -EINVAL; - if (btf_kfunc_is_modify_return(btf, btf_id) || + if (btf_kfunc_is_modify_return(btf, btf_id, prog) || !check_attach_modify_return(addr, tname)) ret = 0; if (ret) { -- cgit v1.2.3 From 4ddbcb886268af8d12a23e6640b39d1d9c652b1b Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:55 +0000 Subject: bpf: Add bpf_sock_destroy kfunc The socket destroy kfunc is used to forcefully terminate sockets from certain BPF contexts. We plan to use the capability in Cilium load-balancing to terminate client sockets that continue to connect to deleted backends. The other use case is on-the-fly policy enforcement where existing socket connections prevented by policies need to be forcefully terminated. The kfunc also allows terminating sockets that may or may not be actively sending traffic. The kfunc can currently be called only from BPF TCP and UDP iterators where users can filter, and terminate selected sockets. More specifically, it can only be called from BPF contexts that ensure socket locking in order to allow synchronous execution of protocol specific `diag_destroy` handlers. The previous commit that batches UDP sockets during iteration facilitated a synchronous invocation of the UDP destroy callback from BPF context by skipping socket locks in `udp_abort`. TCP iterator already supported batching of sockets being iterated. To that end, `tracing_iter_filter` callback filter is added so that verifier can restrict the kfunc to programs with `BPF_TRACE_ITER` attach type, and reject other programs. The kfunc takes `sock_common` type argument, even though it expects, and casts them to a `sock` pointer. This enables the verifier to allow the sock_destroy kfunc to be called for TCP with `sock_common` and UDP with `sock` structs. Furthermore, as `sock_common` only has a subset of certain fields of `sock`, casting pointer to the latter type might not always be safe for certain sockets like request sockets, but these have a special handling in the diag_destroy handlers. Additionally, the kfunc is defined with `KF_TRUSTED_ARGS` flag to avoid the cases where a `PTR_TO_BTF_ID` sk is obtained by following another pointer. eg. getting a sk pointer (may be even NULL) by following another sk pointer. The pointer socket argument passed in TCP and UDP iterators is tagged as `PTR_TRUSTED` in {tcp,udp}_reg_info. The TRUSTED arg changes are contributed by Martin KaFai Lau . Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-8-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- net/core/filter.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp.c | 9 +++++--- net/ipv4/tcp_ipv4.c | 2 +- net/ipv4/udp.c | 8 ++++--- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 451b0ec7f242..968139f4a1ac 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -11723,3 +11723,66 @@ static int __init bpf_kfunc_init(void) return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &bpf_kfunc_set_xdp); } late_initcall(bpf_kfunc_init); + +/* Disables missing prototype warnings */ +__diag_push(); +__diag_ignore_all("-Wmissing-prototypes", + "Global functions as their definitions will be in vmlinux BTF"); + +/* bpf_sock_destroy: Destroy the given socket with ECONNABORTED error code. + * + * The function expects a non-NULL pointer to a socket, and invokes the + * protocol specific socket destroy handlers. + * + * The helper can only be called from BPF contexts that have acquired the socket + * locks. + * + * Parameters: + * @sock: Pointer to socket to be destroyed + * + * Return: + * On error, may return EPROTONOSUPPORT, EINVAL. + * EPROTONOSUPPORT if protocol specific destroy handler is not supported. + * 0 otherwise + */ +__bpf_kfunc int bpf_sock_destroy(struct sock_common *sock) +{ + struct sock *sk = (struct sock *)sock; + + /* The locking semantics that allow for synchronous execution of the + * destroy handlers are only supported for TCP and UDP. + * Supporting protocols will need to acquire sock lock in the BPF context + * prior to invoking this kfunc. + */ + if (!sk->sk_prot->diag_destroy || (sk->sk_protocol != IPPROTO_TCP && + sk->sk_protocol != IPPROTO_UDP)) + return -EOPNOTSUPP; + + return sk->sk_prot->diag_destroy(sk, ECONNABORTED); +} + +__diag_pop() + +BTF_SET8_START(bpf_sk_iter_kfunc_ids) +BTF_ID_FLAGS(func, bpf_sock_destroy, KF_TRUSTED_ARGS) +BTF_SET8_END(bpf_sk_iter_kfunc_ids) + +static int tracing_iter_filter(const struct bpf_prog *prog, u32 kfunc_id) +{ + if (btf_id_set8_contains(&bpf_sk_iter_kfunc_ids, kfunc_id) && + prog->expected_attach_type != BPF_TRACE_ITER) + return -EACCES; + return 0; +} + +static const struct btf_kfunc_id_set bpf_sk_iter_kfunc_set = { + .owner = THIS_MODULE, + .set = &bpf_sk_iter_kfunc_ids, + .filter = tracing_iter_filter, +}; + +static int init_subsystem(void) +{ + return register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_sk_iter_kfunc_set); +} +late_initcall(init_subsystem); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 4d6392c16b7a..87a04c3d9425 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -4682,8 +4682,10 @@ int tcp_abort(struct sock *sk, int err) return 0; } - /* Don't race with userspace socket closes such as tcp_close. */ - lock_sock(sk); + /* BPF context ensures sock locking. */ + if (!has_current_bpf_ctx()) + /* Don't race with userspace socket closes such as tcp_close. */ + lock_sock(sk); if (sk->sk_state == TCP_LISTEN) { tcp_set_state(sk, TCP_CLOSE); @@ -4707,7 +4709,8 @@ int tcp_abort(struct sock *sk, int err) bh_unlock_sock(sk); local_bh_enable(); tcp_write_queue_purge(sk); - release_sock(sk); + if (!has_current_bpf_ctx()) + release_sock(sk); return 0; } EXPORT_SYMBOL_GPL(tcp_abort); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 6e945199709b..6c2a5f1c63c4 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3355,7 +3355,7 @@ static struct bpf_iter_reg tcp_reg_info = { .ctx_arg_info_size = 1, .ctx_arg_info = { { offsetof(struct bpf_iter__tcp, sk_common), - PTR_TO_BTF_ID_OR_NULL }, + PTR_TO_BTF_ID_OR_NULL | PTR_TRUSTED }, }, .get_func_proto = bpf_iter_tcp_get_func_proto, .seq_info = &tcp_seq_info, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0c999aa5ab30..6893fb867529 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2930,7 +2930,8 @@ EXPORT_SYMBOL(udp_poll); int udp_abort(struct sock *sk, int err) { - lock_sock(sk); + if (!has_current_bpf_ctx()) + lock_sock(sk); /* udp{v6}_destroy_sock() sets it under the sk lock, avoid racing * with close() @@ -2943,7 +2944,8 @@ int udp_abort(struct sock *sk, int err) __udp_disconnect(sk, 0); out: - release_sock(sk); + if (!has_current_bpf_ctx()) + release_sock(sk); return 0; } @@ -3646,7 +3648,7 @@ static struct bpf_iter_reg udp_reg_info = { .ctx_arg_info_size = 1, .ctx_arg_info = { { offsetof(struct bpf_iter__udp, udp_sk), - PTR_TO_BTF_ID_OR_NULL }, + PTR_TO_BTF_ID_OR_NULL | PTR_TRUSTED }, }, .seq_info = &udp_seq_info, }; -- cgit v1.2.3 From 176ba657e6aaa61df637558a57acd8b7bf043cb4 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:56 +0000 Subject: selftests/bpf: Add helper to get port using getsockname The helper will be used to programmatically retrieve and pass ports in userspace and kernel selftest programs. Suggested-by: Stanislav Fomichev Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-9-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/network_helpers.c | 23 +++++++++++++++++++++++ tools/testing/selftests/bpf/network_helpers.h | 1 + 2 files changed, 24 insertions(+) diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c index 596caa176582..a105c0cd008a 100644 --- a/tools/testing/selftests/bpf/network_helpers.c +++ b/tools/testing/selftests/bpf/network_helpers.c @@ -427,3 +427,26 @@ void close_netns(struct nstoken *token) close(token->orig_netns_fd); free(token); } + +int get_socket_local_port(int sock_fd) +{ + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + int err; + + err = getsockname(sock_fd, (struct sockaddr *)&addr, &addrlen); + if (err < 0) + return err; + + if (addr.ss_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + + return sin->sin_port; + } else if (addr.ss_family == AF_INET6) { + struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&addr; + + return sin->sin6_port; + } + + return -1; +} diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index f882c691b790..694185644da6 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -56,6 +56,7 @@ int fastopen_connect(int server_fd, const char *data, unsigned int data_len, int make_sockaddr(int family, const char *addr_str, __u16 port, struct sockaddr_storage *addr, socklen_t *len); char *ping_command(int family); +int get_socket_local_port(int sock_fd); struct nstoken; /** -- cgit v1.2.3 From 1a8bc2299f4028e9bac36020ffaaec27a0dfb9c1 Mon Sep 17 00:00:00 2001 From: Aditi Ghag Date: Fri, 19 May 2023 22:51:57 +0000 Subject: selftests/bpf: Test bpf_sock_destroy The test cases for destroying sockets mirror the intended usages of the bpf_sock_destroy kfunc using iterators. The destroy helpers set `ECONNABORTED` error code that we can validate in the test code with client sockets. But UDP sockets have an overriding error code from `disconnect()` called during abort, so the error code validation is only done for TCP sockets. The failure test cases validate that the `bpf_sock_destroy` kfunc is not allowed from program attach types other than BPF trace iterator, and such programs fail to load. Signed-off-by: Aditi Ghag Link: https://lore.kernel.org/r/20230519225157.760788-10-aditi.ghag@isovalent.com Signed-off-by: Martin KaFai Lau --- .../selftests/bpf/prog_tests/sock_destroy.c | 221 +++++++++++++++++++++ .../selftests/bpf/progs/sock_destroy_prog.c | 145 ++++++++++++++ .../selftests/bpf/progs/sock_destroy_prog_fail.c | 22 ++ 3 files changed, 388 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/sock_destroy.c create mode 100644 tools/testing/selftests/bpf/progs/sock_destroy_prog.c create mode 100644 tools/testing/selftests/bpf/progs/sock_destroy_prog_fail.c diff --git a/tools/testing/selftests/bpf/prog_tests/sock_destroy.c b/tools/testing/selftests/bpf/prog_tests/sock_destroy.c new file mode 100644 index 000000000000..b0583309a94e --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/sock_destroy.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include "sock_destroy_prog.skel.h" +#include "sock_destroy_prog_fail.skel.h" +#include "network_helpers.h" + +#define TEST_NS "sock_destroy_netns" + +static void start_iter_sockets(struct bpf_program *prog) +{ + struct bpf_link *link; + char buf[50] = {}; + int iter_fd, len; + + link = bpf_program__attach_iter(prog, NULL); + if (!ASSERT_OK_PTR(link, "attach_iter")) + return; + + iter_fd = bpf_iter_create(bpf_link__fd(link)); + if (!ASSERT_GE(iter_fd, 0, "create_iter")) + goto free_link; + + while ((len = read(iter_fd, buf, sizeof(buf))) > 0) + ; + ASSERT_GE(len, 0, "read"); + + close(iter_fd); + +free_link: + bpf_link__destroy(link); +} + +static void test_tcp_client(struct sock_destroy_prog *skel) +{ + int serv = -1, clien = -1, accept_serv = -1, n; + + serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0); + if (!ASSERT_GE(serv, 0, "start_server")) + goto cleanup; + + clien = connect_to_fd(serv, 0); + if (!ASSERT_GE(clien, 0, "connect_to_fd")) + goto cleanup; + + accept_serv = accept(serv, NULL, NULL); + if (!ASSERT_GE(accept_serv, 0, "serv accept")) + goto cleanup; + + n = send(clien, "t", 1, 0); + if (!ASSERT_EQ(n, 1, "client send")) + goto cleanup; + + /* Run iterator program that destroys connected client sockets. */ + start_iter_sockets(skel->progs.iter_tcp6_client); + + n = send(clien, "t", 1, 0); + if (!ASSERT_LT(n, 0, "client_send on destroyed socket")) + goto cleanup; + ASSERT_EQ(errno, ECONNABORTED, "error code on destroyed socket"); + +cleanup: + if (clien != -1) + close(clien); + if (accept_serv != -1) + close(accept_serv); + if (serv != -1) + close(serv); +} + +static void test_tcp_server(struct sock_destroy_prog *skel) +{ + int serv = -1, clien = -1, accept_serv = -1, n, serv_port; + + serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0); + if (!ASSERT_GE(serv, 0, "start_server")) + goto cleanup; + serv_port = get_socket_local_port(serv); + if (!ASSERT_GE(serv_port, 0, "get_sock_local_port")) + goto cleanup; + skel->bss->serv_port = (__be16) serv_port; + + clien = connect_to_fd(serv, 0); + if (!ASSERT_GE(clien, 0, "connect_to_fd")) + goto cleanup; + + accept_serv = accept(serv, NULL, NULL); + if (!ASSERT_GE(accept_serv, 0, "serv accept")) + goto cleanup; + + n = send(clien, "t", 1, 0); + if (!ASSERT_EQ(n, 1, "client send")) + goto cleanup; + + /* Run iterator program that destroys server sockets. */ + start_iter_sockets(skel->progs.iter_tcp6_server); + + n = send(clien, "t", 1, 0); + if (!ASSERT_LT(n, 0, "client_send on destroyed socket")) + goto cleanup; + ASSERT_EQ(errno, ECONNRESET, "error code on destroyed socket"); + +cleanup: + if (clien != -1) + close(clien); + if (accept_serv != -1) + close(accept_serv); + if (serv != -1) + close(serv); +} + +static void test_udp_client(struct sock_destroy_prog *skel) +{ + int serv = -1, clien = -1, n = 0; + + serv = start_server(AF_INET6, SOCK_DGRAM, NULL, 0, 0); + if (!ASSERT_GE(serv, 0, "start_server")) + goto cleanup; + + clien = connect_to_fd(serv, 0); + if (!ASSERT_GE(clien, 0, "connect_to_fd")) + goto cleanup; + + n = send(clien, "t", 1, 0); + if (!ASSERT_EQ(n, 1, "client send")) + goto cleanup; + + /* Run iterator program that destroys sockets. */ + start_iter_sockets(skel->progs.iter_udp6_client); + + n = send(clien, "t", 1, 0); + if (!ASSERT_LT(n, 0, "client_send on destroyed socket")) + goto cleanup; + /* UDP sockets have an overriding error code after they are disconnected, + * so we don't check for ECONNABORTED error code. + */ + +cleanup: + if (clien != -1) + close(clien); + if (serv != -1) + close(serv); +} + +static void test_udp_server(struct sock_destroy_prog *skel) +{ + int *listen_fds = NULL, n, i, serv_port; + unsigned int num_listens = 5; + char buf[1]; + + /* Start reuseport servers. */ + listen_fds = start_reuseport_server(AF_INET6, SOCK_DGRAM, + "::1", 0, 0, num_listens); + if (!ASSERT_OK_PTR(listen_fds, "start_reuseport_server")) + goto cleanup; + serv_port = get_socket_local_port(listen_fds[0]); + if (!ASSERT_GE(serv_port, 0, "get_sock_local_port")) + goto cleanup; + skel->bss->serv_port = (__be16) serv_port; + + /* Run iterator program that destroys server sockets. */ + start_iter_sockets(skel->progs.iter_udp6_server); + + for (i = 0; i < num_listens; ++i) { + n = read(listen_fds[i], buf, sizeof(buf)); + if (!ASSERT_EQ(n, -1, "read") || + !ASSERT_EQ(errno, ECONNABORTED, "error code on destroyed socket")) + break; + } + ASSERT_EQ(i, num_listens, "server socket"); + +cleanup: + free_fds(listen_fds, num_listens); +} + +void test_sock_destroy(void) +{ + struct sock_destroy_prog *skel; + struct nstoken *nstoken = NULL; + int cgroup_fd; + + skel = sock_destroy_prog__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + return; + + cgroup_fd = test__join_cgroup("/sock_destroy"); + if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup")) + goto cleanup; + + skel->links.sock_connect = bpf_program__attach_cgroup( + skel->progs.sock_connect, cgroup_fd); + if (!ASSERT_OK_PTR(skel->links.sock_connect, "prog_attach")) + goto cleanup; + + SYS(cleanup, "ip netns add %s", TEST_NS); + SYS(cleanup, "ip -net %s link set dev lo up", TEST_NS); + + nstoken = open_netns(TEST_NS); + if (!ASSERT_OK_PTR(nstoken, "open_netns")) + goto cleanup; + + if (test__start_subtest("tcp_client")) + test_tcp_client(skel); + if (test__start_subtest("tcp_server")) + test_tcp_server(skel); + if (test__start_subtest("udp_client")) + test_udp_client(skel); + if (test__start_subtest("udp_server")) + test_udp_server(skel); + + RUN_TESTS(sock_destroy_prog_fail); + +cleanup: + if (nstoken) + close_netns(nstoken); + SYS_NOFAIL("ip netns del " TEST_NS " &> /dev/null"); + if (cgroup_fd >= 0) + close(cgroup_fd); + sock_destroy_prog__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/sock_destroy_prog.c b/tools/testing/selftests/bpf/progs/sock_destroy_prog.c new file mode 100644 index 000000000000..9e0bf7a54cec --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sock_destroy_prog.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include + +#include "bpf_tracing_net.h" + +__be16 serv_port = 0; + +int bpf_sock_destroy(struct sock_common *sk) __ksym; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u64); +} tcp_conn_sockets SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, __u64); +} udp_conn_sockets SEC(".maps"); + +SEC("cgroup/connect6") +int sock_connect(struct bpf_sock_addr *ctx) +{ + __u64 sock_cookie = 0; + int key = 0; + __u32 keyc = 0; + + if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6) + return 1; + + sock_cookie = bpf_get_socket_cookie(ctx); + if (ctx->protocol == IPPROTO_TCP) + bpf_map_update_elem(&tcp_conn_sockets, &key, &sock_cookie, 0); + else if (ctx->protocol == IPPROTO_UDP) + bpf_map_update_elem(&udp_conn_sockets, &keyc, &sock_cookie, 0); + else + return 1; + + return 1; +} + +SEC("iter/tcp") +int iter_tcp6_client(struct bpf_iter__tcp *ctx) +{ + struct sock_common *sk_common = ctx->sk_common; + __u64 sock_cookie = 0; + __u64 *val; + int key = 0; + + if (!sk_common) + return 0; + + if (sk_common->skc_family != AF_INET6) + return 0; + + sock_cookie = bpf_get_socket_cookie(sk_common); + val = bpf_map_lookup_elem(&tcp_conn_sockets, &key); + if (!val) + return 0; + /* Destroy connected client sockets. */ + if (sock_cookie == *val) + bpf_sock_destroy(sk_common); + + return 0; +} + +SEC("iter/tcp") +int iter_tcp6_server(struct bpf_iter__tcp *ctx) +{ + struct sock_common *sk_common = ctx->sk_common; + const struct inet_connection_sock *icsk; + const struct inet_sock *inet; + struct tcp6_sock *tcp_sk; + __be16 srcp; + + if (!sk_common) + return 0; + + if (sk_common->skc_family != AF_INET6) + return 0; + + tcp_sk = bpf_skc_to_tcp6_sock(sk_common); + if (!tcp_sk) + return 0; + + icsk = &tcp_sk->tcp.inet_conn; + inet = &icsk->icsk_inet; + srcp = inet->inet_sport; + + /* Destroy server sockets. */ + if (srcp == serv_port) + bpf_sock_destroy(sk_common); + + return 0; +} + + +SEC("iter/udp") +int iter_udp6_client(struct bpf_iter__udp *ctx) +{ + struct udp_sock *udp_sk = ctx->udp_sk; + struct sock *sk = (struct sock *) udp_sk; + __u64 sock_cookie = 0, *val; + int key = 0; + + if (!sk) + return 0; + + sock_cookie = bpf_get_socket_cookie(sk); + val = bpf_map_lookup_elem(&udp_conn_sockets, &key); + if (!val) + return 0; + /* Destroy connected client sockets. */ + if (sock_cookie == *val) + bpf_sock_destroy((struct sock_common *)sk); + + return 0; +} + +SEC("iter/udp") +int iter_udp6_server(struct bpf_iter__udp *ctx) +{ + struct udp_sock *udp_sk = ctx->udp_sk; + struct sock *sk = (struct sock *) udp_sk; + struct inet_sock *inet; + __be16 srcp; + + if (!sk) + return 0; + + inet = &udp_sk->inet; + srcp = inet->inet_sport; + if (srcp == serv_port) + bpf_sock_destroy((struct sock_common *)sk); + + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/sock_destroy_prog_fail.c b/tools/testing/selftests/bpf/progs/sock_destroy_prog_fail.c new file mode 100644 index 000000000000..dd6850b58e25 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/sock_destroy_prog_fail.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include + +#include "bpf_misc.h" + +char _license[] SEC("license") = "GPL"; + +int bpf_sock_destroy(struct sock_common *sk) __ksym; + +SEC("tp_btf/tcp_destroy_sock") +__failure __msg("calling kernel function bpf_sock_destroy is not allowed") +int BPF_PROG(trace_tcp_destroy_sock, struct sock *sk) +{ + /* should not load */ + bpf_sock_destroy((struct sock_common *)sk); + + return 0; +} + -- cgit v1.2.3 From e4ac7cc6e5a45306049ac2337dea0e636adf36be Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Fri, 19 May 2023 09:48:25 +0800 Subject: net: fec: turn on XDP features The XDP features are supported since the commit 66c0e13ad236 ("drivers: net: turn on XDP features"). Currently, the fec driver supports NETDEV_XDP_ACT_BASIC, NETDEV_XDP_ACT_REDIRECT and NETDEV_XDP_ACT_NDO_XMIT. So turn on these XDP features for fec driver. Signed-off-by: Wei Fang Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 6d0b46c76924..87a431222af6 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -4030,6 +4030,11 @@ static int fec_enet_init(struct net_device *ndev) ndev->hw_features = ndev->features; + if (!(fep->quirks & FEC_QUIRK_SWAP_FRAME)) + ndev->xdp_features = NETDEV_XDP_ACT_BASIC | + NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_NDO_XMIT; + fec_restart(ndev); if (fep->quirks & FEC_QUIRK_MIB_CLEAR) -- cgit v1.2.3 From 2ae9c66b04554bf5b3eeaab8c12a0bfb9f28ebde Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Fri, 19 May 2023 10:01:13 +0800 Subject: net: fec: remove useless fec_enet_reset_skb() This patch is a cleanup for fec driver. The fec_enet_reset_skb() is used to free skb buffers for tx queues and is only invoked in fec_restart(). However, fec_enet_bd_init() also resets skb buffers and is invoked in fec_restart() too. So fec_enet_reset_skb() is redundant and useless. Signed-off-by: Wei Fang Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 87a431222af6..3ecf20ee5851 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1011,24 +1011,6 @@ static void fec_enet_enable_ring(struct net_device *ndev) } } -static void fec_enet_reset_skb(struct net_device *ndev) -{ - struct fec_enet_private *fep = netdev_priv(ndev); - struct fec_enet_priv_tx_q *txq; - int i, j; - - for (i = 0; i < fep->num_tx_queues; i++) { - txq = fep->tx_queue[i]; - - for (j = 0; j < txq->bd.ring_size; j++) { - if (txq->tx_skbuff[j]) { - dev_kfree_skb_any(txq->tx_skbuff[j]); - txq->tx_skbuff[j] = NULL; - } - } - } -} - /* * This function is called to start or restart the FEC during a link * change, transmit timeout, or to reconfigure the FEC. The network @@ -1071,9 +1053,6 @@ fec_restart(struct net_device *ndev) fec_enet_enable_ring(ndev); - /* Reset tx SKB buffers. */ - fec_enet_reset_skb(ndev); - /* Enable MII mode */ if (fep->full_duplex == DUPLEX_FULL) { /* FD enable */ -- cgit v1.2.3 From dbb99d78522ae3d3f0d69fe7a8a0544a829f1d8e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 19 May 2023 11:32:38 +0200 Subject: net: ipconfig: move ic_nameservers_fallback into #ifdef block The new variable is only used when IPCONFIG_BOOTP is defined and otherwise causes a warning: net/ipv4/ipconfig.c:177:12: error: 'ic_nameservers_fallback' defined but not used [-Werror=unused-variable] Move it next to the user. Fixes: 81ac2722fa19 ("net: ipconfig: Allow DNS to be overwritten by DHCPACK") Signed-off-by: Arnd Bergmann Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/ipv4/ipconfig.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 202fa1943ccd..c56b6fe6f0d7 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -173,9 +173,6 @@ static int ic_proto_have_if __initdata; /* MTU for boot device */ static int ic_dev_mtu __initdata; -/* DHCPACK can overwrite DNS if fallback was set upon first BOOTP reply */ -static int ic_nameservers_fallback __initdata; - #ifdef IPCONFIG_DYNAMIC static DEFINE_SPINLOCK(ic_recv_lock); static volatile int ic_got_reply __initdata; /* Proto(s) that replied */ @@ -668,6 +665,9 @@ static struct packet_type bootp_packet_type __initdata = { .func = ic_bootp_recv, }; +/* DHCPACK can overwrite DNS if fallback was set upon first BOOTP reply */ +static int ic_nameservers_fallback __initdata; + /* * Initialize DHCP/BOOTP extension fields in the request. */ -- cgit v1.2.3 From 8b6b7c1190c3da1137d320c3de5e8d7f69baba5b Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 19 May 2023 11:33:04 +0100 Subject: net: altera: tse: remove mac_an_restart() function The mac_an_restart() method will only be called if the driver sets legacy_pre_march2020, which the altera tse driver does not do. Therefore, providing a stub is unnecessary. Fixes: fef2998203e1 ("net: altera: tse: convert to phylink") Signed-off-by: Russell King (Oracle) Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_tse_main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 66e3af73ec41..190ff1bcd94e 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1036,10 +1036,6 @@ static struct net_device_ops altera_tse_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static void alt_tse_mac_an_restart(struct phylink_config *config) -{ -} - static void alt_tse_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) { @@ -1096,7 +1092,6 @@ static struct phylink_pcs *alt_tse_select_pcs(struct phylink_config *config, } static const struct phylink_mac_ops alt_tse_phylink_ops = { - .mac_an_restart = alt_tse_mac_an_restart, .mac_config = alt_tse_mac_config, .mac_link_down = alt_tse_mac_link_down, .mac_link_up = alt_tse_mac_link_up, -- cgit v1.2.3 From 4b159f5048b90844679dad08afb3240c1957aba1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 19 May 2023 14:03:59 +0100 Subject: net: phy: add helpers for comparing phy IDs There are several places which open code comparing PHY IDs. Provide a couple of helpers to assist with this, using a slightly simpler test than the original: - phy_id_compare() compares two arbitary PHY IDs and a mask of the significant bits in the ID. - phydev_id_compare() compares the bound phydev with the specified PHY ID, using the bound driver's mask. Signed-off-by: Russell King Reviewed-by: Simon Horman Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 6 +++--- drivers/net/phy/phy_device.c | 16 +++++++--------- drivers/net/phy/phylink.c | 4 ++-- include/linux/phy.h | 28 ++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 3f81bb8dac44..2094d49025a7 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -637,7 +637,7 @@ static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev, { int ret; - if ((phydev->phy_id & MICREL_PHY_ID_MASK) != PHY_ID_KSZ8051) + if (!phy_id_compare(phydev->phy_id, PHY_ID_KSZ8051, MICREL_PHY_ID_MASK)) return 0; ret = phy_read(phydev, MII_BMSR); @@ -1566,7 +1566,7 @@ static int ksz9x31_cable_test_fault_length(struct phy_device *phydev, u16 stat) * * distance to fault = (VCT_DATA - 22) * 4 / cable propagation velocity */ - if ((phydev->phy_id & MICREL_PHY_ID_MASK) == PHY_ID_KSZ9131) + if (phydev_id_compare(phydev, PHY_ID_KSZ9131)) dt = clamp(dt - 22, 0, 255); return (dt * 400) / 10; @@ -1998,7 +1998,7 @@ static __always_inline int ksz886x_cable_test_fault_length(struct phy_device *ph */ dt = FIELD_GET(data_mask, status); - if ((phydev->phy_id & MICREL_PHY_ID_MASK) == PHY_ID_LAN8814) + if (phydev_id_compare(phydev, PHY_ID_LAN8814)) return ((dt - 22) * 800) / 10; else return (dt * 400) / 10; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 8852b0c53114..2cad9cc3f6b8 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -454,8 +454,7 @@ int phy_unregister_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask) fixup = list_entry(pos, struct phy_fixup, list); if ((!strcmp(fixup->bus_id, bus_id)) && - ((fixup->phy_uid & phy_uid_mask) == - (phy_uid & phy_uid_mask))) { + phy_id_compare(fixup->phy_uid, phy_uid, phy_uid_mask)) { list_del(&fixup->list); kfree(fixup); ret = 0; @@ -491,8 +490,8 @@ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0) return 0; - if ((fixup->phy_uid & fixup->phy_uid_mask) != - (phydev->phy_id & fixup->phy_uid_mask)) + if (!phy_id_compare(phydev->phy_id, fixup->phy_uid, + fixup->phy_uid_mask)) if (fixup->phy_uid != PHY_ANY_UID) return 0; @@ -539,15 +538,14 @@ static int phy_bus_match(struct device *dev, struct device_driver *drv) if (phydev->c45_ids.device_ids[i] == 0xffffffff) continue; - if ((phydrv->phy_id & phydrv->phy_id_mask) == - (phydev->c45_ids.device_ids[i] & - phydrv->phy_id_mask)) + if (phy_id_compare(phydev->c45_ids.device_ids[i], + phydrv->phy_id, phydrv->phy_id_mask)) return 1; } return 0; } else { - return (phydrv->phy_id & phydrv->phy_id_mask) == - (phydev->phy_id & phydrv->phy_id_mask); + return phy_id_compare(phydev->phy_id, phydrv->phy_id, + phydrv->phy_id_mask); } } diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index f2106d17847a..a4dd5197355a 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -3151,8 +3151,8 @@ static void phylink_sfp_link_up(void *upstream) */ static bool phylink_phy_no_inband(struct phy_device *phy) { - return phy->is_c45 && - (phy->c45_ids.device_ids[1] & 0xfffffff0) == 0xae025150; + return phy->is_c45 && phy_id_compare(phy->c45_ids.device_ids[1], + 0xae025150, 0xfffffff0); } static int phylink_sfp_connect_phy(void *upstream, struct phy_device *phy) diff --git a/include/linux/phy.h b/include/linux/phy.h index d8cd7115c773..2da87a36200d 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1112,6 +1112,34 @@ struct phy_driver { #define PHY_ID_MATCH_MODEL(id) .phy_id = (id), .phy_id_mask = GENMASK(31, 4) #define PHY_ID_MATCH_VENDOR(id) .phy_id = (id), .phy_id_mask = GENMASK(31, 10) +/** + * phy_id_compare - compare @id1 with @id2 taking account of @mask + * @id1: first PHY ID + * @id2: second PHY ID + * @mask: the PHY ID mask, set bits are significant in matching + * + * Return true if the bits from @id1 and @id2 specified by @mask match. + * This uses an equivalent test to (@id & @mask) == (@phy_id & @mask). + */ +static inline bool phy_id_compare(u32 id1, u32 id2, u32 mask) +{ + return !((id1 ^ id2) & mask); +} + +/** + * phydev_id_compare - compare @id with the PHY's Clause 22 ID + * @phydev: the PHY device + * @id: the PHY ID to be matched + * + * Compare the @phydev clause 22 ID with the provided @id and return true or + * false depending whether it matches, using the bound driver mask. The + * @phydev must be bound to a driver. + */ +static inline bool phydev_id_compare(struct phy_device *phydev, u32 id) +{ + return phy_id_compare(id, phydev->phy_id, phydev->drv->phy_id_mask); +} + /* A Structure for boards to register fixups with the PHY Lib */ struct phy_fixup { struct list_head list; -- cgit v1.2.3 From fe79bd65c819cc520aa66de65caae8e4cea29c5a Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Fri, 19 May 2023 14:30:36 +0100 Subject: net/tcp: refactor tcp_inet6_sk() Don't keep hand coded offset caluclations and replace it with container_of(). It should be type safer and a bit less confusing. It also makes it with a macro instead of inline function to preserve constness, which was previously casted out like in case of tcp_v6_send_synack(). Signed-off-by: Pavel Begunkov Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 7132eb213a7a..d657713d1c71 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -93,12 +93,8 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk, * This avoids a dereference and allow compiler optimizations. * It is a specialized version of inet6_sk_generic(). */ -static struct ipv6_pinfo *tcp_inet6_sk(const struct sock *sk) -{ - unsigned int offset = sizeof(struct tcp6_sock) - sizeof(struct ipv6_pinfo); - - return (struct ipv6_pinfo *)(((u8 *)sk) + offset); -} +#define tcp_inet6_sk(sk) (&container_of_const(tcp_sk(sk), \ + struct tcp6_sock, tcp)->inet6) static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) { @@ -533,7 +529,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, struct sk_buff *syn_skb) { struct inet_request_sock *ireq = inet_rsk(req); - struct ipv6_pinfo *np = tcp_inet6_sk(sk); + const struct ipv6_pinfo *np = tcp_inet6_sk(sk); struct ipv6_txoptions *opt; struct flowi6 *fl6 = &fl->u.ip6; struct sk_buff *skb; -- cgit v1.2.3 From efc3001f8b44bf5da0f178bd726a73c73f370707 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sat, 20 May 2023 19:21:04 +0200 Subject: nfc: Switch i2c drivers back to use .probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit b8a1a4cd5a98 ("i2c: Provide a temporary .probe_new() call-back type"), all drivers being converted to .probe_new() and then 03c835f498b5 ("i2c: Switch .probe() to not take an id parameter") convert back to (the new) .probe() to be able to eventually drop .probe_new() from struct i2c_driver. Signed-off-by: Uwe Kleine-König Reviewed-by: Luca Ceresoli Signed-off-by: David S. Miller --- drivers/nfc/fdp/i2c.c | 2 +- drivers/nfc/microread/i2c.c | 2 +- drivers/nfc/nfcmrvl/i2c.c | 2 +- drivers/nfc/nxp-nci/i2c.c | 2 +- drivers/nfc/pn533/i2c.c | 2 +- drivers/nfc/pn544/i2c.c | 2 +- drivers/nfc/s3fwrn5/i2c.c | 2 +- drivers/nfc/st-nci/i2c.c | 2 +- drivers/nfc/st21nfca/i2c.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/nfc/fdp/i2c.c b/drivers/nfc/fdp/i2c.c index 1e0f2297f9c6..c1896a1d978c 100644 --- a/drivers/nfc/fdp/i2c.c +++ b/drivers/nfc/fdp/i2c.c @@ -359,7 +359,7 @@ static struct i2c_driver fdp_nci_i2c_driver = { .name = FDP_I2C_DRIVER_NAME, .acpi_match_table = fdp_nci_i2c_acpi_match, }, - .probe_new = fdp_nci_i2c_probe, + .probe = fdp_nci_i2c_probe, .remove = fdp_nci_i2c_remove, }; module_i2c_driver(fdp_nci_i2c_driver); diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c index e72b358a2a12..642df4e0ce24 100644 --- a/drivers/nfc/microread/i2c.c +++ b/drivers/nfc/microread/i2c.c @@ -286,7 +286,7 @@ static struct i2c_driver microread_i2c_driver = { .driver = { .name = MICROREAD_I2C_DRIVER_NAME, }, - .probe_new = microread_i2c_probe, + .probe = microread_i2c_probe, .remove = microread_i2c_remove, .id_table = microread_i2c_id, }; diff --git a/drivers/nfc/nfcmrvl/i2c.c b/drivers/nfc/nfcmrvl/i2c.c index 164e2ab859fd..74553134c1b1 100644 --- a/drivers/nfc/nfcmrvl/i2c.c +++ b/drivers/nfc/nfcmrvl/i2c.c @@ -258,7 +258,7 @@ static const struct i2c_device_id nfcmrvl_i2c_id_table[] = { MODULE_DEVICE_TABLE(i2c, nfcmrvl_i2c_id_table); static struct i2c_driver nfcmrvl_i2c_driver = { - .probe_new = nfcmrvl_i2c_probe, + .probe = nfcmrvl_i2c_probe, .id_table = nfcmrvl_i2c_id_table, .remove = nfcmrvl_i2c_remove, .driver = { diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c index d4c299be7949..baddaf242d18 100644 --- a/drivers/nfc/nxp-nci/i2c.c +++ b/drivers/nfc/nxp-nci/i2c.c @@ -348,7 +348,7 @@ static struct i2c_driver nxp_nci_i2c_driver = { .acpi_match_table = ACPI_PTR(acpi_id), .of_match_table = of_nxp_nci_i2c_match, }, - .probe_new = nxp_nci_i2c_probe, + .probe = nxp_nci_i2c_probe, .id_table = nxp_nci_i2c_id_table, .remove = nxp_nci_i2c_remove, }; diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c index 1503a98f0405..438ab9553f7a 100644 --- a/drivers/nfc/pn533/i2c.c +++ b/drivers/nfc/pn533/i2c.c @@ -259,7 +259,7 @@ static struct i2c_driver pn533_i2c_driver = { .name = PN533_I2C_DRIVER_NAME, .of_match_table = of_match_ptr(of_pn533_i2c_match), }, - .probe_new = pn533_i2c_probe, + .probe = pn533_i2c_probe, .id_table = pn533_i2c_id_table, .remove = pn533_i2c_remove, }; diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index 8b0d910bee06..3f6d74832bac 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -953,7 +953,7 @@ static struct i2c_driver pn544_hci_i2c_driver = { .of_match_table = of_match_ptr(of_pn544_i2c_match), .acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match), }, - .probe_new = pn544_hci_i2c_probe, + .probe = pn544_hci_i2c_probe, .id_table = pn544_hci_i2c_id_table, .remove = pn544_hci_i2c_remove, }; diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c index 2517ae71f9a4..720d4a72493c 100644 --- a/drivers/nfc/s3fwrn5/i2c.c +++ b/drivers/nfc/s3fwrn5/i2c.c @@ -261,7 +261,7 @@ static struct i2c_driver s3fwrn5_i2c_driver = { .name = S3FWRN5_I2C_DRIVER_NAME, .of_match_table = of_match_ptr(of_s3fwrn5_i2c_match), }, - .probe_new = s3fwrn5_i2c_probe, + .probe = s3fwrn5_i2c_probe, .remove = s3fwrn5_i2c_remove, .id_table = s3fwrn5_i2c_id_table, }; diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c index 6b5eed8a1fbe..d20a337e90b4 100644 --- a/drivers/nfc/st-nci/i2c.c +++ b/drivers/nfc/st-nci/i2c.c @@ -283,7 +283,7 @@ static struct i2c_driver st_nci_i2c_driver = { .of_match_table = of_match_ptr(of_st_nci_i2c_match), .acpi_match_table = ACPI_PTR(st_nci_i2c_acpi_match), }, - .probe_new = st_nci_i2c_probe, + .probe = st_nci_i2c_probe, .id_table = st_nci_i2c_id_table, .remove = st_nci_i2c_remove, }; diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c index 55f7a2391bb1..064a63db288b 100644 --- a/drivers/nfc/st21nfca/i2c.c +++ b/drivers/nfc/st21nfca/i2c.c @@ -597,7 +597,7 @@ static struct i2c_driver st21nfca_hci_i2c_driver = { .of_match_table = of_match_ptr(of_st21nfca_i2c_match), .acpi_match_table = ACPI_PTR(st21nfca_hci_i2c_acpi_match), }, - .probe_new = st21nfca_hci_i2c_probe, + .probe = st21nfca_hci_i2c_probe, .id_table = st21nfca_hci_i2c_id_table, .remove = st21nfca_hci_i2c_remove, }; -- cgit v1.2.3 From 843b84640349e56ab96812cd68c19ed7021f4606 Mon Sep 17 00:00:00 2001 From: Carsten Schmidt Date: Tue, 16 May 2023 14:53:32 +0200 Subject: can: kvaser_usb: Add len8_dlc support Add support for the Classical CAN raw DLC functionality to send and receive DLC values from 9 .. 15. v1: https://lore.kernel.org/all/20230506105529.4023-1-carsten.schmidt-achim@t-online.de Signed-off-by: Carsten Schmidt Tested-by: Jimmy Assarsson Signed-off-by: Jimmy Assarsson Link: https://lore.kernel.org/r/20230516125332.82894-1-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 2 +- drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c | 13 +++++++++---- drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c | 6 +++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c index 7135ec851341..71ef4db5c09f 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c @@ -816,7 +816,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) init_completion(&priv->stop_comp); init_completion(&priv->flush_comp); init_completion(&priv->get_busparams_comp); - priv->can.ctrlmode_supported = 0; + priv->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC; priv->dev = dev; priv->netdev = netdev; diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c index ef341c4254fc..c7ba768dfe17 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c @@ -1263,7 +1263,7 @@ static void kvaser_usb_hydra_rx_msg_std(const struct kvaser_usb *dev, if (flags & KVASER_USB_HYDRA_CF_FLAG_OVERRUN) kvaser_usb_can_rx_over_error(priv->netdev); - cf->len = can_cc_dlc2len(cmd->rx_can.dlc); + can_frame_set_cc_len((struct can_frame *)cf, cmd->rx_can.dlc, priv->can.ctrlmode); if (flags & KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME) { cf->can_id |= CAN_RTR_FLAG; @@ -1342,7 +1342,7 @@ static void kvaser_usb_hydra_rx_msg_ext(const struct kvaser_usb *dev, if (flags & KVASER_USB_HYDRA_CF_FLAG_ESI) cf->flags |= CANFD_ESI; } else { - cf->len = can_cc_dlc2len(dlc); + can_frame_set_cc_len((struct can_frame *)cf, dlc, priv->can.ctrlmode); } if (flags & KVASER_USB_HYDRA_CF_FLAG_REMOTE_FRAME) { @@ -1442,7 +1442,7 @@ kvaser_usb_hydra_frame_to_cmd_ext(const struct kvaser_usb_net_priv *priv, struct kvaser_usb *dev = priv->dev; struct kvaser_cmd_ext *cmd; struct canfd_frame *cf = (struct canfd_frame *)skb->data; - u8 dlc = can_fd_len2dlc(cf->len); + u8 dlc; u8 nbr_of_bytes = cf->len; u32 flags; u32 id; @@ -1467,6 +1467,11 @@ kvaser_usb_hydra_frame_to_cmd_ext(const struct kvaser_usb_net_priv *priv, cmd->len = cpu_to_le16(*cmd_len); + if (can_is_canfd_skb(skb)) + dlc = can_fd_len2dlc(cf->len); + else + dlc = can_get_cc_dlc((struct can_frame *)cf, priv->can.ctrlmode); + cmd->tx_can.databytes = nbr_of_bytes; cmd->tx_can.dlc = dlc; @@ -1542,7 +1547,7 @@ kvaser_usb_hydra_frame_to_cmd_std(const struct kvaser_usb_net_priv *priv, id = cf->can_id & CAN_SFF_MASK; } - cmd->tx_can.dlc = cf->len; + cmd->tx_can.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); flags = (cf->can_id & CAN_EFF_FLAG ? KVASER_USB_HYDRA_CF_FLAG_EXTENDED_ID : 0); diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c index 1c2f99ce4c6c..23bd7574b1c7 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c @@ -573,7 +573,7 @@ kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv, cmd->u.tx_can.data[1] = cf->can_id & 0x3f; } - cmd->u.tx_can.data[5] = cf->len; + cmd->u.tx_can.data[5] = can_get_cc_dlc(cf, priv->can.ctrlmode); memcpy(&cmd->u.tx_can.data[6], cf->data, cf->len); if (cf->can_id & CAN_RTR_FLAG) @@ -1349,7 +1349,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev, else cf->can_id &= CAN_SFF_MASK; - cf->len = can_cc_dlc2len(cmd->u.leaf.log_message.dlc); + can_frame_set_cc_len(cf, cmd->u.leaf.log_message.dlc & 0xF, priv->can.ctrlmode); if (cmd->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME) cf->can_id |= CAN_RTR_FLAG; @@ -1367,7 +1367,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev, cf->can_id |= CAN_EFF_FLAG; } - cf->len = can_cc_dlc2len(rx_data[5]); + can_frame_set_cc_len(cf, rx_data[5] & 0xF, priv->can.ctrlmode); if (cmd->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME) cf->can_id |= CAN_RTR_FLAG; -- cgit v1.2.3 From d7588f02e8d8a795702cf06cbbb4303c48b02a61 Mon Sep 17 00:00:00 2001 From: Marcel Hellwig Date: Mon, 17 Apr 2023 10:52:04 +0200 Subject: can: dev: add transceiver capabilities to xilinx_can Currently the xilinx_can driver does not support adding a phy like the "ti,tcan1043" to its devicetree. This code makes it possible to add such phy, so that the kernel makes sure that the PHY is in operational state, when the link is set to an "up" state. Signed-off-by: Marcel Hellwig Link: https://lore.kernel.org/r/20230417085204.179268-1-git@cookiesoft.de [mkl: call phy_power_off() after pm_runtime_put()] [mkl: remove error message for phy_power_on() failure] [mkl: update kernel-doc for struct xcan_priv] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/xilinx_can.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 797c69a0314d..4d3283db3a13 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #define DRIVER_NAME "xilinx_can" @@ -198,6 +199,7 @@ struct xcan_devtype_data { * @bus_clk: Pointer to struct clk * @can_clk: Pointer to struct clk * @devtype: Device type specific constants + * @transceiver: Optional pointer to associated CAN transceiver */ struct xcan_priv { struct can_priv can; @@ -215,6 +217,7 @@ struct xcan_priv { struct clk *bus_clk; struct clk *can_clk; struct xcan_devtype_data devtype; + struct phy *transceiver; }; /* CAN Bittiming constants as per Xilinx CAN specs */ @@ -1419,6 +1422,10 @@ static int xcan_open(struct net_device *ndev) struct xcan_priv *priv = netdev_priv(ndev); int ret; + ret = phy_power_on(priv->transceiver); + if (ret) + return ret; + ret = pm_runtime_get_sync(priv->dev); if (ret < 0) { netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", @@ -1462,6 +1469,7 @@ err_irq: free_irq(ndev->irq, ndev); err: pm_runtime_put(priv->dev); + phy_power_off(priv->transceiver); return ret; } @@ -1483,6 +1491,7 @@ static int xcan_close(struct net_device *ndev) close_candev(ndev); pm_runtime_put(priv->dev); + phy_power_off(priv->transceiver); return 0; } @@ -1713,6 +1722,7 @@ static int xcan_probe(struct platform_device *pdev) { struct net_device *ndev; struct xcan_priv *priv; + struct phy *transceiver; const struct of_device_id *of_id; const struct xcan_devtype_data *devtype = &xcan_axi_data; void __iomem *addr; @@ -1843,6 +1853,14 @@ static int xcan_probe(struct platform_device *pdev) goto err_free; } + transceiver = devm_phy_optional_get(&pdev->dev, NULL); + if (IS_ERR(transceiver)) { + ret = PTR_ERR(transceiver); + dev_err_probe(&pdev->dev, ret, "failed to get phy\n"); + goto err_free; + } + priv->transceiver = transceiver; + priv->write_reg = xcan_write_reg_le; priv->read_reg = xcan_read_reg_le; @@ -1869,6 +1887,7 @@ static int xcan_probe(struct platform_device *pdev) goto err_disableclks; } + of_can_transceiver(ndev); pm_runtime_put(&pdev->dev); if (priv->devtype.flags & XCAN_FLAG_CANFD_2) { -- cgit v1.2.3 From 1ad549cf980c0967497572c49f4f99eed7c500b8 Mon Sep 17 00:00:00 2001 From: Frank Jungclaus Date: Fri, 19 May 2023 21:55:55 +0200 Subject: can: esd_usb: Make use of existing kernel macros Make use of existing kernel macros: - Use the unit suffixes from linux/units.h for the controller clock frequencies - Use the BIT() and the GENMASK() macro to set specific bits in some constants - Use CAN_MAX_DLEN (instead of directly using the value 8) for the maximum CAN payload length Additionally: - Spend some commenting for the previously changed constants - Add the current year to the copyright notice - While adding the header linux/units.h to the list of include files also sort that list alphabetically Suggested-by: Vincent MAILHOL Link: https://lore.kernel.org/all/CAMZ6RqLaDNy-fZ2G0+QMhUEckkXLL+ZyELVSDFmqpd++aBzZQg@mail.gmail.com/ Link: https://lore.kernel.org/all/CAMZ6RqKdg5YBufa0C+ttzJvoG=9yuti-8AmthCi4jBbd08JEtw@mail.gmail.com/ Suggested-by: Marc Kleine-Budde Link: https://lore.kernel.org/all/20230518-grower-film-ea8b5f853f3e-mkl@pengutronix.de/ Signed-off-by: Frank Jungclaus Link: https://lore.kernel.org/r/20230519195600.420644-2-frank.jungclaus@esd.eu [mkl: remove hex constants in comments after BIT()] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index d33bac3a6c10..93c2351d1e3c 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -3,18 +3,19 @@ * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro * * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs - * Copyright (C) 2022 esd electronics gmbh, Frank Jungclaus + * Copyright (C) 2022-2023 esd electronics gmbh, Frank Jungclaus */ -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include +#include +#include +#include +#include MODULE_AUTHOR("Matthias Fuchs "); MODULE_AUTHOR("Frank Jungclaus "); @@ -27,8 +28,8 @@ MODULE_LICENSE("GPL v2"); #define USB_CANUSBM_PRODUCT_ID 0x0011 /* CAN controller clock frequencies */ -#define ESD_USB2_CAN_CLOCK 60000000 -#define ESD_USBM_CAN_CLOCK 36000000 +#define ESD_USB2_CAN_CLOCK (60 * MEGA) /* Hz */ +#define ESD_USBM_CAN_CLOCK (36 * MEGA) /* Hz */ /* Maximum number of CAN nets */ #define ESD_USB_MAX_NETS 2 @@ -42,20 +43,21 @@ MODULE_LICENSE("GPL v2"); #define CMD_IDADD 6 /* also used for IDADD_REPLY */ /* esd CAN message flags - dlc field */ -#define ESD_RTR 0x10 +#define ESD_RTR BIT(4) + /* esd CAN message flags - id field */ -#define ESD_EXTID 0x20000000 -#define ESD_EVENT 0x40000000 -#define ESD_IDMASK 0x1fffffff +#define ESD_EXTID BIT(29) +#define ESD_EVENT BIT(30) +#define ESD_IDMASK GENMASK(28, 0) /* esd CAN event ids */ #define ESD_EV_CAN_ERROR_EXT 2 /* CAN controller specific diagnostic data */ /* baudrate message flags */ -#define ESD_USB_UBR 0x80000000 -#define ESD_USB_LOM 0x40000000 -#define ESD_USB_NO_BAUDRATE 0x7fffffff +#define ESD_USB_LOM BIT(30) /* Listen Only Mode */ +#define ESD_USB_UBR BIT(31) /* User Bit Rate (controller BTR) in bits 0..27 */ +#define ESD_USB_NO_BAUDRATE GENMASK(30, 0) /* bit rate unconfigured */ /* bit timing CAN-USB/2 */ #define ESD_USB2_TSEG1_MIN 1 @@ -70,7 +72,7 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB2_BRP_MIN 1 #define ESD_USB2_BRP_MAX 1024 #define ESD_USB2_BRP_INC 1 -#define ESD_USB2_3_SAMPLES 0x00800000 +#define ESD_USB2_3_SAMPLES BIT(23) /* esd IDADD message */ #define ESD_ID_ENABLE 0x80 @@ -128,7 +130,7 @@ struct rx_msg { __le32 ts; __le32 id; /* upper 3 bits contain flags */ union { - u8 data[8]; + u8 data[CAN_MAX_DLEN]; struct { u8 status; /* CAN Controller Status */ u8 ecc; /* Error Capture Register */ @@ -145,7 +147,7 @@ struct tx_msg { u8 dlc; u32 hnd; /* opaque handle, not used by device */ __le32 id; /* upper 3 bits contain flags */ - u8 data[8]; + u8 data[CAN_MAX_DLEN]; }; struct tx_done_msg { -- cgit v1.2.3 From 5859a99b52254be356d3cca2e40f7f371ef24b0a Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sat, 20 May 2023 11:18:30 +0100 Subject: net: sfp: add support for a couple of copper multi-rate modules Add support for the Fiberstore SFP-10G-T and Walsun HXSX-ATRC-1 modules. Internally, the PCB silkscreen has what seems to be a part number of WT_502. Fiberstore use v2.2 whereas Walsun use v2.6. These modules contain a Marvell AQrate AQR113C PHY, accessible through I2C 0x51 using the "rollball" protocol. In both cases, the PHY is programmed to use 10GBASE-R with pause-mode rate adaption. Unlike the other rollball modules, these only need a four second delay before we can talk to the PHY. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1q0JfS-006Dqc-8t@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 4799976a1609..7ddebf38ef3d 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -170,7 +170,6 @@ static const enum gpiod_flags gpio_flags[] = { * on board (for a copper SFP) time to initialise. */ #define T_WAIT msecs_to_jiffies(50) -#define T_WAIT_ROLLBALL msecs_to_jiffies(25000) #define T_START_UP msecs_to_jiffies(300) #define T_START_UP_BAD_GPON msecs_to_jiffies(60000) @@ -351,6 +350,27 @@ static void sfp_fixup_ignore_tx_fault(struct sfp *sfp) sfp->tx_fault_ignore = true; } +// For 10GBASE-T short-reach modules +static void sfp_fixup_10gbaset_30m(struct sfp *sfp) +{ + sfp->id.base.connector = SFF8024_CONNECTOR_RJ45; + sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR; +} + +static void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs) +{ + sfp->mdio_protocol = MDIO_I2C_ROLLBALL; + sfp->module_t_wait = msecs_to_jiffies(secs * 1000); +} + +static void sfp_fixup_fs_10gt(struct sfp *sfp) +{ + sfp_fixup_10gbaset_30m(sfp); + + // These SFPs need 4 seconds before the PHY can be accessed + sfp_fixup_rollball_proto(sfp, 4); +} + static void sfp_fixup_halny_gsfp(struct sfp *sfp) { /* Ignore the TX_FAULT and LOS signals on this module. @@ -362,8 +382,8 @@ static void sfp_fixup_halny_gsfp(struct sfp *sfp) static void sfp_fixup_rollball(struct sfp *sfp) { - sfp->mdio_protocol = MDIO_I2C_ROLLBALL; - sfp->module_t_wait = T_WAIT_ROLLBALL; + // Rollball SFPs need 25 seconds before the PHY can be accessed + sfp_fixup_rollball_proto(sfp, 25); } static void sfp_fixup_rollball_cc(struct sfp *sfp) @@ -428,6 +448,10 @@ static const struct sfp_quirk sfp_quirks[] = { SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", sfp_quirk_2500basex, sfp_fixup_long_startup), + // Fiberstore SFP-10G-T doesn't identify as copper, and uses the + // Rollball protocol to talk to the PHY. + SFP_QUIRK_F("FS", "SFP-10G-T", sfp_fixup_fs_10gt), + SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp), // HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports @@ -445,6 +469,10 @@ static const struct sfp_quirk sfp_quirks[] = { SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant), + // Walsun HXSX-ATRC-1 doesn't identify as copper, and uses the + // Rollball protocol to talk to the PHY. + SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt), + SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc), -- cgit v1.2.3 From de5c9bf40c4582729f64f66d9cf4920d50beb897 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Sat, 20 May 2023 11:41:42 +0100 Subject: net: phylink: require supported_interfaces to be filled We have been requiring the supported_interfaces bitmap to be filled in by MAC drivers that have a mac_select_pcs() method. Now that all MAC drivers fill in the supported_interfaces bitmap, it is time to enforce this. We have already required supported_interfaces to be set in order for optical SFPs to be configured in commit f81fa96d8a6c ("net: phylink: use phy_interface_t bitmaps for optical modules"). Refuse phylink creation if supported_interfaces is empty, and remove code to deal with cases where this mask is empty. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/E1q0K1u-006EIP-ET@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index a4dd5197355a..093b7b6e0263 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -712,14 +712,11 @@ static int phylink_validate(struct phylink *pl, unsigned long *supported, { const unsigned long *interfaces = pl->config->supported_interfaces; - if (!phy_interface_empty(interfaces)) { - if (state->interface == PHY_INTERFACE_MODE_NA) - return phylink_validate_mask(pl, supported, state, - interfaces); + if (state->interface == PHY_INTERFACE_MODE_NA) + return phylink_validate_mask(pl, supported, state, interfaces); - if (!test_bit(state->interface, interfaces)) - return -EINVAL; - } + if (!test_bit(state->interface, interfaces)) + return -EINVAL; return phylink_validate_mac_and_pcs(pl, supported, state); } @@ -1513,19 +1510,18 @@ struct phylink *phylink_create(struct phylink_config *config, struct phylink *pl; int ret; - if (mac_ops->mac_select_pcs && - mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) != - ERR_PTR(-EOPNOTSUPP)) - using_mac_select_pcs = true; - /* Validate the supplied configuration */ - if (using_mac_select_pcs && - phy_interface_empty(config->supported_interfaces)) { + if (phy_interface_empty(config->supported_interfaces)) { dev_err(config->dev, - "phylink: error: empty supported_interfaces but mac_select_pcs() method present\n"); + "phylink: error: empty supported_interfaces\n"); return ERR_PTR(-EINVAL); } + if (mac_ops->mac_select_pcs && + mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) != + ERR_PTR(-EOPNOTSUPP)) + using_mac_select_pcs = true; + pl = kzalloc(sizeof(*pl), GFP_KERNEL); if (!pl) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From b2e3406a38f0f48b1dfb81e5bb73d243ff6af179 Mon Sep 17 00:00:00 2001 From: Ratheesh Kannoth Date: Mon, 22 May 2023 07:34:04 +0530 Subject: octeontx2-pf: Add support for page pool Page pool for each rx queue enhance rx side performance by reclaiming buffers back to each queue specific pool. DMA mapping is done only for first allocation of buffers. As subsequent buffers allocation avoid DMA mapping, it results in performance improvement. Image | Performance ------------ | ------------ Vannila | 3Mpps | with this | 42Mpps change | --------------------------- Signed-off-by: Ratheesh Kannoth Link: https://lore.kernel.org/r/20230522020404.152020-1-rkannoth@marvell.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/marvell/octeontx2/Kconfig | 1 + .../ethernet/marvell/octeontx2/nic/otx2_common.c | 78 +++++++++++++++++++--- .../ethernet/marvell/octeontx2/nic/otx2_common.h | 6 +- .../net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 11 ++- .../net/ethernet/marvell/octeontx2/nic/otx2_txrx.c | 19 +++--- .../net/ethernet/marvell/octeontx2/nic/otx2_txrx.h | 1 + .../net/ethernet/marvell/octeontx2/nic/qos_sq.c | 2 +- 7 files changed, 96 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig index 993ac180a5db..a32d85d6f599 100644 --- a/drivers/net/ethernet/marvell/octeontx2/Kconfig +++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig @@ -32,6 +32,7 @@ config OCTEONTX2_PF tristate "Marvell OcteonTX2 NIC Physical Function driver" select OCTEONTX2_MBOX select NET_DEVLINK + select PAGE_POOL depends on (64BIT && COMPILE_TEST) || ARM64 select DIMLIB depends on PCI diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index f9286648e45c..a79cb680bb23 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -518,11 +518,32 @@ void otx2_config_irq_coalescing(struct otx2_nic *pfvf, int qidx) (pfvf->hw.cq_ecount_wait - 1)); } +static int otx2_alloc_pool_buf(struct otx2_nic *pfvf, struct otx2_pool *pool, + dma_addr_t *dma) +{ + unsigned int offset = 0; + struct page *page; + size_t sz; + + sz = SKB_DATA_ALIGN(pool->rbsize); + sz = ALIGN(sz, OTX2_ALIGN); + + page = page_pool_alloc_frag(pool->page_pool, &offset, sz, GFP_ATOMIC); + if (unlikely(!page)) + return -ENOMEM; + + *dma = page_pool_get_dma_addr(page) + offset; + return 0; +} + static int __otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, dma_addr_t *dma) { u8 *buf; + if (pool->page_pool) + return otx2_alloc_pool_buf(pfvf, pool, dma); + buf = napi_alloc_frag_align(pool->rbsize, OTX2_ALIGN); if (unlikely(!buf)) return -ENOMEM; @@ -1205,10 +1226,31 @@ void otx2_sq_free_sqbs(struct otx2_nic *pfvf) } } +void otx2_free_bufs(struct otx2_nic *pfvf, struct otx2_pool *pool, + u64 iova, int size) +{ + struct page *page; + u64 pa; + + pa = otx2_iova_to_phys(pfvf->iommu_domain, iova); + page = virt_to_head_page(phys_to_virt(pa)); + + if (pool->page_pool) { + page_pool_put_full_page(pool->page_pool, page, true); + } else { + dma_unmap_page_attrs(pfvf->dev, iova, size, + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + + put_page(page); + } +} + void otx2_free_aura_ptr(struct otx2_nic *pfvf, int type) { int pool_id, pool_start = 0, pool_end = 0, size = 0; - u64 iova, pa; + struct otx2_pool *pool; + u64 iova; if (type == AURA_NIX_SQ) { pool_start = otx2_get_pool_idx(pfvf, type, 0); @@ -1224,15 +1266,13 @@ void otx2_free_aura_ptr(struct otx2_nic *pfvf, int type) /* Free SQB and RQB pointers from the aura pool */ for (pool_id = pool_start; pool_id < pool_end; pool_id++) { iova = otx2_aura_allocptr(pfvf, pool_id); + pool = &pfvf->qset.pool[pool_id]; while (iova) { if (type == AURA_NIX_RQ) iova -= OTX2_HEAD_ROOM; - pa = otx2_iova_to_phys(pfvf->iommu_domain, iova); - dma_unmap_page_attrs(pfvf->dev, iova, size, - DMA_FROM_DEVICE, - DMA_ATTR_SKIP_CPU_SYNC); - put_page(virt_to_page(phys_to_virt(pa))); + otx2_free_bufs(pfvf, pool, iova, size); + iova = otx2_aura_allocptr(pfvf, pool_id); } } @@ -1250,6 +1290,8 @@ void otx2_aura_pool_free(struct otx2_nic *pfvf) pool = &pfvf->qset.pool[pool_id]; qmem_free(pfvf->dev, pool->stack); qmem_free(pfvf->dev, pool->fc_addr); + page_pool_destroy(pool->page_pool); + pool->page_pool = NULL; } devm_kfree(pfvf->dev, pfvf->qset.pool); pfvf->qset.pool = NULL; @@ -1333,8 +1375,9 @@ int otx2_aura_init(struct otx2_nic *pfvf, int aura_id, } int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, - int stack_pages, int numptrs, int buf_size) + int stack_pages, int numptrs, int buf_size, int type) { + struct page_pool_params pp_params = { 0 }; struct npa_aq_enq_req *aq; struct otx2_pool *pool; int err; @@ -1378,6 +1421,22 @@ int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, aq->ctype = NPA_AQ_CTYPE_POOL; aq->op = NPA_AQ_INSTOP_INIT; + if (type != AURA_NIX_RQ) { + pool->page_pool = NULL; + return 0; + } + + pp_params.flags = PP_FLAG_PAGE_FRAG | PP_FLAG_DMA_MAP; + pp_params.pool_size = numptrs; + pp_params.nid = NUMA_NO_NODE; + pp_params.dev = pfvf->dev; + pp_params.dma_dir = DMA_FROM_DEVICE; + pool->page_pool = page_pool_create(&pp_params); + if (IS_ERR(pool->page_pool)) { + netdev_err(pfvf->netdev, "Creation of page pool failed\n"); + return PTR_ERR(pool->page_pool); + } + return 0; } @@ -1412,7 +1471,7 @@ int otx2_sq_aura_pool_init(struct otx2_nic *pfvf) /* Initialize pool context */ err = otx2_pool_init(pfvf, pool_id, stack_pages, - num_sqbs, hw->sqb_size); + num_sqbs, hw->sqb_size, AURA_NIX_SQ); if (err) goto fail; } @@ -1475,7 +1534,7 @@ int otx2_rq_aura_pool_init(struct otx2_nic *pfvf) } for (pool_id = 0; pool_id < hw->rqpool_cnt; pool_id++) { err = otx2_pool_init(pfvf, pool_id, stack_pages, - num_ptrs, pfvf->rbsize); + num_ptrs, pfvf->rbsize, AURA_NIX_RQ); if (err) goto fail; } @@ -1659,7 +1718,6 @@ int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable) req->bpid_per_chan = 0; #endif - return otx2_sync_mbox_msg(&pfvf->mbox); } EXPORT_SYMBOL(otx2_nix_config_bp); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index b2267c8bec37..a9ed15d1793a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -976,7 +976,7 @@ int otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, int otx2_rxtx_enable(struct otx2_nic *pfvf, bool enable); void otx2_ctx_disable(struct mbox *mbox, int type, bool npa); int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable); -void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq); +void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, int qidx); void otx2_cleanup_tx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq); int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura); int otx2_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); @@ -984,7 +984,7 @@ int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); int otx2_alloc_buffer(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, dma_addr_t *dma); int otx2_pool_init(struct otx2_nic *pfvf, u16 pool_id, - int stack_pages, int numptrs, int buf_size); + int stack_pages, int numptrs, int buf_size, int type); int otx2_aura_init(struct otx2_nic *pfvf, int aura_id, int pool_id, int numptrs); @@ -1054,6 +1054,8 @@ u16 otx2_get_max_mtu(struct otx2_nic *pfvf); int otx2_handle_ntuple_tc_features(struct net_device *netdev, netdev_features_t features); int otx2_smq_flush(struct otx2_nic *pfvf, int smq); +void otx2_free_bufs(struct otx2_nic *pfvf, struct otx2_pool *pool, + u64 iova, int size); /* tc support */ int otx2_init_tc(struct otx2_nic *nic); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index e1883c3edda3..db3fcab1c8cd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -1555,7 +1555,9 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) struct nix_lf_free_req *free_req; struct mbox *mbox = &pf->mbox; struct otx2_cq_queue *cq; + struct otx2_pool *pool; struct msg_req *req; + int pool_id; int qidx; /* Ensure all SQE are processed */ @@ -1584,7 +1586,7 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) for (qidx = 0; qidx < qset->cq_cnt; qidx++) { cq = &qset->cq[qidx]; if (cq->cq_type == CQ_RX) - otx2_cleanup_rx_cqes(pf, cq); + otx2_cleanup_rx_cqes(pf, cq, qidx); else otx2_cleanup_tx_cqes(pf, cq); } @@ -1594,6 +1596,13 @@ static void otx2_free_hw_resources(struct otx2_nic *pf) /* Free RQ buffer pointers*/ otx2_free_aura_ptr(pf, AURA_NIX_RQ); + for (qidx = 0; qidx < pf->hw.rx_queues; qidx++) { + pool_id = otx2_get_pool_idx(pf, AURA_NIX_RQ, qidx); + pool = &pf->qset.pool[pool_id]; + page_pool_destroy(pool->page_pool); + pool->page_pool = NULL; + } + otx2_free_cq_res(pf); /* Free all ingress bandwidth profiles allocated */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c index e288f46b23a8..bd84144480a5 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c @@ -217,9 +217,6 @@ static bool otx2_skb_add_frag(struct otx2_nic *pfvf, struct sk_buff *skb, skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, va - page_address(page) + off, len - off, pfvf->rbsize); - - otx2_dma_unmap_page(pfvf, iova - OTX2_HEAD_ROOM, - pfvf->rbsize, DMA_FROM_DEVICE); return true; } @@ -382,6 +379,8 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf, if (pfvf->netdev->features & NETIF_F_RXCSUM) skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_mark_for_recycle(skb); + napi_gro_frags(napi); } @@ -1186,11 +1185,13 @@ bool otx2_sq_append_skb(struct net_device *netdev, struct otx2_snd_queue *sq, } EXPORT_SYMBOL(otx2_sq_append_skb); -void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq) +void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, int qidx) { struct nix_cqe_rx_s *cqe; + struct otx2_pool *pool; int processed_cqe = 0; - u64 iova, pa; + u16 pool_id; + u64 iova; if (pfvf->xdp_prog) xdp_rxq_info_unreg(&cq->xdp_rxq); @@ -1198,6 +1199,9 @@ void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq) if (otx2_nix_cq_op_status(pfvf, cq) || !cq->pend_cqe) return; + pool_id = otx2_get_pool_idx(pfvf, AURA_NIX_RQ, qidx); + pool = &pfvf->qset.pool[pool_id]; + while (cq->pend_cqe) { cqe = (struct nix_cqe_rx_s *)otx2_get_next_cqe(cq); processed_cqe++; @@ -1210,9 +1214,8 @@ void otx2_cleanup_rx_cqes(struct otx2_nic *pfvf, struct otx2_cq_queue *cq) continue; } iova = cqe->sg.seg_addr - OTX2_HEAD_ROOM; - pa = otx2_iova_to_phys(pfvf->iommu_domain, iova); - otx2_dma_unmap_page(pfvf, iova, pfvf->rbsize, DMA_FROM_DEVICE); - put_page(virt_to_page(phys_to_virt(pa))); + + otx2_free_bufs(pfvf, pool, iova, pfvf->rbsize); } /* Free CQEs to HW */ diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h index 7ab6db9a986f..b5d689eeff80 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h @@ -118,6 +118,7 @@ struct otx2_cq_poll { struct otx2_pool { struct qmem *stack; struct qmem *fc_addr; + struct page_pool *page_pool; u16 rbsize; }; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c index d96ed29c1567..9d887bfc3108 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos_sq.c @@ -63,7 +63,7 @@ static int otx2_qos_sq_aura_pool_init(struct otx2_nic *pfvf, int qidx) /* Initialize pool context */ err = otx2_pool_init(pfvf, pool_id, stack_pages, - num_sqbs, hw->sqb_size); + num_sqbs, hw->sqb_size, AURA_NIX_SQ); if (err) goto aura_free; -- cgit v1.2.3 From 6cc385d2cdb410fd7a774100bf865ae2da9c709b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 17 May 2023 15:41:33 +0200 Subject: selftests/bpf: Add xdp_feature selftest for bond device Introduce selftests to check xdp_feature support for bond driver. Signed-off-by: Lorenzo Bianconi Signed-off-by: Daniel Borkmann Reviewed-by: Jussi Maki Link: https://lore.kernel.org/bpf/64cb8f20e6491f5b971f8d3129335093c359aad7.1684329998.git.lorenzo@kernel.org --- .../testing/selftests/bpf/prog_tests/xdp_bonding.c | 121 +++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c b/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c index d19f79048ff6..c3b45745cbcc 100644 --- a/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c +++ b/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "xdp_dummy.skel.h" #include "xdp_redirect_multi_kern.skel.h" @@ -492,6 +493,123 @@ out: system("ip link del bond_nest2"); } +static void test_xdp_bonding_features(struct skeletons *skeletons) +{ + LIBBPF_OPTS(bpf_xdp_query_opts, query_opts); + int bond_idx, veth1_idx, err; + struct bpf_link *link = NULL; + + if (!ASSERT_OK(system("ip link add bond type bond"), "add bond")) + goto out; + + bond_idx = if_nametoindex("bond"); + if (!ASSERT_GE(bond_idx, 0, "if_nametoindex bond")) + goto out; + + /* query default xdp-feature for bond device */ + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + if (!ASSERT_EQ(query_opts.feature_flags, NETDEV_XDP_ACT_MASK, + "bond query_opts.feature_flags")) + goto out; + + if (!ASSERT_OK(system("ip link add veth0 type veth peer name veth1"), + "add veth{0,1} pair")) + goto out; + + if (!ASSERT_OK(system("ip link add veth2 type veth peer name veth3"), + "add veth{2,3} pair")) + goto out; + + if (!ASSERT_OK(system("ip link set veth0 master bond"), + "add veth0 to master bond")) + goto out; + + /* xdp-feature for bond device should be obtained from the single slave + * device (veth0) + */ + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + if (!ASSERT_EQ(query_opts.feature_flags, + NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_RX_SG, + "bond query_opts.feature_flags")) + goto out; + + veth1_idx = if_nametoindex("veth1"); + if (!ASSERT_GE(veth1_idx, 0, "if_nametoindex veth1")) + goto out; + + link = bpf_program__attach_xdp(skeletons->xdp_dummy->progs.xdp_dummy_prog, + veth1_idx); + if (!ASSERT_OK_PTR(link, "attach program to veth1")) + goto out; + + /* xdp-feature for veth0 are changed */ + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + if (!ASSERT_EQ(query_opts.feature_flags, + NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_RX_SG | NETDEV_XDP_ACT_NDO_XMIT | + NETDEV_XDP_ACT_NDO_XMIT_SG, + "bond query_opts.feature_flags")) + goto out; + + if (!ASSERT_OK(system("ip link set veth2 master bond"), + "add veth2 to master bond")) + goto out; + + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + /* xdp-feature for bond device should be set to the most restrict + * value obtained from attached slave devices (veth0 and veth2) + */ + if (!ASSERT_EQ(query_opts.feature_flags, + NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_RX_SG, + "bond query_opts.feature_flags")) + goto out; + + if (!ASSERT_OK(system("ip link set veth2 nomaster"), + "del veth2 to master bond")) + goto out; + + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + if (!ASSERT_EQ(query_opts.feature_flags, + NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_RX_SG | NETDEV_XDP_ACT_NDO_XMIT | + NETDEV_XDP_ACT_NDO_XMIT_SG, + "bond query_opts.feature_flags")) + goto out; + + if (!ASSERT_OK(system("ip link set veth0 nomaster"), + "del veth0 to master bond")) + goto out; + + err = bpf_xdp_query(bond_idx, XDP_FLAGS_DRV_MODE, &query_opts); + if (!ASSERT_OK(err, "bond bpf_xdp_query")) + goto out; + + ASSERT_EQ(query_opts.feature_flags, NETDEV_XDP_ACT_MASK, + "bond query_opts.feature_flags"); +out: + bpf_link__destroy(link); + system("ip link del veth0"); + system("ip link del veth2"); + system("ip link del bond"); +} + static int libbpf_debug_print(enum libbpf_print_level level, const char *format, va_list args) { @@ -546,6 +664,9 @@ void serial_test_xdp_bonding(void) if (test__start_subtest("xdp_bonding_nested")) test_xdp_bonding_nested(&skeletons); + if (test__start_subtest("xdp_bonding_features")) + test_xdp_bonding_features(&skeletons); + for (i = 0; i < ARRAY_SIZE(bond_test_cases); i++) { struct bond_test_case *test_case = &bond_test_cases[i]; -- cgit v1.2.3 From f46392ee3dec24066e5fb260d9bd497b4cd4d191 Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Wed, 17 May 2023 18:01:04 +0200 Subject: bpftool: Specify XDP Hints ifname when loading program Add ability to specify a network interface used to resolve XDP hints kfuncs when loading program through bpftool. Usage: bpftool prog load [...] xdpmeta_dev Writing just 'dev ' instead of 'xdpmeta_dev' is a very probable mistake that results in not very descriptive errors, so 'bpftool prog load [...] dev ' syntax becomes deprecated, followed by 'bpftool map create [...] dev ' for consistency. Now, to offload program, execute: bpftool prog load [...] offload_dev To offload map: bpftool map create [...] offload_dev 'dev ' still performs offloading in the commands above, but now triggers a warning and is excluded from bash completion. 'xdpmeta_dev' and 'offload_dev' are mutually exclusive options, because 'xdpmeta_dev' basically makes a program device-bound without loading it onto the said device. For now, offloaded programs cannot use XDP hints [0], but if this changes, using 'offload_dev ' should cover this case. [0] https://lore.kernel.org/bpf/a5a636cc-5b03-686f-4be0-000383b05cfc@linux.dev Signed-off-by: Larysa Zaremba Signed-off-by: Daniel Borkmann Reviewed-by: Quentin Monnet Link: https://lore.kernel.org/bpf/20230517160103.1088185-1-larysa.zaremba@intel.com --- tools/bpf/bpftool/Documentation/bpftool-map.rst | 8 ++-- tools/bpf/bpftool/Documentation/bpftool-prog.rst | 11 +++-- tools/bpf/bpftool/bash-completion/bpftool | 7 ++-- tools/bpf/bpftool/map.c | 7 +++- tools/bpf/bpftool/prog.c | 51 ++++++++++++++++++++---- 5 files changed, 64 insertions(+), 20 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst index 11250c4734fe..3b7ba037af95 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst @@ -28,7 +28,7 @@ MAP COMMANDS | **bpftool** **map** { **show** | **list** } [*MAP*] | **bpftool** **map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* \ | **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**inner_map** *MAP*] \ -| [**dev** *NAME*] +| [**offload_dev** *NAME*] | **bpftool** **map dump** *MAP* | **bpftool** **map update** *MAP* [**key** *DATA*] [**value** *VALUE*] [*UPDATE_FLAGS*] | **bpftool** **map lookup** *MAP* [**key** *DATA*] @@ -73,7 +73,7 @@ DESCRIPTION maps. On such kernels bpftool will automatically emit this information as well. - **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**inner_map** *MAP*] [**dev** *NAME*] + **bpftool map create** *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* **entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**inner_map** *MAP*] [**offload_dev** *NAME*] Create a new map with given parameters and pin it to *bpffs* as *FILE*. @@ -86,8 +86,8 @@ DESCRIPTION kernel needs it to collect metadata related to the inner maps that the new map will work with. - Keyword **dev** expects a network interface name, and is used - to request hardware offload for the map. + Keyword **offload_dev** expects a network interface name, + and is used to request hardware offload for the map. **bpftool map dump** *MAP* Dump all entries in a given *MAP*. In case of **name**, diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 9443c524bb76..dcae81bd27ed 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -31,7 +31,7 @@ PROG COMMANDS | **bpftool** **prog dump xlated** *PROG* [{ **file** *FILE* | [**opcodes**] [**linum**] [**visual**] }] | **bpftool** **prog dump jited** *PROG* [{ **file** *FILE* | [**opcodes**] [**linum**] }] | **bpftool** **prog pin** *PROG* *FILE* -| **bpftool** **prog** { **load** | **loadall** } *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**] +| **bpftool** **prog** { **load** | **loadall** } *OBJ* *PATH* [**type** *TYPE*] [**map** { **idx** *IDX* | **name** *NAME* } *MAP*] [{ **offload_dev** | **xdpmeta_dev** } *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**] | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] | **bpftool** **prog detach** *PROG* *ATTACH_TYPE* [*MAP*] | **bpftool** **prog tracelog** @@ -129,7 +129,7 @@ DESCRIPTION contain a dot character ('.'), which is reserved for future extensions of *bpffs*. - **bpftool prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**] + **bpftool prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** { **idx** *IDX* | **name** *NAME* } *MAP*] [{ **offload_dev** | **xdpmeta_dev** } *NAME*] [**pinmaps** *MAP_DIR*] [**autoattach**] Load bpf program(s) from binary *OBJ* and pin as *PATH*. **bpftool prog load** pins only the first program from the *OBJ* as *PATH*. **bpftool prog loadall** pins all programs @@ -143,8 +143,11 @@ DESCRIPTION to be replaced in the ELF file counting from 0, while *NAME* allows to replace a map by name. *MAP* specifies the map to use, referring to it by **id** or through a **pinned** file. - If **dev** *NAME* is specified program will be loaded onto - given networking device (offload). + If **offload_dev** *NAME* is specified program will be loaded + onto given networking device (offload). + If **xdpmeta_dev** *NAME* is specified program will become + device-bound without offloading, this facilitates access + to XDP metadata. Optional **pinmaps** argument can be provided to pin all maps under *MAP_DIR* directory. diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index e7234d1a5306..085bf18f3659 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -278,7 +278,7 @@ _bpftool() _bpftool_get_prog_tags return 0 ;; - dev) + dev|offload_dev|xdpmeta_dev) _sysfs_get_netdevs return 0 ;; @@ -508,7 +508,8 @@ _bpftool() ;; *) COMPREPLY=( $( compgen -W "map" -- "$cur" ) ) - _bpftool_once_attr 'type dev pinmaps autoattach' + _bpftool_once_attr 'type pinmaps autoattach' + _bpftool_one_of_list 'offload_dev xdpmeta_dev' return 0 ;; esac @@ -733,7 +734,7 @@ _bpftool() esac ;; *) - _bpftool_once_attr 'type key value entries name flags dev' + _bpftool_once_attr 'type key value entries name flags offload_dev' if _bpftool_search_list 'array_of_maps' 'hash_of_maps'; then _bpftool_once_attr 'inner_map' fi diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index ae9e822aa3fe..f98f7bbea2b1 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -1287,6 +1287,11 @@ static int do_create(int argc, char **argv) "flags")) goto exit; } else if (is_prefix(*argv, "dev")) { + p_info("Warning: 'bpftool map create [...] dev ' syntax is deprecated.\n" + "Going further, please use 'offload_dev ' to request hardware offload for the map."); + goto offload_dev; + } else if (is_prefix(*argv, "offload_dev")) { +offload_dev: NEXT_ARG(); if (attr.map_ifindex) { @@ -1431,7 +1436,7 @@ static int do_help(int argc, char **argv) "Usage: %1$s %2$s { show | list } [MAP]\n" " %1$s %2$s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n" " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n" - " [inner_map MAP] [dev NAME]\n" + " [inner_map MAP] [offload_dev NAME]\n" " %1$s %2$s dump MAP\n" " %1$s %2$s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n" " %1$s %2$s lookup MAP [key DATA]\n" diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 1f736dc29824..8443a149dd17 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -1517,12 +1517,13 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) struct bpf_program *prog = NULL, *pos; unsigned int old_map_fds = 0; const char *pinmaps = NULL; + __u32 xdpmeta_ifindex = 0; + __u32 offload_ifindex = 0; bool auto_attach = false; struct bpf_object *obj; struct bpf_map *map; const char *pinfile; unsigned int i, j; - __u32 ifindex = 0; const char *file; int idx, err; @@ -1614,17 +1615,46 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) map_replace[old_map_fds].fd = fd; old_map_fds++; } else if (is_prefix(*argv, "dev")) { + p_info("Warning: 'bpftool prog load [...] dev ' syntax is deprecated.\n" + "Going further, please use 'offload_dev ' to offload program to device.\n" + "For applications using XDP hints only, use 'xdpmeta_dev '."); + goto offload_dev; + } else if (is_prefix(*argv, "offload_dev")) { +offload_dev: NEXT_ARG(); - if (ifindex) { - p_err("offload device already specified"); + if (offload_ifindex) { + p_err("offload_dev already specified"); + goto err_free_reuse_maps; + } else if (xdpmeta_ifindex) { + p_err("xdpmeta_dev and offload_dev are mutually exclusive"); + goto err_free_reuse_maps; + } + if (!REQ_ARGS(1)) + goto err_free_reuse_maps; + + offload_ifindex = if_nametoindex(*argv); + if (!offload_ifindex) { + p_err("unrecognized netdevice '%s': %s", + *argv, strerror(errno)); + goto err_free_reuse_maps; + } + NEXT_ARG(); + } else if (is_prefix(*argv, "xdpmeta_dev")) { + NEXT_ARG(); + + if (xdpmeta_ifindex) { + p_err("xdpmeta_dev already specified"); + goto err_free_reuse_maps; + } else if (offload_ifindex) { + p_err("xdpmeta_dev and offload_dev are mutually exclusive"); goto err_free_reuse_maps; } if (!REQ_ARGS(1)) goto err_free_reuse_maps; - ifindex = if_nametoindex(*argv); - if (!ifindex) { + xdpmeta_ifindex = if_nametoindex(*argv); + if (!xdpmeta_ifindex) { p_err("unrecognized netdevice '%s': %s", *argv, strerror(errno)); goto err_free_reuse_maps; @@ -1671,7 +1701,12 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) goto err_close_obj; } - bpf_program__set_ifindex(pos, ifindex); + if (prog_type == BPF_PROG_TYPE_XDP && xdpmeta_ifindex) { + bpf_program__set_flags(pos, BPF_F_XDP_DEV_BOUND_ONLY); + bpf_program__set_ifindex(pos, xdpmeta_ifindex); + } else { + bpf_program__set_ifindex(pos, offload_ifindex); + } if (bpf_program__type(pos) != prog_type) bpf_program__set_type(pos, prog_type); bpf_program__set_expected_attach_type(pos, expected_attach_type); @@ -1709,7 +1744,7 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) idx = 0; bpf_object__for_each_map(map, obj) { if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) - bpf_map__set_ifindex(map, ifindex); + bpf_map__set_ifindex(map, offload_ifindex); if (j < old_map_fds && idx == map_replace[j].idx) { err = bpf_map__reuse_fd(map, map_replace[j++].fd); @@ -2416,7 +2451,7 @@ static int do_help(int argc, char **argv) " %1$s %2$s dump jited PROG [{ file FILE | [opcodes] [linum] }]\n" " %1$s %2$s pin PROG FILE\n" " %1$s %2$s { load | loadall } OBJ PATH \\\n" - " [type TYPE] [dev NAME] \\\n" + " [type TYPE] [{ offload_dev | xdpmeta_dev } NAME] \\\n" " [map { idx IDX | name NAME } MAP]\\\n" " [pinmaps MAP_DIR]\n" " [autoattach]\n" -- cgit v1.2.3 From e7d85427ef898afe66c4c1b7e06e5659cec6b640 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 22 May 2023 16:29:14 -0700 Subject: bpf: Validate BPF object in BPF_OBJ_PIN before calling LSM Do a sanity check whether provided file-to-be-pinned is actually a BPF object (prog, map, btf) before calling security_path_mknod LSM hook. If it's not, LSM hook doesn't have to be triggered, as the operation has no chance of succeeding anyways. Suggested-by: Christian Brauner Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Reviewed-by: Christian Brauner Link: https://lore.kernel.org/bpf/20230522232917.2454595-2-andrii@kernel.org --- kernel/bpf/inode.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 9948b542a470..329f27d5cacf 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -448,18 +448,17 @@ static int bpf_obj_do_pin(const char __user *pathname, void *raw, if (IS_ERR(dentry)) return PTR_ERR(dentry); - mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask()); - - ret = security_path_mknod(&path, dentry, mode, 0); - if (ret) - goto out; - dir = d_inode(path.dentry); if (dir->i_op != &bpf_dir_iops) { ret = -EPERM; goto out; } + mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask()); + ret = security_path_mknod(&path, dentry, mode, 0); + if (ret) + goto out; + switch (type) { case BPF_TYPE_PROG: ret = vfs_mkobj(dentry, mode, bpf_mkprog, raw); -- cgit v1.2.3 From 2b001b94073be6097b1a4a21defc5cfbb7aa2f9f Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 May 2023 10:00:11 -0700 Subject: libbpf: Start v1.3 development cycle Bump libbpf.map to v1.3.0 to start a new libbpf version cycle. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230523170013.728457-3-andrii@kernel.org --- tools/lib/bpf/libbpf.map | 3 +++ tools/lib/bpf/libbpf_version.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index a5aa3a383d69..9171ac89a802 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -391,3 +391,6 @@ LIBBPF_1.2.0 { bpf_map_get_info_by_fd; bpf_prog_get_info_by_fd; } LIBBPF_1.1.0; + +LIBBPF_1.3.0 { +} LIBBPF_1.2.0; diff --git a/tools/lib/bpf/libbpf_version.h b/tools/lib/bpf/libbpf_version.h index 1fd2eeac5cfc..290411ddb39e 100644 --- a/tools/lib/bpf/libbpf_version.h +++ b/tools/lib/bpf/libbpf_version.h @@ -4,6 +4,6 @@ #define __LIBBPF_VERSION_H #define LIBBPF_MAJOR_VERSION 1 -#define LIBBPF_MINOR_VERSION 2 +#define LIBBPF_MINOR_VERSION 3 #endif /* __LIBBPF_VERSION_H */ -- cgit v1.2.3 From cb8edce28073a906401c9e421eca7c99f3396da1 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 15 May 2023 16:48:06 -0700 Subject: bpf: Support O_PATH FDs in BPF_OBJ_PIN and BPF_OBJ_GET commands Current UAPI of BPF_OBJ_PIN and BPF_OBJ_GET commands of bpf() syscall forces users to specify pinning location as a string-based absolute or relative (to current working directory) path. This has various implications related to security (e.g., symlink-based attacks), forces BPF FS to be exposed in the file system, which can cause races with other applications. One of the feedbacks we got from folks working with containers heavily was that inability to use purely FD-based location specification was an unfortunate limitation and hindrance for BPF_OBJ_PIN and BPF_OBJ_GET commands. This patch closes this oversight, adding path_fd field to BPF_OBJ_PIN and BPF_OBJ_GET UAPI, following conventions established by *at() syscalls for dirfd + pathname combinations. This now allows interesting possibilities like working with detached BPF FS mount (e.g., to perform multiple pinnings without running a risk of someone interfering with them), and generally making pinning/getting more secure and not prone to any races and/or security attacks. This is demonstrated by a selftest added in subsequent patch that takes advantage of new mount APIs (fsopen, fsconfig, fsmount) to demonstrate creating detached BPF FS mount, pinning, and then getting BPF map out of it, all while never exposing this private instance of BPF FS to outside worlds. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Reviewed-by: Christian Brauner Link: https://lore.kernel.org/bpf/20230523170013.728457-4-andrii@kernel.org --- include/linux/bpf.h | 4 ++-- include/uapi/linux/bpf.h | 10 ++++++++++ kernel/bpf/inode.c | 16 ++++++++-------- kernel/bpf/syscall.c | 25 ++++++++++++++++++++----- tools/include/uapi/linux/bpf.h | 10 ++++++++++ 5 files changed, 50 insertions(+), 15 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 36e4b2d8cca2..f58895830ada 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2077,8 +2077,8 @@ struct file *bpf_link_new_file(struct bpf_link *link, int *reserved_fd); struct bpf_link *bpf_link_get_from_fd(u32 ufd); struct bpf_link *bpf_link_get_curr_or_next(u32 *id); -int bpf_obj_pin_user(u32 ufd, const char __user *pathname); -int bpf_obj_get_user(const char __user *pathname, int flags); +int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname); +int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags); #define BPF_ITER_FUNC_PREFIX "bpf_iter_" #define DEFINE_BPF_ITER_FUNC(target, args...) \ diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 1bb11a6ee667..9273c654743c 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1272,6 +1272,9 @@ enum { /* Create a map that will be registered/unregesitered by the backed bpf_link */ BPF_F_LINK = (1U << 13), + +/* Get path from provided FD in BPF_OBJ_PIN/BPF_OBJ_GET commands */ + BPF_F_PATH_FD = (1U << 14), }; /* Flags for BPF_PROG_QUERY. */ @@ -1420,6 +1423,13 @@ union bpf_attr { __aligned_u64 pathname; __u32 bpf_fd; __u32 file_flags; + /* Same as dirfd in openat() syscall; see openat(2) + * manpage for details of path FD and pathname semantics; + * path_fd should accompanied by BPF_F_PATH_FD flag set in + * file_flags field, otherwise it should be set to zero; + * if BPF_F_PATH_FD flag is not set, AT_FDCWD is assumed. + */ + __s32 path_fd; }; struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 329f27d5cacf..4174f76133df 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -435,7 +435,7 @@ static int bpf_iter_link_pin_kernel(struct dentry *parent, return ret; } -static int bpf_obj_do_pin(const char __user *pathname, void *raw, +static int bpf_obj_do_pin(int path_fd, const char __user *pathname, void *raw, enum bpf_type type) { struct dentry *dentry; @@ -444,7 +444,7 @@ static int bpf_obj_do_pin(const char __user *pathname, void *raw, umode_t mode; int ret; - dentry = user_path_create(AT_FDCWD, pathname, &path, 0); + dentry = user_path_create(path_fd, pathname, &path, 0); if (IS_ERR(dentry)) return PTR_ERR(dentry); @@ -477,7 +477,7 @@ out: return ret; } -int bpf_obj_pin_user(u32 ufd, const char __user *pathname) +int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname) { enum bpf_type type; void *raw; @@ -487,14 +487,14 @@ int bpf_obj_pin_user(u32 ufd, const char __user *pathname) if (IS_ERR(raw)) return PTR_ERR(raw); - ret = bpf_obj_do_pin(pathname, raw, type); + ret = bpf_obj_do_pin(path_fd, pathname, raw, type); if (ret != 0) bpf_any_put(raw, type); return ret; } -static void *bpf_obj_do_get(const char __user *pathname, +static void *bpf_obj_do_get(int path_fd, const char __user *pathname, enum bpf_type *type, int flags) { struct inode *inode; @@ -502,7 +502,7 @@ static void *bpf_obj_do_get(const char __user *pathname, void *raw; int ret; - ret = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW, &path); + ret = user_path_at(path_fd, pathname, LOOKUP_FOLLOW, &path); if (ret) return ERR_PTR(ret); @@ -526,7 +526,7 @@ out: return ERR_PTR(ret); } -int bpf_obj_get_user(const char __user *pathname, int flags) +int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags) { enum bpf_type type = BPF_TYPE_UNSPEC; int f_flags; @@ -537,7 +537,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags) if (f_flags < 0) return f_flags; - raw = bpf_obj_do_get(pathname, &type, f_flags); + raw = bpf_obj_do_get(path_fd, pathname, &type, f_flags); if (IS_ERR(raw)) return PTR_ERR(raw); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index b2621089904b..c7f6807215e6 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2697,23 +2697,38 @@ free_prog: return err; } -#define BPF_OBJ_LAST_FIELD file_flags +#define BPF_OBJ_LAST_FIELD path_fd static int bpf_obj_pin(const union bpf_attr *attr) { - if (CHECK_ATTR(BPF_OBJ) || attr->file_flags != 0) + int path_fd; + + if (CHECK_ATTR(BPF_OBJ) || attr->file_flags & ~BPF_F_PATH_FD) + return -EINVAL; + + /* path_fd has to be accompanied by BPF_F_PATH_FD flag */ + if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd) return -EINVAL; - return bpf_obj_pin_user(attr->bpf_fd, u64_to_user_ptr(attr->pathname)); + path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD; + return bpf_obj_pin_user(attr->bpf_fd, path_fd, + u64_to_user_ptr(attr->pathname)); } static int bpf_obj_get(const union bpf_attr *attr) { + int path_fd; + if (CHECK_ATTR(BPF_OBJ) || attr->bpf_fd != 0 || - attr->file_flags & ~BPF_OBJ_FLAG_MASK) + attr->file_flags & ~(BPF_OBJ_FLAG_MASK | BPF_F_PATH_FD)) + return -EINVAL; + + /* path_fd has to be accompanied by BPF_F_PATH_FD flag */ + if (!(attr->file_flags & BPF_F_PATH_FD) && attr->path_fd) return -EINVAL; - return bpf_obj_get_user(u64_to_user_ptr(attr->pathname), + path_fd = attr->file_flags & BPF_F_PATH_FD ? attr->path_fd : AT_FDCWD; + return bpf_obj_get_user(path_fd, u64_to_user_ptr(attr->pathname), attr->file_flags); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 1bb11a6ee667..9273c654743c 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1272,6 +1272,9 @@ enum { /* Create a map that will be registered/unregesitered by the backed bpf_link */ BPF_F_LINK = (1U << 13), + +/* Get path from provided FD in BPF_OBJ_PIN/BPF_OBJ_GET commands */ + BPF_F_PATH_FD = (1U << 14), }; /* Flags for BPF_PROG_QUERY. */ @@ -1420,6 +1423,13 @@ union bpf_attr { __aligned_u64 pathname; __u32 bpf_fd; __u32 file_flags; + /* Same as dirfd in openat() syscall; see openat(2) + * manpage for details of path FD and pathname semantics; + * path_fd should accompanied by BPF_F_PATH_FD flag set in + * file_flags field, otherwise it should be set to zero; + * if BPF_F_PATH_FD flag is not set, AT_FDCWD is assumed. + */ + __s32 path_fd; }; struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ -- cgit v1.2.3 From f1674dc79fd276aeef6cad738a5f25ed2ba6d329 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 15 May 2023 17:01:58 -0700 Subject: libbpf: Add opts-based bpf_obj_pin() API and add support for path_fd Add path_fd support for bpf_obj_pin() and bpf_obj_get() operations (through their opts-based variants). This allows to take advantage of new kernel-side support for O_PATH-based pin/get location specification. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230523170013.728457-4-andrii@kernel.org --- tools/lib/bpf/bpf.c | 17 ++++++++++++++--- tools/lib/bpf/bpf.h | 18 ++++++++++++++++-- tools/lib/bpf/libbpf.map | 2 ++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 128ac723c4ea..ed86b37d8024 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -572,20 +572,30 @@ int bpf_map_update_batch(int fd, const void *keys, const void *values, __u32 *co (void *)keys, (void *)values, count, opts); } -int bpf_obj_pin(int fd, const char *pathname) +int bpf_obj_pin_opts(int fd, const char *pathname, const struct bpf_obj_pin_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, file_flags); + const size_t attr_sz = offsetofend(union bpf_attr, path_fd); union bpf_attr attr; int ret; + if (!OPTS_VALID(opts, bpf_obj_pin_opts)) + return libbpf_err(-EINVAL); + memset(&attr, 0, attr_sz); + attr.path_fd = OPTS_GET(opts, path_fd, 0); attr.pathname = ptr_to_u64((void *)pathname); + attr.file_flags = OPTS_GET(opts, file_flags, 0); attr.bpf_fd = fd; ret = sys_bpf(BPF_OBJ_PIN, &attr, attr_sz); return libbpf_err_errno(ret); } +int bpf_obj_pin(int fd, const char *pathname) +{ + return bpf_obj_pin_opts(fd, pathname, NULL); +} + int bpf_obj_get(const char *pathname) { return bpf_obj_get_opts(pathname, NULL); @@ -593,7 +603,7 @@ int bpf_obj_get(const char *pathname) int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts) { - const size_t attr_sz = offsetofend(union bpf_attr, file_flags); + const size_t attr_sz = offsetofend(union bpf_attr, path_fd); union bpf_attr attr; int fd; @@ -601,6 +611,7 @@ int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts) return libbpf_err(-EINVAL); memset(&attr, 0, attr_sz); + attr.path_fd = OPTS_GET(opts, path_fd, 0); attr.pathname = ptr_to_u64((void *)pathname); attr.file_flags = OPTS_GET(opts, file_flags, 0); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index a2c091389b18..9aa0ee473754 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -284,16 +284,30 @@ LIBBPF_API int bpf_map_update_batch(int fd, const void *keys, const void *values __u32 *count, const struct bpf_map_batch_opts *opts); -struct bpf_obj_get_opts { +struct bpf_obj_pin_opts { size_t sz; /* size of this struct for forward/backward compatibility */ __u32 file_flags; + int path_fd; size_t :0; }; -#define bpf_obj_get_opts__last_field file_flags +#define bpf_obj_pin_opts__last_field path_fd LIBBPF_API int bpf_obj_pin(int fd, const char *pathname); +LIBBPF_API int bpf_obj_pin_opts(int fd, const char *pathname, + const struct bpf_obj_pin_opts *opts); + +struct bpf_obj_get_opts { + size_t sz; /* size of this struct for forward/backward compatibility */ + + __u32 file_flags; + int path_fd; + + size_t :0; +}; +#define bpf_obj_get_opts__last_field path_fd + LIBBPF_API int bpf_obj_get(const char *pathname); LIBBPF_API int bpf_obj_get_opts(const char *pathname, const struct bpf_obj_get_opts *opts); diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 9171ac89a802..7521a2fb7626 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -393,4 +393,6 @@ LIBBPF_1.2.0 { } LIBBPF_1.1.0; LIBBPF_1.3.0 { + global: + bpf_obj_pin_opts; } LIBBPF_1.2.0; -- cgit v1.2.3 From 3b22f98e5a05feee20699df0870dc5d47c9b61dd Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 23 May 2023 10:00:13 -0700 Subject: selftests/bpf: Add path_fd-based BPF_OBJ_PIN and BPF_OBJ_GET tests Add a selftest demonstrating using detach-mounted BPF FS using new mount APIs, and pinning and getting BPF map using such mount. This demonstrates how something like container manager could setup BPF FS, pin and adjust all the necessary objects in it, all before exposing BPF FS to a particular mount namespace. Also add a few subtests validating all meaningful combinations of path_fd and pathname. We use mounted /sys/fs/bpf location for these. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230523170013.728457-5-andrii@kernel.org --- .../selftests/bpf/prog_tests/bpf_obj_pinning.c | 268 +++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c b/tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c new file mode 100644 index 000000000000..31f1e815f671 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +static inline int sys_fsopen(const char *fsname, unsigned flags) +{ + return syscall(__NR_fsopen, fsname, flags); +} + +static inline int sys_fsconfig(int fs_fd, unsigned cmd, const char *key, const void *val, int aux) +{ + return syscall(__NR_fsconfig, fs_fd, cmd, key, val, aux); +} + +static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags) +{ + return syscall(__NR_fsmount, fs_fd, flags, ms_flags); +} + +__attribute__((unused)) +static inline int sys_move_mount(int from_dfd, const char *from_path, + int to_dfd, const char *to_path, + unsigned int ms_flags) +{ + return syscall(__NR_move_mount, from_dfd, from_path, to_dfd, to_path, ms_flags); +} + +static void bpf_obj_pinning_detached(void) +{ + LIBBPF_OPTS(bpf_obj_pin_opts, pin_opts); + LIBBPF_OPTS(bpf_obj_get_opts, get_opts); + int fs_fd = -1, mnt_fd = -1; + int map_fd = -1, map_fd2 = -1; + int zero = 0, src_value, dst_value, err; + const char *map_name = "fsmount_map"; + + /* A bunch of below UAPI calls are constructed based on reading: + * https://brauner.io/2023/02/28/mounting-into-mount-namespaces.html + */ + + /* create VFS context */ + fs_fd = sys_fsopen("bpf", 0); + if (!ASSERT_GE(fs_fd, 0, "fs_fd")) + goto cleanup; + + /* instantiate FS object */ + err = sys_fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); + if (!ASSERT_OK(err, "fs_create")) + goto cleanup; + + /* create O_PATH fd for detached mount */ + mnt_fd = sys_fsmount(fs_fd, 0, 0); + if (!ASSERT_GE(mnt_fd, 0, "mnt_fd")) + goto cleanup; + + /* If we wanted to expose detached mount in the file system, we'd do + * something like below. But the whole point is that we actually don't + * even have to expose BPF FS in the file system to be able to work + * (pin/get objects) with it. + * + * err = sys_move_mount(mnt_fd, "", -EBADF, mnt_path, MOVE_MOUNT_F_EMPTY_PATH); + * if (!ASSERT_OK(err, "move_mount")) + * goto cleanup; + */ + + /* create BPF map to pin */ + map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, map_name, 4, 4, 1, NULL); + if (!ASSERT_GE(map_fd, 0, "map_fd")) + goto cleanup; + + /* pin BPF map into detached BPF FS through mnt_fd */ + pin_opts.file_flags = BPF_F_PATH_FD; + pin_opts.path_fd = mnt_fd; + err = bpf_obj_pin_opts(map_fd, map_name, &pin_opts); + if (!ASSERT_OK(err, "map_pin")) + goto cleanup; + + /* get BPF map from detached BPF FS through mnt_fd */ + get_opts.file_flags = BPF_F_PATH_FD; + get_opts.path_fd = mnt_fd; + map_fd2 = bpf_obj_get_opts(map_name, &get_opts); + if (!ASSERT_GE(map_fd2, 0, "map_get")) + goto cleanup; + + /* update map through one FD */ + src_value = 0xcafebeef; + err = bpf_map_update_elem(map_fd, &zero, &src_value, 0); + ASSERT_OK(err, "map_update"); + + /* check values written/read through different FDs do match */ + dst_value = 0; + err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value); + ASSERT_OK(err, "map_lookup"); + ASSERT_EQ(dst_value, src_value, "map_value_eq1"); + ASSERT_EQ(dst_value, 0xcafebeef, "map_value_eq2"); + +cleanup: + if (map_fd >= 0) + ASSERT_OK(close(map_fd), "close_map_fd"); + if (map_fd2 >= 0) + ASSERT_OK(close(map_fd2), "close_map_fd2"); + if (fs_fd >= 0) + ASSERT_OK(close(fs_fd), "close_fs_fd"); + if (mnt_fd >= 0) + ASSERT_OK(close(mnt_fd), "close_mnt_fd"); +} + +enum path_kind +{ + PATH_STR_ABS, + PATH_STR_REL, + PATH_FD_REL, +}; + +static void validate_pin(int map_fd, const char *map_name, int src_value, + enum path_kind path_kind) +{ + LIBBPF_OPTS(bpf_obj_pin_opts, pin_opts); + char abs_path[PATH_MAX], old_cwd[PATH_MAX]; + const char *pin_path = NULL; + int zero = 0, dst_value, map_fd2, err; + + snprintf(abs_path, sizeof(abs_path), "/sys/fs/bpf/%s", map_name); + old_cwd[0] = '\0'; + + switch (path_kind) { + case PATH_STR_ABS: + /* absolute path */ + pin_path = abs_path; + break; + case PATH_STR_REL: + /* cwd + relative path */ + ASSERT_OK_PTR(getcwd(old_cwd, sizeof(old_cwd)), "getcwd"); + ASSERT_OK(chdir("/sys/fs/bpf"), "chdir"); + pin_path = map_name; + break; + case PATH_FD_REL: + /* dir fd + relative path */ + pin_opts.file_flags = BPF_F_PATH_FD; + pin_opts.path_fd = open("/sys/fs/bpf", O_PATH); + ASSERT_GE(pin_opts.path_fd, 0, "path_fd"); + pin_path = map_name; + break; + } + + /* pin BPF map using specified path definition */ + err = bpf_obj_pin_opts(map_fd, pin_path, &pin_opts); + ASSERT_OK(err, "obj_pin"); + + /* cleanup */ + if (pin_opts.path_fd >= 0) + close(pin_opts.path_fd); + if (old_cwd[0]) + ASSERT_OK(chdir(old_cwd), "restore_cwd"); + + map_fd2 = bpf_obj_get(abs_path); + if (!ASSERT_GE(map_fd2, 0, "map_get")) + goto cleanup; + + /* update map through one FD */ + err = bpf_map_update_elem(map_fd, &zero, &src_value, 0); + ASSERT_OK(err, "map_update"); + + /* check values written/read through different FDs do match */ + dst_value = 0; + err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value); + ASSERT_OK(err, "map_lookup"); + ASSERT_EQ(dst_value, src_value, "map_value_eq"); +cleanup: + if (map_fd2 >= 0) + ASSERT_OK(close(map_fd2), "close_map_fd2"); + unlink(abs_path); +} + +static void validate_get(int map_fd, const char *map_name, int src_value, + enum path_kind path_kind) +{ + LIBBPF_OPTS(bpf_obj_get_opts, get_opts); + char abs_path[PATH_MAX], old_cwd[PATH_MAX]; + const char *pin_path = NULL; + int zero = 0, dst_value, map_fd2, err; + + snprintf(abs_path, sizeof(abs_path), "/sys/fs/bpf/%s", map_name); + /* pin BPF map using specified path definition */ + err = bpf_obj_pin(map_fd, abs_path); + if (!ASSERT_OK(err, "pin_map")) + return; + + old_cwd[0] = '\0'; + + switch (path_kind) { + case PATH_STR_ABS: + /* absolute path */ + pin_path = abs_path; + break; + case PATH_STR_REL: + /* cwd + relative path */ + ASSERT_OK_PTR(getcwd(old_cwd, sizeof(old_cwd)), "getcwd"); + ASSERT_OK(chdir("/sys/fs/bpf"), "chdir"); + pin_path = map_name; + break; + case PATH_FD_REL: + /* dir fd + relative path */ + get_opts.file_flags = BPF_F_PATH_FD; + get_opts.path_fd = open("/sys/fs/bpf", O_PATH); + ASSERT_GE(get_opts.path_fd, 0, "path_fd"); + pin_path = map_name; + break; + } + + map_fd2 = bpf_obj_get_opts(pin_path, &get_opts); + if (!ASSERT_GE(map_fd2, 0, "map_get")) + goto cleanup; + + /* cleanup */ + if (get_opts.path_fd >= 0) + close(get_opts.path_fd); + if (old_cwd[0]) + ASSERT_OK(chdir(old_cwd), "restore_cwd"); + + /* update map through one FD */ + err = bpf_map_update_elem(map_fd, &zero, &src_value, 0); + ASSERT_OK(err, "map_update"); + + /* check values written/read through different FDs do match */ + dst_value = 0; + err = bpf_map_lookup_elem(map_fd2, &zero, &dst_value); + ASSERT_OK(err, "map_lookup"); + ASSERT_EQ(dst_value, src_value, "map_value_eq"); +cleanup: + if (map_fd2 >= 0) + ASSERT_OK(close(map_fd2), "close_map_fd2"); + unlink(abs_path); +} + +static void bpf_obj_pinning_mounted(enum path_kind path_kind) +{ + const char *map_name = "mounted_map"; + int map_fd; + + /* create BPF map to pin */ + map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, map_name, 4, 4, 1, NULL); + if (!ASSERT_GE(map_fd, 0, "map_fd")) + return; + + validate_pin(map_fd, map_name, 100 + (int)path_kind, path_kind); + validate_get(map_fd, map_name, 200 + (int)path_kind, path_kind); + ASSERT_OK(close(map_fd), "close_map_fd"); +} + +void test_bpf_obj_pinning() +{ + if (test__start_subtest("detached")) + bpf_obj_pinning_detached(); + if (test__start_subtest("mounted-str-abs")) + bpf_obj_pinning_mounted(PATH_STR_ABS); + if (test__start_subtest("mounted-str-rel")) + bpf_obj_pinning_mounted(PATH_STR_REL); + if (test__start_subtest("mounted-fd-rel")) + bpf_obj_pinning_mounted(PATH_FD_REL); +} -- cgit v1.2.3 From ac2e8e3cfe48439a2403b3d616fb654db313e362 Mon Sep 17 00:00:00 2001 From: Josua Mayer Date: Mon, 22 May 2023 17:52:42 +0300 Subject: net: sfp: add support for HXSX-ATRI-1 copper SFP+ module Walsun offers commercial ("C") and industrial ("I") variants of multi-rate copper SFP+ modules. Add quirk for HXSX-ATRI-1 using same parameters as the already supported commercial variant HXSX-ATRC-1. Signed-off-by: Josua Mayer Reviewed-by: Russell King (Oracle) Link: https://lore.kernel.org/r/20230522145242.30192-2-josua@solid-run.com/ Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 7ddebf38ef3d..d855a18308d7 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -469,9 +469,10 @@ static const struct sfp_quirk sfp_quirks[] = { SFP_QUIRK_M("UBNT", "UF-INSTANT", sfp_quirk_ubnt_uf_instant), - // Walsun HXSX-ATRC-1 doesn't identify as copper, and uses the + // Walsun HXSX-ATR[CI]-1 don't identify as copper, and use the // Rollball protocol to talk to the PHY. SFP_QUIRK_F("Walsun", "HXSX-ATRC-1", sfp_fixup_fs_10gt), + SFP_QUIRK_F("Walsun", "HXSX-ATRI-1", sfp_fixup_fs_10gt), SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), SFP_QUIRK_M("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), -- cgit v1.2.3 From 57910a47ffe993c2724a916b9e003d84ff0c0df7 Mon Sep 17 00:00:00 2001 From: Jaco Coetzee Date: Mon, 22 May 2023 16:13:35 +0200 Subject: nfp: add L4 RSS hashing on UDP traffic Add layer 4 RSS hashing on UDP traffic to allow for the utilization of multiple queues for multiple connections on the same IP address. Previously, since the introduction of the driver, RSS hashing was only performed on the source and destination IP addresses of UDP packets thereby limiting UDP traffic to a single queue for multiple connections on the same IP address. The transport layer is now included in RSS hashing for UDP traffic, which was not previously the case. The reason behind the previous limitation is unclear - either a historic limitation of the NFP device, or an oversight. Signed-off-by: Jaco Coetzee Acked-by: Simon Horman Signed-off-by: Louis Peens Link: https://lore.kernel.org/r/20230522141335.22536-1-louis.peens@corigine.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 62f0bf91d1e1..b7cce746b5c0 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -2418,6 +2418,8 @@ static void nfp_net_rss_init(struct nfp_net *nn) /* Enable IPv4/IPv6 TCP by default */ nn->rss_cfg = NFP_NET_CFG_RSS_IPV4_TCP | NFP_NET_CFG_RSS_IPV6_TCP | + NFP_NET_CFG_RSS_IPV4_UDP | + NFP_NET_CFG_RSS_IPV6_UDP | FIELD_PREP(NFP_NET_CFG_RSS_HFUNC, nn->rss_hfunc) | NFP_NET_CFG_RSS_MASK; } -- cgit v1.2.3 From b841b901c452d92610f739a36e54978453528876 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:10 +0100 Subject: net: Declare MSG_SPLICE_PAGES internal sendmsg() flag Declare MSG_SPLICE_PAGES, an internal sendmsg() flag, that hints to a network protocol that it should splice pages from the source iterator rather than copying the data if it can. This flag is added to a list that is cleared by sendmsg syscalls on entry. This is intended as a replacement for the ->sendpage() op, allowing a way to splice in several multipage folios in one go. Signed-off-by: David Howells Reviewed-by: Willem de Bruijn cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/linux/socket.h | 3 +++ io_uring/net.c | 2 ++ net/socket.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/include/linux/socket.h b/include/linux/socket.h index 13c3a237b9c9..bd1cc3238851 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -327,6 +327,7 @@ struct ucred { */ #define MSG_ZEROCOPY 0x4000000 /* Use user data in kernel path */ +#define MSG_SPLICE_PAGES 0x8000000 /* Splice the pages from the iterator in sendmsg() */ #define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */ #define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exec for file descriptor received through @@ -337,6 +338,8 @@ struct ucred { #define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */ #endif +/* Flags to be cleared on entry by sendmsg and sendmmsg syscalls */ +#define MSG_INTERNAL_SENDMSG_FLAGS (MSG_SPLICE_PAGES) /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ #define SOL_IP 0 diff --git a/io_uring/net.c b/io_uring/net.c index 89e839013837..f7cbb3c7a575 100644 --- a/io_uring/net.c +++ b/io_uring/net.c @@ -389,6 +389,7 @@ int io_send(struct io_kiocb *req, unsigned int issue_flags) if (flags & MSG_WAITALL) min_ret = iov_iter_count(&msg.msg_iter); + flags &= ~MSG_INTERNAL_SENDMSG_FLAGS; msg.msg_flags = flags; ret = sock_sendmsg(sock, &msg); if (ret < min_ret) { @@ -1136,6 +1137,7 @@ int io_send_zc(struct io_kiocb *req, unsigned int issue_flags) msg_flags |= MSG_DONTWAIT; if (msg_flags & MSG_WAITALL) min_ret = iov_iter_count(&msg.msg_iter); + msg_flags &= ~MSG_INTERNAL_SENDMSG_FLAGS; msg.msg_flags = msg_flags; msg.msg_ubuf = &io_notif_to_data(zc->notif)->uarg; diff --git a/net/socket.c b/net/socket.c index b7e01d0fe082..3df96e9ba4e2 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2138,6 +2138,7 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags, msg.msg_name = (struct sockaddr *)&address; msg.msg_namelen = addr_len; } + flags &= ~MSG_INTERNAL_SENDMSG_FLAGS; if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; msg.msg_flags = flags; @@ -2483,6 +2484,7 @@ static int ____sys_sendmsg(struct socket *sock, struct msghdr *msg_sys, msg_sys->msg_control = ctl_buf; msg_sys->msg_control_is_user = false; } + flags &= ~MSG_INTERNAL_SENDMSG_FLAGS; msg_sys->msg_flags = flags; if (sock->file->f_flags & O_NONBLOCK) -- cgit v1.2.3 From 96449f90240713bd9bd653d6b15266a1044cfa7b Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:11 +0100 Subject: net: Pass max frags into skb_append_pagefrags() Pass the maximum number of fragments into skb_append_pagefrags() rather than using MAX_SKB_FRAGS so that it can be used from code that wants to specify sysctl_max_skb_frags. Signed-off-by: David Howells cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 2 +- net/core/skbuff.c | 4 ++-- net/ipv4/ip_output.c | 3 ++- net/unix/af_unix.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 8cff3d817131..15011408c47c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1383,7 +1383,7 @@ static inline int skb_pad(struct sk_buff *skb, int pad) #define dev_kfree_skb(a) consume_skb(a) int skb_append_pagefrags(struct sk_buff *skb, struct page *page, - int offset, size_t size); + int offset, size_t size, size_t max_frags); struct skb_seq_state { __u32 lower_offset; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6724a84ebb09..7f53dcb26ad3 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4188,13 +4188,13 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, EXPORT_SYMBOL(skb_find_text); int skb_append_pagefrags(struct sk_buff *skb, struct page *page, - int offset, size_t size) + int offset, size_t size, size_t max_frags) { int i = skb_shinfo(skb)->nr_frags; if (skb_can_coalesce(skb, i, page, offset)) { skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], size); - } else if (i < MAX_SKB_FRAGS) { + } else if (i < max_frags) { skb_zcopy_downgrade_managed(skb); get_page(page); skb_fill_page_desc_noacc(skb, i, page, offset, size); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 61892268e8a6..52fc840898d8 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1450,7 +1450,8 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, if (len > size) len = size; - if (skb_append_pagefrags(skb, page, offset, len)) { + if (skb_append_pagefrags(skb, page, offset, len, + MAX_SKB_FRAGS)) { err = -EMSGSIZE; goto error; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index cc695c9f09ec..dd55506b4632 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2349,7 +2349,7 @@ alloc_skb: newskb = NULL; } - if (skb_append_pagefrags(skb, page, offset, size)) { + if (skb_append_pagefrags(skb, page, offset, size, MAX_SKB_FRAGS)) { tail = skb; goto alloc_skb; } -- cgit v1.2.3 From 2e910b95329c2dc7feffbec00907f9e02d1a850a Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:12 +0100 Subject: net: Add a function to splice pages into an skbuff for MSG_SPLICE_PAGES Add a function to handle MSG_SPLICE_PAGES being passed internally to sendmsg(). Pages are spliced into the given socket buffer if possible and copied in if not (e.g. they're slab pages or have a zero refcount). Signed-off-by: David Howells cc: David Ahern cc: Al Viro cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 3 ++ net/core/skbuff.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 15011408c47c..1b2ebf6113e0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -5097,5 +5097,8 @@ static inline void skb_mark_for_recycle(struct sk_buff *skb) #endif } +ssize_t skb_splice_from_iter(struct sk_buff *skb, struct iov_iter *iter, + ssize_t maxsize, gfp_t gfp); + #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7f53dcb26ad3..f4a5b51aed22 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -6892,3 +6892,91 @@ nodefer: __kfree_skb(skb); if (unlikely(kick) && !cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) smp_call_function_single_async(cpu, &sd->defer_csd); } + +static void skb_splice_csum_page(struct sk_buff *skb, struct page *page, + size_t offset, size_t len) +{ + const char *kaddr; + __wsum csum; + + kaddr = kmap_local_page(page); + csum = csum_partial(kaddr + offset, len, 0); + kunmap_local(kaddr); + skb->csum = csum_block_add(skb->csum, csum, skb->len); +} + +/** + * skb_splice_from_iter - Splice (or copy) pages to skbuff + * @skb: The buffer to add pages to + * @iter: Iterator representing the pages to be added + * @maxsize: Maximum amount of pages to be added + * @gfp: Allocation flags + * + * This is a common helper function for supporting MSG_SPLICE_PAGES. It + * extracts pages from an iterator and adds them to the socket buffer if + * possible, copying them to fragments if not possible (such as if they're slab + * pages). + * + * Returns the amount of data spliced/copied or -EMSGSIZE if there's + * insufficient space in the buffer to transfer anything. + */ +ssize_t skb_splice_from_iter(struct sk_buff *skb, struct iov_iter *iter, + ssize_t maxsize, gfp_t gfp) +{ + size_t frag_limit = READ_ONCE(sysctl_max_skb_frags); + struct page *pages[8], **ppages = pages; + ssize_t spliced = 0, ret = 0; + unsigned int i; + + while (iter->count > 0) { + ssize_t space, nr; + size_t off, len; + + ret = -EMSGSIZE; + space = frag_limit - skb_shinfo(skb)->nr_frags; + if (space < 0) + break; + + /* We might be able to coalesce without increasing nr_frags */ + nr = clamp_t(size_t, space, 1, ARRAY_SIZE(pages)); + + len = iov_iter_extract_pages(iter, &ppages, maxsize, nr, 0, &off); + if (len <= 0) { + ret = len ?: -EIO; + break; + } + + i = 0; + do { + struct page *page = pages[i++]; + size_t part = min_t(size_t, PAGE_SIZE - off, len); + + ret = -EIO; + if (WARN_ON_ONCE(!sendpage_ok(page))) + goto out; + + ret = skb_append_pagefrags(skb, page, off, part, + frag_limit); + if (ret < 0) { + iov_iter_revert(iter, len); + goto out; + } + + if (skb->ip_summed == CHECKSUM_NONE) + skb_splice_csum_page(skb, page, off, part); + + off = 0; + spliced += part; + maxsize -= part; + len -= part; + } while (len > 0); + + if (maxsize <= 0) + break; + } + +out: + skb_len_add(skb, spliced); + return spliced ?: ret; +} +EXPORT_SYMBOL(skb_splice_from_iter); -- cgit v1.2.3 From 270a1c3de47e49dd2fc18f48e46b101e48050e78 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:13 +0100 Subject: tcp: Support MSG_SPLICE_PAGES Make TCP's sendmsg() support MSG_SPLICE_PAGES. This causes pages to be spliced or copied (if it cannot be spliced) from the source iterator. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/ipv4/tcp.c | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 3d18e295bb2f..2d61150d01f1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1223,7 +1223,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) int flags, err, copied = 0; int mss_now = 0, size_goal, copied_syn = 0; int process_backlog = 0; - bool zc = false; + int zc = 0; long timeo; flags = msg->msg_flags; @@ -1231,7 +1231,8 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) if ((flags & MSG_ZEROCOPY) && size) { if (msg->msg_ubuf) { uarg = msg->msg_ubuf; - zc = sk->sk_route_caps & NETIF_F_SG; + if (sk->sk_route_caps & NETIF_F_SG) + zc = MSG_ZEROCOPY; } else if (sock_flag(sk, SOCK_ZEROCOPY)) { skb = tcp_write_queue_tail(sk); uarg = msg_zerocopy_realloc(sk, size, skb_zcopy(skb)); @@ -1239,10 +1240,14 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size) err = -ENOBUFS; goto out_err; } - zc = sk->sk_route_caps & NETIF_F_SG; - if (!zc) + if (sk->sk_route_caps & NETIF_F_SG) + zc = MSG_ZEROCOPY; + else uarg_to_msgzc(uarg)->zerocopy = 0; } + } else if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES) && size) { + if (sk->sk_route_caps & NETIF_F_SG) + zc = MSG_SPLICE_PAGES; } if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect) && @@ -1305,7 +1310,7 @@ restart: goto do_error; while (msg_data_left(msg)) { - int copy = 0; + ssize_t copy = 0; skb = tcp_write_queue_tail(sk); if (skb) @@ -1346,7 +1351,7 @@ new_segment: if (copy > msg_data_left(msg)) copy = msg_data_left(msg); - if (!zc) { + if (zc == 0) { bool merge = true; int i = skb_shinfo(skb)->nr_frags; struct page_frag *pfrag = sk_page_frag(sk); @@ -1391,7 +1396,7 @@ new_segment: page_ref_inc(pfrag->page); } pfrag->offset += copy; - } else { + } else if (zc == MSG_ZEROCOPY) { /* First append to a fragless skb builds initial * pure zerocopy skb */ @@ -1412,6 +1417,30 @@ new_segment: if (err < 0) goto do_error; copy = err; + } else if (zc == MSG_SPLICE_PAGES) { + /* Splice in data if we can; copy if we can't. */ + if (tcp_downgrade_zcopy_pure(sk, skb)) + goto wait_for_space; + copy = tcp_wmem_schedule(sk, copy); + if (!copy) + goto wait_for_space; + + err = skb_splice_from_iter(skb, &msg->msg_iter, copy, + sk->sk_allocation); + if (err < 0) { + if (err == -EMSGSIZE) { + tcp_mark_push(tp, skb); + goto new_segment; + } + goto do_error; + } + copy = err; + + if (!(flags & MSG_NO_SHARED_FRAGS)) + skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; + + sk_wmem_queued_add(sk, copy); + sk_mem_charge(sk, copy); } if (!copied) -- cgit v1.2.3 From c5c37af6ecad955acad82a440b812eb9cd73f77f Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:14 +0100 Subject: tcp: Convert do_tcp_sendpages() to use MSG_SPLICE_PAGES Convert do_tcp_sendpages() to use sendmsg() with MSG_SPLICE_PAGES rather than directly splicing in the pages itself. do_tcp_sendpages() can then be inlined in subsequent patches into its callers. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/ipv4/tcp.c | 158 +++------------------------------------------------------ 1 file changed, 7 insertions(+), 151 deletions(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 2d61150d01f1..f3a0c02678e0 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -974,163 +974,19 @@ static int tcp_wmem_schedule(struct sock *sk, int copy) return min(copy, sk->sk_forward_alloc); } -static struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags, - struct page *page, int offset, size_t *size) -{ - struct sk_buff *skb = tcp_write_queue_tail(sk); - struct tcp_sock *tp = tcp_sk(sk); - bool can_coalesce; - int copy, i; - - if (!skb || (copy = size_goal - skb->len) <= 0 || - !tcp_skb_can_collapse_to(skb)) { -new_segment: - if (!sk_stream_memory_free(sk)) - return NULL; - - skb = tcp_stream_alloc_skb(sk, 0, sk->sk_allocation, - tcp_rtx_and_write_queues_empty(sk)); - if (!skb) - return NULL; - -#ifdef CONFIG_TLS_DEVICE - skb->decrypted = !!(flags & MSG_SENDPAGE_DECRYPTED); -#endif - tcp_skb_entail(sk, skb); - copy = size_goal; - } - - if (copy > *size) - copy = *size; - - i = skb_shinfo(skb)->nr_frags; - can_coalesce = skb_can_coalesce(skb, i, page, offset); - if (!can_coalesce && i >= READ_ONCE(sysctl_max_skb_frags)) { - tcp_mark_push(tp, skb); - goto new_segment; - } - if (tcp_downgrade_zcopy_pure(sk, skb)) - return NULL; - - copy = tcp_wmem_schedule(sk, copy); - if (!copy) - return NULL; - - if (can_coalesce) { - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); - } else { - get_page(page); - skb_fill_page_desc_noacc(skb, i, page, offset, copy); - } - - if (!(flags & MSG_NO_SHARED_FRAGS)) - skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; - - skb->len += copy; - skb->data_len += copy; - skb->truesize += copy; - sk_wmem_queued_add(sk, copy); - sk_mem_charge(sk, copy); - WRITE_ONCE(tp->write_seq, tp->write_seq + copy); - TCP_SKB_CB(skb)->end_seq += copy; - tcp_skb_pcount_set(skb, 0); - - *size = copy; - return skb; -} - ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, size_t size, int flags) { - struct tcp_sock *tp = tcp_sk(sk); - int mss_now, size_goal; - int err; - ssize_t copied; - long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); - - if (IS_ENABLED(CONFIG_DEBUG_VM) && - WARN_ONCE(!sendpage_ok(page), - "page must not be a Slab one and have page_count > 0")) - return -EINVAL; - - /* Wait for a connection to finish. One exception is TCP Fast Open - * (passive side) where data is allowed to be sent before a connection - * is fully established. - */ - if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && - !tcp_passive_fastopen(sk)) { - err = sk_stream_wait_connect(sk, &timeo); - if (err != 0) - goto out_err; - } + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; - sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - mss_now = tcp_send_mss(sk, &size_goal, flags); - copied = 0; + if (flags & MSG_SENDPAGE_NOTLAST) + msg.msg_flags |= MSG_MORE; - err = -EPIPE; - if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) - goto out_err; - - while (size > 0) { - struct sk_buff *skb; - size_t copy = size; - - skb = tcp_build_frag(sk, size_goal, flags, page, offset, ©); - if (!skb) - goto wait_for_space; - - if (!copied) - TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; - - copied += copy; - offset += copy; - size -= copy; - if (!size) - goto out; - - if (skb->len < size_goal || (flags & MSG_OOB)) - continue; - - if (forced_push(tp)) { - tcp_mark_push(tp, skb); - __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_PUSH); - } else if (skb == tcp_send_head(sk)) - tcp_push_one(sk, mss_now); - continue; - -wait_for_space: - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - tcp_push(sk, flags & ~MSG_MORE, mss_now, - TCP_NAGLE_PUSH, size_goal); - - err = sk_stream_wait_memory(sk, &timeo); - if (err != 0) - goto do_error; - - mss_now = tcp_send_mss(sk, &size_goal, flags); - } - -out: - if (copied) { - tcp_tx_timestamp(sk, sk->sk_tsflags); - if (!(flags & MSG_SENDPAGE_NOTLAST)) - tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); - } - return copied; - -do_error: - tcp_remove_empty_skb(sk); - if (copied) - goto out; -out_err: - /* make sure we wake any epoll edge trigger waiter */ - if (unlikely(tcp_rtx_and_write_queues_empty(sk) && err == -EAGAIN)) { - sk->sk_write_space(sk); - tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); - } - return sk_stream_error(sk, flags, err); + return tcp_sendmsg_locked(sk, &msg, size); } EXPORT_SYMBOL_GPL(do_tcp_sendpages); -- cgit v1.2.3 From ebf2e8860eea66e2c4764316b80c6a5ee5f336ee Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:15 +0100 Subject: tcp_bpf: Inline do_tcp_sendpages as it's now a wrapper around tcp_sendmsg do_tcp_sendpages() is now just a small wrapper around tcp_sendmsg_locked(), so inline it. This is part of replacing ->sendpage() with a call to sendmsg() with MSG_SPLICE_PAGES set. Signed-off-by: David Howells cc: John Fastabend cc: Jakub Sitnicki cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_bpf.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index 2e9547467edb..0291d15acd19 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -72,11 +72,13 @@ static int tcp_bpf_push(struct sock *sk, struct sk_msg *msg, u32 apply_bytes, { bool apply = apply_bytes; struct scatterlist *sge; + struct msghdr msghdr = { .msg_flags = flags | MSG_SPLICE_PAGES, }; struct page *page; int size, ret = 0; u32 off; while (1) { + struct bio_vec bvec; bool has_tx_ulp; sge = sk_msg_elem(msg, msg->sg.start); @@ -88,16 +90,18 @@ static int tcp_bpf_push(struct sock *sk, struct sk_msg *msg, u32 apply_bytes, tcp_rate_check_app_limited(sk); retry: has_tx_ulp = tls_sw_has_ctx_tx(sk); - if (has_tx_ulp) { - flags |= MSG_SENDPAGE_NOPOLICY; - ret = kernel_sendpage_locked(sk, - page, off, size, flags); - } else { - ret = do_tcp_sendpages(sk, page, off, size, flags); - } + if (has_tx_ulp) + msghdr.msg_flags |= MSG_SENDPAGE_NOPOLICY; + if (flags & MSG_SENDPAGE_NOTLAST) + msghdr.msg_flags |= MSG_MORE; + + bvec_set_page(&bvec, page, size, off); + iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, size); + ret = tcp_sendmsg_locked(sk, &msghdr, size); if (ret <= 0) return ret; + if (apply) apply_bytes -= ret; msg->sg.size -= ret; @@ -404,7 +408,7 @@ static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) long timeo; int flags; - /* Don't let internal do_tcp_sendpages() flags through */ + /* Don't let internal sendpage flags through */ flags = (msg->msg_flags & ~MSG_SENDPAGE_DECRYPTED); flags |= MSG_NO_SHARED_FRAGS; -- cgit v1.2.3 From 7f8816ab4bae9dd42c5720fdad4b102532d4e43a Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:16 +0100 Subject: espintcp: Inline do_tcp_sendpages() do_tcp_sendpages() is now just a small wrapper around tcp_sendmsg_locked(), so inline it, allowing do_tcp_sendpages() to be removed. This is part of replacing ->sendpage() with a call to sendmsg() with MSG_SPLICE_PAGES set. Signed-off-by: David Howells cc: Steffen Klassert cc: Herbert Xu cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/xfrm/espintcp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/xfrm/espintcp.c b/net/xfrm/espintcp.c index 872b80188e83..3504925babdb 100644 --- a/net/xfrm/espintcp.c +++ b/net/xfrm/espintcp.c @@ -205,14 +205,16 @@ static int espintcp_sendskb_locked(struct sock *sk, struct espintcp_msg *emsg, static int espintcp_sendskmsg_locked(struct sock *sk, struct espintcp_msg *emsg, int flags) { + struct msghdr msghdr = { .msg_flags = flags | MSG_SPLICE_PAGES, }; struct sk_msg *skmsg = &emsg->skmsg; struct scatterlist *sg; int done = 0; int ret; - flags |= MSG_SENDPAGE_NOTLAST; + msghdr.msg_flags |= MSG_SENDPAGE_NOTLAST; sg = &skmsg->sg.data[skmsg->sg.start]; do { + struct bio_vec bvec; size_t size = sg->length - emsg->offset; int offset = sg->offset + emsg->offset; struct page *p; @@ -220,11 +222,13 @@ static int espintcp_sendskmsg_locked(struct sock *sk, emsg->offset = 0; if (sg_is_last(sg)) - flags &= ~MSG_SENDPAGE_NOTLAST; + msghdr.msg_flags &= ~MSG_SENDPAGE_NOTLAST; p = sg_page(sg); retry: - ret = do_tcp_sendpages(sk, p, offset, size, flags); + bvec_set_page(&bvec, p, size, offset); + iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, size); + ret = tcp_sendmsg_locked(sk, &msghdr, size); if (ret < 0) { emsg->offset = offset - sg->offset; skmsg->sg.start += done; -- cgit v1.2.3 From e117dcfd646e84a50999a395df3d724feb28b173 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:17 +0100 Subject: tls: Inline do_tcp_sendpages() do_tcp_sendpages() is now just a small wrapper around tcp_sendmsg_locked(), so inline it, allowing do_tcp_sendpages() to be removed. This is part of replacing ->sendpage() with a call to sendmsg() with MSG_SPLICE_PAGES set. Signed-off-by: David Howells cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/net/tls.h | 2 +- net/tls/tls_main.c | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index 6056ce5a2aa5..5791ca7a189c 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -258,7 +258,7 @@ struct tls_context { struct scatterlist *partially_sent_record; u16 partially_sent_offset; - bool in_tcp_sendpages; + bool splicing_pages; bool pending_open_record_frags; struct mutex tx_lock; /* protects partially_sent_* fields and diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index f2e7302a4d96..3d45fdb5c4e9 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -125,7 +125,10 @@ int tls_push_sg(struct sock *sk, u16 first_offset, int flags) { - int sendpage_flags = flags | MSG_SENDPAGE_NOTLAST; + struct bio_vec bvec; + struct msghdr msg = { + .msg_flags = MSG_SENDPAGE_NOTLAST | MSG_SPLICE_PAGES | flags, + }; int ret = 0; struct page *p; size_t size; @@ -134,16 +137,19 @@ int tls_push_sg(struct sock *sk, size = sg->length - offset; offset += sg->offset; - ctx->in_tcp_sendpages = true; + ctx->splicing_pages = true; while (1) { if (sg_is_last(sg)) - sendpage_flags = flags; + msg.msg_flags = flags; /* is sending application-limited? */ tcp_rate_check_app_limited(sk); p = sg_page(sg); retry: - ret = do_tcp_sendpages(sk, p, offset, size, sendpage_flags); + bvec_set_page(&bvec, p, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + + ret = tcp_sendmsg_locked(sk, &msg, size); if (ret != size) { if (ret > 0) { @@ -155,7 +161,7 @@ retry: offset -= sg->offset; ctx->partially_sent_offset = offset; ctx->partially_sent_record = (void *)sg; - ctx->in_tcp_sendpages = false; + ctx->splicing_pages = false; return ret; } @@ -169,7 +175,7 @@ retry: size = sg->length; } - ctx->in_tcp_sendpages = false; + ctx->splicing_pages = false; return 0; } @@ -247,11 +253,11 @@ static void tls_write_space(struct sock *sk) { struct tls_context *ctx = tls_get_ctx(sk); - /* If in_tcp_sendpages call lower protocol write space handler + /* If splicing_pages call lower protocol write space handler * to ensure we wake up any waiting operations there. For example - * if do_tcp_sendpages where to call sk_wait_event. + * if splicing pages where to call sk_wait_event. */ - if (ctx->in_tcp_sendpages) { + if (ctx->splicing_pages) { ctx->sk_write_space(sk); return; } -- cgit v1.2.3 From c2ff29e99a764769eb2ce3a1a5585013633ee9a6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:18 +0100 Subject: siw: Inline do_tcp_sendpages() do_tcp_sendpages() is now just a small wrapper around tcp_sendmsg_locked(), so inline it, allowing do_tcp_sendpages() to be removed. This is part of replacing ->sendpage() with a call to sendmsg() with MSG_SPLICE_PAGES set. Signed-off-by: David Howells Reviewed-by: Bernard Metzler Reviewed-by: Tom Talpey cc: Jason Gunthorpe cc: Leon Romanovsky cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- drivers/infiniband/sw/siw/siw_qp_tx.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index 4b292e0504f1..ffb16beb6c30 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -312,7 +312,7 @@ static int siw_tx_ctrl(struct siw_iwarp_tx *c_tx, struct socket *s, } /* - * 0copy TCP transmit interface: Use do_tcp_sendpages. + * 0copy TCP transmit interface: Use MSG_SPLICE_PAGES. * * Using sendpage to push page by page appears to be less efficient * than using sendmsg, even if data are copied. @@ -323,20 +323,27 @@ static int siw_tx_ctrl(struct siw_iwarp_tx *c_tx, struct socket *s, static int siw_tcp_sendpages(struct socket *s, struct page **page, int offset, size_t size) { + struct bio_vec bvec; + struct msghdr msg = { + .msg_flags = (MSG_MORE | MSG_DONTWAIT | MSG_SENDPAGE_NOTLAST | + MSG_SPLICE_PAGES), + }; struct sock *sk = s->sk; - int i = 0, rv = 0, sent = 0, - flags = MSG_MORE | MSG_DONTWAIT | MSG_SENDPAGE_NOTLAST; + int i = 0, rv = 0, sent = 0; while (size) { size_t bytes = min_t(size_t, PAGE_SIZE - offset, size); if (size + offset <= PAGE_SIZE) - flags = MSG_MORE | MSG_DONTWAIT; + msg.msg_flags &= ~MSG_SENDPAGE_NOTLAST; tcp_rate_check_app_limited(sk); + bvec_set_page(&bvec, page[i], bytes, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + try_page_again: lock_sock(sk); - rv = do_tcp_sendpages(sk, page[i], offset, bytes, flags); + rv = tcp_sendmsg_locked(sk, &msg, size); release_sock(sk); if (rv > 0) { -- cgit v1.2.3 From 5367f9bbb86a9fa377f8cfc673d9b8a446f3e917 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:19 +0100 Subject: tcp: Fold do_tcp_sendpages() into tcp_sendpage_locked() Fold do_tcp_sendpages() into its last remaining caller, tcp_sendpage_locked(). Signed-off-by: David Howells cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/net/tcp.h | 2 -- net/ipv4/tcp.c | 21 +++++++-------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 04a31643cda3..02a6cff1827e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -333,8 +333,6 @@ int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags); int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, size_t size, int flags); -ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, - size_t size, int flags); int tcp_send_mss(struct sock *sk, int *size_goal, int flags); void tcp_push(struct sock *sk, int flags, int mss_now, int nonagle, int size_goal); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f3a0c02678e0..e9506cebecce 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -974,12 +974,17 @@ static int tcp_wmem_schedule(struct sock *sk, int copy) return min(copy, sk->sk_forward_alloc); } -ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, - size_t size, int flags) +int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, + size_t size, int flags) { struct bio_vec bvec; struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; + if (!(sk->sk_route_caps & NETIF_F_SG)) + return sock_no_sendpage_locked(sk, page, offset, size, flags); + + tcp_rate_check_app_limited(sk); /* is sending application-limited? */ + bvec_set_page(&bvec, page, size, offset); iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); @@ -988,18 +993,6 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, return tcp_sendmsg_locked(sk, &msg, size); } -EXPORT_SYMBOL_GPL(do_tcp_sendpages); - -int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - if (!(sk->sk_route_caps & NETIF_F_SG)) - return sock_no_sendpage_locked(sk, page, offset, size, flags); - - tcp_rate_check_app_limited(sk); /* is sending application-limited? */ - - return do_tcp_sendpages(sk, page, offset, size, flags); -} EXPORT_SYMBOL_GPL(tcp_sendpage_locked); int tcp_sendpage(struct sock *sk, struct page *page, int offset, -- cgit v1.2.3 From 7da0dde68486b2d5bd7c689a9b327b77efecdfd0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:20 +0100 Subject: ip, udp: Support MSG_SPLICE_PAGES Make IP/UDP sendmsg() support MSG_SPLICE_PAGES. This causes pages to be spliced from the source iterator. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Willem de Bruijn cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/ipv4/ip_output.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 52fc840898d8..c7db973b5d29 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1048,6 +1048,14 @@ static int __ip_append_data(struct sock *sk, skb_zcopy_set(skb, uarg, &extra_uref); } } + } else if ((flags & MSG_SPLICE_PAGES) && length) { + if (inet->hdrincl) + return -EPERM; + if (rt->dst.dev->features & NETIF_F_SG) + /* We need an empty buffer to attach stuff to */ + paged = true; + else + flags &= ~MSG_SPLICE_PAGES; } cork->length += length; @@ -1207,6 +1215,15 @@ alloc_new_skb: err = -EFAULT; goto error; } + } else if (flags & MSG_SPLICE_PAGES) { + struct msghdr *msg = from; + + err = skb_splice_from_iter(skb, &msg->msg_iter, copy, + sk->sk_allocation); + if (err < 0) + goto error; + copy = err; + wmem_alloc_delta += copy; } else if (!zc) { int i = skb_shinfo(skb)->nr_frags; -- cgit v1.2.3 From 6d8192bd69bb431ef6b2558be3b5746b706cd252 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:21 +0100 Subject: ip6, udp6: Support MSG_SPLICE_PAGES Make IP6/UDP6 sendmsg() support MSG_SPLICE_PAGES. This causes pages to be spliced from the source iterator if possible, copying the data if not. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Willem de Bruijn cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/ipv6/ip6_output.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9554cf46ed88..c722cb881b2d 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1589,6 +1589,14 @@ emsgsize: skb_zcopy_set(skb, uarg, &extra_uref); } } + } else if ((flags & MSG_SPLICE_PAGES) && length) { + if (inet_sk(sk)->hdrincl) + return -EPERM; + if (rt->dst.dev->features & NETIF_F_SG) + /* We need an empty buffer to attach stuff to */ + paged = true; + else + flags &= ~MSG_SPLICE_PAGES; } /* @@ -1778,6 +1786,15 @@ alloc_new_skb: err = -EFAULT; goto error; } + } else if (flags & MSG_SPLICE_PAGES) { + struct msghdr *msg = from; + + err = skb_splice_from_iter(skb, &msg->msg_iter, copy, + sk->sk_allocation); + if (err < 0) + goto error; + copy = err; + wmem_alloc_delta += copy; } else if (!zc) { int i = skb_shinfo(skb)->nr_frags; -- cgit v1.2.3 From 7ac7c987850c3ec617c778f7bd871804dc1c648d Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:22 +0100 Subject: udp: Convert udp_sendpage() to use MSG_SPLICE_PAGES Convert udp_sendpage() to use sendmsg() with MSG_SPLICE_PAGES rather than directly splicing in the pages itself. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Willem de Bruijn cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/ipv4/udp.c | 51 ++++++--------------------------------------------- 1 file changed, 6 insertions(+), 45 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index aa32afd871ee..2879dc6d66ea 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1332,54 +1332,15 @@ EXPORT_SYMBOL(udp_sendmsg); int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { - struct inet_sock *inet = inet_sk(sk); - struct udp_sock *up = udp_sk(sk); - int ret; + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES }; if (flags & MSG_SENDPAGE_NOTLAST) - flags |= MSG_MORE; - - if (!up->pending) { - struct msghdr msg = { .msg_flags = flags|MSG_MORE }; - - /* Call udp_sendmsg to specify destination address which - * sendpage interface can't pass. - * This will succeed only when the socket is connected. - */ - ret = udp_sendmsg(sk, &msg, 0); - if (ret < 0) - return ret; - } - - lock_sock(sk); + msg.msg_flags |= MSG_MORE; - if (unlikely(!up->pending)) { - release_sock(sk); - - net_dbg_ratelimited("cork failed\n"); - return -EINVAL; - } - - ret = ip_append_page(sk, &inet->cork.fl.u.ip4, - page, offset, size, flags); - if (ret == -EOPNOTSUPP) { - release_sock(sk); - return sock_no_sendpage(sk->sk_socket, page, offset, - size, flags); - } - if (ret < 0) { - udp_flush_pending_frames(sk); - goto out; - } - - up->len += size; - if (!(READ_ONCE(up->corkflag) || (flags&MSG_MORE))) - ret = udp_push_pending_frames(sk); - if (!ret) - ret = size; -out: - release_sock(sk); - return ret; + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + return udp_sendmsg(sk, &msg, size); } #define UDP_SKB_IS_STATELESS 0x80000000 -- cgit v1.2.3 From c49cf26632910581ee1173d75c0fca322ccaf4bb Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:23 +0100 Subject: ip: Remove ip_append_page() ip_append_page() is no longer used with the removal of udp_sendpage(), so remove it. Signed-off-by: David Howells cc: Willem de Bruijn cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/net/ip.h | 2 - net/ipv4/ip_output.c | 148 ++------------------------------------------------- 2 files changed, 4 insertions(+), 146 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index c3fffaa92d6e..7627a4df893b 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -220,8 +220,6 @@ int ip_append_data(struct sock *sk, struct flowi4 *fl4, unsigned int flags); int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb); -ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - int offset, size_t size, int flags); struct sk_buff *__ip_make_skb(struct sock *sk, struct flowi4 *fl4, struct sk_buff_head *queue, struct inet_cork *cork); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index c7db973b5d29..553c740a6bfb 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -946,17 +946,6 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk } EXPORT_SYMBOL(ip_generic_getfrag); -static inline __wsum -csum_page(struct page *page, int offset, int copy) -{ - char *kaddr; - __wsum csum; - kaddr = kmap(page); - csum = csum_partial(kaddr + offset, copy, 0); - kunmap(page); - return csum; -} - static int __ip_append_data(struct sock *sk, struct flowi4 *fl4, struct sk_buff_head *queue, @@ -1327,10 +1316,10 @@ static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, } /* - * ip_append_data() and ip_append_page() can make one large IP datagram - * from many pieces of data. Each pieces will be holded on the socket - * until ip_push_pending_frames() is called. Each piece can be a page - * or non-page data. + * ip_append_data() can make one large IP datagram from many pieces of + * data. Each piece will be held on the socket until + * ip_push_pending_frames() is called. Each piece can be a page or + * non-page data. * * Not only UDP, other transport protocols - e.g. raw sockets - can use * this interface potentially. @@ -1363,135 +1352,6 @@ int ip_append_data(struct sock *sk, struct flowi4 *fl4, from, length, transhdrlen, flags); } -ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - int offset, size_t size, int flags) -{ - struct inet_sock *inet = inet_sk(sk); - struct sk_buff *skb; - struct rtable *rt; - struct ip_options *opt = NULL; - struct inet_cork *cork; - int hh_len; - int mtu; - int len; - int err; - unsigned int maxfraglen, fragheaderlen, fraggap, maxnonfragsize; - - if (inet->hdrincl) - return -EPERM; - - if (flags&MSG_PROBE) - return 0; - - if (skb_queue_empty(&sk->sk_write_queue)) - return -EINVAL; - - cork = &inet->cork.base; - rt = (struct rtable *)cork->dst; - if (cork->flags & IPCORK_OPT) - opt = cork->opt; - - if (!(rt->dst.dev->features & NETIF_F_SG)) - return -EOPNOTSUPP; - - hh_len = LL_RESERVED_SPACE(rt->dst.dev); - mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize; - - fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); - maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; - maxnonfragsize = ip_sk_ignore_df(sk) ? 0xFFFF : mtu; - - if (cork->length + size > maxnonfragsize - fragheaderlen) { - ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, - mtu - (opt ? opt->optlen : 0)); - return -EMSGSIZE; - } - - skb = skb_peek_tail(&sk->sk_write_queue); - if (!skb) - return -EINVAL; - - cork->length += size; - - while (size > 0) { - /* Check if the remaining data fits into current packet. */ - len = mtu - skb->len; - if (len < size) - len = maxfraglen - skb->len; - - if (len <= 0) { - struct sk_buff *skb_prev; - int alloclen; - - skb_prev = skb; - fraggap = skb_prev->len - maxfraglen; - - alloclen = fragheaderlen + hh_len + fraggap + 15; - skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation); - if (unlikely(!skb)) { - err = -ENOBUFS; - goto error; - } - - /* - * Fill in the control structures - */ - skb->ip_summed = CHECKSUM_NONE; - skb->csum = 0; - skb_reserve(skb, hh_len); - - /* - * Find where to start putting bytes. - */ - skb_put(skb, fragheaderlen + fraggap); - skb_reset_network_header(skb); - skb->transport_header = (skb->network_header + - fragheaderlen); - if (fraggap) { - skb->csum = skb_copy_and_csum_bits(skb_prev, - maxfraglen, - skb_transport_header(skb), - fraggap); - skb_prev->csum = csum_sub(skb_prev->csum, - skb->csum); - pskb_trim_unique(skb_prev, maxfraglen); - } - - /* - * Put the packet on the pending queue. - */ - __skb_queue_tail(&sk->sk_write_queue, skb); - continue; - } - - if (len > size) - len = size; - - if (skb_append_pagefrags(skb, page, offset, len, - MAX_SKB_FRAGS)) { - err = -EMSGSIZE; - goto error; - } - - if (skb->ip_summed == CHECKSUM_NONE) { - __wsum csum; - csum = csum_page(page, offset, len); - skb->csum = csum_block_add(skb->csum, csum, skb->len); - } - - skb_len_add(skb, len); - refcount_add(len, &sk->sk_wmem_alloc); - offset += len; - size -= len; - } - return 0; - -error: - cork->length -= size; - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); - return err; -} - static void ip_cork_release(struct inet_cork *cork) { cork->flags &= ~IPCORK_OPT; -- cgit v1.2.3 From a0dbf5f818f9082d2262c1f8a8c0aab68364341f Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:24 +0100 Subject: af_unix: Support MSG_SPLICE_PAGES Make AF_UNIX sendmsg() support MSG_SPLICE_PAGES, splicing in pages from the source iterator if possible and copying the data in otherwise. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Kuniyuki Iwashima cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/unix/af_unix.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index dd55506b4632..976bc1c5e11b 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2200,19 +2200,25 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, while (sent < len) { size = len - sent; - /* Keep two messages in the pipe so it schedules better */ - size = min_t(int, size, (sk->sk_sndbuf >> 1) - 64); + if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) { + skb = sock_alloc_send_pskb(sk, 0, 0, + msg->msg_flags & MSG_DONTWAIT, + &err, 0); + } else { + /* Keep two messages in the pipe so it schedules better */ + size = min_t(int, size, (sk->sk_sndbuf >> 1) - 64); - /* allow fallback to order-0 allocations */ - size = min_t(int, size, SKB_MAX_HEAD(0) + UNIX_SKB_FRAGS_SZ); + /* allow fallback to order-0 allocations */ + size = min_t(int, size, SKB_MAX_HEAD(0) + UNIX_SKB_FRAGS_SZ); - data_len = max_t(int, 0, size - SKB_MAX_HEAD(0)); + data_len = max_t(int, 0, size - SKB_MAX_HEAD(0)); - data_len = min_t(size_t, size, PAGE_ALIGN(data_len)); + data_len = min_t(size_t, size, PAGE_ALIGN(data_len)); - skb = sock_alloc_send_pskb(sk, size - data_len, data_len, - msg->msg_flags & MSG_DONTWAIT, &err, - get_order(UNIX_SKB_FRAGS_SZ)); + skb = sock_alloc_send_pskb(sk, size - data_len, data_len, + msg->msg_flags & MSG_DONTWAIT, &err, + get_order(UNIX_SKB_FRAGS_SZ)); + } if (!skb) goto out_err; @@ -2224,13 +2230,24 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, } fds_sent = true; - skb_put(skb, size - data_len); - skb->data_len = data_len; - skb->len = size; - err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); - if (err) { - kfree_skb(skb); - goto out_err; + if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) { + err = skb_splice_from_iter(skb, &msg->msg_iter, size, + sk->sk_allocation); + if (err < 0) { + kfree_skb(skb); + goto out_err; + } + size = err; + refcount_add(size, &sk->sk_wmem_alloc); + } else { + skb_put(skb, size - data_len); + skb->data_len = data_len; + skb->len = size; + err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); + if (err) { + kfree_skb(skb); + goto out_err; + } } unix_state_lock(other); -- cgit v1.2.3 From 57d44a354a43edba4ef9963327d4657d12edbfbc Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 22 May 2023 13:11:25 +0100 Subject: unix: Convert unix_stream_sendpage() to use MSG_SPLICE_PAGES Convert unix_stream_sendpage() to use sendmsg() with MSG_SPLICE_PAGES rather than directly splicing in the pages itself. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Kuniyuki Iwashima cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/unix/af_unix.c | 134 +++-------------------------------------------------- 1 file changed, 7 insertions(+), 127 deletions(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 976bc1c5e11b..115436ce1f8a 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1839,24 +1839,6 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock, } } -static int maybe_init_creds(struct scm_cookie *scm, - struct socket *socket, - const struct sock *other) -{ - int err; - struct msghdr msg = { .msg_controllen = 0 }; - - err = scm_send(socket, &msg, scm, false); - if (err) - return err; - - if (unix_passcred_enabled(socket, other)) { - scm->pid = get_pid(task_tgid(current)); - current_uid_gid(&scm->creds.uid, &scm->creds.gid); - } - return err; -} - static bool unix_skb_scm_eq(struct sk_buff *skb, struct scm_cookie *scm) { @@ -2292,117 +2274,15 @@ out_err: static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page, int offset, size_t size, int flags) { - int err; - bool send_sigpipe = false; - bool init_scm = true; - struct scm_cookie scm; - struct sock *other, *sk = socket->sk; - struct sk_buff *skb, *newskb = NULL, *tail = NULL; - - if (flags & MSG_OOB) - return -EOPNOTSUPP; + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES }; - other = unix_peer(sk); - if (!other || sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; - - if (false) { -alloc_skb: - unix_state_unlock(other); - mutex_unlock(&unix_sk(other)->iolock); - newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT, - &err, 0); - if (!newskb) - goto err; - } - - /* we must acquire iolock as we modify already present - * skbs in the sk_receive_queue and mess with skb->len - */ - err = mutex_lock_interruptible(&unix_sk(other)->iolock); - if (err) { - err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS; - goto err; - } - - if (sk->sk_shutdown & SEND_SHUTDOWN) { - err = -EPIPE; - send_sigpipe = true; - goto err_unlock; - } - - unix_state_lock(other); + if (flags & MSG_SENDPAGE_NOTLAST) + msg.msg_flags |= MSG_MORE; - if (sock_flag(other, SOCK_DEAD) || - other->sk_shutdown & RCV_SHUTDOWN) { - err = -EPIPE; - send_sigpipe = true; - goto err_state_unlock; - } - - if (init_scm) { - err = maybe_init_creds(&scm, socket, other); - if (err) - goto err_state_unlock; - init_scm = false; - } - - skb = skb_peek_tail(&other->sk_receive_queue); - if (tail && tail == skb) { - skb = newskb; - } else if (!skb || !unix_skb_scm_eq(skb, &scm)) { - if (newskb) { - skb = newskb; - } else { - tail = skb; - goto alloc_skb; - } - } else if (newskb) { - /* this is fast path, we don't necessarily need to - * call to kfree_skb even though with newskb == NULL - * this - does no harm - */ - consume_skb(newskb); - newskb = NULL; - } - - if (skb_append_pagefrags(skb, page, offset, size, MAX_SKB_FRAGS)) { - tail = skb; - goto alloc_skb; - } - - skb->len += size; - skb->data_len += size; - skb->truesize += size; - refcount_add(size, &sk->sk_wmem_alloc); - - if (newskb) { - err = unix_scm_to_skb(&scm, skb, false); - if (err) - goto err_state_unlock; - spin_lock(&other->sk_receive_queue.lock); - __skb_queue_tail(&other->sk_receive_queue, newskb); - spin_unlock(&other->sk_receive_queue.lock); - } - - unix_state_unlock(other); - mutex_unlock(&unix_sk(other)->iolock); - - other->sk_data_ready(other); - scm_destroy(&scm); - return size; - -err_state_unlock: - unix_state_unlock(other); -err_unlock: - mutex_unlock(&unix_sk(other)->iolock); -err: - kfree_skb(newskb); - if (send_sigpipe && !(flags & MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 0); - if (!init_scm) - scm_destroy(&scm); - return err; + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + return unix_stream_sendmsg(socket, &msg, size); } static int unix_seqpacket_sendmsg(struct socket *sock, struct msghdr *msg, -- cgit v1.2.3 From a695641c8eaac268ad7e373c7e33c00b88b2bcbf Mon Sep 17 00:00:00 2001 From: Coco Li Date: Mon, 22 May 2023 13:15:52 -0700 Subject: gve: Support IPv6 Big TCP on DQ Add support for using IPv6 Big TCP on DQ which can handle large TSO/GRO packets. See https://lwn.net/Articles/895398/. This can improve the throughput and CPU usage. Perf test result: ip -d link show $DEV gso_max_size 185000 gso_max_segs 65535 tso_max_size 262143 tso_max_segs 65535 gro_max_size 185000 For performance, tested with neper using 9k MTU on hardware that supports 200Gb/s line rate. In single streams when line rate is not saturated, we expect throughput improvements. When the networking is performing at line rate, we expect cpu usage improvements. Tcp_stream (unidirectional stream test, T=thread, F=flow): skb=180kb, T=1, F=1, no zerocopy: throughput average=64576.88 Mb/s, sender stime=8.3, receiver stime=10.68 skb=64kb, T=1, F=1, no zerocopy: throughput average=64862.54 Mb/s, sender stime=9.96, receiver stime=12.67 skb=180kb, T=1, F=1, yes zerocopy: throughput average=146604.97 Mb/s, sender stime=10.61, receiver stime=5.52 skb=64kb, T=1, F=1, yes zerocopy: throughput average=131357.78 Mb/s, sender stime=12.11, receiver stime=12.25 skb=180kb, T=20, F=100, no zerocopy: throughput average=182411.37 Mb/s, sender stime=41.62, receiver stime=79.4 skb=64kb, T=20, F=100, no zerocopy: throughput average=182892.02 Mb/s, sender stime=57.39, receiver stime=72.69 skb=180kb, T=20, F=100, yes zerocopy: throughput average=182337.65 Mb/s, sender stime=27.94, receiver stime=39.7 skb=64kb, T=20, F=100, yes zerocopy: throughput average=182144.20 Mb/s, sender stime=47.06, receiver stime=39.01 Signed-off-by: Ziwei Xiao Signed-off-by: Coco Li Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230522201552.3585421-1-ziweixiao@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_main.c | 5 +++++ drivers/net/ethernet/google/gve/gve_tx_dqo.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index caa00c72aeeb..8fb70db63b8b 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -31,6 +31,7 @@ // Minimum amount of time between queue kicks in msec (10 seconds) #define MIN_TX_TIMEOUT_GAP (1000 * 10) +#define DQO_TX_MAX 0x3FFFF const char gve_version_str[] = GVE_VERSION; static const char gve_version_prefix[] = GVE_VERSION_PREFIX; @@ -2047,6 +2048,10 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device) goto err; } + /* Big TCP is only supported on DQ*/ + if (!gve_is_gqi(priv)) + netif_set_tso_max_size(priv->dev, DQO_TX_MAX); + priv->num_registered_pages = 0; priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK; /* gvnic has one Notification Block per MSI-x vector, except for the diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c index b76143bfd594..3c09e66ba1ab 100644 --- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c @@ -8,6 +8,7 @@ #include "gve_adminq.h" #include "gve_utils.h" #include "gve_dqo.h" +#include #include #include #include @@ -646,6 +647,9 @@ static int gve_try_tx_skb(struct gve_priv *priv, struct gve_tx_ring *tx, goto drop; } + if (unlikely(ipv6_hopopt_jumbo_remove(skb))) + goto drop; + num_buffer_descs = gve_num_buffer_descs_needed(skb); } else { num_buffer_descs = gve_num_buffer_descs_needed(skb); -- cgit v1.2.3 From 726de790f66029a7654b3e748f8d3e7888a30ae5 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 22 May 2023 16:37:57 +0200 Subject: ping: Stop using RTO_ONLINK. Define a new helper to figure out the correct route scope to use on TX, depending on socket configuration, ancillary data and send flags. Use this new helper to properly initialise the scope in flowi4_init_output(), instead of overriding tos with the RTO_ONLINK flag. The objective is to eventually remove RTO_ONLINK, which will allow converting .flowi4_tos to dscp_t. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip.h | 13 +++++++++++++ net/ipv4/ping.c | 15 +++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 7627a4df893b..f1cb28d649e4 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -240,6 +240,19 @@ static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4) return __ip_make_skb(sk, fl4, &sk->sk_write_queue, &inet_sk(sk)->cork.base); } +/* Get the route scope that should be used when sending a packet. */ +static inline u8 ip_sendmsg_scope(const struct inet_sock *inet, + const struct ipcm_cookie *ipc, + const struct msghdr *msg) +{ + if (sock_flag(&inet->sk, SOCK_LOCALROUTE) || + msg->msg_flags & MSG_DONTROUTE || + (ipc->opt && ipc->opt->opt.is_strictroute)) + return RT_SCOPE_LINK; + + return RT_SCOPE_UNIVERSE; +} + static inline __u8 get_rttos(struct ipcm_cookie* ipc, struct inet_sock *inet) { return (ipc->tos != -1) ? RT_TOS(ipc->tos) : RT_TOS(inet->tos); diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 3793c81bda8a..25dd78cee179 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -705,7 +705,7 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) struct ip_options_data opt_copy; int free = 0; __be32 saddr, daddr, faddr; - u8 tos; + u8 tos, scope; int err; pr_debug("ping_v4_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num); @@ -769,11 +769,7 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) faddr = ipc.opt->opt.faddr; } tos = get_rttos(&ipc, inet); - if (sock_flag(sk, SOCK_LOCALROUTE) || - (msg->msg_flags & MSG_DONTROUTE) || - (ipc.opt && ipc.opt->opt.is_strictroute)) { - tos |= RTO_ONLINK; - } + scope = ip_sendmsg_scope(inet, &ipc, msg); if (ipv4_is_multicast(daddr)) { if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) @@ -783,10 +779,9 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) } else if (!ipc.oif) ipc.oif = inet->uc_index; - flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, - RT_SCOPE_UNIVERSE, sk->sk_protocol, - inet_sk_flowi_flags(sk), faddr, saddr, 0, 0, - sk->sk_uid); + flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, scope, + sk->sk_protocol, inet_sk_flowi_flags(sk), faddr, + saddr, 0, 0, sk->sk_uid); fl4.fl4_icmp_type = user_icmph.type; fl4.fl4_icmp_code = user_icmph.code; -- cgit v1.2.3 From c85be08fc4fa44f07167be0377ebaa8d36b1dd58 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 22 May 2023 16:38:02 +0200 Subject: raw: Stop using RTO_ONLINK. Use ip_sendmsg_scope() to properly initialise the scope in flowi4_init_output(), instead of overriding tos with the RTO_ONLINK flag. The objective is to eventually remove RTO_ONLINK, which will allow converting .flowi4_tos to dscp_t. The MSG_DONTROUTE and SOCK_LOCALROUTE cases were already handled by raw_sendmsg() (SOCK_LOCALROUTE was handled by the RT_CONN_FLAGS*() macros called by get_rtconn_flags()). However, opt.is_strictroute wasn't taken into account. Therefore, a side effect of this patch is to now honour opt.is_strictroute, and thus align raw_sendmsg() with ping_v4_sendmsg() and udp_sendmsg(). Since raw_sendmsg() was the only user of get_rtconn_flags(), we can now remove this function. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip.h | 5 ----- net/ipv4/raw.c | 10 ++++------ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index f1cb28d649e4..8a3860a916dc 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -258,11 +258,6 @@ static inline __u8 get_rttos(struct ipcm_cookie* ipc, struct inet_sock *inet) return (ipc->tos != -1) ? RT_TOS(ipc->tos) : RT_TOS(inet->tos); } -static inline __u8 get_rtconn_flags(struct ipcm_cookie* ipc, struct sock* sk) -{ - return (ipc->tos != -1) ? RT_CONN_FLAGS_TOS(sk, ipc->tos) : RT_CONN_FLAGS(sk); -} - /* datagram.c */ int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index ff712bf2a98d..8b7b5c842bdd 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -476,10 +476,10 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) struct ipcm_cookie ipc; struct rtable *rt = NULL; struct flowi4 fl4; + u8 tos, scope; int free = 0; __be32 daddr; __be32 saddr; - u8 tos; int err; struct ip_options_data opt_copy; struct raw_frag_vec rfv; @@ -572,9 +572,8 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) daddr = ipc.opt->opt.faddr; } } - tos = get_rtconn_flags(&ipc, sk); - if (msg->msg_flags & MSG_DONTROUTE) - tos |= RTO_ONLINK; + tos = get_rttos(&ipc, inet); + scope = ip_sendmsg_scope(inet, &ipc, msg); if (ipv4_is_multicast(daddr)) { if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) @@ -597,8 +596,7 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) } } - flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, - RT_SCOPE_UNIVERSE, + flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, scope, hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk) | (hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), -- cgit v1.2.3 From 0e26371db548834052a8f0c3e138c5ff07e253a0 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 22 May 2023 16:38:07 +0200 Subject: udp: Stop using RTO_ONLINK. Use ip_sendmsg_scope() to properly initialise the scope in flowi4_init_output(), instead of overriding tos with the RTO_ONLINK flag. The objective is to eventually remove RTO_ONLINK, which will allow converting .flowi4_tos to dscp_t. Now that the scope is determined by ip_sendmsg_scope(), we need to check its result to set the 'connected' variable. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv4/udp.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 2879dc6d66ea..e992dd5392e3 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1062,8 +1062,8 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) int free = 0; int connected = 0; __be32 daddr, faddr, saddr; + u8 tos, scope; __be16 dport; - u8 tos; int err, is_udplite = IS_UDPLITE(sk); int corkreq = READ_ONCE(up->corkflag) || msg->msg_flags&MSG_MORE; int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); @@ -1183,12 +1183,9 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) connected = 0; } tos = get_rttos(&ipc, inet); - if (sock_flag(sk, SOCK_LOCALROUTE) || - (msg->msg_flags & MSG_DONTROUTE) || - (ipc.opt && ipc.opt->opt.is_strictroute)) { - tos |= RTO_ONLINK; + scope = ip_sendmsg_scope(inet, &ipc, msg); + if (scope == RT_SCOPE_LINK) connected = 0; - } if (ipv4_is_multicast(daddr)) { if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) @@ -1221,11 +1218,9 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) fl4 = &fl4_stack; - flowi4_init_output(fl4, ipc.oif, ipc.sockc.mark, tos, - RT_SCOPE_UNIVERSE, sk->sk_protocol, - flow_flags, - faddr, saddr, dport, inet->inet_sport, - sk->sk_uid); + flowi4_init_output(fl4, ipc.oif, ipc.sockc.mark, tos, scope, + sk->sk_protocol, flow_flags, faddr, saddr, + dport, inet->inet_sport, sk->sk_uid); security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4)); rt = ip_route_output_flow(net, fl4, sk); -- cgit v1.2.3 From 59088b5a946ee8a6603a9a84781670cedb01c40d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 22 May 2023 16:58:08 +0100 Subject: net: phy: avoid kernel warning dump when stopping an errored PHY When taking a network interface down (or removing a SFP module) after the PHY has encountered an error, phy_stop() complains incorrectly that it was called from HALTED state. The reason this is incorrect is that the network driver will have called phy_start() when the interface was brought up, and the fact that the PHY has a problem bears no relationship to the administrative state of the interface. Taking the interface administratively down (which calls phy_stop()) is always the right thing to do after a successful phy_start() call, whether or not the PHY has encountered an error. Signed-off-by: Russell King (Oracle) Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 11 +++++++---- include/linux/phy.h | 7 +++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 0c0df38cd1ab..bdf00b2b2c1d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -52,6 +52,7 @@ static const char *phy_state_to_str(enum phy_state st) PHY_STATE_STR(NOLINK) PHY_STATE_STR(CABLETEST) PHY_STATE_STR(HALTED) + PHY_STATE_STR(ERROR) } return NULL; @@ -1184,7 +1185,7 @@ void phy_stop_machine(struct phy_device *phydev) static void phy_process_error(struct phy_device *phydev) { mutex_lock(&phydev->lock); - phydev->state = PHY_HALTED; + phydev->state = PHY_ERROR; mutex_unlock(&phydev->lock); phy_trigger_machine(phydev); @@ -1198,10 +1199,10 @@ static void phy_error_precise(struct phy_device *phydev, } /** - * phy_error - enter HALTED state for this PHY device + * phy_error - enter ERROR state for this PHY device * @phydev: target phy_device struct * - * Moves the PHY to the HALTED state in response to a read + * Moves the PHY to the ERROR state in response to a read * or write error, and tells the controller the link is down. * Must not be called from interrupt context, or while the * phydev->lock is held. @@ -1326,7 +1327,8 @@ void phy_stop(struct phy_device *phydev) struct net_device *dev = phydev->attached_dev; enum phy_state old_state; - if (!phy_is_started(phydev) && phydev->state != PHY_DOWN) { + if (!phy_is_started(phydev) && phydev->state != PHY_DOWN && + phydev->state != PHY_ERROR) { WARN(1, "called from state %s\n", phy_state_to_str(phydev->state)); return; @@ -1443,6 +1445,7 @@ void phy_state_machine(struct work_struct *work) } break; case PHY_HALTED: + case PHY_ERROR: if (phydev->link) { phydev->link = 0; phy_link_down(phydev); diff --git a/include/linux/phy.h b/include/linux/phy.h index 2da87a36200d..7addde5d14c0 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -497,14 +497,17 @@ struct phy_device *mdiobus_scan_c22(struct mii_bus *bus, int addr); * Once complete, move to UP to restart the PHY. * - phy_stop aborts the running test and moves to @PHY_HALTED * - * @PHY_HALTED: PHY is up, but no polling or interrupts are done. Or - * PHY is in an error state. + * @PHY_HALTED: PHY is up, but no polling or interrupts are done. * - phy_start moves to @PHY_UP + * + * @PHY_ERROR: PHY is up, but is in an error state. + * - phy_stop moves to @PHY_HALTED */ enum phy_state { PHY_DOWN = 0, PHY_READY, PHY_HALTED, + PHY_ERROR, PHY_UP, PHY_RUNNING, PHY_NOLINK, -- cgit v1.2.3 From 7c2435ef76e5f2d9fac44b241e4a54113f6eafbf Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Tue, 23 May 2023 10:37:47 +0100 Subject: tools: ynl: Use dict of predefined Structs to decode scalar types Use a dict of predefined Struct() objects to decode scalar types in native, big or little endian format. This removes the repetitive code for the scalar variants and ensures all the signed variants are supported. Signed-off-by: Donald Hunter Signed-off-by: David S. Miller --- tools/net/ynl/lib/ynl.py | 101 +++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 57 deletions(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index aa77bcae4807..6185ba27f2e7 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -1,10 +1,12 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +from collections import namedtuple import functools import os import random import socket import struct +from struct import Struct import yaml from .nlspec import SpecFamily @@ -76,10 +78,17 @@ class NlError(Exception): class NlAttr: - type_formats = { 'u8' : ('B', 1), 's8' : ('b', 1), - 'u16': ('H', 2), 's16': ('h', 2), - 'u32': ('I', 4), 's32': ('i', 4), - 'u64': ('Q', 8), 's64': ('q', 8) } + ScalarFormat = namedtuple('ScalarFormat', ['native', 'big', 'little']) + type_formats = { + 'u8' : ScalarFormat(Struct('B'), Struct("B"), Struct("B")), + 's8' : ScalarFormat(Struct('b'), Struct("b"), Struct("b")), + 'u16': ScalarFormat(Struct('H'), Struct(">H"), Struct("h"), Struct("I"), Struct("i"), Struct("Q"), Struct("q"), Struct("" if byte_order == "big-endian" else "<" - return "" + return format.big if byte_order == "big-endian" \ + else format.little + return format.native - def as_u8(self): - return struct.unpack("B", self.raw)[0] - - def as_u16(self, byte_order=None): - endian = NlAttr.format_byte_order(byte_order) - return struct.unpack(f"{endian}H", self.raw)[0] - - def as_u32(self, byte_order=None): - endian = NlAttr.format_byte_order(byte_order) - return struct.unpack(f"{endian}I", self.raw)[0] - - def as_u64(self, byte_order=None): - endian = NlAttr.format_byte_order(byte_order) - return struct.unpack(f"{endian}Q", self.raw)[0] + def as_scalar(self, attr_type, byte_order=None): + format = self.get_format(attr_type, byte_order) + return format.unpack(self.raw)[0] def as_strz(self): return self.raw.decode('ascii')[:-1] @@ -115,17 +116,17 @@ class NlAttr: return self.raw def as_c_array(self, type): - format, _ = self.type_formats[type] - return list({ x[0] for x in struct.iter_unpack(format, self.raw) }) + format = self.get_format(type) + return [ x[0] for x in format.iter_unpack(self.raw) ] def as_struct(self, members): value = dict() offset = 0 for m in members: # TODO: handle non-scalar members - format, size = self.type_formats[m.type] - decoded = struct.unpack_from(format, self.raw, offset) - offset += size + format = self.get_format(m.type) + decoded = format.unpack_from(self.raw, offset) + offset += format.size value[m.name] = decoded[0] return value @@ -184,11 +185,11 @@ class NlMsg: if extack.type == Netlink.NLMSGERR_ATTR_MSG: self.extack['msg'] = extack.as_strz() elif extack.type == Netlink.NLMSGERR_ATTR_MISS_TYPE: - self.extack['miss-type'] = extack.as_u32() + self.extack['miss-type'] = extack.as_scalar('u32') elif extack.type == Netlink.NLMSGERR_ATTR_MISS_NEST: - self.extack['miss-nest'] = extack.as_u32() + self.extack['miss-nest'] = extack.as_scalar('u32') elif extack.type == Netlink.NLMSGERR_ATTR_OFFS: - self.extack['bad-attr-offs'] = extack.as_u32() + self.extack['bad-attr-offs'] = extack.as_scalar('u32') else: if 'unknown' not in self.extack: self.extack['unknown'] = [] @@ -272,11 +273,11 @@ def _genl_load_families(): fam = dict() for attr in gm.raw_attrs: if attr.type == Netlink.CTRL_ATTR_FAMILY_ID: - fam['id'] = attr.as_u16() + fam['id'] = attr.as_scalar('u16') elif attr.type == Netlink.CTRL_ATTR_FAMILY_NAME: fam['name'] = attr.as_strz() elif attr.type == Netlink.CTRL_ATTR_MAXATTR: - fam['maxattr'] = attr.as_u32() + fam['maxattr'] = attr.as_scalar('u32') elif attr.type == Netlink.CTRL_ATTR_MCAST_GROUPS: fam['mcast'] = dict() for entry in NlAttrs(attr.raw): @@ -286,7 +287,7 @@ def _genl_load_families(): if entry_attr.type == Netlink.CTRL_ATTR_MCAST_GRP_NAME: mcast_name = entry_attr.as_strz() elif entry_attr.type == Netlink.CTRL_ATTR_MCAST_GRP_ID: - mcast_id = entry_attr.as_u32() + mcast_id = entry_attr.as_scalar('u32') if mcast_name and mcast_id is not None: fam['mcast'][mcast_name] = mcast_id if 'name' in fam and 'id' in fam: @@ -304,9 +305,9 @@ class GenlMsg: self.fixed_header_attrs = dict() for m in fixed_header_members: - format, size = NlAttr.type_formats[m.type] - decoded = struct.unpack_from(format, nl_msg.raw, offset) - offset += size + format = NlAttr.get_format(m.type) + decoded = format.unpack_from(nl_msg.raw, offset) + offset += format.size self.fixed_header_attrs[m.name] = decoded[0] self.raw = nl_msg.raw[offset:] @@ -381,21 +382,13 @@ class YnlFamily(SpecFamily): attr_payload += self._add_attr(attr['nested-attributes'], subname, subvalue) elif attr["type"] == 'flag': attr_payload = b'' - elif attr["type"] == 'u8': - attr_payload = struct.pack("B", int(value)) - elif attr["type"] == 'u16': - endian = NlAttr.format_byte_order(attr.byte_order) - attr_payload = struct.pack(f"{endian}H", int(value)) - elif attr["type"] == 'u32': - endian = NlAttr.format_byte_order(attr.byte_order) - attr_payload = struct.pack(f"{endian}I", int(value)) - elif attr["type"] == 'u64': - endian = NlAttr.format_byte_order(attr.byte_order) - attr_payload = struct.pack(f"{endian}Q", int(value)) elif attr["type"] == 'string': attr_payload = str(value).encode('ascii') + b'\x00' elif attr["type"] == 'binary': attr_payload = value + elif attr['type'] in NlAttr.type_formats: + format = NlAttr.get_format(attr['type'], attr.byte_order) + attr_payload = format.pack(int(value)) else: raise Exception(f'Unknown type at {space} {name} {value} {attr["type"]}') @@ -434,22 +427,16 @@ class YnlFamily(SpecFamily): if attr_spec["type"] == 'nest': subdict = self._decode(NlAttrs(attr.raw), attr_spec['nested-attributes']) decoded = subdict - elif attr_spec['type'] == 'u8': - decoded = attr.as_u8() - elif attr_spec['type'] == 'u16': - decoded = attr.as_u16(attr_spec.byte_order) - elif attr_spec['type'] == 'u32': - decoded = attr.as_u32(attr_spec.byte_order) - elif attr_spec['type'] == 'u64': - decoded = attr.as_u64(attr_spec.byte_order) elif attr_spec["type"] == 'string': decoded = attr.as_strz() elif attr_spec["type"] == 'binary': decoded = self._decode_binary(attr, attr_spec) elif attr_spec["type"] == 'flag': decoded = True + elif attr_spec["type"] in NlAttr.type_formats: + decoded = attr.as_scalar(attr_spec['type'], attr_spec.byte_order) else: - raise Exception(f'Unknown {attr.type} {attr_spec["name"]} {attr_spec["type"]}') + raise Exception(f'Unknown {attr_spec["type"]} with name {attr_spec["name"]}') if not attr_spec.is_multi: rsp[attr_spec['name']] = decoded @@ -555,8 +542,8 @@ class YnlFamily(SpecFamily): fixed_header_members = self.consts[op.fixed_header].members for m in fixed_header_members: value = vals.pop(m.name) - format, _ = NlAttr.type_formats[m.type] - msg += struct.pack(format, value) + format = NlAttr.get_format(m.type) + msg += format.pack(value) for name, value in vals.items(): msg += self._add_attr(op.attr_set.name, name, value) msg = _genl_msg_finalize(msg) -- cgit v1.2.3 From bddd2e561b0ad5ca42e16fb26a20fc806d521912 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Tue, 23 May 2023 10:37:48 +0100 Subject: tools: ynl: Handle byte-order in struct members Add support for byte-order in struct members in the genetlink-legacy spec. Signed-off-by: Donald Hunter Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/netlink/genetlink-legacy.yaml | 2 ++ tools/net/ynl/lib/nlspec.py | 4 +++- tools/net/ynl/lib/ynl.py | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index b33541a51d6b..b5319cde9e17 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -122,6 +122,8 @@ properties: enum: [ u8, u16, u32, u64, s8, s16, s32, s64, string ] len: $ref: '#/$defs/len-or-define' + byte-order: + enum: [ little-endian, big-endian ] # End genetlink-legacy attribute-sets: diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index a0241add3839..c624cdfde223 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -226,11 +226,13 @@ class SpecStructMember(SpecElement): Represents a single struct member attribute. Attributes: - type string, type of the member attribute + type string, type of the member attribute + byte_order string or None for native byte order """ def __init__(self, family, yaml): super().__init__(family, yaml) self.type = yaml['type'] + self.byte_order = yaml.get('byte-order') class SpecStruct(SpecElement): diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 6185ba27f2e7..39a2296c0003 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -124,7 +124,7 @@ class NlAttr: offset = 0 for m in members: # TODO: handle non-scalar members - format = self.get_format(m.type) + format = self.get_format(m.type, m.byte_order) decoded = format.unpack_from(self.raw, offset) offset += format.size value[m.name] = decoded[0] @@ -305,7 +305,7 @@ class GenlMsg: self.fixed_header_attrs = dict() for m in fixed_header_members: - format = NlAttr.get_format(m.type) + format = NlAttr.get_format(m.type, m.byte_order) decoded = format.unpack_from(nl_msg.raw, offset) offset += format.size self.fixed_header_attrs[m.name] = decoded[0] @@ -542,7 +542,7 @@ class YnlFamily(SpecFamily): fixed_header_members = self.consts[op.fixed_header].members for m in fixed_header_members: value = vals.pop(m.name) - format = NlAttr.get_format(m.type) + format = NlAttr.get_format(m.type, m.byte_order) msg += format.pack(value) for name, value in vals.items(): msg += self._add_attr(op.attr_set.name, name, value) -- cgit v1.2.3 From c496daeb863093a046e0bb8db7265bf45d91775a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 23 May 2023 14:37:59 +0200 Subject: devlink: remove duplicate port notification The notification about created port is send from devl_port_register() function called from ops->port_new(). No need to send it again here, so remove the call and the helper function. Signed-off-by: Jiri Pirko Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx5/core/sf/devlink.c | 9 ++--- drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h | 3 +- include/net/devlink.h | 4 +- net/devlink/leftover.c | 45 +--------------------- 4 files changed, 6 insertions(+), 55 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c index 7d955a4d9f14..de15b9c85e1b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c @@ -282,8 +282,7 @@ out: static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table, const struct devlink_port_new_attrs *new_attr, - struct netlink_ext_ack *extack, - unsigned int *new_port_index) + struct netlink_ext_ack *extack) { struct mlx5_eswitch *esw = dev->priv.eswitch; struct mlx5_sf *sf; @@ -297,7 +296,6 @@ static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table, new_attr->controller, new_attr->sfnum); if (err) goto esw_err; - *new_port_index = sf->port_index; trace_mlx5_sf_add(dev, sf->port_index, sf->controller, sf->hw_fn_id, new_attr->sfnum); return 0; @@ -338,8 +336,7 @@ mlx5_sf_new_check_attr(struct mlx5_core_dev *dev, const struct devlink_port_new_ int mlx5_devlink_sf_port_new(struct devlink *devlink, const struct devlink_port_new_attrs *new_attr, - struct netlink_ext_ack *extack, - unsigned int *new_port_index) + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_priv(devlink); struct mlx5_sf_table *table; @@ -355,7 +352,7 @@ int mlx5_devlink_sf_port_new(struct devlink *devlink, "Port add is only supported in eswitch switchdev mode or SF ports are disabled."); return -EOPNOTSUPP; } - err = mlx5_sf_add(dev, table, new_attr, extack, new_port_index); + err = mlx5_sf_add(dev, table, new_attr, extack); mlx5_sf_table_put(table); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h index 3a480e06ecc0..1f7d8cbd72e8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h @@ -20,8 +20,7 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev); int mlx5_devlink_sf_port_new(struct devlink *devlink, const struct devlink_port_new_attrs *add_attr, - struct netlink_ext_ack *extack, - unsigned int *new_port_index); + struct netlink_ext_ack *extack); int mlx5_devlink_sf_port_del(struct devlink *devlink, unsigned int port_index, struct netlink_ext_ack *extack); int mlx5_devlink_sf_port_fn_state_get(struct devlink_port *dl_port, diff --git a/include/net/devlink.h b/include/net/devlink.h index 6a942e70e451..ccea6e079777 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1500,7 +1500,6 @@ struct devlink_ops { * @devlink: Devlink instance * @attrs: attributes of the new port * @extack: extack for reporting error messages - * @new_port_index: index of the new port * * Devlink core will call this device driver function upon user request * to create a new port function of a specified flavor and optional @@ -1515,8 +1514,7 @@ struct devlink_ops { */ int (*port_new)(struct devlink *devlink, const struct devlink_port_new_attrs *attrs, - struct netlink_ext_ack *extack, - unsigned int *new_port_index); + struct netlink_ext_ack *extack); /** * port_del() - Delete a port function * @devlink: Devlink instance diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index cd0254968076..cb60e42b2761 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1354,45 +1354,12 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, return devlink->ops->port_unsplit(devlink, devlink_port, info->extack); } -static int devlink_port_new_notify(struct devlink *devlink, - unsigned int port_index, - struct genl_info *info) -{ - struct devlink_port *devlink_port; - struct sk_buff *msg; - int err; - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - lockdep_assert_held(&devlink->lock); - devlink_port = devlink_port_get_by_index(devlink, port_index); - if (!devlink_port) { - err = -ENODEV; - goto out; - } - - err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_NEW, - info->snd_portid, info->snd_seq, 0, NULL); - if (err) - goto out; - - return genlmsg_reply(msg, info); - -out: - nlmsg_free(msg); - return err; -} - static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, struct genl_info *info) { struct netlink_ext_ack *extack = info->extack; struct devlink_port_new_attrs new_attrs = {}; struct devlink *devlink = info->user_ptr[0]; - unsigned int new_port_index; - int err; if (!devlink->ops->port_new || !devlink->ops->port_del) return -EOPNOTSUPP; @@ -1423,17 +1390,7 @@ static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, new_attrs.sfnum_valid = true; } - err = devlink->ops->port_new(devlink, &new_attrs, extack, - &new_port_index); - if (err) - return err; - - err = devlink_port_new_notify(devlink, new_port_index, info); - if (err && err != -ENODEV) { - /* Fail to send the response; destroy newly created port. */ - devlink->ops->port_del(devlink, new_port_index, extack); - } - return err; + return devlink->ops->port_new(devlink, &new_attrs, extack); } static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb, -- cgit v1.2.3 From 1bb1b57898504da4e10d48b901556278e161c7fd Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 23 May 2023 14:38:00 +0200 Subject: devlink: remove no longer true locking comment from port_new/del() All commands are called holding instance lock. Remove the outdated comment that says otherwise. Signed-off-by: Jiri Pirko Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- include/net/devlink.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/net/devlink.h b/include/net/devlink.h index ccea6e079777..24a48f3d4c35 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1506,8 +1506,6 @@ struct devlink_ops { * attributes * * Notes: - * - Called without devlink instance lock being held. Drivers must - * implement own means of synchronization * - On success, drivers must register a port with devlink core * * Return: 0 on success, negative value otherwise. @@ -1525,8 +1523,6 @@ struct devlink_ops { * to delete a previously created port function * * Notes: - * - Called without devlink instance lock being held. Drivers must - * implement own means of synchronization * - On success, drivers must unregister the corresponding devlink * port * -- cgit v1.2.3 From 9277649c66fe7cb0e2f8adb09621556bcfb052c7 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 23 May 2023 14:38:01 +0200 Subject: devlink: pass devlink_port pointer to ops->port_del() instead of index Historically there was a reason why port_dev() along with for example port_split() did get port_index instead of the devlink_port pointer. With the locking changes that were done which ensured devlink instance mutex is hold for every command, the port ops could get devlink_port pointer directly. Change the forgotten port_dev() op to be as others and pass devlink_port pointer instead of port_index. Signed-off-by: Jiri Pirko Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c | 5 +++-- drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h | 3 ++- include/net/devlink.h | 4 ++-- net/devlink/leftover.c | 11 +++-------- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c index de15b9c85e1b..c7d4691cb65a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c @@ -376,7 +376,8 @@ static void mlx5_sf_dealloc(struct mlx5_sf_table *table, struct mlx5_sf *sf) } } -int mlx5_devlink_sf_port_del(struct devlink *devlink, unsigned int port_index, +int mlx5_devlink_sf_port_del(struct devlink *devlink, + struct devlink_port *dl_port, struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_priv(devlink); @@ -391,7 +392,7 @@ int mlx5_devlink_sf_port_del(struct devlink *devlink, unsigned int port_index, "Port del is only supported in eswitch switchdev mode or SF ports are disabled."); return -EOPNOTSUPP; } - sf = mlx5_sf_lookup_by_index(table, port_index); + sf = mlx5_sf_lookup_by_index(table, dl_port->index); if (!sf) { err = -ENODEV; goto sf_err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h index 1f7d8cbd72e8..c5430b8dcdf6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h @@ -21,7 +21,8 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev); int mlx5_devlink_sf_port_new(struct devlink *devlink, const struct devlink_port_new_attrs *add_attr, struct netlink_ext_ack *extack); -int mlx5_devlink_sf_port_del(struct devlink *devlink, unsigned int port_index, +int mlx5_devlink_sf_port_del(struct devlink *devlink, + struct devlink_port *dl_port, struct netlink_ext_ack *extack); int mlx5_devlink_sf_port_fn_state_get(struct devlink_port *dl_port, enum devlink_port_fn_state *state, diff --git a/include/net/devlink.h b/include/net/devlink.h index 24a48f3d4c35..1bd56c8d6f3c 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1516,7 +1516,7 @@ struct devlink_ops { /** * port_del() - Delete a port function * @devlink: Devlink instance - * @port_index: port function index to delete + * @port: The devlink port * @extack: extack for reporting error messages * * Devlink core will call this device driver function upon user request @@ -1528,7 +1528,7 @@ struct devlink_ops { * * Return: 0 on success, negative value otherwise. */ - int (*port_del)(struct devlink *devlink, unsigned int port_index, + int (*port_del)(struct devlink *devlink, struct devlink_port *port, struct netlink_ext_ack *extack); /** * port_fn_state_get() - Get the state of a port function diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index cb60e42b2761..0410137a4a31 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1396,20 +1396,14 @@ static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb, struct genl_info *info) { + struct devlink_port *devlink_port = info->user_ptr[1]; struct netlink_ext_ack *extack = info->extack; struct devlink *devlink = info->user_ptr[0]; - unsigned int port_index; if (!devlink->ops->port_del) return -EOPNOTSUPP; - if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PORT_INDEX)) { - NL_SET_ERR_MSG(extack, "Port index is not specified"); - return -EINVAL; - } - port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]); - - return devlink->ops->port_del(devlink, port_index, extack); + return devlink->ops->port_del(devlink, devlink_port, extack); } static int @@ -6341,6 +6335,7 @@ const struct genl_small_ops devlink_nl_ops[56] = { .cmd = DEVLINK_CMD_PORT_DEL, .doit = devlink_nl_cmd_port_del_doit, .flags = GENL_ADMIN_PERM, + .internal_flags = DEVLINK_NL_FLAG_NEED_PORT, }, { .cmd = DEVLINK_CMD_LINECARD_GET, -- cgit v1.2.3 From e9261467ae86a6544bb602a55a1eab52696e71e3 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:15:48 +0100 Subject: net: mdio: add clause 73 to ethtool conversion helper Add a helper to convert a clause 73 advertisement to an ethtool bitmap. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- include/linux/mdio.h | 39 +++++++++++++++++++++++++++++++++++++++ include/uapi/linux/mdio.h | 24 ++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 27013d6bf24a..0670cc6e067c 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -486,6 +486,45 @@ static inline u32 linkmode_adv_to_mii_10base_t1_t(unsigned long *adv) return result; } +/** + * mii_c73_mod_linkmode - convert a Clause 73 advertisement to linkmodes + * @adv: linkmode advertisement setting + * @lpa: array of three u16s containing the advertisement + * + * Convert an IEEE 802.3 Clause 73 advertisement to ethtool link modes. + */ +static inline void mii_c73_mod_linkmode(unsigned long *adv, u16 *lpa) +{ + linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, + adv, lpa[0] & MDIO_AN_C73_0_PAUSE); + linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + adv, lpa[0] & MDIO_AN_C73_0_ASM_DIR); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_1000BASE_KX); + linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_10GBASE_KX4); + linkmode_mod_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_40GBASE_KR4); + linkmode_mod_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_40GBASE_CR4); + /* 100GBASE_CR10 and 100GBASE_KP4 not implemented */ + linkmode_mod_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_100GBASE_KR4); + linkmode_mod_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_100GBASE_CR4); + /* 25GBASE_R_S not implemented */ + /* The 25GBASE_R bit can be used for 25Gbase KR or CR modes */ + linkmode_mod_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_25GBASE_R); + linkmode_mod_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_25GBASE_R); + linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, + adv, lpa[1] & MDIO_AN_C73_1_10GBASE_KR); + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, + adv, lpa[2] & MDIO_AN_C73_2_2500BASE_KX); + /* 5GBASE_KR not implemented */ +} + int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); int __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum, diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h index 256b463e47a6..b826598d1e94 100644 --- a/include/uapi/linux/mdio.h +++ b/include/uapi/linux/mdio.h @@ -231,6 +231,30 @@ #define MDIO_PMA_EXTABLE_BT1 0x0800 /* BASE-T1 ability */ #define MDIO_PMA_EXTABLE_NBT 0x4000 /* 2.5/5GBASE-T ability */ +/* AN Clause 73 linkword */ +#define MDIO_AN_C73_0_S_MASK GENMASK(4, 0) +#define MDIO_AN_C73_0_E_MASK GENMASK(9, 5) +#define MDIO_AN_C73_0_PAUSE BIT(10) +#define MDIO_AN_C73_0_ASM_DIR BIT(11) +#define MDIO_AN_C73_0_C2 BIT(12) +#define MDIO_AN_C73_0_RF BIT(13) +#define MDIO_AN_C73_0_ACK BIT(14) +#define MDIO_AN_C73_0_NP BIT(15) +#define MDIO_AN_C73_1_T_MASK GENMASK(4, 0) +#define MDIO_AN_C73_1_1000BASE_KX BIT(5) +#define MDIO_AN_C73_1_10GBASE_KX4 BIT(6) +#define MDIO_AN_C73_1_10GBASE_KR BIT(7) +#define MDIO_AN_C73_1_40GBASE_KR4 BIT(8) +#define MDIO_AN_C73_1_40GBASE_CR4 BIT(9) +#define MDIO_AN_C73_1_100GBASE_CR10 BIT(10) +#define MDIO_AN_C73_1_100GBASE_KP4 BIT(11) +#define MDIO_AN_C73_1_100GBASE_KR4 BIT(12) +#define MDIO_AN_C73_1_100GBASE_CR4 BIT(13) +#define MDIO_AN_C73_1_25GBASE_R_S BIT(14) +#define MDIO_AN_C73_1_25GBASE_R BIT(15) +#define MDIO_AN_C73_2_2500BASE_KX BIT(0) +#define MDIO_AN_C73_2_5GBASE_KR BIT(1) + /* PHY XGXS lane state register. */ #define MDIO_PHYXS_LNSTAT_SYNC0 0x0001 #define MDIO_PHYXS_LNSTAT_SYNC1 0x0002 -- cgit v1.2.3 From dc7a51411ec5381a567d02bee683c99713c411d9 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:15:53 +0100 Subject: net: phylink: remove duplicated linkmode pause resolution Phylink had two chunks of code virtually the same for resolving the negotiated pause modes. Factor this down to one function. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 093b7b6e0263..d68015db0f2f 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -977,11 +977,10 @@ static void phylink_apply_manual_flow(struct phylink *pl, state->pause = pl->link_config.pause; } -static void phylink_resolve_flow(struct phylink_link_state *state) +static void phylink_resolve_an_pause(struct phylink_link_state *state) { bool tx_pause, rx_pause; - state->pause = MLO_PAUSE_NONE; if (state->duplex == DUPLEX_FULL) { linkmode_resolve_pause(state->advertising, state->lp_advertising, @@ -1193,7 +1192,8 @@ static void phylink_get_fixed_state(struct phylink *pl, else if (pl->link_gpio) state->link = !!gpiod_get_value_cansleep(pl->link_gpio); - phylink_resolve_flow(state); + state->pause = MLO_PAUSE_NONE; + phylink_resolve_an_pause(state); } static void phylink_mac_initial_config(struct phylink *pl, bool force_restart) @@ -3215,7 +3215,6 @@ static const struct sfp_upstream_ops sfp_phylink_ops = { static void phylink_decode_c37_word(struct phylink_link_state *state, uint16_t config_reg, int speed) { - bool tx_pause, rx_pause; int fd_bit; if (speed == SPEED_2500) @@ -3234,13 +3233,7 @@ static void phylink_decode_c37_word(struct phylink_link_state *state, state->link = false; } - linkmode_resolve_pause(state->advertising, state->lp_advertising, - &tx_pause, &rx_pause); - - if (tx_pause) - state->pause |= MLO_PAUSE_TX; - if (rx_pause) - state->pause |= MLO_PAUSE_RX; + phylink_resolve_an_pause(state); } static void phylink_decode_sgmii_word(struct phylink_link_state *state, -- cgit v1.2.3 From dad987484eaaa7cd7f7f7459f4aee1470d8ec8ef Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:15:58 +0100 Subject: net: phylink: add function to resolve clause 73 negotiation Add a function to resolve clause 73 negotiation according to the priority resolution function described in clause 73.3.6. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/phylink.h | 2 ++ 2 files changed, 41 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index d68015db0f2f..28417d307cf0 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -3212,6 +3212,45 @@ static const struct sfp_upstream_ops sfp_phylink_ops = { /* Helpers for MAC drivers */ +static struct { + int bit; + int speed; +} phylink_c73_priority_resolution[] = { + { ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, SPEED_100000 }, + { ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, SPEED_100000 }, + /* 100GBASE-KP4 and 100GBASE-CR10 not supported */ + { ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, SPEED_40000 }, + { ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, SPEED_40000 }, + { ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, SPEED_10000 }, + { ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, SPEED_10000 }, + /* 5GBASE-KR not supported */ + { ETHTOOL_LINK_MODE_2500baseX_Full_BIT, SPEED_2500 }, + { ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, SPEED_1000 }, +}; + +void phylink_resolve_c73(struct phylink_link_state *state) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(phylink_c73_priority_resolution); i++) { + int bit = phylink_c73_priority_resolution[i].bit; + if (linkmode_test_bit(bit, state->advertising) && + linkmode_test_bit(bit, state->lp_advertising)) + break; + } + + if (i < ARRAY_SIZE(phylink_c73_priority_resolution)) { + state->speed = phylink_c73_priority_resolution[i].speed; + state->duplex = DUPLEX_FULL; + } else { + /* negotiation failure */ + state->link = false; + } + + phylink_resolve_an_pause(state); +} +EXPORT_SYMBOL_GPL(phylink_resolve_c73); + static void phylink_decode_c37_word(struct phylink_link_state *state, uint16_t config_reg, int speed) { diff --git a/include/linux/phylink.h b/include/linux/phylink.h index bb782f05ad08..0cf07d7d11b8 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -656,6 +656,8 @@ int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, const unsigned long *advertising); void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs); +void phylink_resolve_c73(struct phylink_link_state *state); + void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs, struct phylink_link_state *state); -- cgit v1.2.3 From 6f7b89b45f1e9d8bdf8b4c4dcb8029633905ea85 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:16:03 +0100 Subject: net: pcs: xpcs: clean up reading clause 73 link partner advertisement Read the clause 73 link partner advertisement in a loop and then translate to the ethtool modes. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 39 +++++++++++++++++---------------------- drivers/net/pcs/pcs-xpcs.h | 3 --- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 72f25e778840..5723abfc6fc8 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -487,7 +487,7 @@ static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs, return ret; if (ret & MDIO_AN_STAT1_COMPLETE) { - ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1); + ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_AN_LPA); if (ret < 0) return ret; @@ -506,7 +506,8 @@ static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs, static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs, struct phylink_link_state *state) { - int ret; + u16 lpa[3]; + int i, ret; ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1); if (ret < 0) @@ -519,32 +520,26 @@ static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs, phylink_set(state->lp_advertising, Autoneg); - /* Clause 73 outcome */ - ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL3); - if (ret < 0) - return ret; - - if (ret & DW_C73_2500KX) - phylink_set(state->lp_advertising, 2500baseX_Full); + /* Read Clause 73 link partner advertisement */ + for (i = ARRAY_SIZE(lpa); --i >= 0; ) { + ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_AN_LPA + i); + if (ret < 0) + return ret; - ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL2); - if (ret < 0) - return ret; + lpa[i] = ret; + } - if (ret & DW_C73_1000KX) + if (lpa[2] & DW_C73_2500KX) + phylink_set(state->lp_advertising, 2500baseX_Full); + if (lpa[1] & DW_C73_1000KX) phylink_set(state->lp_advertising, 1000baseKX_Full); - if (ret & DW_C73_10000KX4) + if (lpa[1] & DW_C73_10000KX4) phylink_set(state->lp_advertising, 10000baseKX4_Full); - if (ret & DW_C73_10000KR) + if (lpa[1] & DW_C73_10000KR) phylink_set(state->lp_advertising, 10000baseKR_Full); - - ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1); - if (ret < 0) - return ret; - - if (ret & DW_C73_PAUSE) + if (lpa[0] & DW_C73_PAUSE) phylink_set(state->lp_advertising, Pause); - if (ret & DW_C73_ASYM_PAUSE) + if (lpa[0] & DW_C73_ASYM_PAUSE) phylink_set(state->lp_advertising, Asym_Pause); linkmode_and(state->lp_advertising, state->lp_advertising, diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h index 770df50323a0..68c6b5a62088 100644 --- a/drivers/net/pcs/pcs-xpcs.h +++ b/drivers/net/pcs/pcs-xpcs.h @@ -32,9 +32,6 @@ #define DW_SR_AN_ADV1 0x10 #define DW_SR_AN_ADV2 0x11 #define DW_SR_AN_ADV3 0x12 -#define DW_SR_AN_LP_ABL1 0x13 -#define DW_SR_AN_LP_ABL2 0x14 -#define DW_SR_AN_LP_ABL3 0x15 /* Clause 73 Defines */ /* AN_LP_ABL1 */ -- cgit v1.2.3 From 3f0360e09c8d92bb0a99c6eeeb2f3f6e7732955e Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:16:08 +0100 Subject: net: pcs: xpcs: use mii_c73_to_linkmode() helper Convert xpcs clause 73 reading to use the newly introduced mii_c73_to_linkmode() helper to translate the link partner advertisement to an ethtool bitmap. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 5723abfc6fc8..2165859a063c 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -529,18 +529,7 @@ static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs, lpa[i] = ret; } - if (lpa[2] & DW_C73_2500KX) - phylink_set(state->lp_advertising, 2500baseX_Full); - if (lpa[1] & DW_C73_1000KX) - phylink_set(state->lp_advertising, 1000baseKX_Full); - if (lpa[1] & DW_C73_10000KX4) - phylink_set(state->lp_advertising, 10000baseKX4_Full); - if (lpa[1] & DW_C73_10000KR) - phylink_set(state->lp_advertising, 10000baseKR_Full); - if (lpa[0] & DW_C73_PAUSE) - phylink_set(state->lp_advertising, Pause); - if (lpa[0] & DW_C73_ASYM_PAUSE) - phylink_set(state->lp_advertising, Asym_Pause); + mii_c73_mod_linkmode(state->lp_advertising, lpa); linkmode_and(state->lp_advertising, state->lp_advertising, state->advertising); -- cgit v1.2.3 From 1f94ba198bda5738bd26cb7633dca4b33a43dff2 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:16:13 +0100 Subject: net: pcs: xpcs: correct lp_advertising contents lp_advertising is supposed to reflect the link partner's advertisement unmodified by the local advertisement, but xpcs bitwise ands it with the local advertisement prior to calculating the resolution of the negotiation. Fix this by moving the bitwise and to xpcs_resolve_lpa_c73() so it can place the results in a temporary bitmap before passing that to ixpcs_get_max_usxgmii_speed(). Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 2165859a063c..90920a7ba136 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -531,18 +531,19 @@ static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs, mii_c73_mod_linkmode(state->lp_advertising, lpa); - linkmode_and(state->lp_advertising, state->lp_advertising, - state->advertising); return 0; } static void xpcs_resolve_lpa_c73(struct dw_xpcs *xpcs, struct phylink_link_state *state) { - int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising); + __ETHTOOL_DECLARE_LINK_MODE_MASK(res); + + /* Calculate the union of the advertising masks */ + linkmode_and(res, state->lp_advertising, state->advertising); state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX; - state->speed = max_speed; + state->speed = xpcs_get_max_usxgmii_speed(res); state->duplex = DUPLEX_FULL; } -- cgit v1.2.3 From 428d603fcaeb3c8135f9983c35619925f1a56f49 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:16:18 +0100 Subject: net: pcs: xpcs: correct pause resolution xpcs was indicating symmetric pause should be enabled regardless of the advertisements by either party. Fix this to use linkmode_resolve_pause() now that we're no longer obliterating the link partner's advertisement by logically anding it with our own. This is transitional, the function will be entirely replaced with phylink_resolve_c73() in the following patch. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 90920a7ba136..eec10392e584 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -538,11 +538,20 @@ static void xpcs_resolve_lpa_c73(struct dw_xpcs *xpcs, struct phylink_link_state *state) { __ETHTOOL_DECLARE_LINK_MODE_MASK(res); + bool tx_pause, rx_pause; /* Calculate the union of the advertising masks */ linkmode_and(res, state->lp_advertising, state->advertising); - state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX; + /* Resolve pause modes */ + linkmode_resolve_pause(state->advertising, state->lp_advertising, + &tx_pause, &rx_pause); + + if (tx_pause) + state->pause |= MLO_PAUSE_TX; + if (rx_pause) + state->pause |= MLO_PAUSE_RX; + state->speed = xpcs_get_max_usxgmii_speed(res); state->duplex = DUPLEX_FULL; } -- cgit v1.2.3 From 21234ef16665a78cf8b07182453a8395463865c8 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:16:24 +0100 Subject: net: pcs: xpcs: use phylink_resolve_c73() helper Use phylink_resolve_c73() to resolve the clause 73 autonegotiation result. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index eec10392e584..7c45887da4ed 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -336,22 +336,6 @@ static int xpcs_read_link_c73(struct dw_xpcs *xpcs) return link; } -static int xpcs_get_max_usxgmii_speed(const unsigned long *supported) -{ - int max = SPEED_UNKNOWN; - - if (phylink_test(supported, 1000baseKX_Full)) - max = SPEED_1000; - if (phylink_test(supported, 2500baseX_Full)) - max = SPEED_2500; - if (phylink_test(supported, 10000baseKX4_Full)) - max = SPEED_10000; - if (phylink_test(supported, 10000baseKR_Full)) - max = SPEED_10000; - - return max; -} - static void xpcs_config_usxgmii(struct dw_xpcs *xpcs, int speed) { int ret, speed_sel; @@ -534,28 +518,6 @@ static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs, return 0; } -static void xpcs_resolve_lpa_c73(struct dw_xpcs *xpcs, - struct phylink_link_state *state) -{ - __ETHTOOL_DECLARE_LINK_MODE_MASK(res); - bool tx_pause, rx_pause; - - /* Calculate the union of the advertising masks */ - linkmode_and(res, state->lp_advertising, state->advertising); - - /* Resolve pause modes */ - linkmode_resolve_pause(state->advertising, state->lp_advertising, - &tx_pause, &rx_pause); - - if (tx_pause) - state->pause |= MLO_PAUSE_TX; - if (rx_pause) - state->pause |= MLO_PAUSE_RX; - - state->speed = xpcs_get_max_usxgmii_speed(res); - state->duplex = DUPLEX_FULL; -} - static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs, struct phylink_link_state *state) { @@ -940,7 +902,7 @@ static int xpcs_get_state_c73(struct dw_xpcs *xpcs, if (an_enabled && xpcs_aneg_done_c73(xpcs, state, compat)) { state->an_complete = true; xpcs_read_lpa_c73(xpcs, state); - xpcs_resolve_lpa_c73(xpcs, state); + phylink_resolve_c73(state); } else if (an_enabled) { state->link = 0; } else if (state->link) { -- cgit v1.2.3 From 883a98ede4b67369569f2bd163015b31b03c3278 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 11:16:29 +0100 Subject: net: pcs: xpcs: avoid reading STAT1 more than once Avoid reading the STAT1 registers more than once while getting the PCS state, as this register contains latching-low bits that are lost after the first read. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 91 +++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 7c45887da4ed..736776e40c25 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -271,15 +271,12 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs, }) static int xpcs_read_fault_c73(struct dw_xpcs *xpcs, - struct phylink_link_state *state) + struct phylink_link_state *state, + u16 pcs_stat1) { int ret; - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1); - if (ret < 0) - return ret; - - if (ret & MDIO_STAT1_FAULT) { + if (pcs_stat1 & MDIO_STAT1_FAULT) { xpcs_warn(xpcs, state, "Link fault condition detected!\n"); return -EFAULT; } @@ -321,21 +318,6 @@ static int xpcs_read_fault_c73(struct dw_xpcs *xpcs, return 0; } -static int xpcs_read_link_c73(struct dw_xpcs *xpcs) -{ - bool link = true; - int ret; - - ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1); - if (ret < 0) - return ret; - - if (!(ret & MDIO_STAT1_LSTATUS)) - link = false; - - return link; -} - static void xpcs_config_usxgmii(struct dw_xpcs *xpcs, int speed) { int ret, speed_sel; @@ -462,15 +444,11 @@ static int xpcs_config_aneg_c73(struct dw_xpcs *xpcs, static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs, struct phylink_link_state *state, - const struct xpcs_compat *compat) + const struct xpcs_compat *compat, u16 an_stat1) { int ret; - ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1); - if (ret < 0) - return ret; - - if (ret & MDIO_AN_STAT1_COMPLETE) { + if (an_stat1 & MDIO_AN_STAT1_COMPLETE) { ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_AN_LPA); if (ret < 0) return ret; @@ -488,16 +466,12 @@ static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs, } static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs, - struct phylink_link_state *state) + struct phylink_link_state *state, u16 an_stat1) { u16 lpa[3]; int i, ret; - ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1); - if (ret < 0) - return ret; - - if (!(ret & MDIO_AN_STAT1_LPABLE)) { + if (!(an_stat1 & MDIO_AN_STAT1_LPABLE)) { phylink_clear(state->lp_advertising, Autoneg); return 0; } @@ -880,13 +854,25 @@ static int xpcs_get_state_c73(struct dw_xpcs *xpcs, const struct xpcs_compat *compat) { bool an_enabled; + int pcs_stat1; + int an_stat1; int ret; + /* The link status bit is latching-low, so it is important to + * avoid unnecessary re-reads of this register to avoid missing + * a link-down event. + */ + pcs_stat1 = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1); + if (pcs_stat1 < 0) { + state->link = false; + return pcs_stat1; + } + /* Link needs to be read first ... */ - state->link = xpcs_read_link_c73(xpcs) > 0 ? 1 : 0; + state->link = !!(pcs_stat1 & MDIO_STAT1_LSTATUS); /* ... and then we check the faults. */ - ret = xpcs_read_fault_c73(xpcs, state); + ret = xpcs_read_fault_c73(xpcs, state, pcs_stat1); if (ret) { ret = xpcs_soft_reset(xpcs, compat); if (ret) @@ -897,15 +883,38 @@ static int xpcs_get_state_c73(struct dw_xpcs *xpcs, return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND, NULL); } + /* There is no point doing anything else if the link is down. */ + if (!state->link) + return 0; + an_enabled = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, state->advertising); - if (an_enabled && xpcs_aneg_done_c73(xpcs, state, compat)) { - state->an_complete = true; - xpcs_read_lpa_c73(xpcs, state); + if (an_enabled) { + /* The link status bit is latching-low, so it is important to + * avoid unnecessary re-reads of this register to avoid missing + * a link-down event. + */ + an_stat1 = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1); + if (an_stat1 < 0) { + state->link = false; + return an_stat1; + } + + state->an_complete = xpcs_aneg_done_c73(xpcs, state, compat, + an_stat1); + if (!state->an_complete) { + state->link = false; + return 0; + } + + ret = xpcs_read_lpa_c73(xpcs, state, an_stat1); + if (ret < 0) { + state->link = false; + return ret; + } + phylink_resolve_c73(state); - } else if (an_enabled) { - state->link = 0; - } else if (state->link) { + } else { xpcs_resolve_pma(xpcs, state); } -- cgit v1.2.3 From 9d0a23313b1aa107df857e8441ea2ed74811ea17 Mon Sep 17 00:00:00 2001 From: JP Kobryn Date: Tue, 23 May 2023 17:45:36 -0700 Subject: libbpf: Add capability for resizing datasec maps This patch updates bpf_map__set_value_size() so that if the given map is memory mapped, it will attempt to resize the mapped region. Initial contents of the mapped region are preserved. BTF is not required, but after the mapping is resized an attempt is made to adjust the associated BTF information if the following criteria is met: - BTF info is present - the map is a datasec - the final variable in the datasec is an array ... the resulting BTF info will be updated so that the final array variable is associated with a new BTF array type sized to cover the requested size. Note that the initial resizing of the memory mapped region can succeed while the subsequent BTF adjustment can fail. In this case, BTF info is dropped from the map by clearing the key and value type. Signed-off-by: JP Kobryn Signed-off-by: Andrii Nakryiko Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230524004537.18614-2-inwardvessel@gmail.com --- tools/lib/bpf/libbpf.c | 135 +++++++++++++++++++++++++++++++++++++++++++++---- tools/lib/bpf/libbpf.h | 18 ++++++- 2 files changed, 142 insertions(+), 11 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index ad1ec893b41b..5cca00979aae 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1500,16 +1500,36 @@ static struct bpf_map *bpf_object__add_map(struct bpf_object *obj) return map; } -static size_t bpf_map_mmap_sz(const struct bpf_map *map) +static size_t bpf_map_mmap_sz(unsigned int value_sz, unsigned int max_entries) { - long page_sz = sysconf(_SC_PAGE_SIZE); + const long page_sz = sysconf(_SC_PAGE_SIZE); size_t map_sz; - map_sz = (size_t)roundup(map->def.value_size, 8) * map->def.max_entries; + map_sz = (size_t)roundup(value_sz, 8) * max_entries; map_sz = roundup(map_sz, page_sz); return map_sz; } +static int bpf_map_mmap_resize(struct bpf_map *map, size_t old_sz, size_t new_sz) +{ + void *mmaped; + + if (!map->mmaped) + return -EINVAL; + + if (old_sz == new_sz) + return 0; + + mmaped = mmap(NULL, new_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (mmaped == MAP_FAILED) + return -errno; + + memcpy(mmaped, map->mmaped, min(old_sz, new_sz)); + munmap(map->mmaped, old_sz); + map->mmaped = mmaped; + return 0; +} + static char *internal_map_name(struct bpf_object *obj, const char *real_name) { char map_name[BPF_OBJ_NAME_LEN], *p; @@ -1608,6 +1628,7 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, { struct bpf_map_def *def; struct bpf_map *map; + size_t mmap_sz; int err; map = bpf_object__add_map(obj); @@ -1642,7 +1663,8 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, pr_debug("map '%s' (global data): at sec_idx %d, offset %zu, flags %x.\n", map->name, map->sec_idx, map->sec_offset, def->map_flags); - map->mmaped = mmap(NULL, bpf_map_mmap_sz(map), PROT_READ | PROT_WRITE, + mmap_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries); + map->mmaped = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (map->mmaped == MAP_FAILED) { err = -errno; @@ -8294,7 +8316,10 @@ static void bpf_map__destroy(struct bpf_map *map) map->init_slots_sz = 0; if (map->mmaped) { - munmap(map->mmaped, bpf_map_mmap_sz(map)); + size_t mmap_sz; + + mmap_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries); + munmap(map->mmaped, mmap_sz); map->mmaped = NULL; } @@ -9412,10 +9437,103 @@ __u32 bpf_map__value_size(const struct bpf_map *map) return map->def.value_size; } +static int map_btf_datasec_resize(struct bpf_map *map, __u32 size) +{ + struct btf *btf; + struct btf_type *datasec_type, *var_type; + struct btf_var_secinfo *var; + const struct btf_type *array_type; + const struct btf_array *array; + int vlen, element_sz; + __u32 nr_elements, new_array_id; + + /* check btf existence */ + btf = bpf_object__btf(map->obj); + if (!btf) + return -ENOENT; + + /* verify map is datasec */ + datasec_type = btf_type_by_id(btf, bpf_map__btf_value_type_id(map)); + if (!btf_is_datasec(datasec_type)) { + pr_warn("map '%s': cannot be resized, map value type is not a datasec\n", + bpf_map__name(map)); + return -EINVAL; + } + + /* verify datasec has at least one var */ + vlen = btf_vlen(datasec_type); + if (vlen == 0) { + pr_warn("map '%s': cannot be resized, map value datasec is empty\n", + bpf_map__name(map)); + return -EINVAL; + } + + /* verify last var in the datasec is an array */ + var = &btf_var_secinfos(datasec_type)[vlen - 1]; + var_type = btf_type_by_id(btf, var->type); + array_type = skip_mods_and_typedefs(btf, var_type->type, NULL); + if (!btf_is_array(array_type)) { + pr_warn("map '%s': cannot be resized, last var must be an array\n", + bpf_map__name(map)); + return -EINVAL; + } + + /* verify request size aligns with array */ + array = btf_array(array_type); + element_sz = btf__resolve_size(btf, array->type); + if (element_sz <= 0 || (size - var->offset) % element_sz != 0) { + pr_warn("map '%s': cannot be resized, element size (%d) doesn't align with new total size (%u)\n", + bpf_map__name(map), element_sz, size); + return -EINVAL; + } + + /* create a new array based on the existing array, but with new length */ + nr_elements = (size - var->offset) / element_sz; + new_array_id = btf__add_array(btf, array->index_type, array->type, nr_elements); + if (new_array_id < 0) + return new_array_id; + + /* adding a new btf type invalidates existing pointers to btf objects, + * so refresh pointers before proceeding + */ + datasec_type = btf_type_by_id(btf, map->btf_value_type_id); + var = &btf_var_secinfos(datasec_type)[vlen - 1]; + var_type = btf_type_by_id(btf, var->type); + + /* finally update btf info */ + datasec_type->size = size; + var->size = size - var->offset; + var_type->type = new_array_id; + + return 0; +} + int bpf_map__set_value_size(struct bpf_map *map, __u32 size) { if (map->fd >= 0) return libbpf_err(-EBUSY); + + if (map->mmaped) { + int err; + size_t mmap_old_sz, mmap_new_sz; + + mmap_old_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries); + mmap_new_sz = bpf_map_mmap_sz(size, map->def.max_entries); + err = bpf_map_mmap_resize(map, mmap_old_sz, mmap_new_sz); + if (err) { + pr_warn("map '%s': failed to resize memory-mapped region: %d\n", + bpf_map__name(map), err); + return err; + } + err = map_btf_datasec_resize(map, size); + if (err && err != -ENOENT) { + pr_warn("map '%s': failed to adjust resized BTF, clearing BTF key/value info: %d\n", + bpf_map__name(map), err); + map->btf_value_type_id = 0; + map->btf_key_type_id = 0; + } + } + map->def.value_size = size; return 0; } @@ -9441,7 +9559,7 @@ int bpf_map__set_initial_value(struct bpf_map *map, return 0; } -const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize) +void *bpf_map__initial_value(struct bpf_map *map, size_t *psize) { if (!map->mmaped) return NULL; @@ -12693,7 +12811,7 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s) for (i = 0; i < s->map_cnt; i++) { struct bpf_map *map = *s->maps[i].map; - size_t mmap_sz = bpf_map_mmap_sz(map); + size_t mmap_sz = bpf_map_mmap_sz(map->def.value_size, map->def.max_entries); int prot, map_fd = bpf_map__fd(map); void **mmaped = s->maps[i].mmaped; @@ -12720,8 +12838,7 @@ int bpf_object__load_skeleton(struct bpf_object_skeleton *s) * as per normal clean up procedure, so we don't need to worry * about it from skeleton's clean up perspective. */ - *mmaped = mmap(map->mmaped, mmap_sz, prot, - MAP_SHARED | MAP_FIXED, map_fd, 0); + *mmaped = mmap(map->mmaped, mmap_sz, prot, MAP_SHARED | MAP_FIXED, map_fd, 0); if (*mmaped == MAP_FAILED) { err = -errno; *mmaped = NULL; diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 0b7362397ea3..754da73c643b 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -869,8 +869,22 @@ LIBBPF_API int bpf_map__set_numa_node(struct bpf_map *map, __u32 numa_node); /* get/set map key size */ LIBBPF_API __u32 bpf_map__key_size(const struct bpf_map *map); LIBBPF_API int bpf_map__set_key_size(struct bpf_map *map, __u32 size); -/* get/set map value size */ +/* get map value size */ LIBBPF_API __u32 bpf_map__value_size(const struct bpf_map *map); +/** + * @brief **bpf_map__set_value_size()** sets map value size. + * @param map the BPF map instance + * @return 0, on success; negative error, otherwise + * + * There is a special case for maps with associated memory-mapped regions, like + * the global data section maps (bss, data, rodata). When this function is used + * on such a map, the mapped region is resized. Afterward, an attempt is made to + * adjust the corresponding BTF info. This attempt is best-effort and can only + * succeed if the last variable of the data section map is an array. The array + * BTF type is replaced by a new BTF array type with a different length. + * Any previously existing pointers returned from bpf_map__initial_value() or + * corresponding data section skeleton pointer must be reinitialized. + */ LIBBPF_API int bpf_map__set_value_size(struct bpf_map *map, __u32 size); /* get map key/value BTF type IDs */ LIBBPF_API __u32 bpf_map__btf_key_type_id(const struct bpf_map *map); @@ -884,7 +898,7 @@ LIBBPF_API int bpf_map__set_map_extra(struct bpf_map *map, __u64 map_extra); LIBBPF_API int bpf_map__set_initial_value(struct bpf_map *map, const void *data, size_t size); -LIBBPF_API const void *bpf_map__initial_value(struct bpf_map *map, size_t *psize); +LIBBPF_API void *bpf_map__initial_value(struct bpf_map *map, size_t *psize); /** * @brief **bpf_map__is_internal()** tells the caller whether or not the -- cgit v1.2.3 From 08b0895675736c49f7b172eac7d5c042fc71c3ec Mon Sep 17 00:00:00 2001 From: JP Kobryn Date: Tue, 23 May 2023 17:45:37 -0700 Subject: libbpf: Selftests for resizing datasec maps This patch adds test coverage for resizing datasec maps. The first two subtests resize the bss and custom data sections. In both cases, an initial array (of length one) has its element set to one. After resizing the rest of the array is filled with ones as well. A BPF program is then run to sum the respective arrays and back on the userspace side the sum is checked to be equal to the number of elements. The third subtest attempts to perform resizing under conditions that will result in either the resize failing or the BTF info being cleared. Signed-off-by: JP Kobryn Signed-off-by: Andrii Nakryiko Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230524004537.18614-3-inwardvessel@gmail.com --- .../selftests/bpf/prog_tests/global_map_resize.c | 227 +++++++++++++++++++++ .../selftests/bpf/progs/test_global_map_resize.c | 58 ++++++ 2 files changed, 285 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/global_map_resize.c create mode 100644 tools/testing/selftests/bpf/progs/test_global_map_resize.c diff --git a/tools/testing/selftests/bpf/prog_tests/global_map_resize.c b/tools/testing/selftests/bpf/prog_tests/global_map_resize.c new file mode 100644 index 000000000000..fd41425d2e5c --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/global_map_resize.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#include +#include +#include +#include "test_global_map_resize.skel.h" +#include "test_progs.h" + +static void run_prog_bss_array_sum(void) +{ + (void)syscall(__NR_getpid); +} + +static void run_prog_data_array_sum(void) +{ + (void)syscall(__NR_getuid); +} + +static void global_map_resize_bss_subtest(void) +{ + int err; + struct test_global_map_resize *skel; + struct bpf_map *map; + const __u32 desired_sz = sizeof(skel->bss->sum) + sysconf(_SC_PAGE_SIZE) * 2; + size_t array_len, actual_sz; + + skel = test_global_map_resize__open(); + if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) + goto teardown; + + /* set some initial value before resizing. + * it is expected this non-zero value will be preserved + * while resizing. + */ + skel->bss->array[0] = 1; + + /* resize map value and verify the new size */ + map = skel->maps.bss; + err = bpf_map__set_value_size(map, desired_sz); + if (!ASSERT_OK(err, "bpf_map__set_value_size")) + goto teardown; + if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize")) + goto teardown; + + /* set the expected number of elements based on the resized array */ + array_len = (desired_sz - sizeof(skel->bss->sum)) / sizeof(skel->bss->array[0]); + if (!ASSERT_GT(array_len, 1, "array_len")) + goto teardown; + + skel->bss = bpf_map__initial_value(skel->maps.bss, &actual_sz); + if (!ASSERT_OK_PTR(skel->bss, "bpf_map__initial_value (ptr)")) + goto teardown; + if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)")) + goto teardown; + + /* fill the newly resized array with ones, + * skipping the first element which was previously set + */ + for (int i = 1; i < array_len; i++) + skel->bss->array[i] = 1; + + /* set global const values before loading */ + skel->rodata->pid = getpid(); + skel->rodata->bss_array_len = array_len; + skel->rodata->data_array_len = 1; + + err = test_global_map_resize__load(skel); + if (!ASSERT_OK(err, "test_global_map_resize__load")) + goto teardown; + err = test_global_map_resize__attach(skel); + if (!ASSERT_OK(err, "test_global_map_resize__attach")) + goto teardown; + + /* run the bpf program which will sum the contents of the array. + * since the array was filled with ones,verify the sum equals array_len + */ + run_prog_bss_array_sum(); + if (!ASSERT_EQ(skel->bss->sum, array_len, "sum")) + goto teardown; + +teardown: + test_global_map_resize__destroy(skel); +} + +static void global_map_resize_data_subtest(void) +{ + int err; + struct test_global_map_resize *skel; + struct bpf_map *map; + const __u32 desired_sz = sysconf(_SC_PAGE_SIZE) * 2; + size_t array_len, actual_sz; + + skel = test_global_map_resize__open(); + if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) + goto teardown; + + /* set some initial value before resizing. + * it is expected this non-zero value will be preserved + * while resizing. + */ + skel->data_custom->my_array[0] = 1; + + /* resize map value and verify the new size */ + map = skel->maps.data_custom; + err = bpf_map__set_value_size(map, desired_sz); + if (!ASSERT_OK(err, "bpf_map__set_value_size")) + goto teardown; + if (!ASSERT_EQ(bpf_map__value_size(map), desired_sz, "resize")) + goto teardown; + + /* set the expected number of elements based on the resized array */ + array_len = (desired_sz - sizeof(skel->bss->sum)) / sizeof(skel->data_custom->my_array[0]); + if (!ASSERT_GT(array_len, 1, "array_len")) + goto teardown; + + skel->data_custom = bpf_map__initial_value(skel->maps.data_custom, &actual_sz); + if (!ASSERT_OK_PTR(skel->data_custom, "bpf_map__initial_value (ptr)")) + goto teardown; + if (!ASSERT_EQ(actual_sz, desired_sz, "bpf_map__initial_value (size)")) + goto teardown; + + /* fill the newly resized array with ones, + * skipping the first element which was previously set + */ + for (int i = 1; i < array_len; i++) + skel->data_custom->my_array[i] = 1; + + /* set global const values before loading */ + skel->rodata->pid = getpid(); + skel->rodata->bss_array_len = 1; + skel->rodata->data_array_len = array_len; + + err = test_global_map_resize__load(skel); + if (!ASSERT_OK(err, "test_global_map_resize__load")) + goto teardown; + err = test_global_map_resize__attach(skel); + if (!ASSERT_OK(err, "test_global_map_resize__attach")) + goto teardown; + + /* run the bpf program which will sum the contents of the array. + * since the array was filled with ones,verify the sum equals array_len + */ + run_prog_data_array_sum(); + if (!ASSERT_EQ(skel->bss->sum, array_len, "sum")) + goto teardown; + +teardown: + test_global_map_resize__destroy(skel); +} + +static void global_map_resize_invalid_subtest(void) +{ + int err; + struct test_global_map_resize *skel; + struct bpf_map *map; + __u32 element_sz, desired_sz; + + skel = test_global_map_resize__open(); + if (!ASSERT_OK_PTR(skel, "test_global_map_resize__open")) + return; + + /* attempt to resize a global datasec map to size + * which does NOT align with array + */ + map = skel->maps.data_custom; + if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.custom initial btf")) + goto teardown; + /* set desired size a fraction of element size beyond an aligned size */ + element_sz = sizeof(skel->data_custom->my_array[0]); + desired_sz = element_sz + element_sz / 2; + /* confirm desired size does NOT align with array */ + if (!ASSERT_NEQ(desired_sz % element_sz, 0, "my_array alignment")) + goto teardown; + err = bpf_map__set_value_size(map, desired_sz); + /* confirm resize is OK but BTF info is cleared */ + if (!ASSERT_OK(err, ".data.custom bpf_map__set_value_size") || + !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.custom clear btf key") || + !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.custom clear btf val")) + goto teardown; + + /* attempt to resize a global datasec map whose only var is NOT an array */ + map = skel->maps.data_non_array; + if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array initial btf")) + goto teardown; + /* set desired size to arbitrary value */ + desired_sz = 1024; + err = bpf_map__set_value_size(map, desired_sz); + /* confirm resize is OK but BTF info is cleared */ + if (!ASSERT_OK(err, ".data.non_array bpf_map__set_value_size") || + !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.non_array clear btf key") || + !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.non_array clear btf val")) + goto teardown; + + /* attempt to resize a global datasec map + * whose last var is NOT an array + */ + map = skel->maps.data_array_not_last; + if (!ASSERT_NEQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last initial btf")) + goto teardown; + /* set desired size to a multiple of element size */ + element_sz = sizeof(skel->data_array_not_last->my_array_first[0]); + desired_sz = element_sz * 8; + /* confirm desired size aligns with array */ + if (!ASSERT_EQ(desired_sz % element_sz, 0, "my_array_first alignment")) + goto teardown; + err = bpf_map__set_value_size(map, desired_sz); + /* confirm resize is OK but BTF info is cleared */ + if (!ASSERT_OK(err, ".data.array_not_last bpf_map__set_value_size") || + !ASSERT_EQ(bpf_map__btf_key_type_id(map), 0, ".data.array_not_last clear btf key") || + !ASSERT_EQ(bpf_map__btf_value_type_id(map), 0, ".data.array_not_last clear btf val")) + goto teardown; + +teardown: + test_global_map_resize__destroy(skel); +} + +void test_global_map_resize(void) +{ + if (test__start_subtest("global_map_resize_bss")) + global_map_resize_bss_subtest(); + + if (test__start_subtest("global_map_resize_data")) + global_map_resize_data_subtest(); + + if (test__start_subtest("global_map_resize_invalid")) + global_map_resize_invalid_subtest(); +} diff --git a/tools/testing/selftests/bpf/progs/test_global_map_resize.c b/tools/testing/selftests/bpf/progs/test_global_map_resize.c new file mode 100644 index 000000000000..2588f2384246 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_global_map_resize.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include "vmlinux.h" +#include + +char _license[] SEC("license") = "GPL"; + +/* rodata section */ +const volatile pid_t pid; +const volatile size_t bss_array_len; +const volatile size_t data_array_len; + +/* bss section */ +int sum = 0; +int array[1]; + +/* custom data secton */ +int my_array[1] SEC(".data.custom"); + +/* custom data section which should NOT be resizable, + * since it contains a single var which is not an array + */ +int my_int SEC(".data.non_array"); + +/* custom data section which should NOT be resizable, + * since its last var is not an array + */ +int my_array_first[1] SEC(".data.array_not_last"); +int my_int_last SEC(".data.array_not_last"); + +SEC("tp/syscalls/sys_enter_getpid") +int bss_array_sum(void *ctx) +{ + if (pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + sum = 0; + + for (size_t i = 0; i < bss_array_len; ++i) + sum += array[i]; + + return 0; +} + +SEC("tp/syscalls/sys_enter_getuid") +int data_array_sum(void *ctx) +{ + if (pid != (bpf_get_current_pid_tgid() >> 32)) + return 0; + + sum = 0; + + for (size_t i = 0; i < data_array_len; ++i) + sum += my_array[i]; + + return 0; +} -- cgit v1.2.3 From ae4899bb486f73e6d3d55a82b40482b2c5529a98 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 23 May 2023 16:31:50 +0100 Subject: net: phylink: provide phylink_pcs_config() and phylink_pcs_link_up() Add two helper functions for calling PCS methods. phylink_pcs_config() allows us to handle PCS configuration specifics in one location, rather than the two call sites. phylink_pcs_link_up() gives us consistency. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1q1TzK-007Exd-Rs@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 53 +++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 28417d307cf0..508434fd4da8 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -992,6 +992,25 @@ static void phylink_resolve_an_pause(struct phylink_link_state *state) } } +static int phylink_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + const struct phylink_link_state *state, + bool permit_pause_to_mac) +{ + if (!pcs) + return 0; + + return pcs->ops->pcs_config(pcs, mode, state->interface, + state->advertising, permit_pause_to_mac); +} + +static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, int speed, + int duplex) +{ + if (pcs && pcs->ops->pcs_link_up) + pcs->ops->pcs_link_up(pcs, mode, interface, speed, duplex); +} + static void phylink_pcs_poll_stop(struct phylink *pl) { if (pl->cfg_link_an_mode == MLO_AN_INBAND) @@ -1075,18 +1094,15 @@ static void phylink_major_config(struct phylink *pl, bool restart, phylink_mac_config(pl, state); - if (pl->pcs) { - err = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode, - state->interface, - state->advertising, - !!(pl->link_config.pause & - MLO_PAUSE_AN)); - if (err < 0) - phylink_err(pl, "pcs_config failed: %pe\n", - ERR_PTR(err)); - if (err > 0) - restart = true; - } + err = phylink_pcs_config(pl->pcs, pl->cur_link_an_mode, state, + !!(pl->link_config.pause & + MLO_PAUSE_AN)); + if (err < 0) + phylink_err(pl, "pcs_config failed: %pe\n", + ERR_PTR(err)); + else if (err > 0) + restart = true; + if (restart) phylink_mac_pcs_an_restart(pl); @@ -1137,11 +1153,9 @@ static int phylink_change_inband_advert(struct phylink *pl) * restart negotiation if the pcs_config() helper indicates that * the programmed advertisement has changed. */ - ret = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode, - pl->link_config.interface, - pl->link_config.advertising, - !!(pl->link_config.pause & - MLO_PAUSE_AN)); + ret = phylink_pcs_config(pl->pcs, pl->cur_link_an_mode, + &pl->link_config, + !!(pl->link_config.pause & MLO_PAUSE_AN)); if (ret < 0) return ret; @@ -1273,9 +1287,8 @@ static void phylink_link_up(struct phylink *pl, pl->cur_interface = link_state.interface; - if (pl->pcs && pl->pcs->ops->pcs_link_up) - pl->pcs->ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode, - pl->cur_interface, speed, duplex); + phylink_pcs_link_up(pl->pcs, pl->cur_link_an_mode, pl->cur_interface, + speed, duplex); pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode, pl->cur_interface, speed, duplex, -- cgit v1.2.3 From cee4bd16c3195a701be683f7da9e88c6e11acb73 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Apr 2023 23:07:39 +0200 Subject: leds: trigger: netdev: Recheck NETDEV_LED_MODE_LINKUP on dev rename Dev can be renamed also while up for supported device. We currently wrongly clear the NETDEV_LED_MODE_LINKUP flag on NETDEV_CHANGENAME event. Fix this by rechecking if the carrier is ok on NETDEV_CHANGENAME and correctly set the NETDEV_LED_MODE_LINKUP bit. Fixes: 5f820ed52371 ("leds: trigger: netdev: fix handling on interface rename") Cc: stable@vger.kernel.org # v5.5+ Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230419210743.3594-2-ansuelsmth@gmail.com --- drivers/leds/trigger/ledtrig-netdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index d5e774d83021..f4d670ec30bc 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -318,6 +318,9 @@ static int netdev_trig_notify(struct notifier_block *nb, clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); switch (evt) { case NETDEV_CHANGENAME: + if (netif_carrier_ok(dev)) + set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + fallthrough; case NETDEV_REGISTER: if (trigger_data->net_dev) dev_put(trigger_data->net_dev); -- cgit v1.2.3 From e2f24cb1b5daf9a4f6f3ba574c1fa74aab9807a4 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Apr 2023 23:07:40 +0200 Subject: leds: trigger: netdev: Drop NETDEV_LED_MODE_LINKUP from mode Putting NETDEV_LED_MODE_LINKUP in the same list of the netdev trigger modes is wrong as it's used to set the link state of the device and not to set a blink mode as it's done by NETDEV_LED_LINK, NETDEV_LED_TX and NETDEV_LED_RX. It's also wrong to put this state in the same bitmap of the netdev trigger mode and should be external to it. Drop NETDEV_LED_MODE_LINKUP from mode list and convert to a simple bool that will be true or false based on the carrier link. No functional change intended. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230419210743.3594-3-ansuelsmth@gmail.com --- drivers/leds/trigger/ledtrig-netdev.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index f4d670ec30bc..d5c4e72b8261 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -50,10 +50,10 @@ struct led_netdev_data { unsigned int last_activity; unsigned long mode; + bool carrier_link_up; #define NETDEV_LED_LINK 0 #define NETDEV_LED_TX 1 #define NETDEV_LED_RX 2 -#define NETDEV_LED_MODE_LINKUP 3 }; enum netdev_led_attr { @@ -73,9 +73,9 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) if (!led_cdev->blink_brightness) led_cdev->blink_brightness = led_cdev->max_brightness; - if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode)) + if (!trigger_data->carrier_link_up) { led_set_brightness(led_cdev, LED_OFF); - else { + } else { if (test_bit(NETDEV_LED_LINK, &trigger_data->mode)) led_set_brightness(led_cdev, led_cdev->blink_brightness); @@ -131,10 +131,9 @@ static ssize_t device_name_store(struct device *dev, trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name); - clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = false; if (trigger_data->net_dev != NULL) - if (netif_carrier_ok(trigger_data->net_dev)) - set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev); trigger_data->last_activity = 0; @@ -315,11 +314,10 @@ static int netdev_trig_notify(struct notifier_block *nb, spin_lock_bh(&trigger_data->lock); - clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = false; switch (evt) { case NETDEV_CHANGENAME: - if (netif_carrier_ok(dev)) - set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = netif_carrier_ok(dev); fallthrough; case NETDEV_REGISTER: if (trigger_data->net_dev) @@ -333,8 +331,7 @@ static int netdev_trig_notify(struct notifier_block *nb, break; case NETDEV_UP: case NETDEV_CHANGE: - if (netif_carrier_ok(dev)) - set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + trigger_data->carrier_link_up = netif_carrier_ok(dev); break; } -- cgit v1.2.3 From bdec9cb83936e0ac4cb87fed5b49fad0175f7dec Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Apr 2023 23:07:41 +0200 Subject: leds: trigger: netdev: Rename add namespace to netdev trigger enum modes Rename NETDEV trigger enum modes to a more symbolic name and add a namespace to them. Also add __TRIGGER_NETDEV_MAX to identify the max modes of the netdev trigger. This is a cleanup to drop the define and no behaviour change are intended. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230419210743.3594-4-ansuelsmth@gmail.com --- drivers/leds/trigger/ledtrig-netdev.c | 58 +++++++++++++++-------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index d5c4e72b8261..25d7a20d353d 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -51,15 +51,15 @@ struct led_netdev_data { unsigned long mode; bool carrier_link_up; -#define NETDEV_LED_LINK 0 -#define NETDEV_LED_TX 1 -#define NETDEV_LED_RX 2 }; -enum netdev_led_attr { - NETDEV_ATTR_LINK, - NETDEV_ATTR_TX, - NETDEV_ATTR_RX +enum led_trigger_netdev_modes { + TRIGGER_NETDEV_LINK = 0, + TRIGGER_NETDEV_TX, + TRIGGER_NETDEV_RX, + + /* Keep last */ + __TRIGGER_NETDEV_MAX, }; static void set_baseline_state(struct led_netdev_data *trigger_data) @@ -76,7 +76,7 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) if (!trigger_data->carrier_link_up) { led_set_brightness(led_cdev, LED_OFF); } else { - if (test_bit(NETDEV_LED_LINK, &trigger_data->mode)) + if (test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode)) led_set_brightness(led_cdev, led_cdev->blink_brightness); else @@ -85,8 +85,8 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) /* If we are looking for RX/TX start periodically * checking stats */ - if (test_bit(NETDEV_LED_TX, &trigger_data->mode) || - test_bit(NETDEV_LED_RX, &trigger_data->mode)) + if (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode)) schedule_delayed_work(&trigger_data->work, 0); } } @@ -146,20 +146,16 @@ static ssize_t device_name_store(struct device *dev, static DEVICE_ATTR_RW(device_name); static ssize_t netdev_led_attr_show(struct device *dev, char *buf, - enum netdev_led_attr attr) + enum led_trigger_netdev_modes attr) { struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); int bit; switch (attr) { - case NETDEV_ATTR_LINK: - bit = NETDEV_LED_LINK; - break; - case NETDEV_ATTR_TX: - bit = NETDEV_LED_TX; - break; - case NETDEV_ATTR_RX: - bit = NETDEV_LED_RX; + case TRIGGER_NETDEV_LINK: + case TRIGGER_NETDEV_TX: + case TRIGGER_NETDEV_RX: + bit = attr; break; default: return -EINVAL; @@ -169,7 +165,7 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf, } static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, - size_t size, enum netdev_led_attr attr) + size_t size, enum led_trigger_netdev_modes attr) { struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); unsigned long state; @@ -181,14 +177,10 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, return ret; switch (attr) { - case NETDEV_ATTR_LINK: - bit = NETDEV_LED_LINK; - break; - case NETDEV_ATTR_TX: - bit = NETDEV_LED_TX; - break; - case NETDEV_ATTR_RX: - bit = NETDEV_LED_RX; + case TRIGGER_NETDEV_LINK: + case TRIGGER_NETDEV_TX: + case TRIGGER_NETDEV_RX: + bit = attr; break; default: return -EINVAL; @@ -360,21 +352,21 @@ static void netdev_trig_work(struct work_struct *work) } /* If we are not looking for RX/TX then return */ - if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) && - !test_bit(NETDEV_LED_RX, &trigger_data->mode)) + if (!test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) && + !test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode)) return; dev_stats = dev_get_stats(trigger_data->net_dev, &temp); new_activity = - (test_bit(NETDEV_LED_TX, &trigger_data->mode) ? + (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ? dev_stats->tx_packets : 0) + - (test_bit(NETDEV_LED_RX, &trigger_data->mode) ? + (test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) ? dev_stats->rx_packets : 0); if (trigger_data->last_activity != new_activity) { led_stop_software_blink(trigger_data->led_cdev); - invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode); + invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode); interval = jiffies_to_msecs( atomic_read(&trigger_data->interval)); /* base state is ON (link present) */ -- cgit v1.2.3 From 164b67d53476a9d114be85c885bd31f783835be4 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Apr 2023 23:07:42 +0200 Subject: leds: trigger: netdev: Convert device attr to macro Convert link tx and rx device attr to a common macro to reduce common code and in preparation for additional attr. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230419210743.3594-5-ansuelsmth@gmail.com --- drivers/leds/trigger/ledtrig-netdev.c | 57 ++++++++++------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 25d7a20d353d..af16565c40ba 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -198,47 +198,22 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, return size; } -static ssize_t link_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return netdev_led_attr_show(dev, buf, NETDEV_ATTR_LINK); -} - -static ssize_t link_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_LINK); -} - -static DEVICE_ATTR_RW(link); - -static ssize_t tx_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return netdev_led_attr_show(dev, buf, NETDEV_ATTR_TX); -} - -static ssize_t tx_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_TX); -} - -static DEVICE_ATTR_RW(tx); - -static ssize_t rx_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return netdev_led_attr_show(dev, buf, NETDEV_ATTR_RX); -} - -static ssize_t rx_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_RX); -} - -static DEVICE_ATTR_RW(rx); +#define DEFINE_NETDEV_TRIGGER(trigger_name, trigger) \ + static ssize_t trigger_name##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ + { \ + return netdev_led_attr_show(dev, buf, trigger); \ + } \ + static ssize_t trigger_name##_store(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t size) \ + { \ + return netdev_led_attr_store(dev, buf, size, trigger); \ + } \ + static DEVICE_ATTR_RW(trigger_name) + +DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK); +DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX); +DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX); static ssize_t interval_show(struct device *dev, struct device_attribute *attr, char *buf) -- cgit v1.2.3 From d1b9e1391ab2dc80e9db87fe8b2de015c651e4c9 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Apr 2023 23:07:43 +0200 Subject: leds: trigger: netdev: Use mutex instead of spinlocks Some LEDs may require to sleep while doing some operation like setting brightness and other cleanup. For this reason, using a spinlock will cause a sleep under spinlock warning. It should be safe to convert this to a sleepable lock since: - sysfs read/write can sleep - netdev_trig_work is a work queue and can sleep - netdev _trig_notify can sleep The spinlock was used when brightness didn't support sleeping, but this changed and now it supported with brightness_set_blocking(). Convert to mutex lock to permit sleeping using brightness_set_blocking(). Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230419210743.3594-6-ansuelsmth@gmail.com --- drivers/leds/trigger/ledtrig-netdev.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index af16565c40ba..305eb543ba84 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include "../leds.h" @@ -37,7 +37,7 @@ */ struct led_netdev_data { - spinlock_t lock; + struct mutex lock; struct delayed_work work; struct notifier_block notifier; @@ -97,9 +97,9 @@ static ssize_t device_name_show(struct device *dev, struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); ssize_t len; - spin_lock_bh(&trigger_data->lock); + mutex_lock(&trigger_data->lock); len = sprintf(buf, "%s\n", trigger_data->device_name); - spin_unlock_bh(&trigger_data->lock); + mutex_unlock(&trigger_data->lock); return len; } @@ -115,7 +115,7 @@ static ssize_t device_name_store(struct device *dev, cancel_delayed_work_sync(&trigger_data->work); - spin_lock_bh(&trigger_data->lock); + mutex_lock(&trigger_data->lock); if (trigger_data->net_dev) { dev_put(trigger_data->net_dev); @@ -138,7 +138,7 @@ static ssize_t device_name_store(struct device *dev, trigger_data->last_activity = 0; set_baseline_state(trigger_data); - spin_unlock_bh(&trigger_data->lock); + mutex_unlock(&trigger_data->lock); return size; } @@ -279,7 +279,7 @@ static int netdev_trig_notify(struct notifier_block *nb, cancel_delayed_work_sync(&trigger_data->work); - spin_lock_bh(&trigger_data->lock); + mutex_lock(&trigger_data->lock); trigger_data->carrier_link_up = false; switch (evt) { @@ -304,7 +304,7 @@ static int netdev_trig_notify(struct notifier_block *nb, set_baseline_state(trigger_data); - spin_unlock_bh(&trigger_data->lock); + mutex_unlock(&trigger_data->lock); return NOTIFY_DONE; } @@ -365,7 +365,7 @@ static int netdev_trig_activate(struct led_classdev *led_cdev) if (!trigger_data) return -ENOMEM; - spin_lock_init(&trigger_data->lock); + mutex_init(&trigger_data->lock); trigger_data->notifier.notifier_call = netdev_trig_notify; trigger_data->notifier.priority = 10; -- cgit v1.2.3 From 4fbfde4e272065943cbcf2d016f0679456cb4f75 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Tue, 23 May 2023 18:14:51 +0200 Subject: net: tcp: make the txhash available in TIME_WAIT sockets for IPv4 too Commit c67b85558ff2 ("ipv6: tcp: send consistent autoflowlabel in TIME_WAIT state") made the socket txhash also available in TIME_WAIT sockets but for IPv6 only. Make it available for IPv4 too as we'll use it in later commits. Signed-off-by: Antoine Tenart Reviewed-by: Eric Dumazet Signed-off-by: Paolo Abeni --- net/ipv4/tcp_minisocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index dac0d62120e6..04fc328727e6 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -303,6 +303,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tcptw->tw_ts_offset = tp->tsoffset; tcptw->tw_last_oow_ack_time = 0; tcptw->tw_tx_delay = tp->tcp_tx_delay; + tw->tw_txhash = sk->sk_txhash; #if IS_ENABLED(CONFIG_IPV6) if (tw->tw_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); @@ -311,7 +312,6 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; tw->tw_tclass = np->tclass; tw->tw_flowlabel = be32_to_cpu(np->flow_label & IPV6_FLOWLABEL_MASK); - tw->tw_txhash = sk->sk_txhash; tw->tw_ipv6only = sk->sk_ipv6only; } #endif -- cgit v1.2.3 From c0a8966e2bc7d31f77a7246947ebc09c1ff06066 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Tue, 23 May 2023 18:14:52 +0200 Subject: net: ipv4: use consistent txhash in TIME_WAIT and SYN_RECV When using IPv4/TCP, skb->hash comes from sk->sk_txhash except in TIME_WAIT and SYN_RECV where it's not set in the reply skb from ip_send_unicast_reply. Those packets will have a mismatched hash with others from the same flow as their hashes will be 0. IPv6 does not have the same issue as the hash is set from the socket txhash in those cases. This commits sets the hash in the reply skb from ip_send_unicast_reply, which makes the IPv4 code behaving like IPv6. Signed-off-by: Antoine Tenart Reviewed-by: Eric Dumazet Signed-off-by: Paolo Abeni --- include/net/ip.h | 2 +- net/ipv4/ip_output.c | 4 +++- net/ipv4/tcp_ipv4.c | 14 +++++++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 8a3860a916dc..2982dd13cf16 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -286,7 +286,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, const struct ip_options *sopt, __be32 daddr, __be32 saddr, const struct ip_reply_arg *arg, - unsigned int len, u64 transmit_time); + unsigned int len, u64 transmit_time, u32 txhash); #define IP_INC_STATS(net, field) SNMP_INC_STATS64((net)->mib.ip_statistics, field) #define __IP_INC_STATS(net, field) __SNMP_INC_STATS64((net)->mib.ip_statistics, field) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 553c740a6bfb..244fb9365d87 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1570,7 +1570,7 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, const struct ip_options *sopt, __be32 daddr, __be32 saddr, const struct ip_reply_arg *arg, - unsigned int len, u64 transmit_time) + unsigned int len, u64 transmit_time, u32 txhash) { struct ip_options_data replyopts; struct ipcm_cookie ipc; @@ -1633,6 +1633,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, arg->csum)); nskb->ip_summed = CHECKSUM_NONE; nskb->mono_delivery_time = !!transmit_time; + if (txhash) + skb_set_hash(nskb, txhash, PKT_HASH_TYPE_L4); ip_push_pending_frames(sk, &fl4); } out: diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index af043f063a73..a50bd782f91f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -692,6 +692,7 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) u64 transmit_time = 0; struct sock *ctl_sk; struct net *net; + u32 txhash = 0; /* Never send a reset in response to a reset. */ if (th->rst) @@ -829,6 +830,8 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) inet_twsk(sk)->tw_priority : sk->sk_priority; transmit_time = tcp_transmit_time(sk); xfrm_sk_clone_policy(ctl_sk, sk); + txhash = (sk->sk_state == TCP_TIME_WAIT) ? + inet_twsk(sk)->tw_txhash : sk->sk_txhash; } else { ctl_sk->sk_mark = 0; ctl_sk->sk_priority = 0; @@ -837,7 +840,7 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) skb, &TCP_SKB_CB(skb)->header.h4.opt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len, - transmit_time); + transmit_time, txhash); xfrm_sk_free_policy(ctl_sk); sock_net_set(ctl_sk, &init_net); @@ -859,7 +862,7 @@ static void tcp_v4_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, struct tcp_md5sig_key *key, - int reply_flags, u8 tos) + int reply_flags, u8 tos, u32 txhash) { const struct tcphdr *th = tcp_hdr(skb); struct { @@ -935,7 +938,7 @@ static void tcp_v4_send_ack(const struct sock *sk, skb, &TCP_SKB_CB(skb)->header.h4.opt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, &arg, arg.iov[0].iov_len, - transmit_time); + transmit_time, txhash); sock_net_set(ctl_sk, &init_net); __TCP_INC_STATS(net, TCP_MIB_OUTSEGS); @@ -955,7 +958,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0, - tw->tw_tos + tw->tw_tos, + tw->tw_txhash ); inet_twsk_put(tw); @@ -988,7 +992,7 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, 0, tcp_md5_do_lookup(sk, l3index, addr, AF_INET), inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, - ip_hdr(skb)->tos); + ip_hdr(skb)->tos, tcp_rsk(req)->txhash); } /* -- cgit v1.2.3 From 7016eb738651ed1dfeef2bbf266bc7dac734067d Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Tue, 23 May 2023 18:14:53 +0200 Subject: Documentation: net: net.core.txrehash is not specific to listening sockets The net.core.txrehash documentation mentions this knob is for listening sockets only, while sk_rethink_txhash can be called on SYN and RTO retransmits on all TCP sockets. Remove the listening socket part. Signed-off-by: Antoine Tenart Reviewed-by: Eric Dumazet Signed-off-by: Paolo Abeni --- Documentation/admin-guide/sysctl/net.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst index 466c560b0c30..4877563241f3 100644 --- a/Documentation/admin-guide/sysctl/net.rst +++ b/Documentation/admin-guide/sysctl/net.rst @@ -386,8 +386,8 @@ Default : 0 (for compatibility reasons) txrehash -------- -Controls default hash rethink behaviour on listening socket when SO_TXREHASH -option is set to SOCK_TXREHASH_DEFAULT (i. e. not overridden by setsockopt). +Controls default hash rethink behaviour on socket when SO_TXREHASH option is set +to SOCK_TXREHASH_DEFAULT (i. e. not overridden by setsockopt). If set to 1 (default), hash rethink is performed on listening socket. If set to 0, hash rethink is not performed. -- cgit v1.2.3 From 623a71385312ee288d59e319b90922e6e6943766 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 23 May 2023 20:17:52 +0200 Subject: net/mlx4: Use bitmap_weight_and() Use bitmap_weight_and() instead of hand writing it. This saves a few LoC and is slightly faster, should it mater. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/a29c2348a062408bec45cee2601b2417310e5ea7.1684865809.git.christophe.jaillet@wanadoo.fr Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlx4/main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 277738c50c56..28c435ce98d8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -1374,16 +1374,13 @@ static int mlx4_mf_bond(struct mlx4_dev *dev) int nvfs; struct mlx4_slaves_pport slaves_port1; struct mlx4_slaves_pport slaves_port2; - DECLARE_BITMAP(slaves_port_1_2, MLX4_MFUNC_MAX); slaves_port1 = mlx4_phys_to_slaves_pport(dev, 1); slaves_port2 = mlx4_phys_to_slaves_pport(dev, 2); - bitmap_and(slaves_port_1_2, - slaves_port1.slaves, slaves_port2.slaves, - dev->persist->num_vfs + 1); /* only single port vfs are allowed */ - if (bitmap_weight(slaves_port_1_2, dev->persist->num_vfs + 1) > 1) { + if (bitmap_weight_and(slaves_port1.slaves, slaves_port2.slaves, + dev->persist->num_vfs + 1) > 1) { mlx4_warn(dev, "HA mode unsupported for dual ported VFs\n"); return -EINVAL; } -- cgit v1.2.3 From 657d42cf5df64d9f32caab73ba2d2284879a37b0 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Wed, 24 May 2023 09:54:10 +0200 Subject: s390/ism: Set DMA coherent mask A future change will convert the DMA API implementation from the architecture specific arch/s390/pci/pci_dma.c to using the common code drivers/iommu/dma-iommu.c which the utilizes the same IOMMU hardware through the s390-iommu driver. Unlike the s390 specific DMA API this requires devices to correctly set the coherent mask to be allowed to use IOVAs >2^32 in dma_alloc_coherent(). This was however not done for ISM devices. ISM requires such addresses since currently the DMA aperture for PCI devices starts at 2^32 and all calls to dma_alloc_coherent() would thus fail. Link: https://lore.kernel.org/all/20230310-dma_iommu-v9-1-65bb8edd2beb@linux.ibm.com/ Reviewed-by: Alexandra Winter Reviewed-by: Matthew Rosato Reviewed-by: Pierre Morel Signed-off-by: Niklas Schnelle Link: https://lore.kernel.org/r/20230524075411.3734141-1-schnelle@linux.ibm.com Signed-off-by: Paolo Abeni --- drivers/s390/net/ism_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index 8acb9eba691b..1399b5dc646c 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -660,7 +660,7 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto err_disable; - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (ret) goto err_resource; -- cgit v1.2.3 From 040a22191879ad77fd904b3aaf10d3aa16adb068 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Mon, 22 May 2023 12:50:48 +0200 Subject: wifi: add HAS_IOPORT dependencies In a future patch HAS_IOPORT=n will result in inb()/outb() and friends not being declared. We thus need to add HAS_IOPORT as dependency for those drivers using them. Co-developed-by: Arnd Bergmann Signed-off-by: Arnd Bergmann Acked-by: Kalle Valo Signed-off-by: Niklas Schnelle Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522105049.1467313-44-schnelle@linux.ibm.com --- drivers/net/wireless/atmel/Kconfig | 2 +- drivers/net/wireless/intersil/hostap/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/atmel/Kconfig b/drivers/net/wireless/atmel/Kconfig index ca45a1021cf4..bafdd57b049a 100644 --- a/drivers/net/wireless/atmel/Kconfig +++ b/drivers/net/wireless/atmel/Kconfig @@ -14,7 +14,7 @@ if WLAN_VENDOR_ATMEL config ATMEL tristate "Atmel at76c50x chipset 802.11b support" - depends on CFG80211 && (PCI || PCMCIA) + depends on CFG80211 && (PCI || PCMCIA) && HAS_IOPORT select WIRELESS_EXT select WEXT_PRIV select FW_LOADER diff --git a/drivers/net/wireless/intersil/hostap/Kconfig b/drivers/net/wireless/intersil/hostap/Kconfig index c865d3156cea..2edff8efbcbb 100644 --- a/drivers/net/wireless/intersil/hostap/Kconfig +++ b/drivers/net/wireless/intersil/hostap/Kconfig @@ -56,7 +56,7 @@ config HOSTAP_FIRMWARE_NVRAM config HOSTAP_PLX tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" - depends on PCI && HOSTAP + depends on PCI && HOSTAP && HAS_IOPORT help Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based PCI adaptors. -- cgit v1.2.3 From e967229ead0e6c5047a1cfd5a0db58ceb930800b Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 22 May 2023 22:24:22 +0200 Subject: wifi: rtw88: sdio: Check the HISR RX_REQUEST bit in rtw_sdio_rx_isr() rtw_sdio_rx_isr() is responsible for receiving data from the wifi chip and is called from the SDIO interrupt handler when the interrupt status register (HISR) has the RX_REQUEST bit set. After the first batch of data has been processed by the driver the wifi chip may have more data ready to be read, which is managed by a loop in rtw_sdio_rx_isr(). It turns out that there are cases where the RX buffer length (from the REG_SDIO_RX0_REQ_LEN register) does not match the data we receive. The following two cases were observed with a RTL8723DS card: - RX length is smaller than the total packet length including overhead and actual data bytes (whose length is part of the buffer we read from the wifi chip and is stored in rtw_rx_pkt_stat.pkt_len). This can result in errors like: skbuff: skb_over_panic: text:ffff8000011924ac len:3341 put:3341 (one case observed was: RX buffer length = 1536 bytes but rtw_rx_pkt_stat.pkt_len = 1546 bytes, this is not valid as it means we need to read beyond the end of the buffer) - RX length looks valid but rtw_rx_pkt_stat.pkt_len is zero Check if the RX_REQUEST is set in the HISR register for each iteration inside rtw_sdio_rx_isr(). This mimics what the RTL8723DS vendor driver does and makes the driver only read more data if the RX_REQUEST bit is set (which seems to be a way for the card's hardware or firmware to tell the host that data is ready to be processed). For RTW_WCPU_11AC chips this check is not needed. The RTL8822BS vendor driver for example states that this check is unnecessary (but still uses it) and the RTL8822CS drops this check entirely. Reviewed-by: Ping-Ke Shih Signed-off-by: Martin Blumenstingl Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522202425.1827005-2-martin.blumenstingl@googlemail.com --- drivers/net/wireless/realtek/rtw88/sdio.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index af0459a79899..e734feb806db 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -1006,9 +1006,9 @@ static void rtw_sdio_rxfifo_recv(struct rtw_dev *rtwdev, u32 rx_len) static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) { - u32 rx_len, total_rx_bytes = 0; + u32 rx_len, hisr, total_rx_bytes = 0; - while (total_rx_bytes < SZ_64K) { + do { if (rtw_chip_wcpu_11n(rtwdev)) rx_len = rtw_read16(rtwdev, REG_SDIO_RX0_REQ_LEN); else @@ -1020,7 +1020,25 @@ static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) rtw_sdio_rxfifo_recv(rtwdev, rx_len); total_rx_bytes += rx_len; - } + + if (rtw_chip_wcpu_11n(rtwdev)) { + /* Stop if no more RX requests are pending, even if + * rx_len could be greater than zero in the next + * iteration. This is needed because the RX buffer may + * already contain data while either HW or FW are not + * done filling that buffer yet. Still reading the + * buffer can result in packets where + * rtw_rx_pkt_stat.pkt_len is zero or points beyond the + * end of the buffer. + */ + hisr = rtw_read32(rtwdev, REG_SDIO_HISR); + } else { + /* RTW_WCPU_11AC chips have improved hardware or + * firmware and can use rx_len unconditionally. + */ + hisr = REG_SDIO_HISR_RX_REQUEST; + } + } while (total_rx_bytes < SZ_64K && hisr & REG_SDIO_HISR_RX_REQUEST); } static void rtw_sdio_handle_interrupt(struct sdio_func *sdio_func) -- cgit v1.2.3 From 9be20a82232779c59979527dfc8febca3182fee2 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 22 May 2023 22:24:23 +0200 Subject: wifi: rtw88: rtw8723d: Implement RTL8723DS (SDIO) efuse parsing The efuse of the SDIO RTL8723DS chip has only one known member: the mac address is at offset 0x11a. Add a struct rtw8723ds_efuse describing this and use it for copying the mac address when the SDIO bus is used. Reviewed-by: Ping-Ke Shih Signed-off-by: Martin Blumenstingl Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522202425.1827005-3-martin.blumenstingl@googlemail.com --- drivers/net/wireless/realtek/rtw88/rtw8723d.c | 9 +++++++++ drivers/net/wireless/realtek/rtw88/rtw8723d.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 06e7454c9ca6..cadf66f4e854 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -216,6 +216,12 @@ static void rtw8723du_efuse_parsing(struct rtw_efuse *efuse, ether_addr_copy(efuse->addr, map->u.mac_addr); } +static void rtw8723ds_efuse_parsing(struct rtw_efuse *efuse, + struct rtw8723d_efuse *map) +{ + ether_addr_copy(efuse->addr, map->s.mac_addr); +} + static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) { struct rtw_efuse *efuse = &rtwdev->efuse; @@ -248,6 +254,9 @@ static int rtw8723d_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) case RTW_HCI_TYPE_USB: rtw8723du_efuse_parsing(efuse, map); break; + case RTW_HCI_TYPE_SDIO: + rtw8723ds_efuse_parsing(efuse, map); + break; default: /* unsupported now */ return -ENOTSUPP; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.h b/drivers/net/wireless/realtek/rtw88/rtw8723d.h index a356318a5c15..3642a2c7f80c 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.h @@ -49,6 +49,11 @@ struct rtw8723du_efuse { u8 mac_addr[ETH_ALEN]; /* 0x107 */ }; +struct rtw8723ds_efuse { + u8 res4[0x4a]; /* 0xd0 */ + u8 mac_addr[ETH_ALEN]; /* 0x11a */ +}; + struct rtw8723d_efuse { __le16 rtl_id; u8 rsvd[2]; @@ -80,6 +85,7 @@ struct rtw8723d_efuse { union { struct rtw8723de_efuse e; struct rtw8723du_efuse u; + struct rtw8723ds_efuse s; }; }; -- cgit v1.2.3 From 09fcdbd28404b7e02cc9fc4862ae5b43b76867c0 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 22 May 2023 22:24:24 +0200 Subject: mmc: sdio: Add/rename SDIO ID of the RTL8723DS SDIO wifi cards RTL8723DS comes in two variant and each of them has their own SDIO ID: - 0xd723 can connect two antennas. The WiFi part is still 1x1 so the second antenna can be dedicated to Bluetooth - 0xd724 can only connect one antenna so it's shared between WiFi and Bluetooth Add a new entry for the single antenna RTL8723DS (0xd724) which can be found on the MangoPi MQ-Quad. Also rename the existing RTL8723DS entry (0xd723) so it's name reflects that it's the variant with support for two antennas. Reviewed-by: Ping-Ke Shih Signed-off-by: Martin Blumenstingl Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522202425.1827005-4-martin.blumenstingl@googlemail.com --- include/linux/mmc/sdio_ids.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index c653accdc7fd..7fada7a714fe 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -121,7 +121,8 @@ #define SDIO_DEVICE_ID_REALTEK_RTW8822BS 0xb822 #define SDIO_DEVICE_ID_REALTEK_RTW8821CS 0xc821 #define SDIO_DEVICE_ID_REALTEK_RTW8822CS 0xc822 -#define SDIO_DEVICE_ID_REALTEK_RTW8723DS 0xd723 +#define SDIO_DEVICE_ID_REALTEK_RTW8723DS_2ANT 0xd723 +#define SDIO_DEVICE_ID_REALTEK_RTW8723DS_1ANT 0xd724 #define SDIO_DEVICE_ID_REALTEK_RTW8821DS 0xd821 #define SDIO_VENDOR_ID_SIANO 0x039a -- cgit v1.2.3 From a3b125ceb45e1acd21c9bcb6d3a5c52897d536e6 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 22 May 2023 22:24:25 +0200 Subject: wifi: rtw88: Add support for the SDIO based RTL8723DS chipset Wire up RTL8723DS chipset support using the rtw88 SDIO HCI code as well as the existing RTL8723D chipset code. Reviewed-by: Ping-Ke Shih Signed-off-by: Martin Blumenstingl Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522202425.1827005-5-martin.blumenstingl@googlemail.com --- drivers/net/wireless/realtek/rtw88/Kconfig | 11 +++++++ drivers/net/wireless/realtek/rtw88/Makefile | 3 ++ drivers/net/wireless/realtek/rtw88/rtw8723ds.c | 41 ++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw88/rtw8723ds.c diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig index 29eb2f8e0eb7..cffad1c01249 100644 --- a/drivers/net/wireless/realtek/rtw88/Kconfig +++ b/drivers/net/wireless/realtek/rtw88/Kconfig @@ -111,6 +111,17 @@ config RTW88_8723DE 802.11n PCIe wireless network adapter +config RTW88_8723DS + tristate "Realtek 8723DS SDIO wireless network adapter" + depends on MMC + select RTW88_CORE + select RTW88_SDIO + select RTW88_8723D + help + Select this option will enable support for 8723DS chipset + + 802.11n SDIO wireless network adapter + config RTW88_8723DU tristate "Realtek 8723DU USB wireless network adapter" depends on USB diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 82979b30ae8d..fd212c09d88a 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -50,6 +50,9 @@ rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o rtw88_8723de-objs := rtw8723de.o +obj-$(CONFIG_RTW88_8723DS) += rtw88_8723ds.o +rtw88_8723ds-objs := rtw8723ds.o + obj-$(CONFIG_RTW88_8723DU) += rtw88_8723du.o rtw88_8723du-objs := rtw8723du.o diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723ds.c b/drivers/net/wireless/realtek/rtw88/rtw8723ds.c new file mode 100644 index 000000000000..e5b6960ba0a0 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8723ds.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) Martin Blumenstingl + */ + +#include +#include +#include +#include "main.h" +#include "rtw8723d.h" +#include "sdio.h" + +static const struct sdio_device_id rtw_8723ds_id_table[] = { + { + SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK, + SDIO_DEVICE_ID_REALTEK_RTW8723DS_1ANT), + .driver_data = (kernel_ulong_t)&rtw8723d_hw_spec, + }, + { + SDIO_DEVICE(SDIO_VENDOR_ID_REALTEK, + SDIO_DEVICE_ID_REALTEK_RTW8723DS_2ANT), + .driver_data = (kernel_ulong_t)&rtw8723d_hw_spec, + }, + {} +}; +MODULE_DEVICE_TABLE(sdio, rtw_8723ds_id_table); + +static struct sdio_driver rtw_8723ds_driver = { + .name = "rtw_8723ds", + .probe = rtw_sdio_probe, + .remove = rtw_sdio_remove, + .id_table = rtw_8723ds_id_table, + .drv = { + .pm = &rtw_sdio_pm_ops, + .shutdown = rtw_sdio_shutdown, + } +}; +module_sdio_driver(rtw_8723ds_driver); + +MODULE_AUTHOR("Martin Blumenstingl "); +MODULE_DESCRIPTION("Realtek 802.11n wireless 8723ds driver"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From cda66049bab5273c61f09a4ea8c09d1de4d64fc0 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 16 May 2023 16:24:39 +0800 Subject: wifi: rtw89: ser: reset total_sta_assoc and tdls_peer when L2 The total_sta_assoc and the tdls_peer are used for statistics accodring to stations' information. L2 (Level 2) SER (system error recovery) will call ieee80211_restart_hw() which re-invokes sta_state ops. And then, the total_sta_assoc and tdls_peer will be re-increased. In case wrong statistics results, we reset them in SER L2 handling. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230516082441.11154-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/ser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 9ba99f3764e7..54b314b8b329 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -303,6 +303,7 @@ static void ser_reset_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); rtwvif->net_type = RTW89_NET_TYPE_NO_LINK; rtwvif->trigger = false; + rtwvif->tdls_peer = 0; } static void ser_sta_deinit_cam_iter(void *data, struct ieee80211_sta *sta) @@ -341,6 +342,8 @@ static void ser_reset_mac_binding(struct rtw89_dev *rtwdev) rtw89_core_release_all_bits_map(rtwdev->mac_id_map, RTW89_MAX_MAC_ID_NUM); rtw89_for_each_rtwvif(rtwdev, rtwvif) ser_reset_vif(rtwdev, rtwvif); + + rtwdev->total_sta_assoc = 0; } /* hal function */ -- cgit v1.2.3 From b79a84fbbdb0a715b130ab470c241db211539dfb Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 16 May 2023 16:24:40 +0800 Subject: wifi: rtw89: tweak H2C TX waiting function for SER Some specific H2C (host to chip command) needs waiting until FW ACK by C2H (chip to host event). However, during SER (system error recovery), most interrupts are disabled, so we can't receive C2H immediately. It causes this kind of H2C TX waits will always time out during SER. To save time spent by SER, we don't do these redundant waits. And, to make a difference from -ETIMEDOUT in other cases, we make the function return 1 for SER case. When some H2C callers really catch `ret == 1` at runtime, they can determine whether it's reasonable or not, and consider how to resolve their flow if needed. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230516082441.11154-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 1 + drivers/net/wireless/realtek/rtw89/fw.c | 8 ++++++++ drivers/net/wireless/realtek/rtw89/ser.c | 2 ++ 3 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index fe464b7212f5..ce6fc18dbfc7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3505,6 +3505,7 @@ enum rtw89_flags { RTW89_FLAG_LOW_POWER_MODE, RTW89_FLAG_INACTIVE_PS, RTW89_FLAG_CRASH_SIMULATING, + RTW89_FLAG_SER_HANDLING, RTW89_FLAG_WOWLAN, RTW89_FLAG_FORBIDDEN_TRACK_WROK, RTW89_FLAG_CHANGING_INTERFACE, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index ad277f22b197..b7befcfd4a91 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -3792,6 +3792,11 @@ fail: return ret; } +/* Return < 0, if failures happen during waiting for the condition. + * Return 0, when waiting for the condition succeeds. + * Return > 0, if the wait is considered unreachable due to driver/FW design, + * where 1 means during SER. + */ static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_wait_info *wait, unsigned int cond) { @@ -3804,6 +3809,9 @@ static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, return -EBUSY; } + if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) + return 1; + return rtw89_wait_for_cond(wait, cond); } diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 54b314b8b329..0462ba693f6f 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -409,6 +409,7 @@ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) switch (evt) { case SER_EV_STATE_IN: rtw89_hci_recovery_complete(rtwdev); + clear_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags); clear_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags); break; case SER_EV_L1_RESET_PREPARE: @@ -421,6 +422,7 @@ static void ser_idle_st_hdl(struct rtw89_ser *ser, u8 evt) ser_state_goto(ser, SER_L2_RESET_ST); break; case SER_EV_STATE_OUT: + set_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags); rtw89_hci_recovery_start(rtwdev); break; default: -- cgit v1.2.3 From 8b21c08ef7df41aa615439beac323a7b3b1df0e6 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Tue, 16 May 2023 16:24:41 +0800 Subject: wifi: rtw89: refine packet offload handling under SER H2C of packet offload needs to wait FW ACK by C2H. But, it's possible that packet offload happens during SER (system error recovery), e.g. SER L2 which restarts HW. More, packet offload flow isn't deferrable. So, the H2C wait may get `ret == 1` (unreachable). However, the logic FW deals with packet offload is simple enough, just clone content. It means that as long as the H2C is issued successfully, the thing will succeed sooner or later. Therefore, after we add a debug log when receiving ACK to packet offload, it would be acceptable that during SER, packet offload don't really wait for ACK. And, if debugging, we can still check its debug logs. Besides, we can expect that if we see SER before receiving ACK to packet offload, those debug logs of the ACK have a time difference. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230516082441.11154-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 4 ++-- drivers/net/wireless/realtek/rtw89/mac.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index b7befcfd4a91..f7d4f9d14736 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2467,7 +2467,7 @@ int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id) cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(id, RTW89_PKT_OFLD_OP_DEL); ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); - if (ret) { + if (ret < 0) { rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to del pkt ofld: id %d, ret %d\n", id, ret); @@ -2517,7 +2517,7 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(alloc_id, RTW89_PKT_OFLD_OP_ADD); ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); - if (ret) { + if (ret < 0) { rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to add pkt ofld: id %d, ret %d\n", alloc_id, ret); diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index acba53cf7cc3..f637fdafc7f1 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -4456,6 +4456,9 @@ rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, struct rtw89_completion_data data = {}; unsigned int cond; + rtw89_debug(rtwdev, RTW89_DBG_FW, "pkt ofld rsp: id %d op %d len %d\n", + pkt_id, pkt_op, pkt_len); + data.err = !pkt_len; cond = RTW89_FW_OFLD_WAIT_COND_PKT_OFLD(pkt_id, pkt_op); -- cgit v1.2.3 From 76f2516f79373e17974ce03c52eba4cfea8483e9 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2023 11:14:54 +0800 Subject: wifi: rtw89: 8851b: add TX power related functions Get TX power value from tables according to selected country and channel, and set proper power to registers. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230519031500.21087-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 254 ++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 6ecdd3d3f776..cead009b270d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -448,6 +448,34 @@ static void rtw8851b_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev, } } +static void rtw8851b_thermal_trim(struct rtw89_dev *rtwdev) +{ +#define __thm_setting(raw) \ +({ \ + u8 __v = (raw); \ + ((__v & 0x1) << 3) | ((__v & 0x1f) >> 1); \ +}) + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u8 i, val; + + if (!info->pg_thermal_trim) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] no PG, do nothing\n"); + + return; + } + + for (i = 0; i < RF_PATH_NUM_8851B; i++) { + val = __thm_setting(info->thermal_trim[i]); + rtw89_write_rf(rtwdev, i, RR_TM2, RR_TM2_OFF, val); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[THERMAL][TRIM] path=%d thermal_setting=0x%x\n", + i, val); + } +#undef __thm_setting +} + static void rtw8851b_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, u8 *phycap_map) { @@ -468,6 +496,32 @@ static void rtw8851b_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, } } +static void rtw8851b_pa_bias_trim(struct rtw89_dev *rtwdev) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u8 pabias_2g, pabias_5g; + u8 i; + + if (!info->pg_pa_bias_trim) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] no PG, do nothing\n"); + + return; + } + + for (i = 0; i < RF_PATH_NUM_8851B; i++) { + pabias_2g = u8_get_bits(info->pa_bias_trim[i], GENMASK(3, 0)); + pabias_5g = u8_get_bits(info->pa_bias_trim[i], GENMASK(7, 4)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n", + i, pabias_2g, pabias_5g); + + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG, pabias_2g); + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA, pabias_5g); + } +} + static void rtw8851b_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phycap_map) { static const u32 comp_addrs[][RTW89_SUBBAND_2GHZ_5GHZ_NR] = { @@ -565,6 +619,12 @@ static void rtw8851b_rfe_gpio(struct rtw89_dev *rtwdev) } } +static void rtw8851b_power_trim(struct rtw89_dev *rtwdev) +{ + rtw8851b_thermal_trim(rtwdev); + rtw8851b_pa_bias_trim(rtwdev); +} + static void rtw8851b_set_channel_mac(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, u8 mac_idx) @@ -1355,6 +1415,195 @@ static void rtw8851b_set_channel_help(struct rtw89_dev *rtwdev, bool enter, } } +static u32 rtw8851b_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx, s16 ref) +{ + const u16 tssi_16dbm_cw = 0x12c; + const u8 base_cw_0db = 0x27; + const s8 ofst_int = 0; + s16 pwr_s10_3; + s16 rf_pwr_cw; + u16 bb_pwr_cw; + u32 pwr_cw; + u32 tssi_ofst_cw; + + pwr_s10_3 = (ref << 1) + (s16)(ofst_int) + (s16)(base_cw_0db << 3); + bb_pwr_cw = u16_get_bits(pwr_s10_3, GENMASK(2, 0)); + rf_pwr_cw = u16_get_bits(pwr_s10_3, GENMASK(8, 3)); + rf_pwr_cw = clamp_t(s16, rf_pwr_cw, 15, 63); + pwr_cw = (rf_pwr_cw << 3) | bb_pwr_cw; + + tssi_ofst_cw = (u32)((s16)tssi_16dbm_cw + (ref << 1) - (16 << 3)); + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, + "[TXPWR] tssi_ofst_cw=%d rf_cw=0x%x bb_cw=0x%x\n", + tssi_ofst_cw, rf_pwr_cw, bb_pwr_cw); + + return u32_encode_bits(tssi_ofst_cw, B_DPD_TSSI_CW) | + u32_encode_bits(pwr_cw, B_DPD_PWR_CW) | + u32_encode_bits(ref, B_DPD_REF); +} + +static void rtw8851b_set_txpwr_ref(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + static const u32 addr[RF_PATH_NUM_8851B] = {0x5800}; + const u32 mask = B_DPD_TSSI_CW | B_DPD_PWR_CW | B_DPD_REF; + const u8 ofst_ofdm = 0x4; + const u8 ofst_cck = 0x8; + const s16 ref_ofdm = 0; + const s16 ref_cck = 0; + u32 val; + u8 i; + + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n"); + + rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_CTRL, + B_AX_PWR_REF, 0x0); + + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb ofdm txpwr ref\n"); + val = rtw8851b_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_ofdm); + + for (i = 0; i < RF_PATH_NUM_8851B; i++) + rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_ofdm, mask, val, + phy_idx); + + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb cck txpwr ref\n"); + val = rtw8851b_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_cck); + + for (i = 0; i < RF_PATH_NUM_8851B; i++) + rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_cck, mask, val, + phy_idx); +} + +static void rtw8851b_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + u8 tx_shape_idx, + enum rtw89_phy_idx phy_idx) +{ +#define __DFIR_CFG_ADDR(i) (R_TXFIR0 + ((i) << 2)) +#define __DFIR_CFG_MASK 0xffffffff +#define __DFIR_CFG_NR 8 +#define __DECL_DFIR_PARAM(_name, _val...) \ + static const u32 param_ ## _name[] = {_val}; \ + static_assert(ARRAY_SIZE(param_ ## _name) == __DFIR_CFG_NR) + + __DECL_DFIR_PARAM(flat, + 0x023D23FF, 0x0029B354, 0x000FC1C8, 0x00FDB053, + 0x00F86F9A, 0x06FAEF92, 0x00FE5FCC, 0x00FFDFF5); + __DECL_DFIR_PARAM(sharp, + 0x023D83FF, 0x002C636A, 0x0013F204, 0x00008090, + 0x00F87FB0, 0x06F99F83, 0x00FDBFBA, 0x00003FF5); + __DECL_DFIR_PARAM(sharp_14, + 0x023B13FF, 0x001C42DE, 0x00FDB0AD, 0x00F60F6E, + 0x00FD8F92, 0x0602D011, 0x0001C02C, 0x00FFF00A); + u8 ch = chan->channel; + const u32 *param; + u32 addr; + int i; + + if (ch > 14) { + rtw89_warn(rtwdev, + "set tx shape dfir by unknown ch: %d on 2G\n", ch); + return; + } + + if (ch == 14) + param = param_sharp_14; + else + param = tx_shape_idx == 0 ? param_flat : param_sharp; + + for (i = 0; i < __DFIR_CFG_NR; i++) { + addr = __DFIR_CFG_ADDR(i); + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, + "set tx shape dfir: 0x%x: 0x%x\n", addr, param[i]); + rtw89_phy_write32_idx(rtwdev, addr, __DFIR_CFG_MASK, param[i], + phy_idx); + } + +#undef __DECL_DFIR_PARAM +#undef __DFIR_CFG_NR +#undef __DFIR_CFG_MASK +#undef __DECL_CFG_ADDR +} + +static void rtw8851b_set_tx_shape(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + u8 band = chan->band_type; + u8 regd = rtw89_regd_get(rtwdev, band); + u8 tx_shape_cck = rtw89_8851b_tx_shape[band][RTW89_RS_CCK][regd]; + u8 tx_shape_ofdm = rtw89_8851b_tx_shape[band][RTW89_RS_OFDM][regd]; + + if (band == RTW89_BAND_2G) + rtw8851b_bb_set_tx_shape_dfir(rtwdev, chan, tx_shape_cck, phy_idx); + + rtw89_phy_write32_mask(rtwdev, R_DCFO_OPT, B_TXSHAPE_TRIANGULAR_CFG, + tx_shape_ofdm); +} + +static void rtw8851b_set_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx); + rtw8851b_set_tx_shape(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx); +} + +static void rtw8851b_set_txpwr_ctrl(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw8851b_set_txpwr_ref(rtwdev, phy_idx); +} + +static +void rtw8851b_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, + s8 pw_ofst, enum rtw89_mac_idx mac_idx) +{ + u32 reg; + + if (pw_ofst < -16 || pw_ofst > 15) { + rtw89_warn(rtwdev, "[ULTB] Err pwr_offset=%d\n", pw_ofst); + return; + } + + reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_CTRL, mac_idx); + rtw89_write32_set(rtwdev, reg, B_AX_PWR_UL_TB_CTRL_EN); + + reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_1T, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_1T_MASK, pw_ofst); + + pw_ofst = max_t(s8, pw_ofst - 3, -16); + reg = rtw89_mac_reg_by_idx(R_AX_PWR_UL_TB_2T, mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_PWR_UL_TB_2T_MASK, pw_ofst); +} + +static int +rtw8851b_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + int ret; + + ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL2, 0x07763333); + if (ret) + return ret; + + ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_COEXT_CTRL, 0x01ebf000); + if (ret) + return ret; + + ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL0, 0x0002f8ff); + if (ret) + return ret; + + rtw8851b_set_txpwr_ul_tb_offset(rtwdev, 0, phy_idx == RTW89_PHY_1 ? + RTW89_MAC_1 : RTW89_MAC_0); + + return 0; +} + static void rtw8851b_btc_set_rfe(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -1711,6 +1960,11 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .read_phycap = rtw8851b_read_phycap, .fem_setup = NULL, .rfe_gpio = rtw8851b_rfe_gpio, + .power_trim = rtw8851b_power_trim, + .set_txpwr = rtw8851b_set_txpwr, + .set_txpwr_ctrl = rtw8851b_set_txpwr_ctrl, + .init_txpwr_unit = rtw8851b_init_txpwr_unit, + .set_txpwr_ul_tb_offset = rtw8851b_set_txpwr_ul_tb_offset, .pwr_on_func = rtw8851b_pwr_on_func, .pwr_off_func = rtw8851b_pwr_off_func, .fill_txdesc = rtw89_core_fill_txdesc, -- cgit v1.2.3 From 68a2cb6b0669bf96bbb203cbb81e57ad122ded42 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2023 11:14:55 +0800 Subject: wifi: rtw89: 8851b: fill BB related capabilities to chip_info These capabilities include helpers of BT coexistence, RX PPDU status parser, DIG (dynamic initial gain) and CFO (center frequency offset) settings. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230519031500.21087-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 2 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 199 ++++++++++++++++++++++++++ 2 files changed, 201 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index bb609f222019..7c2807345f60 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4398,6 +4398,8 @@ #define B_PATH0_BT_BACKOFF_V1 GENMASK(23, 0) #define R_PATH1_BT_BACKOFF_V1 0x4AEC #define B_PATH1_BT_BACKOFF_V1 GENMASK(23, 0) +#define R_DCFO_COMP_S0_V2 0x4B20 +#define B_DCFO_COMP_S0_MSK_V2 GENMASK(13, 0) #define R_PATH0_TX_CFR 0x4B30 #define B_PATH0_TX_CFR_LGC1 GENMASK(19, 10) #define B_PATH0_TX_CFR_LGC0 GENMASK(9, 0) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index cead009b270d..11282f604f71 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -68,12 +68,63 @@ static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = { NULL}, }; +static const struct rtw89_reg3_def rtw8851b_btc_preagc_en_defs[] = { + {0x46D0, GENMASK(1, 0), 0x3}, + {0x4AD4, GENMASK(31, 0), 0xf}, + {0x4688, GENMASK(23, 16), 0x80}, + {0x4688, GENMASK(31, 24), 0x80}, + {0x4694, GENMASK(7, 0), 0x80}, + {0x4694, GENMASK(15, 8), 0x80}, + {0x4AE4, GENMASK(11, 6), 0x34}, + {0x4AE4, GENMASK(17, 12), 0x0}, + {0x469C, GENMASK(31, 26), 0x34}, +}; + +static DECLARE_PHY_REG3_TBL(rtw8851b_btc_preagc_en_defs); + +static const struct rtw89_reg3_def rtw8851b_btc_preagc_dis_defs[] = { + {0x46D0, GENMASK(1, 0), 0x0}, + {0x4AD4, GENMASK(31, 0), 0x60}, + {0x4688, GENMASK(23, 16), 0x10}, + {0x4690, GENMASK(31, 24), 0x2a}, + {0x4694, GENMASK(15, 8), 0x2a}, + {0x4AE4, GENMASK(11, 6), 0x26}, + {0x4AE4, GENMASK(17, 12), 0x1e}, + {0x469C, GENMASK(31, 26), 0x26}, +}; + +static DECLARE_PHY_REG3_TBL(rtw8851b_btc_preagc_dis_defs); + +static const struct rtw89_reg_def rtw8851b_dcfo_comp = { + R_DCFO_COMP_S0_V2, B_DCFO_COMP_S0_MSK_V2 +}; + static const struct rtw89_xtal_info rtw8851b_xtal_info = { .xcap_reg = R_AX_XTAL_ON_CTRL3, .sc_xo_mask = B_AX_XTAL_SC_XO_A_BLOCK_MASK, .sc_xi_mask = B_AX_XTAL_SC_XI_A_BLOCK_MASK, }; +static const struct rtw89_dig_regs rtw8851b_dig_regs = { + .seg0_pd_reg = R_SEG0R_PD_V1, + .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK, + .pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1, + .p0_lna_init = {R_PATH0_LNA_INIT_V1, B_PATH0_LNA_INIT_IDX_MSK}, + .p1_lna_init = {R_PATH1_LNA_INIT_V1, B_PATH1_LNA_INIT_IDX_MSK}, + .p0_tia_init = {R_PATH0_TIA_INIT_V1, B_PATH0_TIA_INIT_IDX_MSK_V1}, + .p1_tia_init = {R_PATH1_TIA_INIT_V1, B_PATH1_TIA_INIT_IDX_MSK_V1}, + .p0_rxb_init = {R_PATH0_RXB_INIT_V1, B_PATH0_RXB_INIT_IDX_MSK_V1}, + .p1_rxb_init = {R_PATH1_RXB_INIT_V1, B_PATH1_RXB_INIT_IDX_MSK_V1}, + .p0_p20_pagcugc_en = {R_PATH0_P20_FOLLOW_BY_PAGCUGC_V2, + B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p0_s20_pagcugc_en = {R_PATH0_S20_FOLLOW_BY_PAGCUGC_V2, + B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p1_p20_pagcugc_en = {R_PATH1_P20_FOLLOW_BY_PAGCUGC_V2, + B_PATH1_P20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p1_s20_pagcugc_en = {R_PATH1_S20_FOLLOW_BY_PAGCUGC_V2, + B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, +}; + static const struct rtw89_btc_rf_trx_para rtw89_btc_8851b_rf_ul[] = { {255, 0, 0, 7}, /* 0 -> original */ {255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */ @@ -1604,6 +1655,112 @@ rtw8851b_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) return 0; } +static void rtw8851b_bb_ctrl_btc_preagc(struct rtw89_dev *rtwdev, bool bt_en) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + + rtw89_phy_write_reg3_tbl(rtwdev, bt_en ? &rtw8851b_btc_preagc_en_defs_tbl : + &rtw8851b_btc_preagc_dis_defs_tbl); + + if (!bt_en) { + if (chan->band_type == RTW89_BAND_2G) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_LNA6_OP1DB_V1, + B_PATH0_G_LNA6_OP1DB_V1, 0x20); + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_TIA0_LNA6_OP1DB_V1, + B_PATH0_G_TIA0_LNA6_OP1DB_V1, 0x30); + } else { + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_LNA6_OP1DB_V1, + B_PATH0_G_LNA6_OP1DB_V1, 0x1a); + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_TIA0_LNA6_OP1DB_V1, + B_PATH0_G_TIA0_LNA6_OP1DB_V1, 0x2a); + } + } +} + +static void rtw8851b_ctrl_btg(struct rtw89_dev *rtwdev, bool btg) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + + if (btg) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, + B_PATH0_BT_SHARE_V1, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, + B_PATH0_BTG_PATH_V1, 0x1); + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_LNA6_OP1DB_V1, + B_PATH0_G_LNA6_OP1DB_V1, 0x20); + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_TIA0_LNA6_OP1DB_V1, + B_PATH0_G_TIA0_LNA6_OP1DB_V1, 0x30); + rtw89_phy_write32_mask(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x1); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x1); + rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, + B_BT_DYN_DC_EST_EN_MSK, 0x1); + rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x1); + } else { + rtw89_phy_write32_mask(rtwdev, R_PATH0_BT_SHARE_V1, + B_PATH0_BT_SHARE_V1, 0x0); + rtw89_phy_write32_mask(rtwdev, R_PATH0_BTG_PATH_V1, + B_PATH0_BTG_PATH_V1, 0x0); + if (chan->band_type == RTW89_BAND_2G) { + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_LNA6_OP1DB_V1, + B_PATH0_G_LNA6_OP1DB_V1, 0x80); + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_TIA0_LNA6_OP1DB_V1, + B_PATH0_G_TIA0_LNA6_OP1DB_V1, 0x80); + } else { + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_LNA6_OP1DB_V1, + B_PATH0_G_LNA6_OP1DB_V1, 0x1a); + rtw89_phy_write32_mask(rtwdev, R_PATH0_G_TIA0_LNA6_OP1DB_V1, + B_PATH0_G_TIA0_LNA6_OP1DB_V1, 0x2a); + } + rtw89_phy_write32_mask(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0xc); + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_BT_SHARE, 0x0); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_BT_SEG0, 0x0); + rtw89_phy_write32_mask(rtwdev, R_BT_DYN_DC_EST_EN_V1, + B_BT_DYN_DC_EST_EN_MSK, 0x1); + rtw89_phy_write32_mask(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, 0x0); + } +} + +static void rtw8851b_bb_ctrl_rx_path(struct rtw89_dev *rtwdev, + enum rtw89_rf_path_bit rx_path) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + u32 rst_mask0; + + if (rx_path == RF_A) { + rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD_V1, B_ANT_RX_SEG0, 1); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG0, 1); + rtw89_phy_write32_mask(rtwdev, R_FC0_BW_V1, B_ANT_RX_1RCCA_SEG1, 1); + rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 4); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); + } + + rtw8851b_set_gain_offset(rtwdev, chan->subband_type, RTW89_PHY_0); + + rst_mask0 = B_P0_TXPW_RSTB_MANON | B_P0_TXPW_RSTB_TSSI; + if (rx_path == RF_A) { + rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 1); + rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 3); + } +} + +static void rtw8851b_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) +{ + rtw8851b_bb_ctrl_rx_path(rtwdev, RF_A); + + if (rtwdev->hal.rx_nss == 1) { + rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0); + rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0); + } + + rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0x0, RTW89_PHY_0); +} + static void rtw8851b_btc_set_rfe(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -1895,6 +2052,39 @@ static void rtw8851b_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level) } } +static void rtw8851b_fill_freq_with_ppdu(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status) +{ + u16 chan = phy_ppdu->chan_idx; + enum nl80211_band band; + u8 ch; + + if (chan == 0) + return; + + rtw89_decode_chan_idx(rtwdev, chan, &ch, &band); + status->freq = ieee80211_channel_to_frequency(ch, band); + status->band = band; +} + +static void rtw8851b_query_ppdu(struct rtw89_dev *rtwdev, + struct rtw89_rx_phy_ppdu *phy_ppdu, + struct ieee80211_rx_status *status) +{ + u8 path; + u8 *rx_power = phy_ppdu->rssi; + + status->signal = RTW89_RSSI_RAW_TO_DBM(rx_power[RF_PATH_A]); + + for (path = 0; path < rtwdev->chip->rf_path_num; path++) { + status->chains |= BIT(path); + status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]); + } + if (phy_ppdu->valid) + rtw8851b_fill_freq_with_ppdu(rtwdev, phy_ppdu, status); +} + static int rtw8851b_mac_enable_bb_rf(struct rtw89_dev *rtwdev) { int ret; @@ -1964,6 +2154,10 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .set_txpwr = rtw8851b_set_txpwr, .set_txpwr_ctrl = rtw8851b_set_txpwr_ctrl, .init_txpwr_unit = rtw8851b_init_txpwr_unit, + .ctrl_btg = rtw8851b_ctrl_btg, + .query_ppdu = rtw8851b_query_ppdu, + .bb_ctrl_btc_preagc = rtw8851b_bb_ctrl_btc_preagc, + .cfg_txrx_path = rtw8851b_bb_cfg_txrx_path, .set_txpwr_ul_tb_offset = rtw8851b_set_txpwr_ul_tb_offset, .pwr_on_func = rtw8851b_pwr_on_func, .pwr_off_func = rtw8851b_pwr_off_func, @@ -2021,6 +2215,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, .dig_table = NULL, + .dig_regs = &rtw8851b_dig_regs, .tssi_dbw_table = NULL, .support_chanctx_num = 0, .support_bands = BIT(NL80211_BAND_2GHZ) | @@ -2069,6 +2264,10 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .hci_func_en_addr = R_AX_HCI_FUNC_EN, .h2c_desc_size = sizeof(struct rtw89_txwd_body), .txwd_body_size = sizeof(struct rtw89_txwd_body), + .cfo_src_fd = true, + .cfo_hw_comp = true, + .dcfo_comp = &rtw8851b_dcfo_comp, + .dcfo_comp_sft = 12, .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | -- cgit v1.2.3 From 92aa2643235d72bb01206259362d4e0a845ba02a Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2023 11:14:56 +0800 Subject: wifi: rtw89: 8851b: add MAC configurations to chip_info These configurations include path control, TX grant, TX scheduler, register-based H2C/C2H and so on. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230519031500.21087-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 89 +++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 11282f604f71..148cf0074412 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -95,16 +95,92 @@ static const struct rtw89_reg3_def rtw8851b_btc_preagc_dis_defs[] = { static DECLARE_PHY_REG3_TBL(rtw8851b_btc_preagc_dis_defs); +static const u32 rtw8851b_h2c_regs[RTW89_H2CREG_MAX] = { + R_AX_H2CREG_DATA0, R_AX_H2CREG_DATA1, R_AX_H2CREG_DATA2, + R_AX_H2CREG_DATA3 +}; + +static const u32 rtw8851b_c2h_regs[RTW89_C2HREG_MAX] = { + R_AX_C2HREG_DATA0, R_AX_C2HREG_DATA1, R_AX_C2HREG_DATA2, + R_AX_C2HREG_DATA3 +}; + +static const struct rtw89_page_regs rtw8851b_page_regs = { + .hci_fc_ctrl = R_AX_HCI_FC_CTRL, + .ch_page_ctrl = R_AX_CH_PAGE_CTRL, + .ach_page_ctrl = R_AX_ACH0_PAGE_CTRL, + .ach_page_info = R_AX_ACH0_PAGE_INFO, + .pub_page_info3 = R_AX_PUB_PAGE_INFO3, + .pub_page_ctrl1 = R_AX_PUB_PAGE_CTRL1, + .pub_page_ctrl2 = R_AX_PUB_PAGE_CTRL2, + .pub_page_info1 = R_AX_PUB_PAGE_INFO1, + .pub_page_info2 = R_AX_PUB_PAGE_INFO2, + .wp_page_ctrl1 = R_AX_WP_PAGE_CTRL1, + .wp_page_ctrl2 = R_AX_WP_PAGE_CTRL2, + .wp_page_info1 = R_AX_WP_PAGE_INFO1, +}; + static const struct rtw89_reg_def rtw8851b_dcfo_comp = { R_DCFO_COMP_S0_V2, B_DCFO_COMP_S0_MSK_V2 }; +static const struct rtw89_imr_info rtw8851b_imr_info = { + .wdrls_imr_set = B_AX_WDRLS_IMR_SET, + .wsec_imr_reg = R_AX_SEC_DEBUG, + .wsec_imr_set = B_AX_IMR_ERROR, + .mpdu_tx_imr_set = 0, + .mpdu_rx_imr_set = 0, + .sta_sch_imr_set = B_AX_STA_SCHEDULER_IMR_SET, + .txpktctl_imr_b0_reg = R_AX_TXPKTCTL_ERR_IMR_ISR, + .txpktctl_imr_b0_clr = B_AX_TXPKTCTL_IMR_B0_CLR, + .txpktctl_imr_b0_set = B_AX_TXPKTCTL_IMR_B0_SET, + .txpktctl_imr_b1_reg = R_AX_TXPKTCTL_ERR_IMR_ISR_B1, + .txpktctl_imr_b1_clr = B_AX_TXPKTCTL_IMR_B1_CLR, + .txpktctl_imr_b1_set = B_AX_TXPKTCTL_IMR_B1_SET, + .wde_imr_clr = B_AX_WDE_IMR_CLR, + .wde_imr_set = B_AX_WDE_IMR_SET, + .ple_imr_clr = B_AX_PLE_IMR_CLR, + .ple_imr_set = B_AX_PLE_IMR_SET, + .host_disp_imr_clr = B_AX_HOST_DISP_IMR_CLR, + .host_disp_imr_set = B_AX_HOST_DISP_IMR_SET, + .cpu_disp_imr_clr = B_AX_CPU_DISP_IMR_CLR, + .cpu_disp_imr_set = B_AX_CPU_DISP_IMR_SET, + .other_disp_imr_clr = B_AX_OTHER_DISP_IMR_CLR, + .other_disp_imr_set = 0, + .bbrpt_com_err_imr_reg = R_AX_BBRPT_COM_ERR_IMR_ISR, + .bbrpt_chinfo_err_imr_reg = R_AX_BBRPT_CHINFO_ERR_IMR_ISR, + .bbrpt_err_imr_set = 0, + .bbrpt_dfs_err_imr_reg = R_AX_BBRPT_DFS_ERR_IMR_ISR, + .ptcl_imr_clr = B_AX_PTCL_IMR_CLR_ALL, + .ptcl_imr_set = B_AX_PTCL_IMR_SET, + .cdma_imr_0_reg = R_AX_DLE_CTRL, + .cdma_imr_0_clr = B_AX_DLE_IMR_CLR, + .cdma_imr_0_set = B_AX_DLE_IMR_SET, + .cdma_imr_1_reg = 0, + .cdma_imr_1_clr = 0, + .cdma_imr_1_set = 0, + .phy_intf_imr_reg = R_AX_PHYINFO_ERR_IMR, + .phy_intf_imr_clr = 0, + .phy_intf_imr_set = 0, + .rmac_imr_reg = R_AX_RMAC_ERR_ISR, + .rmac_imr_clr = B_AX_RMAC_IMR_CLR, + .rmac_imr_set = B_AX_RMAC_IMR_SET, + .tmac_imr_reg = R_AX_TMAC_ERR_IMR_ISR, + .tmac_imr_clr = B_AX_TMAC_IMR_CLR, + .tmac_imr_set = B_AX_TMAC_IMR_SET, +}; + static const struct rtw89_xtal_info rtw8851b_xtal_info = { .xcap_reg = R_AX_XTAL_ON_CTRL3, .sc_xo_mask = B_AX_XTAL_SC_XO_A_BLOCK_MASK, .sc_xi_mask = B_AX_XTAL_SC_XI_A_BLOCK_MASK, }; +static const struct rtw89_rrsr_cfgs rtw8851b_rrsr_cfgs = { + .ref_rate = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_REF_RATE_SEL, 0}, + .rsc = {R_AX_TRXPTCL_RRSR_CTL_0, B_AX_WMAC_RESP_RSC_MASK, 2}, +}; + static const struct rtw89_dig_regs rtw8851b_dig_regs = { .seg0_pd_reg = R_SEG0R_PD_V1, .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK, @@ -2163,6 +2239,10 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .pwr_off_func = rtw8851b_pwr_off_func, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, + .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, + .mac_cfg_gnt = rtw89_mac_cfg_gnt, + .stop_sch_tx = rtw89_mac_stop_sch_tx, + .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, .btc_set_rfe = rtw8851b_btc_set_rfe, @@ -2264,10 +2344,19 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .hci_func_en_addr = R_AX_HCI_FUNC_EN, .h2c_desc_size = sizeof(struct rtw89_txwd_body), .txwd_body_size = sizeof(struct rtw89_txwd_body), + .h2c_ctrl_reg = R_AX_H2CREG_CTRL, + .h2c_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_H2C_DEQ_CNT_MASK >> 8}, + .h2c_regs = rtw8851b_h2c_regs, + .c2h_ctrl_reg = R_AX_C2HREG_CTRL, + .c2h_counter_reg = {R_AX_UDM1 + 1, B_AX_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, + .c2h_regs = rtw8851b_c2h_regs, + .page_regs = &rtw8851b_page_regs, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = &rtw8851b_dcfo_comp, .dcfo_comp_sft = 12, + .imr_info = &rtw8851b_imr_info, + .rrsr_cfgs = &rtw8851b_rrsr_cfgs, .bss_clr_map_reg = R_BSS_CLR_MAP_V1, .dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) | BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) | -- cgit v1.2.3 From 791af3fb2decc11b2994f7020378dffecd654fcd Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2023 11:14:57 +0800 Subject: wifi: rtw89: 8851b: add RF configurations RF configurations include RF calibrations and getting thermal value. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230519031500.21087-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 61 +++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 148cf0074412..eb98d4adc306 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -1542,6 +1542,44 @@ static void rtw8851b_set_channel_help(struct rtw89_dev *rtwdev, bool enter, } } +static void rtw8851b_rfk_init(struct rtw89_dev *rtwdev) +{ + rtwdev->is_tssi_mode[RF_PATH_A] = false; + rtwdev->is_tssi_mode[RF_PATH_B] = false; + + rtw8851b_dpk_init(rtwdev); + rtw8851b_aack(rtwdev); + rtw8851b_rck(rtwdev); + rtw8851b_dack(rtwdev); + rtw8851b_rx_dck(rtwdev, RTW89_PHY_0); +} + +static void rtw8851b_rfk_channel(struct rtw89_dev *rtwdev) +{ + enum rtw89_phy_idx phy_idx = RTW89_PHY_0; + + rtw8851b_rx_dck(rtwdev, phy_idx); + rtw8851b_iqk(rtwdev, phy_idx); + rtw8851b_tssi(rtwdev, phy_idx, true); + rtw8851b_dpk(rtwdev, phy_idx); +} + +static void rtw8851b_rfk_band_changed(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw8851b_tssi_scan(rtwdev, phy_idx); +} + +static void rtw8851b_rfk_scan(struct rtw89_dev *rtwdev, bool start) +{ + rtw8851b_wifi_scan_notify(rtwdev, start, RTW89_PHY_0); +} + +static void rtw8851b_rfk_track(struct rtw89_dev *rtwdev) +{ + rtw8851b_dpk_track(rtwdev); +} + static u32 rtw8851b_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, s16 ref) { @@ -1837,6 +1875,23 @@ static void rtw8851b_bb_cfg_txrx_path(struct rtw89_dev *rtwdev) rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0x0, RTW89_PHY_0); } +static u8 rtw8851b_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path) +{ + if (rtwdev->is_tssi_mode[rf_path]) { + u32 addr = R_TSSI_THER + (rf_path << 13); + + return rtw89_phy_read32_mask(rtwdev, addr, B_TSSI_THER); + } + + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x0); + rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1); + + fsleep(200); + + return rtw89_read_rf(rtwdev, rf_path, RR_TM, RR_TM_VAL); +} + static void rtw8851b_btc_set_rfe(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -2226,10 +2281,16 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .read_phycap = rtw8851b_read_phycap, .fem_setup = NULL, .rfe_gpio = rtw8851b_rfe_gpio, + .rfk_init = rtw8851b_rfk_init, + .rfk_channel = rtw8851b_rfk_channel, + .rfk_band_changed = rtw8851b_rfk_band_changed, + .rfk_scan = rtw8851b_rfk_scan, + .rfk_track = rtw8851b_rfk_track, .power_trim = rtw8851b_power_trim, .set_txpwr = rtw8851b_set_txpwr, .set_txpwr_ctrl = rtw8851b_set_txpwr_ctrl, .init_txpwr_unit = rtw8851b_init_txpwr_unit, + .get_thermal = rtw8851b_get_thermal, .ctrl_btg = rtw8851b_ctrl_btg, .query_ppdu = rtw8851b_query_ppdu, .bb_ctrl_btc_preagc = rtw8851b_bb_ctrl_btc_preagc, -- cgit v1.2.3 From 4cfad52a5df718a615f8de5ba14370d99537db4c Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2023 11:14:58 +0800 Subject: wifi: rtw89: enlarge supported length of read_reg debugfs entry The register ranges of upcoming chips are different from current, and even existing chips have different ranges, so support longer length to dump registers. Then, user space can decide the ranges according to chip. Since arbitrary length (e.g. 7) would be a little complicated, so simply make length a multiple of 16. The output looks like 18620000h : 8580801f 82828282 82828282 080800fd Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230519031500.21087-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 6f418f14ec3f..39f6b7f5f656 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -30,7 +30,7 @@ struct rtw89_debugfs_priv { u32 cb_data; struct { u32 addr; - u8 len; + u32 len; } read_reg; struct { u32 addr; @@ -164,12 +164,15 @@ static int rtw89_debug_priv_read_reg_get(struct seq_file *m, void *v) { struct rtw89_debugfs_priv *debugfs_priv = m->private; struct rtw89_dev *rtwdev = debugfs_priv->rtwdev; - u32 addr, data; - u8 len; + u32 addr, end, data, k; + u32 len; len = debugfs_priv->read_reg.len; addr = debugfs_priv->read_reg.addr; + if (len > 4) + goto ndata; + switch (len) { case 1: data = rtw89_read8(rtwdev, addr); @@ -187,6 +190,20 @@ static int rtw89_debug_priv_read_reg_get(struct seq_file *m, void *v) seq_printf(m, "get %d bytes at 0x%08x=0x%08x\n", len, addr, data); + return 0; + +ndata: + end = addr + len; + + for (; addr < end; addr += 16) { + seq_printf(m, "%08xh : ", 0x18600000 + addr); + for (k = 0; k < 16; k += 4) { + data = rtw89_read32(rtwdev, addr + k); + seq_printf(m, "%08x ", data); + } + seq_puts(m, "\n"); + } + return 0; } -- cgit v1.2.3 From c4ff50149885723f24ef9bc3b0220ee20bca3e03 Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Fri, 19 May 2023 11:14:59 +0800 Subject: wifi: rtw89: add tx_wake notify for 8851B 8851B has the same issue: management frames get stuck when WiFi chip enters low PS mode, so we also add notify wake function to trigger WiFi chip wake before forwarding management frames. Signed-off-by: Chin-Yen Lee Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230519031500.21087-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index f7d4f9d14736..32a9563e556e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -256,6 +256,7 @@ struct __fw_feat_cfg { } static const struct __fw_feat_cfg fw_feat_tbl[] = { + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), -- cgit v1.2.3 From 14820388aafb10cd051b0883e92326f5f2012ed4 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 19 May 2023 11:15:00 +0800 Subject: wifi: rtw89: 8851b: add 8851be to Makefile and Kconfig Since 8851BE is ready, so add 8851BE to Makefile and Kconfig. Currently, it can support STA, AP and monitor modes with good performance. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230519031500.21087-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/Kconfig | 14 ++++++++++++++ drivers/net/wireless/realtek/rtw89/Makefile | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/Kconfig b/drivers/net/wireless/realtek/rtw89/Kconfig index 2b20cf8bbf3a..90ffbab7cc4c 100644 --- a/drivers/net/wireless/realtek/rtw89/Kconfig +++ b/drivers/net/wireless/realtek/rtw89/Kconfig @@ -16,6 +16,9 @@ config RTW89_CORE config RTW89_PCI tristate +config RTW89_8851B + tristate + config RTW89_8852A tristate @@ -25,6 +28,17 @@ config RTW89_8852B config RTW89_8852C tristate +config RTW89_8851BE + tristate "Realtek 8851BE PCI wireless network (Wi-Fi 6) adapter" + depends on PCI + select RTW89_CORE + select RTW89_PCI + select RTW89_8851B + help + Select this option will enable support for 8851BE chipset + + 802.11ax PCIe wireless network (Wi-Fi 6) adapter + config RTW89_8852AE tristate "Realtek 8852AE PCI wireless network (Wi-Fi 6) adapter" depends on PCI diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index 99e870d6a7d7..41940099af1b 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -18,6 +18,15 @@ rtw89_core-y += core.o \ rtw89_core-$(CONFIG_PM) += wow.o +obj-$(CONFIG_RTW89_8851B) += rtw89_8851b.o +rtw89_8851b-objs := rtw8851b.o \ + rtw8851b_table.o \ + rtw8851b_rfk.o \ + rtw8851b_rfk_table.o + +obj-$(CONFIG_RTW89_8851BE) += rtw89_8851be.o +rtw89_8851be-objs := rtw8851be.o + obj-$(CONFIG_RTW89_8852A) += rtw89_8852a.o rtw89_8852a-objs := rtw8852a.o \ rtw8852a_table.o \ -- cgit v1.2.3 From de9f93385d0f318b3eba0c1026fd2ec8fba2e982 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 22 May 2023 20:25:09 +0800 Subject: wifi: rtw89: add chip_ops::query_rxdesc() and rxd_len as helpers to support newer chips The next generation chips use different RX descriptor format, so add a chip_ops to hook suitable handlers. Also, the length of RX descriptor is different, so add a variable to store the length according to chip and descriptor content dynamically. Then, the code can be more general. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522122513.13559-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 4 ++++ drivers/net/wireless/realtek/rtw89/core.h | 14 ++++++++++++++ drivers/net/wireless/realtek/rtw89/pci.c | 12 ++++-------- drivers/net/wireless/realtek/rtw89/rtw8851b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852b.c | 1 + drivers/net/wireless/realtek/rtw89/rtw8852c.c | 1 + 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index fbcb9b6e6f75..ae547b38dfaa 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1819,6 +1819,10 @@ void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev, shift_len = desc_info->shift << 1; /* 2-byte unit */ drv_info_len = desc_info->drv_info_size << 3; /* 8-byte unit */ desc_info->offset = data_offset + shift_len + drv_info_len; + if (desc_info->long_rxdesc) + desc_info->rxd_len = sizeof(struct rtw89_rxdesc_long); + else + desc_info->rxd_len = sizeof(struct rtw89_rxdesc_short); desc_info->ready = true; if (!desc_info->long_rxdesc) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ce6fc18dbfc7..7b0e780c8a02 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -776,6 +776,7 @@ struct rtw89_rx_desc_info { u8 sec_cam_id; u8 mac_id; u16 offset; + u16 rxd_len; bool ready; }; @@ -2824,6 +2825,9 @@ struct rtw89_chip_ops { s8 pw_ofst, enum rtw89_mac_idx mac_idx); int (*pwr_on_func)(struct rtw89_dev *rtwdev); int (*pwr_off_func)(struct rtw89_dev *rtwdev); + void (*query_rxdesc)(struct rtw89_dev *rtwdev, + struct rtw89_rx_desc_info *desc_info, + u8 *data, u32 data_offset); void (*fill_txdesc)(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); @@ -4855,6 +4859,16 @@ static inline void rtw89_ctrl_btg(struct rtw89_dev *rtwdev, bool btg) chip->ops->ctrl_btg(rtwdev, btg); } +static inline +void rtw89_chip_query_rxdesc(struct rtw89_dev *rtwdev, + struct rtw89_rx_desc_info *desc_info, + u8 *data, u32 data_offset) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + chip->ops->query_rxdesc(rtwdev, desc_info, data, data_offset); +} + static inline void rtw89_chip_fill_txdesc(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 92bfef942d3a..9402f1a0caea 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -265,7 +265,7 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, goto err_sync_device; } - rtw89_core_query_rxdesc(rtwdev, desc_info, skb->data, rxinfo_size); + rtw89_chip_query_rxdesc(rtwdev, desc_info, skb->data, rxinfo_size); new = rtw89_alloc_skb_for_rx(rtwdev, desc_info->pkt_size); if (!new) @@ -274,9 +274,7 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev, rx_ring->diliver_skb = new; /* first segment has RX desc */ - offset = desc_info->offset; - offset += desc_info->long_rxdesc ? sizeof(struct rtw89_rxdesc_long) : - sizeof(struct rtw89_rxdesc_short); + offset = desc_info->offset + desc_info->rxd_len; } else { offset = sizeof(struct rtw89_pci_rxbd_info); if (!new) { @@ -546,12 +544,10 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev, return cnt; } - rtw89_core_query_rxdesc(rtwdev, &desc_info, skb->data, rxinfo_size); + rtw89_chip_query_rxdesc(rtwdev, &desc_info, skb->data, rxinfo_size); /* first segment has RX desc */ - offset = desc_info.offset; - offset += desc_info.long_rxdesc ? sizeof(struct rtw89_rxdesc_long) : - sizeof(struct rtw89_rxdesc_short); + offset = desc_info.offset + desc_info.rxd_len; for (; offset + rpp_size <= rx_info->len; offset += rpp_size) { rpp = (struct rtw89_pci_rpp_fmt *)(skb->data + offset); rtw89_pci_release_rpp(rtwdev, rpp); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index eb98d4adc306..c4254e051be0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -2298,6 +2298,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .set_txpwr_ul_tb_offset = rtw8851b_set_txpwr_ul_tb_offset, .pwr_on_func = rtw8851b_pwr_on_func, .pwr_off_func = rtw8851b_pwr_off_func, + .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 541ad2f4b0c2..559835ce86bb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2050,6 +2050,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .set_txpwr_ul_tb_offset = rtw8852a_set_txpwr_ul_tb_offset, .pwr_on_func = NULL, .pwr_off_func = NULL, + .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index 4e4023f114ec..2a143751abc5 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -2472,6 +2472,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .set_txpwr_ul_tb_offset = rtw8852b_set_txpwr_ul_tb_offset, .pwr_on_func = rtw8852b_pwr_on_func, .pwr_off_func = rtw8852b_pwr_off_func, + .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index e4c984c87d6c..9c7c9812d4f4 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2780,6 +2780,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .set_txpwr_ul_tb_offset = rtw8852c_set_txpwr_ul_tb_offset, .pwr_on_func = rtw8852c_pwr_on_func, .pwr_off_func = rtw8852c_pwr_off_func, + .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc_v1, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc_fwcmd_v1, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path_v1, -- cgit v1.2.3 From 88bdc3ff956cd9267777ae8557de46bbf2d49e32 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 22 May 2023 20:25:10 +0800 Subject: wifi: rtw89: use struct and le32_get_bits to access RX info If received packet type is PPDU status, RX info provides information attached by MAC hardware, and mention how long BB information attached. This conversion patch doesn't change logic at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522122513.13559-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 7 ++-- drivers/net/wireless/realtek/rtw89/txrx.h | 53 +++++++++++++++---------------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index ae547b38dfaa..c92a83bf2f36 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1213,14 +1213,15 @@ static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_rx_phy_ppdu *phy_ppdu) { + const struct rtw89_rxinfo *rxinfo = (const struct rtw89_rxinfo *)skb->data; bool rx_cnt_valid = false; u8 plcp_size = 0; u8 usr_num = 0; u8 *phy_sts; - rx_cnt_valid = RTW89_GET_RXINFO_RX_CNT_VLD(skb->data); - plcp_size = RTW89_GET_RXINFO_PLCP_LEN(skb->data) << 3; - usr_num = RTW89_GET_RXINFO_USR_NUM(skb->data); + rx_cnt_valid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_RX_CNT_VLD); + plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3; + usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM); if (usr_num > RTW89_PPDU_MAX_USR) { rtw89_warn(rtwdev, "Invalid user number in mac info\n"); return -EINVAL; diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index d880ecb879ca..d096d16c8d3b 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -251,34 +251,31 @@ #define RTW89_GET_RXWD_SEC_CAM_ID(rxdesc) \ le32_get_bits((rxdesc)->dword5, GENMASK(7, 0)) -#define RTW89_GET_RXINFO_USR_NUM(rpt) \ - le32_get_bits(*((const __le32 *)rpt), GENMASK(3, 0)) -#define RTW89_GET_RXINFO_FW_DEFINE(rpt) \ - le32_get_bits(*((const __le32 *)rpt), GENMASK(15, 8)) -#define RTW89_GET_RXINFO_LSIG_LEN(rpt) \ - le32_get_bits(*((const __le32 *)rpt), GENMASK(27, 16)) -#define RTW89_GET_RXINFO_IS_TO_SELF(rpt) \ - le32_get_bits(*((const __le32 *)rpt), BIT(28)) -#define RTW89_GET_RXINFO_RX_CNT_VLD(rpt) \ - le32_get_bits(*((const __le32 *)rpt), BIT(29)) -#define RTW89_GET_RXINFO_LONG_RXD(rpt) \ - le32_get_bits(*((const __le32 *)rpt), GENMASK(31, 30)) -#define RTW89_GET_RXINFO_SERVICE(rpt) \ - le32_get_bits(*((const __le32 *)(rpt) + 1), GENMASK(15, 0)) -#define RTW89_GET_RXINFO_PLCP_LEN(rpt) \ - le32_get_bits(*((const __le32 *)(rpt) + 1), GENMASK(23, 16)) -#define RTW89_GET_RXINFO_MAC_ID_VALID(rpt, usr) \ - le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(0)) -#define RTW89_GET_RXINFO_DATA(rpt, usr) \ - le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(1)) -#define RTW89_GET_RXINFO_CTRL(rpt, usr) \ - le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(2)) -#define RTW89_GET_RXINFO_MGMT(rpt, usr) \ - le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(3)) -#define RTW89_GET_RXINFO_BCM(rpt, usr) \ - le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), BIT(4)) -#define RTW89_GET_RXINFO_MACID(rpt, usr) \ - le32_get_bits(*((const __le32 *)(rpt) + (usr) + 2), GENMASK(15, 8)) +struct rtw89_rxinfo_user { + __le32 w0; +}; + +#define RTW89_RXINFO_USER_MAC_ID_VALID BIT(0) +#define RTW89_RXINFO_USER_DATA BIT(1) +#define RTW89_RXINFO_USER_CTRL BIT(2) +#define RTW89_RXINFO_USER_MGMT BIT(3) +#define RTW89_RXINFO_USER_BCM BIT(4) +#define RTW89_RXINFO_USER_MACID GENMASK(15, 8) + +struct rtw89_rxinfo { + __le32 w0; + __le32 w1; + struct rtw89_rxinfo_user user[]; +} __packed; + +#define RTW89_RXINFO_W0_USR_NUM GENMASK(3, 0) +#define RTW89_RXINFO_W0_FW_DEFINE GENMASK(15, 8) +#define RTW89_RXINFO_W0_LSIG_LEN GENMASK(27, 16) +#define RTW89_RXINFO_W0_IS_TO_SELF BIT(28) +#define RTW89_RXINFO_W0_RX_CNT_VLD BIT(29) +#define RTW89_RXINFO_W0_LONG_RXD GENMASK(31, 30) +#define RTW89_RXINFO_W1_SERVICE GENMASK(15, 0) +#define RTW89_RXINFO_W1_PLCP_LEN GENMASK(23, 16) #define RTW89_GET_PHY_STS_IE_MAP(sts) \ le32_get_bits(*((const __le32 *)(sts)), GENMASK(4, 0)) -- cgit v1.2.3 From 332debb80488e98f6083238bdf61e6f953d5c180 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 22 May 2023 20:25:11 +0800 Subject: wifi: rtw89: use struct and le32_get_bits() to access received PHY status IEs PHY status IEs generated by BB hardware is to provide more detail information related to received packets, such as RSSI and bandwidth. To avoid type casting, change buf type from u8* to void* as well. This patch doesn't change logic at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522122513.13559-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 53 +++++++++++++++++++------------ drivers/net/wireless/realtek/rtw89/core.h | 2 +- drivers/net/wireless/realtek/rtw89/txrx.h | 37 ++++++++++----------- 3 files changed, 52 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index c92a83bf2f36..5a52815fc607 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1280,7 +1280,8 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data, #define VAR_LEN 0xff #define VAR_LEN_UNIT 8 -static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, u8 *addr) +static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, + const struct rtw89_phy_sts_iehdr *iehdr) { static const u8 physts_ie_len_tab[32] = { 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, @@ -1290,19 +1291,20 @@ static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, u8 *addr) u16 ie_len; u8 ie; - ie = RTW89_GET_PHY_STS_IE_TYPE(addr); + ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE); if (physts_ie_len_tab[ie] != VAR_LEN) ie_len = physts_ie_len_tab[ie]; else - ie_len = RTW89_GET_PHY_STS_IE_LEN(addr) * VAR_LEN_UNIT; + ie_len = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_LEN) * VAR_LEN_UNIT; return ie_len; } -static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev, u8 *addr, +static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev, + const struct rtw89_phy_sts_iehdr *iehdr, struct rtw89_rx_phy_ppdu *phy_ppdu) { - const struct rtw89_phy_sts_ie0 *ie = (const struct rtw89_phy_sts_ie0 *)addr; + const struct rtw89_phy_sts_ie0 *ie = (const struct rtw89_phy_sts_ie0 *)iehdr; s16 cfo; u32 t; @@ -1330,15 +1332,17 @@ static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev, u8 *addr, rtw89_phy_cfo_parse(rtwdev, cfo, phy_ppdu); } -static int rtw89_core_process_phy_status_ie(struct rtw89_dev *rtwdev, u8 *addr, +static int rtw89_core_process_phy_status_ie(struct rtw89_dev *rtwdev, + const struct rtw89_phy_sts_iehdr *iehdr, struct rtw89_rx_phy_ppdu *phy_ppdu) { u8 ie; - ie = RTW89_GET_PHY_STS_IE_TYPE(addr); + ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE); + switch (ie) { case RTW89_PHYSTS_IE01_CMN_OFDM: - rtw89_core_parse_phy_status_ie01(rtwdev, addr, phy_ppdu); + rtw89_core_parse_phy_status_ie01(rtwdev, iehdr, phy_ppdu); break; default: break; @@ -1349,21 +1353,26 @@ static int rtw89_core_process_phy_status_ie(struct rtw89_dev *rtwdev, u8 *addr, static void rtw89_core_update_phy_ppdu(struct rtw89_rx_phy_ppdu *phy_ppdu) { + const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf; u8 *rssi = phy_ppdu->rssi; - u8 *buf = phy_ppdu->buf; - phy_ppdu->ie = RTW89_GET_PHY_STS_IE_MAP(buf); - phy_ppdu->rssi_avg = RTW89_GET_PHY_STS_RSSI_AVG(buf); - rssi[RF_PATH_A] = RTW89_GET_PHY_STS_RSSI_A(buf); - rssi[RF_PATH_B] = RTW89_GET_PHY_STS_RSSI_B(buf); - rssi[RF_PATH_C] = RTW89_GET_PHY_STS_RSSI_C(buf); - rssi[RF_PATH_D] = RTW89_GET_PHY_STS_RSSI_D(buf); + phy_ppdu->ie = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_IE_MAP); + phy_ppdu->rssi_avg = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_RSSI_AVG); + rssi[RF_PATH_A] = le32_get_bits(hdr->w1, RTW89_PHY_STS_HDR_W1_RSSI_A); + rssi[RF_PATH_B] = le32_get_bits(hdr->w1, RTW89_PHY_STS_HDR_W1_RSSI_B); + rssi[RF_PATH_C] = le32_get_bits(hdr->w1, RTW89_PHY_STS_HDR_W1_RSSI_C); + rssi[RF_PATH_D] = le32_get_bits(hdr->w1, RTW89_PHY_STS_HDR_W1_RSSI_D); } static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu) { - if (RTW89_GET_PHY_STS_LEN(phy_ppdu->buf) << 3 != phy_ppdu->len) { + const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf; + u32 len_from_header; + + len_from_header = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_LEN) << 3; + + if (len_from_header != phy_ppdu->len) { rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "phy ppdu len mismatch\n"); return -EINVAL; } @@ -1376,17 +1385,19 @@ static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu) { u16 ie_len; - u8 *pos, *end; + void *pos, *end; /* mark invalid reports and bypass them */ if (phy_ppdu->ie < RTW89_CCK_PKT) return -EINVAL; - pos = (u8 *)phy_ppdu->buf + PHY_STS_HDR_LEN; - end = (u8 *)phy_ppdu->buf + phy_ppdu->len; + pos = phy_ppdu->buf + PHY_STS_HDR_LEN; + end = phy_ppdu->buf + phy_ppdu->len; while (pos < end) { - ie_len = rtw89_core_get_phy_status_ie_len(rtwdev, pos); - rtw89_core_process_phy_status_ie(rtwdev, pos, phy_ppdu); + const struct rtw89_phy_sts_iehdr *iehdr = pos; + + ie_len = rtw89_core_get_phy_status_ie_len(rtwdev, iehdr); + rtw89_core_process_phy_status_ie(rtwdev, iehdr, phy_ppdu); pos += ie_len; if (pos > end || ie_len == 0) { rtw89_debug(rtwdev, RTW89_DBG_TXRX, diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7b0e780c8a02..6e807fa571c7 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -550,7 +550,7 @@ struct rtw89_rate_desc { #define RF_PATH_MAX 4 #define RTW89_MAX_PPDU_CNT 8 struct rtw89_rx_phy_ppdu { - u8 *buf; + void *buf; u32 len; u8 rssi_avg; u8 rssi[RF_PATH_MAX]; diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index d096d16c8d3b..5f20656aa1ad 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -277,24 +277,25 @@ struct rtw89_rxinfo { #define RTW89_RXINFO_W1_SERVICE GENMASK(15, 0) #define RTW89_RXINFO_W1_PLCP_LEN GENMASK(23, 16) -#define RTW89_GET_PHY_STS_IE_MAP(sts) \ - le32_get_bits(*((const __le32 *)(sts)), GENMASK(4, 0)) -#define RTW89_GET_PHY_STS_RSSI_A(sts) \ - le32_get_bits(*((const __le32 *)(sts) + 1), GENMASK(7, 0)) -#define RTW89_GET_PHY_STS_RSSI_B(sts) \ - le32_get_bits(*((const __le32 *)(sts) + 1), GENMASK(15, 8)) -#define RTW89_GET_PHY_STS_RSSI_C(sts) \ - le32_get_bits(*((const __le32 *)(sts) + 1), GENMASK(23, 16)) -#define RTW89_GET_PHY_STS_RSSI_D(sts) \ - le32_get_bits(*((const __le32 *)(sts) + 1), GENMASK(31, 24)) -#define RTW89_GET_PHY_STS_LEN(sts) \ - le32_get_bits(*((const __le32 *)sts), GENMASK(15, 8)) -#define RTW89_GET_PHY_STS_RSSI_AVG(sts) \ - le32_get_bits(*((const __le32 *)sts), GENMASK(31, 24)) -#define RTW89_GET_PHY_STS_IE_TYPE(ie) \ - le32_get_bits(*((const __le32 *)ie), GENMASK(4, 0)) -#define RTW89_GET_PHY_STS_IE_LEN(ie) \ - le32_get_bits(*((const __le32 *)ie), GENMASK(11, 5)) +struct rtw89_phy_sts_hdr { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_PHY_STS_HDR_W0_IE_MAP GENMASK(4, 0) +#define RTW89_PHY_STS_HDR_W0_LEN GENMASK(15, 8) +#define RTW89_PHY_STS_HDR_W0_RSSI_AVG GENMASK(31, 24) +#define RTW89_PHY_STS_HDR_W1_RSSI_A GENMASK(7, 0) +#define RTW89_PHY_STS_HDR_W1_RSSI_B GENMASK(15, 8) +#define RTW89_PHY_STS_HDR_W1_RSSI_C GENMASK(23, 16) +#define RTW89_PHY_STS_HDR_W1_RSSI_D GENMASK(31, 24) + +struct rtw89_phy_sts_iehdr { + __le32 w0; +}; + +#define RTW89_PHY_STS_IEHDR_TYPE GENMASK(4, 0) +#define RTW89_PHY_STS_IEHDR_LEN GENMASK(11, 5) struct rtw89_phy_sts_ie0 { __le32 w0; -- cgit v1.2.3 From c26700d2df01d084ee904ca872fd4db67e772c6f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 22 May 2023 20:25:12 +0800 Subject: wifi: rtw89: use struct and le32_get_bits() to access RX descriptor RX descriptor is to provide basic and important information related to packets, such as packet size, security, MAC ID and so on. Change to use struct to access these fields, and not change logic at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522122513.13559-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 50 ++++++++++++------------ drivers/net/wireless/realtek/rtw89/txrx.h | 65 ------------------------------- 2 files changed, 25 insertions(+), 90 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 5a52815fc607..101047686fff 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1806,27 +1806,27 @@ void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev, u8 shift_len, drv_info_len; rxd_s = (struct rtw89_rxdesc_short *)(data + data_offset); - desc_info->pkt_size = RTW89_GET_RXWD_PKT_SIZE(rxd_s); - desc_info->drv_info_size = RTW89_GET_RXWD_DRV_INFO_SIZE(rxd_s); - desc_info->long_rxdesc = RTW89_GET_RXWD_LONG_RXD(rxd_s); - desc_info->pkt_type = RTW89_GET_RXWD_RPKT_TYPE(rxd_s); - desc_info->mac_info_valid = RTW89_GET_RXWD_MAC_INFO_VALID(rxd_s); + desc_info->pkt_size = le32_get_bits(rxd_s->dword0, AX_RXD_RPKT_LEN_MASK); + desc_info->drv_info_size = le32_get_bits(rxd_s->dword0, AX_RXD_DRV_INFO_SIZE_MASK); + desc_info->long_rxdesc = le32_get_bits(rxd_s->dword0, AX_RXD_LONG_RXD); + desc_info->pkt_type = le32_get_bits(rxd_s->dword0, AX_RXD_RPKT_TYPE_MASK); + desc_info->mac_info_valid = le32_get_bits(rxd_s->dword0, AX_RXD_MAC_INFO_VLD); if (chip->chip_id == RTL8852C) - desc_info->bw = RTW89_GET_RXWD_BW_V1(rxd_s); + desc_info->bw = le32_get_bits(rxd_s->dword1, AX_RXD_BW_v1_MASK); else - desc_info->bw = RTW89_GET_RXWD_BW(rxd_s); - desc_info->data_rate = RTW89_GET_RXWD_DATA_RATE(rxd_s); - desc_info->gi_ltf = RTW89_GET_RXWD_GI_LTF(rxd_s); - desc_info->user_id = RTW89_GET_RXWD_USER_ID(rxd_s); - desc_info->sr_en = RTW89_GET_RXWD_SR_EN(rxd_s); - desc_info->ppdu_cnt = RTW89_GET_RXWD_PPDU_CNT(rxd_s); - desc_info->ppdu_type = RTW89_GET_RXWD_PPDU_TYPE(rxd_s); - desc_info->free_run_cnt = RTW89_GET_RXWD_FREE_RUN_CNT(rxd_s); - desc_info->icv_err = RTW89_GET_RXWD_ICV_ERR(rxd_s); - desc_info->crc32_err = RTW89_GET_RXWD_CRC32_ERR(rxd_s); - desc_info->hw_dec = RTW89_GET_RXWD_HW_DEC(rxd_s); - desc_info->sw_dec = RTW89_GET_RXWD_SW_DEC(rxd_s); - desc_info->addr1_match = RTW89_GET_RXWD_A1_MATCH(rxd_s); + desc_info->bw = le32_get_bits(rxd_s->dword1, AX_RXD_BW_MASK); + desc_info->data_rate = le32_get_bits(rxd_s->dword1, AX_RXD_RX_DATARATE_MASK); + desc_info->gi_ltf = le32_get_bits(rxd_s->dword1, AX_RXD_RX_GI_LTF_MASK); + desc_info->user_id = le32_get_bits(rxd_s->dword1, AX_RXD_USER_ID_MASK); + desc_info->sr_en = le32_get_bits(rxd_s->dword1, AX_RXD_SR_EN); + desc_info->ppdu_cnt = le32_get_bits(rxd_s->dword1, AX_RXD_PPDU_CNT_MASK); + desc_info->ppdu_type = le32_get_bits(rxd_s->dword1, AX_RXD_PPDU_TYPE_MASK); + desc_info->free_run_cnt = le32_get_bits(rxd_s->dword2, AX_RXD_FREERUN_CNT_MASK); + desc_info->icv_err = le32_get_bits(rxd_s->dword3, AX_RXD_ICV_ERR); + desc_info->crc32_err = le32_get_bits(rxd_s->dword3, AX_RXD_CRC32_ERR); + desc_info->hw_dec = le32_get_bits(rxd_s->dword3, AX_RXD_HW_DEC); + desc_info->sw_dec = le32_get_bits(rxd_s->dword3, AX_RXD_SW_DEC); + desc_info->addr1_match = le32_get_bits(rxd_s->dword3, AX_RXD_A1_MATCH); shift_len = desc_info->shift << 1; /* 2-byte unit */ drv_info_len = desc_info->drv_info_size << 3; /* 8-byte unit */ @@ -1841,12 +1841,12 @@ void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev, return; rxd_l = (struct rtw89_rxdesc_long *)(data + data_offset); - desc_info->frame_type = RTW89_GET_RXWD_TYPE(rxd_l); - desc_info->addr_cam_valid = RTW89_GET_RXWD_ADDR_CAM_VLD(rxd_l); - desc_info->addr_cam_id = RTW89_GET_RXWD_ADDR_CAM_ID(rxd_l); - desc_info->sec_cam_id = RTW89_GET_RXWD_SEC_CAM_ID(rxd_l); - desc_info->mac_id = RTW89_GET_RXWD_MAC_ID(rxd_l); - desc_info->rx_pl_id = RTW89_GET_RXWD_RX_PL_ID(rxd_l); + desc_info->frame_type = le32_get_bits(rxd_l->dword4, AX_RXD_TYPE_MASK); + desc_info->addr_cam_valid = le32_get_bits(rxd_l->dword5, AX_RXD_ADDR_CAM_VLD); + desc_info->addr_cam_id = le32_get_bits(rxd_l->dword5, AX_RXD_ADDR_CAM_MASK); + desc_info->sec_cam_id = le32_get_bits(rxd_l->dword5, AX_RXD_SEC_CAM_IDX_MASK); + desc_info->mac_id = le32_get_bits(rxd_l->dword5, AX_RXD_MAC_ID_MASK); + desc_info->rx_pl_id = le32_get_bits(rxd_l->dword5, AX_RXD_RX_PL_ID_MASK); } EXPORT_SYMBOL(rtw89_core_query_rxdesc); diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 5f20656aa1ad..ec96da36eacc 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -186,71 +186,6 @@ #define AX_RXD_BIP_KEYID BIT(27) #define AX_RXD_BIP_ENC BIT(28) -/* RX DESC helpers */ -/* Short Descriptor */ -#define RTW89_GET_RXWD_LONG_RXD(rxdesc) \ - le32_get_bits((rxdesc)->dword0, BIT(31)) -#define RTW89_GET_RXWD_DRV_INFO_SIZE(rxdesc) \ - le32_get_bits((rxdesc)->dword0, GENMASK(30, 28)) -#define RTW89_GET_RXWD_RPKT_TYPE(rxdesc) \ - le32_get_bits((rxdesc)->dword0, GENMASK(27, 24)) -#define RTW89_GET_RXWD_MAC_INFO_VALID(rxdesc) \ - le32_get_bits((rxdesc)->dword0, BIT(23)) -#define RTW89_GET_RXWD_BB_SEL(rxdesc) \ - le32_get_bits((rxdesc)->dword0, BIT(22)) -#define RTW89_GET_RXWD_HD_IV_LEN(rxdesc) \ - le32_get_bits((rxdesc)->dword0, GENMASK(21, 16)) -#define RTW89_GET_RXWD_SHIFT(rxdesc) \ - le32_get_bits((rxdesc)->dword0, GENMASK(15, 14)) -#define RTW89_GET_RXWD_PKT_SIZE(rxdesc) \ - le32_get_bits((rxdesc)->dword0, GENMASK(13, 0)) -#define RTW89_GET_RXWD_BW(rxdesc) \ - le32_get_bits((rxdesc)->dword1, GENMASK(31, 30)) -#define RTW89_GET_RXWD_BW_V1(rxdesc) \ - le32_get_bits((rxdesc)->dword1, GENMASK(31, 29)) -#define RTW89_GET_RXWD_GI_LTF(rxdesc) \ - le32_get_bits((rxdesc)->dword1, GENMASK(27, 25)) -#define RTW89_GET_RXWD_DATA_RATE(rxdesc) \ - le32_get_bits((rxdesc)->dword1, GENMASK(24, 16)) -#define RTW89_GET_RXWD_USER_ID(rxdesc) \ - le32_get_bits((rxdesc)->dword1, GENMASK(15, 8)) -#define RTW89_GET_RXWD_SR_EN(rxdesc) \ - le32_get_bits((rxdesc)->dword1, BIT(7)) -#define RTW89_GET_RXWD_PPDU_CNT(rxdesc) \ - le32_get_bits((rxdesc)->dword1, GENMASK(6, 4)) -#define RTW89_GET_RXWD_PPDU_TYPE(rxdesc) \ - le32_get_bits((rxdesc)->dword1, GENMASK(3, 0)) -#define RTW89_GET_RXWD_FREE_RUN_CNT(rxdesc) \ - le32_get_bits((rxdesc)->dword2, GENMASK(31, 0)) -#define RTW89_GET_RXWD_ICV_ERR(rxdesc) \ - le32_get_bits((rxdesc)->dword3, BIT(10)) -#define RTW89_GET_RXWD_CRC32_ERR(rxdesc) \ - le32_get_bits((rxdesc)->dword3, BIT(9)) -#define RTW89_GET_RXWD_HW_DEC(rxdesc) \ - le32_get_bits((rxdesc)->dword3, BIT(2)) -#define RTW89_GET_RXWD_SW_DEC(rxdesc) \ - le32_get_bits((rxdesc)->dword3, BIT(1)) -#define RTW89_GET_RXWD_A1_MATCH(rxdesc) \ - le32_get_bits((rxdesc)->dword3, BIT(0)) - -/* Long Descriptor */ -#define RTW89_GET_RXWD_FRAG(rxdesc) \ - le32_get_bits((rxdesc)->dword4, GENMASK(31, 28)) -#define RTW89_GET_RXWD_SEQ(rxdesc) \ - le32_get_bits((rxdesc)->dword4, GENMASK(27, 16)) -#define RTW89_GET_RXWD_TYPE(rxdesc) \ - le32_get_bits((rxdesc)->dword4, GENMASK(1, 0)) -#define RTW89_GET_RXWD_ADDR_CAM_VLD(rxdesc) \ - le32_get_bits((rxdesc)->dword5, BIT(28)) -#define RTW89_GET_RXWD_RX_PL_ID(rxdesc) \ - le32_get_bits((rxdesc)->dword5, GENMASK(27, 24)) -#define RTW89_GET_RXWD_MAC_ID(rxdesc) \ - le32_get_bits((rxdesc)->dword5, GENMASK(23, 16)) -#define RTW89_GET_RXWD_ADDR_CAM_ID(rxdesc) \ - le32_get_bits((rxdesc)->dword5, GENMASK(15, 8)) -#define RTW89_GET_RXWD_SEC_CAM_ID(rxdesc) \ - le32_get_bits((rxdesc)->dword5, GENMASK(7, 0)) - struct rtw89_rxinfo_user { __le32 w0; }; -- cgit v1.2.3 From 68012b44dfc723a114748a5e67f98a99b2943852 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 22 May 2023 20:25:13 +0800 Subject: wifi: rtw89: use struct to access register-based H2C/C2H The register-based H2C/C2H are used to exchange commands and events with firmware. The exchange data is limited, but it is relatively simple, because it can work before HCI initialization. To make these code clean, use struct to access them. This patch doesn't change logic at all. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522122513.13559-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 18 +++--- drivers/net/wireless/realtek/rtw89/fw.h | 102 ++++++++++++++++--------------- drivers/net/wireless/realtek/rtw89/mac.c | 23 ++++--- 3 files changed, 77 insertions(+), 66 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 32a9563e556e..f7f40a261c96 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -2917,12 +2917,13 @@ static int rtw89_fw_write_h2c_reg(struct rtw89_dev *rtwdev, } len = DIV_ROUND_UP(info->content_len + RTW89_H2CREG_HDR_LEN, - sizeof(info->h2creg[0])); + sizeof(info->u.h2creg[0])); + + u32p_replace_bits(&info->u.hdr.w0, info->id, RTW89_H2CREG_HDR_FUNC_MASK); + u32p_replace_bits(&info->u.hdr.w0, len, RTW89_H2CREG_HDR_LEN_MASK); - RTW89_SET_H2CREG_HDR_FUNC(&info->h2creg[0], info->id); - RTW89_SET_H2CREG_HDR_LEN(&info->h2creg[0], len); for (i = 0; i < RTW89_H2CREG_MAX; i++) - rtw89_write32(rtwdev, h2c_reg[i], info->h2creg[i]); + rtw89_write32(rtwdev, h2c_reg[i], info->u.h2creg[i]); fw_info->h2c_counter++; rtw89_write8_mask(rtwdev, chip->h2c_counter_reg.addr, @@ -2952,13 +2953,14 @@ static int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev, } for (i = 0; i < RTW89_C2HREG_MAX; i++) - info->c2hreg[i] = rtw89_read32(rtwdev, c2h_reg[i]); + info->u.c2hreg[i] = rtw89_read32(rtwdev, c2h_reg[i]); rtw89_write8(rtwdev, chip->c2h_ctrl_reg, 0); - info->id = RTW89_GET_C2H_HDR_FUNC(*info->c2hreg); - info->content_len = (RTW89_GET_C2H_HDR_LEN(*info->c2hreg) << 2) - - RTW89_C2HREG_HDR_LEN; + info->id = u32_get_bits(info->u.hdr.w0, RTW89_C2HREG_HDR_FUNC_MASK); + info->content_len = + (u32_get_bits(info->u.hdr.w0, RTW89_C2HREG_HDR_LEN_MASK) << 2) - + RTW89_C2HREG_HDR_LEN; fw_info->c2h_counter++; rtw89_write8_mask(rtwdev, chip->c2h_counter_reg.addr, diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 048283750a2d..dd71beb152ae 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -18,15 +18,51 @@ enum rtw89_fw_dl_status { RTW89_FWDL_WCPU_FW_INIT_RDY = 7 }; -#define RTW89_GET_C2H_HDR_FUNC(info) \ - u32_get_bits(info, GENMASK(6, 0)) -#define RTW89_GET_C2H_HDR_LEN(info) \ - u32_get_bits(info, GENMASK(11, 8)) +struct rtw89_c2hreg_hdr { + u32 w0; +}; + +#define RTW89_C2HREG_HDR_FUNC_MASK GENMASK(6, 0) +#define RTW89_C2HREG_HDR_ACK BIT(7) +#define RTW89_C2HREG_HDR_LEN_MASK GENMASK(11, 8) +#define RTW89_C2HREG_HDR_SEQ_MASK GENMASK(15, 12) + +struct rtw89_c2hreg_phycap { + u32 w0; + u32 w1; + u32 w2; + u32 w3; +} __packed; + +#define RTW89_C2HREG_PHYCAP_W0_FUNC GENMASK(6, 0) +#define RTW89_C2HREG_PHYCAP_W0_ACK BIT(7) +#define RTW89_C2HREG_PHYCAP_W0_LEN GENMASK(11, 8) +#define RTW89_C2HREG_PHYCAP_W0_SEQ GENMASK(15, 12) +#define RTW89_C2HREG_PHYCAP_W0_RX_NSS GENMASK(23, 16) +#define RTW89_C2HREG_PHYCAP_W0_BW GENMASK(31, 24) +#define RTW89_C2HREG_PHYCAP_W1_TX_NSS GENMASK(7, 0) +#define RTW89_C2HREG_PHYCAP_W1_PROT GENMASK(15, 8) +#define RTW89_C2HREG_PHYCAP_W1_NIC GENMASK(23, 16) +#define RTW89_C2HREG_PHYCAP_W1_WL_FUNC GENMASK(31, 24) +#define RTW89_C2HREG_PHYCAP_W2_HW_TYPE GENMASK(7, 0) +#define RTW89_C2HREG_PHYCAP_W3_ANT_TX_NUM GENMASK(15, 8) +#define RTW89_C2HREG_PHYCAP_W3_ANT_RX_NUM GENMASK(23, 16) + +struct rtw89_h2creg_hdr { + u32 w0; +}; + +#define RTW89_H2CREG_HDR_FUNC_MASK GENMASK(6, 0) +#define RTW89_H2CREG_HDR_LEN_MASK GENMASK(11, 8) -#define RTW89_SET_H2CREG_HDR_FUNC(info, val) \ - u32p_replace_bits(info, val, GENMASK(6, 0)) -#define RTW89_SET_H2CREG_HDR_LEN(info, val) \ - u32p_replace_bits(info, val, GENMASK(11, 8)) +struct rtw89_h2creg_sch_tx_en { + u32 w0; + u32 w1; +} __packed; + +#define RTW89_H2CREG_SCH_TX_EN_W0_EN GENMASK(31, 16) +#define RTW89_H2CREG_SCH_TX_EN_W1_MASK GENMASK(15, 0) +#define RTW89_H2CREG_SCH_TX_EN_W1_BAND BIT(16) #define RTW89_H2CREG_MAX 4 #define RTW89_C2HREG_MAX 4 @@ -36,13 +72,21 @@ enum rtw89_fw_dl_status { struct rtw89_mac_c2h_info { u8 id; u8 content_len; - u32 c2hreg[RTW89_C2HREG_MAX]; + union { + u32 c2hreg[RTW89_C2HREG_MAX]; + struct rtw89_c2hreg_hdr hdr; + struct rtw89_c2hreg_phycap phycap; + } u; }; struct rtw89_mac_h2c_info { u8 id; u8 content_len; - u32 h2creg[RTW89_H2CREG_MAX]; + union { + u32 h2creg[RTW89_H2CREG_MAX]; + struct rtw89_h2creg_hdr hdr; + struct rtw89_h2creg_sch_tx_en sch_tx_en; + } u; }; enum rtw89_mac_h2c_type { @@ -63,33 +107,6 @@ enum rtw89_mac_c2h_type { RTW89_FWCMD_C2HREG_FUNC_NULL = 0xFF }; -#define RTW89_GET_C2H_PHYCAP_FUNC(info) \ - u32_get_bits(*((const u32 *)(info)), GENMASK(6, 0)) -#define RTW89_GET_C2H_PHYCAP_ACK(info) \ - u32_get_bits(*((const u32 *)(info)), BIT(7)) -#define RTW89_GET_C2H_PHYCAP_LEN(info) \ - u32_get_bits(*((const u32 *)(info)), GENMASK(11, 8)) -#define RTW89_GET_C2H_PHYCAP_SEQ(info) \ - u32_get_bits(*((const u32 *)(info)), GENMASK(15, 12)) -#define RTW89_GET_C2H_PHYCAP_RX_NSS(info) \ - u32_get_bits(*((const u32 *)(info)), GENMASK(23, 16)) -#define RTW89_GET_C2H_PHYCAP_BW(info) \ - u32_get_bits(*((const u32 *)(info)), GENMASK(31, 24)) -#define RTW89_GET_C2H_PHYCAP_TX_NSS(info) \ - u32_get_bits(*((const u32 *)(info) + 1), GENMASK(7, 0)) -#define RTW89_GET_C2H_PHYCAP_PROT(info) \ - u32_get_bits(*((const u32 *)(info) + 1), GENMASK(15, 8)) -#define RTW89_GET_C2H_PHYCAP_NIC(info) \ - u32_get_bits(*((const u32 *)(info) + 1), GENMASK(23, 16)) -#define RTW89_GET_C2H_PHYCAP_WL_FUNC(info) \ - u32_get_bits(*((const u32 *)(info) + 1), GENMASK(31, 24)) -#define RTW89_GET_C2H_PHYCAP_HW_TYPE(info) \ - u32_get_bits(*((const u32 *)(info) + 2), GENMASK(7, 0)) -#define RTW89_GET_C2H_PHYCAP_ANT_TX_NUM(info) \ - u32_get_bits(*((const u32 *)(info) + 3), GENMASK(15, 8)) -#define RTW89_GET_C2H_PHYCAP_ANT_RX_NUM(info) \ - u32_get_bits(*((const u32 *)(info) + 3), GENMASK(23, 16)) - enum rtw89_fw_c2h_category { RTW89_C2H_CAT_TEST, RTW89_C2H_CAT_MAC, @@ -214,17 +231,6 @@ struct rtw89_fw_macid_pause_grp { __le32 mask_grp[4]; } __packed; -struct rtw89_h2creg_sch_tx_en { - u8 func:7; - u8 ack:1; - u8 total_len:4; - u8 seq_num:4; - u16 tx_en:16; - u16 mask:16; - u8 band:1; - u16 rsvd:15; -} __packed; - #define RTW89_H2C_MAX_SIZE 2048 #define RTW89_CHANNEL_TIME 45 #define RTW89_CHANNEL_TIME_6G 20 diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index f637fdafc7f1..8853c49b63b1 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -2646,6 +2646,7 @@ int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) struct rtw89_hal *hal = &rtwdev->hal; const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_mac_c2h_info c2h_info = {0}; + const struct rtw89_c2hreg_phycap *phycap; u8 tx_nss; u8 rx_nss; u8 tx_ant; @@ -2656,10 +2657,12 @@ int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) if (ret) return ret; - tx_nss = RTW89_GET_C2H_PHYCAP_TX_NSS(c2h_info.c2hreg); - rx_nss = RTW89_GET_C2H_PHYCAP_RX_NSS(c2h_info.c2hreg); - tx_ant = RTW89_GET_C2H_PHYCAP_ANT_TX_NUM(c2h_info.c2hreg); - rx_ant = RTW89_GET_C2H_PHYCAP_ANT_RX_NUM(c2h_info.c2hreg); + phycap = &c2h_info.u.phycap; + + tx_nss = u32_get_bits(phycap->w1, RTW89_C2HREG_PHYCAP_W1_TX_NSS); + rx_nss = u32_get_bits(phycap->w0, RTW89_C2HREG_PHYCAP_W0_RX_NSS); + tx_ant = u32_get_bits(phycap->w3, RTW89_C2HREG_PHYCAP_W3_ANT_TX_NUM); + rx_ant = u32_get_bits(phycap->w3, RTW89_C2HREG_PHYCAP_W3_ANT_RX_NUM); hal->tx_nss = tx_nss ? min_t(u8, tx_nss, chip->tx_nss) : chip->tx_nss; hal->rx_nss = rx_nss ? min_t(u8, rx_nss, chip->rx_nss) : chip->rx_nss; @@ -2700,14 +2703,14 @@ static int rtw89_hw_sch_tx_en_h2c(struct rtw89_dev *rtwdev, u8 band, u32 ret; struct rtw89_mac_c2h_info c2h_info = {0}; struct rtw89_mac_h2c_info h2c_info = {0}; - struct rtw89_h2creg_sch_tx_en *h2creg = - (struct rtw89_h2creg_sch_tx_en *)h2c_info.h2creg; + struct rtw89_h2creg_sch_tx_en *sch_tx_en = &h2c_info.u.sch_tx_en; h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_SCH_TX_EN; - h2c_info.content_len = sizeof(*h2creg) - RTW89_H2CREG_HDR_LEN; - h2creg->tx_en = tx_en_u16; - h2creg->mask = mask_u16; - h2creg->band = band; + h2c_info.content_len = sizeof(*sch_tx_en) - RTW89_H2CREG_HDR_LEN; + + u32p_replace_bits(&sch_tx_en->w0, tx_en_u16, RTW89_H2CREG_SCH_TX_EN_W0_EN); + u32p_replace_bits(&sch_tx_en->w1, mask_u16, RTW89_H2CREG_SCH_TX_EN_W1_MASK); + u32p_replace_bits(&sch_tx_en->w1, band, RTW89_H2CREG_SCH_TX_EN_W1_BAND); ret = rtw89_fw_msg_reg(rtwdev, &h2c_info, &c2h_info); if (ret) -- cgit v1.2.3 From 56fc4d482783f5e45a6a2b3ec0d9f557908cdf77 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 22 May 2023 09:59:24 +0100 Subject: wifi: rtw89: 8851b: rfk: Fix spelling mistake KIP_RESOTRE -> KIP_RESTORE There is a spelling mistake in a literal string. Fix it. Signed-off-by: Colin Ian King Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230522085924.913649-1-colin.i.king@gmail.com --- drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index d58d6935e7b8..1899a5d69a81 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -1705,7 +1705,7 @@ static void _dpk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, id == 0x2c ? "GAIN_LOSS" : id == 0x2d ? "MDPK_IDL" : id == 0x2f ? "DPK_GAIN_NORM" : - id == 0x31 ? "KIP_RESOTRE" : + id == 0x31 ? "KIP_RESTORE" : id == 0x6 ? "LBK_RXIQK" : "Unknown id", dpk_cmd); } -- cgit v1.2.3 From 47e612268ea02f7d2bcbaa47528698b5be61a8cf Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 23 May 2023 13:32:35 +0200 Subject: wifi: rtw89: use flexible array member in rtw89_btc_btf_tlv struct rtw89_btc_btf_tlv contains a one-byte member that is intended as a flexible array: In function 'fortify_memcpy_chk', inlined from '_append_tdma' at drivers/net/wireless/realtek/rtw89/coex.c:1579:3: include/linux/fortify-string.h:583:25: error: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] 583 | __write_overflow_field(p_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Make this actually use a flexible array to let the compiler understand. Signed-off-by: Arnd Bergmann Reviewed-by: Ping-Ke Shih Reviewed-by: Gustavo A. R. Silva Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230523113241.2772811-1-arnd@kernel.org --- drivers/net/wireless/realtek/rtw89/coex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 3a586a971e8f..bda0e1e99a8c 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -206,7 +206,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { struct rtw89_btc_btf_tlv { u8 type; u8 len; - u8 val[1]; + u8 val[]; } __packed; enum btc_btf_set_report_en { -- cgit v1.2.3 From 925244325159824385209e3e0e3f91fa6bf0646c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 20 May 2023 09:29:46 +0200 Subject: wifi: orinoco: Fix an error handling path in spectrum_cs_probe() Should spectrum_cs_config() fail, some resources need to be released as already done in the remove function. While at it, remove a useless and erroneous comment. The probe is spectrum_cs_probe(), not spectrum_cs_attach(). Fixes: 15b99ac17295 ("[PATCH] pcmcia: add return value to _config() functions") Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/c0bc0c21c58ca477fc5521607615bafbf2aef8eb.1684567733.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/intersil/orinoco/spectrum_cs.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c b/drivers/net/wireless/intersil/orinoco/spectrum_cs.c index 291ef97ed45e..841d623c621a 100644 --- a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/intersil/orinoco/spectrum_cs.c @@ -157,6 +157,7 @@ spectrum_cs_probe(struct pcmcia_device *link) { struct orinoco_private *priv; struct orinoco_pccard *card; + int ret; priv = alloc_orinocodev(sizeof(*card), &link->dev, spectrum_cs_hard_reset, @@ -169,8 +170,16 @@ spectrum_cs_probe(struct pcmcia_device *link) card->p_dev = link; link->priv = priv; - return spectrum_cs_config(link); -} /* spectrum_cs_attach */ + ret = spectrum_cs_config(link); + if (ret) + goto err_free_orinocodev; + + return 0; + +err_free_orinocodev: + free_orinocodev(priv); + return ret; +} static void spectrum_cs_detach(struct pcmcia_device *link) { -- cgit v1.2.3 From 67a81d911c01225f426cc6bee2373df044c1a9b7 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 20 May 2023 09:38:22 +0200 Subject: wifi: orinoco: Fix an error handling path in orinoco_cs_probe() Should orinoco_cs_config() fail, some resources need to be released as already done in the remove function. While at it, remove a useless and erroneous comment. The probe is orinoco_cs_probe(), not orinoco_cs_attach(). Fixes: 15b99ac17295 ("[PATCH] pcmcia: add return value to _config() functions") Signed-off-by: Christophe JAILLET Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/e24735ce4d82901d5f7ea08419eea53bfdde3d65.1684568286.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/intersil/orinoco/orinoco_cs.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c b/drivers/net/wireless/intersil/orinoco/orinoco_cs.c index a956f965a1e5..03bfd2482656 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_cs.c @@ -96,6 +96,7 @@ orinoco_cs_probe(struct pcmcia_device *link) { struct orinoco_private *priv; struct orinoco_pccard *card; + int ret; priv = alloc_orinocodev(sizeof(*card), &link->dev, orinoco_cs_hard_reset, NULL); @@ -107,8 +108,16 @@ orinoco_cs_probe(struct pcmcia_device *link) card->p_dev = link; link->priv = priv; - return orinoco_cs_config(link); -} /* orinoco_cs_attach */ + ret = orinoco_cs_config(link); + if (ret) + goto err_free_orinocodev; + + return 0; + +err_free_orinocodev: + free_orinocodev(priv); + return ret; +} static void orinoco_cs_detach(struct pcmcia_device *link) { -- cgit v1.2.3 From 6b92e4351a29af52c285fe235e6e4d1a75de04b2 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 20 May 2023 09:53:14 +0200 Subject: wifi: atmel: Fix an error handling path in atmel_probe() Should atmel_config() fail, some resources need to be released as already done in the remove function. While at it, remove a useless and erroneous comment. The probe is atmel_probe(), not atmel_attach(). Fixes: 15b99ac17295 ("[PATCH] pcmcia: add return value to _config() functions") Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1e65f174607a83348034197fa7d603bab10ba4a9.1684569156.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/atmel/atmel_cs.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/atmel/atmel_cs.c b/drivers/net/wireless/atmel/atmel_cs.c index 453bb84cb338..58bba9875d36 100644 --- a/drivers/net/wireless/atmel/atmel_cs.c +++ b/drivers/net/wireless/atmel/atmel_cs.c @@ -72,6 +72,7 @@ struct local_info { static int atmel_probe(struct pcmcia_device *p_dev) { struct local_info *local; + int ret; dev_dbg(&p_dev->dev, "atmel_attach()\n"); @@ -82,8 +83,16 @@ static int atmel_probe(struct pcmcia_device *p_dev) p_dev->priv = local; - return atmel_config(p_dev); -} /* atmel_attach */ + ret = atmel_config(p_dev); + if (ret) + goto err_free_priv; + + return 0; + +err_free_priv: + kfree(p_dev->priv); + return ret; +} static void atmel_detach(struct pcmcia_device *link) { -- cgit v1.2.3 From 391af06a02e7642039ac5f6c4b2c034ab0992b5d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 20 May 2023 10:05:08 +0200 Subject: wifi: wl3501_cs: Fix an error handling path in wl3501_probe() Should wl3501_config() fail, some resources need to be released as already done in the remove function. Fixes: 15b99ac17295 ("[PATCH] pcmcia: add return value to _config() functions") Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/7cc9c9316489b7d69b36aeb0edd3123538500b41.1684569865.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/legacy/wl3501_cs.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/legacy/wl3501_cs.c b/drivers/net/wireless/legacy/wl3501_cs.c index 7fb2f9513476..c45c4b7cbbaf 100644 --- a/drivers/net/wireless/legacy/wl3501_cs.c +++ b/drivers/net/wireless/legacy/wl3501_cs.c @@ -1862,6 +1862,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev) { struct net_device *dev; struct wl3501_card *this; + int ret; /* The io structure describes IO port mapping */ p_dev->resource[0]->end = 16; @@ -1873,8 +1874,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev) dev = alloc_etherdev(sizeof(struct wl3501_card)); if (!dev) - goto out_link; - + return -ENOMEM; dev->netdev_ops = &wl3501_netdev_ops; dev->watchdog_timeo = 5 * HZ; @@ -1887,9 +1887,15 @@ static int wl3501_probe(struct pcmcia_device *p_dev) netif_stop_queue(dev); p_dev->priv = dev; - return wl3501_config(p_dev); -out_link: - return -ENOMEM; + ret = wl3501_config(p_dev); + if (ret) + goto out_free_etherdev; + + return 0; + +out_free_etherdev: + free_netdev(dev); + return ret; } static int wl3501_config(struct pcmcia_device *link) -- cgit v1.2.3 From 4f8d66a9fb2edcd05c1e563456a55a08910bfb37 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 20 May 2023 10:13:22 +0200 Subject: wifi: ray_cs: Fix an error handling path in ray_probe() Should ray_config() fail, some resources need to be released as already done in the remove function. While at it, remove a useless and erroneous comment. The probe is ray_probe(), not ray_attach(). Fixes: 15b99ac17295 ("[PATCH] pcmcia: add return value to _config() functions") Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/8c544d18084f8b37dd108e844f7e79e85ff708ff.1684570373.git.christophe.jaillet@wanadoo.fr --- drivers/net/wireless/legacy/ray_cs.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c index 1f57a0055bbd..38782d4c4694 100644 --- a/drivers/net/wireless/legacy/ray_cs.c +++ b/drivers/net/wireless/legacy/ray_cs.c @@ -270,13 +270,14 @@ static int ray_probe(struct pcmcia_device *p_dev) { ray_dev_t *local; struct net_device *dev; + int ret; dev_dbg(&p_dev->dev, "ray_attach()\n"); /* Allocate space for private device-specific data */ dev = alloc_etherdev(sizeof(ray_dev_t)); if (!dev) - goto fail_alloc_dev; + return -ENOMEM; local = netdev_priv(dev); local->finder = p_dev; @@ -313,11 +314,16 @@ static int ray_probe(struct pcmcia_device *p_dev) timer_setup(&local->timer, NULL, 0); this_device = p_dev; - return ray_config(p_dev); + ret = ray_config(p_dev); + if (ret) + goto err_free_dev; + + return 0; -fail_alloc_dev: - return -ENOMEM; -} /* ray_attach */ +err_free_dev: + free_netdev(dev); + return ret; +} static void ray_detach(struct pcmcia_device *link) { -- cgit v1.2.3 From cbb3debbb1630132a39e90058861f1c1d01dffb6 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 17 May 2023 18:03:16 +0300 Subject: wifi: wil6210: fw: Replace zero-length arrays with DECLARE_FLEX_ARRAY() helper Zero-length arrays are deprecated, and we are moving towards adopting C99 flexible-array members, instead. So, replace zero-length arrays declarations alone in structs with the new DECLARE_FLEX_ARRAY() helper macro. This helper allows for flexible-array members alone in structs. Link: https://github.com/KSPP/linux/issues/193 Link: https://github.com/KSPP/linux/issues/287 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Signed-off-by: Gustavo A. R. Silva Reviewed-by: Simon Horman Reviewed-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/ZGKHByxujJoygK+l@work --- drivers/net/wireless/ath/wil6210/fw.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h index 440614d61156..aa1620e0d24f 100644 --- a/drivers/net/wireless/ath/wil6210/fw.h +++ b/drivers/net/wireless/ath/wil6210/fw.h @@ -47,7 +47,7 @@ struct wil_fw_record_fill { /* type == wil_fw_type_fill */ * for informational purpose, data_size is @head.size from record header */ struct wil_fw_record_comment { /* type == wil_fw_type_comment */ - u8 data[0]; /* free-form data [data_size], see above */ + DECLARE_FLEX_ARRAY(u8, data); /* free-form data [data_size], see above */ } __packed; /* Comment header - common for all comment record types */ @@ -131,7 +131,7 @@ struct wil_fw_data_dwrite { * data_size is @head.size where @head is record header */ struct wil_fw_record_direct_write { /* type == wil_fw_type_direct_write */ - struct wil_fw_data_dwrite data[0]; + DECLARE_FLEX_ARRAY(struct wil_fw_data_dwrite, data); } __packed; /* verify condition: [@addr] & @mask == @value -- cgit v1.2.3 From 27044b57f8a5328f4f7517f8a15d9fe3171ab279 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 17 May 2023 18:03:17 +0300 Subject: wifi: wil6210: wmi: Replace zero-length array with DECLARE_FLEX_ARRAY() helper Zero-length arrays are deprecated, and we are moving towards adopting C99 flexible-array members, instead. So, replace zero-length arrays declarations alone in structs with the new DECLARE_FLEX_ARRAY() helper macro. This helper allows for flexible-array members alone in structs. Link: https://github.com/KSPP/linux/issues/193 Link: https://github.com/KSPP/linux/issues/288 Link: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html Signed-off-by: Gustavo A. R. Silva Reviewed-by: Simon Horman Reviewed-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/ZGKHM+MWFsuqzTjm@work --- drivers/net/wireless/ath/wil6210/wmi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 9affa4525609..71bf2ae27a98 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -2763,7 +2763,7 @@ struct wmi_rf_xpm_write_result_event { /* WMI_TX_MGMT_PACKET_EVENTID */ struct wmi_tx_mgmt_packet_event { - u8 payload[0]; + DECLARE_FLEX_ARRAY(u8, payload); } __packed; /* WMI_RX_MGMT_PACKET_EVENTID */ -- cgit v1.2.3 From 061b0cb9327b80d7a0f63a33e7c3e2a91a71f142 Mon Sep 17 00:00:00 2001 From: Fedor Pchelkin Date: Wed, 17 May 2023 18:03:17 +0300 Subject: wifi: ath9k: don't allow to overwrite ENDPOINT0 attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bad USB device is able to construct a service connection response message with target endpoint being ENDPOINT0 which is reserved for HTC_CTRL_RSVD_SVC and should not be modified to be used for any other services. Reject such service connection responses. Found by Linux Verification Center (linuxtesting.org) with Syzkaller. Fixes: fb9987d0f748 ("ath9k_htc: Support for AR9271 chipset.") Reported-by: syzbot+b68fbebe56d8362907e8@syzkaller.appspotmail.com Signed-off-by: Fedor Pchelkin Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230516150427.79469-1-pchelkin@ispras.ru --- drivers/net/wireless/ath/ath9k/htc_hst.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index fe62ff668f75..99667aba289d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -114,7 +114,13 @@ static void htc_process_conn_rsp(struct htc_target *target, if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) { epid = svc_rspmsg->endpoint_id; - if (epid < 0 || epid >= ENDPOINT_MAX) + + /* Check that the received epid for the endpoint to attach + * a new service is valid. ENDPOINT0 can't be used here as it + * is already reserved for HTC_CTRL_RSVD_SVC service and thus + * should not be modified. + */ + if (epid <= ENDPOINT0 || epid >= ENDPOINT_MAX) return; service_id = be16_to_cpu(svc_rspmsg->service_id); -- cgit v1.2.3 From c4c84f6fb2c4dc4c0f5fd927b3c3d3fd28b7030e Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 24 May 2023 15:54:19 -0700 Subject: bpf: drop unnecessary bpf_capable() check in BPF_MAP_FREEZE command Seems like that extra bpf_capable() check in BPF_MAP_FREEZE handler was unintentionally left when we switched to a model that all BPF map operations should be allowed regardless of CAP_BPF (or any other capabilities), as long as process got BPF map FD somehow. This patch replaces bpf_capable() check in BPF_MAP_FREEZE handler with writeable access check, given conceptually freezing the map is modifying it: map becomes unmodifiable for subsequent updates. Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/r/20230524225421.1587859-2-andrii@kernel.org Signed-off-by: Alexei Starovoitov --- kernel/bpf/syscall.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index c7f6807215e6..c9a201e4c457 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1931,6 +1931,11 @@ static int map_freeze(const union bpf_attr *attr) return -ENOTSUPP; } + if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { + err = -EPERM; + goto err_put; + } + mutex_lock(&map->freeze_mutex); if (bpf_map_write_active(map)) { err = -EBUSY; @@ -1940,10 +1945,6 @@ static int map_freeze(const union bpf_attr *attr) err = -EBUSY; goto err_put; } - if (!bpf_capable()) { - err = -EPERM; - goto err_put; - } WRITE_ONCE(map->frozen, true); err_put: -- cgit v1.2.3 From 4c857a719bf9c5ddbcf3bd92398632041bff50d0 Mon Sep 17 00:00:00 2001 From: JP Kobryn Date: Wed, 24 May 2023 17:13:23 -0700 Subject: libbpf: Change var type in datasec resize func This changes a local variable type that stores a new array id to match the return type of btf__add_array(). Signed-off-by: JP Kobryn Signed-off-by: Andrii Nakryiko Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230525001323.8554-1-inwardvessel@gmail.com --- tools/lib/bpf/libbpf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 5cca00979aae..1ceb3a97dadc 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -9444,8 +9444,8 @@ static int map_btf_datasec_resize(struct bpf_map *map, __u32 size) struct btf_var_secinfo *var; const struct btf_type *array_type; const struct btf_array *array; - int vlen, element_sz; - __u32 nr_elements, new_array_id; + int vlen, element_sz, new_array_id; + __u32 nr_elements; /* check btf existence */ btf = bpf_object__btf(map->obj); -- cgit v1.2.3 From 321a64b328156fd43d3be589c24905a641c7995b Mon Sep 17 00:00:00 2001 From: Daniel Müller Date: Thu, 25 May 2023 23:22:48 +0000 Subject: selftests/bpf: Check whether to run selftest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sockopt test invokes test__start_subtest and then unconditionally asserts the success. That means that even if deny-listed, any test will still run and potentially fail. Evaluate the return value of test__start_subtest() to achieve the desired behavior, as other tests do. Signed-off-by: Daniel Müller Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230525232248.640465-1-deso@posteo.net --- tools/testing/selftests/bpf/prog_tests/sockopt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/sockopt.c b/tools/testing/selftests/bpf/prog_tests/sockopt.c index 33dd4532e642..9e6a5e3ed4de 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockopt.c +++ b/tools/testing/selftests/bpf/prog_tests/sockopt.c @@ -1060,7 +1060,9 @@ void test_sockopt(void) return; for (i = 0; i < ARRAY_SIZE(tests); i++) { - test__start_subtest(tests[i].descr); + if (!test__start_subtest(tests[i].descr)) + continue; + ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr); } -- cgit v1.2.3 From c857946a4e262e0f798fe7625fadf85bf1190fc4 Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Tue, 23 May 2023 13:15:18 +0200 Subject: net/core: Enable socket busy polling on -RT Busy polling is currently not allowed on PREEMPT_RT, because it disables preemption while invoking the NAPI callback. It is not possible to acquire sleeping locks with disabled preemption. For details see commit 20ab39d13e2e ("net/core: disable NET_RX_BUSY_POLL on PREEMPT_RT"). However, strict cyclic and/or low latency network applications may prefer busy polling e.g., using AF_XDP instead of interrupt driven communication. The preempt_disable() is used in order to prevent the poll_owner and NAPI owner to be preempted while owning the resource to ensure progress. Netpoll performs busy polling in order to acquire the lock. NAPI is locked by setting the NAPIF_STATE_SCHED flag. There is no busy polling if the flag is set and the "owner" is preempted. Worst case is that the task owning NAPI gets preempted and NAPI processing stalls. This is can be prevented by properly prioritising the tasks within the system. Allow RX_BUSY_POLL on PREEMPT_RT if NETPOLL is disabled. Don't disable preemption on PREEMPT_RT within the busy poll loop. Tested on x86 hardware with v6.1-RT and v6.3-RT on Intel i225 (igc) with AF_XDP/ZC sockets configured to run in busy polling mode. Suggested-by: Sebastian Andrzej Siewior Signed-off-by: Kurt Kanzenbach Signed-off-by: David S. Miller --- net/Kconfig | 2 +- net/core/dev.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/net/Kconfig b/net/Kconfig index 7d39c1773eb4..2fb25b534df5 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -324,7 +324,7 @@ config CGROUP_NET_CLASSID config NET_RX_BUSY_POLL bool - default y if !PREEMPT_RT + default y if !PREEMPT_RT || (PREEMPT_RT && !NETCONSOLE) config BQL bool diff --git a/net/core/dev.c b/net/core/dev.c index b3c13e041935..3393c2f3dbe8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6197,7 +6197,8 @@ restart: if (!napi) goto out; - preempt_disable(); + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) + preempt_disable(); for (;;) { int work = 0; @@ -6239,7 +6240,8 @@ count: if (unlikely(need_resched())) { if (napi_poll) busy_poll_stop(napi, have_poll_lock, prefer_busy_poll, budget); - preempt_enable(); + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) + preempt_enable(); rcu_read_unlock(); cond_resched(); if (loop_end(loop_end_arg, start_time)) @@ -6250,7 +6252,8 @@ count: } if (napi_poll) busy_poll_stop(napi, have_poll_lock, prefer_busy_poll, budget); - preempt_enable(); + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) + preempt_enable(); out: rcu_read_unlock(); } -- cgit v1.2.3 From ca7d05007d0a95615a51cb5a624775db8c450f43 Mon Sep 17 00:00:00 2001 From: Pieter Jansen van Vuuren Date: Wed, 24 May 2023 10:36:38 +0100 Subject: sfc: handle VI shortage on ef100 by readjusting the channels When fewer VIs are allocated than what is allowed we can readjust the channels by calling efx_mcdi_alloc_vis() again. Signed-off-by: Pieter Jansen van Vuuren Reviewed-by: Martin Habets Reviewed-by: Simon Horman Reviewed-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef100_netdev.c | 51 +++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c index be395cd8770b..274f3a2562ad 100644 --- a/drivers/net/ethernet/sfc/ef100_netdev.c +++ b/drivers/net/ethernet/sfc/ef100_netdev.c @@ -40,19 +40,26 @@ static int ef100_alloc_vis(struct efx_nic *efx, unsigned int *allocated_vis) unsigned int tx_vis = efx->n_tx_channels + efx->n_extra_tx_channels; unsigned int rx_vis = efx->n_rx_channels; unsigned int min_vis, max_vis; + int rc; EFX_WARN_ON_PARANOID(efx->tx_queues_per_channel != 1); tx_vis += efx->n_xdp_channels * efx->xdp_tx_per_channel; max_vis = max(rx_vis, tx_vis); - /* Currently don't handle resource starvation and only accept - * our maximum needs and no less. + /* We require at least a single complete TX channel worth of queues. */ + min_vis = efx->tx_queues_per_channel; + + rc = efx_mcdi_alloc_vis(efx, min_vis, max_vis, + NULL, allocated_vis); + + /* We retry allocating VIs by reallocating channels when we have not + * been able to allocate the maximum VIs. */ - min_vis = max_vis; + if (!rc && *allocated_vis < max_vis) + rc = -EAGAIN; - return efx_mcdi_alloc_vis(efx, min_vis, max_vis, - NULL, allocated_vis); + return rc; } static int ef100_remap_bar(struct efx_nic *efx, int max_vis) @@ -133,9 +140,41 @@ static int ef100_net_open(struct net_device *net_dev) goto fail; rc = ef100_alloc_vis(efx, &allocated_vis); - if (rc) + if (rc && rc != -EAGAIN) goto fail; + /* Try one more time but with the maximum number of channels + * equal to the allocated VIs, which would more likely succeed. + */ + if (rc == -EAGAIN) { + rc = efx_mcdi_free_vis(efx); + if (rc) + goto fail; + + efx_remove_interrupts(efx); + efx->max_channels = allocated_vis; + + rc = efx_probe_interrupts(efx); + if (rc) + goto fail; + + rc = efx_set_channels(efx); + if (rc) + goto fail; + + rc = ef100_alloc_vis(efx, &allocated_vis); + if (rc && rc != -EAGAIN) + goto fail; + + /* It should be very unlikely that we failed here again, but in + * such a case we return ENOSPC. + */ + if (rc == -EAGAIN) { + rc = -ENOSPC; + goto fail; + } + } + rc = efx_probe_channels(efx); if (rc) return rc; -- cgit v1.2.3 From 9b66ee06e5ca2698d0ba12a7ad7188cb724279e7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 24 May 2023 10:09:01 -0700 Subject: net: ynl: prefix uAPI header include with uapi/ To keep things simple we used to include the uAPI header in the kernel in the #include format. This works well enough, most of the genl families should have headers in include/net/ so linux/$family.h ends up referring to the uAPI header, anyway. And if it doesn't no big deal, we'll just include more info than we need. Unless that is there is a naming conflict. Someone recently created include/linux/psp.h which will be a problem when supporting the PSP protocol. (I'm talking about work-in-progress patches, but it's just a proof that assuming lack of name conflicts was overly optimistic.) Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/core/netdev-genl-gen.c | 2 +- net/core/netdev-genl-gen.h | 2 +- net/handshake/genl.c | 2 +- net/handshake/genl.h | 2 +- net/ipv4/fou_nl.c | 2 +- net/ipv4/fou_nl.h | 2 +- tools/net/ynl/ynl-gen-c.py | 4 +++- 7 files changed, 9 insertions(+), 7 deletions(-) diff --git a/net/core/netdev-genl-gen.c b/net/core/netdev-genl-gen.c index de17ca2f7dbf..ea9231378aa6 100644 --- a/net/core/netdev-genl-gen.c +++ b/net/core/netdev-genl-gen.c @@ -8,7 +8,7 @@ #include "netdev-genl-gen.h" -#include +#include /* NETDEV_CMD_DEV_GET - do */ static const struct nla_policy netdev_dev_get_nl_policy[NETDEV_A_DEV_IFINDEX + 1] = { diff --git a/net/core/netdev-genl-gen.h b/net/core/netdev-genl-gen.h index 74d74fc23167..7b370c073e7d 100644 --- a/net/core/netdev-genl-gen.h +++ b/net/core/netdev-genl-gen.h @@ -9,7 +9,7 @@ #include #include -#include +#include int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info); int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); diff --git a/net/handshake/genl.c b/net/handshake/genl.c index 9f29efb1493e..233be5cbfec9 100644 --- a/net/handshake/genl.c +++ b/net/handshake/genl.c @@ -8,7 +8,7 @@ #include "genl.h" -#include +#include /* HANDSHAKE_CMD_ACCEPT - do */ static const struct nla_policy handshake_accept_nl_policy[HANDSHAKE_A_ACCEPT_HANDLER_CLASS + 1] = { diff --git a/net/handshake/genl.h b/net/handshake/genl.h index 2c1f1aa6a02a..ae72a596f6cc 100644 --- a/net/handshake/genl.h +++ b/net/handshake/genl.h @@ -9,7 +9,7 @@ #include #include -#include +#include int handshake_nl_accept_doit(struct sk_buff *skb, struct genl_info *info); int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info); diff --git a/net/ipv4/fou_nl.c b/net/ipv4/fou_nl.c index 6c37c4f98cca..98b90107b5ab 100644 --- a/net/ipv4/fou_nl.c +++ b/net/ipv4/fou_nl.c @@ -8,7 +8,7 @@ #include "fou_nl.h" -#include +#include /* Global operation policy for fou */ const struct nla_policy fou_nl_policy[FOU_ATTR_IFINDEX + 1] = { diff --git a/net/ipv4/fou_nl.h b/net/ipv4/fou_nl.h index dbd0780a5d34..63a6c4ed803d 100644 --- a/net/ipv4/fou_nl.h +++ b/net/ipv4/fou_nl.h @@ -9,7 +9,7 @@ #include #include -#include +#include /* Global operation policy for fou */ extern const struct nla_policy fou_nl_policy[FOU_ATTR_IFINDEX + 1]; diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index cc2f8c945340..be664510f484 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -2101,7 +2101,9 @@ def main(): if args.out_file: cw.p(f'#include "{os.path.basename(args.out_file[:-2])}.h"') cw.nl() - headers = [parsed.uapi_header] + headers = ['uapi/' + parsed.uapi_header] + else: + headers = [parsed.uapi_header] for definition in parsed['definitions']: if 'header' in definition: headers.append(definition['header']) -- cgit v1.2.3 From 342527f35338d9373f307e24662f174008b571b2 Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Thu, 25 May 2023 20:07:57 +0300 Subject: wifi: ath12k: Add support to parse new WMI event for 6 GHz regulatory In order to support different power levels of 6 GHz AP and client, new WMI event for regulatory (WMI_REG_CHAN_LIST_CC_EXT_EVENTID) has been added in firmware to provide new parameters required for 6 GHz regulatory rules. Firmware advertises its capability of handling new event in WMI service ready event. Based on that, host needs to set host_service_flags in WMI init command to indicate that host supports processing of this WMI event. Based on advertised host capability, firmware sends event WMI_REG_CHAN_LIST_CC_EXT_EVENTID. This new event contains 2G/5G/6G reg rules with additional power value fields for 6GHz and regd is built accordingly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0-02903-QCAHKSWPL_SILICONZ-1 Signed-off-by: P Praneesh Signed-off-by: Ramya Gnanasekar Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230502142018.20301-1-quic_rgnanase@quicinc.com --- drivers/net/wireless/ath/ath12k/wmi.c | 95 +++++++++++++++++++++++------------ drivers/net/wireless/ath/ath12k/wmi.h | 8 ++- 2 files changed, 68 insertions(+), 35 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index f1d0743eb349..6512267ae4ca 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -3181,8 +3181,8 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params); wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count); wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); - wmi_cfg->host_service_flags = - cpu_to_le32(1 << WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); + wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << + WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); } static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi, @@ -3390,6 +3390,10 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab) struct ath12k_wmi_base *wmi_sc = &ab->wmi_ab; struct ath12k_wmi_init_cmd_arg arg = {}; + if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT, + ab->wmi_ab.svc_map)) + arg.res_cfg.is_reg_cc_ext_event_supported = true; + ab->hw_params->wmi_init(ab, &arg.res_cfg); arg.num_mem_chunks = wmi_sc->num_mem_chunks; @@ -5985,47 +5989,72 @@ static void ath12k_vdev_install_key_compl_event(struct ath12k_base *ab, rcu_read_unlock(); } -static void ath12k_service_available_event(struct ath12k_base *ab, struct sk_buff *skb) +static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, + u16 tag, u16 len, + const void *ptr, + void *data) { - const void **tb; const struct wmi_service_available_event *ev; - int ret; + u32 *wmi_ext2_service_bitmap; int i, j; + u16 expected_len; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); - if (IS_ERR(tb)) { - ret = PTR_ERR(tb); - ath12k_warn(ab, "failed to parse tlv: %d\n", ret); - return; + expected_len = WMI_SERVICE_SEGMENT_BM_SIZE32 * sizeof(u32); + if (len < expected_len) { + ath12k_warn(ab, "invalid length %d for the WMI services available tag 0x%x\n", + len, tag); + return -EINVAL; } - ev = tb[WMI_TAG_SERVICE_AVAILABLE_EVENT]; - if (!ev) { - ath12k_warn(ab, "failed to fetch svc available ev"); - kfree(tb); - return; - } + switch (tag) { + case WMI_TAG_SERVICE_AVAILABLE_EVENT: + ev = (struct wmi_service_available_event *)ptr; + for (i = 0, j = WMI_MAX_SERVICE; + i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT_SERVICE; + i++) { + do { + if (le32_to_cpu(ev->wmi_service_segment_bitmap[i]) & + BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) + set_bit(j, ab->wmi_ab.svc_map); + } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); + } - /* TODO: Use wmi_service_segment_offset information to get the service - * especially when more services are advertised in multiple service - * available events. - */ - for (i = 0, j = WMI_MAX_SERVICE; - i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT_SERVICE; - i++) { - do { - if (le32_to_cpu(ev->wmi_service_segment_bitmap[i]) & - BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) - set_bit(j, ab->wmi_ab.svc_map); - } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi_ext_service_bitmap 0x%x 0x%x 0x%x 0x%x", + ev->wmi_service_segment_bitmap[0], + ev->wmi_service_segment_bitmap[1], + ev->wmi_service_segment_bitmap[2], + ev->wmi_service_segment_bitmap[3]); + break; + case WMI_TAG_ARRAY_UINT32: + wmi_ext2_service_bitmap = (u32 *)ptr; + for (i = 0, j = WMI_MAX_EXT_SERVICE; + i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT2_SERVICE; + i++) { + do { + if (wmi_ext2_service_bitmap[i] & + BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) + set_bit(j, ab->wmi_ab.svc_map); + } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); + } + + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi_ext2_service_bitmap 0x%04x 0x%04x 0x%04x 0x%04x", + wmi_ext2_service_bitmap[0], wmi_ext2_service_bitmap[1], + wmi_ext2_service_bitmap[2], wmi_ext2_service_bitmap[3]); + break; } + return 0; +} - ath12k_dbg(ab, ATH12K_DBG_WMI, - "wmi_ext_service_bitmap 0:0x%x, 1:0x%x, 2:0x%x, 3:0x%x", - ev->wmi_service_segment_bitmap[0], ev->wmi_service_segment_bitmap[1], - ev->wmi_service_segment_bitmap[2], ev->wmi_service_segment_bitmap[3]); +static int ath12k_service_available_event(struct ath12k_base *ab, struct sk_buff *skb) +{ + int ret; - kfree(tb); + ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len, + ath12k_wmi_tlv_services_parser, + NULL); + return ret; } static void ath12k_peer_assoc_conf_event(struct ath12k_base *ab, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 5cae2522fc7c..d89c12bfb009 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -2148,7 +2148,10 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219, WMI_TLV_SERVICE_EXT2_MSG = 220, - WMI_MAX_EXT_SERVICE + WMI_MAX_EXT_SERVICE = 256, + + WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281, + WMI_MAX_EXT2_SERVICE, }; enum { @@ -2333,6 +2336,7 @@ struct ath12k_wmi_resource_config_arg { u32 sched_params; u32 twt_ap_pdev_count; u32 twt_ap_sta_count; + bool is_reg_cc_ext_event_supported; }; struct ath12k_wmi_init_cmd_arg { @@ -4664,7 +4668,7 @@ struct ath12k_wmi_base { struct completion service_ready; struct completion unified_ready; - DECLARE_BITMAP(svc_map, WMI_MAX_EXT_SERVICE); + DECLARE_BITMAP(svc_map, WMI_MAX_EXT2_SERVICE); wait_queue_head_t tx_credits_wq; const struct wmi_peer_flags_map *peer_flags; u32 num_mem_chunks; -- cgit v1.2.3 From dd805cf3e80e038aeb06902399ce9bd6fafb4ff3 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 25 May 2023 11:38:44 +0100 Subject: net: dsa: add support for mac_prepare() and mac_finish() calls Add DSA support for the phylink mac_prepare() and mac_finish() calls. These were introduced as part of the PCS support to allow MACs to perform preparatory steps prior to configuration, and finalisation steps after the MAC and PCS has been configured. Introducing phylink_pcs support to the mv88e6xxx DSA driver needs some code moved out of its mac_config() stage into the mac_prepare() and mac_finish() stages, and this commit facilitates such code in DSA drivers. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- include/net/dsa.h | 6 ++++++ net/dsa/port.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 8903053fa5aa..75022cf771cf 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -867,9 +867,15 @@ struct dsa_switch_ops { phy_interface_t iface); int (*phylink_mac_link_state)(struct dsa_switch *ds, int port, struct phylink_link_state *state); + int (*phylink_mac_prepare)(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface); void (*phylink_mac_config)(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state); + int (*phylink_mac_finish)(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface); void (*phylink_mac_an_restart)(struct dsa_switch *ds, int port); void (*phylink_mac_link_down)(struct dsa_switch *ds, int port, unsigned int mode, diff --git a/net/dsa/port.c b/net/dsa/port.c index 71ba30538411..0ce8fd311c78 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -1603,6 +1603,21 @@ dsa_port_phylink_mac_select_pcs(struct phylink_config *config, return pcs; } +static int dsa_port_phylink_mac_prepare(struct phylink_config *config, + unsigned int mode, + phy_interface_t interface) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + int err = 0; + + if (ds->ops->phylink_mac_prepare) + err = ds->ops->phylink_mac_prepare(ds, dp->index, mode, + interface); + + return err; +} + static void dsa_port_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state) @@ -1616,6 +1631,21 @@ static void dsa_port_phylink_mac_config(struct phylink_config *config, ds->ops->phylink_mac_config(ds, dp->index, mode, state); } +static int dsa_port_phylink_mac_finish(struct phylink_config *config, + unsigned int mode, + phy_interface_t interface) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + int err = 0; + + if (ds->ops->phylink_mac_finish) + err = ds->ops->phylink_mac_finish(ds, dp->index, mode, + interface); + + return err; +} + static void dsa_port_phylink_mac_an_restart(struct phylink_config *config) { struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); @@ -1671,7 +1701,9 @@ static const struct phylink_mac_ops dsa_port_phylink_mac_ops = { .validate = dsa_port_phylink_validate, .mac_select_pcs = dsa_port_phylink_mac_select_pcs, .mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state, + .mac_prepare = dsa_port_phylink_mac_prepare, .mac_config = dsa_port_phylink_mac_config, + .mac_finish = dsa_port_phylink_mac_finish, .mac_an_restart = dsa_port_phylink_mac_an_restart, .mac_link_down = dsa_port_phylink_mac_link_down, .mac_link_up = dsa_port_phylink_mac_link_up, -- cgit v1.2.3 From 267d7692f6cd5c9b8796324cdd54db594ca8d3e4 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 25 May 2023 11:38:50 +0100 Subject: net: dsa: mv88e6xxx: move link forcing to mac_prepare/mac_finish Move the link forcing out of mac_config() and into the mac_prepare() and mac_finish() methods. This results in no change to the order in which these operations are performed, but does mean when we convert mv88e6xxx to phylink_pcs support, we will continue to preserve this ordering. Reviewed-by: Andrew Lunn Signed-off-by: Russell King (Oracle) Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 65 +++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 64a2f2f83735..5bbe95fa951c 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -841,29 +841,38 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, } } +static int mv88e6xxx_mac_prepare(struct dsa_switch *ds, int port, + unsigned int mode, phy_interface_t interface) +{ + struct mv88e6xxx_chip *chip = ds->priv; + int err = 0; + + /* In inband mode, the link may come up at any time while the link + * is not forced down. Force the link down while we reconfigure the + * interface mode. + */ + if (mode == MLO_AN_INBAND && + chip->ports[port].interface != interface && + chip->info->ops->port_set_link) { + mv88e6xxx_reg_lock(chip); + err = chip->info->ops->port_set_link(chip, port, + LINK_FORCED_DOWN); + mv88e6xxx_reg_unlock(chip); + } + + return err; +} + static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) { struct mv88e6xxx_chip *chip = ds->priv; - struct mv88e6xxx_port *p; int err = 0; - p = &chip->ports[port]; - mv88e6xxx_reg_lock(chip); if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(ds, port)) { - /* In inband mode, the link may come up at any time while the - * link is not forced down. Force the link down while we - * reconfigure the interface mode. - */ - if (mode == MLO_AN_INBAND && - p->interface != state->interface && - chip->info->ops->port_set_link) - chip->info->ops->port_set_link(chip, port, - LINK_FORCED_DOWN); - err = mv88e6xxx_port_config_interface(chip, port, state->interface); if (err && err != -EOPNOTSUPP) @@ -880,24 +889,38 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, err = 0; } +err_unlock: + mv88e6xxx_reg_unlock(chip); + + if (err && err != -EOPNOTSUPP) + dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); +} + +static int mv88e6xxx_mac_finish(struct dsa_switch *ds, int port, + unsigned int mode, phy_interface_t interface) +{ + struct mv88e6xxx_chip *chip = ds->priv; + int err = 0; + /* Undo the forced down state above after completing configuration * irrespective of its state on entry, which allows the link to come * up in the in-band case where there is no separate SERDES. Also * ensure that the link can come up if the PPU is in use and we are * in PHY mode (we treat the PPU as an effective in-band mechanism.) */ + mv88e6xxx_reg_lock(chip); + if (chip->info->ops->port_set_link && - ((mode == MLO_AN_INBAND && p->interface != state->interface) || + ((mode == MLO_AN_INBAND && + chip->ports[port].interface != interface) || (mode == MLO_AN_PHY && mv88e6xxx_port_ppu_updates(chip, port)))) - chip->info->ops->port_set_link(chip, port, LINK_UNFORCED); + err = chip->info->ops->port_set_link(chip, port, LINK_UNFORCED); - p->interface = state->interface; - -err_unlock: mv88e6xxx_reg_unlock(chip); - if (err && err != -EOPNOTSUPP) - dev_err(ds->dev, "p%d: failed to configure MAC/PCS\n", port); + chip->ports[port].interface = interface; + + return err; } static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, @@ -7002,7 +7025,9 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .port_teardown = mv88e6xxx_port_teardown, .phylink_get_caps = mv88e6xxx_get_caps, .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, + .phylink_mac_prepare = mv88e6xxx_mac_prepare, .phylink_mac_config = mv88e6xxx_mac_config, + .phylink_mac_finish = mv88e6xxx_mac_finish, .phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart, .phylink_mac_link_down = mv88e6xxx_mac_link_down, .phylink_mac_link_up = mv88e6xxx_mac_link_up, -- cgit v1.2.3 From 59842c5451fe830737600276ba9dee4595341d77 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 25 May 2023 15:13:10 -0700 Subject: libbpf: Ensure libbpf always opens files with O_CLOEXEC Make sure that libbpf code always gets FD with O_CLOEXEC flag set, regardless if file is open through open() or fopen(). For the latter this means to add "e" to mode string, which is supported since pretty ancient glibc v2.7. Also drop the outdated TODO comment in usdt.c, which was already completed. Suggested-by: Lennart Poettering Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230525221311.2136408-1-andrii@kernel.org --- tools/lib/bpf/btf.c | 2 +- tools/lib/bpf/libbpf.c | 6 +++--- tools/lib/bpf/libbpf_probes.c | 2 +- tools/lib/bpf/usdt.c | 5 ++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 0a2c079244b6..8484b563b53d 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -1064,7 +1064,7 @@ static struct btf *btf_parse_raw(const char *path, struct btf *base_btf) int err = 0; long sz; - f = fopen(path, "rb"); + f = fopen(path, "rbe"); if (!f) { err = -errno; goto err_out; diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 1ceb3a97dadc..60ef4c5e3bee 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -4351,7 +4351,7 @@ static int bpf_get_map_info_from_fdinfo(int fd, struct bpf_map_info *info) snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd); memset(info, 0, sizeof(*info)); - fp = fopen(file, "r"); + fp = fopen(file, "re"); if (!fp) { err = -errno; pr_warn("failed to open %s: %d. No procfs support?\n", file, @@ -7455,7 +7455,7 @@ int libbpf_kallsyms_parse(kallsyms_cb_t cb, void *ctx) int ret, err = 0; FILE *f; - f = fopen("/proc/kallsyms", "r"); + f = fopen("/proc/kallsyms", "re"); if (!f) { err = -errno; pr_warn("failed to open /proc/kallsyms: %d\n", err); @@ -10075,7 +10075,7 @@ static int parse_uint_from_file(const char *file, const char *fmt) int err, ret; FILE *f; - f = fopen(file, "r"); + f = fopen(file, "re"); if (!f) { err = -errno; pr_debug("failed to open '%s': %s\n", file, diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c index 6065f408a59c..5f78a023b474 100644 --- a/tools/lib/bpf/libbpf_probes.c +++ b/tools/lib/bpf/libbpf_probes.c @@ -38,7 +38,7 @@ static __u32 get_ubuntu_kernel_version(void) if (faccessat(AT_FDCWD, ubuntu_kver_file, R_OK, AT_EACCESS) != 0) return 0; - f = fopen(ubuntu_kver_file, "r"); + f = fopen(ubuntu_kver_file, "re"); if (!f) return 0; diff --git a/tools/lib/bpf/usdt.c b/tools/lib/bpf/usdt.c index 086eef355ab3..f1a141555f08 100644 --- a/tools/lib/bpf/usdt.c +++ b/tools/lib/bpf/usdt.c @@ -466,7 +466,7 @@ static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs, proceed: sprintf(line, "/proc/%d/maps", pid); - f = fopen(line, "r"); + f = fopen(line, "re"); if (!f) { err = -errno; pr_warn("usdt: failed to open '%s' to get base addr of '%s': %d\n", @@ -954,8 +954,7 @@ struct bpf_link *usdt_manager_attach_usdt(struct usdt_manager *man, const struct spec_map_fd = bpf_map__fd(man->specs_map); ip_map_fd = bpf_map__fd(man->ip_to_spec_id_map); - /* TODO: perform path resolution similar to uprobe's */ - fd = open(path, O_RDONLY); + fd = open(path, O_RDONLY | O_CLOEXEC); if (fd < 0) { err = -errno; pr_warn("usdt: failed to open ELF binary '%s': %d\n", path, err); -- cgit v1.2.3 From 4aadd2920b81b3d7e5c8ac63c7d5d673f3c8aaeb Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 25 May 2023 15:13:11 -0700 Subject: libbpf: Ensure FD >= 3 during bpf_map__reuse_fd() Improve bpf_map__reuse_fd() logic and ensure that dup'ed map FD is "good" (>= 3) and has O_CLOEXEC flags. Use fcntl(F_DUPFD_CLOEXEC) for that, similarly to ensure_good_fd() helper we already use in low-level APIs that work with bpf() syscall. Suggested-by: Lennart Poettering Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230525221311.2136408-2-andrii@kernel.org --- tools/lib/bpf/libbpf.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 60ef4c5e3bee..47632606b06d 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -4414,18 +4414,17 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd) if (!new_name) return libbpf_err(-errno); - new_fd = open("/", O_RDONLY | O_CLOEXEC); + /* + * Like dup(), but make sure new FD is >= 3 and has O_CLOEXEC set. + * This is similar to what we do in ensure_good_fd(), but without + * closing original FD. + */ + new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); if (new_fd < 0) { err = -errno; goto err_free_new_name; } - new_fd = dup3(fd, new_fd, O_CLOEXEC); - if (new_fd < 0) { - err = -errno; - goto err_close_new_fd; - } - err = zclose(map->fd); if (err) { err = -errno; -- cgit v1.2.3 From 4266f41feaeee2521749ce2cfb52eafd4e2947c5 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 26 May 2023 12:13:56 +0200 Subject: bpf: Fix bad unlock balance on freeze_mutex Commit c4c84f6fb2c4 ("bpf: drop unnecessary bpf_capable() check in BPF_MAP_FREEZE command") moved the permissions check outside of the freeze_mutex in the map_freeze() handler. The error paths still jumps to the err_put which tries to unlock the freeze_mutex even though it was not locked in the first place. Fix it. Fixes: c4c84f6fb2c4 ("bpf: drop unnecessary bpf_capable() check in BPF_MAP_FREEZE command") Reported-by: syzbot+8982e75c2878b9ffeac5@syzkaller.appspotmail.com Signed-off-by: Daniel Borkmann --- kernel/bpf/syscall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index c9a201e4c457..92a57efc77de 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1932,8 +1932,8 @@ static int map_freeze(const union bpf_attr *attr) } if (!(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) { - err = -EPERM; - goto err_put; + fdput(f); + return -EPERM; } mutex_lock(&map->freeze_mutex); -- cgit v1.2.3 From f26f03b3031938ad46c3fb617745e9fd4a289ce7 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Thu, 25 May 2023 10:57:36 -0400 Subject: tcp: remove unused TCP_SYNQ_INTERVAL definition Currently TCP_SYNQ_INTERVAL is defined but never used. According to "git log -S TCP_SYNQ_INTERVAL net-next/main" it seems the last references to TCP_SYNQ_INTERVAL were removed by 2015 commit fa76ce7328b2 ("inet: get rid of central tcp/dccp listener timer") Signed-off-by: Neal Cardwell Reviewed-by: Simon Horman Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 34f2df9e23c5..0b755988e20c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -161,8 +161,6 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); #define MAX_TCP_KEEPCNT 127 #define MAX_TCP_SYNCNT 127 -#define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */ - #define TCP_PAWS_24DAYS (60 * 60 * 24 * 24) #define TCP_PAWS_MSL 60 /* Per-host timestamps are invalidated * after this time. It should be equal -- cgit v1.2.3 From 4781e965e655b0f1736856908f861939dac79b4e Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 25 May 2023 10:59:15 -0700 Subject: net: phy: broadcom: Register dummy IRQ handler In order to have our interrupt descriptor fully setup and in particular the action, ensure that we register a full fledged interrupt handler. This also allow us to set the interrupt polarity and flow through the same call. This is specifically necessary for kernel/irq/pm.c::suspend_device_irq to set the interrupt descriptor to the IRQD_WAKEUP_ARMED state and enable the interrupt for wake-up since it was still in a disabled state. Without an interrupt descriptor we would have ran into cases where the wake-up interrupt is not capable of waking up the system, specifically if we resumed the system ACPI S5 using the Ethernet PHY. In that case the Ethernet PHY interrupt would be pending by the time the kernel booted, which it would acknowledge but then we could never use it as a wake-up source again. Fixes: 8baddaa9d4ba ("net: phy: broadcom: Add support for Wake-on-LAN") Suggested-by: Doug Berger Debugged-by: Doug Berger Signed-off-by: Florian Fainelli Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/phy/bcm-phy-lib.c | 6 ++++++ drivers/net/phy/bcm-phy-lib.h | 2 ++ drivers/net/phy/broadcom.c | 9 ++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index 27c57f6ab211..5603d0a9ce96 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -1028,6 +1028,12 @@ void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) } EXPORT_SYMBOL_GPL(bcm_phy_get_wol); +irqreturn_t bcm_phy_wol_isr(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(bcm_phy_wol_isr); + MODULE_DESCRIPTION("Broadcom PHY Library"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Broadcom Corporation"); diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index c6fed43ec913..2f30ce0cab0e 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -8,6 +8,7 @@ #include #include +#include struct ethtool_wolinfo; @@ -115,5 +116,6 @@ static inline void bcm_ptp_stop(struct bcm_ptp_private *priv) int bcm_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); +irqreturn_t bcm_phy_wol_isr(int irq, void *dev_id); #endif /* _LINUX_BCM_PHY_LIB_H */ diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 418e6bc0e998..822c8b01dc53 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -927,7 +927,14 @@ static int bcm54xx_phy_probe(struct phy_device *phydev) if (!IS_ERR(wakeup_gpio)) { priv->wake_irq = gpiod_to_irq(wakeup_gpio); - ret = irq_set_irq_type(priv->wake_irq, IRQ_TYPE_LEVEL_LOW); + + /* Dummy interrupt handler which is not enabled but is provided + * in order for the interrupt descriptor to be fully set-up. + */ + ret = devm_request_irq(&phydev->mdio.dev, priv->wake_irq, + bcm_phy_wol_isr, + IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN, + dev_name(&phydev->mdio.dev), phydev); if (ret) return ret; } -- cgit v1.2.3 From daef020558bc34e8031263aa7cf9e803d709f93a Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Thu, 16 Mar 2023 21:32:35 +0800 Subject: wifi: ray_cs: remove one redundant del_timer In ray_detach, it and its child function ray_release both call del_timer(_sync) on the same timer. Fix this by removing the del_timer_sync in the ray_detach, and revising the del_timer to del_timer_sync. Signed-off-by: Dongliang Mu Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230316133236.556198-2-dzm91@hust.edu.cn --- drivers/net/wireless/legacy/ray_cs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c index 38782d4c4694..93eaf3dba6a9 100644 --- a/drivers/net/wireless/legacy/ray_cs.c +++ b/drivers/net/wireless/legacy/ray_cs.c @@ -328,7 +328,6 @@ err_free_dev: static void ray_detach(struct pcmcia_device *link) { struct net_device *dev; - ray_dev_t *local; dev_dbg(&link->dev, "ray_detach\n"); @@ -337,9 +336,6 @@ static void ray_detach(struct pcmcia_device *link) ray_release(link); - local = netdev_priv(dev); - del_timer_sync(&local->timer); - if (link->priv) { unregister_netdev(dev); free_netdev(dev); @@ -740,7 +736,7 @@ static void ray_release(struct pcmcia_device *link) dev_dbg(&link->dev, "ray_release\n"); - del_timer(&local->timer); + del_timer_sync(&local->timer); iounmap(local->sram); iounmap(local->rmem); -- cgit v1.2.3 From 072210c725c4938682e58236eeeb19a2ddd0b817 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Thu, 16 Mar 2023 21:32:36 +0800 Subject: wifi: ray_cs: add sanity check on local->sram/rmem/amem The ray_config uses ray_release as its unified error handling function. However, it does not know if local->sram/rmem/amem succeeds or not. Fix this by adding sanity check on local->sram/rmem/amem in the ray_relase. Signed-off-by: Dongliang Mu Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230316133236.556198-3-dzm91@hust.edu.cn --- drivers/net/wireless/legacy/ray_cs.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c index 93eaf3dba6a9..4b53a9c70e7e 100644 --- a/drivers/net/wireless/legacy/ray_cs.c +++ b/drivers/net/wireless/legacy/ray_cs.c @@ -738,9 +738,12 @@ static void ray_release(struct pcmcia_device *link) del_timer_sync(&local->timer); - iounmap(local->sram); - iounmap(local->rmem); - iounmap(local->amem); + if (local->sram) + iounmap(local->sram); + if (local->rmem) + iounmap(local->rmem); + if (local->amem) + iounmap(local->amem); pcmcia_disable_device(link); dev_dbg(&link->dev, "ray_release ending\n"); -- cgit v1.2.3 From 1f1784a59caf3eefd127908a1a3cf224017ff9c7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 24 May 2023 12:39:34 +0200 Subject: wifi: rtw88: usb: silence log flooding error message When receiving more rx packets than the kernel can handle the driver drops the packets and issues an error message. This is bad for two reasons. The logs are flooded with myriads of messages, but then time consumed for printing messages in that critical code path brings down the device. After some time of excessive rx load the driver responds with: rtw_8822cu 1-1:1.2: failed to get tx report from firmware rtw_8822cu 1-1:1.2: firmware failed to report density after scan rtw_8822cu 1-1:1.2: firmware failed to report density after scan The device stops working until being replugged. Fix this by lowering the priority to debug level and also by ratelimiting it. Fixes: a82dfd33d1237 ("wifi: rtw88: Add common USB chip support") Signed-off-by: Sascha Hauer Reviewed-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230524103934.1019096-1-s.hauer@pengutronix.de --- drivers/net/wireless/realtek/rtw88/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index 44a5fafb9905..976eafa739a2 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -535,7 +535,7 @@ static void rtw_usb_rx_handler(struct work_struct *work) } if (skb_queue_len(&rtwusb->rx_queue) >= RTW_USB_MAX_RXQ_LEN) { - rtw_err(rtwdev, "failed to get rx_queue, overflow\n"); + dev_dbg_ratelimited(rtwdev->dev, "failed to get rx_queue, overflow\n"); dev_kfree_skb_any(skb); continue; } -- cgit v1.2.3 From c4933fa88a68c69205753601044949d516c4db10 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 26 May 2023 11:14:24 +0100 Subject: net: mdio: add mdio_device_get() and mdio_device_put() Add two new operations for a mdio device to manage the refcount on the underlying struct device. This will be used by mdio PCS drivers to simplify the creation and destruction handling, making it easier for users to get it correct. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- include/linux/mdio.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 0670cc6e067c..c1b7008826e5 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -106,6 +106,16 @@ int mdio_driver_register(struct mdio_driver *drv); void mdio_driver_unregister(struct mdio_driver *drv); int mdio_device_bus_match(struct device *dev, struct device_driver *drv); +static inline void mdio_device_get(struct mdio_device *mdiodev) +{ + get_device(&mdiodev->dev); +} + +static inline void mdio_device_put(struct mdio_device *mdiodev) +{ + mdio_device_free(mdiodev); +} + static inline bool mdio_phy_id_is_c45(int phy_id) { return (phy_id & MDIO_PHY_ID_C45) && !(phy_id & ~MDIO_PHY_ID_C45_MASK); -- cgit v1.2.3 From 9a5d500cffdb3652215172b7c5829ca7b41e9efe Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 26 May 2023 11:14:29 +0100 Subject: net: pcs: xpcs: add xpcs_create_mdiodev() Add xpcs_create_mdiodev() to simplify the creation of the mdio device associated with the XPCS. In order to allow xpcs_destroy() to clean this up, we need to arrange for xpcs_create() to take a refcount on the mdiodev, and xpcs_destroy() to put it. Adding the refcounting to xpcs_create()..xpcs_destroy() will be transparent to existing users of these interfaces. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-xpcs.c | 28 ++++++++++++++++++++++++++++ include/linux/pcs/pcs-xpcs.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 736776e40c25..1ba214429e01 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -1235,6 +1235,7 @@ struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, if (!xpcs) return ERR_PTR(-ENOMEM); + mdio_device_get(mdiodev); xpcs->mdiodev = mdiodev; xpcs_id = xpcs_get_id(xpcs); @@ -1267,6 +1268,7 @@ struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, ret = -ENODEV; out: + mdio_device_put(mdiodev); kfree(xpcs); return ERR_PTR(ret); @@ -1275,8 +1277,34 @@ EXPORT_SYMBOL_GPL(xpcs_create); void xpcs_destroy(struct dw_xpcs *xpcs) { + if (xpcs) + mdio_device_put(xpcs->mdiodev); kfree(xpcs); } EXPORT_SYMBOL_GPL(xpcs_destroy); +struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr, + phy_interface_t interface) +{ + struct mdio_device *mdiodev; + struct dw_xpcs *xpcs; + + mdiodev = mdio_device_create(bus, addr); + if (IS_ERR(mdiodev)) + return ERR_CAST(mdiodev); + + xpcs = xpcs_create(mdiodev, interface); + + /* xpcs_create() has taken a refcount on the mdiodev if it was + * successful. If xpcs_create() fails, this will free the mdio + * device here. In any case, we don't need to hold our reference + * anymore, and putting it here will allow mdio_device_put() in + * xpcs_destroy() to automatically free the mdio device. + */ + mdio_device_put(mdiodev); + + return xpcs; +} +EXPORT_SYMBOL_GPL(xpcs_create_mdiodev); + MODULE_LICENSE("GPL v2"); diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index d2da1e0b4a92..a99972a6d046 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -37,6 +37,8 @@ int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable); struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, phy_interface_t interface); +struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr, + phy_interface_t interface); void xpcs_destroy(struct dw_xpcs *xpcs); #endif /* __LINUX_PCS_XPCS_H */ -- cgit v1.2.3 From 727e373f897d06214ffc59f820a356a5bc458789 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 26 May 2023 11:14:34 +0100 Subject: net: stmmac: use xpcs_create_mdiodev() Use the new xpcs_create_mdiodev() creator, which simplifies the creation and destruction of the mdio device associated with xpcs. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 6807c4c1a0a2..3db1cb0fd160 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -491,7 +491,6 @@ int stmmac_mdio_reset(struct mii_bus *bus) int stmmac_xpcs_setup(struct mii_bus *bus) { struct net_device *ndev = bus->priv; - struct mdio_device *mdiodev; struct stmmac_priv *priv; struct dw_xpcs *xpcs; int mode, addr; @@ -501,16 +500,10 @@ int stmmac_xpcs_setup(struct mii_bus *bus) /* Try to probe the XPCS by scanning all addresses. */ for (addr = 0; addr < PHY_MAX_ADDR; addr++) { - mdiodev = mdio_device_create(bus, addr); - if (IS_ERR(mdiodev)) + xpcs = xpcs_create_mdiodev(bus, addr, mode); + if (IS_ERR(xpcs)) continue; - xpcs = xpcs_create(mdiodev, mode); - if (IS_ERR_OR_NULL(xpcs)) { - mdio_device_free(mdiodev); - continue; - } - priv->hw->xpcs = xpcs; break; } @@ -669,10 +662,8 @@ int stmmac_mdio_unregister(struct net_device *ndev) if (!priv->mii) return 0; - if (priv->hw->xpcs) { - mdio_device_free(priv->hw->xpcs->mdiodev); + if (priv->hw->xpcs) xpcs_destroy(priv->hw->xpcs); - } mdiobus_unregister(priv->mii); priv->mii->priv = NULL; -- cgit v1.2.3 From 86b5f2d8cd7828c881036d30ce3a4e711a071726 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 26 May 2023 11:14:39 +0100 Subject: net: pcs: lynx: add lynx_pcs_create_mdiodev() Add lynx_pcs_create_mdiodev() to simplify the creation of the mdio device associated with lynx PCS. In order to allow lynx_pcs_destroy() to clean this up, we need to arrange for lynx_pcs_create() to take a refcount on the mdiodev, and lynx_pcs_destroy() to put it. Adding the refcounting to lynx_pcs_create()..lynx_pcs_destroy() will be transparent to existing users of these interfaces. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Reviewed-by: Ioana Ciornei Tested-by: Ioana Ciornei Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-lynx.c | 31 +++++++++++++++++++++++++++++++ include/linux/pcs-lynx.h | 1 + 2 files changed, 32 insertions(+) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index 622c3de3f3a8..f04dc580ffb8 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -323,6 +323,7 @@ struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) if (!lynx) return NULL; + mdio_device_get(mdio); lynx->mdio = mdio; lynx->pcs.ops = &lynx_pcs_phylink_ops; lynx->pcs.poll = true; @@ -331,10 +332,40 @@ struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) } EXPORT_SYMBOL(lynx_pcs_create); +struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr) +{ + struct mdio_device *mdio; + struct phylink_pcs *pcs; + + mdio = mdio_device_create(bus, addr); + if (IS_ERR(mdio)) + return ERR_CAST(mdio); + + pcs = lynx_pcs_create(mdio); + + /* Convert failure to create the PCS to an error pointer, so this + * function has a consistent return value strategy. + */ + if (!pcs) + pcs = ERR_PTR(-ENOMEM); + + /* lynx_create() has taken a refcount on the mdiodev if it was + * successful. If lynx_create() fails, this will free the mdio + * device here. In any case, we don't need to hold our reference + * anymore, and putting it here will allow mdio_device_put() in + * lynx_destroy() to automatically free the mdio device. + */ + mdio_device_put(mdio); + + return pcs; +} +EXPORT_SYMBOL(lynx_pcs_create_mdiodev); + void lynx_pcs_destroy(struct phylink_pcs *pcs) { struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); + mdio_device_put(lynx->mdio); kfree(lynx); } EXPORT_SYMBOL(lynx_pcs_destroy); diff --git a/include/linux/pcs-lynx.h b/include/linux/pcs-lynx.h index 5712cc2ce775..885b59d10581 100644 --- a/include/linux/pcs-lynx.h +++ b/include/linux/pcs-lynx.h @@ -12,6 +12,7 @@ struct mdio_device *lynx_get_mdio_device(struct phylink_pcs *pcs); struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio); +struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr); void lynx_pcs_destroy(struct phylink_pcs *pcs); -- cgit v1.2.3 From 5767c6a8d9b7893db16702b67287cadeeff57a4a Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 26 May 2023 11:14:44 +0100 Subject: net: dsa: ocelot: use lynx_pcs_create_mdiodev() Use the newly introduced lynx_pcs_create_mdiodev() which simplifies the creation and destruction of the lynx PCS. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Tested-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/dsa/ocelot/felix_vsc9959.c | 20 ++++---------------- drivers/net/dsa/ocelot/seville_vsc9953.c | 20 ++++---------------- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index cfb3faeaa5bf..030738fef60e 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1021,7 +1021,6 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) for (port = 0; port < felix->info->num_ports; port++) { struct ocelot_port *ocelot_port = ocelot->ports[port]; struct phylink_pcs *phylink_pcs; - struct mdio_device *mdio_device; if (dsa_is_unused_port(felix->ds, port)) continue; @@ -1029,16 +1028,10 @@ static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_INTERNAL) continue; - mdio_device = mdio_device_create(felix->imdio, port); - if (IS_ERR(mdio_device)) + phylink_pcs = lynx_pcs_create_mdiodev(felix->imdio, port); + if (IS_ERR(phylink_pcs)) continue; - phylink_pcs = lynx_pcs_create(mdio_device); - if (!phylink_pcs) { - mdio_device_free(mdio_device); - continue; - } - felix->pcs[port] = phylink_pcs; dev_info(dev, "Found PCS at internal MDIO address %d\n", port); @@ -1054,14 +1047,9 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot) for (port = 0; port < ocelot->num_phys_ports; port++) { struct phylink_pcs *phylink_pcs = felix->pcs[port]; - struct mdio_device *mdio_device; - - if (!phylink_pcs) - continue; - mdio_device = lynx_get_mdio_device(phylink_pcs); - mdio_device_free(mdio_device); - lynx_pcs_destroy(phylink_pcs); + if (phylink_pcs) + lynx_pcs_destroy(phylink_pcs); } mdiobus_unregister(felix->imdio); mdiobus_free(felix->imdio); diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index 96d4972a62f0..15003b2af264 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -912,7 +912,6 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot) for (port = 0; port < felix->info->num_ports; port++) { struct ocelot_port *ocelot_port = ocelot->ports[port]; struct phylink_pcs *phylink_pcs; - struct mdio_device *mdio_device; int addr = port + 4; if (dsa_is_unused_port(felix->ds, port)) @@ -921,16 +920,10 @@ static int vsc9953_mdio_bus_alloc(struct ocelot *ocelot) if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_INTERNAL) continue; - mdio_device = mdio_device_create(felix->imdio, addr); - if (IS_ERR(mdio_device)) + phylink_pcs = lynx_pcs_create_mdiodev(felix->imdio, addr); + if (IS_ERR(phylink_pcs)) continue; - phylink_pcs = lynx_pcs_create(mdio_device); - if (!phylink_pcs) { - mdio_device_free(mdio_device); - continue; - } - felix->pcs[port] = phylink_pcs; dev_info(dev, "Found PCS at internal MDIO address %d\n", addr); @@ -946,14 +939,9 @@ static void vsc9953_mdio_bus_free(struct ocelot *ocelot) for (port = 0; port < ocelot->num_phys_ports; port++) { struct phylink_pcs *phylink_pcs = felix->pcs[port]; - struct mdio_device *mdio_device; - - if (!phylink_pcs) - continue; - mdio_device = lynx_get_mdio_device(phylink_pcs); - mdio_device_free(mdio_device); - lynx_pcs_destroy(phylink_pcs); + if (phylink_pcs) + lynx_pcs_destroy(phylink_pcs); } /* mdiobus_unregister and mdiobus_free handled by devres */ -- cgit v1.2.3 From b7d5d0438e01c7c61db5fc87d92ad8cb1166f217 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 26 May 2023 11:14:50 +0100 Subject: net: enetc: use lynx_pcs_create_mdiodev() Use the newly introduced lynx_pcs_create_mdiodev() which simplifies the creation and destruction of the lynx PCS. Signed-off-by: Russell King (Oracle) Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Tested-by: Vladimir Oltean Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/enetc/enetc_pf.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index 7cd22d370caa..1416262d4296 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -863,7 +863,6 @@ static int enetc_imdio_create(struct enetc_pf *pf) struct device *dev = &pf->si->pdev->dev; struct enetc_mdio_priv *mdio_priv; struct phylink_pcs *phylink_pcs; - struct mdio_device *mdio_device; struct mii_bus *bus; int err; @@ -889,17 +888,9 @@ static int enetc_imdio_create(struct enetc_pf *pf) goto free_mdio_bus; } - mdio_device = mdio_device_create(bus, 0); - if (IS_ERR(mdio_device)) { - err = PTR_ERR(mdio_device); - dev_err(dev, "cannot create mdio device (%d)\n", err); - goto unregister_mdiobus; - } - - phylink_pcs = lynx_pcs_create(mdio_device); - if (!phylink_pcs) { - mdio_device_free(mdio_device); - err = -ENOMEM; + phylink_pcs = lynx_pcs_create_mdiodev(bus, 0); + if (IS_ERR(phylink_pcs)) { + err = PTR_ERR(phylink_pcs); dev_err(dev, "cannot create lynx pcs (%d)\n", err); goto unregister_mdiobus; } @@ -918,13 +909,8 @@ free_mdio_bus: static void enetc_imdio_remove(struct enetc_pf *pf) { - struct mdio_device *mdio_device; - - if (pf->pcs) { - mdio_device = lynx_get_mdio_device(pf->pcs); - mdio_device_free(mdio_device); + if (pf->pcs) lynx_pcs_destroy(pf->pcs); - } if (pf->imdio) { mdiobus_unregister(pf->imdio); mdiobus_free(pf->imdio); -- cgit v1.2.3 From 404621fab27310c231bab9a3999eab858390cb45 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 26 May 2023 12:44:43 +0100 Subject: net: dpaa2-mac: use correct interface to free mdiodev Rather than using put_device(&mdiodev->dev), use the proper interface provided to dispose of the mdiodev - that being mdio_device_free(). Signed-off-by: Russell King (Oracle) Reviewed-by: Simon Horman Reviewed-by: Ioana Ciornei Tested-by: Ioana Ciornei Link: https://lore.kernel.org/r/E1q2VsB-008QlZ-El@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index b1871e6c4006..cb70855e2b9a 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -273,7 +273,7 @@ static int dpaa2_pcs_create(struct dpaa2_mac *mac, mac->pcs = lynx_pcs_create(mdiodev); if (!mac->pcs) { netdev_err(mac->net_dev, "lynx_pcs_create() failed\n"); - put_device(&mdiodev->dev); + mdio_device_free(mdiodev); return -ENOMEM; } @@ -286,10 +286,9 @@ static void dpaa2_pcs_destroy(struct dpaa2_mac *mac) if (phylink_pcs) { struct mdio_device *mdio = lynx_get_mdio_device(phylink_pcs); - struct device *dev = &mdio->dev; lynx_pcs_destroy(phylink_pcs); - put_device(dev); + mdio_device_free(mdio); mac->pcs = NULL; } } -- cgit v1.2.3 From ef1bc119ceb52d22a83f72b8dfce1dd64a3cca05 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 26 May 2023 16:39:15 +0300 Subject: net: fix signedness bug in skb_splice_from_iter() The "len" variable needs to be signed for the error handling to work correctly. Fixes: 2e910b95329c ("net: Add a function to splice pages into an skbuff for MSG_SPLICE_PAGES") Signed-off-by: Dan Carpenter Reviewed-by: David Howells Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/366861a7-87c8-4bbf-9101-69dd41021d07@kili.mountain Signed-off-by: Jakub Kicinski --- net/core/skbuff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 653abd8a6975..7c4338221b17 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -6931,8 +6931,8 @@ ssize_t skb_splice_from_iter(struct sk_buff *skb, struct iov_iter *iter, unsigned int i; while (iter->count > 0) { - ssize_t space, nr; - size_t off, len; + ssize_t space, nr, len; + size_t off; ret = -EMSGSIZE; space = frag_limit - skb_shinfo(skb)->nr_frags; -- cgit v1.2.3 From 45402f04c5821a0c42c5d8b17e4abad504e598bb Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 26 May 2023 15:45:13 +0200 Subject: devlink: Spelling corrections Make some minor spelling corrections in comments. Found by inspection. Signed-off-by: Simon Horman Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20230526-devlink-spelling-v1-1-9a3e36cdebc8@kernel.org Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 2 +- net/devlink/leftover.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/devlink.h b/include/net/devlink.h index 1bd56c8d6f3c..ec109b39c3ea 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1261,7 +1261,7 @@ struct devlink_ops { /** * @supported_flash_update_params: * mask of parameters supported by the driver's .flash_update - * implemementation. + * implementation. */ u32 supported_flash_update_params; unsigned long reload_actions; diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 0410137a4a31..9e801b749194 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -6761,7 +6761,7 @@ static void devlink_port_type_warn_cancel(struct devlink_port *devlink_port) * @devlink: devlink * @devlink_port: devlink port * - * Initialize essencial stuff that is needed for functions + * Initialize essential stuff that is needed for functions * that may be called before devlink port registration. * Call to this function is optional and not needed * in case the driver does not use such functions. @@ -6782,7 +6782,7 @@ EXPORT_SYMBOL_GPL(devlink_port_init); * * @devlink_port: devlink port * - * Deinitialize essencial stuff that is in use for functions + * Deinitialize essential stuff that is in use for functions * that may be called after devlink port unregistration. * Call to this function is optional and not needed * in case the driver does not use such functions. -- cgit v1.2.3 From 6d6bae63053d547e96fe4d2c9c8b4fc595bfc5ac Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Sat, 27 May 2023 14:31:04 +0100 Subject: doc: ynl: Add doc attr to struct members in genetlink-legacy spec Make it possible to document the meaning of struct member attributes in genetlink-legacy specs. Signed-off-by: Donald Hunter Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-legacy.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index b5319cde9e17..d8f132114308 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -124,6 +124,9 @@ properties: $ref: '#/$defs/len-or-define' byte-order: enum: [ little-endian, big-endian ] + doc: + description: Documentation for the struct member attribute. + type: string # End genetlink-legacy attribute-sets: -- cgit v1.2.3 From 5ac18889bde04ed2d4f2559da01e9b160234525c Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Sat, 27 May 2023 14:31:05 +0100 Subject: tools: ynl: Initialise fixed headers to 0 in genetlink-legacy This eliminates the need for e.g. --json '{"dp-ifindex":0}' which is not too big a deal for ovs but will get tiresome for fixed header structs that have many members. Signed-off-by: Donald Hunter Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/ynl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 39a2296c0003..85ee6a4bee72 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -541,7 +541,7 @@ class YnlFamily(SpecFamily): if op.fixed_header: fixed_header_members = self.consts[op.fixed_header].members for m in fixed_header_members: - value = vals.pop(m.name) + value = vals.pop(m.name) if m.name in vals else 0 format = NlAttr.get_format(m.type, m.byte_order) msg += format.pack(value) for name, value in vals.items(): -- cgit v1.2.3 From 313a7a808ca8ca0fe08e2175eb145479bd86937e Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Sat, 27 May 2023 14:31:06 +0100 Subject: tools: ynl: Support enums in struct members in genetlink-legacy Support decoding scalars as enums in struct members for genetlink-legacy specs. Signed-off-by: Donald Hunter Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-legacy.yaml | 3 +++ tools/net/ynl/lib/nlspec.py | 2 ++ tools/net/ynl/lib/ynl.py | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index d8f132114308..ac4350498f5e 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -127,6 +127,9 @@ properties: doc: description: Documentation for the struct member attribute. type: string + enum: + description: Name of the enum type used for the attribute. + type: string # End genetlink-legacy attribute-sets: diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index c624cdfde223..ada22b073aa2 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -228,11 +228,13 @@ class SpecStructMember(SpecElement): Attributes: type string, type of the member attribute byte_order string or None for native byte order + enum string, name of the enum definition """ def __init__(self, family, yaml): super().__init__(family, yaml) self.type = yaml['type'] self.byte_order = yaml.get('byte-order') + self.enum = yaml.get('enum') class SpecStruct(SpecElement): diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 85ee6a4bee72..0692293447ad 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -412,7 +412,11 @@ class YnlFamily(SpecFamily): def _decode_binary(self, attr, attr_spec): if attr_spec.struct_name: - decoded = attr.as_struct(self.consts[attr_spec.struct_name]) + members = self.consts[attr_spec.struct_name] + decoded = attr.as_struct(members) + for m in members: + if m.enum: + self._decode_enum(decoded, m) elif attr_spec.sub_type: decoded = attr.as_c_array(attr_spec.sub_type) else: -- cgit v1.2.3 From 93b230b549bcb4daed82d617f3f6f9d6d118befe Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Sat, 27 May 2023 14:31:07 +0100 Subject: netlink: specs: add ynl spec for ovs_flow Add a ynl specification for ovs_flow. This spec is sufficient to dump ovs flows. Some attrs are left as binary blobs because ynl doesn't support C arrays in struct definitions yet. Signed-off-by: Donald Hunter Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/ovs_flow.yaml | 831 ++++++++++++++++++++++++++++++ 1 file changed, 831 insertions(+) create mode 100644 Documentation/netlink/specs/ovs_flow.yaml diff --git a/Documentation/netlink/specs/ovs_flow.yaml b/Documentation/netlink/specs/ovs_flow.yaml new file mode 100644 index 000000000000..3b0624c87074 --- /dev/null +++ b/Documentation/netlink/specs/ovs_flow.yaml @@ -0,0 +1,831 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: ovs_flow +version: 1 +protocol: genetlink-legacy + +doc: + OVS flow configuration over generic netlink. + +definitions: + - + name: ovs-header + type: struct + doc: | + Header for OVS Generic Netlink messages. + members: + - + name: dp-ifindex + type: u32 + doc: | + ifindex of local port for datapath (0 to make a request not specific + to a datapath). + - + name: ovs-flow-stats + type: struct + members: + - + name: n-packets + type: u64 + doc: Number of matched packets. + - + name: n-bytes + type: u64 + doc: Number of matched bytes. + - + name: ovs-key-mpls + type: struct + members: + - + name: mpls-lse + type: u32 + byte-order: big-endian + - + name: ovs-key-ipv4 + type: struct + members: + - + name: ipv4-src + type: u32 + byte-order: big-endian + - + name: ipv4-dst + type: u32 + byte-order: big-endian + - + name: ipv4-proto + type: u8 + - + name: ipv4-tos + type: u8 + - + name: ipv4-ttl + type: u8 + - + name: ipv4-frag + type: u8 + enum: ovs-frag-type + - + name: ovs-frag-type + type: enum + entries: + - + name: none + doc: Packet is not a fragment. + - + name: first + doc: Packet is a fragment with offset 0. + - + name: later + doc: Packet is a fragment with nonzero offset. + - + name: any + value: 255 + - + name: ovs-key-tcp + type: struct + members: + - + name: tcp-src + type: u16 + byte-order: big-endian + - + name: tcp-dst + type: u16 + byte-order: big-endian + - + name: ovs-key-udp + type: struct + members: + - + name: udp-src + type: u16 + byte-order: big-endian + - + name: udp-dst + type: u16 + byte-order: big-endian + - + name: ovs-key-sctp + type: struct + members: + - + name: sctp-src + type: u16 + byte-order: big-endian + - + name: sctp-dst + type: u16 + byte-order: big-endian + - + name: ovs-key-icmp + type: struct + members: + - + name: icmp-type + type: u8 + - + name: icmp-code + type: u8 + - + name: ovs-key-ct-tuple-ipv4 + type: struct + members: + - + name: ipv4-src + type: u32 + byte-order: big-endian + - + name: ipv4-dst + type: u32 + byte-order: big-endian + - + name: src-port + type: u16 + byte-order: big-endian + - + name: dst-port + type: u16 + byte-order: big-endian + - + name: ipv4-proto + type: u8 + - + name: ovs-action-push-vlan + type: struct + members: + - + name: vlan_tpid + type: u16 + byte-order: big-endian + doc: Tag protocol identifier (TPID) to push. + - + name: vlan_tci + type: u16 + byte-order: big-endian + doc: Tag control identifier (TCI) to push. + - + name: ovs-ufid-flags + type: flags + entries: + - omit-key + - omit-mask + - omit-actions + - + name: ovs-action-hash + type: struct + members: + - + name: hash-algorithm + type: u32 + doc: Algorithm used to compute hash prior to recirculation. + - + name: hash-basis + type: u32 + doc: Basis used for computing hash. + - + name: ovs-hash-alg + type: enum + doc: | + Data path hash algorithm for computing Datapath hash. The algorithm type only specifies + the fields in a flow will be used as part of the hash. Each datapath is free to use its + own hash algorithm. The hash value will be opaque to the user space daemon. + entries: + - ovs-hash-alg-l4 + + - + name: ovs-action-push-mpls + type: struct + members: + - + name: lse + type: u32 + byte-order: big-endian + doc: | + MPLS label stack entry to push + - + name: ethertype + type: u32 + byte-order: big-endian + doc: | + Ethertype to set in the encapsulating ethernet frame. The only values + ethertype should ever be given are ETH_P_MPLS_UC and ETH_P_MPLS_MC, + indicating MPLS unicast or multicast. Other are rejected. + - + name: ovs-action-add-mpls + type: struct + members: + - + name: lse + type: u32 + byte-order: big-endian + doc: | + MPLS label stack entry to push + - + name: ethertype + type: u32 + byte-order: big-endian + doc: | + Ethertype to set in the encapsulating ethernet frame. The only values + ethertype should ever be given are ETH_P_MPLS_UC and ETH_P_MPLS_MC, + indicating MPLS unicast or multicast. Other are rejected. + - + name: tun-flags + type: u16 + doc: | + MPLS tunnel attributes. + - + name: ct-state-flags + type: flags + entries: + - + name: new + doc: Beginning of a new connection. + - + name: established + doc: Part of an existing connenction + - + name: related + doc: Related to an existing connection. + - + name: reply-dir + doc: Flow is in the reply direction. + - + name: invalid + doc: Could not track the connection. + - + name: tracked + doc: Conntrack has occurred. + - + name: src-nat + doc: Packet's source address/port was mangled by NAT. + - + name: dst-nat + doc: Packet's destination address/port was mangled by NAT. + +attribute-sets: + - + name: flow-attrs + attributes: + - + name: key + type: nest + nested-attributes: key-attrs + doc: | + Nested attributes specifying the flow key. Always present in + notifications. Required for all requests (except dumps). + - + name: actions + type: nest + nested-attributes: action-attrs + doc: | + Nested attributes specifying the actions to take for packets that + match the key. Always present in notifications. Required for + OVS_FLOW_CMD_NEW requests, optional for OVS_FLOW_CMD_SET requests. An + OVS_FLOW_CMD_SET without OVS_FLOW_ATTR_ACTIONS will not modify the + actions. To clear the actions, an OVS_FLOW_ATTR_ACTIONS without any + nested attributes must be given. + - + name: stats + type: binary + struct: ovs-flow-stats + doc: | + Statistics for this flow. Present in notifications if the stats would + be nonzero. Ignored in requests. + - + name: tcp-flags + type: u8 + doc: | + An 8-bit value giving the ORed value of all of the TCP flags seen on + packets in this flow. Only present in notifications for TCP flows, and + only if it would be nonzero. Ignored in requests. + - + name: used + type: u64 + doc: | + A 64-bit integer giving the time, in milliseconds on the system + monotonic clock, at which a packet was last processed for this + flow. Only present in notifications if a packet has been processed for + this flow. Ignored in requests. + - + name: clear + type: flag + doc: | + If present in a OVS_FLOW_CMD_SET request, clears the last-used time, + accumulated TCP flags, and statistics for this flow. Otherwise + ignored in requests. Never present in notifications. + - + name: mask + type: nest + nested-attributes: key-attrs + doc: | + Nested attributes specifying the mask bits for wildcarded flow + match. Mask bit value '1' specifies exact match with corresponding + flow key bit, while mask bit value '0' specifies a wildcarded + match. Omitting attribute is treated as wildcarding all corresponding + fields. Optional for all requests. If not present, all flow key bits + are exact match bits. + - + name: probe + type: binary + doc: | + Flow operation is a feature probe, error logging should be suppressed. + - + name: ufid + type: binary + doc: | + A value between 1-16 octets specifying a unique identifier for the + flow. Causes the flow to be indexed by this value rather than the + value of the OVS_FLOW_ATTR_KEY attribute. Optional for all + requests. Present in notifications if the flow was created with this + attribute. + - + name: ufid-flags + type: u32 + enum: ovs-ufid-flags + doc: | + A 32-bit value of ORed flags that provide alternative semantics for + flow installation and retrieval. Optional for all requests. + - + name: pad + type: binary + + - + name: key-attrs + attributes: + - + name: encap + type: nest + nested-attributes: key-attrs + - + name: priority + type: u32 + - + name: in-port + type: u32 + - + name: ethernet + type: binary + doc: struct ovs_key_ethernet + - + name: vlan + type: u16 + byte-order: big-endian + - + name: ethertype + type: u16 + byte-order: big-endian + - + name: ipv4 + type: binary + struct: ovs-key-ipv4 + - + name: ipv6 + type: binary + doc: struct ovs_key_ipv6 + - + name: tcp + type: binary + struct: ovs-key-tcp + - + name: udp + type: binary + struct: ovs-key-udp + - + name: icmp + type: binary + struct: ovs-key-icmp + - + name: icmpv6 + type: binary + struct: ovs-key-icmp + - + name: arp + type: binary + doc: struct ovs_key_arp + - + name: nd + type: binary + doc: struct ovs_key_nd + - + name: skb-mark + type: u32 + - + name: tunnel + type: nest + nested-attributes: tunnel-key-attrs + - + name: sctp + type: binary + struct: ovs-key-sctp + - + name: tcp-flags + type: u16 + byte-order: big-endian + - + name: dp-hash + type: u32 + doc: Value 0 indicates the hash is not computed by the datapath. + - + name: recirc-id + type: u32 + - + name: mpls + type: binary + struct: ovs-key-mpls + - + name: ct-state + type: u32 + enum: ct-state-flags + enum-as-flags: true + - + name: ct-zone + type: u16 + doc: connection tracking zone + - + name: ct-mark + type: u32 + doc: connection tracking mark + - + name: ct-labels + type: binary + doc: 16-octet connection tracking label + - + name: ct-orig-tuple-ipv4 + type: binary + struct: ovs-key-ct-tuple-ipv4 + - + name: ct-orig-tuple-ipv6 + type: binary + doc: struct ovs_key_ct_tuple_ipv6 + - + name: nsh + type: nest + nested-attributes: ovs-nsh-key-attrs + - + name: packet-type + type: u32 + byte-order: big-endian + doc: Should not be sent to the kernel + - + name: nd-extensions + type: binary + doc: Should not be sent to the kernel + - + name: tunnel-info + type: binary + doc: struct ip_tunnel_info + - + name: ipv6-exthdrs + type: binary + doc: struct ovs_key_ipv6_exthdr + - + name: action-attrs + attributes: + - + name: output + type: u32 + doc: ovs port number in datapath + - + name: userspace + type: nest + nested-attributes: userspace-attrs + - + name: set + type: nest + nested-attributes: key-attrs + doc: Replaces the contents of an existing header. The single nested attribute specifies a header to modify and its value. + - + name: push-vlan + type: binary + struct: ovs-action-push-vlan + doc: Push a new outermost 802.1Q or 802.1ad header onto the packet. + - + name: pop-vlan + type: flag + doc: Pop the outermost 802.1Q or 802.1ad header from the packet. + - + name: sample + type: nest + nested-attributes: sample-attrs + doc: | + Probabilistically executes actions, as specified in the nested attributes. + - + name: recirc + type: u32 + doc: recirc id + - + name: hash + type: binary + struct: ovs-action-hash + - + name: push-mpls + type: binary + struct: ovs-action-push-mpls + doc: | + Push a new MPLS label stack entry onto the top of the packets MPLS + label stack. Set the ethertype of the encapsulating frame to either + ETH_P_MPLS_UC or ETH_P_MPLS_MC to indicate the new packet contents. + - + name: pop-mpls + type: u16 + byte-order: big-endian + doc: ethertype + - + name: set-masked + type: nest + nested-attributes: key-attrs + doc: | + Replaces the contents of an existing header. A nested attribute + specifies a header to modify, its value, and a mask. For every bit set + in the mask, the corresponding bit value is copied from the value to + the packet header field, rest of the bits are left unchanged. The + non-masked value bits must be passed in as zeroes. Masking is not + supported for the OVS_KEY_ATTR_TUNNEL attribute. + - + name: ct + type: nest + nested-attributes: ct-attrs + doc: | + Track the connection. Populate the conntrack-related entries + in the flow key. + - + name: trunc + type: u32 + doc: struct ovs_action_trunc is a u32 max length + - + name: push-eth + type: binary + doc: struct ovs_action_push_eth + - + name: pop-eth + type: flag + - + name: ct-clear + type: flag + - + name: push-nsh + type: nest + nested-attributes: ovs-nsh-key-attrs + doc: | + Push NSH header to the packet. + - + name: pop-nsh + type: flag + doc: | + Pop the outermost NSH header off the packet. + - + name: meter + type: u32 + doc: | + Run packet through a meter, which may drop the packet, or modify the + packet (e.g., change the DSCP field) + - + name: clone + type: nest + nested-attributes: action-attrs + doc: | + Make a copy of the packet and execute a list of actions without + affecting the original packet and key. + - + name: check-pkt-len + type: nest + nested-attributes: check-pkt-len-attrs + doc: | + Check the packet length and execute a set of actions if greater than + the specified packet length, else execute another set of actions. + - + name: add-mpls + type: binary + struct: ovs-action-add-mpls + doc: | + Push a new MPLS label stack entry at the start of the packet or at the + start of the l3 header depending on the value of l3 tunnel flag in the + tun_flags field of this OVS_ACTION_ATTR_ADD_MPLS argument. + - + name: dec-ttl + type: nest + nested-attributes: dec-ttl-attrs + - + name: tunnel-key-attrs + attributes: + - + name: id + type: u64 + byte-order: big-endian + value: 0 + - + name: ipv4-src + type: u32 + byte-order: big-endian + - + name: ipv4-dst + type: u32 + byte-order: big-endian + - + name: tos + type: u8 + - + name: ttl + type: u8 + - + name: dont-fragment + type: flag + - + name: csum + type: flag + - + name: oam + type: flag + - + name: geneve-opts + type: binary + sub-type: u32 + - + name: tp-src + type: u16 + byte-order: big-endian + - + name: tp-dst + type: u16 + byte-order: big-endian + - + name: vxlan-opts + type: nest + nested-attributes: vxlan-ext-attrs + - + name: ipv6-src + type: binary + doc: | + struct in6_addr source IPv6 address + - + name: ipv6-dst + type: binary + doc: | + struct in6_addr destination IPv6 address + - + name: pad + type: binary + - + name: erspan-opts + type: binary + doc: | + struct erspan_metadata + - + name: ipv4-info-bridge + type: flag + - + name: check-pkt-len-attrs + attributes: + - + name: pkt-len + type: u16 + - + name: actions-if-greater + type: nest + nested-attributes: action-attrs + - + name: actions-if-less-equal + type: nest + nested-attributes: action-attrs + - + name: sample-attrs + attributes: + - + name: probability + type: u32 + - + name: actions + type: nest + nested-attributes: action-attrs + - + name: userspace-attrs + attributes: + - + name: pid + type: u32 + - + name: userdata + type: binary + - + name: egress-tun-port + type: u32 + - + name: actions + type: flag + - + name: ovs-nsh-key-attrs + attributes: + - + name: base + type: binary + - + name: md1 + type: binary + - + name: md2 + type: binary + - + name: ct-attrs + attributes: + - + name: commit + type: flag + - + name: zone + type: u16 + - + name: mark + type: binary + - + name: labels + type: binary + - + name: helper + type: string + - + name: nat + type: nest + nested-attributes: nat-attrs + - + name: force-commit + type: flag + - + name: eventmask + type: u32 + - + name: timeout + type: string + - + name: nat-attrs + attributes: + - + name: src + type: binary + - + name: dst + type: binary + - + name: ip-min + type: binary + - + name: ip-max + type: binary + - + name: proto-min + type: binary + - + name: proto-max + type: binary + - + name: persistent + type: binary + - + name: proto-hash + type: binary + - + name: proto-random + type: binary + - + name: dec-ttl-attrs + attributes: + - + name: action + type: nest + nested-attributes: action-attrs + - + name: vxlan-ext-attrs + attributes: + - + name: gbp + type: u32 + +operations: + fixed-header: ovs-header + list: + - + name: flow-get + doc: Get / dump OVS flow configuration and state + value: 3 + attribute-set: flow-attrs + do: &flow-get-op + request: + attributes: + - dp-ifindex + - key + - ufid + - ufid-flags + reply: + attributes: + - dp-ifindex + - key + - ufid + - mask + - stats + - actions + dump: *flow-get-op + +mcast-groups: + list: + - + name: ovs_flow -- cgit v1.2.3 From 2f0d579956e87a67c43e225c85488ff7a13bc3b8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 May 2023 09:34:41 +0200 Subject: net: dsa: microchip: improving error handling for 8-bit register RMW operations This patch refines the error handling mechanism for 8-bit register read-modify-write operations. In case of a failure, it now logs an error message detailing the problematic offset. This enhancement aids in debugging by providing more precise information when these operations encounter issues. Furthermore, the ksz_prmw8() function has been updated to return error values rather than void, enabling calling functions to appropriately respond to errors. Additionally, in case of an error that affects both the current and future accesses, the PHY driver will log the errors consistently, akin to the existing behavior in all ksz_read*/ksz_write* helpers. Signed-off-by: Oleksij Rempel Signed-off-by: Paolo Abeni --- drivers/net/dsa/microchip/ksz_common.h | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 8abecaf6089e..b86f1e27a0c3 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -508,7 +508,14 @@ static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value) static inline int ksz_rmw8(struct ksz_device *dev, int offset, u8 mask, u8 val) { - return regmap_update_bits(dev->regmap[0], offset, mask, val); + int ret; + + ret = regmap_update_bits(dev->regmap[0], offset, mask, val); + if (ret) + dev_err(dev->dev, "can't rmw 8bit reg 0x%x: %pe\n", offset, + ERR_PTR(ret)); + + return ret; } static inline int ksz_pread8(struct ksz_device *dev, int port, int offset, @@ -549,12 +556,21 @@ static inline int ksz_pwrite32(struct ksz_device *dev, int port, int offset, data); } -static inline void ksz_prmw8(struct ksz_device *dev, int port, int offset, - u8 mask, u8 val) +static inline int ksz_prmw8(struct ksz_device *dev, int port, int offset, + u8 mask, u8 val) { - regmap_update_bits(dev->regmap[0], - dev->dev_ops->get_port_addr(port, offset), - mask, val); + int ret; + + ret = regmap_update_bits(dev->regmap[0], + dev->dev_ops->get_port_addr(port, offset), + mask, val); + if (ret) + dev_err(dev->dev, "can't rmw 8bit reg 0x%x: %pe\n", + dev->dev_ops->get_port_addr(port, offset), + ERR_PTR(ret)); + + return ret; + } static inline void ksz_regmap_lock(void *__mtx) -- cgit v1.2.3 From b8311f46c6f5a2030f43c764e742015867293493 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 26 May 2023 09:34:42 +0200 Subject: net: dsa: microchip: add an enum for regmap widths It is not immediately obvious that this driver allocates, via the KSZ_REGMAP_TABLE() macro, 3 regmaps for register access: dev->regmap[0] for 8-bit access, dev->regmap[1] for 16-bit and dev->regmap[2] for 32-bit access. In future changes that add support for reg_fields, each field will have to specify through which of the 3 regmaps it's going to go. Add an enum now, to denote one of the 3 register access widths, and make the code go through some wrapper functions for easier review and further modification. Signed-off-by: Vladimir Oltean Signed-off-by: Oleksij Rempel Signed-off-by: Paolo Abeni --- drivers/net/dsa/microchip/ksz8795.c | 8 ++--- drivers/net/dsa/microchip/ksz8863_smi.c | 2 +- drivers/net/dsa/microchip/ksz9477.c | 24 +++++++------- drivers/net/dsa/microchip/ksz9477_i2c.c | 2 +- drivers/net/dsa/microchip/ksz_common.c | 6 ++-- drivers/net/dsa/microchip/ksz_common.h | 54 ++++++++++++++++++++++---------- drivers/net/dsa/microchip/ksz_spi.c | 2 +- drivers/net/dsa/microchip/lan937x_main.c | 8 ++--- 8 files changed, 63 insertions(+), 43 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index f56fca1b1a22..d2f7fa3fbd27 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -28,13 +28,13 @@ static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { - regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); + regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0); } static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, bool set) { - regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + regmap_update_bits(ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset), bits, set ? bits : 0); } @@ -1425,14 +1425,14 @@ int ksz8_setup(struct dsa_switch *ds) ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true); /* Enable aggressive back off algorithm in half duplex mode. */ - regmap_update_bits(dev->regmap[0], REG_SW_CTRL_1, + regmap_update_bits(ksz_regmap_8(dev), REG_SW_CTRL_1, SW_AGGR_BACKOFF, SW_AGGR_BACKOFF); /* * Make sure unicast VLAN boundary is set as default and * enable no excessive collision drop. */ - regmap_update_bits(dev->regmap[0], REG_SW_CTRL_2, + regmap_update_bits(ksz_regmap_8(dev), REG_SW_CTRL_2, UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP, UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP); diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c index 3698112138b7..2af807db0b45 100644 --- a/drivers/net/dsa/microchip/ksz8863_smi.c +++ b/drivers/net/dsa/microchip/ksz8863_smi.c @@ -136,7 +136,7 @@ static int ksz8863_smi_probe(struct mdio_device *mdiodev) if (!dev) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(ksz8863_regmap_config); i++) { + for (i = 0; i < __KSZ_NUM_REGMAPS; i++) { rc = ksz8863_regmap_config[i]; rc.lock_arg = &dev->regmap_mutex; dev->regmap[i] = devm_regmap_init(&mdiodev->dev, diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index bf13d47c26cf..3019f54049fc 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -21,25 +21,25 @@ static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { - regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); + regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0); } static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, bool set) { - regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + regmap_update_bits(ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset), bits, set ? bits : 0); } static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set) { - regmap_update_bits(dev->regmap[2], addr, bits, set ? bits : 0); + regmap_update_bits(ksz_regmap_32(dev), addr, bits, set ? bits : 0); } static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset, u32 bits, bool set) { - regmap_update_bits(dev->regmap[2], PORT_CTRL_ADDR(port, offset), + regmap_update_bits(ksz_regmap_32(dev), PORT_CTRL_ADDR(port, offset), bits, set ? bits : 0); } @@ -52,7 +52,7 @@ int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu) frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; - return regmap_update_bits(dev->regmap[1], REG_SW_MTU__2, + return regmap_update_bits(ksz_regmap_16(dev), REG_SW_MTU__2, REG_SW_MTU_MASK, frame_size); } @@ -60,7 +60,7 @@ static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) { unsigned int val; - return regmap_read_poll_timeout(dev->regmap[0], REG_SW_VLAN_CTRL, + return regmap_read_poll_timeout(ksz_regmap_8(dev), REG_SW_VLAN_CTRL, val, !(val & VLAN_START), 10, 1000); } @@ -147,7 +147,7 @@ static int ksz9477_wait_alu_ready(struct ksz_device *dev) { unsigned int val; - return regmap_read_poll_timeout(dev->regmap[2], REG_SW_ALU_CTRL__4, + return regmap_read_poll_timeout(ksz_regmap_32(dev), REG_SW_ALU_CTRL__4, val, !(val & ALU_START), 10, 1000); } @@ -155,7 +155,7 @@ static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev) { unsigned int val; - return regmap_read_poll_timeout(dev->regmap[2], + return regmap_read_poll_timeout(ksz_regmap_32(dev), REG_SW_ALU_STAT_CTRL__4, val, !(val & ALU_STAT_START), 10, 1000); @@ -170,7 +170,7 @@ int ksz9477_reset_switch(struct ksz_device *dev) ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true); /* turn off SPI DO Edge select */ - regmap_update_bits(dev->regmap[0], REG_SW_GLOBAL_SERIAL_CTRL_0, + regmap_update_bits(ksz_regmap_8(dev), REG_SW_GLOBAL_SERIAL_CTRL_0, SPI_AUTO_EDGE_DETECTION, 0); /* default configuration */ @@ -213,7 +213,7 @@ void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt) data |= (addr << MIB_COUNTER_INDEX_S); ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data); - ret = regmap_read_poll_timeout(dev->regmap[2], + ret = regmap_read_poll_timeout(ksz_regmap_32(dev), PORT_CTRL_ADDR(port, REG_PORT_MIB_CTRL_STAT__4), val, !(val & MIB_COUNTER_READ), 10, 1000); /* failed to read MIB. get out of loop */ @@ -346,7 +346,7 @@ void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port) const u16 *regs = dev->info->regs; u8 data; - regmap_update_bits(dev->regmap[0], REG_SW_LUE_CTRL_2, + regmap_update_bits(ksz_regmap_8(dev), REG_SW_LUE_CTRL_2, SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S, SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S); @@ -1165,7 +1165,7 @@ int ksz9477_setup(struct dsa_switch *ds) ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_JUMBO_PACKET, true); /* Now we can configure default MTU value */ - ret = regmap_update_bits(dev->regmap[1], REG_SW_MTU__2, REG_SW_MTU_MASK, + ret = regmap_update_bits(ksz_regmap_16(dev), REG_SW_MTU__2, REG_SW_MTU_MASK, VLAN_ETH_FRAME_LEN + ETH_FCS_LEN); if (ret) return ret; diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index 97a317263a2f..497be833f707 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -24,7 +24,7 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c) if (!dev) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) { + for (i = 0; i < __KSZ_NUM_REGMAPS; i++) { rc = ksz9477_regmap_config[i]; rc.lock_arg = &dev->regmap_mutex; dev->regmap[i] = devm_regmap_init_i2c(i2c, &rc); diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index a4428be5f483..53bb7d9712d0 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -2095,7 +2095,7 @@ static int ksz_setup(struct dsa_switch *ds) } /* set broadcast storm protection 10% rate */ - regmap_update_bits(dev->regmap[1], regs[S_BROADCAST_CTRL], + regmap_update_bits(ksz_regmap_16(dev), regs[S_BROADCAST_CTRL], BROADCAST_STORM_RATE, (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100); @@ -2106,7 +2106,7 @@ static int ksz_setup(struct dsa_switch *ds) ds->num_tx_queues = dev->info->num_tx_queues; - regmap_update_bits(dev->regmap[0], regs[S_MULTICAST_CTRL], + regmap_update_bits(ksz_regmap_8(dev), regs[S_MULTICAST_CTRL], MULTICAST_STORM_DISABLE, MULTICAST_STORM_DISABLE); ksz_init_mib_timer(dev); @@ -2156,7 +2156,7 @@ static int ksz_setup(struct dsa_switch *ds) } /* start switch */ - regmap_update_bits(dev->regmap[0], regs[S_START_CTRL], + regmap_update_bits(ksz_regmap_8(dev), regs[S_START_CTRL], SW_START, SW_START); return 0; diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index b86f1e27a0c3..f45f5fe11bde 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -22,6 +22,13 @@ struct ksz_device; struct ksz_port; +enum ksz_regmap_width { + KSZ_REGMAP_8, + KSZ_REGMAP_16, + KSZ_REGMAP_32, + __KSZ_NUM_REGMAPS, +}; + struct vlan_table { u32 table[3]; }; @@ -137,7 +144,7 @@ struct ksz_device { const struct ksz_dev_ops *dev_ops; struct device *dev; - struct regmap *regmap[3]; + struct regmap *regmap[__KSZ_NUM_REGMAPS]; void *priv; int irq; @@ -377,11 +384,25 @@ phy_interface_t ksz_get_xmii(struct ksz_device *dev, int port, bool gbit); extern const struct ksz_chip_data ksz_switch_chips[]; /* Common register access functions */ +static inline struct regmap *ksz_regmap_8(struct ksz_device *dev) +{ + return dev->regmap[KSZ_REGMAP_8]; +} + +static inline struct regmap *ksz_regmap_16(struct ksz_device *dev) +{ + return dev->regmap[KSZ_REGMAP_16]; +} + +static inline struct regmap *ksz_regmap_32(struct ksz_device *dev) +{ + return dev->regmap[KSZ_REGMAP_32]; +} static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val) { unsigned int value; - int ret = regmap_read(dev->regmap[0], reg, &value); + int ret = regmap_read(ksz_regmap_8(dev), reg, &value); if (ret) dev_err(dev->dev, "can't read 8bit reg: 0x%x %pe\n", reg, @@ -394,7 +415,7 @@ static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val) static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) { unsigned int value; - int ret = regmap_read(dev->regmap[1], reg, &value); + int ret = regmap_read(ksz_regmap_16(dev), reg, &value); if (ret) dev_err(dev->dev, "can't read 16bit reg: 0x%x %pe\n", reg, @@ -407,7 +428,7 @@ static inline int ksz_read16(struct ksz_device *dev, u32 reg, u16 *val) static inline int ksz_read32(struct ksz_device *dev, u32 reg, u32 *val) { unsigned int value; - int ret = regmap_read(dev->regmap[2], reg, &value); + int ret = regmap_read(ksz_regmap_32(dev), reg, &value); if (ret) dev_err(dev->dev, "can't read 32bit reg: 0x%x %pe\n", reg, @@ -422,7 +443,7 @@ static inline int ksz_read64(struct ksz_device *dev, u32 reg, u64 *val) u32 value[2]; int ret; - ret = regmap_bulk_read(dev->regmap[2], reg, value, 2); + ret = regmap_bulk_read(ksz_regmap_32(dev), reg, value, 2); if (ret) dev_err(dev->dev, "can't read 64bit reg: 0x%x %pe\n", reg, ERR_PTR(ret)); @@ -436,7 +457,7 @@ static inline int ksz_write8(struct ksz_device *dev, u32 reg, u8 value) { int ret; - ret = regmap_write(dev->regmap[0], reg, value); + ret = regmap_write(ksz_regmap_8(dev), reg, value); if (ret) dev_err(dev->dev, "can't write 8bit reg: 0x%x %pe\n", reg, ERR_PTR(ret)); @@ -448,7 +469,7 @@ static inline int ksz_write16(struct ksz_device *dev, u32 reg, u16 value) { int ret; - ret = regmap_write(dev->regmap[1], reg, value); + ret = regmap_write(ksz_regmap_16(dev), reg, value); if (ret) dev_err(dev->dev, "can't write 16bit reg: 0x%x %pe\n", reg, ERR_PTR(ret)); @@ -460,7 +481,7 @@ static inline int ksz_write32(struct ksz_device *dev, u32 reg, u32 value) { int ret; - ret = regmap_write(dev->regmap[2], reg, value); + ret = regmap_write(ksz_regmap_32(dev), reg, value); if (ret) dev_err(dev->dev, "can't write 32bit reg: 0x%x %pe\n", reg, ERR_PTR(ret)); @@ -473,7 +494,7 @@ static inline int ksz_rmw16(struct ksz_device *dev, u32 reg, u16 mask, { int ret; - ret = regmap_update_bits(dev->regmap[1], reg, mask, value); + ret = regmap_update_bits(ksz_regmap_16(dev), reg, mask, value); if (ret) dev_err(dev->dev, "can't rmw 16bit reg 0x%x: %pe\n", reg, ERR_PTR(ret)); @@ -486,7 +507,7 @@ static inline int ksz_rmw32(struct ksz_device *dev, u32 reg, u32 mask, { int ret; - ret = regmap_update_bits(dev->regmap[2], reg, mask, value); + ret = regmap_update_bits(ksz_regmap_32(dev), reg, mask, value); if (ret) dev_err(dev->dev, "can't rmw 32bit reg 0x%x: %pe\n", reg, ERR_PTR(ret)); @@ -503,14 +524,14 @@ static inline int ksz_write64(struct ksz_device *dev, u32 reg, u64 value) val[0] = swab32(value & 0xffffffffULL); val[1] = swab32(value >> 32ULL); - return regmap_bulk_write(dev->regmap[2], reg, val, 2); + return regmap_bulk_write(ksz_regmap_32(dev), reg, val, 2); } static inline int ksz_rmw8(struct ksz_device *dev, int offset, u8 mask, u8 val) { int ret; - ret = regmap_update_bits(dev->regmap[0], offset, mask, val); + ret = regmap_update_bits(ksz_regmap_8(dev), offset, mask, val); if (ret) dev_err(dev->dev, "can't rmw 8bit reg 0x%x: %pe\n", offset, ERR_PTR(ret)); @@ -561,7 +582,7 @@ static inline int ksz_prmw8(struct ksz_device *dev, int port, int offset, { int ret; - ret = regmap_update_bits(dev->regmap[0], + ret = regmap_update_bits(ksz_regmap_8(dev), dev->dev_ops->get_port_addr(port, offset), mask, val); if (ret) @@ -570,7 +591,6 @@ static inline int ksz_prmw8(struct ksz_device *dev, int port, int offset, ERR_PTR(ret)); return ret; - } static inline void ksz_regmap_lock(void *__mtx) @@ -725,9 +745,9 @@ static inline int is_lan937x(struct ksz_device *dev) #define KSZ_REGMAP_TABLE(ksz, swp, regbits, regpad, regalign) \ static const struct regmap_config ksz##_regmap_config[] = { \ - KSZ_REGMAP_ENTRY(8, swp, (regbits), (regpad), (regalign)), \ - KSZ_REGMAP_ENTRY(16, swp, (regbits), (regpad), (regalign)), \ - KSZ_REGMAP_ENTRY(32, swp, (regbits), (regpad), (regalign)), \ + [KSZ_REGMAP_8] = KSZ_REGMAP_ENTRY(8, swp, (regbits), (regpad), (regalign)), \ + [KSZ_REGMAP_16] = KSZ_REGMAP_ENTRY(16, swp, (regbits), (regpad), (regalign)), \ + [KSZ_REGMAP_32] = KSZ_REGMAP_ENTRY(32, swp, (regbits), (regpad), (regalign)), \ } #endif diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 96c52e8fb51b..279338451621 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -63,7 +63,7 @@ static int ksz_spi_probe(struct spi_device *spi) else regmap_config = ksz9477_regmap_config; - for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) { + for (i = 0; i < __KSZ_NUM_REGMAPS; i++) { rc = regmap_config[i]; rc.lock_arg = &dev->regmap_mutex; rc.wr_table = chip->wr_table; diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 399a3905e6ca..b479a628b1ae 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -20,13 +20,13 @@ static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set) { - return regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0); + return regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0); } static int lan937x_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits, bool set) { - return regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset), + return regmap_update_bits(ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset), bits, set ? bits : 0); } @@ -86,7 +86,7 @@ static int lan937x_internal_phy_write(struct ksz_device *dev, int addr, int reg, if (ret < 0) return ret; - ret = regmap_read_poll_timeout(dev->regmap[1], REG_VPHY_IND_CTRL__2, + ret = regmap_read_poll_timeout(ksz_regmap_16(dev), REG_VPHY_IND_CTRL__2, value, !(value & VPHY_IND_BUSY), 10, 1000); if (ret < 0) { @@ -116,7 +116,7 @@ static int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg, if (ret < 0) return ret; - ret = regmap_read_poll_timeout(dev->regmap[1], REG_VPHY_IND_CTRL__2, + ret = regmap_read_poll_timeout(ksz_regmap_16(dev), REG_VPHY_IND_CTRL__2, value, !(value & VPHY_IND_BUSY), 10, 1000); if (ret < 0) { -- cgit v1.2.3 From bb4609d27f89cf6d4c6021690c02a10a94719464 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 May 2023 09:34:43 +0200 Subject: net: dsa: microchip: remove ksz_port:on variable The only place where this variable would be set to false is the ksz8_config_cpu_port() function. But it is done in a bogus way: for (i = 0; i < dev->phy_port_cnt; i++) { if (i == dev->phy_port_cnt) <--- will be never executed. break; p->on = 1; So, we never have a situation where p->on = 0. In this case, we can just remove it. Signed-off-by: Oleksij Rempel Reviewed-by: Andrew Lunn Reviewed-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- drivers/net/dsa/microchip/ksz8795.c | 20 +------------------- drivers/net/dsa/microchip/ksz_common.h | 1 - 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index d2f7fa3fbd27..84d502589f8e 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -941,7 +941,6 @@ void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port) { u8 learn[DSA_MAX_PORTS]; int first, index, cnt; - struct ksz_port *p; const u16 *regs; regs = dev->info->regs; @@ -955,9 +954,6 @@ void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port) cnt = dev->info->port_cnt; } for (index = first; index < cnt; index++) { - p = &dev->ports[index]; - if (!p->on) - continue; ksz_pread8(dev, index, regs[P_STP_CTRL], &learn[index]); if (!(learn[index] & PORT_LEARN_DISABLE)) ksz_pwrite8(dev, index, regs[P_STP_CTRL], @@ -965,9 +961,6 @@ void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port) } ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true); for (index = first; index < cnt; index++) { - p = &dev->ports[index]; - if (!p->on) - continue; if (!(learn[index] & PORT_LEARN_DISABLE)) ksz_pwrite8(dev, index, regs[P_STP_CTRL], learn[index]); } @@ -1338,25 +1331,14 @@ void ksz8_config_cpu_port(struct dsa_switch *ds) ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true); - p = &dev->ports[dev->cpu_port]; - p->on = 1; - ksz8_port_setup(dev, dev->cpu_port, true); for (i = 0; i < dev->phy_port_cnt; i++) { - p = &dev->ports[i]; - ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED); - - /* Last port may be disabled. */ - if (i == dev->phy_port_cnt) - break; - p->on = 1; } for (i = 0; i < dev->phy_port_cnt; i++) { p = &dev->ports[i]; - if (!p->on) - continue; + if (!ksz_is_ksz88x3(dev)) { ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote); if (remote & KSZ8_PORT_FIBER_MODE) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index f45f5fe11bde..5aa58aac3e07 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -108,7 +108,6 @@ struct ksz_port { int stp_state; struct phy_device phydev; - u32 on:1; /* port is not disabled by hardware */ u32 fiber:1; /* port is fiber */ u32 force:1; u32 read:1; /* read MIB counters in background */ -- cgit v1.2.3 From ae1ad12e9da4de8f0540258b197131f96cc24c6f Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 May 2023 09:34:44 +0200 Subject: net: dsa: microchip: ksz8: Prepare ksz8863_smi for regmap register access validation This patch prepares the ksz8863_smi part of ksz8 driver to utilize the regmap register access validation feature. Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: Paolo Abeni --- drivers/net/dsa/microchip/ksz8863_smi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c index 2af807db0b45..fd6e2e69a42a 100644 --- a/drivers/net/dsa/microchip/ksz8863_smi.c +++ b/drivers/net/dsa/microchip/ksz8863_smi.c @@ -104,6 +104,7 @@ static const struct regmap_config ksz8863_regmap_config[] = { .cache_type = REGCACHE_NONE, .lock = ksz_regmap_lock, .unlock = ksz_regmap_unlock, + .max_register = U8_MAX, }, { .name = "#16", @@ -113,6 +114,7 @@ static const struct regmap_config ksz8863_regmap_config[] = { .cache_type = REGCACHE_NONE, .lock = ksz_regmap_lock, .unlock = ksz_regmap_unlock, + .max_register = U8_MAX, }, { .name = "#32", @@ -122,11 +124,14 @@ static const struct regmap_config ksz8863_regmap_config[] = { .cache_type = REGCACHE_NONE, .lock = ksz_regmap_lock, .unlock = ksz_regmap_unlock, + .max_register = U8_MAX, } }; static int ksz8863_smi_probe(struct mdio_device *mdiodev) { + struct device *ddev = &mdiodev->dev; + const struct ksz_chip_data *chip; struct regmap_config rc; struct ksz_device *dev; int ret; @@ -136,9 +141,15 @@ static int ksz8863_smi_probe(struct mdio_device *mdiodev) if (!dev) return -ENOMEM; + chip = device_get_match_data(ddev); + if (!chip) + return -EINVAL; + for (i = 0; i < __KSZ_NUM_REGMAPS; i++) { rc = ksz8863_regmap_config[i]; rc.lock_arg = &dev->regmap_mutex; + rc.wr_table = chip->wr_table; + rc.rd_table = chip->rd_table; dev->regmap[i] = devm_regmap_init(&mdiodev->dev, ®map_smi[i], dev, &rc); -- cgit v1.2.3 From d0dec3333040bc41b160ee9b2fd1b4eb91452cd3 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 26 May 2023 09:34:45 +0200 Subject: net: dsa: microchip: Add register access control for KSZ8873 chip This update introduces specific register access boundaries for the KSZ8873 and KSZ8863 chips within the DSA Microchip driver. The outlined ranges target global control registers, port registers, and advanced control registers. Signed-off-by: Oleksij Rempel Signed-off-by: Paolo Abeni --- drivers/net/dsa/microchip/ksz_common.c | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 53bb7d9712d0..768f649d2f40 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1075,6 +1075,45 @@ static const struct regmap_access_table ksz9896_register_set = { .n_yes_ranges = ARRAY_SIZE(ksz9896_valid_regs), }; +static const struct regmap_range ksz8873_valid_regs[] = { + regmap_reg_range(0x00, 0x01), + /* global control register */ + regmap_reg_range(0x02, 0x0f), + + /* port registers */ + regmap_reg_range(0x10, 0x1d), + regmap_reg_range(0x1e, 0x1f), + regmap_reg_range(0x20, 0x2d), + regmap_reg_range(0x2e, 0x2f), + regmap_reg_range(0x30, 0x39), + regmap_reg_range(0x3f, 0x3f), + + /* advanced control registers */ + regmap_reg_range(0x60, 0x6f), + regmap_reg_range(0x70, 0x75), + regmap_reg_range(0x76, 0x78), + regmap_reg_range(0x79, 0x7a), + regmap_reg_range(0x7b, 0x83), + regmap_reg_range(0x8e, 0x99), + regmap_reg_range(0x9a, 0xa5), + regmap_reg_range(0xa6, 0xa6), + regmap_reg_range(0xa7, 0xaa), + regmap_reg_range(0xab, 0xae), + regmap_reg_range(0xaf, 0xba), + regmap_reg_range(0xbb, 0xbc), + regmap_reg_range(0xbd, 0xbd), + regmap_reg_range(0xc0, 0xc0), + regmap_reg_range(0xc2, 0xc2), + regmap_reg_range(0xc3, 0xc3), + regmap_reg_range(0xc4, 0xc4), + regmap_reg_range(0xc6, 0xc6), +}; + +static const struct regmap_access_table ksz8873_register_set = { + .yes_ranges = ksz8873_valid_regs, + .n_yes_ranges = ARRAY_SIZE(ksz8873_valid_regs), +}; + const struct ksz_chip_data ksz_switch_chips[] = { [KSZ8563] = { .chip_id = KSZ8563_CHIP_ID, @@ -1214,6 +1253,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .supports_mii = {false, false, true}, .supports_rmii = {false, false, true}, .internal_phy = {true, true, false}, + .wr_table = &ksz8873_register_set, + .rd_table = &ksz8873_register_set, }, [KSZ9477] = { -- cgit v1.2.3 From ca33db4a86023f1158dc2b3587ca3c90d2a0705e Mon Sep 17 00:00:00 2001 From: Parthiban Veerasooran Date: Fri, 26 May 2023 20:53:43 +0530 Subject: net: phy: microchip_t1s: modify driver description to be more generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove LAN867X from the driver description as this driver is common for all the Microchip 10BASE-T1S PHYs. Reviewed-by: Ramón Nordin Rodriguez Reviewed-by: Andrew Lunn Signed-off-by: Parthiban Veerasooran Signed-off-by: Paolo Abeni --- drivers/net/phy/Kconfig | 2 +- drivers/net/phy/microchip_t1s.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 93b8efc79227..f6829d1bcf42 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -243,7 +243,7 @@ config MICREL_PHY Supports the KSZ9021, VSC8201, KS8001 PHYs. config MICROCHIP_T1S_PHY - tristate "Microchip 10BASE-T1S Ethernet PHY" + tristate "Microchip 10BASE-T1S Ethernet PHYs" help Currently supports the LAN8670, LAN8671, LAN8672 diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c index 094967b3c111..a42a6bb6e3bd 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Driver for Microchip 10BASE-T1S LAN867X PHY + * Driver for Microchip 10BASE-T1S PHYs * * Support: Microchip Phys: * lan8670, lan8671, lan8672 @@ -111,7 +111,7 @@ static int lan867x_read_status(struct phy_device *phydev) return 0; } -static struct phy_driver lan867x_driver[] = { +static struct phy_driver microchip_t1s_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_LAN867X), .name = "LAN867X", @@ -124,7 +124,7 @@ static struct phy_driver lan867x_driver[] = { } }; -module_phy_driver(lan867x_driver); +module_phy_driver(microchip_t1s_driver); static struct mdio_device_id __maybe_unused tbl[] = { { PHY_ID_MATCH_MODEL(PHY_ID_LAN867X) }, @@ -133,6 +133,6 @@ static struct mdio_device_id __maybe_unused tbl[] = { MODULE_DEVICE_TABLE(mdio, tbl); -MODULE_DESCRIPTION("Microchip 10BASE-T1S lan867x Phy driver"); +MODULE_DESCRIPTION("Microchip 10BASE-T1S PHYs driver"); MODULE_AUTHOR("Ramón Nordin Rodriguez"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 221a5344806c3b8c2b172777b1b59f65228dbd8a Mon Sep 17 00:00:00 2001 From: Parthiban Veerasooran Date: Fri, 26 May 2023 20:53:44 +0530 Subject: net: phy: microchip_t1s: replace read-modify-write code with phy_modify_mmd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace read-modify-write code in the lan867x_config_init function to avoid handling data type mismatch and to simplify the code. Reviewed-by: Andrew Lunn Signed-off-by: Parthiban Veerasooran Reviewed-by: Ramón Nordin Rodriguez Signed-off-by: Paolo Abeni --- drivers/net/phy/microchip_t1s.c | 41 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c index a42a6bb6e3bd..fd27e94c9ee5 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -31,19 +31,19 @@ * W 0x1F 0x0099 0x7F80 ------ */ -static const int lan867x_fixup_registers[12] = { +static const u32 lan867x_fixup_registers[12] = { 0x00D0, 0x00D1, 0x0084, 0x0085, 0x008A, 0x0087, 0x0088, 0x008B, 0x0080, 0x00F1, 0x0096, 0x0099, }; -static const int lan867x_fixup_values[12] = { +static const u16 lan867x_fixup_values[12] = { 0x0002, 0x0000, 0x3380, 0x0006, 0xC000, 0x801C, 0x033F, 0x0404, 0x0600, 0x2400, 0x2000, 0x7F80, }; -static const int lan867x_fixup_masks[12] = { +static const u16 lan867x_fixup_masks[12] = { 0x0E03, 0x0300, 0xFFC0, 0x000F, 0xF800, 0x801C, 0x1FFF, 0xFFFF, 0x0600, 0x7F00, 0x2000, 0xFFFF, @@ -51,35 +51,20 @@ static const int lan867x_fixup_masks[12] = { static int lan867x_config_init(struct phy_device *phydev) { - /* HW quirk: Microchip states in the application note (AN1699) for the phy - * that a set of read-modify-write (rmw) operations has to be performed - * on a set of seemingly magic registers. - * The result of these operations is just described as 'optimal performance' - * Microchip gives no explanation as to what these mmd regs do, - * in fact they are marked as reserved in the datasheet. - * It is unclear if phy_modify_mmd would be safe to use or if a write - * really has to happen to each register. - * In order to exactly conform to what is stated in the AN phy_write_mmd is - * used, which might then write the same value back as read + modified. - */ - - int reg_value; int err; - int reg; - /* Read-Modified Write Pseudocode (from AN1699) - * current_val = read_register(mmd, addr) // Read current register value - * new_val = current_val AND (NOT mask) // Clear bit fields to be written - * new_val = new_val OR value // Set bits - * write_register(mmd, addr, new_val) // Write back updated register value + /* Reference to AN1699 + * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8670-1-2-config-60001699.pdf + * AN1699 says Read, Modify, Write, but the Write is not required if the + * register already has the required value. So it is safe to use + * phy_modify_mmd here. */ for (int i = 0; i < ARRAY_SIZE(lan867x_fixup_registers); i++) { - reg = lan867x_fixup_registers[i]; - reg_value = phy_read_mmd(phydev, MDIO_MMD_VEND2, reg); - reg_value &= ~lan867x_fixup_masks[i]; - reg_value |= lan867x_fixup_values[i]; - err = phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, reg_value); - if (err != 0) + err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, + lan867x_fixup_registers[i], + lan867x_fixup_masks[i], + lan867x_fixup_values[i]); + if (err) return err; } -- cgit v1.2.3 From 6f12765ecad399d3cc5f58fcaf7f3c69c275326c Mon Sep 17 00:00:00 2001 From: Parthiban Veerasooran Date: Fri, 26 May 2023 20:53:45 +0530 Subject: net: phy: microchip_t1s: update LAN867x PHY supported revision number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per AN1699, the initial configuration in the driver applies to LAN867x Rev.B1 hardware revision. 0x0007C160 (Rev.A0) and 0x0007C161 (Rev.B0) never released to production and hence they don't need to be supported. Reviewed-by: Ramón Nordin Rodriguez Reviewed-by: Andrew Lunn Signed-off-by: Parthiban Veerasooran Signed-off-by: Paolo Abeni --- drivers/net/phy/Kconfig | 2 +- drivers/net/phy/microchip_t1s.c | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index f6829d1bcf42..47596ada3183 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -245,7 +245,7 @@ config MICREL_PHY config MICROCHIP_T1S_PHY tristate "Microchip 10BASE-T1S Ethernet PHYs" help - Currently supports the LAN8670, LAN8671, LAN8672 + Currently supports the LAN8670/1/2 Rev.B1 config MICROCHIP_PHY tristate "Microchip PHYs" diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c index fd27e94c9ee5..7abecad28bf1 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -3,14 +3,14 @@ * Driver for Microchip 10BASE-T1S PHYs * * Support: Microchip Phys: - * lan8670, lan8671, lan8672 + * lan8670/1/2 Rev.B1 */ #include #include #include -#define PHY_ID_LAN867X 0x0007C160 +#define PHY_ID_LAN867X_REVB1 0x0007C162 #define LAN867X_REG_IRQ_1_CTL 0x001C #define LAN867X_REG_IRQ_2_CTL 0x001D @@ -31,25 +31,25 @@ * W 0x1F 0x0099 0x7F80 ------ */ -static const u32 lan867x_fixup_registers[12] = { +static const u32 lan867x_revb1_fixup_registers[12] = { 0x00D0, 0x00D1, 0x0084, 0x0085, 0x008A, 0x0087, 0x0088, 0x008B, 0x0080, 0x00F1, 0x0096, 0x0099, }; -static const u16 lan867x_fixup_values[12] = { +static const u16 lan867x_revb1_fixup_values[12] = { 0x0002, 0x0000, 0x3380, 0x0006, 0xC000, 0x801C, 0x033F, 0x0404, 0x0600, 0x2400, 0x2000, 0x7F80, }; -static const u16 lan867x_fixup_masks[12] = { +static const u16 lan867x_revb1_fixup_masks[12] = { 0x0E03, 0x0300, 0xFFC0, 0x000F, 0xF800, 0x801C, 0x1FFF, 0xFFFF, 0x0600, 0x7F00, 0x2000, 0xFFFF, }; -static int lan867x_config_init(struct phy_device *phydev) +static int lan867x_revb1_config_init(struct phy_device *phydev) { int err; @@ -59,11 +59,11 @@ static int lan867x_config_init(struct phy_device *phydev) * register already has the required value. So it is safe to use * phy_modify_mmd here. */ - for (int i = 0; i < ARRAY_SIZE(lan867x_fixup_registers); i++) { + for (int i = 0; i < ARRAY_SIZE(lan867x_revb1_fixup_registers); i++) { err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, - lan867x_fixup_registers[i], - lan867x_fixup_masks[i], - lan867x_fixup_values[i]); + lan867x_revb1_fixup_registers[i], + lan867x_revb1_fixup_masks[i], + lan867x_revb1_fixup_values[i]); if (err) return err; } @@ -98,10 +98,10 @@ static int lan867x_read_status(struct phy_device *phydev) static struct phy_driver microchip_t1s_driver[] = { { - PHY_ID_MATCH_MODEL(PHY_ID_LAN867X), - .name = "LAN867X", + PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1), + .name = "LAN867X Rev.B1", .features = PHY_BASIC_T1S_P2MP_FEATURES, - .config_init = lan867x_config_init, + .config_init = lan867x_revb1_config_init, .read_status = lan867x_read_status, .get_plca_cfg = genphy_c45_plca_get_cfg, .set_plca_cfg = genphy_c45_plca_set_cfg, @@ -112,7 +112,7 @@ static struct phy_driver microchip_t1s_driver[] = { module_phy_driver(microchip_t1s_driver); static struct mdio_device_id __maybe_unused tbl[] = { - { PHY_ID_MATCH_MODEL(PHY_ID_LAN867X) }, + { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) }, { } }; -- cgit v1.2.3 From 1d7650b8ce6041be4ea0436ad7a69c057b4d22f8 Mon Sep 17 00:00:00 2001 From: Parthiban Veerasooran Date: Fri, 26 May 2023 20:53:46 +0530 Subject: net: phy: microchip_t1s: fix reset complete status handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per the datasheet DS-LAN8670-1-2-60001573C.pdf, the Reset Complete status bit in the STS2 register has to be checked before proceeding to the initial configuration. Reading STS2 register will also clear the Reset Complete interrupt which is non-maskable. Reviewed-by: Andrew Lunn Signed-off-by: Parthiban Veerasooran Reviewed-by: Ramón Nordin Rodriguez Tested-by: Ramón Nordin Rodriguez Signed-off-by: Paolo Abeni --- drivers/net/phy/microchip_t1s.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c index 7abecad28bf1..0ecef87e5882 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -14,6 +14,9 @@ #define LAN867X_REG_IRQ_1_CTL 0x001C #define LAN867X_REG_IRQ_2_CTL 0x001D +#define LAN867X_REG_STS2 0x0019 + +#define LAN867x_RESET_COMPLETE_STS BIT(11) /* The arrays below are pulled from the following table from AN1699 * Access MMD Address Value Mask @@ -53,6 +56,24 @@ static int lan867x_revb1_config_init(struct phy_device *phydev) { int err; + /* The chip completes a reset in 3us, we might get here earlier than + * that, as an added margin we'll conditionally sleep 5us. + */ + err = phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_STS2); + if (err < 0) + return err; + + if (!(err & LAN867x_RESET_COMPLETE_STS)) { + udelay(5); + err = phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_STS2); + if (err < 0) + return err; + if (!(err & LAN867x_RESET_COMPLETE_STS)) { + phydev_err(phydev, "PHY reset failed\n"); + return -ENODEV; + } + } + /* Reference to AN1699 * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8670-1-2-config-60001699.pdf * AN1699 says Read, Modify, Write, but the Write is not required if the -- cgit v1.2.3 From b4010beb347d63acd5715cd66eb791988128b7b8 Mon Sep 17 00:00:00 2001 From: Parthiban Veerasooran Date: Fri, 26 May 2023 20:53:47 +0530 Subject: net: phy: microchip_t1s: remove unnecessary interrupts disabling code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By default, except Reset Complete interrupt in the Interrupt Mask 2 Register all other interrupts are disabled/masked. As Reset Complete status is already handled, it doesn't make sense to disable it. Reviewed-by: Ramón Nordin Rodriguez Tested-by: Ramón Nordin Rodriguez Reviewed-by: Andrew Lunn Signed-off-by: Parthiban Veerasooran Signed-off-by: Paolo Abeni --- drivers/net/phy/microchip_t1s.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c index 0ecef87e5882..bcfcec56a6c7 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -12,8 +12,6 @@ #define PHY_ID_LAN867X_REVB1 0x0007C162 -#define LAN867X_REG_IRQ_1_CTL 0x001C -#define LAN867X_REG_IRQ_2_CTL 0x001D #define LAN867X_REG_STS2 0x0019 #define LAN867x_RESET_COMPLETE_STS BIT(11) @@ -89,17 +87,7 @@ static int lan867x_revb1_config_init(struct phy_device *phydev) return err; } - /* None of the interrupts in the lan867x phy seem relevant. - * Other phys inspect the link status and call phy_trigger_machine - * in the interrupt handler. - * This phy does not support link status, and thus has no interrupt - * for it either. - * So we'll just disable all interrupts on the chip. - */ - err = phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_IRQ_1_CTL, 0xFFFF); - if (err != 0) - return err; - return phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_IRQ_2_CTL, 0xFFFF); + return 0; } static int lan867x_read_status(struct phy_device *phydev) -- cgit v1.2.3 From 972c6d8346333437ae784271e74129b3f0583248 Mon Sep 17 00:00:00 2001 From: Parthiban Veerasooran Date: Fri, 26 May 2023 20:53:48 +0530 Subject: net: phy: microchip_t1s: add support for Microchip LAN865x Rev.B0 PHYs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the Microchip LAN865x Rev.B0 10BASE-T1S Internal PHYs (LAN8650/1). The LAN865x combines a Media Access Controller (MAC) and an internal 10BASE-T1S Ethernet PHY to access 10BASE‑T1S networks. As LAN867X and LAN865X are using the same function for the read_status, rename the function as lan86xx_read_status. Reviewed-by: Andrew Lunn Signed-off-by: Parthiban Veerasooran Reviewed-by: Ramón Nordin Rodriguez Signed-off-by: Paolo Abeni --- drivers/net/phy/Kconfig | 3 +- drivers/net/phy/microchip_t1s.c | 180 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 179 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 47596ada3183..059bd06a8cce 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -245,7 +245,8 @@ config MICREL_PHY config MICROCHIP_T1S_PHY tristate "Microchip 10BASE-T1S Ethernet PHYs" help - Currently supports the LAN8670/1/2 Rev.B1 + Currently supports the LAN8670/1/2 Rev.B1 and LAN8650/1 Rev.B0 Internal + PHYs. config MICROCHIP_PHY tristate "Microchip PHYs" diff --git a/drivers/net/phy/microchip_t1s.c b/drivers/net/phy/microchip_t1s.c index bcfcec56a6c7..534ca7d1b061 100644 --- a/drivers/net/phy/microchip_t1s.c +++ b/drivers/net/phy/microchip_t1s.c @@ -4,6 +4,7 @@ * * Support: Microchip Phys: * lan8670/1/2 Rev.B1 + * lan8650/1 Rev.B0 Internal PHYs */ #include @@ -11,11 +12,19 @@ #include #define PHY_ID_LAN867X_REVB1 0x0007C162 +#define PHY_ID_LAN865X_REVB0 0x0007C1B3 #define LAN867X_REG_STS2 0x0019 #define LAN867x_RESET_COMPLETE_STS BIT(11) +#define LAN865X_REG_CFGPARAM_ADDR 0x00D8 +#define LAN865X_REG_CFGPARAM_DATA 0x00D9 +#define LAN865X_REG_CFGPARAM_CTRL 0x00DA +#define LAN865X_REG_STS2 0x0019 + +#define LAN865X_CFGPARAM_READ_ENABLE BIT(1) + /* The arrays below are pulled from the following table from AN1699 * Access MMD Address Value Mask * RMW 0x1F 0x00D0 0x0002 0x0E03 @@ -50,6 +59,160 @@ static const u16 lan867x_revb1_fixup_masks[12] = { 0x0600, 0x7F00, 0x2000, 0xFFFF, }; +/* LAN865x Rev.B0 configuration parameters from AN1760 */ +static const u32 lan865x_revb0_fixup_registers[28] = { + 0x0091, 0x0081, 0x0043, 0x0044, + 0x0045, 0x0053, 0x0054, 0x0055, + 0x0040, 0x0050, 0x00D0, 0x00E9, + 0x00F5, 0x00F4, 0x00F8, 0x00F9, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, + 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, +}; + +static const u16 lan865x_revb0_fixup_values[28] = { + 0x9660, 0x00C0, 0x00FF, 0xFFFF, + 0x0000, 0x00FF, 0xFFFF, 0x0000, + 0x0002, 0x0002, 0x5F21, 0x9E50, + 0x1CF8, 0xC020, 0x9B00, 0x4E53, + 0x0103, 0x0910, 0x1D26, 0x002A, + 0x0103, 0x070D, 0x1720, 0x0027, + 0x0509, 0x0E13, 0x1C25, 0x002B, +}; + +static const u16 lan865x_revb0_fixup_cfg_regs[5] = { + 0x0084, 0x008A, 0x00AD, 0x00AE, 0x00AF +}; + +/* Pulled from AN1760 describing 'indirect read' + * + * write_register(0x4, 0x00D8, addr) + * write_register(0x4, 0x00DA, 0x2) + * return (int8)(read_register(0x4, 0x00D9)) + * + * 0x4 refers to memory map selector 4, which maps to MDIO_MMD_VEND2 + */ +static int lan865x_revb0_indirect_read(struct phy_device *phydev, u16 addr) +{ + int ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_ADDR, + addr); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_CTRL, + LAN865X_CFGPARAM_READ_ENABLE); + if (ret) + return ret; + + return phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_DATA); +} + +/* This is pulled straight from AN1760 from 'calculation of offset 1' & + * 'calculation of offset 2' + */ +static int lan865x_generate_cfg_offsets(struct phy_device *phydev, s8 offsets[2]) +{ + const u16 fixup_regs[2] = {0x0004, 0x0008}; + int ret; + + for (int i = 0; i < ARRAY_SIZE(fixup_regs); i++) { + ret = lan865x_revb0_indirect_read(phydev, fixup_regs[i]); + if (ret < 0) + return ret; + if (ret & BIT(4)) + offsets[i] = ret | 0xE0; + else + offsets[i] = ret; + } + + return 0; +} + +static int lan865x_read_cfg_params(struct phy_device *phydev, u16 cfg_params[]) +{ + int ret; + + for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs); i++) { + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, + lan865x_revb0_fixup_cfg_regs[i]); + if (ret < 0) + return ret; + cfg_params[i] = (u16)ret; + } + + return 0; +} + +static int lan865x_write_cfg_params(struct phy_device *phydev, u16 cfg_params[]) +{ + int ret; + + for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs); i++) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + lan865x_revb0_fixup_cfg_regs[i], + cfg_params[i]); + if (ret) + return ret; + } + + return 0; +} + +static int lan865x_setup_cfgparam(struct phy_device *phydev) +{ + u16 cfg_params[ARRAY_SIZE(lan865x_revb0_fixup_cfg_regs)]; + u16 cfg_results[5]; + s8 offsets[2]; + int ret; + + ret = lan865x_generate_cfg_offsets(phydev, offsets); + if (ret) + return ret; + + ret = lan865x_read_cfg_params(phydev, cfg_params); + if (ret) + return ret; + + cfg_results[0] = (cfg_params[0] & 0x000F) | + FIELD_PREP(GENMASK(15, 10), 9 + offsets[0]) | + FIELD_PREP(GENMASK(15, 4), 14 + offsets[0]); + cfg_results[1] = (cfg_params[1] & 0x03FF) | + FIELD_PREP(GENMASK(15, 10), 40 + offsets[1]); + cfg_results[2] = (cfg_params[2] & 0xC0C0) | + FIELD_PREP(GENMASK(15, 8), 5 + offsets[0]) | + (9 + offsets[0]); + cfg_results[3] = (cfg_params[3] & 0xC0C0) | + FIELD_PREP(GENMASK(15, 8), 9 + offsets[0]) | + (14 + offsets[0]); + cfg_results[4] = (cfg_params[4] & 0xC0C0) | + FIELD_PREP(GENMASK(15, 8), 17 + offsets[0]) | + (22 + offsets[0]); + + return lan865x_write_cfg_params(phydev, cfg_results); +} + +static int lan865x_revb0_config_init(struct phy_device *phydev) +{ + int ret; + + /* Reference to AN1760 + * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8650-1-Configuration-60001760.pdf + */ + for (int i = 0; i < ARRAY_SIZE(lan865x_revb0_fixup_registers); i++) { + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, + lan865x_revb0_fixup_registers[i], + lan865x_revb0_fixup_values[i]); + if (ret) + return ret; + } + /* Function to calculate and write the configuration parameters in the + * 0x0084, 0x008A, 0x00AD, 0x00AE and 0x00AF registers (from AN1760) + */ + return lan865x_setup_cfgparam(phydev); +} + static int lan867x_revb1_config_init(struct phy_device *phydev) { int err; @@ -90,7 +253,7 @@ static int lan867x_revb1_config_init(struct phy_device *phydev) return 0; } -static int lan867x_read_status(struct phy_device *phydev) +static int lan86xx_read_status(struct phy_device *phydev) { /* The phy has some limitations, namely: * - always reports link up @@ -111,17 +274,28 @@ static struct phy_driver microchip_t1s_driver[] = { .name = "LAN867X Rev.B1", .features = PHY_BASIC_T1S_P2MP_FEATURES, .config_init = lan867x_revb1_config_init, - .read_status = lan867x_read_status, + .read_status = lan86xx_read_status, .get_plca_cfg = genphy_c45_plca_get_cfg, .set_plca_cfg = genphy_c45_plca_set_cfg, .get_plca_status = genphy_c45_plca_get_status, - } + }, + { + PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0), + .name = "LAN865X Rev.B0 Internal Phy", + .features = PHY_BASIC_T1S_P2MP_FEATURES, + .config_init = lan865x_revb0_config_init, + .read_status = lan86xx_read_status, + .get_plca_cfg = genphy_c45_plca_get_cfg, + .set_plca_cfg = genphy_c45_plca_set_cfg, + .get_plca_status = genphy_c45_plca_get_status, + }, }; module_phy_driver(microchip_t1s_driver); static struct mdio_device_id __maybe_unused tbl[] = { { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) }, + { PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB0) }, { } }; -- cgit v1.2.3 From bb269633f3da56ec65e4e5aa9d9fca0ef8b3d373 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 27 May 2023 21:40:08 +0200 Subject: liquidio: Use vzalloc() Use vzalloc() instead of hand writing it with vmalloc()+memset(). This is less verbose. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/93b010824d9d92376e8d49b9eb396a0fa0c0ac80.1685216322.git.christophe.jaillet@wanadoo.fr Signed-off-by: Paolo Abeni --- drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c | 4 +--- drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index 9ed3d1ab2ca5..285d3825cad3 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -719,12 +719,10 @@ static int cn23xx_setup_pf_mbox(struct octeon_device *oct) for (i = 0; i < oct->sriov_info.max_vfs; i++) { q_no = i * oct->sriov_info.rings_per_vf; - mbox = vmalloc(sizeof(*mbox)); + mbox = vzalloc(sizeof(*mbox)); if (!mbox) goto free_mbox; - memset(mbox, 0, sizeof(struct octeon_mbox)); - spin_lock_init(&mbox->lock); mbox->oct_dev = oct; diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c index fda49404968c..b3bd2767d3dd 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c @@ -279,12 +279,10 @@ static int cn23xx_setup_vf_mbox(struct octeon_device *oct) { struct octeon_mbox *mbox = NULL; - mbox = vmalloc(sizeof(*mbox)); + mbox = vzalloc(sizeof(*mbox)); if (!mbox) return 1; - memset(mbox, 0, sizeof(struct octeon_mbox)); - spin_lock_init(&mbox->lock); mbox->oct_dev = oct; -- cgit v1.2.3 From 3ea3c9cff7f982b42126a009140cb73a53ecd647 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 28 May 2023 17:25:31 +0300 Subject: dsa: lan9303: Remove stray gpiod_unexport() call There is no gpiod_export() and gpiod_unexport() looks pretty much stray. The gpiod_export() and gpiod_unexport() shouldn't be used in the code, GPIO sysfs is deprecated. That said, simply drop the stray call. Signed-off-by: Andy Shevchenko Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230528142531.38602-1-andriy.shevchenko@linux.intel.com Signed-off-by: Paolo Abeni --- drivers/net/dsa/lan9303-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index cbe831875347..b560e73c14ca 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -1462,7 +1462,6 @@ int lan9303_remove(struct lan9303 *chip) /* assert reset to the whole device to prevent it from doing anything */ gpiod_set_value_cansleep(chip->reset_gpio, 1); - gpiod_unexport(chip->reset_gpio); return 0; } -- cgit v1.2.3 From bc590b47549225a03c6b36bbc1aede75c917767b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 28 May 2023 19:35:12 +0200 Subject: r8169: check for PCI read error in probe Check whether first PCI read returns 0xffffffff. Currently, if this is the case, the user sees the following misleading message: unknown chip XID fcf, contact r8169 maintainers (see MAINTAINERS file) Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/75b54d23-fefe-2bf4-7e80-c9d3bc91af11@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/realtek/r8169_main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 4b19803a7dd0..5e6308d574ba 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5164,6 +5164,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) int jumbo_max, region, rc; enum mac_version chipset; struct net_device *dev; + u32 txconfig; u16 xid; dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp)); @@ -5218,7 +5219,13 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->mmio_addr = pcim_iomap_table(pdev)[region]; - xid = (RTL_R32(tp, TxConfig) >> 20) & 0xfcf; + txconfig = RTL_R32(tp, TxConfig); + if (txconfig == ~0U) { + dev_err(&pdev->dev, "PCI read failed\n"); + return -EIO; + } + + xid = (txconfig >> 20) & 0xfcf; /* Identify chip attached to board */ chipset = rtl8169_get_mac_version(xid, tp->supports_gmii); -- cgit v1.2.3 From bc638eabfed90fdc798fd5765e67e41abea76152 Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Mon, 29 May 2023 10:26:15 +0800 Subject: net: fec: remove last_bdp from fec_enet_txq_xmit_frame() The last_bdp is initialized to bdp, and both last_bdp and bdp are not changed. That is to say that last_bdp and bdp are always equal. So bdp can be used directly. Signed-off-by: Wei Fang Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230529022615.669589-1-wei.fang@nxp.com Signed-off-by: Paolo Abeni --- drivers/net/ethernet/freescale/fec_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 632bb4d589d7..4d37a811ae15 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3770,7 +3770,7 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, struct xdp_frame *frame) { unsigned int index, status, estatus; - struct bufdesc *bdp, *last_bdp; + struct bufdesc *bdp; dma_addr_t dma_addr; int entries_free; @@ -3782,7 +3782,6 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, /* Fill in a Tx ring entry */ bdp = txq->bd.cur; - last_bdp = bdp; status = fec16_to_cpu(bdp->cbd_sc); status &= ~BD_ENET_TX_STATS; @@ -3810,7 +3809,6 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, ebdp->cbd_esc = cpu_to_fec32(estatus); } - index = fec_enet_get_bd_index(last_bdp, &txq->bd); txq->tx_skbuff[index] = NULL; /* Make sure the updates to rest of the descriptor are performed before @@ -3825,7 +3823,7 @@ static int fec_enet_txq_xmit_frame(struct fec_enet_private *fep, bdp->cbd_sc = cpu_to_fec16(status); /* If this was the last BD in the ring, start at the beginning again. */ - bdp = fec_enet_get_nextdesc(last_bdp, &txq->bd); + bdp = fec_enet_get_nextdesc(bdp, &txq->bd); /* Make sure the update to bdp are performed before txq->bd.cur. */ dma_wmb(); -- cgit v1.2.3 From 6acdf43d8abe32082356d56a07598e513bbb59f4 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:27 +0200 Subject: devlink: introduce port ops placeholder In devlink, some of the objects have separate ops registered alongside with the object itself. Port however have ops in devlink_ops structure. For drivers what register multiple kinds of ports with different ops this is not convenient. Introduce devlink_port_ops and a set of functions that allow drivers to pass ops pointer during port registration. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- include/net/devlink.h | 41 +++++++++++++++++++++++++++++++++++------ net/devlink/leftover.c | 30 +++++++++++++++++++----------- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/include/net/devlink.h b/include/net/devlink.h index ec109b39c3ea..a1e230d24f05 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -123,6 +123,7 @@ struct devlink_port { struct list_head list; struct list_head region_list; struct devlink *devlink; + const struct devlink_port_ops *ops; unsigned int index; spinlock_t type_lock; /* Protects type and type_eth/ib * structures consistency. @@ -1649,15 +1650,43 @@ void devl_unregister(struct devlink *devlink); void devlink_register(struct devlink *devlink); void devlink_unregister(struct devlink *devlink); void devlink_free(struct devlink *devlink); + +/** + * struct devlink_port_ops - Port operations + */ +struct devlink_port_ops { +}; + void devlink_port_init(struct devlink *devlink, struct devlink_port *devlink_port); void devlink_port_fini(struct devlink_port *devlink_port); -int devl_port_register(struct devlink *devlink, - struct devlink_port *devlink_port, - unsigned int port_index); -int devlink_port_register(struct devlink *devlink, - struct devlink_port *devlink_port, - unsigned int port_index); + +int devl_port_register_with_ops(struct devlink *devlink, + struct devlink_port *devlink_port, + unsigned int port_index, + const struct devlink_port_ops *ops); + +static inline int devl_port_register(struct devlink *devlink, + struct devlink_port *devlink_port, + unsigned int port_index) +{ + return devl_port_register_with_ops(devlink, devlink_port, + port_index, NULL); +} + +int devlink_port_register_with_ops(struct devlink *devlink, + struct devlink_port *devlink_port, + unsigned int port_index, + const struct devlink_port_ops *ops); + +static inline int devlink_port_register(struct devlink *devlink, + struct devlink_port *devlink_port, + unsigned int port_index) +{ + return devlink_port_register_with_ops(devlink, devlink_port, + port_index, NULL); +} + void devl_port_unregister(struct devlink_port *devlink_port); void devlink_port_unregister(struct devlink_port *devlink_port); void devlink_port_type_eth_set(struct devlink_port *devlink_port); diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 9e801b749194..2295fa542dd8 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -6793,12 +6793,15 @@ void devlink_port_fini(struct devlink_port *devlink_port) } EXPORT_SYMBOL_GPL(devlink_port_fini); +static const struct devlink_port_ops devlink_port_dummy_ops = {}; + /** - * devl_port_register() - Register devlink port + * devl_port_register_with_ops() - Register devlink port * * @devlink: devlink * @devlink_port: devlink port * @port_index: driver-specific numerical identifier of the port + * @ops: port ops * * Register devlink port with provided port index. User can use * any indexing, even hw-related one. devlink_port structure @@ -6806,9 +6809,10 @@ EXPORT_SYMBOL_GPL(devlink_port_fini); * Note that the caller should take care of zeroing the devlink_port * structure. */ -int devl_port_register(struct devlink *devlink, - struct devlink_port *devlink_port, - unsigned int port_index) +int devl_port_register_with_ops(struct devlink *devlink, + struct devlink_port *devlink_port, + unsigned int port_index, + const struct devlink_port_ops *ops) { int err; @@ -6819,6 +6823,7 @@ int devl_port_register(struct devlink *devlink, devlink_port_init(devlink, devlink_port); devlink_port->registered = true; devlink_port->index = port_index; + devlink_port->ops = ops ? ops : &devlink_port_dummy_ops; spin_lock_init(&devlink_port->type_lock); INIT_LIST_HEAD(&devlink_port->reporter_list); err = xa_insert(&devlink->ports, port_index, devlink_port, GFP_KERNEL); @@ -6830,14 +6835,15 @@ int devl_port_register(struct devlink *devlink, devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW); return 0; } -EXPORT_SYMBOL_GPL(devl_port_register); +EXPORT_SYMBOL_GPL(devl_port_register_with_ops); /** - * devlink_port_register - Register devlink port + * devlink_port_register_with_ops - Register devlink port * * @devlink: devlink * @devlink_port: devlink port * @port_index: driver-specific numerical identifier of the port + * @ops: port ops * * Register devlink port with provided port index. User can use * any indexing, even hw-related one. devlink_port structure @@ -6847,18 +6853,20 @@ EXPORT_SYMBOL_GPL(devl_port_register); * * Context: Takes and release devlink->lock . */ -int devlink_port_register(struct devlink *devlink, - struct devlink_port *devlink_port, - unsigned int port_index) +int devlink_port_register_with_ops(struct devlink *devlink, + struct devlink_port *devlink_port, + unsigned int port_index, + const struct devlink_port_ops *ops) { int err; devl_lock(devlink); - err = devl_port_register(devlink, devlink_port, port_index); + err = devl_port_register_with_ops(devlink, devlink_port, + port_index, ops); devl_unlock(devlink); return err; } -EXPORT_SYMBOL_GPL(devlink_port_register); +EXPORT_SYMBOL_GPL(devlink_port_register_with_ops); /** * devl_port_unregister() - Unregister devlink port -- cgit v1.2.3 From b2857685372bb0ac5c8b2d5079cd8126aeef1e6b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:28 +0200 Subject: ice: register devlink port for PF with ops Use newly introduce devlink port registration function variant and register devlink port passing ops. Signed-off-by: Jiri Pirko Reviewed-by: Jesse Brandeburg Reviewed-by: Michal Wilczynski Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_devlink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index bc44cc220818..6661d12772a3 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -1512,6 +1512,9 @@ ice_devlink_set_port_split_options(struct ice_pf *pf, ice_active_port_option = active_idx; } +static const struct devlink_port_ops ice_devlink_port_ops = { +}; + /** * ice_devlink_create_pf_port - Create a devlink port for this PF * @pf: the PF to create a devlink port for @@ -1551,7 +1554,8 @@ int ice_devlink_create_pf_port(struct ice_pf *pf) devlink_port_attrs_set(devlink_port, &attrs); devlink = priv_to_devlink(pf); - err = devlink_port_register(devlink, devlink_port, vsi->idx); + err = devlink_port_register_with_ops(devlink, devlink_port, vsi->idx, + &ice_devlink_port_ops); if (err) { dev_err(dev, "Failed to create devlink port for PF %d, error %d\n", pf->hw.pf_id, err); -- cgit v1.2.3 From 865a1a1b97b6779f1e775b075dd534a43de64cfd Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:29 +0200 Subject: mlxsw_core: register devlink port with ops Use newly introduce devlink port registration function variant and register devlink port passing ops. Signed-off-by: Jiri Pirko Reviewed-by: Petr Machata Tested-by: Petr Machata Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 22db0bb15c45..605881b17ccc 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -3116,6 +3116,9 @@ u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core, } EXPORT_SYMBOL(mlxsw_core_res_get); +static const struct devlink_port_ops mlxsw_devlink_port_ops = { +}; + static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port, enum devlink_port_flavour flavour, u8 slot_index, u32 port_number, bool split, @@ -3150,7 +3153,8 @@ static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port, devlink_port_linecard_set(devlink_port, linecard->devlink_linecard); } - err = devl_port_register(devlink, devlink_port, local_port); + err = devl_port_register_with_ops(devlink, devlink_port, local_port, + &mlxsw_devlink_port_ops); if (err) memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port)); return err; -- cgit v1.2.3 From ab8ccc6c134779a26af3e613578f5b2ac820a649 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:30 +0200 Subject: nfp: devlink: register devlink port with ops Use newly introduce devlink port registration function variant and register devlink port passing ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index bf6bae557158..4e4296ecae7c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -321,6 +321,9 @@ const struct devlink_ops nfp_devlink_ops = { .flash_update = nfp_devlink_flash_update, }; +static const struct devlink_port_ops nfp_devlink_port_ops = { +}; + int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) { struct devlink_port_attrs attrs = {}; @@ -351,7 +354,8 @@ int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) devlink = priv_to_devlink(app->pf); - return devl_port_register(devlink, &port->dl_port, port->eth_id); + return devl_port_register_with_ops(devlink, &port->dl_port, + port->eth_id, &nfp_devlink_port_ops); } void nfp_devlink_port_unregister(struct nfp_port *port) -- cgit v1.2.3 From f58a3e4dfe241393ce383363583190903f140da5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:31 +0200 Subject: devlink: move port_split/unsplit() ops into devlink_port_ops Move port_split/unsplit() from devlink_ops into newly introduced devlink_port_ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_devlink.c | 4 ++-- drivers/net/ethernet/mellanox/mlxsw/core.c | 4 ++-- drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 4 ++-- include/net/devlink.h | 11 +++++++---- net/devlink/leftover.c | 10 +++++----- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index 6661d12772a3..80dc5445b50d 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -1256,8 +1256,6 @@ static const struct devlink_ops ice_devlink_ops = { BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), .reload_down = ice_devlink_reload_down, .reload_up = ice_devlink_reload_up, - .port_split = ice_devlink_port_split, - .port_unsplit = ice_devlink_port_unsplit, .eswitch_mode_get = ice_eswitch_mode_get, .eswitch_mode_set = ice_eswitch_mode_set, .info_get = ice_devlink_info_get, @@ -1513,6 +1511,8 @@ ice_devlink_set_port_split_options(struct ice_pf *pf, } static const struct devlink_port_ops ice_devlink_port_ops = { + .port_split = ice_devlink_port_split, + .port_unsplit = ice_devlink_port_unsplit, }; /** diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 605881b17ccc..1ccf3b73ed72 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -1723,8 +1723,6 @@ static const struct devlink_ops mlxsw_devlink_ops = { BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), .reload_down = mlxsw_devlink_core_bus_device_reload_down, .reload_up = mlxsw_devlink_core_bus_device_reload_up, - .port_split = mlxsw_devlink_port_split, - .port_unsplit = mlxsw_devlink_port_unsplit, .sb_pool_get = mlxsw_devlink_sb_pool_get, .sb_pool_set = mlxsw_devlink_sb_pool_set, .sb_port_pool_get = mlxsw_devlink_sb_port_pool_get, @@ -3117,6 +3115,8 @@ u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core, EXPORT_SYMBOL(mlxsw_core_res_get); static const struct devlink_port_ops mlxsw_devlink_port_ops = { + .port_split = mlxsw_devlink_port_split, + .port_unsplit = mlxsw_devlink_port_unsplit, }; static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u16 local_port, diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c index 4e4296ecae7c..8c6954c58a88 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c @@ -311,8 +311,6 @@ nfp_devlink_flash_update(struct devlink *devlink, } const struct devlink_ops nfp_devlink_ops = { - .port_split = nfp_devlink_port_split, - .port_unsplit = nfp_devlink_port_unsplit, .sb_pool_get = nfp_devlink_sb_pool_get, .sb_pool_set = nfp_devlink_sb_pool_set, .eswitch_mode_get = nfp_devlink_eswitch_mode_get, @@ -322,6 +320,8 @@ const struct devlink_ops nfp_devlink_ops = { }; static const struct devlink_port_ops nfp_devlink_port_ops = { + .port_split = nfp_devlink_port_split, + .port_unsplit = nfp_devlink_port_unsplit, }; int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) diff --git a/include/net/devlink.h b/include/net/devlink.h index a1e230d24f05..fdcb2c55f1b5 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1276,10 +1276,6 @@ struct devlink_ops { struct netlink_ext_ack *extack); int (*port_type_set)(struct devlink_port *devlink_port, enum devlink_port_type port_type); - int (*port_split)(struct devlink *devlink, struct devlink_port *port, - unsigned int count, struct netlink_ext_ack *extack); - int (*port_unsplit)(struct devlink *devlink, struct devlink_port *port, - struct netlink_ext_ack *extack); int (*sb_pool_get)(struct devlink *devlink, unsigned int sb_index, u16 pool_index, struct devlink_sb_pool_info *pool_info); @@ -1653,8 +1649,15 @@ void devlink_free(struct devlink *devlink); /** * struct devlink_port_ops - Port operations + * @port_split: Callback used to split the port into multiple ones. + * @port_unsplit: Callback used to unsplit the port group back into + * a single port. */ struct devlink_port_ops { + int (*port_split)(struct devlink *devlink, struct devlink_port *port, + unsigned int count, struct netlink_ext_ack *extack); + int (*port_unsplit)(struct devlink *devlink, struct devlink_port *port, + struct netlink_ext_ack *extack); }; void devlink_port_init(struct devlink *devlink, diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 2295fa542dd8..1ed95c76cf67 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1320,7 +1320,7 @@ static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb, if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PORT_SPLIT_COUNT)) return -EINVAL; - if (!devlink->ops->port_split) + if (!devlink_port->ops->port_split) return -EOPNOTSUPP; count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]); @@ -1339,8 +1339,8 @@ static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb, return -EINVAL; } - return devlink->ops->port_split(devlink, devlink_port, count, - info->extack); + return devlink_port->ops->port_split(devlink, devlink_port, count, + info->extack); } static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, @@ -1349,9 +1349,9 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, struct devlink_port *devlink_port = info->user_ptr[1]; struct devlink *devlink = info->user_ptr[0]; - if (!devlink->ops->port_unsplit) + if (!devlink_port->ops->port_unsplit) return -EOPNOTSUPP; - return devlink->ops->port_unsplit(devlink, devlink_port, info->extack); + return devlink_port->ops->port_unsplit(devlink, devlink_port, info->extack); } static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, -- cgit v1.2.3 From 8a756d91d26c1fe941d6839b41d385a4f84ac453 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:32 +0200 Subject: mlx4: register devlink port with ops Use newly introduce devlink port registration function variant and register devlink port passing ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx4/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 28c435ce98d8..369642478fab 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3024,13 +3024,17 @@ no_msi: } } +static const struct devlink_port_ops mlx4_devlink_port_ops = { +}; + static int mlx4_init_port_info(struct mlx4_dev *dev, int port) { struct devlink *devlink = priv_to_devlink(mlx4_priv(dev)); struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; int err; - err = devl_port_register(devlink, &info->devlink_port, port); + err = devl_port_register_with_ops(devlink, &info->devlink_port, port, + &mlx4_devlink_port_ops); if (err) return err; -- cgit v1.2.3 From 65a4c44bf9375a5d13287ee1e389b512e83f37eb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:33 +0200 Subject: devlink: move port_type_set() op into devlink_port_ops Move port_type_set() from devlink_ops into newly introduced devlink_port_ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx4/main.c | 52 +++++++++++++++---------------- include/net/devlink.h | 5 +-- net/devlink/leftover.c | 5 ++- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 369642478fab..61286b0d9b0c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3024,7 +3024,33 @@ no_msi: } } +static int mlx4_devlink_port_type_set(struct devlink_port *devlink_port, + enum devlink_port_type port_type) +{ + struct mlx4_port_info *info = container_of(devlink_port, + struct mlx4_port_info, + devlink_port); + enum mlx4_port_type mlx4_port_type; + + switch (port_type) { + case DEVLINK_PORT_TYPE_AUTO: + mlx4_port_type = MLX4_PORT_TYPE_AUTO; + break; + case DEVLINK_PORT_TYPE_ETH: + mlx4_port_type = MLX4_PORT_TYPE_ETH; + break; + case DEVLINK_PORT_TYPE_IB: + mlx4_port_type = MLX4_PORT_TYPE_IB; + break; + default: + return -EOPNOTSUPP; + } + + return __set_port_type(info, mlx4_port_type); +} + static const struct devlink_port_ops mlx4_devlink_port_ops = { + .port_type_set = mlx4_devlink_port_type_set, }; static int mlx4_init_port_info(struct mlx4_dev *dev, int port) @@ -3878,31 +3904,6 @@ err_disable_pdev: return err; } -static int mlx4_devlink_port_type_set(struct devlink_port *devlink_port, - enum devlink_port_type port_type) -{ - struct mlx4_port_info *info = container_of(devlink_port, - struct mlx4_port_info, - devlink_port); - enum mlx4_port_type mlx4_port_type; - - switch (port_type) { - case DEVLINK_PORT_TYPE_AUTO: - mlx4_port_type = MLX4_PORT_TYPE_AUTO; - break; - case DEVLINK_PORT_TYPE_ETH: - mlx4_port_type = MLX4_PORT_TYPE_ETH; - break; - case DEVLINK_PORT_TYPE_IB: - mlx4_port_type = MLX4_PORT_TYPE_IB; - break; - default: - return -EOPNOTSUPP; - } - - return __set_port_type(info, mlx4_port_type); -} - static void mlx4_devlink_param_load_driverinit_values(struct devlink *devlink) { struct mlx4_priv *priv = devlink_priv(devlink); @@ -3987,7 +3988,6 @@ static int mlx4_devlink_reload_up(struct devlink *devlink, enum devlink_reload_a } static const struct devlink_ops mlx4_devlink_ops = { - .port_type_set = mlx4_devlink_port_type_set, .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT), .reload_down = mlx4_devlink_reload_down, .reload_up = mlx4_devlink_reload_up, diff --git a/include/net/devlink.h b/include/net/devlink.h index fdcb2c55f1b5..0dfadc234b9e 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1274,8 +1274,6 @@ struct devlink_ops { int (*reload_up)(struct devlink *devlink, enum devlink_reload_action action, enum devlink_reload_limit limit, u32 *actions_performed, struct netlink_ext_ack *extack); - int (*port_type_set)(struct devlink_port *devlink_port, - enum devlink_port_type port_type); int (*sb_pool_get)(struct devlink *devlink, unsigned int sb_index, u16 pool_index, struct devlink_sb_pool_info *pool_info); @@ -1652,12 +1650,15 @@ void devlink_free(struct devlink *devlink); * @port_split: Callback used to split the port into multiple ones. * @port_unsplit: Callback used to unsplit the port group back into * a single port. + * @port_type_set: Callback used to set a type of a port. */ struct devlink_port_ops { int (*port_split)(struct devlink *devlink, struct devlink_port *port, unsigned int count, struct netlink_ext_ack *extack); int (*port_unsplit)(struct devlink *devlink, struct devlink_port *port, struct netlink_ext_ack *extack); + int (*port_type_set)(struct devlink_port *devlink_port, + enum devlink_port_type port_type); }; void devlink_port_init(struct devlink *devlink, diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 1ed95c76cf67..d69e278ae15a 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1137,14 +1137,13 @@ static int devlink_port_type_set(struct devlink_port *devlink_port, { int err; - if (!devlink_port->devlink->ops->port_type_set) + if (!devlink_port->ops->port_type_set) return -EOPNOTSUPP; if (port_type == devlink_port->type) return 0; - err = devlink_port->devlink->ops->port_type_set(devlink_port, - port_type); + err = devlink_port->ops->port_type_set(devlink_port, port_type); if (err) return err; -- cgit v1.2.3 From 7bfb3d0a83b66567ccf2b19110bbb787c56089aa Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:34 +0200 Subject: sfc: register devlink port with ops Use newly introduce devlink port registration function variant and register devlink port passing ops. Signed-off-by: Jiri Pirko Acked-by: Martin Habets Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/efx_devlink.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c index ef9971cbb695..e74f74037405 100644 --- a/drivers/net/ethernet/sfc/efx_devlink.c +++ b/drivers/net/ethernet/sfc/efx_devlink.c @@ -25,6 +25,10 @@ struct efx_devlink { }; #ifdef CONFIG_SFC_SRIOV + +static const struct devlink_port_ops sfc_devlink_port_ops = { +}; + static void efx_devlink_del_port(struct devlink_port *dl_port) { if (!dl_port) @@ -57,7 +61,9 @@ static int efx_devlink_add_port(struct efx_nic *efx, mport->dl_port.index = mport->mport_id; - return devl_port_register(efx->devlink, &mport->dl_port, mport->mport_id); + return devl_port_register_with_ops(efx->devlink, &mport->dl_port, + mport->mport_id, + &sfc_devlink_port_ops); } static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr, -- cgit v1.2.3 From aa3aff8264f2a6b463a24a5453aff7afa3483425 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:35 +0200 Subject: mlx5: register devlink ports with ops Use newly introduce devlink port registration function variant and register devlink port passing ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index 084a910bb4e7..d9c17481b972 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -65,6 +65,9 @@ static void mlx5_esw_dl_port_free(struct devlink_port *dl_port) kfree(dl_port); } +static const struct devlink_port_ops mlx5_esw_dl_port_ops = { +}; + int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num) { struct mlx5_core_dev *dev = esw->dev; @@ -87,7 +90,8 @@ int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_ devlink = priv_to_devlink(dev); dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num); - err = devl_port_register(devlink, dl_port, dl_port_index); + err = devl_port_register_with_ops(devlink, dl_port, dl_port_index, + &mlx5_esw_dl_port_ops); if (err) goto reg_err; @@ -134,6 +138,9 @@ struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u1 return IS_ERR(vport) ? ERR_CAST(vport) : vport->dl_port; } +static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = { +}; + int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port, u16 vport_num, u32 controller, u32 sfnum) { @@ -156,7 +163,8 @@ int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_p devlink_port_attrs_pci_sf_set(dl_port, controller, pfnum, sfnum, !!controller); devlink = priv_to_devlink(dev); dl_port_index = mlx5_esw_vport_to_devlink_port_index(dev, vport_num); - err = devl_port_register(devlink, dl_port, dl_port_index); + err = devl_port_register_with_ops(devlink, dl_port, dl_port_index, + &mlx5_esw_dl_sf_port_ops); if (err) return err; -- cgit v1.2.3 From 71c93e37cf3d0528e5d17ecc0b1b07db2086db67 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:36 +0200 Subject: devlink: move port_fn_hw_addr_get/set() to devlink_port_ops Move port_fn_hw_addr_get/set() from devlink_ops into newly introduced devlink_port_ops. Signed-off-by: Jiri Pirko Acked-by: Martin Habets Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 2 - .../ethernet/mellanox/mlx5/core/esw/devlink_port.c | 4 + drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 12 +-- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 12 +-- drivers/net/ethernet/sfc/efx_devlink.c | 86 +++++++++++----------- include/net/devlink.h | 38 ++++------ net/devlink/leftover.c | 15 ++-- 7 files changed, 80 insertions(+), 89 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index bfaec67abf0d..1e96f32bd1b5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -310,8 +310,6 @@ static const struct devlink_ops mlx5_devlink_ops = { .eswitch_inline_mode_get = mlx5_devlink_eswitch_inline_mode_get, .eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set, .eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get, - .port_function_hw_addr_get = mlx5_devlink_port_function_hw_addr_get, - .port_function_hw_addr_set = mlx5_devlink_port_function_hw_addr_set, .rate_leaf_tx_share_set = mlx5_esw_devlink_rate_leaf_tx_share_set, .rate_leaf_tx_max_set = mlx5_esw_devlink_rate_leaf_tx_max_set, .rate_node_tx_share_set = mlx5_esw_devlink_rate_node_tx_share_set, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index d9c17481b972..78d12c377900 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -66,6 +66,8 @@ static void mlx5_esw_dl_port_free(struct devlink_port *dl_port) } static const struct devlink_port_ops mlx5_esw_dl_port_ops = { + .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get, + .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, }; int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num) @@ -139,6 +141,8 @@ struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u1 } static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = { + .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get, + .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, }; int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 280dc71b032c..f70124ad71cf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -506,12 +506,12 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, struct netlink_ext_ack *extack); int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, enum devlink_eswitch_encap_mode *encap); -int mlx5_devlink_port_function_hw_addr_get(struct devlink_port *port, - u8 *hw_addr, int *hw_addr_len, - struct netlink_ext_ack *extack); -int mlx5_devlink_port_function_hw_addr_set(struct devlink_port *port, - const u8 *hw_addr, int hw_addr_len, - struct netlink_ext_ack *extack); +int mlx5_devlink_port_fn_hw_addr_get(struct devlink_port *port, + u8 *hw_addr, int *hw_addr_len, + struct netlink_ext_ack *extack); +int mlx5_devlink_port_fn_hw_addr_set(struct devlink_port *port, + const u8 *hw_addr, int hw_addr_len, + struct netlink_ext_ack *extack); int mlx5_devlink_port_fn_roce_get(struct devlink_port *port, bool *is_enabled, struct netlink_ext_ack *extack); int mlx5_devlink_port_fn_roce_set(struct devlink_port *port, bool enable, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 7a65dcf01dba..1b2f5e273525 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -3957,9 +3957,9 @@ is_port_function_supported(struct mlx5_eswitch *esw, u16 vport_num) mlx5_esw_is_sf_vport(esw, vport_num); } -int mlx5_devlink_port_function_hw_addr_get(struct devlink_port *port, - u8 *hw_addr, int *hw_addr_len, - struct netlink_ext_ack *extack) +int mlx5_devlink_port_fn_hw_addr_get(struct devlink_port *port, + u8 *hw_addr, int *hw_addr_len, + struct netlink_ext_ack *extack) { struct mlx5_eswitch *esw; struct mlx5_vport *vport; @@ -3986,9 +3986,9 @@ int mlx5_devlink_port_function_hw_addr_get(struct devlink_port *port, return 0; } -int mlx5_devlink_port_function_hw_addr_set(struct devlink_port *port, - const u8 *hw_addr, int hw_addr_len, - struct netlink_ext_ack *extack) +int mlx5_devlink_port_fn_hw_addr_set(struct devlink_port *port, + const u8 *hw_addr, int hw_addr_len, + struct netlink_ext_ack *extack) { struct mlx5_eswitch *esw; u16 vport_num; diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c index e74f74037405..b82dad50a5b1 100644 --- a/drivers/net/ethernet/sfc/efx_devlink.c +++ b/drivers/net/ethernet/sfc/efx_devlink.c @@ -26,46 +26,6 @@ struct efx_devlink { #ifdef CONFIG_SFC_SRIOV -static const struct devlink_port_ops sfc_devlink_port_ops = { -}; - -static void efx_devlink_del_port(struct devlink_port *dl_port) -{ - if (!dl_port) - return; - devl_port_unregister(dl_port); -} - -static int efx_devlink_add_port(struct efx_nic *efx, - struct mae_mport_desc *mport) -{ - bool external = false; - - if (!ef100_mport_on_local_intf(efx, mport)) - external = true; - - switch (mport->mport_type) { - case MAE_MPORT_DESC_MPORT_TYPE_VNIC: - if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) - devlink_port_attrs_pci_vf_set(&mport->dl_port, 0, mport->pf_idx, - mport->vf_idx, - external); - else - devlink_port_attrs_pci_pf_set(&mport->dl_port, 0, mport->pf_idx, - external); - break; - default: - /* MAE_MPORT_DESC_MPORT_ALIAS and UNDEFINED */ - return 0; - } - - mport->dl_port.index = mport->mport_id; - - return devl_port_register_with_ops(efx->devlink, &mport->dl_port, - mport->mport_id, - &sfc_devlink_port_ops); -} - static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr, int *hw_addr_len, struct netlink_ext_ack *extack) @@ -164,6 +124,48 @@ static int efx_devlink_port_addr_set(struct devlink_port *port, return rc; } +static const struct devlink_port_ops sfc_devlink_port_ops = { + .port_fn_hw_addr_get = efx_devlink_port_addr_get, + .port_fn_hw_addr_set = efx_devlink_port_addr_set, +}; + +static void efx_devlink_del_port(struct devlink_port *dl_port) +{ + if (!dl_port) + return; + devl_port_unregister(dl_port); +} + +static int efx_devlink_add_port(struct efx_nic *efx, + struct mae_mport_desc *mport) +{ + bool external = false; + + if (!ef100_mport_on_local_intf(efx, mport)) + external = true; + + switch (mport->mport_type) { + case MAE_MPORT_DESC_MPORT_TYPE_VNIC: + if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) + devlink_port_attrs_pci_vf_set(&mport->dl_port, 0, mport->pf_idx, + mport->vf_idx, + external); + else + devlink_port_attrs_pci_pf_set(&mport->dl_port, 0, mport->pf_idx, + external); + break; + default: + /* MAE_MPORT_DESC_MPORT_ALIAS and UNDEFINED */ + return 0; + } + + mport->dl_port.index = mport->mport_id; + + return devl_port_register_with_ops(efx->devlink, &mport->dl_port, + mport->mport_id, + &sfc_devlink_port_ops); +} + #endif static int efx_devlink_info_nvram_partition(struct efx_nic *efx, @@ -615,10 +617,6 @@ static int efx_devlink_info_get(struct devlink *devlink, static const struct devlink_ops sfc_devlink_ops = { .info_get = efx_devlink_info_get, -#ifdef CONFIG_SFC_SRIOV - .port_function_hw_addr_get = efx_devlink_port_addr_get, - .port_function_hw_addr_set = efx_devlink_port_addr_set, -#endif }; #ifdef CONFIG_SFC_SRIOV diff --git a/include/net/devlink.h b/include/net/devlink.h index 0dfadc234b9e..c580b154cfe4 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1429,28 +1429,6 @@ struct devlink_ops { int (*trap_policer_counter_get)(struct devlink *devlink, const struct devlink_trap_policer *policer, u64 *p_drops); - /** - * @port_function_hw_addr_get: Port function's hardware address get function. - * - * Should be used by device drivers to report the hardware address of a function managed - * by the devlink port. Driver should return -EOPNOTSUPP if it doesn't support port - * function handling for a particular port. - * - * Note: @extack can be NULL when port notifier queries the port function. - */ - int (*port_function_hw_addr_get)(struct devlink_port *port, u8 *hw_addr, - int *hw_addr_len, - struct netlink_ext_ack *extack); - /** - * @port_function_hw_addr_set: Port function's hardware address set function. - * - * Should be used by device drivers to set the hardware address of a function managed - * by the devlink port. Driver should return -EOPNOTSUPP if it doesn't support port - * function handling for a particular port. - */ - int (*port_function_hw_addr_set)(struct devlink_port *port, - const u8 *hw_addr, int hw_addr_len, - struct netlink_ext_ack *extack); /** * @port_fn_roce_get: Port function's roce get function. * @@ -1651,6 +1629,16 @@ void devlink_free(struct devlink *devlink); * @port_unsplit: Callback used to unsplit the port group back into * a single port. * @port_type_set: Callback used to set a type of a port. + * @port_fn_hw_addr_get: Callback used to set port function's hardware address. + * Should be used by device drivers to report + * the hardware address of a function managed + * by the devlink port. + * @port_fn_hw_addr_set: Callback used to set port function's hardware address. + * Should be used by device drivers to set the hardware + * address of a function managed by the devlink port. + * + * Note: Driver should return -EOPNOTSUPP if it doesn't support + * port function (@port_fn_*) handling for a particular port. */ struct devlink_port_ops { int (*port_split)(struct devlink *devlink, struct devlink_port *port, @@ -1659,6 +1647,12 @@ struct devlink_port_ops { struct netlink_ext_ack *extack); int (*port_type_set)(struct devlink_port *devlink_port, enum devlink_port_type port_type); + int (*port_fn_hw_addr_get)(struct devlink_port *port, u8 *hw_addr, + int *hw_addr_len, + struct netlink_ext_ack *extack); + int (*port_fn_hw_addr_set)(struct devlink_port *port, + const u8 *hw_addr, int hw_addr_len, + struct netlink_ext_ack *extack); }; void devlink_port_init(struct devlink *devlink, diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index d69e278ae15a..ac171ea984cc 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -691,8 +691,7 @@ static int devlink_nl_port_attrs_put(struct sk_buff *msg, return 0; } -static int devlink_port_fn_hw_addr_fill(const struct devlink_ops *ops, - struct devlink_port *port, +static int devlink_port_fn_hw_addr_fill(struct devlink_port *port, struct sk_buff *msg, struct netlink_ext_ack *extack, bool *msg_updated) @@ -701,10 +700,10 @@ static int devlink_port_fn_hw_addr_fill(const struct devlink_ops *ops, int hw_addr_len; int err; - if (!ops->port_function_hw_addr_get) + if (!port->ops->port_fn_hw_addr_get) return 0; - err = ops->port_function_hw_addr_get(port, hw_addr, &hw_addr_len, + err = port->ops->port_fn_hw_addr_get(port, hw_addr, &hw_addr_len, extack); if (err) { if (err == -EOPNOTSUPP) @@ -884,8 +883,7 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por return -EMSGSIZE; ops = port->devlink->ops; - err = devlink_port_fn_hw_addr_fill(ops, port, msg, extack, - &msg_updated); + err = devlink_port_fn_hw_addr_fill(port, msg, extack, &msg_updated); if (err) goto out; err = devlink_port_fn_caps_fill(ops, port, msg, extack, @@ -1156,7 +1154,6 @@ static int devlink_port_function_hw_addr_set(struct devlink_port *port, const struct nlattr *attr, struct netlink_ext_ack *extack) { - const struct devlink_ops *ops = port->devlink->ops; const u8 *hw_addr; int hw_addr_len; @@ -1177,7 +1174,7 @@ static int devlink_port_function_hw_addr_set(struct devlink_port *port, } } - return ops->port_function_hw_addr_set(port, hw_addr, hw_addr_len, + return port->ops->port_fn_hw_addr_set(port, hw_addr, hw_addr_len, extack); } @@ -1201,7 +1198,7 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port, struct nlattr *attr; if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] && - !ops->port_function_hw_addr_set) { + !devlink_port->ops->port_fn_hw_addr_set) { NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR], "Port doesn't support function attributes"); return -EOPNOTSUPP; -- cgit v1.2.3 From 933c13275c4933ad68f107ed93ae9b0658b19ad0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:37 +0200 Subject: devlink: move port_fn_roce_get/set() to devlink_port_ops Move port_fn_roce_get/set() from devlink_ops into newly introduced devlink_port_ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 2 -- .../ethernet/mellanox/mlx5/core/esw/devlink_port.c | 4 +++ include/net/devlink.h | 31 +++++++++------------- net/devlink/leftover.c | 17 ++++++------ 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 1e96f32bd1b5..d63ec466dcd6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -317,8 +317,6 @@ static const struct devlink_ops mlx5_devlink_ops = { .rate_node_new = mlx5_esw_devlink_rate_node_new, .rate_node_del = mlx5_esw_devlink_rate_node_del, .rate_leaf_parent_set = mlx5_esw_devlink_rate_parent_set, - .port_fn_roce_get = mlx5_devlink_port_fn_roce_get, - .port_fn_roce_set = mlx5_devlink_port_fn_roce_set, .port_fn_migratable_get = mlx5_devlink_port_fn_migratable_get, .port_fn_migratable_set = mlx5_devlink_port_fn_migratable_set, #endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index 78d12c377900..9011619e1fdd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -68,6 +68,8 @@ static void mlx5_esw_dl_port_free(struct devlink_port *dl_port) static const struct devlink_port_ops mlx5_esw_dl_port_ops = { .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get, .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, + .port_fn_roce_get = mlx5_devlink_port_fn_roce_get, + .port_fn_roce_set = mlx5_devlink_port_fn_roce_set, }; int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num) @@ -143,6 +145,8 @@ struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u1 static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = { .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get, .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, + .port_fn_roce_get = mlx5_devlink_port_fn_roce_get, + .port_fn_roce_set = mlx5_devlink_port_fn_roce_set, }; int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port, diff --git a/include/net/devlink.h b/include/net/devlink.h index c580b154cfe4..b8e8ea850562 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1429,24 +1429,6 @@ struct devlink_ops { int (*trap_policer_counter_get)(struct devlink *devlink, const struct devlink_trap_policer *policer, u64 *p_drops); - /** - * @port_fn_roce_get: Port function's roce get function. - * - * Query RoCE state of a function managed by the devlink port. - * Return -EOPNOTSUPP if port function RoCE handling is not supported. - */ - int (*port_fn_roce_get)(struct devlink_port *devlink_port, - bool *is_enable, - struct netlink_ext_ack *extack); - /** - * @port_fn_roce_set: Port function's roce set function. - * - * Enable/Disable the RoCE state of a function managed by the devlink - * port. - * Return -EOPNOTSUPP if port function RoCE handling is not supported. - */ - int (*port_fn_roce_set)(struct devlink_port *devlink_port, - bool enable, struct netlink_ext_ack *extack); /** * @port_fn_migratable_get: Port function's migratable get function. * @@ -1636,6 +1618,14 @@ void devlink_free(struct devlink *devlink); * @port_fn_hw_addr_set: Callback used to set port function's hardware address. * Should be used by device drivers to set the hardware * address of a function managed by the devlink port. + * @port_fn_roce_get: Callback used to get port function's RoCE capability. + * Should be used by device drivers to report + * the current state of RoCE capability of a function + * managed by the devlink port. + * @port_fn_roce_set: Callback used to set port function's RoCE capability. + * Should be used by device drivers to enable/disable + * RoCE capability of a function managed + * by the devlink port. * * Note: Driver should return -EOPNOTSUPP if it doesn't support * port function (@port_fn_*) handling for a particular port. @@ -1653,6 +1643,11 @@ struct devlink_port_ops { int (*port_fn_hw_addr_set)(struct devlink_port *port, const u8 *hw_addr, int hw_addr_len, struct netlink_ext_ack *extack); + int (*port_fn_roce_get)(struct devlink_port *devlink_port, + bool *is_enable, + struct netlink_ext_ack *extack); + int (*port_fn_roce_set)(struct devlink_port *devlink_port, + bool enable, struct netlink_ext_ack *extack); }; void devlink_port_init(struct devlink *devlink, diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index ac171ea984cc..e87ca3933a50 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -447,18 +447,18 @@ static void devlink_port_fn_cap_fill(struct nla_bitfield32 *caps, caps->value |= cap; } -static int devlink_port_fn_roce_fill(const struct devlink_ops *ops, - struct devlink_port *devlink_port, +static int devlink_port_fn_roce_fill(struct devlink_port *devlink_port, struct nla_bitfield32 *caps, struct netlink_ext_ack *extack) { bool is_enable; int err; - if (!ops->port_fn_roce_get) + if (!devlink_port->ops->port_fn_roce_get) return 0; - err = ops->port_fn_roce_get(devlink_port, &is_enable, extack); + err = devlink_port->ops->port_fn_roce_get(devlink_port, &is_enable, + extack); if (err) { if (err == -EOPNOTSUPP) return 0; @@ -501,7 +501,7 @@ static int devlink_port_fn_caps_fill(const struct devlink_ops *ops, struct nla_bitfield32 caps = {}; int err; - err = devlink_port_fn_roce_fill(ops, devlink_port, &caps, extack); + err = devlink_port_fn_roce_fill(devlink_port, &caps, extack); if (err) return err; @@ -837,9 +837,8 @@ static int devlink_port_fn_roce_set(struct devlink_port *devlink_port, bool enable, struct netlink_ext_ack *extack) { - const struct devlink_ops *ops = devlink_port->devlink->ops; - - return ops->port_fn_roce_set(devlink_port, enable, extack); + return devlink_port->ops->port_fn_roce_set(devlink_port, enable, + extack); } static int devlink_port_fn_caps_set(struct devlink_port *devlink_port, @@ -1214,7 +1213,7 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port, caps = nla_get_bitfield32(attr); if (caps.selector & DEVLINK_PORT_FN_CAP_ROCE && - !ops->port_fn_roce_set) { + !devlink_port->ops->port_fn_roce_set) { NL_SET_ERR_MSG_ATTR(extack, attr, "Port doesn't support RoCE function attribute"); return -EOPNOTSUPP; -- cgit v1.2.3 From 4a490d7154b3d84c7e451502306a53b6607b6566 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:38 +0200 Subject: devlink: move port_fn_migratable_get/set() to devlink_port_ops Move port_fn_migratable_get/set() from devlink_ops into newly introduced devlink_port_ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 2 -- .../ethernet/mellanox/mlx5/core/esw/devlink_port.c | 2 ++ include/net/devlink.h | 35 +++++++++------------- net/devlink/leftover.c | 23 +++++++------- 4 files changed, 26 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index d63ec466dcd6..678bae618769 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -317,8 +317,6 @@ static const struct devlink_ops mlx5_devlink_ops = { .rate_node_new = mlx5_esw_devlink_rate_node_new, .rate_node_del = mlx5_esw_devlink_rate_node_del, .rate_leaf_parent_set = mlx5_esw_devlink_rate_parent_set, - .port_fn_migratable_get = mlx5_devlink_port_fn_migratable_get, - .port_fn_migratable_set = mlx5_devlink_port_fn_migratable_set, #endif #ifdef CONFIG_MLX5_SF_MANAGER .port_new = mlx5_devlink_sf_port_new, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index 9011619e1fdd..2ececd2b86c8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -70,6 +70,8 @@ static const struct devlink_port_ops mlx5_esw_dl_port_ops = { .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, .port_fn_roce_get = mlx5_devlink_port_fn_roce_get, .port_fn_roce_set = mlx5_devlink_port_fn_roce_set, + .port_fn_migratable_get = mlx5_devlink_port_fn_migratable_get, + .port_fn_migratable_set = mlx5_devlink_port_fn_migratable_set, }; int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, u16 vport_num) diff --git a/include/net/devlink.h b/include/net/devlink.h index b8e8ea850562..25fa952a46a6 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1429,27 +1429,6 @@ struct devlink_ops { int (*trap_policer_counter_get)(struct devlink *devlink, const struct devlink_trap_policer *policer, u64 *p_drops); - /** - * @port_fn_migratable_get: Port function's migratable get function. - * - * Query migratable state of a function managed by the devlink port. - * Return -EOPNOTSUPP if port function migratable handling is not - * supported. - */ - int (*port_fn_migratable_get)(struct devlink_port *devlink_port, - bool *is_enable, - struct netlink_ext_ack *extack); - /** - * @port_fn_migratable_set: Port function's migratable set function. - * - * Enable/Disable migratable state of a function managed by the devlink - * port. - * Return -EOPNOTSUPP if port function migratable handling is not - * supported. - */ - int (*port_fn_migratable_set)(struct devlink_port *devlink_port, - bool enable, - struct netlink_ext_ack *extack); /** * port_new() - Add a new port function of a specified flavor * @devlink: Devlink instance @@ -1626,6 +1605,14 @@ void devlink_free(struct devlink *devlink); * Should be used by device drivers to enable/disable * RoCE capability of a function managed * by the devlink port. + * @port_fn_migratable_get: Callback used to get port function's migratable + * capability. Should be used by device drivers + * to report the current state of migratable capability + * of a function managed by the devlink port. + * @port_fn_migratable_set: Callback used to set port function's migratable + * capability. Should be used by device drivers + * to enable/disable migratable capability of + * a function managed by the devlink port. * * Note: Driver should return -EOPNOTSUPP if it doesn't support * port function (@port_fn_*) handling for a particular port. @@ -1648,6 +1635,12 @@ struct devlink_port_ops { struct netlink_ext_ack *extack); int (*port_fn_roce_set)(struct devlink_port *devlink_port, bool enable, struct netlink_ext_ack *extack); + int (*port_fn_migratable_get)(struct devlink_port *devlink_port, + bool *is_enable, + struct netlink_ext_ack *extack); + int (*port_fn_migratable_set)(struct devlink_port *devlink_port, + bool enable, + struct netlink_ext_ack *extack); }; void devlink_port_init(struct devlink *devlink, diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index e87ca3933a50..c16451ca744d 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -469,19 +469,19 @@ static int devlink_port_fn_roce_fill(struct devlink_port *devlink_port, return 0; } -static int devlink_port_fn_migratable_fill(const struct devlink_ops *ops, - struct devlink_port *devlink_port, +static int devlink_port_fn_migratable_fill(struct devlink_port *devlink_port, struct nla_bitfield32 *caps, struct netlink_ext_ack *extack) { bool is_enable; int err; - if (!ops->port_fn_migratable_get || + if (!devlink_port->ops->port_fn_migratable_get || devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_PCI_VF) return 0; - err = ops->port_fn_migratable_get(devlink_port, &is_enable, extack); + err = devlink_port->ops->port_fn_migratable_get(devlink_port, + &is_enable, extack); if (err) { if (err == -EOPNOTSUPP) return 0; @@ -492,8 +492,7 @@ static int devlink_port_fn_migratable_fill(const struct devlink_ops *ops, return 0; } -static int devlink_port_fn_caps_fill(const struct devlink_ops *ops, - struct devlink_port *devlink_port, +static int devlink_port_fn_caps_fill(struct devlink_port *devlink_port, struct sk_buff *msg, struct netlink_ext_ack *extack, bool *msg_updated) @@ -505,7 +504,7 @@ static int devlink_port_fn_caps_fill(const struct devlink_ops *ops, if (err) return err; - err = devlink_port_fn_migratable_fill(ops, devlink_port, &caps, extack); + err = devlink_port_fn_migratable_fill(devlink_port, &caps, extack); if (err) return err; @@ -828,9 +827,8 @@ static int devlink_port_fn_mig_set(struct devlink_port *devlink_port, bool enable, struct netlink_ext_ack *extack) { - const struct devlink_ops *ops = devlink_port->devlink->ops; - - return ops->port_fn_migratable_set(devlink_port, enable, extack); + return devlink_port->ops->port_fn_migratable_set(devlink_port, enable, + extack); } static int @@ -885,8 +883,7 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por err = devlink_port_fn_hw_addr_fill(port, msg, extack, &msg_updated); if (err) goto out; - err = devlink_port_fn_caps_fill(ops, port, msg, extack, - &msg_updated); + err = devlink_port_fn_caps_fill(port, msg, extack, &msg_updated); if (err) goto out; err = devlink_port_fn_state_fill(ops, port, msg, extack, &msg_updated); @@ -1219,7 +1216,7 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port, return -EOPNOTSUPP; } if (caps.selector & DEVLINK_PORT_FN_CAP_MIGRATABLE) { - if (!ops->port_fn_migratable_set) { + if (!devlink_port->ops->port_fn_migratable_set) { NL_SET_ERR_MSG_ATTR(extack, attr, "Port doesn't support migratable function attribute"); return -EOPNOTSUPP; -- cgit v1.2.3 From 216aa67f3e981a0cfb0a7c3b0d4c107823ef6c56 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:39 +0200 Subject: devlink: move port_fn_state_get/set() to devlink_port_ops Move port_fn_state_get/set() from devlink_ops into newly introduced devlink_port_ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 2 - .../ethernet/mellanox/mlx5/core/esw/devlink_port.c | 4 ++ include/net/devlink.h | 45 ++++++++-------------- net/devlink/leftover.c | 19 ++++----- 4 files changed, 26 insertions(+), 44 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 678bae618769..e39fd85ea2f9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -321,8 +321,6 @@ static const struct devlink_ops mlx5_devlink_ops = { #ifdef CONFIG_MLX5_SF_MANAGER .port_new = mlx5_devlink_sf_port_new, .port_del = mlx5_devlink_sf_port_del, - .port_fn_state_get = mlx5_devlink_sf_port_fn_state_get, - .port_fn_state_set = mlx5_devlink_sf_port_fn_state_set, #endif .flash_update = mlx5_devlink_flash_update, .info_get = mlx5_devlink_info_get, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index 2ececd2b86c8..76c5d6e9d47f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -149,6 +149,10 @@ static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = { .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, .port_fn_roce_get = mlx5_devlink_port_fn_roce_get, .port_fn_roce_set = mlx5_devlink_port_fn_roce_set, +#ifdef CONFIG_MLX5_SF_MANAGER + .port_fn_state_get = mlx5_devlink_sf_port_fn_state_get, + .port_fn_state_set = mlx5_devlink_sf_port_fn_state_set, +#endif }; int mlx5_esw_devlink_sf_port_register(struct mlx5_eswitch *esw, struct devlink_port *dl_port, diff --git a/include/net/devlink.h b/include/net/devlink.h index 25fa952a46a6..835989c10395 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1464,36 +1464,6 @@ struct devlink_ops { */ int (*port_del)(struct devlink *devlink, struct devlink_port *port, struct netlink_ext_ack *extack); - /** - * port_fn_state_get() - Get the state of a port function - * @devlink: Devlink instance - * @port: The devlink port - * @state: Admin configured state - * @opstate: Current operational state - * @extack: extack for reporting error messages - * - * Reports the admin and operational state of a devlink port function - * - * Return: 0 on success, negative value otherwise. - */ - int (*port_fn_state_get)(struct devlink_port *port, - enum devlink_port_fn_state *state, - enum devlink_port_fn_opstate *opstate, - struct netlink_ext_ack *extack); - /** - * port_fn_state_set() - Set the admin state of a port function - * @devlink: Devlink instance - * @port: The devlink port - * @state: Admin state - * @extack: extack for reporting error messages - * - * Set the admin state of a devlink port function - * - * Return: 0 on success, negative value otherwise. - */ - int (*port_fn_state_set)(struct devlink_port *port, - enum devlink_port_fn_state state, - struct netlink_ext_ack *extack); /** * Rate control callbacks. @@ -1613,6 +1583,14 @@ void devlink_free(struct devlink *devlink); * capability. Should be used by device drivers * to enable/disable migratable capability of * a function managed by the devlink port. + * @port_fn_state_get: Callback used to get port function's state. + * Should be used by device drivers to report + * the current admin and operational state of a + * function managed by the devlink port. + * @port_fn_state_set: Callback used to get port function's state. + * Should be used by device drivers set + * the admin state of a function managed + * by the devlink port. * * Note: Driver should return -EOPNOTSUPP if it doesn't support * port function (@port_fn_*) handling for a particular port. @@ -1641,6 +1619,13 @@ struct devlink_port_ops { int (*port_fn_migratable_set)(struct devlink_port *devlink_port, bool enable, struct netlink_ext_ack *extack); + int (*port_fn_state_get)(struct devlink_port *port, + enum devlink_port_fn_state *state, + enum devlink_port_fn_opstate *opstate, + struct netlink_ext_ack *extack); + int (*port_fn_state_set)(struct devlink_port *port, + enum devlink_port_fn_state state, + struct netlink_ext_ack *extack); }; void devlink_port_init(struct devlink *devlink, diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index c16451ca744d..36acaa6a6f18 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -787,8 +787,7 @@ devlink_port_fn_opstate_valid(enum devlink_port_fn_opstate opstate) opstate == DEVLINK_PORT_FN_OPSTATE_ATTACHED; } -static int devlink_port_fn_state_fill(const struct devlink_ops *ops, - struct devlink_port *port, +static int devlink_port_fn_state_fill(struct devlink_port *port, struct sk_buff *msg, struct netlink_ext_ack *extack, bool *msg_updated) @@ -797,10 +796,10 @@ static int devlink_port_fn_state_fill(const struct devlink_ops *ops, enum devlink_port_fn_state state; int err; - if (!ops->port_fn_state_get) + if (!port->ops->port_fn_state_get) return 0; - err = ops->port_fn_state_get(port, &state, &opstate, extack); + err = port->ops->port_fn_state_get(port, &state, &opstate, extack); if (err) { if (err == -EOPNOTSUPP) return 0; @@ -870,7 +869,6 @@ static int devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port, struct netlink_ext_ack *extack) { - const struct devlink_ops *ops; struct nlattr *function_attr; bool msg_updated = false; int err; @@ -879,14 +877,13 @@ devlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *por if (!function_attr) return -EMSGSIZE; - ops = port->devlink->ops; err = devlink_port_fn_hw_addr_fill(port, msg, extack, &msg_updated); if (err) goto out; err = devlink_port_fn_caps_fill(port, msg, extack, &msg_updated); if (err) goto out; - err = devlink_port_fn_state_fill(ops, port, msg, extack, &msg_updated); + err = devlink_port_fn_state_fill(port, msg, extack, &msg_updated); out: if (err || !msg_updated) nla_nest_cancel(msg, function_attr); @@ -1179,18 +1176,15 @@ static int devlink_port_fn_state_set(struct devlink_port *port, struct netlink_ext_ack *extack) { enum devlink_port_fn_state state; - const struct devlink_ops *ops; state = nla_get_u8(attr); - ops = port->devlink->ops; - return ops->port_fn_state_set(port, state, extack); + return port->ops->port_fn_state_set(port, state, extack); } static int devlink_port_function_validate(struct devlink_port *devlink_port, struct nlattr **tb, struct netlink_ext_ack *extack) { - const struct devlink_ops *ops = devlink_port->devlink->ops; struct nlattr *attr; if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] && @@ -1199,7 +1193,8 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port, "Port doesn't support function attributes"); return -EOPNOTSUPP; } - if (tb[DEVLINK_PORT_FN_ATTR_STATE] && !ops->port_fn_state_set) { + if (tb[DEVLINK_PORT_FN_ATTR_STATE] && + !devlink_port->ops->port_fn_state_set) { NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR], "Function does not support state setting"); return -EOPNOTSUPP; -- cgit v1.2.3 From 216ba9f4adc8f2e452edb9a58d2dfbfc11608c00 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:40 +0200 Subject: devlink: move port_del() to devlink_port_ops Move port_del() from devlink_ops into newly introduced devlink_port_ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 1 - .../ethernet/mellanox/mlx5/core/esw/devlink_port.c | 3 +++ include/net/devlink.h | 22 +++++----------------- net/devlink/leftover.c | 6 +++--- 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index e39fd85ea2f9..63635cc44479 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -320,7 +320,6 @@ static const struct devlink_ops mlx5_devlink_ops = { #endif #ifdef CONFIG_MLX5_SF_MANAGER .port_new = mlx5_devlink_sf_port_new, - .port_del = mlx5_devlink_sf_port_del, #endif .flash_update = mlx5_devlink_flash_update, .info_get = mlx5_devlink_info_get, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index 76c5d6e9d47f..f370f67d9e33 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -145,6 +145,9 @@ struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u1 } static const struct devlink_port_ops mlx5_esw_dl_sf_port_ops = { +#ifdef CONFIG_MLX5_SF_MANAGER + .port_del = mlx5_devlink_sf_port_del, +#endif .port_fn_hw_addr_get = mlx5_devlink_port_fn_hw_addr_get, .port_fn_hw_addr_set = mlx5_devlink_port_fn_hw_addr_set, .port_fn_roce_get = mlx5_devlink_port_fn_roce_get, diff --git a/include/net/devlink.h b/include/net/devlink.h index 835989c10395..fe42ad46cf3b 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1447,23 +1447,6 @@ struct devlink_ops { int (*port_new)(struct devlink *devlink, const struct devlink_port_new_attrs *attrs, struct netlink_ext_ack *extack); - /** - * port_del() - Delete a port function - * @devlink: Devlink instance - * @port: The devlink port - * @extack: extack for reporting error messages - * - * Devlink core will call this device driver function upon user request - * to delete a previously created port function - * - * Notes: - * - On success, drivers must unregister the corresponding devlink - * port - * - * Return: 0 on success, negative value otherwise. - */ - int (*port_del)(struct devlink *devlink, struct devlink_port *port, - struct netlink_ext_ack *extack); /** * Rate control callbacks. @@ -1560,6 +1543,9 @@ void devlink_free(struct devlink *devlink); * @port_unsplit: Callback used to unsplit the port group back into * a single port. * @port_type_set: Callback used to set a type of a port. + * @port_del: Callback used to delete selected port along with related function. + * Devlink core calls this upon user request to delete + * a port previously created by devlink_ops->port_new(). * @port_fn_hw_addr_get: Callback used to set port function's hardware address. * Should be used by device drivers to report * the hardware address of a function managed @@ -1602,6 +1588,8 @@ struct devlink_port_ops { struct netlink_ext_ack *extack); int (*port_type_set)(struct devlink_port *devlink_port, enum devlink_port_type port_type); + int (*port_del)(struct devlink *devlink, struct devlink_port *port, + struct netlink_ext_ack *extack); int (*port_fn_hw_addr_get)(struct devlink_port *port, u8 *hw_addr, int *hw_addr_len, struct netlink_ext_ack *extack); diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 36acaa6a6f18..404313128cfb 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1348,7 +1348,7 @@ static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, struct devlink_port_new_attrs new_attrs = {}; struct devlink *devlink = info->user_ptr[0]; - if (!devlink->ops->port_new || !devlink->ops->port_del) + if (!devlink->ops->port_new) return -EOPNOTSUPP; if (!info->attrs[DEVLINK_ATTR_PORT_FLAVOUR] || @@ -1387,10 +1387,10 @@ static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb, struct netlink_ext_ack *extack = info->extack; struct devlink *devlink = info->user_ptr[0]; - if (!devlink->ops->port_del) + if (!devlink_port->ops->port_del) return -EOPNOTSUPP; - return devlink->ops->port_del(devlink, devlink_port, extack); + return devlink_port->ops->port_del(devlink, devlink_port, extack); } static int -- cgit v1.2.3 From 4b5ed2b5a145543bd901b97f33bcac55a574253b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 26 May 2023 12:28:41 +0200 Subject: devlink: save devlink_port_ops into a variable in devlink_port_function_validate() Now when the original ops variable is removed, introduce it again but this time for devlink_port_ops. Signed-off-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- net/devlink/leftover.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 404313128cfb..d5ca9fbe2d40 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1185,16 +1185,16 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port, struct nlattr **tb, struct netlink_ext_ack *extack) { + const struct devlink_port_ops *ops = devlink_port->ops; struct nlattr *attr; if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] && - !devlink_port->ops->port_fn_hw_addr_set) { + !ops->port_fn_hw_addr_set) { NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR], "Port doesn't support function attributes"); return -EOPNOTSUPP; } - if (tb[DEVLINK_PORT_FN_ATTR_STATE] && - !devlink_port->ops->port_fn_state_set) { + if (tb[DEVLINK_PORT_FN_ATTR_STATE] && !ops->port_fn_state_set) { NL_SET_ERR_MSG_ATTR(extack, tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR], "Function does not support state setting"); return -EOPNOTSUPP; @@ -1205,13 +1205,13 @@ static int devlink_port_function_validate(struct devlink_port *devlink_port, caps = nla_get_bitfield32(attr); if (caps.selector & DEVLINK_PORT_FN_CAP_ROCE && - !devlink_port->ops->port_fn_roce_set) { + !ops->port_fn_roce_set) { NL_SET_ERR_MSG_ATTR(extack, attr, "Port doesn't support RoCE function attribute"); return -EOPNOTSUPP; } if (caps.selector & DEVLINK_PORT_FN_CAP_MIGRATABLE) { - if (!devlink_port->ops->port_fn_migratable_set) { + if (!ops->port_fn_migratable_set) { NL_SET_ERR_MSG_ATTR(extack, attr, "Port doesn't support migratable function attribute"); return -EOPNOTSUPP; -- cgit v1.2.3 From e6c2f594ed961273479505b42040782820190305 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 30 May 2023 13:50:29 -0700 Subject: bpf: Silence a warning in btf_type_id_size() syzbot reported a warning in [1] with the following stacktrace: WARNING: CPU: 0 PID: 5005 at kernel/bpf/btf.c:1988 btf_type_id_size+0x2d9/0x9d0 kernel/bpf/btf.c:1988 ... RIP: 0010:btf_type_id_size+0x2d9/0x9d0 kernel/bpf/btf.c:1988 ... Call Trace: map_check_btf kernel/bpf/syscall.c:1024 [inline] map_create+0x1157/0x1860 kernel/bpf/syscall.c:1198 __sys_bpf+0x127f/0x5420 kernel/bpf/syscall.c:5040 __do_sys_bpf kernel/bpf/syscall.c:5162 [inline] __se_sys_bpf kernel/bpf/syscall.c:5160 [inline] __x64_sys_bpf+0x79/0xc0 kernel/bpf/syscall.c:5160 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd With the following btf [1] DECL_TAG 'a' type_id=4 component_idx=-1 [2] PTR '(anon)' type_id=0 [3] TYPE_TAG 'a' type_id=2 [4] VAR 'a' type_id=3, linkage=static and when the bpf_attr.btf_key_type_id = 1 (DECL_TAG), the following WARN_ON_ONCE in btf_type_id_size() is triggered: if (WARN_ON_ONCE(!btf_type_is_modifier(size_type) && !btf_type_is_var(size_type))) return NULL; Note that 'return NULL' is the correct behavior as we don't want a DECL_TAG type to be used as a btf_{key,value}_type_id even for the case like 'DECL_TAG -> STRUCT'. So there is no correctness issue here, we just want to silence warning. To silence the warning, I added DECL_TAG as one of kinds in btf_type_nosize() which will cause btf_type_id_size() returning NULL earlier without the warning. [1] https://lore.kernel.org/bpf/000000000000e0df8d05fc75ba86@google.com/ Reported-by: syzbot+958967f249155967d42a@syzkaller.appspotmail.com Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20230530205029.264910-1-yhs@fb.com Signed-off-by: Martin KaFai Lau --- kernel/bpf/btf.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 947f0b83bfad..bd2cac057928 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -492,25 +492,26 @@ static bool btf_type_is_fwd(const struct btf_type *t) return BTF_INFO_KIND(t->info) == BTF_KIND_FWD; } -static bool btf_type_nosize(const struct btf_type *t) +static bool btf_type_is_datasec(const struct btf_type *t) { - return btf_type_is_void(t) || btf_type_is_fwd(t) || - btf_type_is_func(t) || btf_type_is_func_proto(t); + return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC; } -static bool btf_type_nosize_or_null(const struct btf_type *t) +static bool btf_type_is_decl_tag(const struct btf_type *t) { - return !t || btf_type_nosize(t); + return BTF_INFO_KIND(t->info) == BTF_KIND_DECL_TAG; } -static bool btf_type_is_datasec(const struct btf_type *t) +static bool btf_type_nosize(const struct btf_type *t) { - return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC; + return btf_type_is_void(t) || btf_type_is_fwd(t) || + btf_type_is_func(t) || btf_type_is_func_proto(t) || + btf_type_is_decl_tag(t); } -static bool btf_type_is_decl_tag(const struct btf_type *t) +static bool btf_type_nosize_or_null(const struct btf_type *t) { - return BTF_INFO_KIND(t->info) == BTF_KIND_DECL_TAG; + return !t || btf_type_nosize(t); } static bool btf_type_is_decl_tag_target(const struct btf_type *t) -- cgit v1.2.3 From e38096d95f4d7e8cc15280b4a3515eee31925561 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 30 May 2023 13:50:34 -0700 Subject: selftests/bpf: Add a test where map key_type_id with decl_tag type Add two selftests where map creation key/value type_id's are decl_tags. Without previous patch, kernel warnings will appear similar to the one in the previous patch. With the previous patch, both kernel warnings are silenced. Signed-off-by: Yonghong Song Link: https://lore.kernel.org/r/20230530205034.266643-1-yhs@fb.com Signed-off-by: Martin KaFai Lau --- tools/testing/selftests/bpf/prog_tests/btf.c | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c index 210d643fda6c..4e0cdb593318 100644 --- a/tools/testing/selftests/bpf/prog_tests/btf.c +++ b/tools/testing/selftests/bpf/prog_tests/btf.c @@ -3990,6 +3990,46 @@ static struct btf_raw_test raw_tests[] = { .btf_load_err = true, .err_str = "Invalid arg#1", }, +{ + .descr = "decl_tag test #18, decl_tag as the map key type", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_STRUCT_ENC(0, 2, 8), /* [2] */ + BTF_MEMBER_ENC(NAME_TBD, 1, 0), + BTF_MEMBER_ENC(NAME_TBD, 1, 32), + BTF_DECL_TAG_ENC(NAME_TBD, 2, -1), /* [3] */ + BTF_END_RAW, + }, + BTF_STR_SEC("\0m1\0m2\0tag"), + .map_type = BPF_MAP_TYPE_HASH, + .map_name = "tag_type_check_btf", + .key_size = 8, + .value_size = 4, + .key_type_id = 3, + .value_type_id = 1, + .max_entries = 1, + .map_create_err = true, +}, +{ + .descr = "decl_tag test #19, decl_tag as the map value type", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_STRUCT_ENC(0, 2, 8), /* [2] */ + BTF_MEMBER_ENC(NAME_TBD, 1, 0), + BTF_MEMBER_ENC(NAME_TBD, 1, 32), + BTF_DECL_TAG_ENC(NAME_TBD, 2, -1), /* [3] */ + BTF_END_RAW, + }, + BTF_STR_SEC("\0m1\0m2\0tag"), + .map_type = BPF_MAP_TYPE_HASH, + .map_name = "tag_type_check_btf", + .key_size = 4, + .value_size = 8, + .key_type_id = 1, + .value_type_id = 3, + .max_entries = 1, + .map_create_err = true, +}, { .descr = "type_tag test #1", .raw_types = { -- cgit v1.2.3 From 7b4858df3bf7a8d43ed6b58f411543a040c56f10 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:28 +0300 Subject: skbuff: bridge: Add layer 2 miss indication For EVPN non-DF (Designated Forwarder) filtering we need to be able to prevent decapsulated traffic from being flooded to a multi-homed host. Filtering of multicast and broadcast traffic can be achieved using the following flower filter: # tc filter add dev bond0 egress pref 1 proto all flower indev vxlan0 dst_mac 01:00:00:00:00:00/01:00:00:00:00:00 action drop Unlike broadcast and multicast traffic, it is not currently possible to filter unknown unicast traffic. The classification into unknown unicast is performed by the bridge driver, but is not visible to other layers such as tc. Solve this by adding a new 'l2_miss' bit to the tc skb extension. Clear the bit whenever a packet enters the bridge (received from a bridge port or transmitted via the bridge) and set it if the packet did not match an FDB or MDB entry. If there is no skb extension and the bit needs to be cleared, then do not allocate one as no extension is equivalent to the bit being cleared. The bit is not set for broadcast packets as they never perform a lookup and therefore never incur a miss. A bit that is set for every flooded packet would also work for the current use case, but it does not allow us to differentiate between registered and unregistered multicast traffic, which might be useful in the future. To keep the performance impact to a minimum, the marking of packets is guarded by the 'tc_skb_ext_tc' static key. When 'false', the skb is not touched and an skb extension is not allocated. Instead, only a 5 bytes nop is executed, as demonstrated below for the call site in br_handle_frame(). Before the patch: ``` memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); c37b09: 49 c7 44 24 28 00 00 movq $0x0,0x28(%r12) c37b10: 00 00 p = br_port_get_rcu(skb->dev); c37b12: 49 8b 44 24 10 mov 0x10(%r12),%rax memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); c37b17: 49 c7 44 24 30 00 00 movq $0x0,0x30(%r12) c37b1e: 00 00 c37b20: 49 c7 44 24 38 00 00 movq $0x0,0x38(%r12) c37b27: 00 00 ``` After the patch (when static key is disabled): ``` memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); c37c29: 49 c7 44 24 28 00 00 movq $0x0,0x28(%r12) c37c30: 00 00 c37c32: 49 8d 44 24 28 lea 0x28(%r12),%rax c37c37: 48 c7 40 08 00 00 00 movq $0x0,0x8(%rax) c37c3e: 00 c37c3f: 48 c7 40 10 00 00 00 movq $0x0,0x10(%rax) c37c46: 00 #ifdef CONFIG_HAVE_JUMP_LABEL_HACK static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { asm_volatile_goto("1:" c37c47: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) br_tc_skb_miss_set(skb, false); p = br_port_get_rcu(skb->dev); c37c4c: 49 8b 44 24 10 mov 0x10(%r12),%rax ``` Subsequent patches will extend the flower classifier to be able to match on the new 'l2_miss' bit and enable / disable the static key when filters that match on it are added / deleted. Signed-off-by: Ido Schimmel Acked-by: Nikolay Aleksandrov Acked-by: Jakub Kicinski Signed-off-by: Jakub Kicinski --- include/linux/skbuff.h | 1 + net/bridge/br_device.c | 1 + net/bridge/br_forward.c | 3 +++ net/bridge/br_input.c | 1 + net/bridge/br_private.h | 27 +++++++++++++++++++++++++++ 5 files changed, 33 insertions(+) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 5951904413ab..e2f48ddb2f7c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -330,6 +330,7 @@ struct tc_skb_ext { u8 post_ct_snat:1; u8 post_ct_dnat:1; u8 act_miss:1; /* Set if act_miss_cookie is used */ + u8 l2_miss:1; /* Set by bridge upon FDB or MDB miss */ }; #endif diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 8eca8a5c80c6..9a5ea06236bd 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -39,6 +39,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) u16 vid = 0; memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); + br_tc_skb_miss_set(skb, false); rcu_read_lock(); nf_ops = rcu_dereference(nf_br_ops); diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 84d6dd5e5b1a..6116eba1bd89 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -203,6 +203,8 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb, struct net_bridge_port *prev = NULL; struct net_bridge_port *p; + br_tc_skb_miss_set(skb, pkt_type != BR_PKT_BROADCAST); + list_for_each_entry_rcu(p, &br->port_list, list) { /* Do not flood unicast traffic to ports that turn it off, nor * other traffic if flood off, except for traffic we originate @@ -295,6 +297,7 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst, allow_mode_include = false; } else { p = NULL; + br_tc_skb_miss_set(skb, true); } while (p || rp) { diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index fc17b9fd93e6..c34a0b0901b0 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -334,6 +334,7 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb) return RX_HANDLER_CONSUMED; memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); + br_tc_skb_miss_set(skb, false); p = br_port_get_rcu(skb->dev); if (p->flags & BR_VLAN_TUNNEL) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2119729ded2b..a63b32c1638e 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -754,6 +755,32 @@ void br_boolopt_multi_get(const struct net_bridge *br, struct br_boolopt_multi *bm); void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on); +#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT) +static inline void br_tc_skb_miss_set(struct sk_buff *skb, bool miss) +{ + struct tc_skb_ext *ext; + + if (!tc_skb_ext_tc_enabled()) + return; + + ext = skb_ext_find(skb, TC_SKB_EXT); + if (ext) { + ext->l2_miss = miss; + return; + } + if (!miss) + return; + ext = tc_skb_ext_alloc(skb); + if (!ext) + return; + ext->l2_miss = true; +} +#else +static inline void br_tc_skb_miss_set(struct sk_buff *skb, bool miss) +{ +} +#endif + /* br_device.c */ void br_dev_setup(struct net_device *dev); void br_dev_delete(struct net_device *dev, struct list_head *list); -- cgit v1.2.3 From d5ccfd90df7fd0a50038a68634c131b8fd081bac Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:29 +0300 Subject: flow_dissector: Dissect layer 2 miss from tc skb extension Extend the 'FLOW_DISSECTOR_KEY_META' key with a new 'l2_miss' field and populate it from a field with the same name in the tc skb extension. This field is set by the bridge driver for packets that incur an FDB or MDB miss. The next patch will extend the flower classifier to be able to match on layer 2 misses. Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jakub Kicinski --- include/net/flow_dissector.h | 2 ++ net/core/flow_dissector.c | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 85b2281576ed..8b41668c77fc 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -243,10 +243,12 @@ struct flow_dissector_key_ip { * struct flow_dissector_key_meta: * @ingress_ifindex: ingress ifindex * @ingress_iftype: ingress interface type + * @l2_miss: packet did not match an L2 entry during forwarding */ struct flow_dissector_key_meta { int ingress_ifindex; u16 ingress_iftype; + u8 l2_miss; }; /** diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 25fb0bbc310f..481ca4080cbd 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -241,6 +242,15 @@ void skb_flow_dissect_meta(const struct sk_buff *skb, FLOW_DISSECTOR_KEY_META, target_container); meta->ingress_ifindex = skb->skb_iif; +#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT) + if (tc_skb_ext_tc_enabled()) { + struct tc_skb_ext *ext; + + ext = skb_ext_find(skb, TC_SKB_EXT); + if (ext) + meta->l2_miss = ext->l2_miss; + } +#endif } EXPORT_SYMBOL(skb_flow_dissect_meta); -- cgit v1.2.3 From 1a432018c0cdf51a77a2e134b19ba6cab4c29c89 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:30 +0300 Subject: net/sched: flower: Allow matching on layer 2 miss Add the 'TCA_FLOWER_L2_MISS' netlink attribute that allows user space to match on packets that encountered a layer 2 miss. The miss indication is set as metadata in the tc skb extension by the bridge driver upon FDB or MDB lookup miss and dissected by the flow dissector to the 'FLOW_DISSECTOR_KEY_META' key. The use of this skb extension is guarded by the 'tc_skb_ext_tc' static key. As such, enable / disable this key when filters that match on layer 2 miss are added / deleted. Tested: # cat tc_skb_ext_tc.py #!/usr/bin/env -S drgn -s vmlinux refcount = prog["tc_skb_ext_tc"].key.enabled.counter.value_() print(f"tc_skb_ext_tc reference count is {refcount}") # ./tc_skb_ext_tc.py tc_skb_ext_tc reference count is 0 # tc filter add dev swp1 egress proto all handle 101 pref 1 flower src_mac 00:11:22:33:44:55 action drop # tc filter add dev swp1 egress proto all handle 102 pref 2 flower src_mac 00:11:22:33:44:55 l2_miss true action drop # tc filter add dev swp1 egress proto all handle 103 pref 3 flower src_mac 00:11:22:33:44:55 l2_miss false action drop # ./tc_skb_ext_tc.py tc_skb_ext_tc reference count is 2 # tc filter replace dev swp1 egress proto all handle 102 pref 2 flower src_mac 00:01:02:03:04:05 l2_miss false action drop # ./tc_skb_ext_tc.py tc_skb_ext_tc reference count is 2 # tc filter del dev swp1 egress proto all handle 103 pref 3 flower # tc filter del dev swp1 egress proto all handle 102 pref 2 flower # tc filter del dev swp1 egress proto all handle 101 pref 1 flower # ./tc_skb_ext_tc.py tc_skb_ext_tc reference count is 0 Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jakub Kicinski --- include/uapi/linux/pkt_cls.h | 2 ++ net/sched/cls_flower.c | 30 ++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 648a82f32666..00933dda7b10 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -594,6 +594,8 @@ enum { TCA_FLOWER_KEY_L2TPV3_SID, /* be32 */ + TCA_FLOWER_L2_MISS, /* u8 */ + __TCA_FLOWER_MAX, }; diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 9dbc43388e57..04adcde9eb81 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -120,6 +120,7 @@ struct cls_fl_filter { u32 handle; u32 flags; u32 in_hw_count; + u8 needs_tc_skb_ext:1; struct rcu_work rwork; struct net_device *hw_dev; /* Flower classifier is unlocked, which means that its reference counter @@ -415,6 +416,8 @@ static struct cls_fl_head *fl_head_dereference(struct tcf_proto *tp) static void __fl_destroy_filter(struct cls_fl_filter *f) { + if (f->needs_tc_skb_ext) + tc_skb_ext_tc_disable(); tcf_exts_destroy(&f->exts); tcf_exts_put_net(&f->exts); kfree(f); @@ -615,7 +618,8 @@ static void *fl_get(struct tcf_proto *tp, u32 handle) } static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { - [TCA_FLOWER_UNSPEC] = { .type = NLA_UNSPEC }, + [TCA_FLOWER_UNSPEC] = { .strict_start_type = + TCA_FLOWER_L2_MISS }, [TCA_FLOWER_CLASSID] = { .type = NLA_U32 }, [TCA_FLOWER_INDEV] = { .type = NLA_STRING, .len = IFNAMSIZ }, @@ -720,7 +724,7 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { [TCA_FLOWER_KEY_PPPOE_SID] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_PPP_PROTO] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_L2TPV3_SID] = { .type = NLA_U32 }, - + [TCA_FLOWER_L2_MISS] = NLA_POLICY_MAX(NLA_U8, 1), }; static const struct nla_policy @@ -1668,6 +1672,10 @@ static int fl_set_key(struct net *net, struct nlattr **tb, mask->meta.ingress_ifindex = 0xffffffff; } + fl_set_key_val(tb, &key->meta.l2_miss, TCA_FLOWER_L2_MISS, + &mask->meta.l2_miss, TCA_FLOWER_UNSPEC, + sizeof(key->meta.l2_miss)); + fl_set_key_val(tb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, sizeof(key->eth.dst)); @@ -2085,6 +2093,11 @@ errout_cleanup: return ret; } +static bool fl_needs_tc_skb_ext(const struct fl_flow_key *mask) +{ + return mask->meta.l2_miss; +} + static int fl_set_parms(struct net *net, struct tcf_proto *tp, struct cls_fl_filter *f, struct fl_flow_mask *mask, unsigned long base, struct nlattr **tb, @@ -2121,6 +2134,14 @@ static int fl_set_parms(struct net *net, struct tcf_proto *tp, return -EINVAL; } + /* Enable tc skb extension if filter matches on data extracted from + * this extension. + */ + if (fl_needs_tc_skb_ext(&mask->key)) { + f->needs_tc_skb_ext = 1; + tc_skb_ext_tc_enable(); + } + return 0; } @@ -3074,6 +3095,11 @@ static int fl_dump_key(struct sk_buff *skb, struct net *net, goto nla_put_failure; } + if (fl_dump_key_val(skb, &key->meta.l2_miss, + TCA_FLOWER_L2_MISS, &mask->meta.l2_miss, + TCA_FLOWER_UNSPEC, sizeof(key->meta.l2_miss))) + goto nla_put_failure; + if (fl_dump_key_val(skb, key->eth.dst, TCA_FLOWER_KEY_ETH_DST, mask->eth.dst, TCA_FLOWER_KEY_ETH_DST_MASK, sizeof(key->eth.dst)) || -- cgit v1.2.3 From f4356947f0297b0962fdd197672db7edf9f58be6 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:31 +0300 Subject: flow_offload: Reject matching on layer 2 miss Adjust drivers that support the 'FLOW_DISSECTOR_KEY_META' key to reject filters that try to match on the newly added layer 2 miss field. Add an extack message to clearly communicate the failure reason to user space. The following users were not patched: 1. mtk_flow_offload_replace(): Only checks that the key is present, but does not do anything with it. 2. mlx5_tc_ct_set_tuple_match(): Used as part of netfilter offload, which does not make use of the new field, unlike tc. 3. get_netdev_from_rule() in nfp: Likewise. Example: # tc filter add dev swp1 egress pref 1 proto all flower skip_sw l2_miss true action drop Error: mlxsw_spectrum: Can't match on "l2_miss". We have an error talking to the kernel Acked-by: Elad Nachman Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/prestera/prestera_flower.c | 6 ++++++ drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 6 ++++++ drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c | 6 ++++++ drivers/net/ethernet/mscc/ocelot_flower.c | 10 ++++++++++ 4 files changed, 28 insertions(+) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_flower.c b/drivers/net/ethernet/marvell/prestera/prestera_flower.c index 91a478b75cbf..3e20e71b0f81 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_flower.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_flower.c @@ -148,6 +148,12 @@ static int prestera_flower_parse_meta(struct prestera_acl_rule *rule, __be16 key, mask; flow_rule_match_meta(f_rule, &match); + + if (match.mask->l2_miss) { + NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on \"l2_miss\""); + return -EOPNOTSUPP; + } + if (match.mask->ingress_ifindex != 0xFFFFFFFF) { NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported ingress ifindex mask"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index e95414ef1f04..1b0906cb57ef 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2587,6 +2587,12 @@ static int mlx5e_flower_parse_meta(struct net_device *filter_dev, return 0; flow_rule_match_meta(rule, &match); + + if (match.mask->l2_miss) { + NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on \"l2_miss\""); + return -EOPNOTSUPP; + } + if (!match.mask->ingress_ifindex) return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 594cdcb90b3d..6fec9223250b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -294,6 +294,12 @@ static int mlxsw_sp_flower_parse_meta(struct mlxsw_sp_acl_rule_info *rulei, return 0; flow_rule_match_meta(rule, &match); + + if (match.mask->l2_miss) { + NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on \"l2_miss\""); + return -EOPNOTSUPP; + } + if (match.mask->ingress_ifindex != 0xFFFFFFFF) { NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported ingress ifindex mask"); return -EINVAL; diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index ee052404eb55..e0916afcddfb 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -592,6 +592,16 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress, return -EOPNOTSUPP; } + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) { + struct flow_match_meta match; + + flow_rule_match_meta(rule, &match); + if (match.mask->l2_miss) { + NL_SET_ERR_MSG_MOD(extack, "Can't match on \"l2_miss\""); + return -EOPNOTSUPP; + } + } + /* For VCAP ES0 (egress rewriter) we can match on the ingress port */ if (!ingress) { ret = ocelot_flower_parse_indev(ocelot, port, f, filter); -- cgit v1.2.3 From d04e265096784b4cebeb627b21f0f27410d20dc4 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:32 +0300 Subject: mlxsw: spectrum_flower: Split iif parsing to a separate function Currently, mlxsw only supports the 'ingress_ifindex' field in the 'FLOW_DISSECTOR_KEY_META' key, but subsequent patches are going to add support for the 'l2_miss' field as well. Split the parsing of the 'ingress_ifindex' field to a separate function to avoid nesting. No functional changes intended. Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum_flower.c | 54 +++++++++++++--------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 6fec9223250b..2b0bae847eb9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -281,45 +281,35 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, return 0; } -static int mlxsw_sp_flower_parse_meta(struct mlxsw_sp_acl_rule_info *rulei, - struct flow_cls_offload *f, - struct mlxsw_sp_flow_block *block) +static int +mlxsw_sp_flower_parse_meta_iif(struct mlxsw_sp_acl_rule_info *rulei, + const struct mlxsw_sp_flow_block *block, + const struct flow_match_meta *match, + struct netlink_ext_ack *extack) { - struct flow_rule *rule = flow_cls_offload_flow_rule(f); struct mlxsw_sp_port *mlxsw_sp_port; struct net_device *ingress_dev; - struct flow_match_meta match; - - if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) - return 0; - - flow_rule_match_meta(rule, &match); - if (match.mask->l2_miss) { - NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on \"l2_miss\""); - return -EOPNOTSUPP; - } - - if (match.mask->ingress_ifindex != 0xFFFFFFFF) { - NL_SET_ERR_MSG_MOD(f->common.extack, "Unsupported ingress ifindex mask"); + if (match->mask->ingress_ifindex != 0xFFFFFFFF) { + NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask"); return -EINVAL; } ingress_dev = __dev_get_by_index(block->net, - match.key->ingress_ifindex); + match->key->ingress_ifindex); if (!ingress_dev) { - NL_SET_ERR_MSG_MOD(f->common.extack, "Can't find specified ingress port to match on"); + NL_SET_ERR_MSG_MOD(extack, "Can't find specified ingress port to match on"); return -EINVAL; } if (!mlxsw_sp_port_dev_check(ingress_dev)) { - NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on non-mlxsw ingress port"); + NL_SET_ERR_MSG_MOD(extack, "Can't match on non-mlxsw ingress port"); return -EINVAL; } mlxsw_sp_port = netdev_priv(ingress_dev); if (mlxsw_sp_port->mlxsw_sp != block->mlxsw_sp) { - NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on a port from different device"); + NL_SET_ERR_MSG_MOD(extack, "Can't match on a port from different device"); return -EINVAL; } @@ -327,9 +317,31 @@ static int mlxsw_sp_flower_parse_meta(struct mlxsw_sp_acl_rule_info *rulei, MLXSW_AFK_ELEMENT_SRC_SYS_PORT, mlxsw_sp_port->local_port, 0xFFFFFFFF); + return 0; } +static int mlxsw_sp_flower_parse_meta(struct mlxsw_sp_acl_rule_info *rulei, + struct flow_cls_offload *f, + struct mlxsw_sp_flow_block *block) +{ + struct flow_rule *rule = flow_cls_offload_flow_rule(f); + struct flow_match_meta match; + + if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) + return 0; + + flow_rule_match_meta(rule, &match); + + if (match.mask->l2_miss) { + NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on \"l2_miss\""); + return -EOPNOTSUPP; + } + + return mlxsw_sp_flower_parse_meta_iif(rulei, block, &match, + f->common.extack); +} + static void mlxsw_sp_flower_parse_ipv4(struct mlxsw_sp_acl_rule_info *rulei, struct flow_cls_offload *f) { -- cgit v1.2.3 From 0b9cd74b8d1e07111a048e8eeb15f54f2ed9cbe2 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:33 +0300 Subject: mlxsw: spectrum_flower: Do not force matching on iif Currently, mlxsw only supports the 'ingress_ifindex' field in the 'FLOW_DISSECTOR_KEY_META' key, but subsequent patches are going to add support for the 'l2_miss' field as well. It is valid to only match on 'l2_miss' without 'ingress_ifindex', so do not force matching on it. Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 2b0bae847eb9..9c62c12e410b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -290,6 +290,9 @@ mlxsw_sp_flower_parse_meta_iif(struct mlxsw_sp_acl_rule_info *rulei, struct mlxsw_sp_port *mlxsw_sp_port; struct net_device *ingress_dev; + if (!match->mask->ingress_ifindex) + return 0; + if (match->mask->ingress_ifindex != 0xFFFFFFFF) { NL_SET_ERR_MSG_MOD(extack, "Unsupported ingress ifindex mask"); return -EINVAL; -- cgit v1.2.3 From caa4c58ab5d9078097067cdd8a350ff6796df0ba Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:34 +0300 Subject: mlxsw: spectrum_flower: Add ability to match on layer 2 miss Add the 'fdb_miss' key element to supported key blocks and make use of it to match on layer 2 miss. The key is only supported on Spectrum-{2,3,4}. An error is returned for Spectrum-1 since the key element is not present in any of its key blocks. Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c | 1 + drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h | 3 ++- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c | 2 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c | 6 ++---- 4 files changed, 7 insertions(+), 5 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 bd1a51a0a540..f0b2963ebac3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c @@ -42,6 +42,7 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = { MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP_64_95, 0x34, 4), MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP_32_63, 0x38, 4), MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP_0_31, 0x3C, 4), + MLXSW_AFK_ELEMENT_INFO_U32(FDB_MISS, 0x40, 0, 1), }; 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 3a037fe47211..65a4abadc7db 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h @@ -35,6 +35,7 @@ enum mlxsw_afk_element { MLXSW_AFK_ELEMENT_IP_DSCP, MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB, MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB, + MLXSW_AFK_ELEMENT_FDB_MISS, MLXSW_AFK_ELEMENT_MAX, }; @@ -69,7 +70,7 @@ struct mlxsw_afk_element_info { MLXSW_AFK_ELEMENT_INFO(MLXSW_AFK_ELEMENT_TYPE_BUF, \ _element, _offset, 0, _size) -#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x40 +#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x44 struct mlxsw_afk_element_inst { /* element instance in actual block */ enum mlxsw_afk_element element; 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 00c32320f891..4dea39f2b304 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_keys.c @@ -123,10 +123,12 @@ const struct mlxsw_afk_ops mlxsw_sp1_afk_ops = { }; static 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[] = { + MLXSW_AFK_ELEMENT_INST_U32(FDB_MISS, 0x00, 3, 1), MLXSW_AFK_ELEMENT_INST_BUF(SMAC_0_31, 0x04, 4), }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 9c62c12e410b..72917f09e806 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -336,10 +336,8 @@ static int mlxsw_sp_flower_parse_meta(struct mlxsw_sp_acl_rule_info *rulei, flow_rule_match_meta(rule, &match); - if (match.mask->l2_miss) { - NL_SET_ERR_MSG_MOD(f->common.extack, "Can't match on \"l2_miss\""); - return -EOPNOTSUPP; - } + mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_FDB_MISS, + match.key->l2_miss, match.mask->l2_miss); return mlxsw_sp_flower_parse_meta_iif(rulei, block, &match, f->common.extack); -- cgit v1.2.3 From 8c33266ae26aa462409f8959624a95aea7831763 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Mon, 29 May 2023 14:48:35 +0300 Subject: selftests: forwarding: Add layer 2 miss test cases Add test cases to verify that the bridge driver correctly marks layer 2 misses only when it should and that the flower classifier can match on this metadata. Example output: # ./tc_flower_l2_miss.sh TEST: L2 miss - Unicast [ OK ] TEST: L2 miss - Multicast (IPv4) [ OK ] TEST: L2 miss - Multicast (IPv6) [ OK ] TEST: L2 miss - Link-local multicast (IPv4) [ OK ] TEST: L2 miss - Link-local multicast (IPv6) [ OK ] TEST: L2 miss - Broadcast [ OK ] Signed-off-by: Ido Schimmel Reviewed-by: Nikolay Aleksandrov Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/Makefile | 1 + .../selftests/net/forwarding/tc_flower_l2_miss.sh | 350 +++++++++++++++++++++ 2 files changed, 351 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile index a474c60fe348..9d0062b542e5 100644 --- a/tools/testing/selftests/net/forwarding/Makefile +++ b/tools/testing/selftests/net/forwarding/Makefile @@ -83,6 +83,7 @@ TEST_PROGS = bridge_igmp.sh \ tc_chains.sh \ tc_flower_router.sh \ tc_flower.sh \ + tc_flower_l2_miss.sh \ tc_mpls_l2vpn.sh \ tc_police.sh \ tc_shblocks.sh \ diff --git a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh new file mode 100755 index 000000000000..37b0369b5246 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh @@ -0,0 +1,350 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# +-----------------------+ +----------------------+ +# | H1 (vrf) | | H2 (vrf) | +# | + $h1 | | $h2 + | +# | | 192.0.2.1/28 | | 192.0.2.2/28 | | +# | | 2001:db8:1::1/64 | | 2001:db8:1::2/64 | | +# +----|------------------+ +------------------|---+ +# | | +# +----|-------------------------------------------------------------------|---+ +# | SW | | | +# | +-|-------------------------------------------------------------------|-+ | +# | | + $swp1 BR $swp2 + | | +# | +-----------------------------------------------------------------------+ | +# +----------------------------------------------------------------------------+ + +ALL_TESTS=" + test_l2_miss_unicast + test_l2_miss_multicast + test_l2_miss_ll_multicast + test_l2_miss_broadcast +" + +NUM_NETIFS=4 +source lib.sh +source tc_common.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/28 2001:db8:1::2/64 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.2/28 2001:db8:1::2/64 +} + +switch_create() +{ + ip link add name br1 up type bridge + ip link set dev $swp1 master br1 + ip link set dev $swp1 up + ip link set dev $swp2 master br1 + ip link set dev $swp2 up + + tc qdisc add dev $swp2 clsact +} + +switch_destroy() +{ + tc qdisc del dev $swp2 clsact + + ip link set dev $swp2 down + ip link set dev $swp2 nomaster + ip link set dev $swp1 down + ip link set dev $swp1 nomaster + ip link del dev br1 +} + +test_l2_miss_unicast() +{ + local dmac=00:01:02:03:04:05 + local dip=192.0.2.2 + local sip=192.0.2.1 + + RET=0 + + # Unknown unicast. + tc filter add dev $swp2 egress protocol ipv4 handle 101 pref 1 \ + flower indev $swp1 l2_miss true dst_mac $dmac src_ip $sip \ + dst_ip $dip action pass + # Known unicast. + tc filter add dev $swp2 egress protocol ipv4 handle 102 pref 1 \ + flower indev $swp1 l2_miss false dst_mac $dmac src_ip $sip \ + dst_ip $dip action pass + + # Before adding FDB entry. + $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Unknown unicast filter was not hit before adding FDB entry" + + tc_check_packets "dev $swp2 egress" 102 0 + check_err $? "Known unicast filter was hit before adding FDB entry" + + # Adding FDB entry. + bridge fdb replace $dmac dev $swp2 master static + + $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Unknown unicast filter was hit after adding FDB entry" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "Known unicast filter was not hit after adding FDB entry" + + # Deleting FDB entry. + bridge fdb del $dmac dev $swp2 master static + + $MZ $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 2 + check_err $? "Unknown unicast filter was not hit after deleting FDB entry" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "Known unicast filter was hit after deleting FDB entry" + + tc filter del dev $swp2 egress protocol ipv4 pref 1 handle 102 flower + tc filter del dev $swp2 egress protocol ipv4 pref 1 handle 101 flower + + log_test "L2 miss - Unicast" +} + +test_l2_miss_multicast_common() +{ + local proto=$1; shift + local sip=$1; shift + local dip=$1; shift + local mode=$1; shift + local name=$1; shift + + RET=0 + + # Unregistered multicast. + tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \ + flower indev $swp1 l2_miss true src_ip $sip dst_ip $dip \ + action pass + # Registered multicast. + tc filter add dev $swp2 egress protocol $proto handle 102 pref 1 \ + flower indev $swp1 l2_miss false src_ip $sip dst_ip $dip \ + action pass + + # Before adding MDB entry. + $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Unregistered multicast filter was not hit before adding MDB entry" + + tc_check_packets "dev $swp2 egress" 102 0 + check_err $? "Registered multicast filter was hit before adding MDB entry" + + # Adding MDB entry. + bridge mdb replace dev br1 port $swp2 grp $dip permanent + + $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Unregistered multicast filter was hit after adding MDB entry" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "Registered multicast filter was not hit after adding MDB entry" + + # Deleting MDB entry. + bridge mdb del dev br1 port $swp2 grp $dip + + $MZ $mode $h1 -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 2 + check_err $? "Unregistered multicast filter was not hit after deleting MDB entry" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "Registered multicast filter was hit after deleting MDB entry" + + tc filter del dev $swp2 egress protocol $proto pref 1 handle 102 flower + tc filter del dev $swp2 egress protocol $proto pref 1 handle 101 flower + + log_test "L2 miss - Multicast ($name)" +} + +test_l2_miss_multicast_ipv4() +{ + local proto="ipv4" + local sip=192.0.2.1 + local dip=239.1.1.1 + local mode="-4" + local name="IPv4" + + test_l2_miss_multicast_common $proto $sip $dip $mode $name +} + +test_l2_miss_multicast_ipv6() +{ + local proto="ipv6" + local sip=2001:db8:1::1 + local dip=ff0e::1 + local mode="-6" + local name="IPv6" + + test_l2_miss_multicast_common $proto $sip $dip $mode $name +} + +test_l2_miss_multicast() +{ + # Configure $swp2 as a multicast router port so that it will forward + # both registered and unregistered multicast traffic. + bridge link set dev $swp2 mcast_router 2 + + # Forwarding according to MDB entries only takes place when the bridge + # detects that there is a valid querier in the network. Set the bridge + # as the querier and assign it a valid IPv6 link-local address to be + # used as the source address for MLD queries. + ip link set dev br1 type bridge mcast_querier 1 + ip -6 address add fe80::1/64 nodad dev br1 + # Wait the default Query Response Interval (10 seconds) for the bridge + # to determine that there are no other queriers in the network. + sleep 10 + + test_l2_miss_multicast_ipv4 + test_l2_miss_multicast_ipv6 + + ip -6 address del fe80::1/64 dev br1 + ip link set dev br1 type bridge mcast_querier 0 + bridge link set dev $swp2 mcast_router 1 +} + +test_l2_miss_multicast_common2() +{ + local name=$1; shift + local dmac=$1; shift + local dip=224.0.0.1 + local sip=192.0.2.1 + +} + +test_l2_miss_ll_multicast_common() +{ + local proto=$1; shift + local dmac=$1; shift + local sip=$1; shift + local dip=$1; shift + local mode=$1; shift + local name=$1; shift + + RET=0 + + tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \ + flower indev $swp1 l2_miss true dst_mac $dmac src_ip $sip \ + dst_ip $dip action pass + + $MZ $mode $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 1 + check_err $? "Filter was not hit" + + tc filter del dev $swp2 egress protocol $proto pref 1 handle 101 flower + + log_test "L2 miss - Link-local multicast ($name)" +} + +test_l2_miss_ll_multicast_ipv4() +{ + local proto=ipv4 + local dmac=01:00:5e:00:00:01 + local sip=192.0.2.1 + local dip=224.0.0.1 + local mode="-4" + local name="IPv4" + + test_l2_miss_ll_multicast_common $proto $dmac $sip $dip $mode $name +} + +test_l2_miss_ll_multicast_ipv6() +{ + local proto=ipv6 + local dmac=33:33:00:00:00:01 + local sip=2001:db8:1::1 + local dip=ff02::1 + local mode="-6" + local name="IPv6" + + test_l2_miss_ll_multicast_common $proto $dmac $sip $dip $mode $name +} + +test_l2_miss_ll_multicast() +{ + test_l2_miss_ll_multicast_ipv4 + test_l2_miss_ll_multicast_ipv6 +} + +test_l2_miss_broadcast() +{ + local dmac=ff:ff:ff:ff:ff:ff + local smac=00:01:02:03:04:05 + + RET=0 + + tc filter add dev $swp2 egress protocol all handle 101 pref 1 \ + flower l2_miss true dst_mac $dmac src_mac $smac \ + action pass + tc filter add dev $swp2 egress protocol all handle 102 pref 1 \ + flower l2_miss false dst_mac $dmac src_mac $smac \ + action pass + + $MZ $h1 -a $smac -b $dmac -c 1 -p 100 -q + + tc_check_packets "dev $swp2 egress" 101 0 + check_err $? "L2 miss filter was hit when should not" + + tc_check_packets "dev $swp2 egress" 102 1 + check_err $? "L2 no miss filter was not hit when should" + + tc filter del dev $swp2 egress protocol all pref 1 handle 102 flower + tc filter del dev $swp2 egress protocol all pref 1 handle 101 flower + + log_test "L2 miss - Broadcast" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS -- cgit v1.2.3 From 9229a9483d80ba1cc7a75a552afff3e5afdf99e0 Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Mon, 29 May 2023 10:02:40 +0200 Subject: dt-bindings: net: dsa: marvell: add MV88E6361 switch to compatibility list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marvell MV88E6361 is an 8-port switch derived from the 88E6393X/88E9193X/88E6191X switches family. Since its functional behavior is very close to switches from this family, it can benefit from existing drivers for this family, so add it to the list of compatible switches Signed-off-by: Alexis Lothoré Reviewed-by: Andrew Lunn Acked-by: Conor Dooley Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/dsa/marvell.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/dsa/marvell.txt b/Documentation/devicetree/bindings/net/dsa/marvell.txt index 2363b412410c..33726134f5c9 100644 --- a/Documentation/devicetree/bindings/net/dsa/marvell.txt +++ b/Documentation/devicetree/bindings/net/dsa/marvell.txt @@ -20,7 +20,7 @@ which is at a different MDIO base address in different switch families. 6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321, 6341, 6350, 6351, 6352 - "marvell,mv88e6190" : Switch has base address 0x00. Use with models: - 6190, 6190X, 6191, 6290, 6390, 6390X + 6163, 6190, 6190X, 6191, 6290, 6390, 6390X - "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model: 6220, 6250 -- cgit v1.2.3 From ca345931907ff1893f02f5fe1349b16c9fc27e4c Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Mon, 29 May 2023 10:02:41 +0200 Subject: net: dsa: mv88e6xxx: pass directly chip structure to mv88e6xxx_phy_is_internal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since this function is a simple helper, we do not need to pass a full dsa_switch structure, we can directly pass the mv88e6xxx_chip structure. Doing so will allow to share this function with any other function not manipulating dsa_switch structure but needing info about number of internal phys Signed-off-by: Alexis Lothoré Reviewed-by: Russell King (Oracle) Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 5bbe95fa951c..e6f6c062cf77 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -463,10 +463,8 @@ restore_link: return err; } -static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) +static int mv88e6xxx_phy_is_internal(struct mv88e6xxx_chip *chip, int port) { - struct mv88e6xxx_chip *chip = ds->priv; - return port < chip->info->num_internal_phys; } @@ -584,7 +582,7 @@ static void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100; - if (mv88e6xxx_phy_is_internal(chip->ds, port)) { + if (mv88e6xxx_phy_is_internal(chip, port)) { __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces); } else { if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) && @@ -832,7 +830,7 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port, chip->info->ops->phylink_get_caps(chip, port, config); mv88e6xxx_reg_unlock(chip); - if (mv88e6xxx_phy_is_internal(ds, port)) { + if (mv88e6xxx_phy_is_internal(chip, port)) { __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); /* Internal ports with no phy-mode need GMII for PHYLIB */ @@ -872,7 +870,7 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, mv88e6xxx_reg_lock(chip); - if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(ds, port)) { + if (mode != MLO_AN_PHY || !mv88e6xxx_phy_is_internal(chip, port)) { err = mv88e6xxx_port_config_interface(chip, port, state->interface); if (err && err != -EOPNOTSUPP) -- cgit v1.2.3 From 7a2dd00be869f0bcdcb13f4272913ba7371ab583 Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Mon, 29 May 2023 10:02:42 +0200 Subject: net: dsa: mv88e6xxx: use mv88e6xxx_phy_is_internal in mv88e6xxx_port_ppu_updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure to use existing helper to get internal PHYs count instead of redoing it manually Signed-off-by: Alexis Lothoré Reviewed-by: Russell King (Oracle) Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index e6f6c062cf77..1b5a05f118b4 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -477,7 +477,7 @@ static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) * report whether the port is internal. */ if (chip->info->family == MV88E6XXX_FAMILY_6250) - return port < chip->info->num_internal_phys; + return mv88e6xxx_phy_is_internal(chip, port); err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); if (err) { -- cgit v1.2.3 From 3ba89b28adb21a5d5d78e905e2c3972816606bb4 Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Mon, 29 May 2023 10:02:43 +0200 Subject: net: dsa: mv88e6xxx: add field to specify internal phys layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mv88e6xxx currently assumes that switch equipped with internal phys have those phys mapped contiguously starting from port 0 (see mv88e6xxx_phy_is_internal). However, some switches have internal PHYs but NOT starting from port 0. For example 88e6393X, 88E6193X and 88E6191X have integrated PHYs available on ports 1 to 8 To properly support this offset, add a new field to allow specifying an internal PHYs layout. If field is not set, default layout is assumed (start at port 0) Signed-off-by: Alexis Lothoré Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 4 +++- drivers/net/dsa/mv88e6xxx/chip.h | 5 +++++ drivers/net/dsa/mv88e6xxx/global2.c | 5 ++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 1b5a05f118b4..c967259fcadd 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -465,7 +465,9 @@ restore_link: static int mv88e6xxx_phy_is_internal(struct mv88e6xxx_chip *chip, int port) { - return port < chip->info->num_internal_phys; + return port >= chip->info->internal_phys_offset && + port < chip->info->num_internal_phys + + chip->info->internal_phys_offset; } static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index da6e1339f809..eca51946c100 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -167,6 +167,11 @@ struct mv88e6xxx_info { /* Supports PTP */ bool ptp_support; + + /* Internal PHY start index. 0 means that internal PHYs range starts at + * port 0, 1 means internal PHYs range starts at port 1, etc + */ + unsigned int internal_phys_offset; }; struct mv88e6xxx_atu_entry { diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 615896893076..937a01f2ba75 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -1196,9 +1196,12 @@ out: int mv88e6xxx_g2_irq_mdio_setup(struct mv88e6xxx_chip *chip, struct mii_bus *bus) { + int phy_start = chip->info->internal_phys_offset; + int phy_end = chip->info->internal_phys_offset + + chip->info->num_internal_phys; int phy, irq; - for (phy = 0; phy < chip->info->num_internal_phys; phy++) { + for (phy = phy_start; phy < phy_end; phy++) { irq = irq_find_mapping(chip->g2_irq.domain, phy); if (irq < 0) return irq; -- cgit v1.2.3 From 2f93493970dfa46779f134f1fb2cd803b8c80ea4 Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Mon, 29 May 2023 10:02:44 +0200 Subject: net: dsa: mv88e6xxx: fix 88E6393X family internal phys layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 88E6393X/88E6193X/88E6191X switches have in fact 8 internal PHYs, but those are not present starting at port 0: supported ports go from 1 to 8 Signed-off-by: Alexis Lothoré Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index c967259fcadd..d3d861e55fe0 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -6047,7 +6047,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6191X", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ - .num_internal_phys = 9, + .num_internal_phys = 8, + .internal_phys_offset = 1, .max_vid = 8191, .max_sid = 63, .port_base_addr = 0x0, @@ -6070,7 +6071,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6193X", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ - .num_internal_phys = 9, + .num_internal_phys = 8, + .internal_phys_offset = 1, .max_vid = 8191, .max_sid = 63, .port_base_addr = 0x0, @@ -6389,7 +6391,8 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .name = "Marvell 88E6393X", .num_databases = 4096, .num_ports = 11, /* 10 + Z80 */ - .num_internal_phys = 9, + .num_internal_phys = 8, + .internal_phys_offset = 1, .max_vid = 8191, .max_sid = 63, .port_base_addr = 0x0, -- cgit v1.2.3 From 18e1b7422dffe4c0f897fa63eb074f79d1d9d0a0 Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Mon, 29 May 2023 10:02:45 +0200 Subject: net: dsa: mv88e6xxx: pass mv88e6xxx_chip structure to port_max_speed_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some switches families have minor differences on supported link speed for ports. Instead of redefining a new port_max_speed_mode for each different configuration, allow to pass mv88e6xxx_chip structure to allow differentiating those chips by known chip id Signed-off-by: Alexis Lothoré Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- drivers/net/dsa/mv88e6xxx/chip.h | 3 ++- drivers/net/dsa/mv88e6xxx/port.c | 12 ++++++++---- drivers/net/dsa/mv88e6xxx/port.h | 12 ++++++++---- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d3d861e55fe0..a2b5cac39507 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -3334,7 +3334,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) caps = pl_config.mac_capabilities; if (chip->info->ops->port_max_speed_mode) - mode = chip->info->ops->port_max_speed_mode(port); + mode = chip->info->ops->port_max_speed_mode(chip, port); else mode = PHY_INTERFACE_MODE_NA; diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index eca51946c100..dd7c8880e987 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -518,7 +518,8 @@ struct mv88e6xxx_ops { int speed, int duplex); /* What interface mode should be used for maximum speed? */ - phy_interface_t (*port_max_speed_mode)(int port); + phy_interface_t (*port_max_speed_mode)(struct mv88e6xxx_chip *chip, + int port); int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port); diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index f79cf716c541..66f1b40b4e96 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -342,7 +342,8 @@ int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, duplex); } -phy_interface_t mv88e6341_port_max_speed_mode(int port) +phy_interface_t mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip *chip, + int port) { if (port == 5) return PHY_INTERFACE_MODE_2500BASEX; @@ -381,7 +382,8 @@ int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, duplex); } -phy_interface_t mv88e6390_port_max_speed_mode(int port) +phy_interface_t mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip *chip, + int port) { if (port == 9 || port == 10) return PHY_INTERFACE_MODE_2500BASEX; @@ -403,7 +405,8 @@ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, duplex); } -phy_interface_t mv88e6390x_port_max_speed_mode(int port) +phy_interface_t mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip *chip, + int port) { if (port == 9 || port == 10) return PHY_INTERFACE_MODE_XAUI; @@ -500,7 +503,8 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, return 0; } -phy_interface_t mv88e6393x_port_max_speed_mode(int port) +phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip, + int port) { if (port == 0 || port == 9 || port == 10) return PHY_INTERFACE_MODE_10GBASER; diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index d19b6303b91f..8331b9a89a15 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -359,10 +359,14 @@ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, int speed, int duplex); -phy_interface_t mv88e6341_port_max_speed_mode(int port); -phy_interface_t mv88e6390_port_max_speed_mode(int port); -phy_interface_t mv88e6390x_port_max_speed_mode(int port); -phy_interface_t mv88e6393x_port_max_speed_mode(int port); +phy_interface_t mv88e6341_port_max_speed_mode(struct mv88e6xxx_chip *chip, + int port); +phy_interface_t mv88e6390_port_max_speed_mode(struct mv88e6xxx_chip *chip, + int port); +phy_interface_t mv88e6390x_port_max_speed_mode(struct mv88e6xxx_chip *chip, + int port); +phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip, + int port); int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state); -- cgit v1.2.3 From 12899f299803d293d8e4d46d67cf2cc1380b9faa Mon Sep 17 00:00:00 2001 From: Alexis Lothoré Date: Mon, 29 May 2023 10:02:46 +0200 Subject: net: dsa: mv88e6xxx: enable support for 88E6361 switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marvell 88E6361 is an 8-port switch derived from the 88E6393X/88E9193X/88E6191X switches family. It can benefit from the existing mv88e6xxx driver by simply adding the proper switch description in the driver. Main differences with other switches from this family are: - 8 ports exposed (instead of 11): ports 1, 2 and 8 not available - No 5GBase-x nor SFI/USXGMII support Signed-off-by: Alexis Lothoré Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 42 +++++++++++++++++++++++++++++++++++----- drivers/net/dsa/mv88e6xxx/chip.h | 3 ++- drivers/net/dsa/mv88e6xxx/port.c | 14 +++++++++++--- drivers/net/dsa/mv88e6xxx/port.h | 1 + 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index a2b5cac39507..624b43dd079c 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -790,6 +790,8 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, unsigned long *supported = config->supported_interfaces; bool is_6191x = chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X; + bool is_6361 = + chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361; mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported); @@ -804,13 +806,17 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, /* 6191X supports >1G modes only on port 10 */ if (!is_6191x || port == 10) { __set_bit(PHY_INTERFACE_MODE_2500BASEX, supported); - __set_bit(PHY_INTERFACE_MODE_5GBASER, supported); - __set_bit(PHY_INTERFACE_MODE_10GBASER, supported); + config->mac_capabilities |= MAC_2500FD; + + /* 6361 only supports up to 2500BaseX */ + if (!is_6361) { + __set_bit(PHY_INTERFACE_MODE_5GBASER, supported); + __set_bit(PHY_INTERFACE_MODE_10GBASER, supported); + config->mac_capabilities |= MAC_5000FD | + MAC_10000FD; + } /* FIXME: USXGMII is not supported yet */ /* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */ - - config->mac_capabilities |= MAC_2500FD | MAC_5000FD | - MAC_10000FD; } } @@ -6334,6 +6340,32 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .ptp_support = true, .ops = &mv88e6352_ops, }, + [MV88E6361] = { + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6361, + .family = MV88E6XXX_FAMILY_6393, + .name = "Marvell 88E6361", + .num_databases = 4096, + .num_macs = 16384, + .num_ports = 11, + /* Ports 1, 2 and 8 are not routed */ + .invalid_port_mask = BIT(1) | BIT(2) | BIT(8), + .num_internal_phys = 5, + .internal_phys_offset = 3, + .max_vid = 4095, + .max_sid = 63, + .port_base_addr = 0x0, + .phy_base_addr = 0x0, + .global1_addr = 0x1b, + .global2_addr = 0x1c, + .age_time_coeff = 3750, + .g1_irqs = 10, + .g2_irqs = 14, + .atu_move_port_mask = 0x1f, + .pvt = true, + .multi_chip = true, + .ptp_support = true, + .ops = &mv88e6393x_ops, + }, [MV88E6390] = { .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390, .family = MV88E6XXX_FAMILY_6390, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index dd7c8880e987..79c06ba42c54 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -82,6 +82,7 @@ enum mv88e6xxx_model { MV88E6350, MV88E6351, MV88E6352, + MV88E6361, MV88E6390, MV88E6390X, MV88E6393X, @@ -100,7 +101,7 @@ enum mv88e6xxx_family { MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */ MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */ - MV88E6XXX_FAMILY_6393, /* 6191X 6193X 6393X */ + MV88E6XXX_FAMILY_6393, /* 6191X 6193X 6361 6393X */ }; /** diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 66f1b40b4e96..e9b4a6ea4d09 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -424,6 +424,10 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, u16 reg, ctrl; int err; + if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361 && + speed > 2500) + return -EOPNOTSUPP; + if (speed == 200 && port != 0) return -EOPNOTSUPP; @@ -506,10 +510,14 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, phy_interface_t mv88e6393x_port_max_speed_mode(struct mv88e6xxx_chip *chip, int port) { - if (port == 0 || port == 9 || port == 10) - return PHY_INTERFACE_MODE_10GBASER; - return PHY_INTERFACE_MODE_NA; + if (port != 0 && port != 9 && port != 10) + return PHY_INTERFACE_MODE_NA; + + if (chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6361) + return PHY_INTERFACE_MODE_2500BASEX; + + return PHY_INTERFACE_MODE_10GBASER; } static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 8331b9a89a15..ec9019004404 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -133,6 +133,7 @@ #define MV88E6XXX_PORT_SWITCH_ID_PROD_6220 0x2200 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6250 0x2500 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6361 0x2610 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6290 0x2900 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6321 0x3100 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6141 0x3400 -- cgit v1.2.3 From 6cd8ec58c1bf65adcdf346fe241ba69e0b56e6bd Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 29 May 2023 10:52:13 -0400 Subject: tipc: delete tipc_mtu_bad from tipc_udp_enable Since commit a4dfa72d0acd ("tipc: set default MTU for UDP media"), it's been no longer using dev->mtu for b->mtu, and the issue described in commit 3de81b758853 ("tipc: check minimum bearer MTU") doesn't exist in UDP bearer any more. Besides, dev->mtu can still be changed to a too small mtu after the UDP bearer is created even with tipc_mtu_bad() check in tipc_udp_enable(). Note that NETDEV_CHANGEMTU event processing in tipc_l2_device_event() doesn't really work for UDP bearer. So this patch deletes the unnecessary tipc_mtu_bad from tipc_udp_enable. Signed-off-by: Xin Long Reviewed-by: Tung Nguyen Link: https://lore.kernel.org/r/282f1f5cc40e6cad385aa1c60569e6c5b70e2fb3.1685371933.git.lucien.xin@gmail.com Signed-off-by: Jakub Kicinski --- net/tipc/bearer.c | 4 ++-- net/tipc/bearer.h | 4 ++-- net/tipc/udp_media.c | 4 ---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 53881406e200..114140c49108 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -431,7 +431,7 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b, dev = dev_get_by_name(net, dev_name); if (!dev) return -ENODEV; - if (tipc_mtu_bad(dev, 0)) { + if (tipc_mtu_bad(dev)) { dev_put(dev); return -EINVAL; } @@ -708,7 +708,7 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, test_and_set_bit_lock(0, &b->up); break; case NETDEV_CHANGEMTU: - if (tipc_mtu_bad(dev, 0)) { + if (tipc_mtu_bad(dev)) { bearer_disable(net, b); break; } diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index bd0cc5c287ef..1ee60649bd17 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -257,9 +257,9 @@ static inline void tipc_loopback_trace(struct net *net, } /* check if device MTU is too low for tipc headers */ -static inline bool tipc_mtu_bad(struct net_device *dev, unsigned int reserve) +static inline bool tipc_mtu_bad(struct net_device *dev) { - if (dev->mtu >= TIPC_MIN_BEARER_MTU + reserve) + if (dev->mtu >= TIPC_MIN_BEARER_MTU) return false; netdev_warn(dev, "MTU too low for tipc bearer\n"); return true; diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 0a85244fd618..926232557e77 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -739,10 +739,6 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, udp_conf.use_udp_checksums = false; ub->ifindex = dev->ifindex; b->encap_hlen = sizeof(struct iphdr) + sizeof(struct udphdr); - if (tipc_mtu_bad(dev, b->encap_hlen)) { - err = -EINVAL; - goto err; - } b->mtu = b->media->mtu; #if IS_ENABLED(CONFIG_IPV6) } else if (local.proto == htons(ETH_P_IPV6)) { -- cgit v1.2.3 From ed554d3f945179c5b159bddfad7be34b403fe11a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:31 +0200 Subject: leds: add APIs for LEDs hw control Add an option to permit LED driver to declare support for a specific trigger to use hw control and setup the LED to blink based on specific provided modes. Add APIs for LEDs hw control. These functions will be used to activate hardware control where a LED will use the provided flags, from an unique defined supported trigger, to setup the LED to be driven by hardware. Add hw_control_is_supported() to ask the LED driver if the requested mode by the trigger are supported and the LED can be setup to follow the requested modes. Deactivate hardware blink control by setting brightness to LED_OFF via the brightness_set() callback. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- include/linux/leds.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/include/linux/leds.h b/include/linux/leds.h index c39bbf17a25b..4caf559b1922 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -183,6 +183,43 @@ struct led_classdev { /* LEDs that have private triggers have this set */ struct led_hw_trigger_type *trigger_type; + + /* Unique trigger name supported by LED set in hw control mode */ + const char *hw_control_trigger; + /* + * Check if the LED driver supports the requested mode provided by the + * defined supported trigger to setup the LED to hw control mode. + * + * Return 0 on success. Return -EOPNOTSUPP when the passed flags are not + * supported and software fallback needs to be used. + * Return a negative error number on any other case for check fail due + * to various reason like device not ready or timeouts. + */ + int (*hw_control_is_supported)(struct led_classdev *led_cdev, + unsigned long flags); + /* + * Activate hardware control, LED driver will use the provided flags + * from the supported trigger and setup the LED to be driven by hardware + * following the requested mode from the trigger flags. + * Deactivate hardware blink control by setting brightness to LED_OFF via + * the brightness_set() callback. + * + * Return 0 on success, a negative error number on flags apply fail. + */ + int (*hw_control_set)(struct led_classdev *led_cdev, + unsigned long flags); + /* + * Get from the LED driver the current mode that the LED is set in hw + * control mode and put them in flags. + * Trigger can use this to get the initial state of a LED already set in + * hardware blink control. + * + * Return 0 on success, a negative error number on failing parsing the + * initial mode. Error from this function is NOT FATAL as the device + * may be in a not supported initial state by the attached LED trigger. + */ + int (*hw_control_get)(struct led_classdev *led_cdev, + unsigned long *flags); #endif #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED -- cgit v1.2.3 From 052c38eb17e866c5b4cd43924e7a5e20167b55c0 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 29 May 2023 18:32:32 +0200 Subject: leds: add API to get attached device for LED hw control Some specific LED triggers blink the LED based on events from a device or subsystem. For example, an LED could be blinked to indicate a network device is receiving packets, or a disk is reading blocks. To correctly enable and request the hw control of the LED, the trigger has to check if the network interface or block device configured via a /sys/class/led file match the one the LED driver provide for hw control for. Provide an API call to get the device which the LED blinks for. Signed-off-by: Andrew Lunn Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- include/linux/leds.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/leds.h b/include/linux/leds.h index 4caf559b1922..3268b4e789d6 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -220,6 +220,12 @@ struct led_classdev { */ int (*hw_control_get)(struct led_classdev *led_cdev, unsigned long *flags); + /* + * Get the device this LED blinks in response to. + * e.g. for a PHY LED, it is the network device. If the LED is + * not yet associated to a device, return NULL. + */ + struct device *(*hw_control_get_device)(struct led_classdev *led_cdev); #endif #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED -- cgit v1.2.3 From 8aa2fd7b66980ecd2e45e95af61cf7eafede1211 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:33 +0200 Subject: Documentation: leds: leds-class: Document new Hardware driven LEDs APIs Document new Hardware driven LEDs APIs. Some LEDs can be programmed to be driven by hardware. This is not limited to blink but also to turn off or on autonomously. To support this feature, a LED needs to implement various additional ops and needs to declare specific support for the supported triggers. Add documentation for each required value and API to make hw control possible and implementable by both LEDs and triggers. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- Documentation/leds/leds-class.rst | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/Documentation/leds/leds-class.rst b/Documentation/leds/leds-class.rst index cd155ead8703..5db620ed27aa 100644 --- a/Documentation/leds/leds-class.rst +++ b/Documentation/leds/leds-class.rst @@ -169,6 +169,87 @@ Setting the brightness to zero with brightness_set() callback function should completely turn off the LED and cancel the previously programmed hardware blinking function, if any. +Hardware driven LEDs +==================== + +Some LEDs can be programmed to be driven by hardware. This is not +limited to blink but also to turn off or on autonomously. +To support this feature, a LED needs to implement various additional +ops and needs to declare specific support for the supported triggers. + +With hw control we refer to the LED driven by hardware. + +LED driver must define the following value to support hw control: + + - hw_control_trigger: + unique trigger name supported by the LED in hw control + mode. + +LED driver must implement the following API to support hw control: + - hw_control_is_supported: + check if the flags passed by the supported trigger can + be parsed and activate hw control on the LED. + + Return 0 if the passed flags mask is supported and + can be set with hw_control_set(). + + If the passed flags mask is not supported -EOPNOTSUPP + must be returned, the LED trigger will use software + fallback in this case. + + Return a negative error in case of any other error like + device not ready or timeouts. + + - hw_control_set: + activate hw control. LED driver will use the provided + flags passed from the supported trigger, parse them to + a set of mode and setup the LED to be driven by hardware + following the requested modes. + + Set LED_OFF via the brightness_set to deactivate hw control. + + Return 0 on success, a negative error number on failing to + apply flags. + + - hw_control_get: + get active modes from a LED already in hw control, parse + them and set in flags the current active flags for the + supported trigger. + + Return 0 on success, a negative error number on failing + parsing the initial mode. + Error from this function is NOT FATAL as the device may + be in a not supported initial state by the attached LED + trigger. + + - hw_control_get_device: + return the device associated with the LED driver in + hw control. A trigger might use this to match the + returned device from this function with a configured + device for the trigger as the source for blinking + events and correctly enable hw control. + (example a netdev trigger configured to blink for a + particular dev match the returned dev from get_device + to set hw control) + + Returns a pointer to a struct device or NULL if nothing + is currently attached. + +LED driver can activate additional modes by default to workaround the +impossibility of supporting each different mode on the supported trigger. +Examples are hardcoding the blink speed to a set interval, enable special +feature like bypassing blink if some requirements are not met. + +A trigger should first check if the hw control API are supported by the LED +driver and check if the trigger is supported to verify if hw control is possible, +use hw_control_is_supported to check if the flags are supported and only at +the end use hw_control_set to activate hw control. + +A trigger can use hw_control_get to check if a LED is already in hw control +and init their flags. + +When the LED is in hw control, no software blink is possible and doing so +will effectively disable hw control. Known Issues ============ -- cgit v1.2.3 From 28a6a2ef18ad840a390d519840c303b03040961c Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 29 May 2023 18:32:34 +0200 Subject: leds: trigger: netdev: refactor code setting device name Move the code into a helper, ready for it to be called at other times. No intended behaviour change. Signed-off-by: Andrew Lunn Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 305eb543ba84..c93ac3bc85a6 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -104,15 +104,9 @@ static ssize_t device_name_show(struct device *dev, return len; } -static ssize_t device_name_store(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t size) +static int set_device_name(struct led_netdev_data *trigger_data, + const char *name, size_t size) { - struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); - - if (size >= IFNAMSIZ) - return -EINVAL; - cancel_delayed_work_sync(&trigger_data->work); mutex_lock(&trigger_data->lock); @@ -122,7 +116,7 @@ static ssize_t device_name_store(struct device *dev, trigger_data->net_dev = NULL; } - memcpy(trigger_data->device_name, buf, size); + memcpy(trigger_data->device_name, name, size); trigger_data->device_name[size] = 0; if (size > 0 && trigger_data->device_name[size - 1] == '\n') trigger_data->device_name[size - 1] = 0; @@ -140,6 +134,23 @@ static ssize_t device_name_store(struct device *dev, set_baseline_state(trigger_data); mutex_unlock(&trigger_data->lock); + return 0; +} + +static ssize_t device_name_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); + int ret; + + if (size >= IFNAMSIZ) + return -EINVAL; + + ret = set_device_name(trigger_data, buf, size); + + if (ret < 0) + return ret; return size; } -- cgit v1.2.3 From 4fd1b6d47a7a38e81fdc6f8be2ccd4216b3f93db Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:35 +0200 Subject: leds: trigger: netdev: introduce check for possible hw control Introduce function to check if the requested mode can use hw control in preparation for hw control support. Currently everything is handled in software so can_hw_control will always return false. Add knob with the new value hw_control in trigger_data struct to set hw control possible. Useful for future implementation to implement in set_baseline_state() the required function to set the requested mode using LEDs hw control ops and in other function to reject set if hw control is currently active. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index c93ac3bc85a6..e1f3cedd5d57 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -51,6 +51,7 @@ struct led_netdev_data { unsigned long mode; bool carrier_link_up; + bool hw_control; }; enum led_trigger_netdev_modes { @@ -91,6 +92,11 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) } } +static bool can_hw_control(struct led_netdev_data *trigger_data) +{ + return false; +} + static ssize_t device_name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -204,6 +210,8 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, else clear_bit(bit, &trigger_data->mode); + trigger_data->hw_control = can_hw_control(trigger_data); + set_baseline_state(trigger_data); return size; -- cgit v1.2.3 From 6352f25f9fadba59d5df2ba7139495759ccc81d5 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:36 +0200 Subject: leds: trigger: netdev: add basic check for hw control support Add basic check for hw control support. Check if the required API are defined and check if the defined trigger supported in hw control for the LED driver match netdev. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index e1f3cedd5d57..2101cbbda707 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -92,8 +92,22 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) } } +static bool supports_hw_control(struct led_classdev *led_cdev) +{ + if (!led_cdev->hw_control_get || !led_cdev->hw_control_set || + !led_cdev->hw_control_is_supported) + return false; + + return !strcmp(led_cdev->hw_control_trigger, led_cdev->trigger->name); +} + static bool can_hw_control(struct led_netdev_data *trigger_data) { + struct led_classdev *led_cdev = trigger_data->led_cdev; + + if (!supports_hw_control(led_cdev)) + return false; + return false; } -- cgit v1.2.3 From c84c80c7388f887b10dafd70fc55bc6c5fe9fa5a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:37 +0200 Subject: leds: trigger: netdev: reject interval store for hw_control Reject interval store with hw_control enabled. It's are currently not supported and MUST be set to the default value with hw control enabled. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 2101cbbda707..cb2ec33abc4e 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -265,6 +265,9 @@ static ssize_t interval_store(struct device *dev, unsigned long value; int ret; + if (trigger_data->hw_control) + return -EINVAL; + ret = kstrtoul(buf, 0, &value); if (ret) return ret; -- cgit v1.2.3 From 7c145a34ba6e380616af93262fcab9fc7261d851 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:38 +0200 Subject: leds: trigger: netdev: add support for LED hw control Add support for LED hw control for the netdev trigger. The trigger on calling set_baseline_state to configure a new mode, will do various check to verify if hw control can be used for the requested mode in can_hw_control() function. It will first check if the LED driver supports hw control for the netdev trigger, then will use hw_control_is_supported() and finally will call hw_control_set() to apply the requested mode. To use such mode, interval MUST be set to the default value and net_dev MUST be set. If one of these 2 value are not valid, hw control will never be used and normal software fallback is used. The default interval value is moved to a define to make sure they are always synced. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 43 +++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index cb2ec33abc4e..8f592a77cbef 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -24,6 +24,8 @@ #include #include "../leds.h" +#define NETDEV_LED_DEFAULT_INTERVAL 50 + /* * Configurable sysfs attributes: * @@ -68,6 +70,13 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) int current_brightness; struct led_classdev *led_cdev = trigger_data->led_cdev; + /* Already validated, hw control is possible with the requested mode */ + if (trigger_data->hw_control) { + led_cdev->hw_control_set(led_cdev, trigger_data->mode); + + return; + } + current_brightness = led_cdev->brightness; if (current_brightness) led_cdev->blink_brightness = current_brightness; @@ -103,12 +112,42 @@ static bool supports_hw_control(struct led_classdev *led_cdev) static bool can_hw_control(struct led_netdev_data *trigger_data) { + unsigned long default_interval = msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL); + unsigned int interval = atomic_read(&trigger_data->interval); struct led_classdev *led_cdev = trigger_data->led_cdev; + int ret; if (!supports_hw_control(led_cdev)) return false; - return false; + /* + * Interval must be set to the default + * value. Any different value is rejected if in hw + * control. + */ + if (interval != default_interval) + return false; + + /* + * net_dev must be set with hw control, otherwise no + * blinking can be happening and there is nothing to + * offloaded. + */ + if (!trigger_data->net_dev) + return false; + + /* Check if the requested mode is supported */ + ret = led_cdev->hw_control_is_supported(led_cdev, trigger_data->mode); + /* Fall back to software blinking if not supported */ + if (ret == -EOPNOTSUPP) + return false; + if (ret) { + dev_warn(led_cdev->dev, + "Current mode check failed with error %d\n", ret); + return false; + } + + return true; } static ssize_t device_name_show(struct device *dev, @@ -413,7 +452,7 @@ static int netdev_trig_activate(struct led_classdev *led_cdev) trigger_data->device_name[0] = 0; trigger_data->mode = 0; - atomic_set(&trigger_data->interval, msecs_to_jiffies(50)); + atomic_set(&trigger_data->interval, msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL)); trigger_data->last_activity = 0; led_set_trigger_data(led_cdev, trigger_data); -- cgit v1.2.3 From 33ec0b53befff2c0a7f3aa19ff08556d60585d6b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 29 May 2023 18:32:39 +0200 Subject: leds: trigger: netdev: validate configured netdev The netdev which the LED should blink for is configurable in /sys/class/led/foo/device_name. Ensure when offloading that the configured netdev is the same as the netdev the LED is associated with. If it is not, only perform software blinking. Signed-off-by: Andrew Lunn Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 8f592a77cbef..0f3c2ace408d 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -110,6 +110,24 @@ static bool supports_hw_control(struct led_classdev *led_cdev) return !strcmp(led_cdev->hw_control_trigger, led_cdev->trigger->name); } +/* + * Validate the configured netdev is the same as the one associated with + * the LED driver in hw control. + */ +static bool validate_net_dev(struct led_classdev *led_cdev, + struct net_device *net_dev) +{ + struct device *dev = led_cdev->hw_control_get_device(led_cdev); + struct net_device *ndev; + + if (!dev) + return false; + + ndev = to_net_dev(dev); + + return ndev == net_dev; +} + static bool can_hw_control(struct led_netdev_data *trigger_data) { unsigned long default_interval = msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL); @@ -131,9 +149,11 @@ static bool can_hw_control(struct led_netdev_data *trigger_data) /* * net_dev must be set with hw control, otherwise no * blinking can be happening and there is nothing to - * offloaded. + * offloaded. Additionally, for hw control to be + * valid, the configured netdev must be the same as + * netdev associated to the LED. */ - if (!trigger_data->net_dev) + if (!validate_net_dev(led_cdev, trigger_data->net_dev)) return false; /* Check if the requested mode is supported */ -- cgit v1.2.3 From 0316cc5629d15880dd3f097d221c55ca648bcd61 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:40 +0200 Subject: leds: trigger: netdev: init mode if hw control already active On netdev trigger activation, hw control may be already active by default. If this is the case and a device is actually provided by hw_control_get_device(), init the already active mode and set the bool to hw_control bool to true to reflect the already set mode in the trigger_data. Co-developed-by: Andrew Lunn Signed-off-by: Andrew Lunn Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 0f3c2ace408d..e8bb9d0f85c0 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -454,6 +454,8 @@ static void netdev_trig_work(struct work_struct *work) static int netdev_trig_activate(struct led_classdev *led_cdev) { struct led_netdev_data *trigger_data; + unsigned long mode; + struct device *dev; int rc; trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL); @@ -475,6 +477,21 @@ static int netdev_trig_activate(struct led_classdev *led_cdev) atomic_set(&trigger_data->interval, msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL)); trigger_data->last_activity = 0; + /* Check if hw control is active by default on the LED. + * Init already enabled mode in hw control. + */ + if (supports_hw_control(led_cdev) && + !led_cdev->hw_control_get(led_cdev, &mode)) { + dev = led_cdev->hw_control_get_device(led_cdev); + if (dev) { + const char *name = dev_name(dev); + + set_device_name(trigger_data, name, strlen(name)); + trigger_data->hw_control = true; + trigger_data->mode = mode; + } + } + led_set_trigger_data(led_cdev, trigger_data); rc = register_netdevice_notifier(&trigger_data->notifier); -- cgit v1.2.3 From 947acacab5ea151291b861cdfbde16ff5cf1b08c Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:41 +0200 Subject: leds: trigger: netdev: expose netdev trigger modes in linux include Expose netdev trigger modes to make them accessible by LED driver that will support netdev trigger for hw control. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 9 --------- include/linux/leds.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index e8bb9d0f85c0..b0a6f2749552 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -56,15 +56,6 @@ struct led_netdev_data { bool hw_control; }; -enum led_trigger_netdev_modes { - TRIGGER_NETDEV_LINK = 0, - TRIGGER_NETDEV_TX, - TRIGGER_NETDEV_RX, - - /* Keep last */ - __TRIGGER_NETDEV_MAX, -}; - static void set_baseline_state(struct led_netdev_data *trigger_data) { int current_brightness; diff --git a/include/linux/leds.h b/include/linux/leds.h index 3268b4e789d6..8af62ff431f0 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -552,6 +552,16 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) #endif /* CONFIG_LEDS_TRIGGERS */ +/* Trigger specific enum */ +enum led_trigger_netdev_modes { + TRIGGER_NETDEV_LINK = 0, + TRIGGER_NETDEV_TX, + TRIGGER_NETDEV_RX, + + /* Keep last */ + __TRIGGER_NETDEV_MAX, +}; + /* Trigger specific functions */ #ifdef CONFIG_LEDS_TRIGGER_DISK void ledtrig_disk_activity(bool write); -- cgit v1.2.3 From e0256648c831af13cbfe4a1787327fcec01c2807 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 29 May 2023 18:32:42 +0200 Subject: net: dsa: qca8k: implement hw_control ops Implement hw_control ops to drive Switch LEDs based on hardware events. Netdev trigger is the declared supported trigger for hw control operation and supports the following mode: - tx - rx When hw_control_set is called, LEDs are set to follow the requested mode. Each LEDs will blink at 4Hz by default. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/qca/qca8k-leds.c | 154 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c index b883692b7d86..1e0c61726487 100644 --- a/drivers/net/dsa/qca/qca8k-leds.c +++ b/drivers/net/dsa/qca/qca8k-leds.c @@ -31,6 +31,43 @@ qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en return 0; } +static int +qca8k_get_control_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info) +{ + reg_info->reg = QCA8K_LED_CTRL_REG(led_num); + + /* 6 total control rule: + * 3 control rules for phy0-3 that applies to all their leds + * 3 control rules for phy4 + */ + if (port_num == 4) + reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT; + else + reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT; + + return 0; +} + +static int +qca8k_parse_netdev(unsigned long rules, u32 *offload_trigger) +{ + /* Parsing specific to netdev trigger */ + if (test_bit(TRIGGER_NETDEV_TX, &rules)) + *offload_trigger |= QCA8K_LED_TX_BLINK_MASK; + if (test_bit(TRIGGER_NETDEV_RX, &rules)) + *offload_trigger |= QCA8K_LED_RX_BLINK_MASK; + + if (rules && !*offload_trigger) + return -EOPNOTSUPP; + + /* Enable some default rule by default to the requested mode: + * - Blink at 4Hz by default + */ + *offload_trigger |= QCA8K_LED_BLINK_4HZ; + + return 0; +} + static int qca8k_led_brightness_set(struct qca8k_led *led, enum led_brightness brightness) @@ -164,6 +201,119 @@ qca8k_cled_blink_set(struct led_classdev *ldev, return 0; } +static int +qca8k_cled_trigger_offload(struct led_classdev *ldev, bool enable) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 mask, val = QCA8K_LED_ALWAYS_OFF; + + qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info); + + if (enable) + val = QCA8K_LED_RULE_CONTROLLED; + + if (led->port_num == 0 || led->port_num == 4) { + mask = QCA8K_LED_PATTERN_EN_MASK; + val <<= QCA8K_LED_PATTERN_EN_SHIFT; + } else { + mask = QCA8K_LED_PHY123_PATTERN_EN_MASK; + } + + return regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift, + val << reg_info.shift); +} + +static bool +qca8k_cled_hw_control_status(struct led_classdev *ldev) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 val; + + qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info); + + regmap_read(priv->regmap, reg_info.reg, &val); + + val >>= reg_info.shift; + + if (led->port_num == 0 || led->port_num == 4) { + val &= QCA8K_LED_PATTERN_EN_MASK; + val >>= QCA8K_LED_PATTERN_EN_SHIFT; + } else { + val &= QCA8K_LED_PHY123_PATTERN_EN_MASK; + } + + return val == QCA8K_LED_RULE_CONTROLLED; +} + +static int +qca8k_cled_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules) +{ + u32 offload_trigger = 0; + + return qca8k_parse_netdev(rules, &offload_trigger); +} + +static int +qca8k_cled_hw_control_set(struct led_classdev *ldev, unsigned long rules) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 offload_trigger = 0; + int ret; + + ret = qca8k_parse_netdev(rules, &offload_trigger); + if (ret) + return ret; + + ret = qca8k_cled_trigger_offload(ldev, true); + if (ret) + return ret; + + qca8k_get_control_led_reg(led->port_num, led->led_num, ®_info); + + return regmap_update_bits(priv->regmap, reg_info.reg, + QCA8K_LED_RULE_MASK << reg_info.shift, + offload_trigger << reg_info.shift); +} + +static int +qca8k_cled_hw_control_get(struct led_classdev *ldev, unsigned long *rules) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + struct qca8k_led_pattern_en reg_info; + struct qca8k_priv *priv = led->priv; + u32 val; + int ret; + + /* With hw control not active return err */ + if (!qca8k_cled_hw_control_status(ldev)) + return -EINVAL; + + qca8k_get_control_led_reg(led->port_num, led->led_num, ®_info); + + ret = regmap_read(priv->regmap, reg_info.reg, &val); + if (ret) + return ret; + + val >>= reg_info.shift; + val &= QCA8K_LED_RULE_MASK; + + /* Parsing specific to netdev trigger */ + if (val & QCA8K_LED_TX_BLINK_MASK) + set_bit(TRIGGER_NETDEV_TX, rules); + if (val & QCA8K_LED_RX_BLINK_MASK) + set_bit(TRIGGER_NETDEV_RX, rules); + + return 0; +} + static int qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num) { @@ -224,6 +374,10 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p port_led->cdev.max_brightness = 1; port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking; port_led->cdev.blink_set = qca8k_cled_blink_set; + port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported; + port_led->cdev.hw_control_set = qca8k_cled_hw_control_set; + port_led->cdev.hw_control_get = qca8k_cled_hw_control_get; + port_led->cdev.hw_control_trigger = "netdev"; init_data.default_label = ":port"; init_data.fwnode = led; init_data.devname_mandatory = true; -- cgit v1.2.3 From 4f53c27f772e27e4cf4e5507d6f4d5980002cb6a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 29 May 2023 18:32:43 +0200 Subject: net: dsa: qca8k: add op to get ports netdev In order that the LED trigger can blink the switch MAC ports LED, it needs to know the netdev associated to the port. Add the callback to return the struct device of the netdev. Add an helper function qca8k_phy_to_port() to convert the phy back to dsa_port index, as we reference LED port based on the internal PHY index and needs to be converted back. Signed-off-by: Andrew Lunn Signed-off-by: Christian Marangi Signed-off-by: David S. Miller --- drivers/net/dsa/qca/qca8k-leds.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c index 1e0c61726487..6f02029b454b 100644 --- a/drivers/net/dsa/qca/qca8k-leds.c +++ b/drivers/net/dsa/qca/qca8k-leds.c @@ -5,6 +5,18 @@ #include "qca8k.h" #include "qca8k_leds.h" +static u32 qca8k_phy_to_port(int phy) +{ + /* Internal PHY 0 has port at index 1. + * Internal PHY 1 has port at index 2. + * Internal PHY 2 has port at index 3. + * Internal PHY 3 has port at index 4. + * Internal PHY 4 has port at index 5. + */ + + return phy + 1; +} + static int qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info) { @@ -314,6 +326,20 @@ qca8k_cled_hw_control_get(struct led_classdev *ldev, unsigned long *rules) return 0; } +static struct device *qca8k_cled_hw_control_get_device(struct led_classdev *ldev) +{ + struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev); + struct qca8k_priv *priv = led->priv; + struct dsa_port *dp; + + dp = dsa_to_port(priv->ds, qca8k_phy_to_port(led->port_num)); + if (!dp) + return NULL; + if (dp->slave) + return &dp->slave->dev; + return NULL; +} + static int qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num) { @@ -377,6 +403,7 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported; port_led->cdev.hw_control_set = qca8k_cled_hw_control_set; port_led->cdev.hw_control_get = qca8k_cled_hw_control_get; + port_led->cdev.hw_control_get_device = qca8k_cled_hw_control_get_device; port_led->cdev.hw_control_trigger = "netdev"; init_data.default_label = ":port"; init_data.fwnode = led; -- cgit v1.2.3 From b1f2abcf817d82b54764d1474424649feda6fe1b Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 29 May 2023 16:44:30 +0300 Subject: net: Make gro complete function to return void tcp_gro_complete() function only updates the skb fields related to GRO and it always returns zero. All the 3 drivers which are using it do not check for the return value either. Change it to return void instead which simplifies its callers as error handing becomes unnecessary. Signed-off-by: Parav Pandit Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_offload.c | 7 +++---- net/ipv6/tcpv6_offload.c | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 0b755988e20c..14fa716cac50 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -2041,7 +2041,7 @@ INDIRECT_CALLABLE_DECLARE(int tcp4_gro_complete(struct sk_buff *skb, int thoff)) INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)); INDIRECT_CALLABLE_DECLARE(int tcp6_gro_complete(struct sk_buff *skb, int thoff)); INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb)); -int tcp_gro_complete(struct sk_buff *skb); +void tcp_gro_complete(struct sk_buff *skb); void __tcp_v4_send_check(struct sk_buff *skb, __be32 saddr, __be32 daddr); diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 45dda7889387..88f9b0081ee7 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c @@ -296,7 +296,7 @@ out: return pp; } -int tcp_gro_complete(struct sk_buff *skb) +void tcp_gro_complete(struct sk_buff *skb) { struct tcphdr *th = tcp_hdr(skb); @@ -311,8 +311,6 @@ int tcp_gro_complete(struct sk_buff *skb) if (skb->encapsulation) skb->inner_transport_header = skb->transport_header; - - return 0; } EXPORT_SYMBOL(tcp_gro_complete); @@ -342,7 +340,8 @@ INDIRECT_CALLABLE_SCOPE int tcp4_gro_complete(struct sk_buff *skb, int thoff) if (NAPI_GRO_CB(skb)->is_atomic) skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_FIXEDID; - return tcp_gro_complete(skb); + tcp_gro_complete(skb); + return 0; } static const struct net_offload tcpv4_offload = { diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index 39db5a226855..bf0c957e4b5e 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c @@ -36,7 +36,8 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_complete(struct sk_buff *skb, int thoff) &iph->daddr, 0); skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6; - return tcp_gro_complete(skb); + tcp_gro_complete(skb); + return 0; } static struct sk_buff *tcp6_gso_segment(struct sk_buff *skb, -- cgit v1.2.3 From 3ea903e2a523e9655e425ba8eae13733e9e80ac9 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 30 May 2023 08:39:36 +0200 Subject: net: dsa: Switch i2c drivers back to use .probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit b8a1a4cd5a98 ("i2c: Provide a temporary .probe_new() call-back type"), all drivers being converted to .probe_new() and then 03c835f498b5 ("i2c: Switch .probe() to not take an id parameter") convert back to (the new) .probe() to be able to eventually drop .probe_new() from struct i2c_driver. Signed-off-by: Uwe Kleine-König Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/lan9303_i2c.c | 2 +- drivers/net/dsa/microchip/ksz9477_i2c.c | 2 +- drivers/net/dsa/xrs700x/xrs700x_i2c.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/dsa/lan9303_i2c.c b/drivers/net/dsa/lan9303_i2c.c index e8844820c3a9..bbbec322bc4f 100644 --- a/drivers/net/dsa/lan9303_i2c.c +++ b/drivers/net/dsa/lan9303_i2c.c @@ -105,7 +105,7 @@ static struct i2c_driver lan9303_i2c_driver = { .name = "LAN9303_I2C", .of_match_table = lan9303_i2c_of_match, }, - .probe_new = lan9303_i2c_probe, + .probe = lan9303_i2c_probe, .remove = lan9303_i2c_remove, .shutdown = lan9303_i2c_shutdown, .id_table = lan9303_i2c_id, diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index 497be833f707..2710afad4f3a 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -119,7 +119,7 @@ static struct i2c_driver ksz9477_i2c_driver = { .name = "ksz9477-switch", .of_match_table = ksz9477_dt_ids, }, - .probe_new = ksz9477_i2c_probe, + .probe = ksz9477_i2c_probe, .remove = ksz9477_i2c_remove, .shutdown = ksz9477_i2c_shutdown, .id_table = ksz9477_i2c_id, diff --git a/drivers/net/dsa/xrs700x/xrs700x_i2c.c b/drivers/net/dsa/xrs700x/xrs700x_i2c.c index 14ff6887a225..c1179d7311f7 100644 --- a/drivers/net/dsa/xrs700x/xrs700x_i2c.c +++ b/drivers/net/dsa/xrs700x/xrs700x_i2c.c @@ -147,7 +147,7 @@ static struct i2c_driver xrs700x_i2c_driver = { .name = "xrs700x-i2c", .of_match_table = of_match_ptr(xrs700x_i2c_dt_ids), }, - .probe_new = xrs700x_i2c_probe, + .probe = xrs700x_i2c_probe, .remove = xrs700x_i2c_remove, .shutdown = xrs700x_i2c_shutdown, .id_table = xrs700x_i2c_id, -- cgit v1.2.3 From dd4144e54e811729b2a1ff28e1dab380aad5293e Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 30 May 2023 10:39:14 +0200 Subject: net: dsa: Define .set_max_frame_size() callback for mv88e6250 SoC family Switches from mv88e6250 family (including mv88e6020 and mv88e6071) need the possibility to setup the maximal frame size, as they support frames up to 2048 bytes. Signed-off-by: Lukasz Majewski Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 624b43dd079c..4ee2d0657cb8 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -5072,6 +5072,7 @@ static const struct mv88e6xxx_ops mv88e6250_ops = { .avb_ops = &mv88e6352_avb_ops, .ptp_ops = &mv88e6250_ptp_ops, .phylink_get_caps = mv88e6250_phylink_get_caps, + .set_max_frame_size = mv88e6185_g1_set_max_frame_size, }; static const struct mv88e6xxx_ops mv88e6290_ops = { -- cgit v1.2.3 From 71d94a432a15eb710069f5111a1b4459d7e7cd87 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 30 May 2023 10:39:15 +0200 Subject: net: dsa: mv88e6xxx: add support for MV88E6020 switch A mv88e6250 family switch with 2 PHY and RMII ports and no PTP support. Signed-off-by: Matthias Schiffer Signed-off-by: Lukasz Majewski Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 20 ++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 3 ++- drivers/net/dsa/mv88e6xxx/port.h | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 4ee2d0657cb8..d107c582fa93 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -5672,6 +5672,26 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = { }; static const struct mv88e6xxx_info mv88e6xxx_table[] = { + [MV88E6020] = { + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6020, + .family = MV88E6XXX_FAMILY_6250, + .name = "Marvell 88E6020", + .num_databases = 64, + .num_ports = 4, + .num_internal_phys = 2, + .max_vid = 4095, + .port_base_addr = 0x8, + .phy_base_addr = 0x0, + .global1_addr = 0xf, + .global2_addr = 0x7, + .age_time_coeff = 15000, + .g1_irqs = 9, + .g2_irqs = 5, + .atu_move_port_mask = 0xf, + .dual_chip = true, + .ops = &mv88e6250_ops, + }, + [MV88E6085] = { .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, .family = MV88E6XXX_FAMILY_6097, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 79c06ba42c54..1bd7aa591c94 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -54,6 +54,7 @@ enum mv88e6xxx_frame_mode { /* List of supported models */ enum mv88e6xxx_model { + MV88E6020, MV88E6085, MV88E6095, MV88E6097, @@ -95,7 +96,7 @@ enum mv88e6xxx_family { MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */ MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */ MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */ - MV88E6XXX_FAMILY_6250, /* 6220 6250 */ + MV88E6XXX_FAMILY_6250, /* 6220 6250 6020 */ MV88E6XXX_FAMILY_6320, /* 6320 6321 */ MV88E6XXX_FAMILY_6341, /* 6141 6341 */ MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index ec9019004404..111bdfab9619 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -111,6 +111,7 @@ /* Offset 0x03: Switch Identifier Register */ #define MV88E6XXX_PORT_SWITCH_ID 0x03 #define MV88E6XXX_PORT_SWITCH_ID_PROD_MASK 0xfff0 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6020 0x0200 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6085 0x04a0 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6095 0x0950 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6097 0x0990 -- cgit v1.2.3 From 372188c86e4b2adbac41d998ed96ade83eff5494 Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 30 May 2023 10:39:16 +0200 Subject: net: dsa: mv88e6xxx: add support for MV88E6071 switch A mv88e6250 family switch with 5 internal PHYs, 2 RMIIs and no PTP support. Signed-off-by: Lukasz Majewski Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 20 ++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 3 ++- drivers/net/dsa/mv88e6xxx/port.h | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d107c582fa93..8731af6d79de 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -5692,6 +5692,26 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .ops = &mv88e6250_ops, }, + [MV88E6071] = { + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6071, + .family = MV88E6XXX_FAMILY_6250, + .name = "Marvell 88E6071", + .num_databases = 64, + .num_ports = 7, + .num_internal_phys = 5, + .max_vid = 4095, + .port_base_addr = 0x08, + .phy_base_addr = 0x00, + .global1_addr = 0x0f, + .global2_addr = 0x07, + .age_time_coeff = 15000, + .g1_irqs = 9, + .g2_irqs = 5, + .atu_move_port_mask = 0xf, + .dual_chip = true, + .ops = &mv88e6250_ops, + }, + [MV88E6085] = { .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, .family = MV88E6XXX_FAMILY_6097, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 1bd7aa591c94..0ad34b2d8913 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -55,6 +55,7 @@ enum mv88e6xxx_frame_mode { /* List of supported models */ enum mv88e6xxx_model { MV88E6020, + MV88E6071, MV88E6085, MV88E6095, MV88E6097, @@ -96,7 +97,7 @@ enum mv88e6xxx_family { MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */ MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */ MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */ - MV88E6XXX_FAMILY_6250, /* 6220 6250 6020 */ + MV88E6XXX_FAMILY_6250, /* 6220 6250 6020 6071 */ MV88E6XXX_FAMILY_6320, /* 6320 6321 */ MV88E6XXX_FAMILY_6341, /* 6141 6341 */ MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 111bdfab9619..86deeb347cbc 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -112,6 +112,7 @@ #define MV88E6XXX_PORT_SWITCH_ID 0x03 #define MV88E6XXX_PORT_SWITCH_ID_PROD_MASK 0xfff0 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6020 0x0200 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6071 0x0710 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6085 0x04a0 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6095 0x0950 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6097 0x0990 -- cgit v1.2.3 From dced11ef84fb310f4ddfa74d1c09687b8f845d1b Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 30 May 2023 12:19:44 +0300 Subject: net/sched: taprio: don't overwrite "sch" variable in taprio_dump_class_stats() In taprio_dump_class_stats() we don't need a reference to the root Qdisc once we get the reference to the child corresponding to this traffic class, so it's okay to overwrite "sch". But in a future patch we will need the root Qdisc too, so create a dedicated "child" pointer variable to hold the child reference. This also makes the code adhere to a more conventional coding style. Signed-off-by: Vladimir Oltean Acked-by: Vinicius Costa Gomes Signed-off-by: David S. Miller --- net/sched/sch_taprio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 76db9a10ef50..d29e6785854d 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -2388,10 +2388,10 @@ static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, __acquires(d->lock) { struct netdev_queue *dev_queue = taprio_queue_get(sch, cl); + struct Qdisc *child = dev_queue->qdisc_sleeping; - sch = dev_queue->qdisc_sleeping; - if (gnet_stats_copy_basic(d, NULL, &sch->bstats, true) < 0 || - qdisc_qstats_copy(d, sch) < 0) + if (gnet_stats_copy_basic(d, NULL, &child->bstats, true) < 0 || + qdisc_qstats_copy(d, child) < 0) return -1; return 0; } -- cgit v1.2.3 From 2d800bc500fb3fb07a0fb42e2d0a1356fb9e1e8f Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 30 May 2023 12:19:45 +0300 Subject: net/sched: taprio: replace tc_taprio_qopt_offload :: enable with a "cmd" enum Inspired from struct flow_cls_offload :: cmd, in order for taprio to be able to report statistics (which is future work), it seems that we need to drill one step further with the ndo_setup_tc(TC_SETUP_QDISC_TAPRIO) multiplexing, and pass the command as part of the common portion of the muxed structure. Since we already have an "enable" variable in tc_taprio_qopt_offload, refactor all drivers to check for "cmd" instead of "enable", and reject every other command except "replace" and "destroy" - to be future proof. Signed-off-by: Vladimir Oltean Reviewed-by: Horatiu Vultur # for lan966x Acked-by: Kurt Kanzenbach # hellcreek Reviewed-by: Muhammad Husaini Zulkifli Reviewed-by: Gerhard Engleder Signed-off-by: David S. Miller --- drivers/net/dsa/hirschmann/hellcreek.c | 14 +++++++++----- drivers/net/dsa/ocelot/felix_vsc9959.c | 4 +++- drivers/net/dsa/sja1105/sja1105_tas.c | 7 +++++-- drivers/net/ethernet/engleder/tsnep_selftests.c | 12 ++++++------ drivers/net/ethernet/engleder/tsnep_tc.c | 4 +++- drivers/net/ethernet/freescale/enetc/enetc_qos.c | 6 +++++- drivers/net/ethernet/intel/igc/igc_main.c | 13 +++++++++++-- drivers/net/ethernet/microchip/lan966x/lan966x_tc.c | 10 ++++++++-- drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 7 +++++-- drivers/net/ethernet/ti/am65-cpsw-qos.c | 11 ++++++++--- include/net/pkt_sched.h | 7 ++++++- net/sched/sch_taprio.c | 4 ++-- 12 files changed, 71 insertions(+), 28 deletions(-) diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c index 595a548bb0a8..af50001ccdd4 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.c +++ b/drivers/net/dsa/hirschmann/hellcreek.c @@ -1885,13 +1885,17 @@ static int hellcreek_port_setup_tc(struct dsa_switch *ds, int port, case TC_SETUP_QDISC_TAPRIO: { struct tc_taprio_qopt_offload *taprio = type_data; - if (!hellcreek_validate_schedule(hellcreek, taprio)) - return -EOPNOTSUPP; + switch (taprio->cmd) { + case TAPRIO_CMD_REPLACE: + if (!hellcreek_validate_schedule(hellcreek, taprio)) + return -EOPNOTSUPP; - if (taprio->enable) return hellcreek_port_set_schedule(ds, port, taprio); - - return hellcreek_port_del_schedule(ds, port); + case TAPRIO_CMD_DESTROY: + return hellcreek_port_del_schedule(ds, port); + default: + return -EOPNOTSUPP; + } } default: return -EOPNOTSUPP; diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 030738fef60e..5de6a27052fc 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1411,7 +1411,7 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, mutex_lock(&ocelot->tas_lock); - if (!taprio->enable) { + if (taprio->cmd == TAPRIO_CMD_DESTROY) { ocelot_port_mqprio(ocelot, port, &taprio->mqprio); ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE, QSYS_TAG_CONFIG, port); @@ -1423,6 +1423,8 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, mutex_unlock(&ocelot->tas_lock); return 0; + } else if (taprio->cmd != TAPRIO_CMD_REPLACE) { + return -EOPNOTSUPP; } ret = ocelot_port_mqprio(ocelot, port, &taprio->mqprio); diff --git a/drivers/net/dsa/sja1105/sja1105_tas.c b/drivers/net/dsa/sja1105/sja1105_tas.c index e6153848a950..d7818710bc02 100644 --- a/drivers/net/dsa/sja1105/sja1105_tas.c +++ b/drivers/net/dsa/sja1105/sja1105_tas.c @@ -516,10 +516,11 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, /* Can't change an already configured port (must delete qdisc first). * Can't delete the qdisc from an unconfigured port. */ - if (!!tas_data->offload[port] == admin->enable) + if ((!!tas_data->offload[port] && admin->cmd == TAPRIO_CMD_REPLACE) || + (!tas_data->offload[port] && admin->cmd == TAPRIO_CMD_DESTROY)) return -EINVAL; - if (!admin->enable) { + if (admin->cmd == TAPRIO_CMD_DESTROY) { taprio_offload_free(tas_data->offload[port]); tas_data->offload[port] = NULL; @@ -528,6 +529,8 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, return rc; return sja1105_static_config_reload(priv, SJA1105_SCHEDULING); + } else if (admin->cmd != TAPRIO_CMD_REPLACE) { + return -EOPNOTSUPP; } /* The cycle time extension is the amount of time the last cycle from diff --git a/drivers/net/ethernet/engleder/tsnep_selftests.c b/drivers/net/ethernet/engleder/tsnep_selftests.c index 1581d6b22232..8a9145f93147 100644 --- a/drivers/net/ethernet/engleder/tsnep_selftests.c +++ b/drivers/net/ethernet/engleder/tsnep_selftests.c @@ -329,7 +329,7 @@ static bool disable_taprio(struct tsnep_adapter *adapter) int retval; memset(&qopt, 0, sizeof(qopt)); - qopt.enable = 0; + qopt.cmd = TAPRIO_CMD_DESTROY; retval = tsnep_tc_setup(adapter->netdev, TC_SETUP_QDISC_TAPRIO, &qopt); if (retval) return false; @@ -360,7 +360,7 @@ static bool tsnep_test_taprio(struct tsnep_adapter *adapter) for (i = 0; i < 255; i++) qopt->entries[i].command = TC_TAPRIO_CMD_SET_GATES; - qopt->enable = 1; + qopt->cmd = TAPRIO_CMD_REPLACE; qopt->base_time = ktime_set(0, 0); qopt->cycle_time = 1500000; qopt->cycle_time_extension = 0; @@ -382,7 +382,7 @@ static bool tsnep_test_taprio(struct tsnep_adapter *adapter) if (!run_taprio(adapter, qopt, 100)) goto failed; - qopt->enable = 1; + qopt->cmd = TAPRIO_CMD_REPLACE; qopt->base_time = ktime_set(0, 0); qopt->cycle_time = 411854; qopt->cycle_time_extension = 0; @@ -406,7 +406,7 @@ static bool tsnep_test_taprio(struct tsnep_adapter *adapter) if (!run_taprio(adapter, qopt, 100)) goto failed; - qopt->enable = 1; + qopt->cmd = TAPRIO_CMD_REPLACE; qopt->base_time = ktime_set(0, 0); delay_base_time(adapter, qopt, 12); qopt->cycle_time = 125000; @@ -457,7 +457,7 @@ static bool tsnep_test_taprio_change(struct tsnep_adapter *adapter) for (i = 0; i < 255; i++) qopt->entries[i].command = TC_TAPRIO_CMD_SET_GATES; - qopt->enable = 1; + qopt->cmd = TAPRIO_CMD_REPLACE; qopt->base_time = ktime_set(0, 0); qopt->cycle_time = 100000; qopt->cycle_time_extension = 0; @@ -610,7 +610,7 @@ static bool tsnep_test_taprio_extension(struct tsnep_adapter *adapter) for (i = 0; i < 255; i++) qopt->entries[i].command = TC_TAPRIO_CMD_SET_GATES; - qopt->enable = 1; + qopt->cmd = TAPRIO_CMD_REPLACE; qopt->base_time = ktime_set(0, 0); qopt->cycle_time = 100000; qopt->cycle_time_extension = 50000; diff --git a/drivers/net/ethernet/engleder/tsnep_tc.c b/drivers/net/ethernet/engleder/tsnep_tc.c index d083e6684f12..745b191a5540 100644 --- a/drivers/net/ethernet/engleder/tsnep_tc.c +++ b/drivers/net/ethernet/engleder/tsnep_tc.c @@ -325,7 +325,7 @@ static int tsnep_taprio(struct tsnep_adapter *adapter, if (!adapter->gate_control) return -EOPNOTSUPP; - if (!qopt->enable) { + if (qopt->cmd == TAPRIO_CMD_DESTROY) { /* disable gate control if active */ mutex_lock(&adapter->gate_control_lock); @@ -337,6 +337,8 @@ static int tsnep_taprio(struct tsnep_adapter *adapter, mutex_unlock(&adapter->gate_control_lock); return 0; + } else if (qopt->cmd != TAPRIO_CMD_REPLACE) { + return -EOPNOTSUPP; } retval = tsnep_validate_gcl(qopt); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 83c27bbbc6ed..7aad824f4da7 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -65,7 +65,7 @@ static int enetc_setup_taprio(struct net_device *ndev, gcl_len = admin_conf->num_entries; tge = enetc_rd(hw, ENETC_PTGCR); - if (!admin_conf->enable) { + if (admin_conf->cmd == TAPRIO_CMD_DESTROY) { enetc_wr(hw, ENETC_PTGCR, tge & ~ENETC_PTGCR_TGE); enetc_reset_ptcmsdur(hw); @@ -138,6 +138,10 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) struct enetc_ndev_priv *priv = netdev_priv(ndev); int err, i; + if (taprio->cmd != TAPRIO_CMD_REPLACE && + taprio->cmd != TAPRIO_CMD_DESTROY) + return -EOPNOTSUPP; + /* TSD and Qbv are mutually exclusive in hardware */ for (i = 0; i < priv->num_tx_rings; i++) if (priv->tx_ring[i]->tsd_enable) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index c5ef1edcf548..88145c30c919 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -6113,9 +6113,18 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter, size_t n; int i; - adapter->qbv_enable = qopt->enable; + switch (qopt->cmd) { + case TAPRIO_CMD_REPLACE: + adapter->qbv_enable = true; + break; + case TAPRIO_CMD_DESTROY: + adapter->qbv_enable = false; + break; + default: + return -EOPNOTSUPP; + } - if (!qopt->enable) + if (!adapter->qbv_enable) return igc_tsn_clear_schedule(adapter); if (qopt->base_time < 0) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c b/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c index cf0cc7562d04..ee652f2d2359 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_tc.c @@ -21,8 +21,14 @@ static int lan966x_tc_setup_qdisc_mqprio(struct lan966x_port *port, static int lan966x_tc_setup_qdisc_taprio(struct lan966x_port *port, struct tc_taprio_qopt_offload *taprio) { - return taprio->enable ? lan966x_taprio_add(port, taprio) : - lan966x_taprio_del(port); + switch (taprio->cmd) { + case TAPRIO_CMD_REPLACE: + return lan966x_taprio_add(port, taprio); + case TAPRIO_CMD_DESTROY: + return lan966x_taprio_del(port); + default: + return -EOPNOTSUPP; + } } static int lan966x_tc_setup_qdisc_tbf(struct lan966x_port *port, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 9d55226479b4..ac41ef4cbd2f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -966,8 +966,11 @@ static int tc_setup_taprio(struct stmmac_priv *priv, return -EOPNOTSUPP; } - if (!qopt->enable) + if (qopt->cmd == TAPRIO_CMD_DESTROY) goto disable; + else if (qopt->cmd != TAPRIO_CMD_REPLACE) + return -EOPNOTSUPP; + if (qopt->num_entries >= dep) return -EINVAL; if (!qopt->cycle_time) @@ -988,7 +991,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv, mutex_lock(&priv->plat->est->lock); priv->plat->est->gcl_size = size; - priv->plat->est->enable = qopt->enable; + priv->plat->est->enable = qopt->cmd == TAPRIO_CMD_REPLACE; mutex_unlock(&priv->plat->est->lock); for (i = 0; i < size; i++) { diff --git a/drivers/net/ethernet/ti/am65-cpsw-qos.c b/drivers/net/ethernet/ti/am65-cpsw-qos.c index 3a908db6e5b2..eced87fa261c 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-qos.c +++ b/drivers/net/ethernet/ti/am65-cpsw-qos.c @@ -450,7 +450,7 @@ static int am65_cpsw_configure_taprio(struct net_device *ndev, am65_cpsw_est_update_state(ndev); - if (!est_new->taprio.enable) { + if (est_new->taprio.cmd == TAPRIO_CMD_DESTROY) { am65_cpsw_stop_est(ndev); return ret; } @@ -476,7 +476,7 @@ static int am65_cpsw_configure_taprio(struct net_device *ndev, am65_cpsw_est_set_sched_list(ndev, est_new); am65_cpsw_port_est_assign_buf_num(ndev, est_new->buf); - am65_cpsw_est_set(ndev, est_new->taprio.enable); + am65_cpsw_est_set(ndev, est_new->taprio.cmd == TAPRIO_CMD_REPLACE); if (tact == TACT_PROG) { ret = am65_cpsw_timer_set(ndev, est_new); @@ -520,7 +520,7 @@ static int am65_cpsw_set_taprio(struct net_device *ndev, void *type_data) am65_cpsw_cp_taprio(taprio, &est_new->taprio); ret = am65_cpsw_configure_taprio(ndev, est_new); if (!ret) { - if (taprio->enable) { + if (taprio->cmd == TAPRIO_CMD_REPLACE) { devm_kfree(&ndev->dev, port->qos.est_admin); port->qos.est_admin = est_new; @@ -564,8 +564,13 @@ purge_est: static int am65_cpsw_setup_taprio(struct net_device *ndev, void *type_data) { struct am65_cpsw_port *port = am65_ndev_to_port(ndev); + struct tc_taprio_qopt_offload *taprio = type_data; struct am65_cpsw_common *common = port->common; + if (taprio->cmd != TAPRIO_CMD_REPLACE && + taprio->cmd != TAPRIO_CMD_DESTROY) + return -EOPNOTSUPP; + if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS)) return -ENODEV; diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index f436688b6efc..f5fb11da357b 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -185,6 +185,11 @@ struct tc_taprio_caps { bool broken_mqprio:1; }; +enum tc_taprio_qopt_cmd { + TAPRIO_CMD_REPLACE, + TAPRIO_CMD_DESTROY, +}; + struct tc_taprio_sched_entry { u8 command; /* TC_TAPRIO_CMD_* */ @@ -196,7 +201,7 @@ struct tc_taprio_sched_entry { struct tc_taprio_qopt_offload { struct tc_mqprio_qopt_offload mqprio; struct netlink_ext_ack *extack; - u8 enable; + enum tc_taprio_qopt_cmd cmd; ktime_t base_time; u64 cycle_time; u64 cycle_time_extension; diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index d29e6785854d..06bf4c6355a5 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -1524,7 +1524,7 @@ static int taprio_enable_offload(struct net_device *dev, "Not enough memory for enabling offload mode"); return -ENOMEM; } - offload->enable = 1; + offload->cmd = TAPRIO_CMD_REPLACE; offload->extack = extack; mqprio_qopt_reconstruct(dev, &offload->mqprio.qopt); offload->mqprio.extack = extack; @@ -1572,7 +1572,7 @@ static int taprio_disable_offload(struct net_device *dev, "Not enough memory to disable offload mode"); return -ENOMEM; } - offload->enable = 0; + offload->cmd = TAPRIO_CMD_DESTROY; err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TAPRIO, offload); if (err < 0) { -- cgit v1.2.3 From 6c1adb650c8d85c6cb471dbc900c2468f462995a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 30 May 2023 12:19:46 +0300 Subject: net/sched: taprio: add netlink reporting for offload statistics counters Offloading drivers may report some additional statistics counters, some of them even suggested by 802.1Q, like TransmissionOverrun. In my opinion we don't have to limit ourselves to reporting counters only globally to the Qdisc/interface, especially if the device has more detailed reporting (per traffic class), since the more detailed info is valuable for debugging and can help identifying who is exceeding its time slot. But on the other hand, some devices may not be able to report both per TC and global stats. So we end up reporting both ways, and use the good old ethtool_put_stat() strategy to determine which statistics are supported by this NIC. Statistics which aren't set are simply not reported to netlink. For this reason, we need something dynamic (a nlattr nest) to be reported through TCA_STATS_APP, and not something daft like the fixed-size and inextensible struct tc_codel_xstats. A good model for xstats which are a nlattr nest rather than a fixed struct seems to be cake. # Global stats $ tc -s qdisc show dev eth0 root # Per-tc stats $ tc -s class show dev eth0 Signed-off-by: Vladimir Oltean Acked-by: Vinicius Costa Gomes Signed-off-by: David S. Miller --- include/net/pkt_sched.h | 47 ++++++++++++++++++++----- include/uapi/linux/pkt_sched.h | 10 ++++++ net/sched/sch_taprio.c | 78 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 9 deletions(-) diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index f5fb11da357b..530d33adec88 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -188,6 +188,27 @@ struct tc_taprio_caps { enum tc_taprio_qopt_cmd { TAPRIO_CMD_REPLACE, TAPRIO_CMD_DESTROY, + TAPRIO_CMD_STATS, + TAPRIO_CMD_TC_STATS, +}; + +/** + * struct tc_taprio_qopt_stats - IEEE 802.1Qbv statistics + * @window_drops: Frames that were dropped because they were too large to be + * transmitted in any of the allotted time windows (open gates) for their + * traffic class. + * @tx_overruns: Frames still being transmitted by the MAC after the + * transmission gate associated with their traffic class has closed. + * Equivalent to `12.29.1.1.2 TransmissionOverrun` from 802.1Q-2018. + */ +struct tc_taprio_qopt_stats { + u64 window_drops; + u64 tx_overruns; +}; + +struct tc_taprio_qopt_tc_stats { + int tc; + struct tc_taprio_qopt_stats stats; }; struct tc_taprio_sched_entry { @@ -199,16 +220,26 @@ struct tc_taprio_sched_entry { }; struct tc_taprio_qopt_offload { - struct tc_mqprio_qopt_offload mqprio; - struct netlink_ext_ack *extack; enum tc_taprio_qopt_cmd cmd; - ktime_t base_time; - u64 cycle_time; - u64 cycle_time_extension; - u32 max_sdu[TC_MAX_QUEUE]; - size_t num_entries; - struct tc_taprio_sched_entry entries[]; + union { + /* TAPRIO_CMD_STATS */ + struct tc_taprio_qopt_stats stats; + /* TAPRIO_CMD_TC_STATS */ + struct tc_taprio_qopt_tc_stats tc_stats; + /* TAPRIO_CMD_REPLACE */ + struct { + struct tc_mqprio_qopt_offload mqprio; + struct netlink_ext_ack *extack; + ktime_t base_time; + u64 cycle_time; + u64 cycle_time_extension; + u32 max_sdu[TC_MAX_QUEUE]; + + size_t num_entries; + struct tc_taprio_sched_entry entries[]; + }; + }; }; #if IS_ENABLED(CONFIG_NET_SCH_TAPRIO) diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 51a7addc56c6..00f6ff0aff1f 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -1259,6 +1259,16 @@ enum { TCA_TAPRIO_TC_ENTRY_MAX = (__TCA_TAPRIO_TC_ENTRY_CNT - 1) }; +enum { + TCA_TAPRIO_OFFLOAD_STATS_PAD = 1, /* u64 */ + TCA_TAPRIO_OFFLOAD_STATS_WINDOW_DROPS, /* u64 */ + TCA_TAPRIO_OFFLOAD_STATS_TX_OVERRUNS, /* u64 */ + + /* add new constants above here */ + __TCA_TAPRIO_OFFLOAD_STATS_CNT, + TCA_TAPRIO_OFFLOAD_STATS_MAX = (__TCA_TAPRIO_OFFLOAD_STATS_CNT - 1) +}; + enum { TCA_TAPRIO_ATTR_UNSPEC, TCA_TAPRIO_ATTR_PRIOMAP, /* struct tc_mqprio_qopt */ diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 06bf4c6355a5..3c4c2c334878 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -27,6 +27,8 @@ #include #include +#define TAPRIO_STAT_NOT_SET (~0ULL) + #include "sch_mqprio_lib.h" static LIST_HEAD(taprio_list); @@ -2289,6 +2291,72 @@ nla_put_failure: return -EMSGSIZE; } +static int taprio_put_stat(struct sk_buff *skb, u64 val, u16 attrtype) +{ + if (val == TAPRIO_STAT_NOT_SET) + return 0; + if (nla_put_u64_64bit(skb, attrtype, val, TCA_TAPRIO_OFFLOAD_STATS_PAD)) + return -EMSGSIZE; + return 0; +} + +static int taprio_dump_xstats(struct Qdisc *sch, struct gnet_dump *d, + struct tc_taprio_qopt_offload *offload, + struct tc_taprio_qopt_stats *stats) +{ + struct net_device *dev = qdisc_dev(sch); + const struct net_device_ops *ops; + struct sk_buff *skb = d->skb; + struct nlattr *xstats; + int err; + + ops = qdisc_dev(sch)->netdev_ops; + + /* FIXME I could use qdisc_offload_dump_helper(), but that messes + * with sch->flags depending on whether the device reports taprio + * stats, and I'm not sure whether that's a good idea, considering + * that stats are optional to the offload itself + */ + if (!ops->ndo_setup_tc) + return 0; + + memset(stats, 0xff, sizeof(*stats)); + + err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TAPRIO, offload); + if (err == -EOPNOTSUPP) + return 0; + if (err) + return err; + + xstats = nla_nest_start(skb, TCA_STATS_APP); + if (!xstats) + goto err; + + if (taprio_put_stat(skb, stats->window_drops, + TCA_TAPRIO_OFFLOAD_STATS_WINDOW_DROPS) || + taprio_put_stat(skb, stats->tx_overruns, + TCA_TAPRIO_OFFLOAD_STATS_TX_OVERRUNS)) + goto err_cancel; + + nla_nest_end(skb, xstats); + + return 0; + +err_cancel: + nla_nest_cancel(skb, xstats); +err: + return -EMSGSIZE; +} + +static int taprio_dump_stats(struct Qdisc *sch, struct gnet_dump *d) +{ + struct tc_taprio_qopt_offload offload = { + .cmd = TAPRIO_CMD_STATS, + }; + + return taprio_dump_xstats(sch, d, &offload, &offload.stats); +} + static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb) { struct taprio_sched *q = qdisc_priv(sch); @@ -2389,11 +2457,18 @@ static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, { struct netdev_queue *dev_queue = taprio_queue_get(sch, cl); struct Qdisc *child = dev_queue->qdisc_sleeping; + struct tc_taprio_qopt_offload offload = { + .cmd = TAPRIO_CMD_TC_STATS, + .tc_stats = { + .tc = cl - 1, + }, + }; if (gnet_stats_copy_basic(d, NULL, &child->bstats, true) < 0 || qdisc_qstats_copy(d, child) < 0) return -1; - return 0; + + return taprio_dump_xstats(sch, d, &offload, &offload.tc_stats.stats); } static void taprio_walk(struct Qdisc *sch, struct qdisc_walker *arg) @@ -2440,6 +2515,7 @@ static struct Qdisc_ops taprio_qdisc_ops __read_mostly = { .dequeue = taprio_dequeue, .enqueue = taprio_enqueue, .dump = taprio_dump, + .dump_stats = taprio_dump_stats, .owner = THIS_MODULE, }; -- cgit v1.2.3 From 5353599aa74524acbf48c5e78683534f6bdd1ed3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 30 May 2023 12:19:47 +0300 Subject: net: enetc: refactor enetc_setup_tc_taprio() to have a switch/case for cmd Make enetc_setup_tc_taprio() more amenable to future extensions, like reporting statistics. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc.c | 3 +- drivers/net/ethernet/freescale/enetc/enetc.h | 1 + drivers/net/ethernet/freescale/enetc/enetc_qos.c | 79 +++++++++++++++--------- 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 63854294ac33..3aa31a760657 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -2624,7 +2624,7 @@ static void enetc_debug_tx_ring_prios(struct enetc_ndev_priv *priv) priv->tx_ring[i]->prio); } -static void enetc_reset_tc_mqprio(struct net_device *ndev) +void enetc_reset_tc_mqprio(struct net_device *ndev) { struct enetc_ndev_priv *priv = netdev_priv(ndev); struct enetc_hw *hw = &priv->si->hw; @@ -2649,6 +2649,7 @@ static void enetc_reset_tc_mqprio(struct net_device *ndev) enetc_change_preemptible_tcs(priv, 0); } +EXPORT_SYMBOL_GPL(enetc_reset_tc_mqprio); int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) { diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index c97a8e3d7a7f..8577cf7699a0 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -429,6 +429,7 @@ struct net_device_stats *enetc_get_stats(struct net_device *ndev); void enetc_set_features(struct net_device *ndev, netdev_features_t features); int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd); int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data); +void enetc_reset_tc_mqprio(struct net_device *ndev); int enetc_setup_bpf(struct net_device *ndev, struct netdev_bpf *bpf); int enetc_xdp_xmit(struct net_device *ndev, int num_frames, struct xdp_frame **frames, u32 flags); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 7aad824f4da7..2b8fdfffd02d 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -43,10 +43,9 @@ void enetc_sched_speed_set(struct enetc_ndev_priv *priv, int speed) enetc_port_wr(hw, ENETC_PMR, (tmp & ~ENETC_PMR_PSPEED_MASK) | pspeed); } -static int enetc_setup_taprio(struct net_device *ndev, +static int enetc_setup_taprio(struct enetc_ndev_priv *priv, struct tc_taprio_qopt_offload *admin_conf) { - struct enetc_ndev_priv *priv = netdev_priv(ndev); struct enetc_hw *hw = &priv->si->hw; struct enetc_cbd cbd = {.cmd = 0}; struct tgs_gcl_conf *gcl_config; @@ -60,19 +59,13 @@ static int enetc_setup_taprio(struct net_device *ndev, int err; int i; + /* TSD and Qbv are mutually exclusive in hardware */ + for (i = 0; i < priv->num_tx_rings; i++) + if (priv->tx_ring[i]->tsd_enable) + return -EBUSY; + if (admin_conf->num_entries > enetc_get_max_gcl_len(hw)) return -EINVAL; - gcl_len = admin_conf->num_entries; - - tge = enetc_rd(hw, ENETC_PTGCR); - if (admin_conf->cmd == TAPRIO_CMD_DESTROY) { - enetc_wr(hw, ENETC_PTGCR, tge & ~ENETC_PTGCR_TGE); - enetc_reset_ptcmsdur(hw); - - priv->active_offloads &= ~ENETC_F_QBV; - - return 0; - } if (admin_conf->cycle_time > U32_MAX || admin_conf->cycle_time_extension > U32_MAX) @@ -82,6 +75,7 @@ static int enetc_setup_taprio(struct net_device *ndev, * control BD descriptor. */ gcl_config = &cbd.gcl_conf; + gcl_len = admin_conf->num_entries; data_size = struct_size(gcl_data, entry, gcl_len); tmp = enetc_cbd_alloc_data_mem(priv->si, &cbd, data_size, @@ -115,6 +109,7 @@ static int enetc_setup_taprio(struct net_device *ndev, cbd.cls = BDCR_CMD_PORT_GCL; cbd.status_flags = 0; + tge = enetc_rd(hw, ENETC_PTGCR); enetc_wr(hw, ENETC_PTGCR, tge | ENETC_PTGCR_TGE); err = enetc_send_cmd(priv->si, &cbd); @@ -132,29 +127,57 @@ static int enetc_setup_taprio(struct net_device *ndev, return 0; } -int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) +static void enetc_reset_taprio(struct enetc_ndev_priv *priv) +{ + struct enetc_hw *hw = &priv->si->hw; + u32 val; + + val = enetc_rd(hw, ENETC_PTGCR); + enetc_wr(hw, ENETC_PTGCR, val & ~ENETC_PTGCR_TGE); + enetc_reset_ptcmsdur(hw); + + priv->active_offloads &= ~ENETC_F_QBV; +} + +static void enetc_taprio_destroy(struct net_device *ndev) { - struct tc_taprio_qopt_offload *taprio = type_data; struct enetc_ndev_priv *priv = netdev_priv(ndev); - int err, i; - if (taprio->cmd != TAPRIO_CMD_REPLACE && - taprio->cmd != TAPRIO_CMD_DESTROY) - return -EOPNOTSUPP; + enetc_reset_taprio(priv); + enetc_reset_tc_mqprio(ndev); +} - /* TSD and Qbv are mutually exclusive in hardware */ - for (i = 0; i < priv->num_tx_rings; i++) - if (priv->tx_ring[i]->tsd_enable) - return -EBUSY; +static int enetc_taprio_replace(struct net_device *ndev, + struct tc_taprio_qopt_offload *offload) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + int err; - err = enetc_setup_tc_mqprio(ndev, &taprio->mqprio); + err = enetc_setup_tc_mqprio(ndev, &offload->mqprio); if (err) return err; - err = enetc_setup_taprio(ndev, taprio); - if (err) { - taprio->mqprio.qopt.num_tc = 0; - enetc_setup_tc_mqprio(ndev, &taprio->mqprio); + err = enetc_setup_taprio(priv, offload); + if (err) + enetc_reset_tc_mqprio(ndev); + + return err; +} + +int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) +{ + struct tc_taprio_qopt_offload *offload = type_data; + int err = 0; + + switch (offload->cmd) { + case TAPRIO_CMD_REPLACE: + err = enetc_taprio_replace(ndev, offload); + break; + case TAPRIO_CMD_DESTROY: + enetc_taprio_destroy(ndev); + break; + default: + err = -EOPNOTSUPP; } return err; -- cgit v1.2.3 From 4802fca8d1af9687a0fd71b729d96726f05192ad Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 30 May 2023 12:19:48 +0300 Subject: net: enetc: report statistics counters for taprio Report the "win_drop" counter from the unstructured ethtool -S as TCA_TAPRIO_OFFLOAD_STATS_WINDOW_DROPS to the Qdisc layer. It is available both as a global counter as well as a per-TC one. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc_qos.c | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 2b8fdfffd02d..71157eba1fbe 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -147,6 +147,35 @@ static void enetc_taprio_destroy(struct net_device *ndev) enetc_reset_tc_mqprio(ndev); } +static void enetc_taprio_stats(struct net_device *ndev, + struct tc_taprio_qopt_stats *stats) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + u64 window_drops = 0; + int i; + + for (i = 0; i < priv->num_tx_rings; i++) + window_drops += priv->tx_ring[i]->stats.win_drop; + + stats->window_drops = window_drops; +} + +static void enetc_taprio_tc_stats(struct net_device *ndev, + struct tc_taprio_qopt_tc_stats *tc_stats) +{ + struct tc_taprio_qopt_stats *stats = &tc_stats->stats; + struct enetc_ndev_priv *priv = netdev_priv(ndev); + int tc = tc_stats->tc; + u64 window_drops = 0; + int i; + + for (i = 0; i < priv->num_tx_rings; i++) + if (priv->tx_ring[i]->prio == tc) + window_drops += priv->tx_ring[i]->stats.win_drop; + + stats->window_drops = window_drops; +} + static int enetc_taprio_replace(struct net_device *ndev, struct tc_taprio_qopt_offload *offload) { @@ -176,6 +205,12 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) case TAPRIO_CMD_DESTROY: enetc_taprio_destroy(ndev); break; + case TAPRIO_CMD_STATS: + enetc_taprio_stats(ndev, &offload->stats); + break; + case TAPRIO_CMD_TC_STATS: + enetc_taprio_tc_stats(ndev, &offload->tc_stats); + break; default: err = -EOPNOTSUPP; } -- cgit v1.2.3 From 0d2da4b595d03009db7dfb5ebf01c547b89b0ad8 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Wed, 31 May 2023 12:32:51 +0800 Subject: bpf/tests: Use struct_size() Use struct_size() instead of hand writing it. This is less verbose and more informative. Signed-off-by: Su Hui Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230531043251.989312-1-suhui@nfschina.com --- lib/test_bpf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/test_bpf.c b/lib/test_bpf.c index ade9ac672adb..fa0833410ac1 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -15056,8 +15056,7 @@ static __init int prepare_tail_call_tests(struct bpf_array **pprogs) int which, err; /* Allocate the table of programs to be used for tall calls */ - progs = kzalloc(sizeof(*progs) + (ntests + 1) * sizeof(progs->ptrs[0]), - GFP_KERNEL); + progs = kzalloc(struct_size(progs, ptrs, ntests + 1), GFP_KERNEL); if (!progs) goto out_nomem; -- cgit v1.2.3 From ffadc372529e268b54c5b98f56da07d8024fa1cb Mon Sep 17 00:00:00 2001 From: Azeem Shaikh Date: Tue, 30 May 2023 15:56:59 +0000 Subject: bpf: Replace all non-returning strlcpy with strscpy strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated [1]. This is not the case here, however, in an effort to remove strlcpy() completely [2], lets replace strlcpy() here with strscpy(). No return values were used, so a direct replacement is safe. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [2] https://github.com/KSPP/linux/issues/89 Signed-off-by: Azeem Shaikh Signed-off-by: Daniel Borkmann Reviewed-by: Kees Cook Link: https://lore.kernel.org/bpf/20230530155659.309657-1-azeemshaikh38@gmail.com --- kernel/bpf/preload/bpf_preload_kern.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/preload/bpf_preload_kern.c b/kernel/bpf/preload/bpf_preload_kern.c index b56f9f3314fd..0c63bc2cd895 100644 --- a/kernel/bpf/preload/bpf_preload_kern.c +++ b/kernel/bpf/preload/bpf_preload_kern.c @@ -23,9 +23,9 @@ static void free_links_and_skel(void) static int preload(struct bpf_preload_info *obj) { - strlcpy(obj[0].link_name, "maps.debug", sizeof(obj[0].link_name)); + strscpy(obj[0].link_name, "maps.debug", sizeof(obj[0].link_name)); obj[0].link = maps_link; - strlcpy(obj[1].link_name, "progs.debug", sizeof(obj[1].link_name)); + strscpy(obj[1].link_name, "progs.debug", sizeof(obj[1].link_name)); obj[1].link = progs_link; return 0; } -- cgit v1.2.3 From 9b68f30b68701e98abcec331a2cf3df972d910f8 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 26 May 2023 14:21:02 +0300 Subject: net: Use umd_cleanup_helper() bpfilter_umh_cleanup() is the same function as umd_cleanup_helper(). Drop the redundant function. Signed-off-by: Jarkko Sakkinen Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230526112104.1044686-1-jarkko@kernel.org --- include/linux/bpfilter.h | 1 - net/bpfilter/bpfilter_kern.c | 2 +- net/ipv4/bpfilter/sockopt.c | 11 +---------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/include/linux/bpfilter.h b/include/linux/bpfilter.h index 2ae3c8e1d83c..736ded4905e0 100644 --- a/include/linux/bpfilter.h +++ b/include/linux/bpfilter.h @@ -11,7 +11,6 @@ int bpfilter_ip_set_sockopt(struct sock *sk, int optname, sockptr_t optval, unsigned int optlen); int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen); -void bpfilter_umh_cleanup(struct umd_info *info); struct bpfilter_umh_ops { struct umd_info info; diff --git a/net/bpfilter/bpfilter_kern.c b/net/bpfilter/bpfilter_kern.c index 422ec6e7ccff..97e129e3f31c 100644 --- a/net/bpfilter/bpfilter_kern.c +++ b/net/bpfilter/bpfilter_kern.c @@ -21,7 +21,7 @@ static void shutdown_umh(void) if (tgid) { kill_pid(tgid, SIGKILL, 1); wait_event(tgid->wait_pidfd, thread_group_exited(tgid)); - bpfilter_umh_cleanup(info); + umd_cleanup_helper(info); } } diff --git a/net/ipv4/bpfilter/sockopt.c b/net/ipv4/bpfilter/sockopt.c index 1b34cb9a7708..193bcc2acccc 100644 --- a/net/ipv4/bpfilter/sockopt.c +++ b/net/ipv4/bpfilter/sockopt.c @@ -12,15 +12,6 @@ struct bpfilter_umh_ops bpfilter_ops; EXPORT_SYMBOL_GPL(bpfilter_ops); -void bpfilter_umh_cleanup(struct umd_info *info) -{ - fput(info->pipe_to_umh); - fput(info->pipe_from_umh); - put_pid(info->tgid); - info->tgid = NULL; -} -EXPORT_SYMBOL_GPL(bpfilter_umh_cleanup); - static int bpfilter_mbox_request(struct sock *sk, int optname, sockptr_t optval, unsigned int optlen, bool is_set) { @@ -38,7 +29,7 @@ static int bpfilter_mbox_request(struct sock *sk, int optname, sockptr_t optval, } if (bpfilter_ops.info.tgid && thread_group_exited(bpfilter_ops.info.tgid)) - bpfilter_umh_cleanup(&bpfilter_ops.info); + umd_cleanup_helper(&bpfilter_ops.info); if (!bpfilter_ops.info.tgid) { err = bpfilter_ops.start(); -- cgit v1.2.3 From 60548b825b082cedf89b275c21c28b1e1d030e50 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 30 May 2023 16:30:41 +0200 Subject: samples/bpf: xdp1 and xdp2 reduce XDPBUFSIZE to 60 Default samples/pktgen scripts send 60 byte packets as hardware adds 4-bytes FCS checksum, which fulfils minimum Ethernet 64 bytes frame size. XDP layer will not necessary have access to the 4-bytes FCS checksum. This leads to bpf_xdp_load_bytes() failing as it tries to copy 64-bytes from an XDP packet that only have 60-bytes available. Fixes: 772251742262 ("samples/bpf: fixup some tools to be able to support xdp multibuffer") Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Reviewed-by: Tariq Toukan Link: https://lore.kernel.org/bpf/168545704139.2996228.2516528552939485216.stgit@firesoul --- samples/bpf/xdp1_kern.c | 2 +- samples/bpf/xdp2_kern.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/bpf/xdp1_kern.c b/samples/bpf/xdp1_kern.c index 0a5c704badd0..d91f27cbcfa9 100644 --- a/samples/bpf/xdp1_kern.c +++ b/samples/bpf/xdp1_kern.c @@ -39,7 +39,7 @@ static int parse_ipv6(void *data, u64 nh_off, void *data_end) return ip6h->nexthdr; } -#define XDPBUFSIZE 64 +#define XDPBUFSIZE 60 SEC("xdp.frags") int xdp_prog1(struct xdp_md *ctx) { diff --git a/samples/bpf/xdp2_kern.c b/samples/bpf/xdp2_kern.c index 67804ecf7ce3..8bca674451ed 100644 --- a/samples/bpf/xdp2_kern.c +++ b/samples/bpf/xdp2_kern.c @@ -55,7 +55,7 @@ static int parse_ipv6(void *data, u64 nh_off, void *data_end) return ip6h->nexthdr; } -#define XDPBUFSIZE 64 +#define XDPBUFSIZE 60 SEC("xdp.frags") int xdp_prog1(struct xdp_md *ctx) { -- cgit v1.2.3 From 748b442800e877a93a4fa1256418d0b66bdc55ce Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 28 May 2023 19:39:59 +0200 Subject: net: don't set sw irq coalescing defaults in case of PREEMPT_RT If PREEMPT_RT is set, then assume that the user focuses on minimum latency. Therefore don't set sw irq coalescing defaults. This affects the defaults only, users can override these settings via sysfs. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/f9439c7f-c92c-4c2c-703e-110f96d841b7@gmail.com Signed-off-by: Jakub Kicinski --- net/core/dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 3393c2f3dbe8..99d99b247bc9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10571,8 +10571,10 @@ void netdev_sw_irq_coalesce_default_on(struct net_device *dev) { WARN_ON(dev->reg_state == NETREG_REGISTERED); - dev->gro_flush_timeout = 20000; - dev->napi_defer_hard_irqs = 1; + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) { + dev->gro_flush_timeout = 20000; + dev->napi_defer_hard_irqs = 1; + } } EXPORT_SYMBOL_GPL(netdev_sw_irq_coalesce_default_on); -- cgit v1.2.3 From 31605c01fb242806f5b8c9d08abe11328d514206 Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Mon, 29 May 2023 17:50:16 +0530 Subject: phy: mscc: Use PHY_ID_MATCH_VENDOR to minimize PHY ID table All the PHY devices variants specified have the same mask and hence can be simplified to one vendor look up for 0x00070400. Any individual config can be identified by PHY_ID_MATCH_EXACT in the respective structure. Signed-off-by: Harini Katakam Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/phy/mscc/mscc.h | 1 + drivers/net/phy/mscc/mscc_main.c | 16 +--------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h index defe5cc6d4fc..7a962050a4d4 100644 --- a/drivers/net/phy/mscc/mscc.h +++ b/drivers/net/phy/mscc/mscc.h @@ -292,6 +292,7 @@ enum rgmii_clock_delay { #define PHY_ID_VSC8575 0x000707d0 #define PHY_ID_VSC8582 0x000707b0 #define PHY_ID_VSC8584 0x000707c0 +#define PHY_VENDOR_MSCC 0x00070400 #define MSCC_VDDMAC_1500 1500 #define MSCC_VDDMAC_1800 1800 diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index 28df8a2e4230..fc074bcc894d 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -2678,21 +2678,7 @@ static struct phy_driver vsc85xx_driver[] = { module_phy_driver(vsc85xx_driver); static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { - { PHY_ID_VSC8501, 0xfffffff0, }, - { PHY_ID_VSC8502, 0xfffffff0, }, - { PHY_ID_VSC8504, 0xfffffff0, }, - { PHY_ID_VSC8514, 0xfffffff0, }, - { PHY_ID_VSC8530, 0xfffffff0, }, - { PHY_ID_VSC8531, 0xfffffff0, }, - { PHY_ID_VSC8540, 0xfffffff0, }, - { PHY_ID_VSC8541, 0xfffffff0, }, - { PHY_ID_VSC8552, 0xfffffff0, }, - { PHY_ID_VSC856X, 0xfffffff0, }, - { PHY_ID_VSC8572, 0xfffffff0, }, - { PHY_ID_VSC8574, 0xfffffff0, }, - { PHY_ID_VSC8575, 0xfffffff0, }, - { PHY_ID_VSC8582, 0xfffffff0, }, - { PHY_ID_VSC8584, 0xfffffff0, }, + { PHY_ID_MATCH_VENDOR(PHY_VENDOR_MSCC) }, { } }; -- cgit v1.2.3 From dbb050d2bfc8a91dfa3d020c51633c077a53d18b Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Mon, 29 May 2023 17:50:17 +0530 Subject: phy: mscc: Add support for RGMII delay configuration Add support for optional rx/tx-internal-delay-ps from devicetree. - When rx/tx-internal-delay-ps is/are specified, these take priority - When either is absent, 1) use 2ns for respective settings if rgmii-id/rxid/txid is/are present 2) use 0.2ns for respective settings if mode is rgmii Signed-off-by: Harini Katakam Signed-off-by: Jakub Kicinski --- drivers/net/phy/mscc/mscc_main.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index fc074bcc894d..669a4a7a28ce 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -107,6 +107,9 @@ static const struct vsc8531_edge_rate_table edge_table[] = { }; #endif +static const int vsc85xx_internal_delay[] = {200, 800, 1100, 1700, 2000, 2300, + 2600, 3400}; + static int vsc85xx_phy_read_page(struct phy_device *phydev) { return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS); @@ -525,8 +528,12 @@ static int vsc85xx_update_rgmii_cntl(struct phy_device *phydev, u32 rgmii_cntl, { u16 rgmii_rx_delay_pos = ffs(rgmii_rx_delay_mask) - 1; u16 rgmii_tx_delay_pos = ffs(rgmii_tx_delay_mask) - 1; + int delay_size = ARRAY_SIZE(vsc85xx_internal_delay); + struct device *dev = &phydev->mdio.dev; u16 reg_val = 0; u16 mask = 0; + s32 rx_delay; + s32 tx_delay; int rc = 0; /* For traffic to pass, the VSC8502 family needs the RX_CLK disable bit @@ -541,12 +548,28 @@ static int vsc85xx_update_rgmii_cntl(struct phy_device *phydev, u32 rgmii_cntl, if (phy_interface_is_rgmii(phydev)) mask |= rgmii_rx_delay_mask | rgmii_tx_delay_mask; - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - reg_val |= RGMII_CLK_DELAY_2_0_NS << rgmii_rx_delay_pos; - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - reg_val |= RGMII_CLK_DELAY_2_0_NS << rgmii_tx_delay_pos; + rx_delay = phy_get_internal_delay(phydev, dev, vsc85xx_internal_delay, + delay_size, true); + if (rx_delay < 0) { + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + rx_delay = RGMII_CLK_DELAY_2_0_NS; + else + rx_delay = RGMII_CLK_DELAY_0_2_NS; + } + + tx_delay = phy_get_internal_delay(phydev, dev, vsc85xx_internal_delay, + delay_size, false); + if (tx_delay < 0) { + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + rx_delay = RGMII_CLK_DELAY_2_0_NS; + else + rx_delay = RGMII_CLK_DELAY_0_2_NS; + } + + reg_val |= rx_delay << rgmii_rx_delay_pos; + reg_val |= tx_delay << rgmii_tx_delay_pos; if (mask) rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2, -- cgit v1.2.3 From 6f4b98147b8dfcabacb19b5c6abd087af66d0049 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 30 May 2023 18:55:23 -0700 Subject: devlink: make health report on unregistered instance warn just once Devlink health is involved in error recovery. Machines in bad state tend to be fairly unreliable, and occasionally get stuck in error loops. Even with a reasonable grace period devlink health may get a thousand reports in an hour. In case of reporting on an unregistered devlink instance the subsequent reports don't add much value. Switch to WARN_ON_ONCE() to avoid flooding dmesg and fleet monitoring dashboards. Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20230531015523.48961-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- net/devlink/health.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/devlink/health.c b/net/devlink/health.c index 0839706d5741..194340a8bb86 100644 --- a/net/devlink/health.c +++ b/net/devlink/health.c @@ -480,7 +480,7 @@ static void devlink_recover_notify(struct devlink_health_reporter *reporter, int err; WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER); - WARN_ON(!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)); + ASSERT_DEVLINK_REGISTERED(devlink); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) -- cgit v1.2.3 From 3403960cdf86c967442dccc2bec981e0093f716e Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 30 May 2023 10:26:25 +0800 Subject: net: wangxun: libwx add tx offload functions Add tx offload functions for wx_xmit_frame_ring which includes wx_encode_tx_desc_ptype, wx_tso and wx_tx_csum. which supports ngbe and txgbe to implement tx offload function. Signed-off-by: Mengyuan Lou Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 462 ++++++++++++++++++++++++++- drivers/net/ethernet/wangxun/libwx/wx_type.h | 87 ++++- 2 files changed, 541 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 1e8d8b7b0c62..34ac30e87b7c 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -2,9 +2,14 @@ /* Copyright (c) 2019 - 2022 Beijing WangXun Technology Co., Ltd. */ #include +#include #include +#include #include +#include #include +#include +#include #include "wx_type.h" #include "wx_lib.h" @@ -707,11 +712,50 @@ static int wx_maybe_stop_tx(struct wx_ring *tx_ring, u16 size) return 0; } +static u32 wx_tx_cmd_type(u32 tx_flags) +{ + /* set type for advanced descriptor with frame checksum insertion */ + u32 cmd_type = WX_TXD_DTYP_DATA | WX_TXD_IFCS; + + /* set HW vlan bit if vlan is present */ + cmd_type |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_HW_VLAN, WX_TXD_VLE); + /* set segmentation enable bits for TSO/FSO */ + cmd_type |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_TSO, WX_TXD_TSE); + /* set timestamp bit if present */ + cmd_type |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_TSTAMP, WX_TXD_MAC_TSTAMP); + cmd_type |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_LINKSEC, WX_TXD_LINKSEC); + + return cmd_type; +} + +static void wx_tx_olinfo_status(union wx_tx_desc *tx_desc, + u32 tx_flags, unsigned int paylen) +{ + u32 olinfo_status = paylen << WX_TXD_PAYLEN_SHIFT; + + /* enable L4 checksum for TSO and TX checksum offload */ + olinfo_status |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_CSUM, WX_TXD_L4CS); + /* enable IPv4 checksum for TSO */ + olinfo_status |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_IPV4, WX_TXD_IIPCS); + /* enable outer IPv4 checksum for TSO */ + olinfo_status |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_OUTER_IPV4, + WX_TXD_EIPCS); + /* Check Context must be set if Tx switch is enabled, which it + * always is for case where virtual functions are running + */ + olinfo_status |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_CC, WX_TXD_CC); + olinfo_status |= WX_SET_FLAG(tx_flags, WX_TX_FLAGS_IPSEC, + WX_TXD_IPSEC); + tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); +} + static void wx_tx_map(struct wx_ring *tx_ring, - struct wx_tx_buffer *first) + struct wx_tx_buffer *first, + const u8 hdr_len) { struct sk_buff *skb = first->skb; struct wx_tx_buffer *tx_buffer; + u32 tx_flags = first->tx_flags; u16 i = tx_ring->next_to_use; unsigned int data_len, size; union wx_tx_desc *tx_desc; @@ -719,10 +763,9 @@ static void wx_tx_map(struct wx_ring *tx_ring, dma_addr_t dma; u32 cmd_type; - cmd_type = WX_TXD_DTYP_DATA | WX_TXD_IFCS; + cmd_type = wx_tx_cmd_type(tx_flags); tx_desc = WX_TX_DESC(tx_ring, i); - - tx_desc->read.olinfo_status = cpu_to_le32(skb->len << WX_TXD_PAYLEN_SHIFT); + wx_tx_olinfo_status(tx_desc, tx_flags, skb->len - hdr_len); size = skb_headlen(skb); data_len = skb->data_len; @@ -838,12 +881,399 @@ dma_error: tx_ring->next_to_use = i; } +static void wx_tx_ctxtdesc(struct wx_ring *tx_ring, u32 vlan_macip_lens, + u32 fcoe_sof_eof, u32 type_tucmd, u32 mss_l4len_idx) +{ + struct wx_tx_context_desc *context_desc; + u16 i = tx_ring->next_to_use; + + context_desc = WX_TX_CTXTDESC(tx_ring, i); + i++; + tx_ring->next_to_use = (i < tx_ring->count) ? i : 0; + + /* set bits to identify this as an advanced context descriptor */ + type_tucmd |= WX_TXD_DTYP_CTXT; + context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens); + context_desc->seqnum_seed = cpu_to_le32(fcoe_sof_eof); + context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd); + context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); +} + +static void wx_get_ipv6_proto(struct sk_buff *skb, int offset, u8 *nexthdr) +{ + struct ipv6hdr *hdr = (struct ipv6hdr *)(skb->data + offset); + + *nexthdr = hdr->nexthdr; + offset += sizeof(struct ipv6hdr); + while (ipv6_ext_hdr(*nexthdr)) { + struct ipv6_opt_hdr _hdr, *hp; + + if (*nexthdr == NEXTHDR_NONE) + return; + hp = skb_header_pointer(skb, offset, sizeof(_hdr), &_hdr); + if (!hp) + return; + if (*nexthdr == NEXTHDR_FRAGMENT) + break; + *nexthdr = hp->nexthdr; + } +} + +union network_header { + struct iphdr *ipv4; + struct ipv6hdr *ipv6; + void *raw; +}; + +static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first) +{ + u8 tun_prot = 0, l4_prot = 0, ptype = 0; + struct sk_buff *skb = first->skb; + + if (skb->encapsulation) { + union network_header hdr; + + switch (first->protocol) { + case htons(ETH_P_IP): + tun_prot = ip_hdr(skb)->protocol; + ptype = WX_PTYPE_TUN_IPV4; + break; + case htons(ETH_P_IPV6): + wx_get_ipv6_proto(skb, skb_network_offset(skb), &tun_prot); + ptype = WX_PTYPE_TUN_IPV6; + break; + default: + return ptype; + } + + if (tun_prot == IPPROTO_IPIP) { + hdr.raw = (void *)inner_ip_hdr(skb); + ptype |= WX_PTYPE_PKT_IPIP; + } else if (tun_prot == IPPROTO_UDP) { + hdr.raw = (void *)inner_ip_hdr(skb); + if (skb->inner_protocol_type != ENCAP_TYPE_ETHER || + skb->inner_protocol != htons(ETH_P_TEB)) { + ptype |= WX_PTYPE_PKT_IG; + } else { + if (((struct ethhdr *)skb_inner_mac_header(skb))->h_proto + == htons(ETH_P_8021Q)) + ptype |= WX_PTYPE_PKT_IGMV; + else + ptype |= WX_PTYPE_PKT_IGM; + } + + } else if (tun_prot == IPPROTO_GRE) { + hdr.raw = (void *)inner_ip_hdr(skb); + if (skb->inner_protocol == htons(ETH_P_IP) || + skb->inner_protocol == htons(ETH_P_IPV6)) { + ptype |= WX_PTYPE_PKT_IG; + } else { + if (((struct ethhdr *)skb_inner_mac_header(skb))->h_proto + == htons(ETH_P_8021Q)) + ptype |= WX_PTYPE_PKT_IGMV; + else + ptype |= WX_PTYPE_PKT_IGM; + } + } else { + return ptype; + } + + switch (hdr.ipv4->version) { + case IPVERSION: + l4_prot = hdr.ipv4->protocol; + break; + case 6: + wx_get_ipv6_proto(skb, skb_inner_network_offset(skb), &l4_prot); + ptype |= WX_PTYPE_PKT_IPV6; + break; + default: + return ptype; + } + } else { + switch (first->protocol) { + case htons(ETH_P_IP): + l4_prot = ip_hdr(skb)->protocol; + ptype = WX_PTYPE_PKT_IP; + break; + case htons(ETH_P_IPV6): + wx_get_ipv6_proto(skb, skb_network_offset(skb), &l4_prot); + ptype = WX_PTYPE_PKT_IP | WX_PTYPE_PKT_IPV6; + break; + default: + return WX_PTYPE_PKT_MAC | WX_PTYPE_TYP_MAC; + } + } + switch (l4_prot) { + case IPPROTO_TCP: + ptype |= WX_PTYPE_TYP_TCP; + break; + case IPPROTO_UDP: + ptype |= WX_PTYPE_TYP_UDP; + break; + case IPPROTO_SCTP: + ptype |= WX_PTYPE_TYP_SCTP; + break; + default: + ptype |= WX_PTYPE_TYP_IP; + break; + } + + return ptype; +} + +static int wx_tso(struct wx_ring *tx_ring, struct wx_tx_buffer *first, + u8 *hdr_len, u8 ptype) +{ + u32 vlan_macip_lens, type_tucmd, mss_l4len_idx; + struct net_device *netdev = tx_ring->netdev; + u32 l4len, tunhdr_eiplen_tunlen = 0; + struct sk_buff *skb = first->skb; + bool enc = skb->encapsulation; + struct ipv6hdr *ipv6h; + struct tcphdr *tcph; + struct iphdr *iph; + u8 tun_prot = 0; + int err; + + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + + if (!skb_is_gso(skb)) + return 0; + + err = skb_cow_head(skb, 0); + if (err < 0) + return err; + + /* indicates the inner headers in the skbuff are valid. */ + iph = enc ? inner_ip_hdr(skb) : ip_hdr(skb); + if (iph->version == 4) { + tcph = enc ? inner_tcp_hdr(skb) : tcp_hdr(skb); + iph->tot_len = 0; + iph->check = 0; + tcph->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, 0); + first->tx_flags |= WX_TX_FLAGS_TSO | + WX_TX_FLAGS_CSUM | + WX_TX_FLAGS_IPV4 | + WX_TX_FLAGS_CC; + } else if (iph->version == 6 && skb_is_gso_v6(skb)) { + ipv6h = enc ? inner_ipv6_hdr(skb) : ipv6_hdr(skb); + tcph = enc ? inner_tcp_hdr(skb) : tcp_hdr(skb); + ipv6h->payload_len = 0; + tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, + &ipv6h->daddr, 0, + IPPROTO_TCP, 0); + first->tx_flags |= WX_TX_FLAGS_TSO | + WX_TX_FLAGS_CSUM | + WX_TX_FLAGS_CC; + } + + /* compute header lengths */ + l4len = enc ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb); + *hdr_len = enc ? (skb_inner_transport_header(skb) - skb->data) : + skb_transport_offset(skb); + *hdr_len += l4len; + + /* update gso size and bytecount with header size */ + first->gso_segs = skb_shinfo(skb)->gso_segs; + first->bytecount += (first->gso_segs - 1) * *hdr_len; + + /* mss_l4len_id: use 0 as index for TSO */ + mss_l4len_idx = l4len << WX_TXD_L4LEN_SHIFT; + mss_l4len_idx |= skb_shinfo(skb)->gso_size << WX_TXD_MSS_SHIFT; + + /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */ + if (enc) { + switch (first->protocol) { + case htons(ETH_P_IP): + tun_prot = ip_hdr(skb)->protocol; + first->tx_flags |= WX_TX_FLAGS_OUTER_IPV4; + break; + case htons(ETH_P_IPV6): + tun_prot = ipv6_hdr(skb)->nexthdr; + break; + default: + break; + } + switch (tun_prot) { + case IPPROTO_UDP: + tunhdr_eiplen_tunlen = WX_TXD_TUNNEL_UDP; + tunhdr_eiplen_tunlen |= ((skb_network_header_len(skb) >> 2) << + WX_TXD_OUTER_IPLEN_SHIFT) | + (((skb_inner_mac_header(skb) - + skb_transport_header(skb)) >> 1) << + WX_TXD_TUNNEL_LEN_SHIFT); + break; + case IPPROTO_GRE: + tunhdr_eiplen_tunlen = WX_TXD_TUNNEL_GRE; + tunhdr_eiplen_tunlen |= ((skb_network_header_len(skb) >> 2) << + WX_TXD_OUTER_IPLEN_SHIFT) | + (((skb_inner_mac_header(skb) - + skb_transport_header(skb)) >> 1) << + WX_TXD_TUNNEL_LEN_SHIFT); + break; + case IPPROTO_IPIP: + tunhdr_eiplen_tunlen = (((char *)inner_ip_hdr(skb) - + (char *)ip_hdr(skb)) >> 2) << + WX_TXD_OUTER_IPLEN_SHIFT; + break; + default: + break; + } + vlan_macip_lens = skb_inner_network_header_len(skb) >> 1; + } else { + vlan_macip_lens = skb_network_header_len(skb) >> 1; + } + + vlan_macip_lens |= skb_network_offset(skb) << WX_TXD_MACLEN_SHIFT; + vlan_macip_lens |= first->tx_flags & WX_TX_FLAGS_VLAN_MASK; + + type_tucmd = ptype << 24; + if (skb->vlan_proto == htons(ETH_P_8021AD) && + netdev->features & NETIF_F_HW_VLAN_STAG_TX) + type_tucmd |= WX_SET_FLAG(first->tx_flags, + WX_TX_FLAGS_HW_VLAN, + 0x1 << WX_TXD_TAG_TPID_SEL_SHIFT); + wx_tx_ctxtdesc(tx_ring, vlan_macip_lens, tunhdr_eiplen_tunlen, + type_tucmd, mss_l4len_idx); + + return 1; +} + +static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first, + u8 ptype) +{ + u32 tunhdr_eiplen_tunlen = 0, vlan_macip_lens = 0; + struct net_device *netdev = tx_ring->netdev; + u32 mss_l4len_idx = 0, type_tucmd; + struct sk_buff *skb = first->skb; + u8 tun_prot = 0; + + if (skb->ip_summed != CHECKSUM_PARTIAL) { + if (!(first->tx_flags & WX_TX_FLAGS_HW_VLAN) && + !(first->tx_flags & WX_TX_FLAGS_CC)) + return; + vlan_macip_lens = skb_network_offset(skb) << + WX_TXD_MACLEN_SHIFT; + } else { + u8 l4_prot = 0; + union { + struct iphdr *ipv4; + struct ipv6hdr *ipv6; + u8 *raw; + } network_hdr; + union { + struct tcphdr *tcphdr; + u8 *raw; + } transport_hdr; + + if (skb->encapsulation) { + network_hdr.raw = skb_inner_network_header(skb); + transport_hdr.raw = skb_inner_transport_header(skb); + vlan_macip_lens = skb_network_offset(skb) << + WX_TXD_MACLEN_SHIFT; + switch (first->protocol) { + case htons(ETH_P_IP): + tun_prot = ip_hdr(skb)->protocol; + break; + case htons(ETH_P_IPV6): + tun_prot = ipv6_hdr(skb)->nexthdr; + break; + default: + return; + } + switch (tun_prot) { + case IPPROTO_UDP: + tunhdr_eiplen_tunlen = WX_TXD_TUNNEL_UDP; + tunhdr_eiplen_tunlen |= + ((skb_network_header_len(skb) >> 2) << + WX_TXD_OUTER_IPLEN_SHIFT) | + (((skb_inner_mac_header(skb) - + skb_transport_header(skb)) >> 1) << + WX_TXD_TUNNEL_LEN_SHIFT); + break; + case IPPROTO_GRE: + tunhdr_eiplen_tunlen = WX_TXD_TUNNEL_GRE; + tunhdr_eiplen_tunlen |= ((skb_network_header_len(skb) >> 2) << + WX_TXD_OUTER_IPLEN_SHIFT) | + (((skb_inner_mac_header(skb) - + skb_transport_header(skb)) >> 1) << + WX_TXD_TUNNEL_LEN_SHIFT); + break; + case IPPROTO_IPIP: + tunhdr_eiplen_tunlen = (((char *)inner_ip_hdr(skb) - + (char *)ip_hdr(skb)) >> 2) << + WX_TXD_OUTER_IPLEN_SHIFT; + break; + default: + break; + } + + } else { + network_hdr.raw = skb_network_header(skb); + transport_hdr.raw = skb_transport_header(skb); + vlan_macip_lens = skb_network_offset(skb) << + WX_TXD_MACLEN_SHIFT; + } + + switch (network_hdr.ipv4->version) { + case IPVERSION: + vlan_macip_lens |= (transport_hdr.raw - network_hdr.raw) >> 1; + l4_prot = network_hdr.ipv4->protocol; + break; + case 6: + vlan_macip_lens |= (transport_hdr.raw - network_hdr.raw) >> 1; + l4_prot = network_hdr.ipv6->nexthdr; + break; + default: + break; + } + + switch (l4_prot) { + case IPPROTO_TCP: + mss_l4len_idx = (transport_hdr.tcphdr->doff * 4) << + WX_TXD_L4LEN_SHIFT; + break; + case IPPROTO_SCTP: + mss_l4len_idx = sizeof(struct sctphdr) << + WX_TXD_L4LEN_SHIFT; + break; + case IPPROTO_UDP: + mss_l4len_idx = sizeof(struct udphdr) << + WX_TXD_L4LEN_SHIFT; + break; + default: + break; + } + + /* update TX checksum flag */ + first->tx_flags |= WX_TX_FLAGS_CSUM; + } + first->tx_flags |= WX_TX_FLAGS_CC; + /* vlan_macip_lens: MACLEN, VLAN tag */ + vlan_macip_lens |= first->tx_flags & WX_TX_FLAGS_VLAN_MASK; + + type_tucmd = ptype << 24; + if (skb->vlan_proto == htons(ETH_P_8021AD) && + netdev->features & NETIF_F_HW_VLAN_STAG_TX) + type_tucmd |= WX_SET_FLAG(first->tx_flags, + WX_TX_FLAGS_HW_VLAN, + 0x1 << WX_TXD_TAG_TPID_SEL_SHIFT); + wx_tx_ctxtdesc(tx_ring, vlan_macip_lens, tunhdr_eiplen_tunlen, + type_tucmd, mss_l4len_idx); +} + static netdev_tx_t wx_xmit_frame_ring(struct sk_buff *skb, struct wx_ring *tx_ring) { u16 count = TXD_USE_COUNT(skb_headlen(skb)); struct wx_tx_buffer *first; + u8 hdr_len = 0, ptype; unsigned short f; + u32 tx_flags = 0; + int tso; /* need: 1 descriptor per page * PAGE_SIZE/WX_MAX_DATA_PER_TXD, * + 1 desc for skb_headlen/WX_MAX_DATA_PER_TXD, @@ -864,7 +1294,29 @@ static netdev_tx_t wx_xmit_frame_ring(struct sk_buff *skb, first->bytecount = skb->len; first->gso_segs = 1; - wx_tx_map(tx_ring, first); + /* if we have a HW VLAN tag being added default to the HW one */ + if (skb_vlan_tag_present(skb)) { + tx_flags |= skb_vlan_tag_get(skb) << WX_TX_FLAGS_VLAN_SHIFT; + tx_flags |= WX_TX_FLAGS_HW_VLAN; + } + + /* record initial flags and protocol */ + first->tx_flags = tx_flags; + first->protocol = vlan_get_protocol(skb); + + ptype = wx_encode_tx_desc_ptype(first); + + tso = wx_tso(tx_ring, first, &hdr_len, ptype); + if (tso < 0) + goto out_drop; + else if (!tso) + wx_tx_csum(tx_ring, first, ptype); + wx_tx_map(tx_ring, first, hdr_len); + + return NETDEV_TX_OK; +out_drop: + dev_kfree_skb_any(first->skb); + first->skb = NULL; return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index cbe7f184b50e..9d549dc49dfd 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -6,6 +6,7 @@ #include #include +#include #define WX_NCSI_SUP 0x8000 #define WX_NCSI_MASK 0x8000 @@ -315,9 +316,6 @@ #define TXD_USE_COUNT(S) DIV_ROUND_UP((S), WX_MAX_DATA_PER_TXD) #define DESC_NEEDED (MAX_SKB_FRAGS + 4) -/* Ether Types */ -#define WX_ETH_P_CNM 0x22E7 - #define WX_CFG_PORT_ST 0x14404 /******************* Receive Descriptor bit definitions **********************/ @@ -326,6 +324,29 @@ #define WX_RXD_ERR_RXE BIT(29) /* Any MAC Error */ +/* TUN */ +#define WX_PTYPE_TUN_IPV4 0x80 +#define WX_PTYPE_TUN_IPV6 0xC0 + +/* PKT for TUN */ +#define WX_PTYPE_PKT_IPIP 0x00 /* IP+IP */ +#define WX_PTYPE_PKT_IG 0x10 /* IP+GRE */ +#define WX_PTYPE_PKT_IGM 0x20 /* IP+GRE+MAC */ +#define WX_PTYPE_PKT_IGMV 0x30 /* IP+GRE+MAC+VLAN */ +/* PKT for !TUN */ +#define WX_PTYPE_PKT_MAC 0x10 +#define WX_PTYPE_PKT_IP 0x20 + +/* TYP for PKT=mac */ +#define WX_PTYPE_TYP_MAC 0x01 +/* TYP for PKT=ip */ +#define WX_PTYPE_PKT_IPV6 0x08 +#define WX_PTYPE_TYP_IPFRAG 0x01 +#define WX_PTYPE_TYP_IP 0x02 +#define WX_PTYPE_TYP_UDP 0x03 +#define WX_PTYPE_TYP_TCP 0x04 +#define WX_PTYPE_TYP_SCTP 0x05 + /*********************** Transmit Descriptor Config Masks ****************/ #define WX_TXD_STAT_DD BIT(0) /* Descriptor Done */ #define WX_TXD_DTYP_DATA 0 /* Adv Data Descriptor */ @@ -334,6 +355,49 @@ #define WX_TXD_IFCS BIT(25) /* Insert FCS */ #define WX_TXD_RS BIT(27) /* Report Status */ +/*********************** Adv Transmit Descriptor Config Masks ****************/ +#define WX_TXD_MAC_TSTAMP BIT(19) /* IEEE1588 time stamp */ +#define WX_TXD_DTYP_CTXT BIT(20) /* Adv Context Desc */ +#define WX_TXD_LINKSEC BIT(26) /* enable linksec */ +#define WX_TXD_VLE BIT(30) /* VLAN pkt enable */ +#define WX_TXD_TSE BIT(31) /* TCP Seg enable */ +#define WX_TXD_CC BIT(7) /* Check Context */ +#define WX_TXD_IPSEC BIT(8) /* enable ipsec esp */ +#define WX_TXD_L4CS BIT(9) +#define WX_TXD_IIPCS BIT(10) +#define WX_TXD_EIPCS BIT(11) +#define WX_TXD_PAYLEN_SHIFT 13 /* Adv desc PAYLEN shift */ +#define WX_TXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +#define WX_TXD_TAG_TPID_SEL_SHIFT 11 + +#define WX_TXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ +#define WX_TXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ + +#define WX_TXD_OUTER_IPLEN_SHIFT 12 /* Adv ctxt OUTERIPLEN shift */ +#define WX_TXD_TUNNEL_LEN_SHIFT 21 /* Adv ctxt TUNNELLEN shift */ +#define WX_TXD_TUNNEL_TYPE_SHIFT 11 /* Adv Tx Desc Tunnel Type shift */ +#define WX_TXD_TUNNEL_UDP FIELD_PREP(BIT(WX_TXD_TUNNEL_TYPE_SHIFT), 0) +#define WX_TXD_TUNNEL_GRE FIELD_PREP(BIT(WX_TXD_TUNNEL_TYPE_SHIFT), 1) + +enum wx_tx_flags { + /* cmd_type flags */ + WX_TX_FLAGS_HW_VLAN = 0x01, + WX_TX_FLAGS_TSO = 0x02, + WX_TX_FLAGS_TSTAMP = 0x04, + + /* olinfo flags */ + WX_TX_FLAGS_CC = 0x08, + WX_TX_FLAGS_IPV4 = 0x10, + WX_TX_FLAGS_CSUM = 0x20, + WX_TX_FLAGS_OUTER_IPV4 = 0x100, + WX_TX_FLAGS_LINKSEC = 0x200, + WX_TX_FLAGS_IPSEC = 0x400, +}; + +/* VLAN info */ +#define WX_TX_FLAGS_VLAN_MASK GENMASK(31, 16) +#define WX_TX_FLAGS_VLAN_SHIFT 16 + /* Host Interface Command Structures */ struct wx_hic_hdr { u8 cmd; @@ -508,10 +572,25 @@ union wx_rx_desc { } wb; /* writeback */ }; +struct wx_tx_context_desc { + __le32 vlan_macip_lens; + __le32 seqnum_seed; + __le32 type_tucmd_mlhl; + __le32 mss_l4len_idx; +}; + +/* if _flag is in _input, return _result */ +#define WX_SET_FLAG(_input, _flag, _result) \ + (((_flag) <= (_result)) ? \ + ((u32)((_input) & (_flag)) * ((_result) / (_flag))) : \ + ((u32)((_input) & (_flag)) / ((_flag) / (_result)))) + #define WX_RX_DESC(R, i) \ (&(((union wx_rx_desc *)((R)->desc))[i])) #define WX_TX_DESC(R, i) \ (&(((union wx_tx_desc *)((R)->desc))[i])) +#define WX_TX_CTXTDESC(R, i) \ + (&(((struct wx_tx_context_desc *)((R)->desc))[i])) /* wrapper around a pointer to a socket buffer, * so a DMA handle can be stored along with the buffer @@ -523,6 +602,8 @@ struct wx_tx_buffer { unsigned short gso_segs; DEFINE_DMA_UNMAP_ADDR(dma); DEFINE_DMA_UNMAP_LEN(len); + __be16 protocol; + u32 tx_flags; }; struct wx_rx_buffer { -- cgit v1.2.3 From ef4f3c19f912820c15a6de0aedcc0fda67c7dd3a Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 30 May 2023 10:26:26 +0800 Subject: net: wangxun: libwx add rx offload functions Add rx offload functions for wx_clean_rx_irq which supports ngbe and txgbe to implement rx offload function. Signed-off-by: Mengyuan Lou Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 234 ++++++++++++++++++++++++++- drivers/net/ethernet/wangxun/libwx/wx_type.h | 100 +++++++++++- 2 files changed, 331 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 34ac30e87b7c..84107208401e 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -15,6 +15,144 @@ #include "wx_lib.h" #include "wx_hw.h" +/* Lookup table mapping the HW PTYPE to the bit field for decoding */ +static struct wx_dec_ptype wx_ptype_lookup[256] = { + /* L2: mac */ + [0x11] = WX_PTT(L2, NONE, NONE, NONE, NONE, PAY2), + [0x12] = WX_PTT(L2, NONE, NONE, NONE, TS, PAY2), + [0x13] = WX_PTT(L2, NONE, NONE, NONE, NONE, PAY2), + [0x14] = WX_PTT(L2, NONE, NONE, NONE, NONE, PAY2), + [0x15] = WX_PTT(L2, NONE, NONE, NONE, NONE, NONE), + [0x16] = WX_PTT(L2, NONE, NONE, NONE, NONE, PAY2), + [0x17] = WX_PTT(L2, NONE, NONE, NONE, NONE, NONE), + + /* L2: ethertype filter */ + [0x18 ... 0x1F] = WX_PTT(L2, NONE, NONE, NONE, NONE, NONE), + + /* L3: ip non-tunnel */ + [0x21] = WX_PTT(IP, FGV4, NONE, NONE, NONE, PAY3), + [0x22] = WX_PTT(IP, IPV4, NONE, NONE, NONE, PAY3), + [0x23] = WX_PTT(IP, IPV4, NONE, NONE, UDP, PAY4), + [0x24] = WX_PTT(IP, IPV4, NONE, NONE, TCP, PAY4), + [0x25] = WX_PTT(IP, IPV4, NONE, NONE, SCTP, PAY4), + [0x29] = WX_PTT(IP, FGV6, NONE, NONE, NONE, PAY3), + [0x2A] = WX_PTT(IP, IPV6, NONE, NONE, NONE, PAY3), + [0x2B] = WX_PTT(IP, IPV6, NONE, NONE, UDP, PAY3), + [0x2C] = WX_PTT(IP, IPV6, NONE, NONE, TCP, PAY4), + [0x2D] = WX_PTT(IP, IPV6, NONE, NONE, SCTP, PAY4), + + /* L2: fcoe */ + [0x30 ... 0x34] = WX_PTT(FCOE, NONE, NONE, NONE, NONE, PAY3), + [0x38 ... 0x3C] = WX_PTT(FCOE, NONE, NONE, NONE, NONE, PAY3), + + /* IPv4 --> IPv4/IPv6 */ + [0x81] = WX_PTT(IP, IPV4, IPIP, FGV4, NONE, PAY3), + [0x82] = WX_PTT(IP, IPV4, IPIP, IPV4, NONE, PAY3), + [0x83] = WX_PTT(IP, IPV4, IPIP, IPV4, UDP, PAY4), + [0x84] = WX_PTT(IP, IPV4, IPIP, IPV4, TCP, PAY4), + [0x85] = WX_PTT(IP, IPV4, IPIP, IPV4, SCTP, PAY4), + [0x89] = WX_PTT(IP, IPV4, IPIP, FGV6, NONE, PAY3), + [0x8A] = WX_PTT(IP, IPV4, IPIP, IPV6, NONE, PAY3), + [0x8B] = WX_PTT(IP, IPV4, IPIP, IPV6, UDP, PAY4), + [0x8C] = WX_PTT(IP, IPV4, IPIP, IPV6, TCP, PAY4), + [0x8D] = WX_PTT(IP, IPV4, IPIP, IPV6, SCTP, PAY4), + + /* IPv4 --> GRE/NAT --> NONE/IPv4/IPv6 */ + [0x90] = WX_PTT(IP, IPV4, IG, NONE, NONE, PAY3), + [0x91] = WX_PTT(IP, IPV4, IG, FGV4, NONE, PAY3), + [0x92] = WX_PTT(IP, IPV4, IG, IPV4, NONE, PAY3), + [0x93] = WX_PTT(IP, IPV4, IG, IPV4, UDP, PAY4), + [0x94] = WX_PTT(IP, IPV4, IG, IPV4, TCP, PAY4), + [0x95] = WX_PTT(IP, IPV4, IG, IPV4, SCTP, PAY4), + [0x99] = WX_PTT(IP, IPV4, IG, FGV6, NONE, PAY3), + [0x9A] = WX_PTT(IP, IPV4, IG, IPV6, NONE, PAY3), + [0x9B] = WX_PTT(IP, IPV4, IG, IPV6, UDP, PAY4), + [0x9C] = WX_PTT(IP, IPV4, IG, IPV6, TCP, PAY4), + [0x9D] = WX_PTT(IP, IPV4, IG, IPV6, SCTP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC --> NONE/IPv4/IPv6 */ + [0xA0] = WX_PTT(IP, IPV4, IGM, NONE, NONE, PAY3), + [0xA1] = WX_PTT(IP, IPV4, IGM, FGV4, NONE, PAY3), + [0xA2] = WX_PTT(IP, IPV4, IGM, IPV4, NONE, PAY3), + [0xA3] = WX_PTT(IP, IPV4, IGM, IPV4, UDP, PAY4), + [0xA4] = WX_PTT(IP, IPV4, IGM, IPV4, TCP, PAY4), + [0xA5] = WX_PTT(IP, IPV4, IGM, IPV4, SCTP, PAY4), + [0xA9] = WX_PTT(IP, IPV4, IGM, FGV6, NONE, PAY3), + [0xAA] = WX_PTT(IP, IPV4, IGM, IPV6, NONE, PAY3), + [0xAB] = WX_PTT(IP, IPV4, IGM, IPV6, UDP, PAY4), + [0xAC] = WX_PTT(IP, IPV4, IGM, IPV6, TCP, PAY4), + [0xAD] = WX_PTT(IP, IPV4, IGM, IPV6, SCTP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC+VLAN --> NONE/IPv4/IPv6 */ + [0xB0] = WX_PTT(IP, IPV4, IGMV, NONE, NONE, PAY3), + [0xB1] = WX_PTT(IP, IPV4, IGMV, FGV4, NONE, PAY3), + [0xB2] = WX_PTT(IP, IPV4, IGMV, IPV4, NONE, PAY3), + [0xB3] = WX_PTT(IP, IPV4, IGMV, IPV4, UDP, PAY4), + [0xB4] = WX_PTT(IP, IPV4, IGMV, IPV4, TCP, PAY4), + [0xB5] = WX_PTT(IP, IPV4, IGMV, IPV4, SCTP, PAY4), + [0xB9] = WX_PTT(IP, IPV4, IGMV, FGV6, NONE, PAY3), + [0xBA] = WX_PTT(IP, IPV4, IGMV, IPV6, NONE, PAY3), + [0xBB] = WX_PTT(IP, IPV4, IGMV, IPV6, UDP, PAY4), + [0xBC] = WX_PTT(IP, IPV4, IGMV, IPV6, TCP, PAY4), + [0xBD] = WX_PTT(IP, IPV4, IGMV, IPV6, SCTP, PAY4), + + /* IPv6 --> IPv4/IPv6 */ + [0xC1] = WX_PTT(IP, IPV6, IPIP, FGV4, NONE, PAY3), + [0xC2] = WX_PTT(IP, IPV6, IPIP, IPV4, NONE, PAY3), + [0xC3] = WX_PTT(IP, IPV6, IPIP, IPV4, UDP, PAY4), + [0xC4] = WX_PTT(IP, IPV6, IPIP, IPV4, TCP, PAY4), + [0xC5] = WX_PTT(IP, IPV6, IPIP, IPV4, SCTP, PAY4), + [0xC9] = WX_PTT(IP, IPV6, IPIP, FGV6, NONE, PAY3), + [0xCA] = WX_PTT(IP, IPV6, IPIP, IPV6, NONE, PAY3), + [0xCB] = WX_PTT(IP, IPV6, IPIP, IPV6, UDP, PAY4), + [0xCC] = WX_PTT(IP, IPV6, IPIP, IPV6, TCP, PAY4), + [0xCD] = WX_PTT(IP, IPV6, IPIP, IPV6, SCTP, PAY4), + + /* IPv6 --> GRE/NAT -> NONE/IPv4/IPv6 */ + [0xD0] = WX_PTT(IP, IPV6, IG, NONE, NONE, PAY3), + [0xD1] = WX_PTT(IP, IPV6, IG, FGV4, NONE, PAY3), + [0xD2] = WX_PTT(IP, IPV6, IG, IPV4, NONE, PAY3), + [0xD3] = WX_PTT(IP, IPV6, IG, IPV4, UDP, PAY4), + [0xD4] = WX_PTT(IP, IPV6, IG, IPV4, TCP, PAY4), + [0xD5] = WX_PTT(IP, IPV6, IG, IPV4, SCTP, PAY4), + [0xD9] = WX_PTT(IP, IPV6, IG, FGV6, NONE, PAY3), + [0xDA] = WX_PTT(IP, IPV6, IG, IPV6, NONE, PAY3), + [0xDB] = WX_PTT(IP, IPV6, IG, IPV6, UDP, PAY4), + [0xDC] = WX_PTT(IP, IPV6, IG, IPV6, TCP, PAY4), + [0xDD] = WX_PTT(IP, IPV6, IG, IPV6, SCTP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC -> NONE/IPv4/IPv6 */ + [0xE0] = WX_PTT(IP, IPV6, IGM, NONE, NONE, PAY3), + [0xE1] = WX_PTT(IP, IPV6, IGM, FGV4, NONE, PAY3), + [0xE2] = WX_PTT(IP, IPV6, IGM, IPV4, NONE, PAY3), + [0xE3] = WX_PTT(IP, IPV6, IGM, IPV4, UDP, PAY4), + [0xE4] = WX_PTT(IP, IPV6, IGM, IPV4, TCP, PAY4), + [0xE5] = WX_PTT(IP, IPV6, IGM, IPV4, SCTP, PAY4), + [0xE9] = WX_PTT(IP, IPV6, IGM, FGV6, NONE, PAY3), + [0xEA] = WX_PTT(IP, IPV6, IGM, IPV6, NONE, PAY3), + [0xEB] = WX_PTT(IP, IPV6, IGM, IPV6, UDP, PAY4), + [0xEC] = WX_PTT(IP, IPV6, IGM, IPV6, TCP, PAY4), + [0xED] = WX_PTT(IP, IPV6, IGM, IPV6, SCTP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC--> NONE/IPv */ + [0xF0] = WX_PTT(IP, IPV6, IGMV, NONE, NONE, PAY3), + [0xF1] = WX_PTT(IP, IPV6, IGMV, FGV4, NONE, PAY3), + [0xF2] = WX_PTT(IP, IPV6, IGMV, IPV4, NONE, PAY3), + [0xF3] = WX_PTT(IP, IPV6, IGMV, IPV4, UDP, PAY4), + [0xF4] = WX_PTT(IP, IPV6, IGMV, IPV4, TCP, PAY4), + [0xF5] = WX_PTT(IP, IPV6, IGMV, IPV4, SCTP, PAY4), + [0xF9] = WX_PTT(IP, IPV6, IGMV, FGV6, NONE, PAY3), + [0xFA] = WX_PTT(IP, IPV6, IGMV, IPV6, NONE, PAY3), + [0xFB] = WX_PTT(IP, IPV6, IGMV, IPV6, UDP, PAY4), + [0xFC] = WX_PTT(IP, IPV6, IGMV, IPV6, TCP, PAY4), + [0xFD] = WX_PTT(IP, IPV6, IGMV, IPV6, SCTP, PAY4), +}; + +static struct wx_dec_ptype wx_decode_ptype(const u8 ptype) +{ + return wx_ptype_lookup[ptype]; +} + /* wx_test_staterr - tests bits in Rx descriptor status and error fields */ static __le32 wx_test_staterr(union wx_rx_desc *rx_desc, const u32 stat_err_bits) @@ -424,6 +562,98 @@ static bool wx_cleanup_headers(struct wx_ring *rx_ring, return false; } +static void wx_rx_hash(struct wx_ring *ring, + union wx_rx_desc *rx_desc, + struct sk_buff *skb) +{ + u16 rss_type; + + if (!(ring->netdev->features & NETIF_F_RXHASH)) + return; + + rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) & + WX_RXD_RSSTYPE_MASK; + + if (!rss_type) + return; + + skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), + (WX_RSS_L4_TYPES_MASK & (1ul << rss_type)) ? + PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); +} + +/** + * wx_rx_checksum - indicate in skb if hw indicated a good cksum + * @ring: structure containing ring specific data + * @rx_desc: current Rx descriptor being processed + * @skb: skb currently being received and modified + **/ +static void wx_rx_checksum(struct wx_ring *ring, + union wx_rx_desc *rx_desc, + struct sk_buff *skb) +{ + struct wx_dec_ptype dptype = wx_decode_ptype(WX_RXD_PKTTYPE(rx_desc)); + + skb_checksum_none_assert(skb); + /* Rx csum disabled */ + if (!(ring->netdev->features & NETIF_F_RXCSUM)) + return; + + /* if IPv4 header checksum error */ + if ((wx_test_staterr(rx_desc, WX_RXD_STAT_IPCS) && + wx_test_staterr(rx_desc, WX_RXD_ERR_IPE)) || + (wx_test_staterr(rx_desc, WX_RXD_STAT_OUTERIPCS) && + wx_test_staterr(rx_desc, WX_RXD_ERR_OUTERIPER))) { + ring->rx_stats.csum_err++; + return; + } + + /* L4 checksum offload flag must set for the below code to work */ + if (!wx_test_staterr(rx_desc, WX_RXD_STAT_L4CS)) + return; + + /* Hardware can't guarantee csum if IPv6 Dest Header found */ + if (dptype.prot != WX_DEC_PTYPE_PROT_SCTP && WX_RXD_IPV6EX(rx_desc)) + return; + + /* if L4 checksum error */ + if (wx_test_staterr(rx_desc, WX_RXD_ERR_TCPE)) { + ring->rx_stats.csum_err++; + return; + } + + /* It must be a TCP or UDP or SCTP packet with a valid checksum */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* If there is an outer header present that might contain a checksum + * we need to bump the checksum level by 1 to reflect the fact that + * we are indicating we validated the inner checksum. + */ + if (dptype.etype >= WX_DEC_PTYPE_ETYPE_IG) + __skb_incr_checksum_unnecessary(skb); + ring->rx_stats.csum_good_cnt++; +} + +/** + * wx_process_skb_fields - Populate skb header fields from Rx descriptor + * @rx_ring: rx descriptor ring packet is being transacted on + * @rx_desc: pointer to the EOP Rx descriptor + * @skb: pointer to current skb being populated + * + * This function checks the ring, descriptor, and packet information in + * order to populate the hash, checksum, protocol, and + * other fields within the skb. + **/ +static void wx_process_skb_fields(struct wx_ring *rx_ring, + union wx_rx_desc *rx_desc, + struct sk_buff *skb) +{ + wx_rx_hash(rx_ring, rx_desc, skb); + wx_rx_checksum(rx_ring, rx_desc, skb); + skb_record_rx_queue(skb, rx_ring->queue_index); + skb->protocol = eth_type_trans(skb, rx_ring->netdev); +} + /** * wx_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf * @q_vector: structure containing interrupt and ring information @@ -491,8 +721,8 @@ static int wx_clean_rx_irq(struct wx_q_vector *q_vector, /* probably a little skewed due to removing CRC */ total_rx_bytes += skb->len; - skb_record_rx_queue(skb, rx_ring->queue_index); - skb->protocol = eth_type_trans(skb, rx_ring->netdev); + /* populate checksum, timestamp, VLAN, and protocol */ + wx_process_skb_fields(rx_ring, rx_desc, skb); napi_gro_receive(&q_vector->napi, skb); /* update budget accounting */ diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 9d549dc49dfd..2c1fd0f1025d 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -321,9 +321,31 @@ /******************* Receive Descriptor bit definitions **********************/ #define WX_RXD_STAT_DD BIT(0) /* Done */ #define WX_RXD_STAT_EOP BIT(1) /* End of Packet */ +#define WX_RXD_STAT_L4CS BIT(7) /* L4 xsum calculated */ +#define WX_RXD_STAT_IPCS BIT(8) /* IP xsum calculated */ +#define WX_RXD_STAT_OUTERIPCS BIT(10) /* Cloud IP xsum calculated*/ +#define WX_RXD_ERR_OUTERIPER BIT(26) /* CRC IP Header error */ #define WX_RXD_ERR_RXE BIT(29) /* Any MAC Error */ - +#define WX_RXD_ERR_TCPE BIT(30) /* TCP/UDP Checksum Error */ +#define WX_RXD_ERR_IPE BIT(31) /* IP Checksum Error */ + +/* RSS Hash results */ +#define WX_RXD_RSSTYPE_MASK GENMASK(3, 0) +#define WX_RXD_RSSTYPE_IPV4_TCP 0x00000001U +#define WX_RXD_RSSTYPE_IPV6_TCP 0x00000003U +#define WX_RXD_RSSTYPE_IPV4_SCTP 0x00000004U +#define WX_RXD_RSSTYPE_IPV6_SCTP 0x00000006U +#define WX_RXD_RSSTYPE_IPV4_UDP 0x00000007U +#define WX_RXD_RSSTYPE_IPV6_UDP 0x00000008U + +#define WX_RSS_L4_TYPES_MASK \ + ((1ul << WX_RXD_RSSTYPE_IPV4_TCP) | \ + (1ul << WX_RXD_RSSTYPE_IPV4_UDP) | \ + (1ul << WX_RXD_RSSTYPE_IPV4_SCTP) | \ + (1ul << WX_RXD_RSSTYPE_IPV6_TCP) | \ + (1ul << WX_RXD_RSSTYPE_IPV6_UDP) | \ + (1ul << WX_RXD_RSSTYPE_IPV6_SCTP)) /* TUN */ #define WX_PTYPE_TUN_IPV4 0x80 #define WX_PTYPE_TUN_IPV6 0xC0 @@ -347,6 +369,10 @@ #define WX_PTYPE_TYP_TCP 0x04 #define WX_PTYPE_TYP_SCTP 0x05 +#define WX_RXD_PKTTYPE(_rxd) \ + ((le32_to_cpu((_rxd)->wb.lower.lo_dword.data) >> 9) & 0xFF) +#define WX_RXD_IPV6EX(_rxd) \ + ((le32_to_cpu((_rxd)->wb.lower.lo_dword.data) >> 6) & 0x1) /*********************** Transmit Descriptor Config Masks ****************/ #define WX_TXD_STAT_DD BIT(0) /* Descriptor Done */ #define WX_TXD_DTYP_DATA 0 /* Adv Data Descriptor */ @@ -398,6 +424,70 @@ enum wx_tx_flags { #define WX_TX_FLAGS_VLAN_MASK GENMASK(31, 16) #define WX_TX_FLAGS_VLAN_SHIFT 16 +/* wx_dec_ptype.mac: outer mac */ +enum wx_dec_ptype_mac { + WX_DEC_PTYPE_MAC_IP = 0, + WX_DEC_PTYPE_MAC_L2 = 2, + WX_DEC_PTYPE_MAC_FCOE = 3, +}; + +/* wx_dec_ptype.[e]ip: outer&encaped ip */ +#define WX_DEC_PTYPE_IP_FRAG 0x4 +enum wx_dec_ptype_ip { + WX_DEC_PTYPE_IP_NONE = 0, + WX_DEC_PTYPE_IP_IPV4 = 1, + WX_DEC_PTYPE_IP_IPV6 = 2, + WX_DEC_PTYPE_IP_FGV4 = WX_DEC_PTYPE_IP_FRAG | WX_DEC_PTYPE_IP_IPV4, + WX_DEC_PTYPE_IP_FGV6 = WX_DEC_PTYPE_IP_FRAG | WX_DEC_PTYPE_IP_IPV6, +}; + +/* wx_dec_ptype.etype: encaped type */ +enum wx_dec_ptype_etype { + WX_DEC_PTYPE_ETYPE_NONE = 0, + WX_DEC_PTYPE_ETYPE_IPIP = 1, /* IP+IP */ + WX_DEC_PTYPE_ETYPE_IG = 2, /* IP+GRE */ + WX_DEC_PTYPE_ETYPE_IGM = 3, /* IP+GRE+MAC */ + WX_DEC_PTYPE_ETYPE_IGMV = 4, /* IP+GRE+MAC+VLAN */ +}; + +/* wx_dec_ptype.proto: payload proto */ +enum wx_dec_ptype_prot { + WX_DEC_PTYPE_PROT_NONE = 0, + WX_DEC_PTYPE_PROT_UDP = 1, + WX_DEC_PTYPE_PROT_TCP = 2, + WX_DEC_PTYPE_PROT_SCTP = 3, + WX_DEC_PTYPE_PROT_ICMP = 4, + WX_DEC_PTYPE_PROT_TS = 5, /* time sync */ +}; + +/* wx_dec_ptype.layer: payload layer */ +enum wx_dec_ptype_layer { + WX_DEC_PTYPE_LAYER_NONE = 0, + WX_DEC_PTYPE_LAYER_PAY2 = 1, + WX_DEC_PTYPE_LAYER_PAY3 = 2, + WX_DEC_PTYPE_LAYER_PAY4 = 3, +}; + +struct wx_dec_ptype { + u32 known:1; + u32 mac:2; /* outer mac */ + u32 ip:3; /* outer ip*/ + u32 etype:3; /* encaped type */ + u32 eip:3; /* encaped ip */ + u32 prot:4; /* payload proto */ + u32 layer:3; /* payload layer */ +}; + +/* macro to make the table lines short */ +#define WX_PTT(mac, ip, etype, eip, proto, layer)\ + {1, \ + WX_DEC_PTYPE_MAC_##mac, /* mac */\ + WX_DEC_PTYPE_IP_##ip, /* ip */ \ + WX_DEC_PTYPE_ETYPE_##etype, /* etype */\ + WX_DEC_PTYPE_IP_##eip, /* eip */\ + WX_DEC_PTYPE_PROT_##proto, /* proto */\ + WX_DEC_PTYPE_LAYER_##layer /* layer */} + /* Host Interface Command Structures */ struct wx_hic_hdr { u8 cmd; @@ -620,6 +710,11 @@ struct wx_queue_stats { u64 bytes; }; +struct wx_rx_queue_stats { + u64 csum_good_cnt; + u64 csum_err; +}; + /* iterator for handling rings in ring container */ #define wx_for_each_ring(posm, headm) \ for (posm = (headm).ring; posm; posm = posm->next) @@ -661,6 +756,9 @@ struct wx_ring { struct wx_queue_stats stats; struct u64_stats_sync syncp; + union { + struct wx_rx_queue_stats rx_stats; + }; } ____cacheline_internodealigned_in_smp; struct wx_q_vector { -- cgit v1.2.3 From f3b03c655f67834cb25174ac6f2b099c9e68c74d Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 30 May 2023 10:26:27 +0800 Subject: net: wangxun: Implement vlan add and kill functions Implement vlan add/kill functions which add and remove vlan id in hardware. Signed-off-by: Mengyuan Lou Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_hw.c | 272 ++++++++++++++++++++++++++- drivers/net/ethernet/wangxun/libwx/wx_hw.h | 3 + drivers/net/ethernet/wangxun/libwx/wx_lib.c | 18 ++ drivers/net/ethernet/wangxun/libwx/wx_type.h | 25 ++- 4 files changed, 316 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c index ca409b4054d0..39a9aeee7aab 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c @@ -1182,12 +1182,28 @@ static void wx_enable_sec_rx_path(struct wx *wx) WX_WRITE_FLUSH(wx); } +static void wx_vlan_strip_control(struct wx *wx, bool enable) +{ + int i, j; + + for (i = 0; i < wx->num_rx_queues; i++) { + struct wx_ring *ring = wx->rx_ring[i]; + + j = ring->reg_idx; + wr32m(wx, WX_PX_RR_CFG(j), WX_PX_RR_CFG_VLAN, + enable ? WX_PX_RR_CFG_VLAN : 0); + } +} + void wx_set_rx_mode(struct net_device *netdev) { struct wx *wx = netdev_priv(netdev); + netdev_features_t features; u32 fctrl, vmolr, vlnctrl; int count; + features = netdev->features; + /* Check for Promiscuous and All Multicast modes */ fctrl = rd32(wx, WX_PSR_CTL); fctrl &= ~(WX_PSR_CTL_UPE | WX_PSR_CTL_MPE); @@ -1254,6 +1270,13 @@ void wx_set_rx_mode(struct net_device *netdev) wr32(wx, WX_PSR_VLAN_CTL, vlnctrl); wr32(wx, WX_PSR_CTL, fctrl); wr32(wx, WX_PSR_VM_L2CTL(0), vmolr); + + if ((features & NETIF_F_HW_VLAN_CTAG_RX) && + (features & NETIF_F_HW_VLAN_STAG_RX)) + wx_vlan_strip_control(wx, true); + else + wx_vlan_strip_control(wx, false); + } EXPORT_SYMBOL(wx_set_rx_mode); @@ -1462,6 +1485,16 @@ static void wx_configure_tx(struct wx *wx) WX_MAC_TX_CFG_TE, WX_MAC_TX_CFG_TE); } +static void wx_restore_vlan(struct wx *wx) +{ + u16 vid = 1; + + wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), 0); + + for_each_set_bit_from(vid, wx->active_vlans, VLAN_N_VID) + wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), vid); +} + /** * wx_configure_rx - Configure Receive Unit after Reset * @wx: pointer to private structure @@ -1527,7 +1560,7 @@ void wx_configure(struct wx *wx) wx_configure_port(wx); wx_set_rx_mode(wx->netdev); - + wx_restore_vlan(wx); wx_enable_sec_rx_path(wx); wx_configure_tx(wx); @@ -1727,4 +1760,241 @@ int wx_sw_init(struct wx *wx) } EXPORT_SYMBOL(wx_sw_init); +/** + * wx_find_vlvf_slot - find the vlanid or the first empty slot + * @wx: pointer to hardware structure + * @vlan: VLAN id to write to VLAN filter + * + * return the VLVF index where this VLAN id should be placed + * + **/ +static int wx_find_vlvf_slot(struct wx *wx, u32 vlan) +{ + u32 bits = 0, first_empty_slot = 0; + int regindex; + + /* short cut the special case */ + if (vlan == 0) + return 0; + + /* Search for the vlan id in the VLVF entries. Save off the first empty + * slot found along the way + */ + for (regindex = 1; regindex < WX_PSR_VLAN_SWC_ENTRIES; regindex++) { + wr32(wx, WX_PSR_VLAN_SWC_IDX, regindex); + bits = rd32(wx, WX_PSR_VLAN_SWC); + if (!bits && !(first_empty_slot)) + first_empty_slot = regindex; + else if ((bits & 0x0FFF) == vlan) + break; + } + + if (regindex >= WX_PSR_VLAN_SWC_ENTRIES) { + if (first_empty_slot) + regindex = first_empty_slot; + else + regindex = -ENOMEM; + } + + return regindex; +} + +/** + * wx_set_vlvf - Set VLAN Pool Filter + * @wx: pointer to hardware structure + * @vlan: VLAN id to write to VLAN filter + * @vind: VMDq output index that maps queue to VLAN id in VFVFB + * @vlan_on: boolean flag to turn on/off VLAN in VFVF + * @vfta_changed: pointer to boolean flag which indicates whether VFTA + * should be changed + * + * Turn on/off specified bit in VLVF table. + **/ +static int wx_set_vlvf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on, + bool *vfta_changed) +{ + int vlvf_index; + u32 vt, bits; + + /* If VT Mode is set + * Either vlan_on + * make sure the vlan is in VLVF + * set the vind bit in the matching VLVFB + * Or !vlan_on + * clear the pool bit and possibly the vind + */ + vt = rd32(wx, WX_CFG_PORT_CTL); + if (!(vt & WX_CFG_PORT_CTL_NUM_VT_MASK)) + return 0; + + vlvf_index = wx_find_vlvf_slot(wx, vlan); + if (vlvf_index < 0) + return vlvf_index; + + wr32(wx, WX_PSR_VLAN_SWC_IDX, vlvf_index); + if (vlan_on) { + /* set the pool bit */ + if (vind < 32) { + bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L); + bits |= (1 << vind); + wr32(wx, WX_PSR_VLAN_SWC_VM_L, bits); + } else { + bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H); + bits |= (1 << (vind - 32)); + wr32(wx, WX_PSR_VLAN_SWC_VM_H, bits); + } + } else { + /* clear the pool bit */ + if (vind < 32) { + bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L); + bits &= ~(1 << vind); + wr32(wx, WX_PSR_VLAN_SWC_VM_L, bits); + bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_H); + } else { + bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H); + bits &= ~(1 << (vind - 32)); + wr32(wx, WX_PSR_VLAN_SWC_VM_H, bits); + bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_L); + } + } + + if (bits) { + wr32(wx, WX_PSR_VLAN_SWC, (WX_PSR_VLAN_SWC_VIEN | vlan)); + if (!vlan_on && vfta_changed) + *vfta_changed = false; + } else { + wr32(wx, WX_PSR_VLAN_SWC, 0); + } + + return 0; +} + +/** + * wx_set_vfta - Set VLAN filter table + * @wx: pointer to hardware structure + * @vlan: VLAN id to write to VLAN filter + * @vind: VMDq output index that maps queue to VLAN id in VFVFB + * @vlan_on: boolean flag to turn on/off VLAN in VFVF + * + * Turn on/off specified VLAN in the VLAN filter table. + **/ +static int wx_set_vfta(struct wx *wx, u32 vlan, u32 vind, bool vlan_on) +{ + u32 bitindex, vfta, targetbit; + bool vfta_changed = false; + int regindex, ret; + + /* this is a 2 part operation - first the VFTA, then the + * VLVF and VLVFB if VT Mode is set + * We don't write the VFTA until we know the VLVF part succeeded. + */ + + /* Part 1 + * The VFTA is a bitstring made up of 128 32-bit registers + * that enable the particular VLAN id, much like the MTA: + * bits[11-5]: which register + * bits[4-0]: which bit in the register + */ + regindex = (vlan >> 5) & 0x7F; + bitindex = vlan & 0x1F; + targetbit = (1 << bitindex); + /* errata 5 */ + vfta = wx->mac.vft_shadow[regindex]; + if (vlan_on) { + if (!(vfta & targetbit)) { + vfta |= targetbit; + vfta_changed = true; + } + } else { + if ((vfta & targetbit)) { + vfta &= ~targetbit; + vfta_changed = true; + } + } + /* Part 2 + * Call wx_set_vlvf to set VLVFB and VLVF + */ + ret = wx_set_vlvf(wx, vlan, vind, vlan_on, &vfta_changed); + if (ret != 0) + return ret; + + if (vfta_changed) + wr32(wx, WX_PSR_VLAN_TBL(regindex), vfta); + wx->mac.vft_shadow[regindex] = vfta; + + return 0; +} + +/** + * wx_clear_vfta - Clear VLAN filter table + * @wx: pointer to hardware structure + * + * Clears the VLAN filer table, and the VMDq index associated with the filter + **/ +static void wx_clear_vfta(struct wx *wx) +{ + u32 offset; + + for (offset = 0; offset < wx->mac.vft_size; offset++) { + wr32(wx, WX_PSR_VLAN_TBL(offset), 0); + wx->mac.vft_shadow[offset] = 0; + } + + for (offset = 0; offset < WX_PSR_VLAN_SWC_ENTRIES; offset++) { + wr32(wx, WX_PSR_VLAN_SWC_IDX, offset); + wr32(wx, WX_PSR_VLAN_SWC, 0); + wr32(wx, WX_PSR_VLAN_SWC_VM_L, 0); + wr32(wx, WX_PSR_VLAN_SWC_VM_H, 0); + } +} + +int wx_vlan_rx_add_vid(struct net_device *netdev, + __be16 proto, u16 vid) +{ + struct wx *wx = netdev_priv(netdev); + + /* add VID to filter table */ + wx_set_vfta(wx, vid, VMDQ_P(0), true); + set_bit(vid, wx->active_vlans); + + return 0; +} +EXPORT_SYMBOL(wx_vlan_rx_add_vid); + +int wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) +{ + struct wx *wx = netdev_priv(netdev); + + /* remove VID from filter table */ + if (vid) + wx_set_vfta(wx, vid, VMDQ_P(0), false); + clear_bit(vid, wx->active_vlans); + + return 0; +} +EXPORT_SYMBOL(wx_vlan_rx_kill_vid); + +/** + * wx_start_hw - Prepare hardware for Tx/Rx + * @wx: pointer to hardware structure + * + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. + **/ +void wx_start_hw(struct wx *wx) +{ + int i; + + /* Clear the VLAN filter table */ + wx_clear_vfta(wx); + WX_WRITE_FLUSH(wx); + /* Clear the rate limiters */ + for (i = 0; i < wx->mac.max_tx_queues; i++) { + wr32(wx, WX_TDM_RP_IDX, i); + wr32(wx, WX_TDM_RP_RATE, 0); + } +} +EXPORT_SYMBOL(wx_start_hw); + MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h index c173c56f0ab5..1f93ca32c921 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h @@ -26,10 +26,13 @@ void wx_set_rx_mode(struct net_device *netdev); int wx_change_mtu(struct net_device *netdev, int new_mtu); void wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring); void wx_configure(struct wx *wx); +void wx_start_hw(struct wx *wx); int wx_disable_pcie_master(struct wx *wx); int wx_stop_adapter(struct wx *wx); void wx_reset_misc(struct wx *wx); int wx_get_pcie_msix_counts(struct wx *wx, u16 *msix_count, u16 max_msix_count); int wx_sw_init(struct wx *wx); +int wx_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid); +int wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid); #endif /* _WX_HW_H_ */ diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 84107208401e..680f1ad36240 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -634,6 +634,23 @@ static void wx_rx_checksum(struct wx_ring *ring, ring->rx_stats.csum_good_cnt++; } +static void wx_rx_vlan(struct wx_ring *ring, union wx_rx_desc *rx_desc, + struct sk_buff *skb) +{ + u16 ethertype; + u8 idx = 0; + + if ((ring->netdev->features & + (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX)) && + wx_test_staterr(rx_desc, WX_RXD_STAT_VP)) { + idx = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) & + 0x1c0) >> 6; + ethertype = ring->q_vector->wx->tpid[idx]; + __vlan_hwaccel_put_tag(skb, htons(ethertype), + le16_to_cpu(rx_desc->wb.upper.vlan)); + } +} + /** * wx_process_skb_fields - Populate skb header fields from Rx descriptor * @rx_ring: rx descriptor ring packet is being transacted on @@ -650,6 +667,7 @@ static void wx_process_skb_fields(struct wx_ring *rx_ring, { wx_rx_hash(rx_ring, rx_desc, skb); wx_rx_checksum(rx_ring, rx_desc, skb); + wx_rx_vlan(rx_ring, rx_desc, skb); skb_record_rx_queue(skb, rx_ring->queue_index); skb->protocol = eth_type_trans(skb, rx_ring->netdev); } diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 2c1fd0f1025d..91b2e4bfa206 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -6,6 +6,7 @@ #include #include +#include #include #define WX_NCSI_SUP 0x8000 @@ -65,6 +66,8 @@ #define WX_CFG_PORT_CTL_QINQ BIT(2) #define WX_CFG_PORT_CTL_D_VLAN BIT(0) /* double vlan*/ #define WX_CFG_TAG_TPID(_i) (0x14430 + ((_i) * 4)) +#define WX_CFG_PORT_CTL_NUM_VT_MASK GENMASK(13, 12) /* number of TVs */ + /* GPIO Registers */ #define WX_GPIO_DR 0x14800 @@ -88,6 +91,8 @@ /* TDM CTL BIT */ #define WX_TDM_CTL_TE BIT(0) /* Transmit Enable */ #define WX_TDM_PB_THRE(_i) (0x18020 + ((_i) * 4)) +#define WX_TDM_RP_IDX 0x1820C +#define WX_TDM_RP_RATE 0x18404 /***************************** RDB registers *********************************/ /* receive packet buffer */ @@ -151,6 +156,9 @@ #define WX_PSR_LAN_FLEX_DW_H(_i) (0x15C04 + ((_i) * 16)) #define WX_PSR_LAN_FLEX_MSK(_i) (0x15C08 + ((_i) * 16)) +/* vlan tbl */ +#define WX_PSR_VLAN_TBL(_i) (0x16000 + ((_i) * 4)) + /* mac switcher */ #define WX_PSR_MAC_SWC_AD_L 0x16200 #define WX_PSR_MAC_SWC_AD_H 0x16204 @@ -162,6 +170,15 @@ #define WX_PSR_MAC_SWC_IDX 0x16210 #define WX_CLEAR_VMDQ_ALL 0xFFFFFFFFU +/* vlan switch */ +#define WX_PSR_VLAN_SWC 0x16220 +#define WX_PSR_VLAN_SWC_VM_L 0x16224 +#define WX_PSR_VLAN_SWC_VM_H 0x16228 +#define WX_PSR_VLAN_SWC_IDX 0x16230 /* 64 vlan entries */ +/* VLAN pool filtering masks */ +#define WX_PSR_VLAN_SWC_VIEN BIT(31) /* filter is valid */ +#define WX_PSR_VLAN_SWC_ENTRIES 64 + /********************************* RSEC **************************************/ /* general rsec */ #define WX_RSC_CTL 0x17000 @@ -256,6 +273,7 @@ #define WX_PX_RR_RP(_i) (0x0100C + ((_i) * 0x40)) #define WX_PX_RR_CFG(_i) (0x01010 + ((_i) * 0x40)) /* PX_RR_CFG bit definitions */ +#define WX_PX_RR_CFG_VLAN BIT(31) #define WX_PX_RR_CFG_SPLIT_MODE BIT(26) #define WX_PX_RR_CFG_RR_THER_SHIFT 16 #define WX_PX_RR_CFG_RR_HDR_SZ GENMASK(15, 12) @@ -297,6 +315,7 @@ #define WX_MAX_TXD 8192 #define WX_MAX_JUMBO_FRAME_SIZE 9432 /* max payload 9414 */ +#define VMDQ_P(p) p /* Supported Rx Buffer Sizes */ #define WX_RXBUFFER_256 256 /* Used for skb receive header */ @@ -321,6 +340,7 @@ /******************* Receive Descriptor bit definitions **********************/ #define WX_RXD_STAT_DD BIT(0) /* Done */ #define WX_RXD_STAT_EOP BIT(1) /* End of Packet */ +#define WX_RXD_STAT_VP BIT(5) /* IEEE VLAN Pkt */ #define WX_RXD_STAT_L4CS BIT(7) /* L4 xsum calculated */ #define WX_RXD_STAT_IPCS BIT(8) /* IP xsum calculated */ #define WX_RXD_STAT_OUTERIPCS BIT(10) /* Cloud IP xsum calculated*/ @@ -566,6 +586,8 @@ struct wx_mac_info { u32 mta_shadow[128]; s32 mc_filter_type; u32 mcft_size; + u32 vft_shadow[128]; + u32 vft_size; u32 num_rar_entries; u32 rx_pb_size; u32 tx_pb_size; @@ -726,7 +748,6 @@ struct wx_ring_container { u8 count; /* total number of rings in vector */ u8 itr; /* current ITR setting for ring */ }; - struct wx_ring { struct wx_ring *next; /* pointer to next ring in q_vector */ struct wx_q_vector *q_vector; /* backpointer to host q_vector */ @@ -789,6 +810,8 @@ enum wx_isb_idx { }; struct wx { + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; + u8 __iomem *hw_addr; struct pci_dev *pdev; struct net_device *netdev; -- cgit v1.2.3 From 6dbedcffcf543afe1297f86fd6620327482a3a98 Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 30 May 2023 10:26:28 +0800 Subject: net: libwx: Implement xx_set_features ops Implement wx_set_features function which to support ndo_set_features. Signed-off-by: Mengyuan Lou Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/libwx/wx_lib.c | 20 ++++++++++++++++++++ drivers/net/ethernet/wangxun/libwx/wx_lib.h | 1 + drivers/net/ethernet/wangxun/libwx/wx_type.h | 2 ++ 3 files changed, 23 insertions(+) diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 680f1ad36240..3dd328d33fcc 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -2704,4 +2704,24 @@ void wx_get_stats64(struct net_device *netdev, } EXPORT_SYMBOL(wx_get_stats64); +int wx_set_features(struct net_device *netdev, netdev_features_t features) +{ + netdev_features_t changed = netdev->features ^ features; + struct wx *wx = netdev_priv(netdev); + + if (changed & NETIF_F_RXHASH) + wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN, + WX_RDB_RA_CTL_RSS_EN); + else + wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN, 0); + + if (changed & + (NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_STAG_RX)) + wx_set_rx_mode(netdev); + + return 1; +} +EXPORT_SYMBOL(wx_set_features); + MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_lib.h index 50ee41f1fa10..df1f4a5951f0 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.h @@ -28,5 +28,6 @@ void wx_free_resources(struct wx *wx); int wx_setup_resources(struct wx *wx); void wx_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats); +int wx_set_features(struct net_device *netdev, netdev_features_t features); #endif /* _NGBE_LIB_H_ */ diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 91b2e4bfa206..5063846e1b52 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -111,6 +111,8 @@ #define WX_RDB_PL_CFG_L2HDR BIT(3) #define WX_RDB_PL_CFG_TUN_TUNHDR BIT(4) #define WX_RDB_PL_CFG_TUN_OUTL2HDR BIT(5) +#define WX_RDB_RA_CTL 0x194F4 +#define WX_RDB_RA_CTL_RSS_EN BIT(2) /* RSS Enable */ /******************************* PSR Registers *******************************/ /* psr control */ -- cgit v1.2.3 From 50a908a0bd8b9e589fcdcc26f2acd57a253eca8d Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 30 May 2023 10:26:29 +0800 Subject: net: ngbe: Add netdev features support Add features and hw_features that ngbe can support. Signed-off-by: Mengyuan Lou Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c index df6b870aa871..f234c9c4b942 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c @@ -473,6 +473,7 @@ static const struct net_device_ops ngbe_netdev_ops = { .ndo_change_mtu = wx_change_mtu, .ndo_start_xmit = wx_xmit_frame, .ndo_set_rx_mode = wx_set_rx_mode, + .ndo_set_features = wx_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = wx_set_mac, .ndo_get_stats64 = wx_get_stats64, @@ -551,12 +552,18 @@ static int ngbe_probe(struct pci_dev *pdev, ngbe_set_ethtool_ops(netdev); netdev->netdev_ops = &ngbe_netdev_ops; - netdev->features |= NETIF_F_HIGHDMA; - netdev->features = NETIF_F_SG; - + netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_RXHASH | NETIF_F_RXCSUM; + netdev->features |= NETIF_F_SCTP_CRC | NETIF_F_TSO_MANGLEID; + netdev->vlan_features |= netdev->features; + netdev->features |= NETIF_F_IPV6_CSUM | NETIF_F_VLAN_FEATURES; /* copy netdev features into list of user selectable features */ - netdev->hw_features |= netdev->features | - NETIF_F_RXALL; + netdev->hw_features |= netdev->features | NETIF_F_RXALL; + netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC; + netdev->features |= NETIF_F_HIGHDMA; + netdev->hw_features |= NETIF_F_GRO; + netdev->features |= NETIF_F_GRO; netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; -- cgit v1.2.3 From 361bf4f47cee800b9740d8e1f8ba73ccc248a934 Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 30 May 2023 10:26:30 +0800 Subject: net: ngbe: Implement vlan add and remove ops ngbe add ndo_vlan_rx_add_vid and ndo_vlan_rx_kill_vid. Signed-off-by: Mengyuan Lou Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/ngbe/ngbe_main.c | 3 +++ drivers/net/ethernet/wangxun/ngbe/ngbe_type.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c index f234c9c4b942..c99a5d3de72e 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c @@ -115,6 +115,7 @@ static int ngbe_sw_init(struct wx *wx) wx->mac.max_rx_queues = NGBE_MAX_RX_QUEUES; wx->mac.max_tx_queues = NGBE_MAX_TX_QUEUES; wx->mac.mcft_size = NGBE_MC_TBL_SIZE; + wx->mac.vft_size = NGBE_SP_VFT_TBL_SIZE; wx->mac.rx_pb_size = NGBE_RX_PB_SIZE; wx->mac.tx_pb_size = NGBE_TDB_PB_SZ; @@ -477,6 +478,8 @@ static const struct net_device_ops ngbe_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = wx_set_mac, .ndo_get_stats64 = wx_get_stats64, + .ndo_vlan_rx_add_vid = wx_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = wx_vlan_rx_kill_vid, }; /** diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h index 373d5af628cd..b70eca397b67 100644 --- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h +++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h @@ -136,6 +136,7 @@ enum NGBE_MSCA_CMD_value { #define NGBE_RAR_ENTRIES 32 #define NGBE_RX_PB_SIZE 42 #define NGBE_MC_TBL_SIZE 128 +#define NGBE_SP_VFT_TBL_SIZE 128 #define NGBE_TDB_PB_SZ (20 * 1024) /* 160KB Packet Buffer */ /* TX/RX descriptor defines */ -- cgit v1.2.3 From 6670f1ece2c8c069428ed00c8344b8dbbdcf9748 Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 30 May 2023 10:26:31 +0800 Subject: net: txgbe: Add netdev features support Add features and hw_features that ngbe can support. Signed-off-by: Mengyuan Lou Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 5b8a121fb496..bcc9c2959177 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -491,6 +491,7 @@ static const struct net_device_ops txgbe_netdev_ops = { .ndo_change_mtu = wx_change_mtu, .ndo_start_xmit = wx_xmit_frame, .ndo_set_rx_mode = wx_set_rx_mode, + .ndo_set_features = wx_set_features, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = wx_set_mac, .ndo_get_stats64 = wx_get_stats64, @@ -596,11 +597,25 @@ static int txgbe_probe(struct pci_dev *pdev, goto err_free_mac_table; } - netdev->features |= NETIF_F_HIGHDMA; - netdev->features = NETIF_F_SG; - + netdev->features = NETIF_F_SG | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_RXHASH | + NETIF_F_RXCSUM | + NETIF_F_HW_CSUM; + + netdev->gso_partial_features = NETIF_F_GSO_ENCAP_ALL; + netdev->features |= netdev->gso_partial_features; + netdev->features |= NETIF_F_SCTP_CRC; + netdev->vlan_features |= netdev->features | NETIF_F_TSO_MANGLEID; + netdev->hw_enc_features |= netdev->vlan_features; + netdev->features |= NETIF_F_VLAN_FEATURES; /* copy netdev features into list of user selectable features */ netdev->hw_features |= netdev->features | NETIF_F_RXALL; + netdev->hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC; + netdev->features |= NETIF_F_HIGHDMA; + netdev->hw_features |= NETIF_F_GRO; + netdev->features |= NETIF_F_GRO; netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; -- cgit v1.2.3 From 7df4af51deb3cf10a23ad6f6ec3079f5af3c049c Mon Sep 17 00:00:00 2001 From: Mengyuan Lou Date: Tue, 30 May 2023 10:26:32 +0800 Subject: net: txgbe: Implement vlan add and remove ops txgbe add ndo_vlan_rx_add_vid and ndo_vlan_rx_kill_vid. Signed-off-by: Mengyuan Lou Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 4 ++++ drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index bcc9c2959177..0f0d9fa1cde1 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -258,6 +258,7 @@ static void txgbe_reset(struct wx *wx) if (err != 0) wx_err(wx, "Hardware Error: %d\n", err); + wx_start_hw(wx); /* do not flush user set addresses */ memcpy(old_addr, &wx->mac_table[0].addr, netdev->addr_len); wx_flush_sw_mac_table(wx); @@ -330,6 +331,7 @@ static int txgbe_sw_init(struct wx *wx) wx->mac.max_tx_queues = TXGBE_SP_MAX_TX_QUEUES; wx->mac.max_rx_queues = TXGBE_SP_MAX_RX_QUEUES; wx->mac.mcft_size = TXGBE_SP_MC_TBL_SIZE; + wx->mac.vft_size = TXGBE_SP_VFT_TBL_SIZE; wx->mac.rx_pb_size = TXGBE_SP_RX_PB_SIZE; wx->mac.tx_pb_size = TXGBE_SP_TDB_PB_SZ; @@ -495,6 +497,8 @@ static const struct net_device_ops txgbe_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = wx_set_mac, .ndo_get_stats64 = wx_get_stats64, + .ndo_vlan_rx_add_vid = wx_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = wx_vlan_rx_kill_vid, }; /** diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 63a1c733718d..032972369965 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -77,6 +77,7 @@ #define TXGBE_SP_MAX_RX_QUEUES 128 #define TXGBE_SP_RAR_ENTRIES 128 #define TXGBE_SP_MC_TBL_SIZE 128 +#define TXGBE_SP_VFT_TBL_SIZE 128 #define TXGBE_SP_RX_PB_SIZE 512 #define TXGBE_SP_TDB_PB_SZ (160 * 1024) /* 160KB Packet Buffer */ -- cgit v1.2.3 From 88ca89202f8e8afb5225eb5244d79cd67c15d744 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 26 May 2023 12:41:06 +0300 Subject: wifi: ath11k: add support default regdb while searching board-2.bin for WCN6855 Sometimes board-2.bin does not have the regdb data which matched the parameters such as vendor, device, subsystem-vendor, subsystem-device and etc. Add default regdb data with 'bus=%s' into board-2.bin for WCN6855, then ath11k use 'bus=pci' to search regdb data in board-2.bin for WCN6855. kernel: [ 122.515808] ath11k_pci 0000:03:00.0: boot using board name 'bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262' kernel: [ 122.517240] ath11k_pci 0000:03:00.0: boot firmware request ath11k/WCN6855/hw2.0/board-2.bin size 6179564 kernel: [ 122.517280] ath11k_pci 0000:03:00.0: failed to fetch regdb data for bus=pci,vendor=17cb,device=1103,subsystem-vendor=17cb,subsystem-device=3374,qmi-chip-id=2,qmi-board-id=262 from ath11k/WCN6855/hw2.0/board-2.bin kernel: [ 122.517464] ath11k_pci 0000:03:00.0: boot using board name 'bus=pci' kernel: [ 122.518901] ath11k_pci 0000:03:00.0: boot firmware request ath11k/WCN6855/hw2.0/board-2.bin size 6179564 kernel: [ 122.518915] ath11k_pci 0000:03:00.0: board name kernel: [ 122.518917] ath11k_pci 0000:03:00.0: 00000000: 62 75 73 3d 70 63 69 bus=pci kernel: [ 122.518918] ath11k_pci 0000:03:00.0: boot found match regdb data for name 'bus=pci' kernel: [ 122.518920] ath11k_pci 0000:03:00.0: boot found regdb data for 'bus=pci' kernel: [ 122.518921] ath11k_pci 0000:03:00.0: fetched regdb Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230517133959.8224-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath11k/core.c | 53 +++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index b1b90bd34d67..5648963baeb9 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -961,7 +961,8 @@ int ath11k_core_check_dt(struct ath11k_base *ab) } static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name, - size_t name_len, bool with_variant) + size_t name_len, bool with_variant, + bool bus_type_mode) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; @@ -972,15 +973,20 @@ static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name, switch (ab->id.bdf_search) { case ATH11K_BDF_SEARCH_BUS_AND_BOARD: - scnprintf(name, name_len, - "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s", - ath11k_bus_str(ab->hif.bus), - ab->id.vendor, ab->id.device, - ab->id.subsystem_vendor, - ab->id.subsystem_device, - ab->qmi.target.chip_id, - ab->qmi.target.board_id, - variant); + if (bus_type_mode) + scnprintf(name, name_len, + "bus=%s", + ath11k_bus_str(ab->hif.bus)); + else + scnprintf(name, name_len, + "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s", + ath11k_bus_str(ab->hif.bus), + ab->id.vendor, ab->id.device, + ab->id.subsystem_vendor, + ab->id.subsystem_device, + ab->qmi.target.chip_id, + ab->qmi.target.board_id, + variant); break; default: scnprintf(name, name_len, @@ -999,13 +1005,19 @@ static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name, static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, size_t name_len) { - return __ath11k_core_create_board_name(ab, name, name_len, true); + return __ath11k_core_create_board_name(ab, name, name_len, true, false); } static int ath11k_core_create_fallback_board_name(struct ath11k_base *ab, char *name, size_t name_len) { - return __ath11k_core_create_board_name(ab, name, name_len, false); + return __ath11k_core_create_board_name(ab, name, name_len, false, false); +} + +static int ath11k_core_create_bus_type_board_name(struct ath11k_base *ab, char *name, + size_t name_len) +{ + return __ath11k_core_create_board_name(ab, name, name_len, false, true); } const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, @@ -1309,7 +1321,7 @@ success: int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd) { - char boardname[BOARD_NAME_SIZE]; + char boardname[BOARD_NAME_SIZE], default_boardname[BOARD_NAME_SIZE]; int ret; ret = ath11k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); @@ -1326,6 +1338,21 @@ int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd if (!ret) goto exit; + ret = ath11k_core_create_bus_type_board_name(ab, default_boardname, + BOARD_NAME_SIZE); + if (ret) { + ath11k_dbg(ab, ATH11K_DBG_BOOT, + "failed to create default board name for regdb: %d", ret); + goto exit; + } + + ret = ath11k_core_fetch_board_data_api_n(ab, bd, default_boardname, + ATH11K_BD_IE_REGDB, + ATH11K_BD_IE_REGDB_NAME, + ATH11K_BD_IE_REGDB_DATA); + if (!ret) + goto exit; + ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_REGDB_FILE_NAME); if (ret) ath11k_dbg(ab, ATH11K_DBG_BOOT, "failed to fetch %s from %s\n", -- cgit v1.2.3 From 86f85575a3f6a20cef1c8bb98e78585fe3a53ccc Mon Sep 17 00:00:00 2001 From: Govindaraj Saminathan Date: Fri, 26 May 2023 12:41:06 +0300 Subject: wifi: ath11k: remove unused function ath11k_tm_event_wmi() The function ath11k_tm_event_wmi() is only defined and it is not used anywhere. Hence remove the unused. Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Govindaraj Saminathan Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230517135934.16408-2-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath11k/testmode.c | 64 +----------------------------- drivers/net/wireless/ath/ath11k/testmode.h | 8 +--- 2 files changed, 2 insertions(+), 70 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c index 4bf1931adbaa..ebeca5eb6a67 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.c +++ b/drivers/net/wireless/ath/ath11k/testmode.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "testmode.h" @@ -20,69 +21,6 @@ static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = { [ATH11K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 }, }; -/* Returns true if callee consumes the skb and the skb should be discarded. - * Returns false if skb is not used. Does not sleep. - */ -bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb) -{ - struct sk_buff *nl_skb; - bool consumed; - int ret; - - ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, - "testmode event wmi cmd_id %d skb %pK skb->len %d\n", - cmd_id, skb, skb->len); - - ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len); - - spin_lock_bh(&ar->data_lock); - - consumed = true; - - nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy, - 2 * sizeof(u32) + skb->len, - GFP_ATOMIC); - if (!nl_skb) { - ath11k_warn(ar->ab, - "failed to allocate skb for testmode wmi event\n"); - goto out; - } - - ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI); - if (ret) { - ath11k_warn(ar->ab, - "failed to put testmode wmi event cmd attribute: %d\n", - ret); - kfree_skb(nl_skb); - goto out; - } - - ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id); - if (ret) { - ath11k_warn(ar->ab, - "failed to put testmode wmi even cmd_id: %d\n", - ret); - kfree_skb(nl_skb); - goto out; - } - - ret = nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data); - if (ret) { - ath11k_warn(ar->ab, - "failed to copy skb to testmode wmi event: %d\n", - ret); - kfree_skb(nl_skb); - goto out; - } - - cfg80211_testmode_event(nl_skb, GFP_ATOMIC); - -out: - spin_unlock_bh(&ar->data_lock); - - return consumed; -} - static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[]) { struct sk_buff *skb; diff --git a/drivers/net/wireless/ath/ath11k/testmode.h b/drivers/net/wireless/ath/ath11k/testmode.h index aaa122ed9069..ffdb0c30b276 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.h +++ b/drivers/net/wireless/ath/ath11k/testmode.h @@ -1,24 +1,18 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" #ifdef CONFIG_NL80211_TESTMODE -bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb); int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); #else -static inline bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, - struct sk_buff *skb) -{ - return false; -} - static inline int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len) -- cgit v1.2.3 From b43310e44edc823a7f02af1e1e2b4e8a9abc7d91 Mon Sep 17 00:00:00 2001 From: Govindaraj Saminathan Date: Fri, 26 May 2023 12:41:07 +0300 Subject: wifi: ath11k: factory test mode support Add support to process factory test mode commands (FTM) for calibration. By default firmware start with NORMAL mode and to process the FTM commands firmware needs to be restarted in FTM mode using module parameter ftm_mode. The pre-request is all the radios should be down before starting the test. When start command ATH11K_TM_CMD_TESTMODE_START is received, ar->state is set to Test Mode. If the FTM command or event length is greater than 256 bytes, it will be broken down into multiple segments and encoded with TLV header if it is segmented commands, else it is sent to firmware as it is. On receiving UTF event from firmware, if it is segmented event, the driver will wait until it receives all the segments and notify the complete data to user application. In case the segmented sequence are missed or lost from the firmware, driver will skip the already received partial data. In case of unsegmented UTF event from firmware, driver notifies the data to the user application as it comes. Applications handles the data further. Command to boot in ftm mode: insmod ath11k ftm_mode=1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Govindaraj Saminathan Co-developed-by: Sowmiya Sree Elavalagan Signed-off-by: Sowmiya Sree Elavalagan Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230517135934.16408-4-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath11k/ahb.c | 3 +- drivers/net/wireless/ath/ath11k/core.c | 21 +- drivers/net/wireless/ath/ath11k/core.h | 16 +- drivers/net/wireless/ath/ath11k/debug.h | 1 + drivers/net/wireless/ath/ath11k/mac.c | 11 +- drivers/net/wireless/ath/ath11k/pci.c | 3 +- drivers/net/wireless/ath/ath11k/testmode.c | 350 ++++++++++++++++++++++++++- drivers/net/wireless/ath/ath11k/testmode.h | 6 + drivers/net/wireless/ath/ath11k/testmode_i.h | 18 +- drivers/net/wireless/ath/ath11k/wmi.c | 11 +- drivers/net/wireless/ath/ath11k/wmi.h | 22 ++ drivers/net/wireless/ath/ath11k/wow.c | 3 +- 12 files changed, 444 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 5cbba9a8b6ba..32911fa6e505 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1155,6 +1155,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev) ab->hif.ops = hif_ops; ab->pdev = pdev; ab->hw_rev = hw_rev; + ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL; platform_set_drvdata(pdev, ab); ret = ath11k_pcic_register_pci_ops(ab, pci_ops); diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 5648963baeb9..8a82a4ed0af5 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -32,6 +32,10 @@ module_param_named(frame_mode, ath11k_frame_mode, uint, 0644); MODULE_PARM_DESC(frame_mode, "Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)"); +bool ath11k_ftm_mode; +module_param_named(ftm_mode, ath11k_ftm_mode, bool, 0444); +MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode"); + static const struct ath11k_hw_params ath11k_hw_params[] = { { .hw_rev = ATH11K_HW_IPQ8074, @@ -1381,6 +1385,11 @@ static int ath11k_core_soc_create(struct ath11k_base *ab) { int ret; + if (ath11k_ftm_mode) { + ab->fw_mode = ATH11K_FIRMWARE_MODE_FTM; + ath11k_info(ab, "Booting in factory test mode\n"); + } + ret = ath11k_qmi_init_service(ab); if (ret) { ath11k_err(ab, "failed to initialize qmi :%d\n", ret); @@ -1607,7 +1616,7 @@ int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab) { int ret; - ret = ath11k_core_start_firmware(ab, ATH11K_FIRMWARE_MODE_NORMAL); + ret = ath11k_core_start_firmware(ab, ab->fw_mode); if (ret) { ath11k_err(ab, "failed to start firmware: %d\n", ret); return ret; @@ -1772,7 +1781,8 @@ void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab) for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; - if (!ar || ar->state == ATH11K_STATE_OFF) + if (!ar || ar->state == ATH11K_STATE_OFF || + ar->state == ATH11K_STATE_FTM) continue; ieee80211_stop_queues(ar->hw); @@ -1841,7 +1851,12 @@ static void ath11k_core_post_reconfigure_recovery(struct ath11k_base *ab) ath11k_warn(ab, "device is wedged, will not restart radio %d\n", i); break; + case ATH11K_STATE_FTM: + ath11k_dbg(ab, ATH11K_DBG_TESTMODE, + "fw mode reset done radio %d\n", i); + break; } + mutex_unlock(&ar->conf_mutex); } complete(&ab->driver_recovery); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 0830276e5028..9d15b4390b9c 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_CORE_H @@ -52,6 +52,7 @@ #define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_" extern unsigned int ath11k_frame_mode; +extern bool ath11k_ftm_mode; #define ATH11K_SCAN_TIMEOUT_HZ (20 * HZ) @@ -277,6 +278,7 @@ enum ath11k_dev_flags { ATH11K_FLAG_FIXED_MEM_RGN, ATH11K_FLAG_DEVICE_INIT_DONE, ATH11K_FLAG_MULTI_MSI_VECTORS, + ATH11K_FLAG_FTM_SEGMENTED, }; enum ath11k_monitor_flags { @@ -530,6 +532,7 @@ enum ath11k_state { ATH11K_STATE_RESTARTING, ATH11K_STATE_RESTARTED, ATH11K_STATE_WEDGED, + ATH11K_STATE_FTM, /* Add other states as required */ }; @@ -709,6 +712,8 @@ struct ath11k { u32 last_ppdu_id; u32 cached_ppdu_id; int monitor_vdev_id; + struct completion fw_mode_reset; + u8 ftm_msgref; #ifdef CONFIG_ATH11K_DEBUGFS struct ath11k_debug debug; #endif @@ -838,6 +843,7 @@ struct ath11k_msi_config { /* Master structure to hold the hw data which may be used in core module */ struct ath11k_base { enum ath11k_hw_rev hw_rev; + enum ath11k_firmware_mode fw_mode; struct platform_device *pdev; struct device *dev; struct ath11k_qmi qmi; @@ -978,6 +984,14 @@ struct ath11k_base { const struct ath11k_pci_ops *ops; } pci; +#ifdef CONFIG_NL80211_TESTMODE + struct { + u32 data_pos; + u32 expected_seq; + u8 *eventdata; + } testmode; +#endif + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index 91545640c47b..621d85f3118c 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_DEBUG_H_ diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index c947d1c8d8c1..a31b8e89684b 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -643,7 +643,10 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id) return NULL; for (i = 0; i < ab->num_radios; i++) { - pdev = rcu_dereference(ab->pdevs_active[i]); + if (ab->fw_mode == ATH11K_FIRMWARE_MODE_FTM) + pdev = &ab->pdevs[i]; + else + pdev = rcu_dereference(ab->pdevs_active[i]); if (pdev && pdev->pdev_id == pdev_id) return (pdev->ar ? pdev->ar : NULL); @@ -6271,6 +6274,11 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw) struct ath11k_pdev *pdev = ar->pdev; int ret; + if (ath11k_ftm_mode) { + ath11k_warn(ab, "mac operations not supported in factory test mode\n"); + return -EOPNOTSUPP; + } + ath11k_mac_drain_tx(ar); mutex_lock(&ar->conf_mutex); @@ -6285,6 +6293,7 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw) case ATH11K_STATE_RESTARTED: case ATH11K_STATE_WEDGED: case ATH11K_STATE_ON: + case ATH11K_STATE_FTM: WARN_ON(1); ret = -EINVAL; goto err; diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 7b33731a50ee..5a779abe666b 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -745,6 +745,7 @@ static int ath11k_pci_probe(struct pci_dev *pdev, ab_pci->ab = ab; ab_pci->pdev = pdev; ab->hif.ops = &ath11k_pci_hif_ops; + ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL; pci_set_drvdata(pdev, ab); spin_lock_init(&ab_pci->window_lock); diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c index ebeca5eb6a67..3611b6ec39c6 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.c +++ b/drivers/net/wireless/ath/ath11k/testmode.c @@ -12,6 +12,9 @@ #include "core.h" #include "testmode_i.h" +#define ATH11K_FTM_SEGHDR_CURRENT_SEQ GENMASK(3, 0) +#define ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS GENMASK(7, 4) + static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = { [ATH11K_TM_ATTR_CMD] = { .type = NLA_U32 }, [ATH11K_TM_ATTR_DATA] = { .type = NLA_BINARY, @@ -21,13 +24,217 @@ static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = { [ATH11K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 }, }; +static struct ath11k *ath11k_tm_get_ar(struct ath11k_base *ab) +{ + struct ath11k_pdev *pdev; + struct ath11k *ar = NULL; + int i; + + for (i = 0; i < ab->num_radios; i++) { + pdev = &ab->pdevs[i]; + ar = pdev->ar; + + if (ar && ar->state == ATH11K_STATE_FTM) + break; + } + + return ar; +} + +/* This function handles unsegmented events. Data in various events are aggregated + * in application layer, this event is unsegmented from host perspective. + */ +static void ath11k_tm_wmi_event_unsegmented(struct ath11k_base *ab, u32 cmd_id, + struct sk_buff *skb) +{ + struct sk_buff *nl_skb; + struct ath11k *ar; + + ath11k_dbg(ab, ATH11K_DBG_TESTMODE, + "event wmi cmd_id %d skb length %d\n", + cmd_id, skb->len); + ath11k_dbg_dump(ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len); + + ar = ath11k_tm_get_ar(ab); + if (!ar) { + ath11k_warn(ab, "testmode event not handled due to invalid pdev\n"); + return; + } + + spin_lock_bh(&ar->data_lock); + + nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy, + 2 * nla_total_size(sizeof(u32)) + + nla_total_size(skb->len), + GFP_ATOMIC); + if (!nl_skb) { + ath11k_warn(ab, + "failed to allocate skb for unsegmented testmode wmi event\n"); + goto out; + } + + if (nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI) || + nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id) || + nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data)) { + ath11k_warn(ab, "failed to populate testmode unsegmented event\n"); + kfree_skb(nl_skb); + goto out; + } + + cfg80211_testmode_event(nl_skb, GFP_ATOMIC); + spin_unlock_bh(&ar->data_lock); + return; + +out: + spin_unlock_bh(&ar->data_lock); + ath11k_warn(ab, "Failed to send testmode event to higher layers\n"); +} + +/* This function handles segmented events. Data of various events received + * from firmware is aggregated and sent to application layer + */ +static int ath11k_tm_process_event(struct ath11k_base *ab, u32 cmd_id, + const struct wmi_ftm_event_msg *ftm_msg, + u16 length) +{ + struct sk_buff *nl_skb; + int ret = 0; + struct ath11k *ar; + u8 const *buf_pos; + u16 datalen; + u8 total_segments, current_seq; + u32 data_pos; + u32 pdev_id; + + ath11k_dbg(ab, ATH11K_DBG_TESTMODE, + "event wmi cmd_id %d ftm event msg %pK datalen %d\n", + cmd_id, ftm_msg, length); + ath11k_dbg_dump(ab, ATH11K_DBG_TESTMODE, NULL, "", ftm_msg, length); + pdev_id = DP_HW2SW_MACID(ftm_msg->seg_hdr.pdev_id); + + if (pdev_id >= ab->num_radios) { + ath11k_warn(ab, "testmode event not handled due to invalid pdev id: %d\n", + pdev_id); + return -EINVAL; + } + + ar = ab->pdevs[pdev_id].ar; + if (!ar) { + ath11k_warn(ab, "testmode event not handled due to absence of pdev\n"); + return -ENODEV; + } + + current_seq = FIELD_GET(ATH11K_FTM_SEGHDR_CURRENT_SEQ, + ftm_msg->seg_hdr.segmentinfo); + total_segments = FIELD_GET(ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS, + ftm_msg->seg_hdr.segmentinfo); + datalen = length - (sizeof(struct wmi_ftm_seg_hdr)); + buf_pos = ftm_msg->data; + + spin_lock_bh(&ar->data_lock); + + if (current_seq == 0) { + ab->testmode.expected_seq = 0; + ab->testmode.data_pos = 0; + } + + data_pos = ab->testmode.data_pos; + + if ((data_pos + datalen) > ATH11K_FTM_EVENT_MAX_BUF_LENGTH) { + ath11k_warn(ab, "Invalid ftm event length at %d: %d\n", + data_pos, datalen); + ret = -EINVAL; + goto out; + } + + memcpy(&ab->testmode.eventdata[data_pos], buf_pos, datalen); + data_pos += datalen; + + if (++ab->testmode.expected_seq != total_segments) { + ab->testmode.data_pos = data_pos; + ath11k_dbg(ab, ATH11K_DBG_TESTMODE, + "partial data received current_seq %d total_seg %d\n", + current_seq, total_segments); + goto out; + } + + ath11k_dbg(ab, ATH11K_DBG_TESTMODE, + "total data length pos %d len %d\n", + data_pos, ftm_msg->seg_hdr.len); + nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy, + 2 * nla_total_size(sizeof(u32)) + + nla_total_size(data_pos), + GFP_ATOMIC); + if (!nl_skb) { + ath11k_warn(ab, + "failed to allocate skb for segmented testmode wmi event\n"); + ret = -ENOMEM; + goto out; + } + + if (nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, + ATH11K_TM_CMD_WMI_FTM) || + nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id) || + nla_put(nl_skb, ATH11K_TM_ATTR_DATA, data_pos, + &ab->testmode.eventdata[0])) { + ath11k_warn(ab, "failed to populate segmented testmode event"); + kfree_skb(nl_skb); + ret = -ENOBUFS; + goto out; + } + + cfg80211_testmode_event(nl_skb, GFP_ATOMIC); + +out: + spin_unlock_bh(&ar->data_lock); + return ret; +} + +static void ath11k_tm_wmi_event_segmented(struct ath11k_base *ab, u32 cmd_id, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_ftm_event_msg *ev; + u16 length; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse ftm event tlv: %d\n", ret); + return; + } + + ev = tb[WMI_TAG_ARRAY_BYTE]; + if (!ev) { + ath11k_warn(ab, "failed to fetch ftm msg\n"); + kfree(tb); + return; + } + + length = skb->len - TLV_HDR_SIZE; + ret = ath11k_tm_process_event(ab, cmd_id, ev, length); + if (ret) + ath11k_warn(ab, "Failed to process ftm event\n"); + + kfree(tb); +} + +void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id, struct sk_buff *skb) +{ + if (test_bit(ATH11K_FLAG_FTM_SEGMENTED, &ab->dev_flags)) + ath11k_tm_wmi_event_segmented(ab, cmd_id, skb); + else + ath11k_tm_wmi_event_unsegmented(ab, cmd_id, skb); +} + static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[]) { struct sk_buff *skb; int ret; ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, - "testmode cmd get version_major %d version_minor %d\n", + "cmd get version_major %d version_minor %d\n", ATH11K_TESTMODE_VERSION_MAJOR, ATH11K_TESTMODE_VERSION_MINOR); @@ -53,6 +260,43 @@ static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[]) return cfg80211_testmode_reply(skb); } +static int ath11k_tm_cmd_testmode_start(struct ath11k *ar, struct nlattr *tb[]) +{ + int ret; + + mutex_lock(&ar->conf_mutex); + + if (ar->state == ATH11K_STATE_FTM) { + ret = -EALREADY; + goto err; + } + + /* start utf only when the driver is not in use */ + if (ar->state != ATH11K_STATE_OFF) { + ret = -EBUSY; + goto err; + } + + ar->ab->testmode.eventdata = kzalloc(ATH11K_FTM_EVENT_MAX_BUF_LENGTH, + GFP_KERNEL); + if (!ar->ab->testmode.eventdata) { + ret = -ENOMEM; + goto err; + } + + ar->state = ATH11K_STATE_FTM; + ar->ftm_msgref = 0; + + mutex_unlock(&ar->conf_mutex); + + ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, "cmd start\n"); + return 0; + +err: + mutex_unlock(&ar->conf_mutex); + return ret; +} + static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[]) { struct ath11k_pdev_wmi *wmi = ar->wmi; @@ -63,11 +307,6 @@ static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[]) mutex_lock(&ar->conf_mutex); - if (ar->state != ATH11K_STATE_ON) { - ret = -ENETDOWN; - goto out; - } - if (!tb[ATH11K_TM_ATTR_DATA]) { ret = -EINVAL; goto out; @@ -80,11 +319,17 @@ static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[]) buf = nla_data(tb[ATH11K_TM_ATTR_DATA]); buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]); + if (!buf_len) { + ath11k_warn(ar->ab, "No data present in testmode wmi command\n"); + ret = -EINVAL; + goto out; + } + cmd_id = nla_get_u32(tb[ATH11K_TM_ATTR_WMI_CMDID]); ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, - "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n", - cmd_id, buf, buf_len); + "cmd wmi cmd_id %d buf length %d\n", + cmd_id, buf_len); ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len); @@ -111,6 +356,91 @@ out: return ret; } +static int ath11k_tm_cmd_wmi_ftm(struct ath11k *ar, struct nlattr *tb[]) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct ath11k_base *ab = ar->ab; + struct sk_buff *skb; + u32 cmd_id, buf_len, hdr_info; + int ret; + void *buf; + u8 segnumber = 0, seginfo; + u16 chunk_len, total_bytes, num_segments; + u8 *bufpos; + struct wmi_ftm_cmd *ftm_cmd; + + set_bit(ATH11K_FLAG_FTM_SEGMENTED, &ab->dev_flags); + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH11K_STATE_FTM) { + ret = -ENETDOWN; + goto out; + } + + if (!tb[ATH11K_TM_ATTR_DATA]) { + ret = -EINVAL; + goto out; + } + + buf = nla_data(tb[ATH11K_TM_ATTR_DATA]); + buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]); + cmd_id = WMI_PDEV_UTF_CMDID; + + ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, + "cmd wmi ftm cmd_id %d buffer length %d\n", + cmd_id, buf_len); + ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len); + + bufpos = buf; + total_bytes = buf_len; + num_segments = total_bytes / MAX_WMI_UTF_LEN; + + if (buf_len - (num_segments * MAX_WMI_UTF_LEN)) + num_segments++; + + while (buf_len) { + chunk_len = min_t(u16, buf_len, MAX_WMI_UTF_LEN); + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, (chunk_len + + sizeof(struct wmi_ftm_cmd))); + if (!skb) { + ret = -ENOMEM; + goto out; + } + + ftm_cmd = (struct wmi_ftm_cmd *)skb->data; + hdr_info = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | + FIELD_PREP(WMI_TLV_LEN, (chunk_len + + sizeof(struct wmi_ftm_seg_hdr))); + ftm_cmd->tlv_header = hdr_info; + ftm_cmd->seg_hdr.len = total_bytes; + ftm_cmd->seg_hdr.msgref = ar->ftm_msgref; + seginfo = FIELD_PREP(ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS, num_segments) | + FIELD_PREP(ATH11K_FTM_SEGHDR_CURRENT_SEQ, segnumber); + ftm_cmd->seg_hdr.segmentinfo = seginfo; + segnumber++; + + memcpy(&ftm_cmd->data, bufpos, chunk_len); + + ret = ath11k_wmi_cmd_send(wmi, skb, cmd_id); + if (ret) { + ath11k_warn(ar->ab, "failed to send wmi ftm command: %d\n", ret); + goto out; + } + + buf_len -= chunk_len; + bufpos += chunk_len; + } + + ar->ftm_msgref++; + ret = 0; + +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len) { @@ -131,6 +461,10 @@ int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return ath11k_tm_cmd_get_version(ar, tb); case ATH11K_TM_CMD_WMI: return ath11k_tm_cmd_wmi(ar, tb); + case ATH11K_TM_CMD_TESTMODE_START: + return ath11k_tm_cmd_testmode_start(ar, tb); + case ATH11K_TM_CMD_WMI_FTM: + return ath11k_tm_cmd_wmi_ftm(ar, tb); default: return -EOPNOTSUPP; } diff --git a/drivers/net/wireless/ath/ath11k/testmode.h b/drivers/net/wireless/ath/ath11k/testmode.h index ffdb0c30b276..2f62f2c4422f 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.h +++ b/drivers/net/wireless/ath/ath11k/testmode.h @@ -8,11 +8,17 @@ #ifdef CONFIG_NL80211_TESTMODE +void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id, struct sk_buff *skb); int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len); #else +static inline void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id, + struct sk_buff *skb) +{ +} + static inline int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void *data, int len) diff --git a/drivers/net/wireless/ath/ath11k/testmode_i.h b/drivers/net/wireless/ath/ath11k/testmode_i.h index 4bae2a9eeea4..91b83873d660 100644 --- a/drivers/net/wireless/ath/ath11k/testmode_i.h +++ b/drivers/net/wireless/ath/ath11k/testmode_i.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ /* "API" level of the ath11k testmode interface. Bump it after every @@ -11,9 +12,10 @@ /* Bump this after every _compatible_ interface change, for example * addition of a new command or an attribute. */ -#define ATH11K_TESTMODE_VERSION_MINOR 0 +#define ATH11K_TESTMODE_VERSION_MINOR 1 #define ATH11K_TM_DATA_MAX_LEN 5000 +#define ATH11K_FTM_EVENT_MAX_BUF_LENGTH 2048 enum ath11k_tm_attr { __ATH11K_TM_ATTR_INVALID = 0, @@ -47,4 +49,18 @@ enum ath11k_tm_cmd { * ATH11K_TM_ATTR_DATA. */ ATH11K_TM_CMD_WMI = 1, + + /* Boots the UTF firmware, the netdev interface must be down at the + * time. + */ + ATH11K_TM_CMD_TESTMODE_START = 2, + + /* The command used to transmit a FTM WMI command to the firmware + * and the event to receive WMI events from the firmware. The data + * received only contain the payload, need to add the tlv header + * and send the cmd to firmware with command id WMI_PDEV_UTF_CMDID. + * The data payload size could be large and the driver needs to + * send segmented data to firmware. + */ + ATH11K_TM_CMD_WMI_FTM = 3, }; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 443199e85fa2..68622a850527 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -19,6 +19,7 @@ #include "mac.h" #include "hw.h" #include "peer.h" +#include "testmode.h" struct wmi_tlv_policy { size_t min_len; @@ -237,9 +238,8 @@ static int ath11k_wmi_tlv_parse(struct ath11k_base *ar, const void **tb, (void *)tb); } -static const void ** -ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr, - size_t len, gfp_t gfp) +const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr, + size_t len, gfp_t gfp) { const void **tb; int ret; @@ -8606,6 +8606,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID: ath11k_wmi_pdev_csa_switch_count_status_event(ab, skb); break; + case WMI_PDEV_UTF_EVENTID: + ath11k_tm_wmi_event(ab, id, skb); + break; case WMI_PDEV_TEMPERATURE_EVENTID: ath11k_wmi_pdev_temperature_event(ab, skb); break; diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 43aaf55b7f2a..100bb816b592 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_WMI_H @@ -68,6 +69,7 @@ struct wmi_tlv { #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1 +#define MAX_WMI_UTF_LEN 252 #define WMI_BA_MODE_BUFFER_SIZE_256 3 /* * HW mode config type replicated from FW header @@ -3564,6 +3566,24 @@ struct wmi_get_pdev_temperature_cmd { u32 pdev_id; } __packed; +struct wmi_ftm_seg_hdr { + u32 len; + u32 msgref; + u32 segmentinfo; + u32 pdev_id; +} __packed; + +struct wmi_ftm_cmd { + u32 tlv_header; + struct wmi_ftm_seg_hdr seg_hdr; + u8 data[]; +} __packed; + +struct wmi_ftm_event_msg { + struct wmi_ftm_seg_hdr seg_hdr; + u8 data[]; +} __packed; + #define WMI_BEACON_TX_BUFFER_SIZE 512 #define WMI_EMA_TMPL_IDX_SHIFT 8 @@ -6300,6 +6320,8 @@ enum wmi_sta_keepalive_method { #define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30 #define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0 +const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr, + size_t len, gfp_t gfp); int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, u32 cmd_id); struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); diff --git a/drivers/net/wireless/ath/ath11k/wow.c b/drivers/net/wireless/ath/ath11k/wow.c index 1dec23b0699c..99d8ba45a75b 100644 --- a/drivers/net/wireless/ath/ath11k/wow.c +++ b/drivers/net/wireless/ath/ath11k/wow.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -838,6 +838,7 @@ exit: case ATH11K_STATE_RESTARTING: case ATH11K_STATE_RESTARTED: case ATH11K_STATE_WEDGED: + case ATH11K_STATE_FTM: ath11k_warn(ar->ab, "encountered unexpected device state %d on resume, cannot recover\n", ar->state); ret = -EIO; -- cgit v1.2.3 From 8aeba427296bff6a6051686f1d139c89a0b00e4c Mon Sep 17 00:00:00 2001 From: Sowmiya Sree Elavalagan Date: Fri, 26 May 2023 12:41:07 +0300 Subject: wifi: ath11k: Allow ath11k to boot without caldata in ftm mode Currently, if ath11k is unable to load the calibration data file it will always exit. However the calibration data may not be present in factory test mode, so update the logic to allow the driver to execute in FTM mode even if downloading the calibration data fails. Tested-on : IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sowmiya Sree Elavalagan Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230517135934.16408-5-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath11k/qmi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index ab923e24b0a9..fa94ad828599 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2457,6 +2457,14 @@ static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab, fw_entry = ath11k_core_firmware_request(ab, ATH11K_DEFAULT_CAL_FILE); if (IS_ERR(fw_entry)) { + /* Caldata may not be present during first time calibration in + * factory hence allow to boot without loading caldata in ftm mode + */ + if (ath11k_ftm_mode) { + ath11k_info(ab, + "Booting without cal data file in factory test mode\n"); + return 0; + } ret = PTR_ERR(fw_entry); ath11k_warn(ab, "qmi failed to load CAL data file:%s\n", -- cgit v1.2.3 From 2d4f9093e2d8531ad0a2bb98fe5b36dc8addf2a2 Mon Sep 17 00:00:00 2001 From: Nidhi Jain Date: Fri, 26 May 2023 12:41:07 +0300 Subject: wifi: ath11k: Add HTT stats for PHY reset case New HTT stats are added with stats type 37 to provide PHY reset stats and PHY reset counter stats. PHY reset stats are used to display the current PHY-related operation information such as band, CCA threshold, current operating channel etc., PHY reset counter stats are used to display the PHY reset counter values like calibration counts, temperature based recalibration counts etc., Usage: echo 37 > /sys/kernel/debug/ieee80211/phyX/ath11k/htt_stats_type cat /sys/kernel/debug/ieee80211/phyx/ath11k/htt_stats Output: HTT_PHY_RESET_STATS_TLV: pdev_id = 0 chan_mhz = 5180 chan_band_center_freq1 = 5210 chan_band_center_freq2 = 0 chan_phy_mode = 18 chan_flags = 0x8 chan_num = 36 reset_cause = 0x50000 prev_reset_cause = 0x50000 phy_warm_reset_src = 0x0 rx_gain_tbl_mode = 0 xbar_val = 0xfac688 force_calibration = 0 phyrf_mode = 0 phy_homechan = 0 phy_tx_ch_mask = 0x3 phy_rx_ch_mask = 0x3 phybb_ini_mask = 0x5 phyrf_ini_mask = 0x0 phy_dfs_en_mask = 0x0 phy_sscan_en_mask = 0x0 phy_synth_sel_mask = 0x0 phy_adfs_freq = 0 cck_fir_settings = 0x0 phy_dyn_pri_chan = 6 cca_thresh = 0x26232020 dyn_cca_status = 0 rxdesense_thresh_hw = 0xcfe0afe rxdesense_thresh_sw = 0xcfe0afe HTT_PHY_RESET_COUNTERS_TLV: pdev_id = 0 cf_active_low_fail_cnt = 0 cf_active_low_pass_cnt = 0 phy_off_through_vreg_cnt = 0 force_calibration_cnt = 0 rf_mode_switch_phy_off_cnt = 0 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Nidhi Jain Signed-off-by: Maharaja Kennadyrajan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230517141242.2754293-1-quic_mkenna@quicinc.com --- .../net/wireless/ath/ath11k/debugfs_htt_stats.c | 114 +++++++++++++++++++++ .../net/wireless/ath/ath11k/debugfs_htt_stats.h | 43 ++++++++ 2 files changed, 157 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c index b3efca6bd7dd..0207fc4910f3 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c @@ -4011,6 +4011,114 @@ void htt_print_phy_stats_tlv(const void *tag_buf, stats_req->buf_len = len; } +static inline void +htt_print_phy_reset_counters_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct htt_phy_reset_counters_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PHY_RESET_COUNTERS_TLV:\n"); + + len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", + htt_stats_buf->pdev_id); + len += scnprintf(buf + len, buf_len - len, "cf_active_low_fail_cnt = %u\n", + htt_stats_buf->cf_active_low_fail_cnt); + len += scnprintf(buf + len, buf_len - len, "cf_active_low_pass_cnt = %u\n", + htt_stats_buf->cf_active_low_pass_cnt); + len += scnprintf(buf + len, buf_len - len, "phy_off_through_vreg_cnt = %u\n", + htt_stats_buf->phy_off_through_vreg_cnt); + len += scnprintf(buf + len, buf_len - len, "force_calibration_cnt = %u\n", + htt_stats_buf->force_calibration_cnt); + len += scnprintf(buf + len, buf_len - len, "rf_mode_switch_phy_off_cnt = %u\n", + htt_stats_buf->rf_mode_switch_phy_off_cnt); + + stats_req->buf_len = len; +} + +static inline void +htt_print_phy_reset_stats_tlv(const void *tag_buf, + u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct htt_phy_reset_stats_tlv *htt_stats_buf = tag_buf; + u8 *buf = stats_req->buf; + u32 len = stats_req->buf_len; + u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PHY_RESET_STATS_TLV:\n"); + + len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", + htt_stats_buf->pdev_id); + len += scnprintf(buf + len, buf_len - len, "chan_mhz = %u\n", + htt_stats_buf->chan_mhz); + len += scnprintf(buf + len, buf_len - len, "chan_band_center_freq1 = %u\n", + htt_stats_buf->chan_band_center_freq1); + len += scnprintf(buf + len, buf_len - len, "chan_band_center_freq2 = %u\n", + htt_stats_buf->chan_band_center_freq2); + len += scnprintf(buf + len, buf_len - len, "chan_phy_mode = %u\n", + htt_stats_buf->chan_phy_mode); + len += scnprintf(buf + len, buf_len - len, "chan_flags = 0x%0x\n", + htt_stats_buf->chan_flags); + len += scnprintf(buf + len, buf_len - len, "chan_num = %u\n", + htt_stats_buf->chan_num); + len += scnprintf(buf + len, buf_len - len, "reset_cause = 0x%0x\n", + htt_stats_buf->reset_cause); + len += scnprintf(buf + len, buf_len - len, "prev_reset_cause = 0x%0x\n", + htt_stats_buf->prev_reset_cause); + len += scnprintf(buf + len, buf_len - len, "phy_warm_reset_src = 0x%0x\n", + htt_stats_buf->phy_warm_reset_src); + len += scnprintf(buf + len, buf_len - len, "rx_gain_tbl_mode = %d\n", + htt_stats_buf->rx_gain_tbl_mode); + len += scnprintf(buf + len, buf_len - len, "xbar_val = 0x%0x\n", + htt_stats_buf->xbar_val); + len += scnprintf(buf + len, buf_len - len, "force_calibration = %u\n", + htt_stats_buf->force_calibration); + len += scnprintf(buf + len, buf_len - len, "phyrf_mode = %u\n", + htt_stats_buf->phyrf_mode); + len += scnprintf(buf + len, buf_len - len, "phy_homechan = %u\n", + htt_stats_buf->phy_homechan); + len += scnprintf(buf + len, buf_len - len, "phy_tx_ch_mask = 0x%0x\n", + htt_stats_buf->phy_tx_ch_mask); + len += scnprintf(buf + len, buf_len - len, "phy_rx_ch_mask = 0x%0x\n", + htt_stats_buf->phy_rx_ch_mask); + len += scnprintf(buf + len, buf_len - len, "phybb_ini_mask = 0x%0x\n", + htt_stats_buf->phybb_ini_mask); + len += scnprintf(buf + len, buf_len - len, "phyrf_ini_mask = 0x%0x\n", + htt_stats_buf->phyrf_ini_mask); + len += scnprintf(buf + len, buf_len - len, "phy_dfs_en_mask = 0x%0x\n", + htt_stats_buf->phy_dfs_en_mask); + len += scnprintf(buf + len, buf_len - len, "phy_sscan_en_mask = 0x%0x\n", + htt_stats_buf->phy_sscan_en_mask); + len += scnprintf(buf + len, buf_len - len, "phy_synth_sel_mask = 0x%0x\n", + htt_stats_buf->phy_synth_sel_mask); + len += scnprintf(buf + len, buf_len - len, "phy_adfs_freq = %u\n", + htt_stats_buf->phy_adfs_freq); + len += scnprintf(buf + len, buf_len - len, "cck_fir_settings = 0x%0x\n", + htt_stats_buf->cck_fir_settings); + len += scnprintf(buf + len, buf_len - len, "phy_dyn_pri_chan = %u\n", + htt_stats_buf->phy_dyn_pri_chan); + len += scnprintf(buf + len, buf_len - len, "cca_thresh = 0x%0x\n", + htt_stats_buf->cca_thresh); + len += scnprintf(buf + len, buf_len - len, "dyn_cca_status = %u\n", + htt_stats_buf->dyn_cca_status); + len += scnprintf(buf + len, buf_len - len, "rxdesense_thresh_hw = 0x%x\n", + htt_stats_buf->rxdesense_thresh_hw); + len += scnprintf(buf + len, buf_len - len, "rxdesense_thresh_sw = 0x%x\n", + htt_stats_buf->rxdesense_thresh_sw); + + stats_req->buf_len = len; +} + static inline void htt_print_peer_ctrl_path_txrx_stats_tlv(const void *tag_buf, struct debug_htt_stats_req *stats_req) @@ -4425,6 +4533,12 @@ static int ath11k_dbg_htt_ext_stats_parse(struct ath11k_base *ab, case HTT_STATS_PHY_STATS_TAG: htt_print_phy_stats_tlv(tag_buf, stats_req); break; + case HTT_STATS_PHY_RESET_COUNTERS_TAG: + htt_print_phy_reset_counters_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PHY_RESET_STATS_TAG: + htt_print_phy_reset_stats_tlv(tag_buf, len, stats_req); + break; case HTT_STATS_PEER_CTRL_PATH_TXRX_STATS_TAG: htt_print_peer_ctrl_path_txrx_stats_tlv(tag_buf, stats_req); break; diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h index 0bbd58a380de..96219301f05b 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h @@ -111,6 +111,8 @@ enum htt_tlv_tag_t { HTT_STATS_TXBF_OFDMA_STEER_STATS_TAG = 116, HTT_STATS_PHY_COUNTERS_TAG = 121, HTT_STATS_PHY_STATS_TAG = 122, + HTT_STATS_PHY_RESET_COUNTERS_TAG = 123, + HTT_STATS_PHY_RESET_STATS_TAG = 124, HTT_STATS_MAX_TAG, }; @@ -1964,6 +1966,47 @@ struct htt_phy_stats_tlv { u32 fw_run_time; }; +struct htt_phy_reset_counters_tlv { + u32 pdev_id; + u32 cf_active_low_fail_cnt; + u32 cf_active_low_pass_cnt; + u32 phy_off_through_vreg_cnt; + u32 force_calibration_cnt; + u32 rf_mode_switch_phy_off_cnt; +}; + +struct htt_phy_reset_stats_tlv { + u32 pdev_id; + u32 chan_mhz; + u32 chan_band_center_freq1; + u32 chan_band_center_freq2; + u32 chan_phy_mode; + u32 chan_flags; + u32 chan_num; + u32 reset_cause; + u32 prev_reset_cause; + u32 phy_warm_reset_src; + u32 rx_gain_tbl_mode; + u32 xbar_val; + u32 force_calibration; + u32 phyrf_mode; + u32 phy_homechan; + u32 phy_tx_ch_mask; + u32 phy_rx_ch_mask; + u32 phybb_ini_mask; + u32 phyrf_ini_mask; + u32 phy_dfs_en_mask; + u32 phy_sscan_en_mask; + u32 phy_synth_sel_mask; + u32 phy_adfs_freq; + u32 cck_fir_settings; + u32 phy_dyn_pri_chan; + u32 cca_thresh; + u32 dyn_cca_status; + u32 rxdesense_thresh_hw; + u32 rxdesense_thresh_sw; +}; + struct htt_peer_ctrl_path_txrx_stats_tlv { /* peer mac address */ u8 peer_mac_addr[ETH_ALEN]; -- cgit v1.2.3 From 75bd32f5ce94bc365ba0b9b68bcf9de84a391d37 Mon Sep 17 00:00:00 2001 From: Youghandhar Chintala Date: Fri, 26 May 2023 12:41:08 +0300 Subject: wifi: ath10k: Trigger STA disconnect after reconfig complete on hardware restart Currently, on WCN3990, the station disconnect after hardware recovery is not working as expected. This is because of setting the IEEE80211_SDATA_DISCONNECT_HW_RESTART flag very early in the hardware recovery process even before the driver invokes ieee80211_hw_restart(). On the contrary, mac80211 expects this flag to be set after ieee80211_hw_restart() is invoked for it to trigger station disconnect. Set the IEEE80211_SDATA_DISCONNECT_HW_RESTART flag in ath10k_reconfig_complete() instead to fix this. The other targets are not affected by this change, since the hardware params flag is not set. Tested-on: WCN3990 hw1.0 SNOC WLAN.HL.3.2.2.c10-00754-QCAHLSWMTPL-1 Fixes: 2c3fc50591ff ("ath10k: Trigger sta disconnect on hardware restart") Signed-off-by: Youghandhar Chintala Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230518101515.3820-1-quic_youghand@quicinc.com --- drivers/net/wireless/ath/ath10k/core.c | 9 --------- drivers/net/wireless/ath/ath10k/mac.c | 7 +++++++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 533ed7169e11..6cdb225b7eac 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2504,7 +2504,6 @@ EXPORT_SYMBOL(ath10k_core_napi_sync_disable); static void ath10k_core_restart(struct work_struct *work) { struct ath10k *ar = container_of(work, struct ath10k, restart_work); - struct ath10k_vif *arvif; int ret; set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); @@ -2543,14 +2542,6 @@ static void ath10k_core_restart(struct work_struct *work) ar->state = ATH10K_STATE_RESTARTING; ath10k_halt(ar); ath10k_scan_finish(ar); - if (ar->hw_params.hw_restart_disconnect) { - list_for_each_entry(arvif, &ar->arvifs, list) { - if (arvif->is_up && - arvif->vdev_type == WMI_VDEV_TYPE_STA) - ieee80211_hw_restart_disconnect(arvif->vif); - } - } - ieee80211_restart_hw(ar->hw); break; case ATH10K_STATE_OFF: diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9c4bf2fdbc0f..03e7bc5b6c0b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -8109,6 +8109,7 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type) { struct ath10k *ar = hw->priv; + struct ath10k_vif *arvif; if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; @@ -8123,6 +8124,12 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw, ar->state = ATH10K_STATE_ON; ieee80211_wake_queues(ar->hw); clear_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags); + if (ar->hw_params.hw_restart_disconnect) { + list_for_each_entry(arvif, &ar->arvifs, list) { + if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_STA) + ieee80211_hw_restart_disconnect(arvif->vif); + } + } } mutex_unlock(&ar->conf_mutex); -- cgit v1.2.3 From 116f7b361ebbb6095257c27da327e27000488214 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 31 May 2023 12:00:07 +0100 Subject: chelsio: Support MSG_SPLICE_PAGES Make Chelsio's TLS offload sendmsg() support MSG_SPLICE_PAGES, splicing in pages from the source iterator if possible and copying the data in otherwise. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Ayush Sawal cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: netdev@vger.kernel.org Signed-off-by: Paolo Abeni --- drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c index ae6b17b96bf1..1d08386ac916 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c @@ -1092,7 +1092,17 @@ new_buf: if (copy > size) copy = size; - if (skb_tailroom(skb) > 0) { + if (msg->msg_flags & MSG_SPLICE_PAGES) { + err = skb_splice_from_iter(skb, &msg->msg_iter, copy, + sk->sk_allocation); + if (err < 0) { + if (err == -EMSGSIZE) + goto new_buf; + goto do_fault; + } + copy = err; + sk_wmem_queued_add(sk, copy); + } else if (skb_tailroom(skb) > 0) { copy = min(copy, skb_tailroom(skb)); if (is_tls_tx(csk)) copy = min_t(int, copy, csk->tlshws.txleft); -- cgit v1.2.3 From 26acc982c1c5c2835b0c6981d896329efa3557c3 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 31 May 2023 12:00:08 +0100 Subject: chelsio: Convert chtls_sendpage() to use MSG_SPLICE_PAGES Convert chtls_sendpage() to use sendmsg() with MSG_SPLICE_PAGES rather than directly splicing in the pages itself. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Ayush Sawal cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: netdev@vger.kernel.org Signed-off-by: Paolo Abeni --- .../chelsio/inline_crypto/chtls/chtls_io.c | 109 ++------------------- 1 file changed, 7 insertions(+), 102 deletions(-) diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c index 1d08386ac916..5724bbbb6ee0 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c @@ -1240,110 +1240,15 @@ out_err: int chtls_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { - struct chtls_sock *csk; - struct chtls_dev *cdev; - int mss, err, copied; - struct tcp_sock *tp; - long timeo; - - tp = tcp_sk(sk); - copied = 0; - csk = rcu_dereference_sk_user_data(sk); - cdev = csk->cdev; - lock_sock(sk); - timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); + struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; + struct bio_vec bvec; - err = sk_stream_wait_connect(sk, &timeo); - if (!sk_in_state(sk, TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && - err != 0) - goto out_err; - - mss = csk->mss; - csk_set_flag(csk, CSK_TX_MORE_DATA); - - while (size > 0) { - struct sk_buff *skb = skb_peek_tail(&csk->txq); - int copy, i; - - if (!skb || (ULP_SKB_CB(skb)->flags & ULPCB_FLAG_NO_APPEND) || - (copy = mss - skb->len) <= 0) { -new_buf: - if (!csk_mem_free(cdev, sk)) - goto wait_for_sndbuf; + if (flags & MSG_SENDPAGE_NOTLAST) + msg.msg_flags |= MSG_MORE; - if (is_tls_tx(csk)) { - skb = get_record_skb(sk, - select_size(sk, size, - flags, - TX_TLSHDR_LEN), - true); - } else { - skb = get_tx_skb(sk, 0); - } - if (!skb) - goto wait_for_memory; - copy = mss; - } - if (copy > size) - copy = size; - - i = skb_shinfo(skb)->nr_frags; - if (skb_can_coalesce(skb, i, page, offset)) { - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); - } else if (i < MAX_SKB_FRAGS) { - get_page(page); - skb_fill_page_desc(skb, i, page, offset, copy); - } else { - tx_skb_finalize(skb); - push_frames_if_head(sk); - goto new_buf; - } - - skb->len += copy; - if (skb->len == mss) - tx_skb_finalize(skb); - skb->data_len += copy; - skb->truesize += copy; - sk->sk_wmem_queued += copy; - tp->write_seq += copy; - copied += copy; - offset += copy; - size -= copy; - - if (corked(tp, flags) && - (sk_stream_wspace(sk) < sk_stream_min_wspace(sk))) - ULP_SKB_CB(skb)->flags |= ULPCB_FLAG_NO_APPEND; - - if (!size) - break; - - if (unlikely(ULP_SKB_CB(skb)->flags & ULPCB_FLAG_NO_APPEND)) - push_frames_if_head(sk); - continue; -wait_for_sndbuf: - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); -wait_for_memory: - err = csk_wait_memory(cdev, sk, &timeo); - if (err) - goto do_error; - } -out: - csk_reset_flag(csk, CSK_TX_MORE_DATA); - if (copied) - chtls_tcp_push(sk, flags); -done: - release_sock(sk); - return copied; - -do_error: - if (copied) - goto out; - -out_err: - if (csk_conn_inline(csk)) - csk_reset_flag(csk, CSK_TX_MORE_DATA); - copied = sk_stream_error(sk, flags, err); - goto done; + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + return chtls_sendmsg(sk, &msg, size); } static void chtls_select_window(struct sock *sk) -- cgit v1.2.3 From 3e450386e99e6eeb9a40ac09fbc4704936334579 Mon Sep 17 00:00:00 2001 From: Juhee Kang Date: Sat, 27 May 2023 20:49:53 +0900 Subject: wifi: rtlwifi: use helper function rtl_get_hdr() Although rtl_get_hdr was added in commit 3dad618b7b92 ("rtlwifi: Change wifi.h for rtl8192se and rtl8192de"), it is currently not being utilized in some areas. This commit replaces the open code with the rtl_get_hdr() function. Signed-off-by: Juhee Kang Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230527114954.3281-1-claudiajkang@gmail.com --- drivers/net/wireless/realtek/rtlwifi/base.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c | 2 +- drivers/net/wireless/realtek/rtlwifi/usb.c | 8 ++++---- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 9e7e98b55eff..36ae9ba3ac01 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1905,7 +1905,7 @@ EXPORT_SYMBOL(rtl_rx_ampdu_apply); void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION) return; @@ -1991,7 +1991,7 @@ void rtl_scan_list_expire(struct ieee80211_hw *hw) void rtl_collect_scan_list(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); unsigned long flags; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c index 6e4741e9483f..65ebe52883d3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c @@ -674,7 +674,7 @@ void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 fw_queue = QSLT_BEACON; __le32 *pdesc = (__le32 *)pdesc8; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); __le16 fc = hdr->frame_control; dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c index 730c7e939bd2..5376bb34251f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c @@ -527,7 +527,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 fw_queue = QSLT_BEACON; __le32 *pdesc = (__le32 *)pdesc8; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); __le16 fc = hdr->frame_control; dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index ae3c4f97637e..b70767e72f3d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -394,7 +394,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) (struct rx_desc_92c *)rxdesc, p_drvinfo); } skb_pull(skb, (drvinfo_len + RTL_RX_DESC_SIZE)); - hdr = (struct ieee80211_hdr *)(skb->data); + hdr = rtl_get_hdr(skb); fc = hdr->frame_control; bv = ieee80211_is_probe_resp(fc); if (bv) @@ -632,7 +632,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 fw_queue = QSLT_BEACON; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); __le16 fc = hdr->frame_control; __le32 *pdesc = (__le32 *)pdesc8; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c index 807b66c16e11..c09c0c312665 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c @@ -665,7 +665,7 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, struct rtl_hal *rtlhal = rtl_hal(rtlpriv); u8 fw_queue = QSLT_BEACON; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); __le16 fc = hdr->frame_control; __le32 *pdesc = (__le32 *)pdesc8; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c index 27fddbcade32..7f294e698994 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c @@ -528,7 +528,7 @@ void rtl8723e_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 fw_queue = QSLT_BEACON; __le32 *pdesc = (__le32 *)pdesc8; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); __le16 fc = hdr->frame_control; dma_addr_t mapping = dma_map_single(&rtlpci->pdev->dev, skb->data, diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index a8eebafb9a7e..ab675703eaf5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -433,7 +433,7 @@ static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw, skb_pull(skb, RTL_RX_DESC_SIZE); rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); - hdr = (struct ieee80211_hdr *)(skb->data); + hdr = rtl_get_hdr(skb); fc = hdr->frame_control; if (!stats.crc) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); @@ -475,7 +475,7 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw, skb_pull(skb, RTL_RX_DESC_SIZE); rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, rxdesc, skb); skb_pull(skb, (stats.rx_drvinfo_size + stats.rx_bufshift)); - hdr = (struct ieee80211_hdr *)(skb->data); + hdr = rtl_get_hdr(skb); fc = hdr->frame_control; if (!stats.crc) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); @@ -926,7 +926,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl_tx_desc *pdesc = NULL; struct rtl_tcb_desc tcb_desc; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); __le16 fc = hdr->frame_control; u8 *pda_addr = hdr->addr1; @@ -961,7 +961,7 @@ static int rtl_usb_tx(struct ieee80211_hw *hw, { struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); __le16 fc = hdr->frame_control; u16 hw_queue; -- cgit v1.2.3 From 8012ec4a0e64b60d4d782950296e6fb217c6758f Mon Sep 17 00:00:00 2001 From: Juhee Kang Date: Sat, 27 May 2023 20:49:54 +0900 Subject: wifi: brcmutil: use helper function pktq_empty() instead of open code pktq_empty was added in commit 5b435de0d786 ("net: wireless: add brcm80211 drivers") but it is currently not being utilized in some areas. This commit replaces the open code with the pktq_empty() function. Signed-off-by: Juhee Kang Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230527114954.3281-2-claudiajkang@gmail.com --- drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c b/drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c index e87e68cc46e2..fe94db0ba3f3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmutil/utils.c @@ -186,7 +186,7 @@ struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out) { int prec; - if (pq->len == 0) + if (pktq_empty(pq)) return NULL; for (prec = 0; prec < pq->hi_prec; prec++) @@ -223,7 +223,7 @@ struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, struct sk_buff *p; int prec; - if (pq->len == 0) + if (pktq_empty(pq)) return NULL; while ((prec = pq->hi_prec) > 0 && -- cgit v1.2.3 From 8ad77e72caae22a1ddcfd0c03f2884929e93b7a4 Mon Sep 17 00:00:00 2001 From: Louis DeLosSantos Date: Wed, 31 May 2023 15:38:48 -0400 Subject: bpf: Add table ID to bpf_fib_lookup BPF helper Add ability to specify routing table ID to the `bpf_fib_lookup` BPF helper. A new field `tbid` is added to `struct bpf_fib_lookup` used as parameters to the `bpf_fib_lookup` BPF helper. When the helper is called with the `BPF_FIB_LOOKUP_DIRECT` and `BPF_FIB_LOOKUP_TBID` flags the `tbid` field in `struct bpf_fib_lookup` will be used as the table ID for the fib lookup. If the `tbid` does not exist the fib lookup will fail with `BPF_FIB_LKUP_RET_NOT_FWDED`. The `tbid` field becomes a union over the vlan related output fields in `struct bpf_fib_lookup` and will be zeroed immediately after usage. This functionality is useful in containerized environments. For instance, if a CNI wants to dictate the next-hop for traffic leaving a container it can create a container-specific routing table and perform a fib lookup against this table in a "host-net-namespace-side" TC program. This functionality also allows `ip rule` like functionality at the TC layer, allowing an eBPF program to pick a routing table based on some aspect of the sk_buff. As a concrete use case, this feature will be used in Cilium's SRv6 L3VPN datapath. When egress traffic leaves a Pod an eBPF program attached by Cilium will determine which VRF the egress traffic should target, and then perform a FIB lookup in a specific table representing this VRF's FIB. Signed-off-by: Louis DeLosSantos Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230505-bpf-add-tbid-fib-lookup-v2-1-0a31c22c748c@gmail.com --- include/uapi/linux/bpf.h | 21 ++++++++++++++++++--- net/core/filter.c | 14 +++++++++++++- tools/include/uapi/linux/bpf.h | 21 ++++++++++++++++++--- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 9273c654743c..a7b5e91dd768 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -3177,6 +3177,10 @@ union bpf_attr { * **BPF_FIB_LOOKUP_DIRECT** * Do a direct table lookup vs full lookup using FIB * rules. + * **BPF_FIB_LOOKUP_TBID** + * Used with BPF_FIB_LOOKUP_DIRECT. + * Use the routing table ID present in *params*->tbid + * for the fib lookup. * **BPF_FIB_LOOKUP_OUTPUT** * Perform lookup from an egress perspective (default is * ingress). @@ -6831,6 +6835,7 @@ enum { BPF_FIB_LOOKUP_DIRECT = (1U << 0), BPF_FIB_LOOKUP_OUTPUT = (1U << 1), BPF_FIB_LOOKUP_SKIP_NEIGH = (1U << 2), + BPF_FIB_LOOKUP_TBID = (1U << 3), }; enum { @@ -6891,9 +6896,19 @@ struct bpf_fib_lookup { __u32 ipv6_dst[4]; /* in6_addr; network order */ }; - /* output */ - __be16 h_vlan_proto; - __be16 h_vlan_TCI; + union { + struct { + /* output */ + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + }; + /* input: when accompanied with the + * 'BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID` flags, a + * specific routing table to use for the fib lookup. + */ + __u32 tbid; + }; + __u8 smac[6]; /* ETH_ALEN */ __u8 dmac[6]; /* ETH_ALEN */ }; diff --git a/net/core/filter.c b/net/core/filter.c index 968139f4a1ac..d25d52854c21 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5803,6 +5803,12 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params, u32 tbid = l3mdev_fib_table_rcu(dev) ? : RT_TABLE_MAIN; struct fib_table *tb; + if (flags & BPF_FIB_LOOKUP_TBID) { + tbid = params->tbid; + /* zero out for vlan output */ + params->tbid = 0; + } + tb = fib_get_table(net, tbid); if (unlikely(!tb)) return BPF_FIB_LKUP_RET_NOT_FWDED; @@ -5936,6 +5942,12 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params, u32 tbid = l3mdev_fib_table_rcu(dev) ? : RT_TABLE_MAIN; struct fib6_table *tb; + if (flags & BPF_FIB_LOOKUP_TBID) { + tbid = params->tbid; + /* zero out for vlan output */ + params->tbid = 0; + } + tb = ipv6_stub->fib6_get_table(net, tbid); if (unlikely(!tb)) return BPF_FIB_LKUP_RET_NOT_FWDED; @@ -6008,7 +6020,7 @@ set_fwd_params: #endif #define BPF_FIB_LOOKUP_MASK (BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_OUTPUT | \ - BPF_FIB_LOOKUP_SKIP_NEIGH) + BPF_FIB_LOOKUP_SKIP_NEIGH | BPF_FIB_LOOKUP_TBID) BPF_CALL_4(bpf_xdp_fib_lookup, struct xdp_buff *, ctx, struct bpf_fib_lookup *, params, int, plen, u32, flags) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 9273c654743c..a7b5e91dd768 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -3177,6 +3177,10 @@ union bpf_attr { * **BPF_FIB_LOOKUP_DIRECT** * Do a direct table lookup vs full lookup using FIB * rules. + * **BPF_FIB_LOOKUP_TBID** + * Used with BPF_FIB_LOOKUP_DIRECT. + * Use the routing table ID present in *params*->tbid + * for the fib lookup. * **BPF_FIB_LOOKUP_OUTPUT** * Perform lookup from an egress perspective (default is * ingress). @@ -6831,6 +6835,7 @@ enum { BPF_FIB_LOOKUP_DIRECT = (1U << 0), BPF_FIB_LOOKUP_OUTPUT = (1U << 1), BPF_FIB_LOOKUP_SKIP_NEIGH = (1U << 2), + BPF_FIB_LOOKUP_TBID = (1U << 3), }; enum { @@ -6891,9 +6896,19 @@ struct bpf_fib_lookup { __u32 ipv6_dst[4]; /* in6_addr; network order */ }; - /* output */ - __be16 h_vlan_proto; - __be16 h_vlan_TCI; + union { + struct { + /* output */ + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + }; + /* input: when accompanied with the + * 'BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID` flags, a + * specific routing table to use for the fib lookup. + */ + __u32 tbid; + }; + __u8 smac[6]; /* ETH_ALEN */ __u8 dmac[6]; /* ETH_ALEN */ }; -- cgit v1.2.3 From d4ae3e587eced73c9b6f82fd8f88606a09ff710c Mon Sep 17 00:00:00 2001 From: Louis DeLosSantos Date: Wed, 31 May 2023 15:38:49 -0400 Subject: selftests/bpf: Test table ID fib lookup BPF helper Add additional test cases to `fib_lookup.c` prog_test. These test cases add a new /24 network to the previously unused veth2 device, removes the directly connected route from the main routing table and moves it to table 100. The first test case then confirms a fib lookup for a remote address in this directly connected network, using the main routing table fails. The second test case ensures the same fib lookup using table 100 succeeds. An additional pair of tests which function in the same manner are added for IPv6. Signed-off-by: Louis DeLosSantos Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230505-bpf-add-tbid-fib-lookup-v2-2-0a31c22c748c@gmail.com --- .../testing/selftests/bpf/prog_tests/fib_lookup.c | 61 +++++++++++++++++++--- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c index a1e712105811..2fd05649bad1 100644 --- a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c +++ b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ +#include #include #include @@ -15,14 +16,23 @@ #define IPV4_IFACE_ADDR "10.0.0.254" #define IPV4_NUD_FAILED_ADDR "10.0.0.1" #define IPV4_NUD_STALE_ADDR "10.0.0.2" +#define IPV4_TBID_ADDR "172.0.0.254" +#define IPV4_TBID_NET "172.0.0.0" +#define IPV4_TBID_DST "172.0.0.2" +#define IPV6_TBID_ADDR "fd00::FFFF" +#define IPV6_TBID_NET "fd00::" +#define IPV6_TBID_DST "fd00::2" #define DMAC "11:11:11:11:11:11" #define DMAC_INIT { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, } +#define DMAC2 "01:01:01:01:01:01" +#define DMAC_INIT2 { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, } struct fib_lookup_test { const char *desc; const char *daddr; int expected_ret; int lookup_flags; + __u32 tbid; __u8 dmac[6]; }; @@ -43,6 +53,22 @@ static const struct fib_lookup_test tests[] = { { .desc = "IPv4 skip neigh", .daddr = IPV4_NUD_FAILED_ADDR, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH, }, + { .desc = "IPv4 TBID lookup failure", + .daddr = IPV4_TBID_DST, .expected_ret = BPF_FIB_LKUP_RET_NOT_FWDED, + .lookup_flags = BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID, + .tbid = RT_TABLE_MAIN, }, + { .desc = "IPv4 TBID lookup success", + .daddr = IPV4_TBID_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, + .lookup_flags = BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID, .tbid = 100, + .dmac = DMAC_INIT2, }, + { .desc = "IPv6 TBID lookup failure", + .daddr = IPV6_TBID_DST, .expected_ret = BPF_FIB_LKUP_RET_NOT_FWDED, + .lookup_flags = BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID, + .tbid = RT_TABLE_MAIN, }, + { .desc = "IPv6 TBID lookup success", + .daddr = IPV6_TBID_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS, + .lookup_flags = BPF_FIB_LOOKUP_DIRECT | BPF_FIB_LOOKUP_TBID, .tbid = 100, + .dmac = DMAC_INIT2, }, }; static int ifindex; @@ -53,6 +79,7 @@ static int setup_netns(void) SYS(fail, "ip link add veth1 type veth peer name veth2"); SYS(fail, "ip link set dev veth1 up"); + SYS(fail, "ip link set dev veth2 up"); err = write_sysctl("/proc/sys/net/ipv4/neigh/veth1/gc_stale_time", "900"); if (!ASSERT_OK(err, "write_sysctl(net.ipv4.neigh.veth1.gc_stale_time)")) @@ -70,6 +97,17 @@ static int setup_netns(void) SYS(fail, "ip neigh add %s dev veth1 nud failed", IPV4_NUD_FAILED_ADDR); SYS(fail, "ip neigh add %s dev veth1 lladdr %s nud stale", IPV4_NUD_STALE_ADDR, DMAC); + /* Setup for tbid lookup tests */ + SYS(fail, "ip addr add %s/24 dev veth2", IPV4_TBID_ADDR); + SYS(fail, "ip route del %s/24 dev veth2", IPV4_TBID_NET); + SYS(fail, "ip route add table 100 %s/24 dev veth2", IPV4_TBID_NET); + SYS(fail, "ip neigh add %s dev veth2 lladdr %s nud stale", IPV4_TBID_DST, DMAC2); + + SYS(fail, "ip addr add %s/64 dev veth2", IPV6_TBID_ADDR); + SYS(fail, "ip -6 route del %s/64 dev veth2", IPV6_TBID_NET); + SYS(fail, "ip -6 route add table 100 %s/64 dev veth2", IPV6_TBID_NET); + SYS(fail, "ip neigh add %s dev veth2 lladdr %s nud stale", IPV6_TBID_DST, DMAC2); + err = write_sysctl("/proc/sys/net/ipv4/conf/veth1/forwarding", "1"); if (!ASSERT_OK(err, "write_sysctl(net.ipv4.conf.veth1.forwarding)")) goto fail; @@ -83,7 +121,7 @@ fail: return -1; } -static int set_lookup_params(struct bpf_fib_lookup *params, const char *daddr) +static int set_lookup_params(struct bpf_fib_lookup *params, const struct fib_lookup_test *test) { int ret; @@ -91,8 +129,9 @@ static int set_lookup_params(struct bpf_fib_lookup *params, const char *daddr) params->l4_protocol = IPPROTO_TCP; params->ifindex = ifindex; + params->tbid = test->tbid; - if (inet_pton(AF_INET6, daddr, params->ipv6_dst) == 1) { + if (inet_pton(AF_INET6, test->daddr, params->ipv6_dst) == 1) { params->family = AF_INET6; ret = inet_pton(AF_INET6, IPV6_IFACE_ADDR, params->ipv6_src); if (!ASSERT_EQ(ret, 1, "inet_pton(IPV6_IFACE_ADDR)")) @@ -100,7 +139,7 @@ static int set_lookup_params(struct bpf_fib_lookup *params, const char *daddr) return 0; } - ret = inet_pton(AF_INET, daddr, ¶ms->ipv4_dst); + ret = inet_pton(AF_INET, test->daddr, ¶ms->ipv4_dst); if (!ASSERT_EQ(ret, 1, "convert IP[46] address")) return -1; params->family = AF_INET; @@ -154,13 +193,12 @@ void test_fib_lookup(void) fib_params = &skel->bss->fib_params; for (i = 0; i < ARRAY_SIZE(tests); i++) { - printf("Testing %s\n", tests[i].desc); + printf("Testing %s ", tests[i].desc); - if (set_lookup_params(fib_params, tests[i].daddr)) + if (set_lookup_params(fib_params, &tests[i])) continue; skel->bss->fib_lookup_ret = -1; - skel->bss->lookup_flags = BPF_FIB_LOOKUP_OUTPUT | - tests[i].lookup_flags; + skel->bss->lookup_flags = tests[i].lookup_flags; err = bpf_prog_test_run_opts(prog_fd, &run_opts); if (!ASSERT_OK(err, "bpf_prog_test_run_opts")) @@ -175,7 +213,14 @@ void test_fib_lookup(void) mac_str(expected, tests[i].dmac); mac_str(actual, fib_params->dmac); - printf("dmac expected %s actual %s\n", expected, actual); + printf("dmac expected %s actual %s ", expected, actual); + } + + // ensure tbid is zero'd out after fib lookup. + if (tests[i].lookup_flags & BPF_FIB_LOOKUP_DIRECT) { + if (!ASSERT_EQ(skel->bss->fib_params.tbid, 0, + "expected fib_params.tbid to be zero")) + goto fail; } } -- cgit v1.2.3 From 04292c695f82b6cf0d25dd5ae494f16ddbb621f6 Mon Sep 17 00:00:00 2001 From: Abhijeet Rastogi Date: Tue, 16 May 2023 20:08:49 -0700 Subject: ipvs: increase ip_vs_conn_tab_bits range for 64BIT Current range [8, 20] is set purely due to historical reasons because at the time, ~1M (2^20) was considered sufficient. With this change, 27 is the upper limit for 64-bit, 20 otherwise. Previous change regarding this limit is here. Link: https://lore.kernel.org/all/86eabeb9dd62aebf1e2533926fdd13fed48bab1f.1631289960.git.aclaudi@redhat.com/T/#u Signed-off-by: Abhijeet Rastogi Acked-by: Julian Anastasov Acked-by: Simon Horman Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipvs/Kconfig | 27 ++++++++++++++------------- net/netfilter/ipvs/ip_vs_conn.c | 4 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig index 271da8447b29..2a3017b9c001 100644 --- a/net/netfilter/ipvs/Kconfig +++ b/net/netfilter/ipvs/Kconfig @@ -44,7 +44,8 @@ config IP_VS_DEBUG config IP_VS_TAB_BITS int "IPVS connection table size (the Nth power of 2)" - range 8 20 + range 8 20 if !64BIT + range 8 27 if 64BIT default 12 help The IPVS connection hash table uses the chaining scheme to handle @@ -54,24 +55,24 @@ config IP_VS_TAB_BITS Note the table size must be power of 2. The table size will be the value of 2 to the your input number power. The number to choose is - from 8 to 20, the default number is 12, which means the table size - is 4096. Don't input the number too small, otherwise you will lose - performance on it. You can adapt the table size yourself, according - to your virtual server application. It is good to set the table size - not far less than the number of connections per second multiplying - average lasting time of connection in the table. For example, your - virtual server gets 200 connections per second, the connection lasts - for 200 seconds in average in the connection table, the table size - should be not far less than 200x200, it is good to set the table - size 32768 (2**15). + from 8 to 27 for 64BIT(20 otherwise), the default number is 12, + which means the table size is 4096. Don't input the number too + small, otherwise you will lose performance on it. You can adapt the + table size yourself, according to your virtual server application. + It is good to set the table size not far less than the number of + connections per second multiplying average lasting time of + connection in the table. For example, your virtual server gets 200 + connections per second, the connection lasts for 200 seconds in + average in the connection table, the table size should be not far + less than 200x200, it is good to set the table size 32768 (2**15). Another note that each connection occupies 128 bytes effectively and each hash entry uses 8 bytes, so you can estimate how much memory is needed for your box. You can overwrite this number setting conn_tab_bits module parameter - or by appending ip_vs.conn_tab_bits=? to the kernel command line - if IP VS was compiled built-in. + or by appending ip_vs.conn_tab_bits=? to the kernel command line if + IP VS was compiled built-in. comment "IPVS transport protocol load balancing support" diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 928e64653837..f4c55e65abd1 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -1485,8 +1485,8 @@ int __init ip_vs_conn_init(void) int idx; /* Compute size and mask */ - if (ip_vs_conn_tab_bits < 8 || ip_vs_conn_tab_bits > 20) { - pr_info("conn_tab_bits not in [8, 20]. Using default value\n"); + if (ip_vs_conn_tab_bits < 8 || ip_vs_conn_tab_bits > 27) { + pr_info("conn_tab_bits not in [8, 27]. Using default value\n"); ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS; } ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits; -- cgit v1.2.3 From 4f325e26277b6a1381235008ca6fa97e6cc8f43b Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Wed, 17 May 2023 15:37:31 +0300 Subject: ipvs: dynamically limit the connection hash table As we allow the hash table to be configured to rows above 2^20, we should limit it depending on the available memory to some sane values. Switch to kvmalloc allocation to better select the needed allocation type. Signed-off-by: Julian Anastasov Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipvs/ip_vs_conn.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index f4c55e65abd1..9065da3cdd12 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -26,7 +26,6 @@ #include #include #include -#include #include /* for proc_net_* */ #include #include @@ -1482,13 +1481,21 @@ void __net_exit ip_vs_conn_net_cleanup(struct netns_ipvs *ipvs) int __init ip_vs_conn_init(void) { size_t tab_array_size; + int max_avail; +#if BITS_PER_LONG > 32 + int max = 27; +#else + int max = 20; +#endif + int min = 8; int idx; - /* Compute size and mask */ - if (ip_vs_conn_tab_bits < 8 || ip_vs_conn_tab_bits > 27) { - pr_info("conn_tab_bits not in [8, 27]. Using default value\n"); - ip_vs_conn_tab_bits = CONFIG_IP_VS_TAB_BITS; - } + max_avail = order_base_2(totalram_pages()) + PAGE_SHIFT; + max_avail -= 2; /* ~4 in hash row */ + max_avail -= 1; /* IPVS up to 1/2 of mem */ + max_avail -= order_base_2(sizeof(struct ip_vs_conn)); + max = clamp(max, min, max_avail); + ip_vs_conn_tab_bits = clamp_val(ip_vs_conn_tab_bits, min, max); ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits; ip_vs_conn_tab_mask = ip_vs_conn_tab_size - 1; @@ -1497,7 +1504,8 @@ int __init ip_vs_conn_init(void) */ tab_array_size = array_size(ip_vs_conn_tab_size, sizeof(*ip_vs_conn_tab)); - ip_vs_conn_tab = vmalloc(tab_array_size); + ip_vs_conn_tab = kvmalloc_array(ip_vs_conn_tab_size, + sizeof(*ip_vs_conn_tab), GFP_KERNEL); if (!ip_vs_conn_tab) return -ENOMEM; @@ -1506,7 +1514,7 @@ int __init ip_vs_conn_init(void) sizeof(struct ip_vs_conn), 0, SLAB_HWCACHE_ALIGN, NULL); if (!ip_vs_conn_cachep) { - vfree(ip_vs_conn_tab); + kvfree(ip_vs_conn_tab); return -ENOMEM; } @@ -1534,5 +1542,5 @@ void ip_vs_conn_cleanup(void) rcu_barrier(); /* Release the empty cache */ kmem_cache_destroy(ip_vs_conn_cachep); - vfree(ip_vs_conn_tab); + kvfree(ip_vs_conn_tab); } -- cgit v1.2.3 From 5ff9424ea03a1fce2298b271eec1dad5ff4df1be Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 31 May 2023 16:20:25 +0200 Subject: devlink: bring port new reply back In the offending fixes commit I mistakenly removed the reply message of the port new command. I was under impression it is a new port notification, partly due to the "notify" in the name of the helper function. Bring the code sending reply with new port message back, this time putting it directly to devlink_nl_cmd_port_new_doit() Fixes: c496daeb8630 ("devlink: remove duplicate port notification") Signed-off-by: Jiri Pirko Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230531142025.2605001-1-jiri@resnulli.us Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlx5/core/sf/devlink.c | 9 ++++--- drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h | 3 ++- include/net/devlink.h | 4 +++- net/devlink/leftover.c | 28 +++++++++++++++++++++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c index c7d4691cb65a..9c02e5ea797c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c @@ -282,7 +282,8 @@ out: static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table, const struct devlink_port_new_attrs *new_attr, - struct netlink_ext_ack *extack) + struct netlink_ext_ack *extack, + struct devlink_port **dl_port) { struct mlx5_eswitch *esw = dev->priv.eswitch; struct mlx5_sf *sf; @@ -296,6 +297,7 @@ static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table, new_attr->controller, new_attr->sfnum); if (err) goto esw_err; + *dl_port = &sf->dl_port; trace_mlx5_sf_add(dev, sf->port_index, sf->controller, sf->hw_fn_id, new_attr->sfnum); return 0; @@ -336,7 +338,8 @@ mlx5_sf_new_check_attr(struct mlx5_core_dev *dev, const struct devlink_port_new_ int mlx5_devlink_sf_port_new(struct devlink *devlink, const struct devlink_port_new_attrs *new_attr, - struct netlink_ext_ack *extack) + struct netlink_ext_ack *extack, + struct devlink_port **dl_port) { struct mlx5_core_dev *dev = devlink_priv(devlink); struct mlx5_sf_table *table; @@ -352,7 +355,7 @@ int mlx5_devlink_sf_port_new(struct devlink *devlink, "Port add is only supported in eswitch switchdev mode or SF ports are disabled."); return -EOPNOTSUPP; } - err = mlx5_sf_add(dev, table, new_attr, extack); + err = mlx5_sf_add(dev, table, new_attr, extack, dl_port); mlx5_sf_table_put(table); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h index c5430b8dcdf6..860f9ddb7107 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h @@ -20,7 +20,8 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev); int mlx5_devlink_sf_port_new(struct devlink *devlink, const struct devlink_port_new_attrs *add_attr, - struct netlink_ext_ack *extack); + struct netlink_ext_ack *extack, + struct devlink_port **dl_port); int mlx5_devlink_sf_port_del(struct devlink *devlink, struct devlink_port *dl_port, struct netlink_ext_ack *extack); diff --git a/include/net/devlink.h b/include/net/devlink.h index fe42ad46cf3b..9a3c51aa6e81 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -1434,6 +1434,7 @@ struct devlink_ops { * @devlink: Devlink instance * @attrs: attributes of the new port * @extack: extack for reporting error messages + * @devlink_port: pointer to store new devlink port pointer * * Devlink core will call this device driver function upon user request * to create a new port function of a specified flavor and optional @@ -1446,7 +1447,8 @@ struct devlink_ops { */ int (*port_new)(struct devlink *devlink, const struct devlink_port_new_attrs *attrs, - struct netlink_ext_ack *extack); + struct netlink_ext_ack *extack, + struct devlink_port **devlink_port); /** * Rate control callbacks. diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index d5ca9fbe2d40..649a9701eb6a 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -1347,6 +1347,9 @@ static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, struct netlink_ext_ack *extack = info->extack; struct devlink_port_new_attrs new_attrs = {}; struct devlink *devlink = info->user_ptr[0]; + struct devlink_port *devlink_port; + struct sk_buff *msg; + int err; if (!devlink->ops->port_new) return -EOPNOTSUPP; @@ -1377,7 +1380,30 @@ static int devlink_nl_cmd_port_new_doit(struct sk_buff *skb, new_attrs.sfnum_valid = true; } - return devlink->ops->port_new(devlink, &new_attrs, extack); + err = devlink->ops->port_new(devlink, &new_attrs, + extack, &devlink_port); + if (err) + return err; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + err = -ENOMEM; + goto err_out_port_del; + } + err = devlink_nl_port_fill(msg, devlink_port, DEVLINK_CMD_NEW, + info->snd_portid, info->snd_seq, 0, NULL); + if (WARN_ON_ONCE(err)) + goto err_out_msg_free; + err = genlmsg_reply(msg, info); + if (err) + goto err_out_port_del; + return 0; + +err_out_msg_free: + nlmsg_free(msg); +err_out_port_del: + devlink_port->ops->port_del(devlink, devlink_port, NULL); + return err; } static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb, -- cgit v1.2.3 From bd415f6c748ec3ca0017f9a6f23a5c02900eb6d2 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 31 May 2023 12:21:12 +0200 Subject: dt-bindings: net: pse-pd: Allow -N suffix for ethernet-pse node names Extend the pattern matching for PSE-PD controller nodes to allow -N suffixes. This enables the use of multiple "ethernet-pse" nodes without the need for a "reg" property. Signed-off-by: Oleksij Rempel Reviewed-by: Krzysztof Kozlowski Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml b/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml index b110abb42597..2d382faca0e6 100644 --- a/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml +++ b/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml @@ -16,7 +16,7 @@ maintainers: properties: $nodename: - pattern: "^ethernet-pse(@.*)?$" + pattern: "^ethernet-pse(@.*|-([0-9]|[1-9][0-9]+))?$" "#pse-cells": description: -- cgit v1.2.3 From 733b3e27650b1bbce3c21fcfdb4fca22063efd66 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 31 May 2023 22:41:32 +0200 Subject: r8169: use dev_err_probe in all appropriate places in rtl_init_one() In addition to properly handling probe deferrals dev_err_probe() conveniently combines printing an error message with returning the errno. So let's use it for every error path in rtl_init_one() to simplify the code. Signed-off-by: Heiner Kallweit Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/f0596a19-d517-e301-b649-304f9247b75a@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 40 ++++++++++++------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 5e6308d574ba..9445f04f8d48 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5196,44 +5196,35 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* enable device (incl. PCI PM wakeup and hotplug setup) */ rc = pcim_enable_device(pdev); - if (rc < 0) { - dev_err(&pdev->dev, "enable failure\n"); - return rc; - } + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "enable failure\n"); if (pcim_set_mwi(pdev) < 0) dev_info(&pdev->dev, "Mem-Wr-Inval unavailable\n"); /* use first MMIO region */ region = ffs(pci_select_bars(pdev, IORESOURCE_MEM)) - 1; - if (region < 0) { - dev_err(&pdev->dev, "no MMIO resource found\n"); - return -ENODEV; - } + if (region < 0) + return dev_err_probe(&pdev->dev, -ENODEV, "no MMIO resource found\n"); rc = pcim_iomap_regions(pdev, BIT(region), KBUILD_MODNAME); - if (rc < 0) { - dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); - return rc; - } + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "cannot remap MMIO, aborting\n"); tp->mmio_addr = pcim_iomap_table(pdev)[region]; txconfig = RTL_R32(tp, TxConfig); - if (txconfig == ~0U) { - dev_err(&pdev->dev, "PCI read failed\n"); - return -EIO; - } + if (txconfig == ~0U) + return dev_err_probe(&pdev->dev, -EIO, "PCI read failed\n"); xid = (txconfig >> 20) & 0xfcf; /* Identify chip attached to board */ chipset = rtl8169_get_mac_version(xid, tp->supports_gmii); - if (chipset == RTL_GIGA_MAC_NONE) { - dev_err(&pdev->dev, "unknown chip XID %03x, contact r8169 maintainers (see MAINTAINERS file)\n", xid); - return -ENODEV; - } - + if (chipset == RTL_GIGA_MAC_NONE) + return dev_err_probe(&pdev->dev, -ENODEV, + "unknown chip XID %03x, contact r8169 maintainers (see MAINTAINERS file)\n", + xid); tp->mac_version = chipset; tp->dash_type = rtl_check_dash(tp); @@ -5253,10 +5244,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_hw_reset(tp); rc = rtl_alloc_irq(tp); - if (rc < 0) { - dev_err(&pdev->dev, "Can't allocate interrupt\n"); - return rc; - } + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n"); + tp->irq = pci_irq_vector(pdev, 0); INIT_WORK(&tp->wk.work, rtl_task); -- cgit v1.2.3 From e8b6f79b41840c542b7ef45c16b31dd17e1cc6e1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 31 May 2023 16:17:29 -0700 Subject: net: phy: broadcom: Add LPI counter Add the ability to read the PHY maintained LPI counter which is in the Clause 45 vendor space, device address 7, offset 0x803F. The counter is cleared on read. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230531231729.1873932-1-florian.fainelli@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/bcm-phy-lib.c | 19 ++++++++++++------- include/linux/brcmphy.h | 2 ++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index 5603d0a9ce96..c6e2e5f636d4 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -496,18 +496,20 @@ EXPORT_SYMBOL_GPL(bcm_phy_downshift_set); struct bcm_phy_hw_stat { const char *string; - u8 reg; + int devad; + u16 reg; u8 shift; u8 bits; }; /* Counters freeze at either 0xffff or 0xff, better than nothing */ static const struct bcm_phy_hw_stat bcm_phy_hw_stats[] = { - { "phy_receive_errors", MII_BRCM_CORE_BASE12, 0, 16 }, - { "phy_serdes_ber_errors", MII_BRCM_CORE_BASE13, 8, 8 }, - { "phy_false_carrier_sense_errors", MII_BRCM_CORE_BASE13, 0, 8 }, - { "phy_local_rcvr_nok", MII_BRCM_CORE_BASE14, 8, 8 }, - { "phy_remote_rcv_nok", MII_BRCM_CORE_BASE14, 0, 8 }, + { "phy_receive_errors", -1, MII_BRCM_CORE_BASE12, 0, 16 }, + { "phy_serdes_ber_errors", -1, MII_BRCM_CORE_BASE13, 8, 8 }, + { "phy_false_carrier_sense_errors", -1, MII_BRCM_CORE_BASE13, 0, 8 }, + { "phy_local_rcvr_nok", -1, MII_BRCM_CORE_BASE14, 8, 8 }, + { "phy_remote_rcv_nok", -1, MII_BRCM_CORE_BASE14, 0, 8 }, + { "phy_lpi_count", MDIO_MMD_AN, BRCM_CL45VEN_EEE_LPI_CNT, 0, 16 }, }; int bcm_phy_get_sset_count(struct phy_device *phydev) @@ -536,7 +538,10 @@ static u64 bcm_phy_get_stat(struct phy_device *phydev, u64 *shadow, int val; u64 ret; - val = phy_read(phydev, stat.reg); + if (stat.devad < 0) + val = phy_read(phydev, stat.reg); + else + val = phy_read_mmd(phydev, stat.devad, stat.reg); if (val < 0) { ret = U64_MAX; } else { diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index e9afbfb6d7a5..251833ab271f 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -359,6 +359,8 @@ #define LPI_FEATURE_EN 0x8000 #define LPI_FEATURE_EN_DIG1000X 0x4000 +#define BRCM_CL45VEN_EEE_LPI_CNT 0x803f + /* Core register definitions*/ #define MII_BRCM_CORE_BASE12 0x12 #define MII_BRCM_CORE_BASE13 0x13 -- cgit v1.2.3 From a395b8d1c7c3a074bfa83b9759a4a11901a295c5 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Thu, 1 Jun 2023 09:22:50 +0800 Subject: selftests/tc-testing: replace mq with invalid parent ID The test case shown in [1] triggers the kernel to access the null pointer. Therefore, add related test cases to mq. The test results are as follows: ./tdc.py -e 0531 1..1 ok 1 0531 - Replace mq with invalid parent ID ./tdc.py -c mq 1..8 ok 1 ce7d - Add mq Qdisc to multi-queue device (4 queues) ok 2 2f82 - Add mq Qdisc to multi-queue device (256 queues) ok 3 c525 - Add duplicate mq Qdisc ok 4 128a - Delete nonexistent mq Qdisc ok 5 03a9 - Delete mq Qdisc twice ok 6 be0f - Add mq Qdisc to single-queue device ok 7 1023 - Show mq class ok 8 0531 - Replace mq with invalid parent ID [1] https://lore.kernel.org/all/20230527093747.3583502-1-shaozhengchao@huawei.com/ Signed-off-by: Zhengchao Shao Reviewed-by: Pedro Tammela Link: https://lore.kernel.org/r/20230601012250.52738-1-shaozhengchao@huawei.com Signed-off-by: Jakub Kicinski --- .../selftests/tc-testing/tc-tests/qdiscs/mq.json | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json index 44fbfc6caec7..e3d2de5c184f 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/mq.json @@ -155,5 +155,28 @@ "teardown": [ "echo \"1\" > /sys/bus/netdevsim/del_device" ] - } + }, + { + "id": "0531", + "name": "Replace mq with invalid parent ID", + "category": [ + "qdisc", + "mq" + ], + "plugins": { + "requires": "nsPlugin" + }, + "setup": [ + "echo \"1 1 16\" > /sys/bus/netdevsim/new_device", + "$TC qdisc add dev $ETH root handle ffff: mq" + ], + "cmdUnderTest": "$TC qdisc replace dev $ETH parent ffff:fff1 handle ffff: mq", + "expExitCode": "2", + "verifyCmd": "$TC qdisc show dev $ETH", + "matchPattern": "qdisc [a-zA-Z0-9_]+ 0: parent ffff", + "matchCount": "16", + "teardown": [ + "echo \"1\" > /sys/bus/netdevsim/del_device" + ] + } ] -- cgit v1.2.3 From 121dca784fc0f6c022493a5d23d86b3cc20380f4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2023 08:35:50 -0700 Subject: tls: suppress wakeups unless we have a full record TLS does not override .poll() so TLS-enabled socket will generate an event whenever data arrives at the TCP socket. This leads to unnecessary wakeups on slow connections. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- net/tls/tls_main.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 3d45fdb5c4e9..e02a0d882ed3 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -358,6 +358,39 @@ static void tls_sk_proto_close(struct sock *sk, long timeout) tls_ctx_free(sk, ctx); } +static __poll_t tls_sk_poll(struct file *file, struct socket *sock, + struct poll_table_struct *wait) +{ + struct tls_sw_context_rx *ctx; + struct tls_context *tls_ctx; + struct sock *sk = sock->sk; + struct sk_psock *psock; + __poll_t mask = 0; + u8 shutdown; + int state; + + mask = tcp_poll(file, sock, wait); + + state = inet_sk_state_load(sk); + shutdown = READ_ONCE(sk->sk_shutdown); + if (unlikely(state != TCP_ESTABLISHED || shutdown & RCV_SHUTDOWN)) + return mask; + + tls_ctx = tls_get_ctx(sk); + ctx = tls_sw_ctx_rx(tls_ctx); + psock = sk_psock_get(sk); + + if (skb_queue_empty_lockless(&ctx->rx_list) && + !tls_strp_msg_ready(ctx) && + sk_psock_queue_empty(psock)) + mask &= ~(EPOLLIN | EPOLLRDNORM); + + if (psock) + sk_psock_put(sk, psock); + + return mask; +} + static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval, int __user *optlen, int tx) { @@ -928,9 +961,11 @@ static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG] ops[TLS_BASE][TLS_SW ] = ops[TLS_BASE][TLS_BASE]; ops[TLS_BASE][TLS_SW ].splice_read = tls_sw_splice_read; + ops[TLS_BASE][TLS_SW ].poll = tls_sk_poll; ops[TLS_SW ][TLS_SW ] = ops[TLS_SW ][TLS_BASE]; ops[TLS_SW ][TLS_SW ].splice_read = tls_sw_splice_read; + ops[TLS_SW ][TLS_SW ].poll = tls_sk_poll; #ifdef CONFIG_TLS_DEVICE ops[TLS_HW ][TLS_BASE] = ops[TLS_BASE][TLS_BASE]; -- cgit v1.2.3 From 23fcb62bc19c37adb72a585d5dc702ac55b74fb1 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 31 May 2023 08:35:51 -0700 Subject: selftests: tls: add tests for poll behavior Make sure we don't generate premature POLLIN events. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/testing/selftests/net/tls.c | 131 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index e699548d4247..eccea9845c65 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -1637,6 +1638,136 @@ TEST_F(tls_err, timeo) } } +TEST_F(tls_err, poll_partial_rec) +{ + struct pollfd pfd = { }; + ssize_t rec_len; + char rec[256]; + char buf[128]; + + if (self->notls) + SKIP(return, "no TLS support"); + + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 1), 0); + + memrnd(buf, sizeof(buf)); + EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf)); + rec_len = recv(self->cfd, rec, sizeof(rec), 0); + EXPECT_GT(rec_len, sizeof(buf)); + + /* Write 100B, not the full record ... */ + EXPECT_EQ(send(self->fd2, rec, 100, 0), 100); + /* ... no full record should mean no POLLIN */ + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 1), 0); + /* Now write the rest, and it should all pop out of the other end. */ + EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), rec_len - 100); + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 1), 1); + EXPECT_EQ(recv(self->cfd2, rec, sizeof(rec), 0), sizeof(buf)); + EXPECT_EQ(memcmp(buf, rec, sizeof(buf)), 0); +} + +TEST_F(tls_err, epoll_partial_rec) +{ + struct epoll_event ev, events[10]; + ssize_t rec_len; + char rec[256]; + char buf[128]; + int epollfd; + + if (self->notls) + SKIP(return, "no TLS support"); + + epollfd = epoll_create1(0); + ASSERT_GE(epollfd, 0); + + memset(&ev, 0, sizeof(ev)); + ev.events = EPOLLIN; + ev.data.fd = self->cfd2; + ASSERT_GE(epoll_ctl(epollfd, EPOLL_CTL_ADD, self->cfd2, &ev), 0); + + EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 0); + + memrnd(buf, sizeof(buf)); + EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf)); + rec_len = recv(self->cfd, rec, sizeof(rec), 0); + EXPECT_GT(rec_len, sizeof(buf)); + + /* Write 100B, not the full record ... */ + EXPECT_EQ(send(self->fd2, rec, 100, 0), 100); + /* ... no full record should mean no POLLIN */ + EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 0); + /* Now write the rest, and it should all pop out of the other end. */ + EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), rec_len - 100); + EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 1); + EXPECT_EQ(recv(self->cfd2, rec, sizeof(rec), 0), sizeof(buf)); + EXPECT_EQ(memcmp(buf, rec, sizeof(buf)), 0); + + close(epollfd); +} + +TEST_F(tls_err, poll_partial_rec_async) +{ + struct pollfd pfd = { }; + ssize_t rec_len; + char rec[256]; + char buf[128]; + char token; + int p[2]; + int ret; + + if (self->notls) + SKIP(return, "no TLS support"); + + ASSERT_GE(pipe(p), 0); + + memrnd(buf, sizeof(buf)); + EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf)); + rec_len = recv(self->cfd, rec, sizeof(rec), 0); + EXPECT_GT(rec_len, sizeof(buf)); + + ret = fork(); + ASSERT_GE(ret, 0); + + if (ret) { + int status, pid2; + + close(p[1]); + usleep(1000); /* Give child a head start */ + + EXPECT_EQ(send(self->fd2, rec, 100, 0), 100); + + EXPECT_EQ(read(p[0], &token, 1), 1); /* Barrier #1 */ + + EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), + rec_len - 100); + + pid2 = wait(&status); + EXPECT_EQ(pid2, ret); + EXPECT_EQ(status, 0); + } else { + close(p[0]); + + /* Child should sleep in poll(), never get a wake */ + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 5), 0); + + EXPECT_EQ(write(p[1], &token, 1), 1); /* Barrier #1 */ + + pfd.fd = self->cfd2; + pfd.events = POLLIN; + EXPECT_EQ(poll(&pfd, 1, 5), 1); + + exit(!_metadata->passed); + } +} + TEST(non_established) { struct tls12_crypto_info_aes_gcm_256 tls12; struct sockaddr_in addr; -- cgit v1.2.3 From a92fb5c0340411c66b48f66b6b8854f271e4ca8d Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 2 Jun 2023 13:59:25 +0800 Subject: ip_gre: clean up some inconsistent indenting No functional modification involved. net/ipv4/ip_gre.c:192 ipgre_err() warn: inconsistent indenting. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5375 Signed-off-by: Jiapeng Chong Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index e55a20264960..81a1cce1a7d1 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -189,10 +189,10 @@ static int ipgre_err(struct sk_buff *skb, u32 info, } #if IS_ENABLED(CONFIG_IPV6) - if (tpi->proto == htons(ETH_P_IPV6) && - !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, - type, data_len)) - return 0; + if (tpi->proto == htons(ETH_P_IPV6) && + !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4 + tpi->hdr_len, + type, data_len)) + return 0; #endif if (t->parms.iph.daddr == 0 || -- cgit v1.2.3 From 0f0f5868689ecbf643b723fae1a353c5a11a8e46 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Fri, 2 Jun 2023 00:04:14 +0000 Subject: net: lan743x: Remove extranous gotos The gotos for cleanup aren't required, the function might as well just return the actual error code. Signed-off-by: Moritz Fischer Reviewed-by: Siddharth Vadapalli Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/lan743x_main.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index 957d96a91a8a..f1bded993edc 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -160,16 +160,13 @@ static int lan743x_csr_init(struct lan743x_adapter *adapter) { struct lan743x_csr *csr = &adapter->csr; resource_size_t bar_start, bar_length; - int result; bar_start = pci_resource_start(adapter->pdev, 0); bar_length = pci_resource_len(adapter->pdev, 0); csr->csr_address = devm_ioremap(&adapter->pdev->dev, bar_start, bar_length); - if (!csr->csr_address) { - result = -ENOMEM; - goto clean_up; - } + if (!csr->csr_address) + return -ENOMEM; csr->id_rev = lan743x_csr_read(adapter, ID_REV); csr->fpga_rev = lan743x_csr_read(adapter, FPGA_REV); @@ -177,10 +174,8 @@ static int lan743x_csr_init(struct lan743x_adapter *adapter) "ID_REV = 0x%08X, FPGA_REV = %d.%d\n", csr->id_rev, FPGA_REV_GET_MAJOR_(csr->fpga_rev), FPGA_REV_GET_MINOR_(csr->fpga_rev)); - if (!ID_REV_IS_VALID_CHIP_ID_(csr->id_rev)) { - result = -ENODEV; - goto clean_up; - } + if (!ID_REV_IS_VALID_CHIP_ID_(csr->id_rev)) + return -ENODEV; csr->flags = LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR; switch (csr->id_rev & ID_REV_CHIP_REV_MASK_) { @@ -193,12 +188,7 @@ static int lan743x_csr_init(struct lan743x_adapter *adapter) break; } - result = lan743x_csr_light_reset(adapter); - if (result) - goto clean_up; - return 0; -clean_up: - return result; + return lan743x_csr_light_reset(adapter); } static void lan743x_intr_software_isr(struct lan743x_adapter *adapter) -- cgit v1.2.3 From 3f06760c00f56c5fe6c7f3361c2cf64becee1174 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Thu, 1 Jun 2023 18:37:46 +0200 Subject: ipv4: Drop tos parameter from flowi4_update_output() Callers of flowi4_update_output() never try to update ->flowi4_tos: * ip_route_connect() updates ->flowi4_tos with its own current value. * ip_route_newports() has two users: tcp_v4_connect() and dccp_v4_connect. Both initialise fl4 with ip_route_connect(), which in turn sets ->flowi4_tos with RT_TOS(inet_sk(sk)->tos) and ->flowi4_scope based on SOCK_LOCALROUTE. Then ip_route_newports() updates ->flowi4_tos with RT_CONN_FLAGS(sk), which is the same as RT_TOS(inet_sk(sk)->tos), unless SOCK_LOCALROUTE is set on the socket. In that case, the lowest order bit is set to 1, to eventually inform ip_route_output_key_hash() to restrict the scope to RT_SCOPE_LINK. This is equivalent to properly setting ->flowi4_scope as ip_route_connect() did. * ip_vs_xmit.c initialises ->flowi4_tos with memset(0), then calls flowi4_update_output() with tos=0. * sctp_v4_get_dst() uses the same RT_CONN_FLAGS_TOS() when initialising ->flowi4_tos and when calling flowi4_update_output(). In the end, ->flowi4_tos never changes. So let's just drop the tos parameter. This will simplify the conversion of ->flowi4_tos from __u8 to dscp_t. Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller --- include/net/flow.h | 3 +-- include/net/route.h | 6 ++---- net/netfilter/ipvs/ip_vs_xmit.c | 4 ++-- net/sctp/protocol.c | 4 +--- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/net/flow.h b/include/net/flow.h index bb8651a6eaa7..7f0adda3bf2f 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -116,11 +116,10 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, } /* Reset some input parameters after previous lookup */ -static inline void flowi4_update_output(struct flowi4 *fl4, int oif, __u8 tos, +static inline void flowi4_update_output(struct flowi4 *fl4, int oif, __be32 daddr, __be32 saddr) { fl4->flowi4_oif = oif; - fl4->flowi4_tos = tos; fl4->daddr = daddr; fl4->saddr = saddr; } diff --git a/include/net/route.h b/include/net/route.h index bcc367cf3aa2..5a5c726472bd 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -321,8 +321,7 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4, __be32 dst, if (IS_ERR(rt)) return rt; ip_rt_put(rt); - flowi4_update_output(fl4, oif, fl4->flowi4_tos, fl4->daddr, - fl4->saddr); + flowi4_update_output(fl4, oif, fl4->daddr, fl4->saddr); } security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4)); return ip_route_output_flow(net, fl4, sk); @@ -337,8 +336,7 @@ static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable fl4->fl4_dport = dport; fl4->fl4_sport = sport; ip_rt_put(rt); - flowi4_update_output(fl4, sk->sk_bound_dev_if, - RT_CONN_FLAGS(sk), fl4->daddr, + flowi4_update_output(fl4, sk->sk_bound_dev_if, fl4->daddr, fl4->saddr); security_sk_classify_flow(sk, flowi4_to_flowi_common(fl4)); return ip_route_output_flow(sock_net(sk), fl4, sk); diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index feb1d7fcb09f..c7652da78c88 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -139,7 +139,7 @@ retry: if (PTR_ERR(rt) == -EINVAL && *saddr && rt_mode & IP_VS_RT_MODE_CONNECT && !loop) { *saddr = 0; - flowi4_update_output(&fl4, 0, 0, daddr, 0); + flowi4_update_output(&fl4, 0, daddr, 0); goto retry; } IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", &daddr); @@ -147,7 +147,7 @@ retry: } else if (!*saddr && rt_mode & IP_VS_RT_MODE_CONNECT && fl4.saddr) { ip_rt_put(rt); *saddr = fl4.saddr; - flowi4_update_output(&fl4, 0, 0, daddr, fl4.saddr); + flowi4_update_output(&fl4, 0, daddr, fl4.saddr); loop = true; goto retry; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index c365df24ad33..664d1f2e9121 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -500,9 +500,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, continue; fl4->fl4_sport = laddr->a.v4.sin_port; - flowi4_update_output(fl4, - asoc->base.sk->sk_bound_dev_if, - RT_CONN_FLAGS_TOS(asoc->base.sk, tos), + flowi4_update_output(fl4, asoc->base.sk->sk_bound_dev_if, daddr->v4.sin_addr.s_addr, laddr->a.v4.sin_addr.s_addr); -- cgit v1.2.3 From 953bb24ddc118a5a3021a90a8cab8eae946238e7 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Tue, 29 Mar 2022 14:35:22 +0000 Subject: net/mlx5e: en_tc, Extend peer flows to a list Currently, mlx5e_flow is holding a pointer to a peer_flow, in case one was created. e.g. There is an assumption that mlx5e_flow can have only one peer. In order to support more than one peer, refactor mlx5e_flow to hold a list of peer flows. Signed-off-by: Mark Bloch Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en/tc_priv.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 43 ++++++++++++++-------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h index ba2b1f24ff14..8a500a966f06 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h @@ -94,13 +94,13 @@ struct mlx5e_tc_flow { * destinations. */ struct encap_flow_item encaps[MLX5_MAX_FLOW_FWD_VPORTS]; - struct mlx5e_tc_flow *peer_flow; struct mlx5e_hairpin_entry *hpe; /* attached hairpin instance */ struct list_head hairpin; /* flows sharing the same hairpin */ struct list_head peer; /* flows with peer flow */ struct list_head unready; /* flows not ready to be offloaded (e.g * due to missing route) */ + struct list_head peer_flows; /* flows on peer */ struct net_device *orig_dev; /* netdev adding flow first */ int tmp_entry_index; struct list_head tmp_list; /* temporary flow list used by neigh update */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index fd9f928e25c7..9c9c7024772f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1989,6 +1989,8 @@ void mlx5e_put_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list) static void __mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) { struct mlx5_eswitch *esw = flow->priv->mdev->priv.eswitch; + struct mlx5e_tc_flow *peer_flow; + struct mlx5e_tc_flow *tmp; if (!flow_flag_test(flow, ESWITCH) || !flow_flag_test(flow, DUP)) @@ -2000,12 +2002,13 @@ static void __mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) flow_flag_clear(flow, DUP); - if (refcount_dec_and_test(&flow->peer_flow->refcnt)) { - mlx5e_tc_del_fdb_flow(flow->peer_flow->priv, flow->peer_flow); - kfree(flow->peer_flow); + list_for_each_entry_safe(peer_flow, tmp, &flow->peer_flows, peer_flows) { + if (refcount_dec_and_test(&peer_flow->refcnt)) { + mlx5e_tc_del_fdb_flow(peer_flow->priv, peer_flow); + list_del(&peer_flow->peer_flows); + kfree(peer_flow); + } } - - flow->peer_flow = NULL; } static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) @@ -4295,6 +4298,7 @@ mlx5e_alloc_flow(struct mlx5e_priv *priv, int attr_size, INIT_LIST_HEAD(&flow->hairpin); INIT_LIST_HEAD(&flow->l3_to_l2_reformat); INIT_LIST_HEAD(&flow->attrs); + INIT_LIST_HEAD(&flow->peer_flows); refcount_set(&flow->refcnt, 1); init_completion(&flow->init_done); init_completion(&flow->del_hw_done); @@ -4443,7 +4447,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f, goto out; } - flow->peer_flow = peer_flow; + list_add_tail(&peer_flow->peer_flows, &flow->peer_flows); flow_flag_set(flow, DUP); mutex_lock(&esw->offloads.peer_mutex); list_add_tail(&flow->peer, &esw->offloads.peer_flows); @@ -4741,19 +4745,26 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv, if (!peer_esw) goto out; - if (flow_flag_test(flow, DUP) && - flow_flag_test(flow->peer_flow, OFFLOADED)) { - u64 bytes2; - u64 packets2; - u64 lastuse2; + if (flow_flag_test(flow, DUP)) { + struct mlx5e_tc_flow *peer_flow; - if (flow_flag_test(flow, USE_ACT_STATS)) { - f->use_act_stats = true; - } else { - counter = mlx5e_tc_get_counter(flow->peer_flow); + list_for_each_entry(peer_flow, &flow->peer_flows, peer_flows) { + u64 packets2; + u64 lastuse2; + u64 bytes2; + + if (!flow_flag_test(peer_flow, OFFLOADED)) + continue; + if (flow_flag_test(flow, USE_ACT_STATS)) { + f->use_act_stats = true; + break; + } + + counter = mlx5e_tc_get_counter(peer_flow); if (!counter) goto no_peer_counter; - mlx5_fc_query_cached(counter, &bytes2, &packets2, &lastuse2); + mlx5_fc_query_cached(counter, &bytes2, &packets2, + &lastuse2); bytes += bytes2; packets += packets2; -- cgit v1.2.3 From b1661efa4dbbd7d4055543f036cae6c28257d292 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 29 Mar 2022 14:47:20 +0000 Subject: net/mlx5e: tc, Refactor peer add/del flow Move peer_eswitch outside mlx5e_tc_add_fdb_peer_flow() so downstream patch can call mlx5e_tc_add_fdb_peer_flow() with multiple peers. Move peer_eswitch in the remove flow as well in order to keep symmetry. Signed-off-by: Mark Bloch Signed-off-by: Shay Drory Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 65 +++++++++++++------------ 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 9c9c7024772f..6f9adb940588 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1986,7 +1986,7 @@ void mlx5e_put_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list) mlx5e_flow_put(priv, flow); } -static void __mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) +static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) { struct mlx5_eswitch *esw = flow->priv->mdev->priv.eswitch; struct mlx5e_tc_flow *peer_flow; @@ -2011,25 +2011,20 @@ static void __mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) } } -static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) -{ - struct mlx5_core_dev *dev = flow->priv->mdev; - struct mlx5_devcom *devcom = dev->priv.devcom; - struct mlx5_eswitch *peer_esw; - - peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - if (!peer_esw) - return; - - __mlx5e_tc_del_fdb_peer_flow(flow); - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); -} - static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow) { if (mlx5e_is_eswitch_flow(flow)) { + struct mlx5_devcom *devcom = flow->priv->mdev->priv.devcom; + struct mlx5_eswitch *peer_esw; + + peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + if (!peer_esw) { + mlx5e_tc_del_fdb_flow(priv, flow); + return; + } mlx5e_tc_del_fdb_peer_flow(flow); + mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); mlx5e_tc_del_fdb_flow(priv, flow); } else { mlx5e_tc_del_nic_flow(priv, flow); @@ -4407,22 +4402,18 @@ out: static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f, struct mlx5e_tc_flow *flow, - unsigned long flow_flags) + unsigned long flow_flags, + struct mlx5_eswitch *peer_esw) { struct mlx5e_priv *priv = flow->priv, *peer_priv; - struct mlx5_eswitch *esw = priv->mdev->priv.eswitch, *peer_esw; + struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr; - struct mlx5_devcom *devcom = priv->mdev->priv.devcom; struct mlx5e_tc_flow_parse_attr *parse_attr; struct mlx5e_rep_priv *peer_urpriv; struct mlx5e_tc_flow *peer_flow; struct mlx5_core_dev *in_mdev; int err = 0; - peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - if (!peer_esw) - return -ENODEV; - peer_urpriv = mlx5_eswitch_get_uplink_priv(peer_esw, REP_ETH); peer_priv = netdev_priv(peer_urpriv->netdev); @@ -4454,7 +4445,6 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f, mutex_unlock(&esw->offloads.peer_mutex); out: - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); return err; } @@ -4465,9 +4455,11 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv, struct net_device *filter_dev, struct mlx5e_tc_flow **__flow) { + struct mlx5_devcom *devcom = priv->mdev->priv.devcom; struct mlx5e_rep_priv *rpriv = priv->ppriv; struct mlx5_eswitch_rep *in_rep = rpriv->rep; struct mlx5_core_dev *in_mdev = priv->mdev; + struct mlx5_eswitch *peer_esw; struct mlx5e_tc_flow *flow; int err; @@ -4476,19 +4468,30 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv, if (IS_ERR(flow)) return PTR_ERR(flow); - if (is_peer_flow_needed(flow)) { - err = mlx5e_tc_add_fdb_peer_flow(f, flow, flow_flags); - if (err) { - mlx5e_tc_del_fdb_flow(priv, flow); - goto out; - } + if (!is_peer_flow_needed(flow)) { + *__flow = flow; + return 0; } + peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + if (!peer_esw) { + err = -ENODEV; + goto clean_flow; + } + + err = mlx5e_tc_add_fdb_peer_flow(f, flow, flow_flags, peer_esw); + if (err) + goto peer_clean; + mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + *__flow = flow; return 0; -out: +peer_clean: + mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); +clean_flow: + mlx5e_tc_del_fdb_flow(priv, flow); return err; } @@ -5293,7 +5296,7 @@ void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw) struct mlx5e_tc_flow *flow, *tmp; list_for_each_entry_safe(flow, tmp, &esw->offloads.peer_flows, peer) - __mlx5e_tc_del_fdb_peer_flow(flow); + mlx5e_tc_del_fdb_peer_flow(flow); } void mlx5e_tc_reoffload_flows_work(struct work_struct *work) -- cgit v1.2.3 From ed7a8fe71836fda7d669d4a3afbd5f4dba742c18 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Wed, 30 Mar 2022 07:16:23 +0000 Subject: net/mlx5e: rep, store send to vport rules per peer Each representor, for each send queue, is holding a send_to_vport rule for the peer eswitch. In order to support more than one peer, and to map between the peer rules and peer eswitches, refactor representor to hold both the peer rules and pointer to the peer eswitches. This enables mlx5 to store send_to_vport rules per peer, where each peer have dedicate index via mlx5_get_dev_index(). Signed-off-by: Mark Bloch Signed-off-by: Shay Drory Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 99 ++++++++++++++++++---- drivers/net/ethernet/mellanox/mlx5/core/en_rep.h | 7 +- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 18 ++-- 3 files changed, 98 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 3e7041bd5705..3fbb454f7228 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -374,7 +374,9 @@ static void mlx5e_sqs2vport_stop(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep) { struct mlx5e_rep_sq *rep_sq, *tmp; + struct mlx5e_rep_sq_peer *sq_peer; struct mlx5e_rep_priv *rpriv; + unsigned long i; if (esw->mode != MLX5_ESWITCH_OFFLOADS) return; @@ -382,8 +384,15 @@ static void mlx5e_sqs2vport_stop(struct mlx5_eswitch *esw, rpriv = mlx5e_rep_to_rep_priv(rep); list_for_each_entry_safe(rep_sq, tmp, &rpriv->vport_sqs_list, list) { mlx5_eswitch_del_send_to_vport_rule(rep_sq->send_to_vport_rule); - if (rep_sq->send_to_vport_rule_peer) - mlx5_eswitch_del_send_to_vport_rule(rep_sq->send_to_vport_rule_peer); + xa_for_each(&rep_sq->sq_peer, i, sq_peer) { + if (sq_peer->rule) + mlx5_eswitch_del_send_to_vport_rule(sq_peer->rule); + + xa_erase(&rep_sq->sq_peer, i); + kfree(sq_peer); + } + + xa_destroy(&rep_sq->sq_peer); list_del(&rep_sq->list); kfree(rep_sq); } @@ -395,6 +404,7 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw, { struct mlx5_eswitch *peer_esw = NULL; struct mlx5_flow_handle *flow_rule; + struct mlx5e_rep_sq_peer *sq_peer; struct mlx5e_rep_priv *rpriv; struct mlx5e_rep_sq *rep_sq; int err; @@ -414,6 +424,7 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw, err = -ENOMEM; goto out_err; } + xa_init(&rep_sq->sq_peer); /* Add re-inject rule to the PF/representor sqs */ flow_rule = mlx5_eswitch_add_send_to_vport_rule(esw, esw, rep, @@ -427,15 +438,26 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw, rep_sq->sqn = sqns_array[i]; if (peer_esw) { + int peer_rule_idx = mlx5_get_dev_index(peer_esw->dev); + + sq_peer = kzalloc(sizeof(*sq_peer), GFP_KERNEL); + if (!sq_peer) { + err = -ENOMEM; + goto out_sq_peer_err; + } + flow_rule = mlx5_eswitch_add_send_to_vport_rule(peer_esw, esw, rep, sqns_array[i]); if (IS_ERR(flow_rule)) { err = PTR_ERR(flow_rule); - mlx5_eswitch_del_send_to_vport_rule(rep_sq->send_to_vport_rule); - kfree(rep_sq); - goto out_err; + goto out_flow_rule_err; } - rep_sq->send_to_vport_rule_peer = flow_rule; + + sq_peer->rule = flow_rule; + sq_peer->peer = peer_esw; + err = xa_insert(&rep_sq->sq_peer, peer_rule_idx, sq_peer, GFP_KERNEL); + if (err) + goto out_xa_err; } list_add(&rep_sq->list, &rpriv->vport_sqs_list); @@ -446,6 +468,14 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw, return 0; +out_xa_err: + mlx5_eswitch_del_send_to_vport_rule(flow_rule); +out_flow_rule_err: + kfree(sq_peer); +out_sq_peer_err: + mlx5_eswitch_del_send_to_vport_rule(rep_sq->send_to_vport_rule); + xa_destroy(&rep_sq->sq_peer); + kfree(rep_sq); out_err: mlx5e_sqs2vport_stop(esw, rep); @@ -1530,17 +1560,24 @@ static void *mlx5e_vport_rep_get_proto_dev(struct mlx5_eswitch_rep *rep) return rpriv->netdev; } -static void mlx5e_vport_rep_event_unpair(struct mlx5_eswitch_rep *rep) +static void mlx5e_vport_rep_event_unpair(struct mlx5_eswitch_rep *rep, + struct mlx5_eswitch *peer_esw) { + int i = mlx5_get_dev_index(peer_esw->dev); struct mlx5e_rep_priv *rpriv; struct mlx5e_rep_sq *rep_sq; + WARN_ON_ONCE(!peer_esw); rpriv = mlx5e_rep_to_rep_priv(rep); list_for_each_entry(rep_sq, &rpriv->vport_sqs_list, list) { - if (!rep_sq->send_to_vport_rule_peer) + struct mlx5e_rep_sq_peer *sq_peer = xa_load(&rep_sq->sq_peer, i); + + if (!sq_peer || sq_peer->peer != peer_esw) continue; - mlx5_eswitch_del_send_to_vport_rule(rep_sq->send_to_vport_rule_peer); - rep_sq->send_to_vport_rule_peer = NULL; + + mlx5_eswitch_del_send_to_vport_rule(sq_peer->rule); + xa_erase(&rep_sq->sq_peer, i); + kfree(sq_peer); } } @@ -1548,24 +1585,52 @@ static int mlx5e_vport_rep_event_pair(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep, struct mlx5_eswitch *peer_esw) { + int i = mlx5_get_dev_index(peer_esw->dev); struct mlx5_flow_handle *flow_rule; + struct mlx5e_rep_sq_peer *sq_peer; struct mlx5e_rep_priv *rpriv; struct mlx5e_rep_sq *rep_sq; + int err; rpriv = mlx5e_rep_to_rep_priv(rep); list_for_each_entry(rep_sq, &rpriv->vport_sqs_list, list) { - if (rep_sq->send_to_vport_rule_peer) + sq_peer = xa_load(&rep_sq->sq_peer, i); + + if (sq_peer && sq_peer->peer) continue; - flow_rule = mlx5_eswitch_add_send_to_vport_rule(peer_esw, esw, rep, rep_sq->sqn); - if (IS_ERR(flow_rule)) + + flow_rule = mlx5_eswitch_add_send_to_vport_rule(peer_esw, esw, rep, + rep_sq->sqn); + if (IS_ERR(flow_rule)) { + err = PTR_ERR(flow_rule); goto err_out; - rep_sq->send_to_vport_rule_peer = flow_rule; + } + + if (sq_peer) { + sq_peer->rule = flow_rule; + sq_peer->peer = peer_esw; + continue; + } + sq_peer = kzalloc(sizeof(*sq_peer), GFP_KERNEL); + if (!sq_peer) { + err = -ENOMEM; + goto err_sq_alloc; + } + err = xa_insert(&rep_sq->sq_peer, i, sq_peer, GFP_KERNEL); + if (err) + goto err_xa; + sq_peer->rule = flow_rule; + sq_peer->peer = peer_esw; } return 0; +err_xa: + kfree(sq_peer); +err_sq_alloc: + mlx5_eswitch_del_send_to_vport_rule(flow_rule); err_out: - mlx5e_vport_rep_event_unpair(rep); - return PTR_ERR(flow_rule); + mlx5e_vport_rep_event_unpair(rep, peer_esw); + return err; } static int mlx5e_vport_rep_event(struct mlx5_eswitch *esw, @@ -1578,7 +1643,7 @@ static int mlx5e_vport_rep_event(struct mlx5_eswitch *esw, if (event == MLX5_SWITCHDEV_EVENT_PAIR) err = mlx5e_vport_rep_event_pair(esw, rep, data); else if (event == MLX5_SWITCHDEV_EVENT_UNPAIR) - mlx5e_vport_rep_event_unpair(rep); + mlx5e_vport_rep_event_unpair(rep, data); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h index 80b7f5079a5a..70640fa1ad7b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.h @@ -225,9 +225,14 @@ struct mlx5e_encap_entry { struct rcu_head rcu; }; +struct mlx5e_rep_sq_peer { + struct mlx5_flow_handle *rule; + void *peer; +}; + struct mlx5e_rep_sq { struct mlx5_flow_handle *send_to_vport_rule; - struct mlx5_flow_handle *send_to_vport_rule_peer; + struct xarray sq_peer; u32 sqn; struct list_head list; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 1b2f5e273525..9526382f1573 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2673,7 +2673,8 @@ void mlx5_eswitch_offloads_destroy_single_fdb(struct mlx5_eswitch *master_esw, #define ESW_OFFLOADS_DEVCOM_PAIR (0) #define ESW_OFFLOADS_DEVCOM_UNPAIR (1) -static void mlx5_esw_offloads_rep_event_unpair(struct mlx5_eswitch *esw) +static void mlx5_esw_offloads_rep_event_unpair(struct mlx5_eswitch *esw, + struct mlx5_eswitch *peer_esw) { const struct mlx5_eswitch_rep_ops *ops; struct mlx5_eswitch_rep *rep; @@ -2686,17 +2687,18 @@ static void mlx5_esw_offloads_rep_event_unpair(struct mlx5_eswitch *esw) ops = esw->offloads.rep_ops[rep_type]; if (atomic_read(&rep->rep_data[rep_type].state) == REP_LOADED && ops->event) - ops->event(esw, rep, MLX5_SWITCHDEV_EVENT_UNPAIR, NULL); + ops->event(esw, rep, MLX5_SWITCHDEV_EVENT_UNPAIR, peer_esw); } } } -static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw) +static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw, + struct mlx5_eswitch *peer_esw) { #if IS_ENABLED(CONFIG_MLX5_CLS_ACT) mlx5e_tc_clean_fdb_peer_flows(esw); #endif - mlx5_esw_offloads_rep_event_unpair(esw); + mlx5_esw_offloads_rep_event_unpair(esw, peer_esw); esw_del_fdb_peer_miss_rules(esw); } @@ -2728,7 +2730,7 @@ static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw, return 0; err_out: - mlx5_esw_offloads_unpair(esw); + mlx5_esw_offloads_unpair(esw, peer_esw); return err; } @@ -2802,8 +2804,8 @@ static int mlx5_esw_offloads_devcom_event(int event, mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false); esw->paired[mlx5_get_dev_index(peer_esw->dev)] = false; peer_esw->paired[mlx5_get_dev_index(esw->dev)] = false; - mlx5_esw_offloads_unpair(peer_esw); - mlx5_esw_offloads_unpair(esw); + mlx5_esw_offloads_unpair(peer_esw, esw); + mlx5_esw_offloads_unpair(esw, peer_esw); mlx5_esw_offloads_set_ns_peer(esw, peer_esw, false); break; } @@ -2811,7 +2813,7 @@ static int mlx5_esw_offloads_devcom_event(int event, return 0; err_pair: - mlx5_esw_offloads_unpair(esw); + mlx5_esw_offloads_unpair(esw, peer_esw); err_peer: mlx5_esw_offloads_set_ns_peer(esw, peer_esw, false); err_out: -- cgit v1.2.3 From 0af3613ddc915d136e9c56f645f80c4b1cb828ff Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Wed, 30 Mar 2022 08:51:16 +0000 Subject: net/mlx5e: en_tc, re-factor query route port query for peer esw outside of if scope. This is preparation for query route port over multiple peers. Signed-off-by: Mark Bloch Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 32 ++++++++++--------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 6f9adb940588..a096005fd163 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1666,8 +1666,10 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro { struct mlx5e_priv *out_priv, *route_priv; struct mlx5_core_dev *route_mdev; + struct mlx5_devcom *devcom; struct mlx5_eswitch *esw; u16 vhca_id; + int err; out_priv = netdev_priv(out_dev); esw = out_priv->mdev->priv.eswitch; @@ -1675,28 +1677,20 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro route_mdev = route_priv->mdev; vhca_id = MLX5_CAP_GEN(route_mdev, vhca_id); - if (mlx5_lag_is_active(out_priv->mdev)) { - struct mlx5_devcom *devcom; - int err; - - /* In lag case we may get devices from different eswitch instances. - * If we failed to get vport num, it means, mostly, that we on the wrong - * eswitch. - */ - err = mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport); - if (err != -ENOENT) - return err; - - rcu_read_lock(); - devcom = out_priv->mdev->priv.devcom; - esw = mlx5_devcom_get_peer_data_rcu(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - err = esw ? mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport) : -ENODEV; - rcu_read_unlock(); + err = mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport); + if (!err) + return err; + if (!mlx5_lag_is_active(out_priv->mdev)) return err; - } - return mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport); + rcu_read_lock(); + devcom = out_priv->mdev->priv.devcom; + esw = mlx5_devcom_get_peer_data_rcu(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + err = esw ? mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport) : -ENODEV; + rcu_read_unlock(); + + return err; } static int -- cgit v1.2.3 From 9be6c21fdcf8a7ec48262bb76f78c17ac2761ac6 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Mon, 6 Feb 2023 10:12:34 +0200 Subject: net/mlx5e: Handle offloads flows per peer Currently, E-switch offloads table have a list of all flows that create a peer_flow over the peer eswitch. In order to support more than one peer, extend E-switch offloads table peer_flow to hold an array of lists, where each peer have dedicate index via mlx5_get_dev_index(). Thereafter, extend original flow to hold an array of peers as well. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en/tc_priv.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 37 +++++++++++++++++----- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 2 +- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 ++- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h index 8a500a966f06..6cc23af66b5b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h @@ -96,7 +96,7 @@ struct mlx5e_tc_flow { struct encap_flow_item encaps[MLX5_MAX_FLOW_FWD_VPORTS]; struct mlx5e_hairpin_entry *hpe; /* attached hairpin instance */ struct list_head hairpin; /* flows sharing the same hairpin */ - struct list_head peer; /* flows with peer flow */ + struct list_head peer[MLX5_MAX_PORTS]; /* flows with peer flow */ struct list_head unready; /* flows not ready to be offloaded (e.g * due to missing route) */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index a096005fd163..c7797e3de093 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1980,7 +1980,8 @@ void mlx5e_put_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list) mlx5e_flow_put(priv, flow); } -static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) +static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow, + int peer_index) { struct mlx5_eswitch *esw = flow->priv->mdev->priv.eswitch; struct mlx5e_tc_flow *peer_flow; @@ -1991,18 +1992,32 @@ static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow) return; mutex_lock(&esw->offloads.peer_mutex); - list_del(&flow->peer); + list_del(&flow->peer[peer_index]); mutex_unlock(&esw->offloads.peer_mutex); - flow_flag_clear(flow, DUP); - list_for_each_entry_safe(peer_flow, tmp, &flow->peer_flows, peer_flows) { + if (peer_index != mlx5_get_dev_index(peer_flow->priv->mdev)) + continue; if (refcount_dec_and_test(&peer_flow->refcnt)) { mlx5e_tc_del_fdb_flow(peer_flow->priv, peer_flow); list_del(&peer_flow->peer_flows); kfree(peer_flow); } } + + if (list_empty(&flow->peer_flows)) + flow_flag_clear(flow, DUP); +} + +static void mlx5e_tc_del_fdb_peers_flow(struct mlx5e_tc_flow *flow) +{ + int i; + + for (i = 0; i < MLX5_MAX_PORTS; i++) { + if (i == mlx5_get_dev_index(flow->priv->mdev)) + continue; + mlx5e_tc_del_fdb_peer_flow(flow, i); + } } static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, @@ -2017,7 +2032,7 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, mlx5e_tc_del_fdb_flow(priv, flow); return; } - mlx5e_tc_del_fdb_peer_flow(flow); + mlx5e_tc_del_fdb_peers_flow(flow); mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); mlx5e_tc_del_fdb_flow(priv, flow); } else { @@ -4403,6 +4418,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f, struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr; struct mlx5e_tc_flow_parse_attr *parse_attr; + int i = mlx5_get_dev_index(peer_esw->dev); struct mlx5e_rep_priv *peer_urpriv; struct mlx5e_tc_flow *peer_flow; struct mlx5_core_dev *in_mdev; @@ -4435,7 +4451,7 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f, list_add_tail(&peer_flow->peer_flows, &flow->peer_flows); flow_flag_set(flow, DUP); mutex_lock(&esw->offloads.peer_mutex); - list_add_tail(&flow->peer, &esw->offloads.peer_flows); + list_add_tail(&flow->peer[i], &esw->offloads.peer_flows[i]); mutex_unlock(&esw->offloads.peer_mutex); out: @@ -5288,9 +5304,14 @@ int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags) void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw) { struct mlx5e_tc_flow *flow, *tmp; + int i; - list_for_each_entry_safe(flow, tmp, &esw->offloads.peer_flows, peer) - mlx5e_tc_del_fdb_peer_flow(flow); + for (i = 0; i < MLX5_MAX_PORTS; i++) { + if (i == mlx5_get_dev_index(esw->dev)) + continue; + list_for_each_entry_safe(flow, tmp, &esw->offloads.peer_flows[i], peer[i]) + mlx5e_tc_del_fdb_peers_flow(flow); + } } void mlx5e_tc_reoffload_flows_work(struct work_struct *work) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index f70124ad71cf..eadc39542e5e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -249,7 +249,7 @@ struct mlx5_esw_offload { struct mlx5_flow_group *vport_rx_drop_group; struct mlx5_flow_handle *vport_rx_drop_rule; struct xarray vport_reps; - struct list_head peer_flows; + struct list_head peer_flows[MLX5_MAX_PORTS]; struct mutex peer_mutex; struct mutex encap_tbl_lock; /* protects encap_tbl */ DECLARE_HASHTABLE(encap_tbl, 8); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 9526382f1573..a767f3d52c76 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2825,8 +2825,10 @@ err_out: void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw) { struct mlx5_devcom *devcom = esw->dev->priv.devcom; + int i; - INIT_LIST_HEAD(&esw->offloads.peer_flows); + for (i = 0; i < MLX5_MAX_PORTS; i++) + INIT_LIST_HEAD(&esw->offloads.peer_flows[i]); mutex_init(&esw->offloads.peer_mutex); if (!MLX5_CAP_ESW(esw->dev, merged_eswitch)) -- cgit v1.2.3 From 18e31d42267556fd98590d91dda161f2a39a1def Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Sun, 5 Feb 2023 14:44:40 +0200 Subject: net/mlx5: E-switch, enlarge peer miss group table There is an implicit assumption that peer miss group table require to handle only a single peer. Also, there is an assumption that total_vports of the master is greater or equal to the total_vports of each peer. Change the code to support peer miss group for more than one peer. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index a767f3d52c76..ca69ed487413 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1573,6 +1573,7 @@ esw_create_peer_esw_miss_group(struct mlx5_eswitch *esw, u32 *flow_group_in, int *ix) { + int max_peer_ports = (esw->total_vports - 1) * (MLX5_MAX_PORTS - 1); int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_flow_group *g; void *match_criteria; @@ -1599,8 +1600,8 @@ esw_create_peer_esw_miss_group(struct mlx5_eswitch *esw, MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, *ix); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, - *ix + esw->total_vports - 1); - *ix += esw->total_vports; + *ix + max_peer_ports); + *ix += max_peer_ports + 1; g = mlx5_create_flow_group(fdb, flow_group_in); if (IS_ERR(g)) { @@ -1702,7 +1703,7 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw) * total vports of the peer (currently is also uses esw->total_vports). */ table_size = MLX5_MAX_PORTS * (esw->total_vports * MAX_SQ_NVPORTS + MAX_PF_SQ) + - esw->total_vports * 2 + MLX5_ESW_MISS_FLOWS; + esw->total_vports * MLX5_MAX_PORTS + MLX5_ESW_MISS_FLOWS; /* create the slow path fdb with encap set, so further table instances * can be created at run time while VFs are probed if the FW allows that. -- cgit v1.2.3 From 9bee385a6e3981d22d75873a059aa94d276ede32 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Sun, 5 Feb 2023 17:18:19 +0200 Subject: net/mlx5: E-switch, refactor FDB miss rule add/remove Currently, E-switch FDB have a single peer miss rule. In order to support more than one peer, refactor E-switch FDB to have peer miss rule per peer, and change the code to add/remove a rule from specific peer. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index eadc39542e5e..2a941e1cc686 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -218,7 +218,7 @@ struct mlx5_eswitch_fdb { struct mlx5_flow_group *send_to_vport_grp; struct mlx5_flow_group *send_to_vport_meta_grp; struct mlx5_flow_group *peer_miss_grp; - struct mlx5_flow_handle **peer_miss_rules; + struct mlx5_flow_handle **peer_miss_rules[MLX5_MAX_PORTS]; struct mlx5_flow_group *miss_grp; struct mlx5_flow_handle **send_to_vport_meta_rules; struct mlx5_flow_handle *miss_rule_uni; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index ca69ed487413..a7f352777d9e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1132,7 +1132,7 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw, flows[vport->index] = flow; } - esw->fdb_table.offloads.peer_miss_rules = flows; + esw->fdb_table.offloads.peer_miss_rules[mlx5_get_dev_index(peer_dev)] = flows; kvfree(spec); return 0; @@ -1160,13 +1160,14 @@ alloc_flows_err: return err; } -static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw) +static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw, + struct mlx5_core_dev *peer_dev) { struct mlx5_flow_handle **flows; struct mlx5_vport *vport; unsigned long i; - flows = esw->fdb_table.offloads.peer_miss_rules; + flows = esw->fdb_table.offloads.peer_miss_rules[mlx5_get_dev_index(peer_dev)]; mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev)) mlx5_del_flow_rules(flows[vport->index]); @@ -2700,7 +2701,7 @@ static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw, mlx5e_tc_clean_fdb_peer_flows(esw); #endif mlx5_esw_offloads_rep_event_unpair(esw, peer_esw); - esw_del_fdb_peer_miss_rules(esw); + esw_del_fdb_peer_miss_rules(esw, peer_esw->dev); } static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw, -- cgit v1.2.3 From 5e0202eb49ed02b9b9ec423684dd840e0edd8695 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Wed, 22 Feb 2023 11:54:19 +0200 Subject: net/mlx5: E-switch, Handle multiple master egress rules Currently, whenever a shared FDB is created, the slave eswitch is creating master egress rule to the master eswitch. In order to support more than two ports, which means there will be more than one slave eswitch, enlarge bounce_rule, which is used to create master egress rule, to an xarray. Signed-off-by: Shay Drory Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/esw/acl/egress_ofld.c | 15 ++-- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 8 +- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 92 +++++++++++++++------- 3 files changed, 79 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c index 2e504c7461c6..ae815a8392c6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c @@ -15,13 +15,15 @@ static void esw_acl_egress_ofld_fwd2vport_destroy(struct mlx5_vport *vport) vport->egress.offloads.fwd_rule = NULL; } -static void esw_acl_egress_ofld_bounce_rule_destroy(struct mlx5_vport *vport) +static void esw_acl_egress_ofld_bounce_rules_destroy(struct mlx5_vport *vport) { - if (!vport->egress.offloads.bounce_rule) - return; + struct mlx5_flow_handle *bounce_rule; + unsigned long i; - mlx5_del_flow_rules(vport->egress.offloads.bounce_rule); - vport->egress.offloads.bounce_rule = NULL; + xa_for_each(&vport->egress.offloads.bounce_rules, i, bounce_rule) { + mlx5_del_flow_rules(bounce_rule); + xa_erase(&vport->egress.offloads.bounce_rules, i); + } } static int esw_acl_egress_ofld_fwd2vport_create(struct mlx5_eswitch *esw, @@ -96,7 +98,7 @@ static void esw_acl_egress_ofld_rules_destroy(struct mlx5_vport *vport) { esw_acl_egress_vlan_destroy(vport); esw_acl_egress_ofld_fwd2vport_destroy(vport); - esw_acl_egress_ofld_bounce_rule_destroy(vport); + esw_acl_egress_ofld_bounce_rules_destroy(vport); } static int esw_acl_egress_ofld_groups_create(struct mlx5_eswitch *esw, @@ -194,6 +196,7 @@ int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport vport->egress.acl = NULL; return err; } + vport->egress.type = VPORT_EGRESS_ACL_TYPE_DEFAULT; err = esw_acl_egress_ofld_groups_create(esw, vport); if (err) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 2a941e1cc686..05ae1c3a6e68 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -123,8 +123,14 @@ struct vport_ingress { } offloads; }; +enum vport_egress_acl_type { + VPORT_EGRESS_ACL_TYPE_DEFAULT, + VPORT_EGRESS_ACL_TYPE_SHARED_FDB, +}; + struct vport_egress { struct mlx5_flow_table *acl; + enum vport_egress_acl_type type; struct mlx5_flow_handle *allowed_vlan; struct mlx5_flow_group *vlan_grp; union { @@ -136,7 +142,7 @@ struct vport_egress { struct { struct mlx5_flow_group *fwd_grp; struct mlx5_flow_handle *fwd_rule; - struct mlx5_flow_handle *bounce_rule; + struct xarray bounce_rules; struct mlx5_flow_group *bounce_grp; } offloads; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index a7f352777d9e..ce70320b89b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2512,6 +2512,7 @@ static int __esw_set_master_egress_rule(struct mlx5_core_dev *master, struct mlx5_vport *vport, struct mlx5_flow_table *acl) { + u16 slave_index = MLX5_CAP_GEN(slave, vhca_id); struct mlx5_flow_handle *flow_rule = NULL; struct mlx5_flow_destination dest = {}; struct mlx5_flow_act flow_act = {}; @@ -2527,8 +2528,7 @@ static int __esw_set_master_egress_rule(struct mlx5_core_dev *master, misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters); MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_UPLINK); - MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id, - MLX5_CAP_GEN(slave, vhca_id)); + MLX5_SET(fte_match_set_misc, misc, source_eswitch_owner_vhca_id, slave_index); misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters); MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port); @@ -2543,44 +2543,35 @@ static int __esw_set_master_egress_rule(struct mlx5_core_dev *master, flow_rule = mlx5_add_flow_rules(acl, spec, &flow_act, &dest, 1); - if (IS_ERR(flow_rule)) + if (IS_ERR(flow_rule)) { err = PTR_ERR(flow_rule); - else - vport->egress.offloads.bounce_rule = flow_rule; + } else { + err = xa_insert(&vport->egress.offloads.bounce_rules, + slave_index, flow_rule, GFP_KERNEL); + if (err) + mlx5_del_flow_rules(flow_rule); + } kvfree(spec); return err; } -static int esw_set_master_egress_rule(struct mlx5_core_dev *master, - struct mlx5_core_dev *slave) +static int esw_master_egress_create_resources(struct mlx5_flow_namespace *egress_ns, + struct mlx5_vport *vport) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); - struct mlx5_eswitch *esw = master->priv.eswitch; struct mlx5_flow_table_attr ft_attr = { - .max_fte = 1, .prio = 0, .level = 0, + .max_fte = MLX5_MAX_PORTS, .prio = 0, .level = 0, .flags = MLX5_FLOW_TABLE_OTHER_VPORT, }; - struct mlx5_flow_namespace *egress_ns; struct mlx5_flow_table *acl; struct mlx5_flow_group *g; - struct mlx5_vport *vport; void *match_criteria; u32 *flow_group_in; int err; - vport = mlx5_eswitch_get_vport(esw, esw->manager_vport); - if (IS_ERR(vport)) - return PTR_ERR(vport); - - egress_ns = mlx5_get_flow_vport_acl_namespace(master, - MLX5_FLOW_NAMESPACE_ESW_EGRESS, - vport->index); - if (!egress_ns) - return -EINVAL; - if (vport->egress.acl) - return -EINVAL; + return 0; flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) @@ -2604,7 +2595,7 @@ static int esw_set_master_egress_rule(struct mlx5_core_dev *master, MLX5_SET(create_flow_group_in, flow_group_in, source_eswitch_owner_vhca_id_valid, 1); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); - MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0); + MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, MLX5_MAX_PORTS); g = mlx5_create_flow_group(acl, flow_group_in); if (IS_ERR(g)) { @@ -2612,19 +2603,15 @@ static int esw_set_master_egress_rule(struct mlx5_core_dev *master, goto err_group; } - err = __esw_set_master_egress_rule(master, slave, vport, acl); - if (err) - goto err_rule; - vport->egress.acl = acl; vport->egress.offloads.bounce_grp = g; + vport->egress.type = VPORT_EGRESS_ACL_TYPE_SHARED_FDB; + xa_init_flags(&vport->egress.offloads.bounce_rules, XA_FLAGS_ALLOC); kvfree(flow_group_in); return 0; -err_rule: - mlx5_destroy_flow_group(g); err_group: mlx5_destroy_flow_table(acl); out: @@ -2632,6 +2619,52 @@ out: return err; } +static void esw_master_egress_destroy_resources(struct mlx5_vport *vport) +{ + mlx5_destroy_flow_group(vport->egress.offloads.bounce_grp); + mlx5_destroy_flow_table(vport->egress.acl); +} + +static int esw_set_master_egress_rule(struct mlx5_core_dev *master, + struct mlx5_core_dev *slave) +{ + struct mlx5_eswitch *esw = master->priv.eswitch; + u16 slave_index = MLX5_CAP_GEN(slave, vhca_id); + struct mlx5_flow_namespace *egress_ns; + struct mlx5_vport *vport; + int err; + + vport = mlx5_eswitch_get_vport(esw, esw->manager_vport); + if (IS_ERR(vport)) + return PTR_ERR(vport); + + egress_ns = mlx5_get_flow_vport_acl_namespace(master, + MLX5_FLOW_NAMESPACE_ESW_EGRESS, + vport->index); + if (!egress_ns) + return -EINVAL; + + if (vport->egress.acl && vport->egress.type != VPORT_EGRESS_ACL_TYPE_SHARED_FDB) + return 0; + + err = esw_master_egress_create_resources(egress_ns, vport); + if (err) + return err; + + if (xa_load(&vport->egress.offloads.bounce_rules, slave_index)) + return -EINVAL; + + err = __esw_set_master_egress_rule(master, slave, vport, vport->egress.acl); + if (err) + goto err_rule; + + return 0; + +err_rule: + esw_master_egress_destroy_resources(vport); + return err; +} + static void esw_unset_master_egress_rule(struct mlx5_core_dev *dev) { struct mlx5_vport *vport; @@ -2640,6 +2673,7 @@ static void esw_unset_master_egress_rule(struct mlx5_core_dev *dev) dev->priv.eswitch->manager_vport); esw_acl_egress_ofld_cleanup(vport); + xa_destroy(&vport->egress.offloads.bounce_rules); } int mlx5_eswitch_offloads_config_single_fdb(struct mlx5_eswitch *master_esw, -- cgit v1.2.3 From 014e4d48eaa36f1678642f9d9125ac5b4526bd3e Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Thu, 2 Feb 2023 10:27:45 +0200 Subject: net/mlx5: E-switch, generalize shared FDB creation Shared FDB creation is hard coded for only two eswitches. Generalize shared FDB creation so that any number of eswitches could create shared FDB. Signed-off-by: Shay Drory Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/esw/acl/egress_ofld.c | 12 ++++++++ .../net/ethernet/mellanox/mlx5/core/esw/acl/ofld.h | 1 + drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 12 ++++---- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 32 +++++++++++--------- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 35 ++++++++++++++++++---- 5 files changed, 66 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c index ae815a8392c6..24b1ca4e4ff8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/egress_ofld.c @@ -15,6 +15,18 @@ static void esw_acl_egress_ofld_fwd2vport_destroy(struct mlx5_vport *vport) vport->egress.offloads.fwd_rule = NULL; } +void esw_acl_egress_ofld_bounce_rule_destroy(struct mlx5_vport *vport, int rule_index) +{ + struct mlx5_flow_handle *bounce_rule = + xa_load(&vport->egress.offloads.bounce_rules, rule_index); + + if (!bounce_rule) + return; + + mlx5_del_flow_rules(bounce_rule); + xa_erase(&vport->egress.offloads.bounce_rules, rule_index); +} + static void esw_acl_egress_ofld_bounce_rules_destroy(struct mlx5_vport *vport) { struct mlx5_flow_handle *bounce_rule; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ofld.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ofld.h index c9f8469e9a47..536b04e83618 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ofld.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/ofld.h @@ -10,6 +10,7 @@ /* Eswitch acl egress external APIs */ int esw_acl_egress_ofld_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport); void esw_acl_egress_ofld_cleanup(struct mlx5_vport *vport); +void esw_acl_egress_ofld_bounce_rule_destroy(struct mlx5_vport *vport, int rule_index); int mlx5_esw_acl_egress_vport_bond(struct mlx5_eswitch *esw, u16 active_vport_num, u16 passive_vport_num); int mlx5_esw_acl_egress_vport_unbond(struct mlx5_eswitch *esw, u16 vport_num); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 05ae1c3a6e68..9833d1a587cc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -754,9 +754,9 @@ void esw_vport_change_handle_locked(struct mlx5_vport *vport); bool mlx5_esw_offloads_controller_valid(const struct mlx5_eswitch *esw, u32 controller); -int mlx5_eswitch_offloads_config_single_fdb(struct mlx5_eswitch *master_esw, - struct mlx5_eswitch *slave_esw); -void mlx5_eswitch_offloads_destroy_single_fdb(struct mlx5_eswitch *master_esw, +int mlx5_eswitch_offloads_single_fdb_add_one(struct mlx5_eswitch *master_esw, + struct mlx5_eswitch *slave_esw, int max_slaves); +void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw, struct mlx5_eswitch *slave_esw); int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw); @@ -808,14 +808,14 @@ mlx5_esw_vport_to_devlink_port_index(const struct mlx5_core_dev *dev, } static inline int -mlx5_eswitch_offloads_config_single_fdb(struct mlx5_eswitch *master_esw, - struct mlx5_eswitch *slave_esw) +mlx5_eswitch_offloads_single_fdb_add_one(struct mlx5_eswitch *master_esw, + struct mlx5_eswitch *slave_esw, int max_slaves) { return 0; } static inline void -mlx5_eswitch_offloads_destroy_single_fdb(struct mlx5_eswitch *master_esw, +mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw, struct mlx5_eswitch *slave_esw) {} static inline int diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index ce70320b89b3..98d75a33a624 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2557,11 +2557,11 @@ static int __esw_set_master_egress_rule(struct mlx5_core_dev *master, } static int esw_master_egress_create_resources(struct mlx5_flow_namespace *egress_ns, - struct mlx5_vport *vport) + struct mlx5_vport *vport, size_t count) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_flow_table_attr ft_attr = { - .max_fte = MLX5_MAX_PORTS, .prio = 0, .level = 0, + .max_fte = count, .prio = 0, .level = 0, .flags = MLX5_FLOW_TABLE_OTHER_VPORT, }; struct mlx5_flow_table *acl; @@ -2595,7 +2595,7 @@ static int esw_master_egress_create_resources(struct mlx5_flow_namespace *egress MLX5_SET(create_flow_group_in, flow_group_in, source_eswitch_owner_vhca_id_valid, 1); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); - MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, MLX5_MAX_PORTS); + MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, count); g = mlx5_create_flow_group(acl, flow_group_in); if (IS_ERR(g)) { @@ -2626,7 +2626,7 @@ static void esw_master_egress_destroy_resources(struct mlx5_vport *vport) } static int esw_set_master_egress_rule(struct mlx5_core_dev *master, - struct mlx5_core_dev *slave) + struct mlx5_core_dev *slave, size_t count) { struct mlx5_eswitch *esw = master->priv.eswitch; u16 slave_index = MLX5_CAP_GEN(slave, vhca_id); @@ -2647,7 +2647,7 @@ static int esw_set_master_egress_rule(struct mlx5_core_dev *master, if (vport->egress.acl && vport->egress.type != VPORT_EGRESS_ACL_TYPE_SHARED_FDB) return 0; - err = esw_master_egress_create_resources(egress_ns, vport); + err = esw_master_egress_create_resources(egress_ns, vport, count); if (err) return err; @@ -2665,19 +2665,24 @@ err_rule: return err; } -static void esw_unset_master_egress_rule(struct mlx5_core_dev *dev) +static void esw_unset_master_egress_rule(struct mlx5_core_dev *dev, + struct mlx5_core_dev *slave_dev) { struct mlx5_vport *vport; vport = mlx5_eswitch_get_vport(dev->priv.eswitch, dev->priv.eswitch->manager_vport); - esw_acl_egress_ofld_cleanup(vport); - xa_destroy(&vport->egress.offloads.bounce_rules); + esw_acl_egress_ofld_bounce_rule_destroy(vport, MLX5_CAP_GEN(slave_dev, vhca_id)); + + if (xa_empty(&vport->egress.offloads.bounce_rules)) { + esw_acl_egress_ofld_cleanup(vport); + xa_destroy(&vport->egress.offloads.bounce_rules); + } } -int mlx5_eswitch_offloads_config_single_fdb(struct mlx5_eswitch *master_esw, - struct mlx5_eswitch *slave_esw) +int mlx5_eswitch_offloads_single_fdb_add_one(struct mlx5_eswitch *master_esw, + struct mlx5_eswitch *slave_esw, int max_slaves) { int err; @@ -2687,7 +2692,7 @@ int mlx5_eswitch_offloads_config_single_fdb(struct mlx5_eswitch *master_esw, return err; err = esw_set_master_egress_rule(master_esw->dev, - slave_esw->dev); + slave_esw->dev, max_slaves); if (err) goto err_acl; @@ -2695,15 +2700,14 @@ int mlx5_eswitch_offloads_config_single_fdb(struct mlx5_eswitch *master_esw, err_acl: esw_set_slave_root_fdb(NULL, slave_esw->dev); - return err; } -void mlx5_eswitch_offloads_destroy_single_fdb(struct mlx5_eswitch *master_esw, +void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw, struct mlx5_eswitch *slave_esw) { - esw_unset_master_egress_rule(master_esw->dev); esw_set_slave_root_fdb(NULL, slave_esw->dev); + esw_unset_master_egress_rule(master_esw->dev, slave_esw->dev); } #define ESW_OFFLOADS_DEVCOM_PAIR (0) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index 5d331b940f4d..9bc2822881ca 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -550,6 +550,29 @@ char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags) } } +static int mlx5_lag_create_single_fdb(struct mlx5_lag *ldev) +{ + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; + struct mlx5_eswitch *master_esw = dev0->priv.eswitch; + int err; + int i; + + for (i = MLX5_LAG_P1 + 1; i < ldev->ports; i++) { + struct mlx5_eswitch *slave_esw = ldev->pf[i].dev->priv.eswitch; + + err = mlx5_eswitch_offloads_single_fdb_add_one(master_esw, + slave_esw, ldev->ports); + if (err) + goto err; + } + return 0; +err: + for (; i > MLX5_LAG_P1; i--) + mlx5_eswitch_offloads_single_fdb_del_one(master_esw, + ldev->pf[i].dev->priv.eswitch); + return err; +} + static int mlx5_create_lag(struct mlx5_lag *ldev, struct lag_tracker *tracker, enum mlx5_lag_mode mode, @@ -557,7 +580,6 @@ static int mlx5_create_lag(struct mlx5_lag *ldev, { bool shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags); struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; - struct mlx5_core_dev *dev1 = ldev->pf[MLX5_LAG_P2].dev; u32 in[MLX5_ST_SZ_DW(destroy_lag_in)] = {}; int err; @@ -575,8 +597,7 @@ static int mlx5_create_lag(struct mlx5_lag *ldev, } if (shared_fdb) { - err = mlx5_eswitch_offloads_config_single_fdb(dev0->priv.eswitch, - dev1->priv.eswitch); + err = mlx5_lag_create_single_fdb(ldev); if (err) mlx5_core_err(dev0, "Can't enable single FDB mode\n"); else @@ -647,19 +668,21 @@ int mlx5_activate_lag(struct mlx5_lag *ldev, int mlx5_deactivate_lag(struct mlx5_lag *ldev) { struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; - struct mlx5_core_dev *dev1 = ldev->pf[MLX5_LAG_P2].dev; + struct mlx5_eswitch *master_esw = dev0->priv.eswitch; u32 in[MLX5_ST_SZ_DW(destroy_lag_in)] = {}; bool roce_lag = __mlx5_lag_is_roce(ldev); unsigned long flags = ldev->mode_flags; int err; + int i; ldev->mode = MLX5_LAG_MODE_NONE; ldev->mode_flags = 0; mlx5_lag_mp_reset(ldev); if (test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags)) { - mlx5_eswitch_offloads_destroy_single_fdb(dev0->priv.eswitch, - dev1->priv.eswitch); + for (i = MLX5_LAG_P1 + 1; i < ldev->ports; i++) + mlx5_eswitch_offloads_single_fdb_del_one(master_esw, + ldev->pf[i].dev->priv.eswitch); clear_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags); } -- cgit v1.2.3 From 6d5b7321d8af0d4f5ec81d8e739c7ed2a93cf12a Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 21 Feb 2023 10:17:06 +0200 Subject: net/mlx5: DR, handle more than one peer domain Currently, DR domain is using the assumption that each domain can only have a single peer. In order to support VF LAG of more then two ports, expand peer domain to use an array of peers, and align the code accordingly. Signed-off-by: Shay Drory Reviewed-by: Yevgeny Kliteynik Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 12 +++++++----- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h | 3 ++- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 5 +++-- drivers/net/ethernet/mellanox/mlx5/core/fs_core.h | 3 ++- .../net/ethernet/mellanox/mlx5/core/steering/dr_action.c | 5 +++-- .../net/ethernet/mellanox/mlx5/core/steering/dr_domain.c | 13 +++++++------ .../net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c | 9 +++++---- .../net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c | 9 +++++---- drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c | 5 +++-- drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h | 3 ++- 12 files changed, 42 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 98d75a33a624..761278e1af5c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2778,7 +2778,9 @@ static int mlx5_esw_offloads_set_ns_peer(struct mlx5_eswitch *esw, struct mlx5_eswitch *peer_esw, bool pair) { + u8 peer_idx = mlx5_get_dev_index(peer_esw->dev); struct mlx5_flow_root_namespace *peer_ns; + u8 idx = mlx5_get_dev_index(esw->dev); struct mlx5_flow_root_namespace *ns; int err; @@ -2786,18 +2788,18 @@ static int mlx5_esw_offloads_set_ns_peer(struct mlx5_eswitch *esw, ns = esw->dev->priv.steering->fdb_root_ns; if (pair) { - err = mlx5_flow_namespace_set_peer(ns, peer_ns); + err = mlx5_flow_namespace_set_peer(ns, peer_ns, peer_idx); if (err) return err; - err = mlx5_flow_namespace_set_peer(peer_ns, ns); + err = mlx5_flow_namespace_set_peer(peer_ns, ns, idx); if (err) { - mlx5_flow_namespace_set_peer(ns, NULL); + mlx5_flow_namespace_set_peer(ns, NULL, peer_idx); return err; } } else { - mlx5_flow_namespace_set_peer(ns, NULL); - mlx5_flow_namespace_set_peer(peer_ns, NULL); + mlx5_flow_namespace_set_peer(ns, NULL, peer_idx); + mlx5_flow_namespace_set_peer(peer_ns, NULL, idx); } return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 144e59480686..11374c3744c5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -139,7 +139,8 @@ static void mlx5_cmd_stub_modify_header_dealloc(struct mlx5_flow_root_namespace } static int mlx5_cmd_stub_set_peer(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_root_namespace *peer_ns) + struct mlx5_flow_root_namespace *peer_ns, + u8 peer_idx) { return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h index 8ef4254b9ea1..b6b9a5a20591 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h @@ -93,7 +93,8 @@ struct mlx5_flow_cmds { struct mlx5_modify_hdr *modify_hdr); int (*set_peer)(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_root_namespace *peer_ns); + struct mlx5_flow_root_namespace *peer_ns, + u8 peer_idx); int (*create_ns)(struct mlx5_flow_root_namespace *ns); int (*destroy_ns)(struct mlx5_flow_root_namespace *ns); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 19da02c41616..4ef04aa28771 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -3620,7 +3620,8 @@ void mlx5_destroy_match_definer(struct mlx5_core_dev *dev, } int mlx5_flow_namespace_set_peer(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_root_namespace *peer_ns) + struct mlx5_flow_root_namespace *peer_ns, + u8 peer_idx) { if (peer_ns && ns->mode != peer_ns->mode) { mlx5_core_err(ns->dev, @@ -3628,7 +3629,7 @@ int mlx5_flow_namespace_set_peer(struct mlx5_flow_root_namespace *ns, return -EINVAL; } - return ns->cmds->set_peer(ns, peer_ns); + return ns->cmds->set_peer(ns, peer_ns, peer_idx); } /* This function should be called only at init stage of the namespace. diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index f137a0611b77..200ec946409c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -295,7 +295,8 @@ void mlx5_fc_update_sampling_interval(struct mlx5_core_dev *dev, const struct mlx5_flow_cmds *mlx5_fs_cmd_get_fw_cmds(void); int mlx5_flow_namespace_set_peer(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_root_namespace *peer_ns); + struct mlx5_flow_root_namespace *peer_ns, + u8 peer_idx); int mlx5_flow_namespace_set_mode(struct mlx5_flow_namespace *ns, enum mlx5_flow_steering_mode mode); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c index 0eb9a8d7f282..4e9bc1897a88 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c @@ -2071,8 +2071,9 @@ mlx5dr_action_create_dest_vport(struct mlx5dr_domain *dmn, struct mlx5dr_action *action; u8 peer_vport; - peer_vport = vhca_id_valid && (vhca_id != dmn->info.caps.gvmi); - vport_dmn = peer_vport ? dmn->peer_dmn : dmn; + peer_vport = vhca_id_valid && mlx5_core_is_pf(dmn->mdev) && + (vhca_id != dmn->info.caps.gvmi); + vport_dmn = peer_vport ? dmn->peer_dmn[vhca_id] : dmn; if (!vport_dmn) { mlx5dr_dbg(dmn, "No peer vport domain for given vhca_id\n"); return NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c index 9a2dfe6ebe31..75dc85dc24ef 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c @@ -555,17 +555,18 @@ int mlx5dr_domain_destroy(struct mlx5dr_domain *dmn) } void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn, - struct mlx5dr_domain *peer_dmn) + struct mlx5dr_domain *peer_dmn, + u8 peer_idx) { mlx5dr_domain_lock(dmn); - if (dmn->peer_dmn) - refcount_dec(&dmn->peer_dmn->refcount); + if (dmn->peer_dmn[peer_idx]) + refcount_dec(&dmn->peer_dmn[peer_idx]->refcount); - dmn->peer_dmn = peer_dmn; + dmn->peer_dmn[peer_idx] = peer_dmn; - if (dmn->peer_dmn) - refcount_inc(&dmn->peer_dmn->refcount); + if (dmn->peer_dmn[peer_idx]) + refcount_inc(&dmn->peer_dmn[peer_idx]->refcount); mlx5dr_domain_unlock(dmn); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c index 2010d4ac6519..69d7a8f3c402 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v0.c @@ -1647,6 +1647,7 @@ dr_ste_v0_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, u8 *tag) { struct mlx5dr_match_misc *misc = &value->misc; + int id = misc->source_eswitch_owner_vhca_id; struct mlx5dr_cmd_vport_cap *vport_cap; struct mlx5dr_domain *dmn = sb->dmn; struct mlx5dr_domain *vport_dmn; @@ -1657,11 +1658,11 @@ dr_ste_v0_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, if (sb->vhca_id_valid) { /* Find port GVMI based on the eswitch_owner_vhca_id */ - if (misc->source_eswitch_owner_vhca_id == dmn->info.caps.gvmi) + if (id == dmn->info.caps.gvmi) vport_dmn = dmn; - else if (dmn->peer_dmn && (misc->source_eswitch_owner_vhca_id == - dmn->peer_dmn->info.caps.gvmi)) - vport_dmn = dmn->peer_dmn; + else if (id < MLX5_MAX_PORTS && dmn->peer_dmn[id] && + (id == dmn->peer_dmn[id]->info.caps.gvmi)) + vport_dmn = dmn->peer_dmn[id]; else return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c index 4c0704ad166b..f4ef0b22b991 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste_v1.c @@ -1979,6 +1979,7 @@ static int dr_ste_v1_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, u8 *tag) { struct mlx5dr_match_misc *misc = &value->misc; + int id = misc->source_eswitch_owner_vhca_id; struct mlx5dr_cmd_vport_cap *vport_cap; struct mlx5dr_domain *dmn = sb->dmn; struct mlx5dr_domain *vport_dmn; @@ -1988,11 +1989,11 @@ static int dr_ste_v1_build_src_gvmi_qpn_tag(struct mlx5dr_match_param *value, if (sb->vhca_id_valid) { /* Find port GVMI based on the eswitch_owner_vhca_id */ - if (misc->source_eswitch_owner_vhca_id == dmn->info.caps.gvmi) + if (id == dmn->info.caps.gvmi) vport_dmn = dmn; - else if (dmn->peer_dmn && (misc->source_eswitch_owner_vhca_id == - dmn->peer_dmn->info.caps.gvmi)) - vport_dmn = dmn->peer_dmn; + else if (id < MLX5_MAX_PORTS && dmn->peer_dmn[id] && + (id == dmn->peer_dmn[id]->info.caps.gvmi)) + vport_dmn = dmn->peer_dmn[id]; else return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h index 678a993ab053..1622dbbe6b97 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h @@ -935,7 +935,7 @@ struct mlx5dr_domain_info { }; struct mlx5dr_domain { - struct mlx5dr_domain *peer_dmn; + struct mlx5dr_domain *peer_dmn[MLX5_MAX_PORTS]; struct mlx5_core_dev *mdev; u32 pdn; struct mlx5_uars_page *uar; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c index 984653756779..c6fda1cbfcff 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c @@ -770,14 +770,15 @@ restore_fte: } static int mlx5_cmd_dr_set_peer(struct mlx5_flow_root_namespace *ns, - struct mlx5_flow_root_namespace *peer_ns) + struct mlx5_flow_root_namespace *peer_ns, + u8 peer_idx) { struct mlx5dr_domain *peer_domain = NULL; if (peer_ns) peer_domain = peer_ns->fs_dr_domain.dr_domain; mlx5dr_domain_set_peer(ns->fs_dr_domain.dr_domain, - peer_domain); + peer_domain, peer_idx); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h index 9afd268a2573..5ba88f2ecb3f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5dr.h @@ -48,7 +48,8 @@ int mlx5dr_domain_destroy(struct mlx5dr_domain *domain); int mlx5dr_domain_sync(struct mlx5dr_domain *domain, u32 flags); void mlx5dr_domain_set_peer(struct mlx5dr_domain *dmn, - struct mlx5dr_domain *peer_dmn); + struct mlx5dr_domain *peer_dmn, + u8 peer_idx); struct mlx5dr_table * mlx5dr_table_create(struct mlx5dr_domain *domain, u32 level, u32 flags, -- cgit v1.2.3 From e67f928a5204cc577ad35dc8c3ebe60ef64bade8 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 7 Feb 2023 16:08:33 +0200 Subject: net/mlx5: Devcom, Rename paired to ready In downstream patch devcom will provide support for more than two devices. The term 'paired' will be renamed as 'ready' to convey a more accurate meaning. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 ++-- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c | 20 ++++++++++---------- drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h | 10 +++++----- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 3fbb454f7228..51e147c0dd71 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -414,7 +414,7 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw, return 0; rpriv = mlx5e_rep_to_rep_priv(rep); - if (mlx5_devcom_is_paired(esw->dev->priv.devcom, MLX5_DEVCOM_ESW_OFFLOADS)) + if (mlx5_devcom_comp_is_ready(esw->dev->priv.devcom, MLX5_DEVCOM_ESW_OFFLOADS)) peer_esw = mlx5_devcom_get_peer_data(esw->dev->priv.devcom, MLX5_DEVCOM_ESW_OFFLOADS); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index c7797e3de093..9739a61026d8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -4210,8 +4210,8 @@ static bool is_peer_flow_needed(struct mlx5e_tc_flow *flow) flow_flag_test(flow, INGRESS); bool act_is_encap = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT); - bool esw_paired = mlx5_devcom_is_paired(esw_attr->in_mdev->priv.devcom, - MLX5_DEVCOM_ESW_OFFLOADS); + bool esw_paired = mlx5_devcom_comp_is_ready(esw_attr->in_mdev->priv.devcom, + MLX5_DEVCOM_ESW_OFFLOADS); if (!esw_paired) return false; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 761278e1af5c..aeb15b10048e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2836,14 +2836,14 @@ static int mlx5_esw_offloads_devcom_event(int event, esw->paired[mlx5_get_dev_index(peer_esw->dev)] = true; peer_esw->paired[mlx5_get_dev_index(esw->dev)] = true; - mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true); + mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true); break; case ESW_OFFLOADS_DEVCOM_UNPAIR: if (!esw->paired[mlx5_get_dev_index(peer_esw->dev)]) break; - mlx5_devcom_set_paired(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false); + mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false); esw->paired[mlx5_get_dev_index(peer_esw->dev)] = false; peer_esw->paired[mlx5_get_dev_index(esw->dev)] = false; mlx5_esw_offloads_unpair(peer_esw, esw); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index 9bc2822881ca..c820f7d266de 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -824,8 +824,8 @@ bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev) is_mdev_switchdev_mode(dev1) && mlx5_eswitch_vport_match_metadata_enabled(dev0->priv.eswitch) && mlx5_eswitch_vport_match_metadata_enabled(dev1->priv.eswitch) && - mlx5_devcom_is_paired(dev0->priv.devcom, - MLX5_DEVCOM_ESW_OFFLOADS) && + mlx5_devcom_comp_is_ready(dev0->priv.devcom, + MLX5_DEVCOM_ESW_OFFLOADS) && MLX5_CAP_GEN(dev1, lag_native_fdb_selection) && MLX5_CAP_ESW(dev1, root_ft_on_other_esw) && MLX5_CAP_ESW(dev0, esw_shared_ingress_acl)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c index b7d779d08d83..7446900a589e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c @@ -19,7 +19,7 @@ struct mlx5_devcom_component { mlx5_devcom_event_handler_t handler; struct rw_semaphore sem; - bool paired; + bool ready; }; struct mlx5_devcom_list { @@ -218,25 +218,25 @@ int mlx5_devcom_send_event(struct mlx5_devcom *devcom, return err; } -void mlx5_devcom_set_paired(struct mlx5_devcom *devcom, - enum mlx5_devcom_components id, - bool paired) +void mlx5_devcom_comp_set_ready(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id, + bool ready) { struct mlx5_devcom_component *comp; comp = &devcom->priv->components[id]; WARN_ON(!rwsem_is_locked(&comp->sem)); - WRITE_ONCE(comp->paired, paired); + WRITE_ONCE(comp->ready, ready); } -bool mlx5_devcom_is_paired(struct mlx5_devcom *devcom, - enum mlx5_devcom_components id) +bool mlx5_devcom_comp_is_ready(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id) { if (IS_ERR_OR_NULL(devcom)) return false; - return READ_ONCE(devcom->priv->components[id].paired); + return READ_ONCE(devcom->priv->components[id].ready); } void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, @@ -250,7 +250,7 @@ void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, comp = &devcom->priv->components[id]; down_read(&comp->sem); - if (!READ_ONCE(comp->paired)) { + if (!READ_ONCE(comp->ready)) { up_read(&comp->sem); return NULL; } @@ -278,7 +278,7 @@ void *mlx5_devcom_get_peer_data_rcu(struct mlx5_devcom *devcom, enum mlx5_devcom /* This can change concurrently, however 'data' pointer will remain * valid for the duration of RCU read section. */ - if (!READ_ONCE(comp->paired)) + if (!READ_ONCE(comp->ready)) return NULL; return rcu_dereference(comp->device[i].data); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h index 9a496f4722da..d465de8459b4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h @@ -33,11 +33,11 @@ int mlx5_devcom_send_event(struct mlx5_devcom *devcom, int event, void *event_data); -void mlx5_devcom_set_paired(struct mlx5_devcom *devcom, - enum mlx5_devcom_components id, - bool paired); -bool mlx5_devcom_is_paired(struct mlx5_devcom *devcom, - enum mlx5_devcom_components id); +void mlx5_devcom_comp_set_ready(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id, + bool ready); +bool mlx5_devcom_comp_is_ready(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id); void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, enum mlx5_devcom_components id); -- cgit v1.2.3 From 8611df722030171e31535da569d3da488d2cd3b6 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Thu, 2 Feb 2023 10:27:45 +0200 Subject: net/mlx5: E-switch, mark devcom as not ready when all eswitches are unpaired Whenever an eswitch is unpaired with another, the driver mark devcom as not ready. While this is correct in case we are pairing only two eswitches, in order to support pairing of more than two eswitches, driver need to mark devcom as not ready only when all eswitches are unpaired. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 1 + drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 9833d1a587cc..d6e4ca436f39 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -343,6 +343,7 @@ struct mlx5_eswitch { int mode; u16 manager_vport; u16 first_host_vport; + u8 num_peers; struct mlx5_esw_functions esw_funcs; struct { u32 large_group_num; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index aeb15b10048e..09367a320741 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2836,6 +2836,8 @@ static int mlx5_esw_offloads_devcom_event(int event, esw->paired[mlx5_get_dev_index(peer_esw->dev)] = true; peer_esw->paired[mlx5_get_dev_index(esw->dev)] = true; + esw->num_peers++; + peer_esw->num_peers++; mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true); break; @@ -2843,7 +2845,10 @@ static int mlx5_esw_offloads_devcom_event(int event, if (!esw->paired[mlx5_get_dev_index(peer_esw->dev)]) break; - mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false); + peer_esw->num_peers--; + esw->num_peers--; + if (!esw->num_peers && !peer_esw->num_peers) + mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false); esw->paired[mlx5_get_dev_index(peer_esw->dev)] = false; peer_esw->paired[mlx5_get_dev_index(esw->dev)] = false; mlx5_esw_offloads_unpair(peer_esw, esw); @@ -2884,6 +2889,7 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw) mlx5_esw_offloads_devcom_event, esw); + esw->num_peers = 0; mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS, ESW_OFFLOADS_DEVCOM_PAIR, esw); -- cgit v1.2.3 From 90ca127c62e9963e8efd032409f4f4e70308de37 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Fri, 2 Jun 2023 11:51:22 -0700 Subject: net/mlx5: Devcom, introduce devcom_for_each_peer_entry Introduce generic APIs which will retrieve all peers. This API replace mlx5_devcom_get/release_peer_data which retrieve only a single peer. Signed-off-by: Mark Bloch Signed-off-by: Shay Drory Reviewed-by: Vlad Buslov Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 94 +++++++++++++--------- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 44 +++++----- .../net/ethernet/mellanox/mlx5/core/esw/bridge.c | 30 +++++-- .../ethernet/mellanox/mlx5/core/esw/bridge_mcast.c | 21 ++++- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 7 ++ .../net/ethernet/mellanox/mlx5/core/lib/devcom.c | 89 ++++++++++++++------ .../net/ethernet/mellanox/mlx5/core/lib/devcom.h | 23 ++++-- 7 files changed, 209 insertions(+), 99 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 51e147c0dd71..965a8261c99b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -398,25 +398,64 @@ static void mlx5e_sqs2vport_stop(struct mlx5_eswitch *esw, } } +static int mlx5e_sqs2vport_add_peers_rules(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep, + struct mlx5_devcom *devcom, + struct mlx5e_rep_sq *rep_sq, int i) +{ + struct mlx5_eswitch *peer_esw = NULL; + struct mlx5_flow_handle *flow_rule; + int tmp; + + mlx5_devcom_for_each_peer_entry(devcom, MLX5_DEVCOM_ESW_OFFLOADS, + peer_esw, tmp) { + int peer_rule_idx = mlx5_get_dev_index(peer_esw->dev); + struct mlx5e_rep_sq_peer *sq_peer; + int err; + + sq_peer = kzalloc(sizeof(*sq_peer), GFP_KERNEL); + if (!sq_peer) + return -ENOMEM; + + flow_rule = mlx5_eswitch_add_send_to_vport_rule(peer_esw, esw, + rep, rep_sq->sqn); + if (IS_ERR(flow_rule)) { + kfree(sq_peer); + return PTR_ERR(flow_rule); + } + + sq_peer->rule = flow_rule; + sq_peer->peer = peer_esw; + err = xa_insert(&rep_sq->sq_peer, peer_rule_idx, sq_peer, GFP_KERNEL); + if (err) { + kfree(sq_peer); + mlx5_eswitch_del_send_to_vport_rule(flow_rule); + return err; + } + } + + return 0; +} + static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep, u32 *sqns_array, int sqns_num) { - struct mlx5_eswitch *peer_esw = NULL; struct mlx5_flow_handle *flow_rule; - struct mlx5e_rep_sq_peer *sq_peer; struct mlx5e_rep_priv *rpriv; struct mlx5e_rep_sq *rep_sq; + struct mlx5_devcom *devcom; + bool devcom_locked = false; int err; int i; if (esw->mode != MLX5_ESWITCH_OFFLOADS) return 0; + devcom = esw->dev->priv.devcom; rpriv = mlx5e_rep_to_rep_priv(rep); - if (mlx5_devcom_comp_is_ready(esw->dev->priv.devcom, MLX5_DEVCOM_ESW_OFFLOADS)) - peer_esw = mlx5_devcom_get_peer_data(esw->dev->priv.devcom, - MLX5_DEVCOM_ESW_OFFLOADS); + if (mlx5_devcom_comp_is_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS) && + mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) + devcom_locked = true; for (i = 0; i < sqns_num; i++) { rep_sq = kzalloc(sizeof(*rep_sq), GFP_KERNEL); @@ -424,7 +463,6 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw, err = -ENOMEM; goto out_err; } - xa_init(&rep_sq->sq_peer); /* Add re-inject rule to the PF/representor sqs */ flow_rule = mlx5_eswitch_add_send_to_vport_rule(esw, esw, rep, @@ -437,50 +475,30 @@ static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw, rep_sq->send_to_vport_rule = flow_rule; rep_sq->sqn = sqns_array[i]; - if (peer_esw) { - int peer_rule_idx = mlx5_get_dev_index(peer_esw->dev); - - sq_peer = kzalloc(sizeof(*sq_peer), GFP_KERNEL); - if (!sq_peer) { - err = -ENOMEM; - goto out_sq_peer_err; - } - - flow_rule = mlx5_eswitch_add_send_to_vport_rule(peer_esw, esw, - rep, sqns_array[i]); - if (IS_ERR(flow_rule)) { - err = PTR_ERR(flow_rule); - goto out_flow_rule_err; + xa_init(&rep_sq->sq_peer); + if (devcom_locked) { + err = mlx5e_sqs2vport_add_peers_rules(esw, rep, devcom, rep_sq, i); + if (err) { + mlx5_eswitch_del_send_to_vport_rule(rep_sq->send_to_vport_rule); + xa_destroy(&rep_sq->sq_peer); + kfree(rep_sq); + goto out_err; } - - sq_peer->rule = flow_rule; - sq_peer->peer = peer_esw; - err = xa_insert(&rep_sq->sq_peer, peer_rule_idx, sq_peer, GFP_KERNEL); - if (err) - goto out_xa_err; } list_add(&rep_sq->list, &rpriv->vport_sqs_list); } - if (peer_esw) - mlx5_devcom_release_peer_data(esw->dev->priv.devcom, MLX5_DEVCOM_ESW_OFFLOADS); + if (devcom_locked) + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); return 0; -out_xa_err: - mlx5_eswitch_del_send_to_vport_rule(flow_rule); -out_flow_rule_err: - kfree(sq_peer); -out_sq_peer_err: - mlx5_eswitch_del_send_to_vport_rule(rep_sq->send_to_vport_rule); - xa_destroy(&rep_sq->sq_peer); - kfree(rep_sq); out_err: mlx5e_sqs2vport_stop(esw, rep); - if (peer_esw) - mlx5_devcom_release_peer_data(esw->dev->priv.devcom, MLX5_DEVCOM_ESW_OFFLOADS); + if (devcom_locked) + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 9739a61026d8..88631fb9f966 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1670,6 +1670,7 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro struct mlx5_eswitch *esw; u16 vhca_id; int err; + int i; out_priv = netdev_priv(out_dev); esw = out_priv->mdev->priv.eswitch; @@ -1686,8 +1687,13 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro rcu_read_lock(); devcom = out_priv->mdev->priv.devcom; - esw = mlx5_devcom_get_peer_data_rcu(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - err = esw ? mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport) : -ENODEV; + err = -ENODEV; + mlx5_devcom_for_each_peer_entry_rcu(devcom, MLX5_DEVCOM_ESW_OFFLOADS, + esw, i) { + err = mlx5_eswitch_vhca_id_to_vport(esw, vhca_id, vport); + if (!err) + break; + } rcu_read_unlock(); return err; @@ -2025,15 +2031,14 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, { if (mlx5e_is_eswitch_flow(flow)) { struct mlx5_devcom *devcom = flow->priv->mdev->priv.devcom; - struct mlx5_eswitch *peer_esw; - peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - if (!peer_esw) { + if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) { mlx5e_tc_del_fdb_flow(priv, flow); return; } + mlx5e_tc_del_fdb_peers_flow(flow); - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); mlx5e_tc_del_fdb_flow(priv, flow); } else { mlx5e_tc_del_nic_flow(priv, flow); @@ -4472,6 +4477,7 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv, struct mlx5_eswitch *peer_esw; struct mlx5e_tc_flow *flow; int err; + int i; flow = __mlx5e_add_fdb_flow(priv, f, flow_flags, filter_dev, in_rep, in_mdev); @@ -4483,23 +4489,27 @@ mlx5e_add_fdb_flow(struct mlx5e_priv *priv, return 0; } - peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - if (!peer_esw) { + if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) { err = -ENODEV; goto clean_flow; } - err = mlx5e_tc_add_fdb_peer_flow(f, flow, flow_flags, peer_esw); - if (err) - goto peer_clean; - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + mlx5_devcom_for_each_peer_entry(devcom, + MLX5_DEVCOM_ESW_OFFLOADS, + peer_esw, i) { + err = mlx5e_tc_add_fdb_peer_flow(f, flow, flow_flags, peer_esw); + if (err) + goto peer_clean; + } - *__flow = flow; + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + *__flow = flow; return 0; peer_clean: - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + mlx5e_tc_del_fdb_peers_flow(flow); + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); clean_flow: mlx5e_tc_del_fdb_flow(priv, flow); return err; @@ -4719,7 +4729,6 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv, { struct mlx5_devcom *devcom = priv->mdev->priv.devcom; struct rhashtable *tc_ht = get_tc_ht(priv, flags); - struct mlx5_eswitch *peer_esw; struct mlx5e_tc_flow *flow; struct mlx5_fc *counter; u64 lastuse = 0; @@ -4754,8 +4763,7 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv, /* Under multipath it's possible for one rule to be currently * un-offloaded while the other rule is offloaded. */ - peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - if (!peer_esw) + if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) goto out; if (flow_flag_test(flow, DUP)) { @@ -4786,7 +4794,7 @@ int mlx5e_stats_flower(struct net_device *dev, struct mlx5e_priv *priv, } no_peer_counter: - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); out: flow_stats_update(&f->stats, bytes, packets, 0, lastuse, FLOW_ACTION_HW_STATS_DELAYED); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c index 1ba03e219111..bea7cc645461 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c @@ -647,22 +647,35 @@ mlx5_esw_bridge_ingress_flow_create(u16 vport_num, const unsigned char *addr, } static struct mlx5_flow_handle * -mlx5_esw_bridge_ingress_flow_peer_create(u16 vport_num, const unsigned char *addr, +mlx5_esw_bridge_ingress_flow_peer_create(u16 vport_num, u16 esw_owner_vhca_id, + const unsigned char *addr, struct mlx5_esw_bridge_vlan *vlan, u32 counter_id, struct mlx5_esw_bridge *bridge) { struct mlx5_devcom *devcom = bridge->br_offloads->esw->dev->priv.devcom; + struct mlx5_eswitch *tmp, *peer_esw = NULL; static struct mlx5_flow_handle *handle; - struct mlx5_eswitch *peer_esw; + int i; - peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - if (!peer_esw) + if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) return ERR_PTR(-ENODEV); + mlx5_devcom_for_each_peer_entry(devcom, + MLX5_DEVCOM_ESW_OFFLOADS, + tmp, i) { + if (mlx5_esw_is_owner(tmp, vport_num, esw_owner_vhca_id)) { + peer_esw = tmp; + break; + } + } + if (!peer_esw) { + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + return ERR_PTR(-ENODEV); + } + handle = mlx5_esw_bridge_ingress_flow_with_esw_create(vport_num, addr, vlan, counter_id, bridge, peer_esw); - - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); return handle; } @@ -1369,8 +1382,9 @@ mlx5_esw_bridge_fdb_entry_init(struct net_device *dev, u16 vport_num, u16 esw_ow entry->ingress_counter = counter; handle = peer ? - mlx5_esw_bridge_ingress_flow_peer_create(vport_num, addr, vlan, - mlx5_fc_id(counter), bridge) : + mlx5_esw_bridge_ingress_flow_peer_create(vport_num, esw_owner_vhca_id, + addr, vlan, mlx5_fc_id(counter), + bridge) : mlx5_esw_bridge_ingress_flow_create(vport_num, addr, vlan, mlx5_fc_id(counter), bridge); if (IS_ERR(handle)) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c index 2eae594a5e80..2455f8b93c1e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c @@ -540,16 +540,29 @@ static struct mlx5_flow_handle * mlx5_esw_bridge_mcast_filter_flow_peer_create(struct mlx5_esw_bridge_port *port) { struct mlx5_devcom *devcom = port->bridge->br_offloads->esw->dev->priv.devcom; + struct mlx5_eswitch *tmp, *peer_esw = NULL; static struct mlx5_flow_handle *handle; - struct mlx5_eswitch *peer_esw; + int i; - peer_esw = mlx5_devcom_get_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); - if (!peer_esw) + if (!mlx5_devcom_for_each_peer_begin(devcom, MLX5_DEVCOM_ESW_OFFLOADS)) return ERR_PTR(-ENODEV); + mlx5_devcom_for_each_peer_entry(devcom, + MLX5_DEVCOM_ESW_OFFLOADS, + tmp, i) { + if (mlx5_esw_is_owner(tmp, port->vport_num, port->esw_owner_vhca_id)) { + peer_esw = tmp; + break; + } + } + if (!peer_esw) { + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + return ERR_PTR(-ENODEV); + } + handle = mlx5_esw_bridge_mcast_flow_with_esw_create(port, peer_esw); - mlx5_devcom_release_peer_data(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + mlx5_devcom_for_each_peer_end(devcom, MLX5_DEVCOM_ESW_OFFLOADS); return handle; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index d6e4ca436f39..c42c16d9ccbc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -585,6 +585,13 @@ mlx5_esw_is_manager_vport(const struct mlx5_eswitch *esw, u16 vport_num) return esw->manager_vport == vport_num; } +static inline bool mlx5_esw_is_owner(struct mlx5_eswitch *esw, u16 vport_num, + u16 esw_owner_vhca_id) +{ + return esw_owner_vhca_id == MLX5_CAP_GEN(esw->dev, vhca_id) || + (vport_num == MLX5_VPORT_UPLINK && mlx5_lag_is_master(esw->dev)); +} + static inline u16 mlx5_eswitch_first_host_vport_num(struct mlx5_core_dev *dev) { return mlx5_core_is_ecpf_esw_manager(dev) ? diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c index 7446900a589e..96a3b7b9a5cd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c @@ -239,55 +239,92 @@ bool mlx5_devcom_comp_is_ready(struct mlx5_devcom *devcom, return READ_ONCE(devcom->priv->components[id].ready); } -void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, - enum mlx5_devcom_components id) +bool mlx5_devcom_for_each_peer_begin(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id) { struct mlx5_devcom_component *comp; - int i; if (IS_ERR_OR_NULL(devcom)) - return NULL; + return false; comp = &devcom->priv->components[id]; down_read(&comp->sem); if (!READ_ONCE(comp->ready)) { up_read(&comp->sem); - return NULL; + return false; } - for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) - if (i != devcom->idx) - break; + return true; +} + +void mlx5_devcom_for_each_peer_end(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id) +{ + struct mlx5_devcom_component *comp = &devcom->priv->components[id]; - return rcu_dereference_protected(comp->device[i].data, lockdep_is_held(&comp->sem)); + up_read(&comp->sem); } -void *mlx5_devcom_get_peer_data_rcu(struct mlx5_devcom *devcom, enum mlx5_devcom_components id) +void *mlx5_devcom_get_next_peer_data(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id, + int *i) { struct mlx5_devcom_component *comp; - int i; + void *ret; + int idx; - if (IS_ERR_OR_NULL(devcom)) - return NULL; + comp = &devcom->priv->components[id]; - for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) - if (i != devcom->idx) - break; + if (*i == MLX5_DEVCOM_PORTS_SUPPORTED) + return NULL; + for (idx = *i; idx < MLX5_DEVCOM_PORTS_SUPPORTED; idx++) { + if (idx != devcom->idx) { + ret = rcu_dereference_protected(comp->device[idx].data, + lockdep_is_held(&comp->sem)); + if (ret) + break; + } + } - comp = &devcom->priv->components[id]; - /* This can change concurrently, however 'data' pointer will remain - * valid for the duration of RCU read section. - */ - if (!READ_ONCE(comp->ready)) + if (idx == MLX5_DEVCOM_PORTS_SUPPORTED) { + *i = idx; return NULL; + } + *i = idx + 1; - return rcu_dereference(comp->device[i].data); + return ret; } -void mlx5_devcom_release_peer_data(struct mlx5_devcom *devcom, - enum mlx5_devcom_components id) +void *mlx5_devcom_get_next_peer_data_rcu(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id, + int *i) { - struct mlx5_devcom_component *comp = &devcom->priv->components[id]; + struct mlx5_devcom_component *comp; + void *ret; + int idx; - up_read(&comp->sem); + comp = &devcom->priv->components[id]; + + if (*i == MLX5_DEVCOM_PORTS_SUPPORTED) + return NULL; + for (idx = *i; idx < MLX5_DEVCOM_PORTS_SUPPORTED; idx++) { + if (idx != devcom->idx) { + /* This can change concurrently, however 'data' pointer will remain + * valid for the duration of RCU read section. + */ + if (!READ_ONCE(comp->ready)) + return NULL; + ret = rcu_dereference(comp->device[idx].data); + if (ret) + break; + } + } + + if (idx == MLX5_DEVCOM_PORTS_SUPPORTED) { + *i = idx; + return NULL; + } + *i = idx + 1; + + return ret; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h index d465de8459b4..b7f72f1a5367 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h @@ -39,11 +39,24 @@ void mlx5_devcom_comp_set_ready(struct mlx5_devcom *devcom, bool mlx5_devcom_comp_is_ready(struct mlx5_devcom *devcom, enum mlx5_devcom_components id); -void *mlx5_devcom_get_peer_data(struct mlx5_devcom *devcom, - enum mlx5_devcom_components id); -void *mlx5_devcom_get_peer_data_rcu(struct mlx5_devcom *devcom, enum mlx5_devcom_components id); -void mlx5_devcom_release_peer_data(struct mlx5_devcom *devcom, +bool mlx5_devcom_for_each_peer_begin(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id); +void mlx5_devcom_for_each_peer_end(struct mlx5_devcom *devcom, enum mlx5_devcom_components id); +void *mlx5_devcom_get_next_peer_data(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id, int *i); -#endif +#define mlx5_devcom_for_each_peer_entry(devcom, id, data, i) \ + for (i = 0, data = mlx5_devcom_get_next_peer_data(devcom, id, &i); \ + data; \ + data = mlx5_devcom_get_next_peer_data(devcom, id, &i)) + +void *mlx5_devcom_get_next_peer_data_rcu(struct mlx5_devcom *devcom, + enum mlx5_devcom_components id, int *i); +#define mlx5_devcom_for_each_peer_entry_rcu(devcom, id, data, i) \ + for (i = 0, data = mlx5_devcom_get_next_peer_data_rcu(devcom, id, &i); \ + data; \ + data = mlx5_devcom_get_next_peer_data_rcu(devcom, id, &i)) + +#endif -- cgit v1.2.3 From e2a82bf8a428165a803c037228bdaa67cbe4764c Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Mon, 6 Feb 2023 13:50:13 +0200 Subject: net/mlx5: Devcom, extend mlx5_devcom_send_event to work with more than two devices mlx5_devcom_send_event is used to send event from one eswitch to the other. In other words, only one event is sent, which means, no error mechanism is needed. However, In case devcom have more than two eswitches, a proper error mechanism is needed. Hence, in case of error, devcom will perform the error unwind, since devcom knows how many events were successful. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 +++- drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c | 17 +++++++++++++++-- drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 09367a320741..29de4e759f4f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2892,7 +2892,8 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw) esw->num_peers = 0; mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS, - ESW_OFFLOADS_DEVCOM_PAIR, esw); + ESW_OFFLOADS_DEVCOM_PAIR, + ESW_OFFLOADS_DEVCOM_UNPAIR, esw); } void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) @@ -2906,6 +2907,7 @@ void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) return; mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS, + ESW_OFFLOADS_DEVCOM_UNPAIR, ESW_OFFLOADS_DEVCOM_UNPAIR, esw); mlx5_devcom_unregister_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c index 96a3b7b9a5cd..8472bbb3cd58 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c @@ -193,7 +193,7 @@ void mlx5_devcom_unregister_component(struct mlx5_devcom *devcom, int mlx5_devcom_send_event(struct mlx5_devcom *devcom, enum mlx5_devcom_components id, - int event, + int event, int rollback_event, void *event_data) { struct mlx5_devcom_component *comp; @@ -210,10 +210,23 @@ int mlx5_devcom_send_event(struct mlx5_devcom *devcom, if (i != devcom->idx && data) { err = comp->handler(event, data, event_data); - break; + if (err) + goto rollback; } } + up_write(&comp->sem); + return 0; + +rollback: + while (i--) { + void *data = rcu_dereference_protected(comp->device[i].data, + lockdep_is_held(&comp->sem)); + + if (i != devcom->idx && data) + comp->handler(rollback_event, data, event_data); + } + up_write(&comp->sem); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h index b7f72f1a5367..bb1970ba8730 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h @@ -30,7 +30,7 @@ void mlx5_devcom_unregister_component(struct mlx5_devcom *devcom, int mlx5_devcom_send_event(struct mlx5_devcom *devcom, enum mlx5_devcom_components id, - int event, + int event, int rollback_event, void *event_data); void mlx5_devcom_comp_set_ready(struct mlx5_devcom *devcom, -- cgit v1.2.3 From 91dfaef243cdabbda8af95643bba82b778a4d0dc Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:39 -0700 Subject: tools: ynl-gen: add extra headers for user space Make sure all relevant headers are included, we allocate memory, use memcpy() and Linux types without including the headers. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index be664510f484..5823ddf912f6 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -2103,6 +2103,13 @@ def main(): cw.nl() headers = ['uapi/' + parsed.uapi_header] else: + cw.p('#include ') + if args.header: + cw.p('#include ') + cw.p('#include ') + else: + cw.p(f'#include "{parsed.name}-user.h"') + cw.p('#include "ynl.h"') headers = [parsed.uapi_header] for definition in parsed['definitions']: if 'header' in definition: -- cgit v1.2.3 From 6ad49839ba9b44cf957555f2b0b4f8bc076db48f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:40 -0700 Subject: tools: ynl-gen: fix unused / pad attribute handling Unused and Pad attributes don't carry information. Unused should never exist, and be rejected. Pad should be silently skipped. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 5823ddf912f6..11dcbfc21ecc 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -170,6 +170,7 @@ class Type(SpecAttr): for line in lines: ri.cw.p(line) ri.cw.block_end() + return True def _setter_lines(self, ri, member, presence): raise Exception(f"Setter not implemented for class type {self.type}") @@ -197,6 +198,12 @@ class TypeUnused(Type): def presence_type(self): return '' + def arg_member(self, ri): + return [] + + def _attr_get(self, ri, var): + return ['return MNL_CB_ERROR;'], None, None + def _attr_typol(self): return '.type = YNL_PT_REJECT, ' @@ -208,8 +215,14 @@ class TypePad(Type): def presence_type(self): return '' + def arg_member(self, ri): + return [] + def _attr_typol(self): - return '.type = YNL_PT_REJECT, ' + return '.type = YNL_PT_IGNORE, ' + + def attr_get(self, ri, var, first): + pass def attr_policy(self, cw): pass @@ -1211,8 +1224,9 @@ def _multi_parse(ri, struct, init_lines, local_vars): first = True for _, arg in struct.member_list(): - arg.attr_get(ri, 'dst', first=first) - first = False + good = arg.attr_get(ri, 'dst', first=first) + # First may be 'unused' or 'pad', ignore those + first &= not good ri.cw.block_end() ri.cw.nl() -- cgit v1.2.3 From 67c65ce762adaf3515fe058538c0a7065dc9f2b4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:41 -0700 Subject: tools: ynl-gen: don't override pure nested struct For pure structs (parsed nested attributes) we track what forms of the struct exist in request and reply directions. Make sure we don't overwrite the recorded struct each time, otherwise the information is lost. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 11dcbfc21ecc..40f7c47407c8 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -825,7 +825,8 @@ class Family(SpecFamily): inherit = set() nested = spec['nested-attributes'] if nested not in self.root_sets: - self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) + if nested not in self.pure_nested_structs: + self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) if attr in rs_members['request']: self.pure_nested_structs[nested].request = True if attr in rs_members['reply']: -- cgit v1.2.3 From 5605f102378f59f4e87f33685bb273602622c643 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:42 -0700 Subject: tools: ynl-gen: loosen type consistency check for events Both event and notify types are always consistent. Rewrite the condition checking if we can reuse reply types to be less picky and let notify thru. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 40f7c47407c8..2ceb4ce1423f 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -897,11 +897,12 @@ class RenderInfo: self.op_mode = op_mode # 'do' and 'dump' response parsing is identical - if op_mode != 'do' and 'dump' in op and 'do' in op and 'reply' in op['do'] and \ - op["do"]["reply"] == op["dump"]["reply"]: - self.type_consistent = True - else: - self.type_consistent = op_mode == 'event' + self.type_consistent = True + if op_mode != 'do' and 'dump' in op and 'do' in op: + if ('reply' in op['do']) != ('reply' in op["dump"]): + self.type_consistent = False + elif 'reply' in op['do'] and op["do"]["reply"] != op["dump"]["reply"]: + self.type_consistent = False self.attr_set = attr_set if not self.attr_set: @@ -2245,7 +2246,7 @@ def main(): ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify') has_ntf = True if not ri.type_consistent: - raise Exception('Only notifications with consistent types supported') + raise Exception(f'Only notifications with consistent types supported ({op.name})') print_wrapped_type(ri) if 'event' in op: @@ -2304,7 +2305,7 @@ def main(): ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify') has_ntf = True if not ri.type_consistent: - raise Exception('Only notifications with consistent types supported') + raise Exception(f'Only notifications with consistent types supported ({op.name})') print_ntf_type_free(ri) if 'event' in op: -- cgit v1.2.3 From eef9b794eac87022464c28a3763f9030e1d53f80 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:43 -0700 Subject: tools: ynl-gen: add error checking for nested structs Parsing nested types may return an error, propagate it. Not marking as a fix, because nothing uses YNL upstream. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 2ceb4ce1423f..8bf4b70216d7 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -424,7 +424,8 @@ class TypeNest(Type): f"{self.enum_name}, &{var}->{self.c_name})") def _attr_get(self, ri, var): - get_lines = [f"{self.nested_render_name}_parse(&parg, attr);"] + get_lines = [f"if ({self.nested_render_name}_parse(&parg, attr))", + "return MNL_CB_ERROR;"] init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;", f"parg.data = &{var}->{self.c_name};"] return get_lines, init_lines, None -- cgit v1.2.3 From 21b6e302789c412bdde84439b9325c76e2a5c428 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:44 -0700 Subject: tools: ynl-gen: generate enum-to-string helpers It's sometimes useful to print the name of an enum value, flag or name of the op. Python can do it, add C helper code gen for getting names of things. Example: static const char * const netdev_xdp_act_strmap[] = { [0] = "basic", [1] = "redirect", [2] = "ndo-xmit", [3] = "xsk-zerocopy", [4] = "hw-offload", [5] = "rx-sg", [6] = "ndo-xmit-sg", }; const char *netdev_xdp_act_str(enum netdev_xdp_act value) { value = ffs(value) - 1; if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xdp_act_strmap)) return NULL; return netdev_xdp_act_strmap[value]; } Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 8bf4b70216d7..5318edfdb874 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1168,6 +1168,56 @@ def put_typol(cw, struct): cw.nl() +def put_op_name_fwd(family, cw): + cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';') + + +def put_op_name(family, cw): + map_name = f'{family.name}_op_strmap' + cw.block_start(line=f"static const char * const {map_name}[] =") + for op_name, op in family.msgs.items(): + cw.p(f'[{op.enum_name}] = "{op_name}",') + cw.block_end(line=';') + cw.nl() + + cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op']) + cw.block_start() + cw.p(f'if (op < 0 || op >= (int)MNL_ARRAY_SIZE({map_name}))') + cw.p('return NULL;') + cw.p(f'return {map_name}[op];') + cw.block_end() + cw.nl() + + +def put_enum_to_str_fwd(family, cw, enum): + args = [f'enum {enum.render_name} value'] + if 'enum-name' in enum and not enum['enum-name']: + args = ['int value'] + cw.write_func_prot('const char *', f'{enum.render_name}_str', args, suffix=';') + + +def put_enum_to_str(family, cw, enum): + map_name = f'{enum.render_name}_strmap' + cw.block_start(line=f"static const char * const {map_name}[] =") + for entry in enum.entries.values(): + cw.p(f'[{entry.value}] = "{entry.name}",') + cw.block_end(line=';') + cw.nl() + + args = [f'enum {enum.render_name} value'] + if 'enum-name' in enum and not enum['enum-name']: + args = ['int value'] + cw.write_func_prot('const char *', f'{enum.render_name}_str', args) + cw.block_start() + if enum.type == 'flags': + cw.p('value = ffs(value) - 1;') + cw.p(f'if (value < 0 || value >= (int)MNL_ARRAY_SIZE({map_name}))') + cw.p('return NULL;') + cw.p(f'return {map_name}[value];') + cw.block_end() + cw.nl() + + def put_req_nested(ri, struct): func_args = ['struct nlmsghdr *nlh', 'unsigned int attr_type', @@ -2210,6 +2260,14 @@ def main(): if args.mode == "user": has_ntf = False if args.header: + cw.p('/* Enums */') + put_op_name_fwd(parsed, cw) + + for name, const in parsed.consts.items(): + if isinstance(const, EnumSet): + put_enum_to_str_fwd(parsed, cw, const) + cw.nl() + cw.p('/* Common nested types */') for attr_set, struct in sorted(parsed.pure_nested_structs.items()): ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set) @@ -2262,6 +2320,14 @@ def main(): print_ntf_parse_prototype(parsed, cw) cw.nl() else: + cw.p('/* Enums */') + put_op_name(parsed, cw) + + for name, const in parsed.consts.items(): + if isinstance(const, EnumSet): + put_enum_to_str(parsed, cw, const) + cw.nl() + cw.p('/* Policies */') for name, _ in parsed.attr_sets.items(): struct = Struct(parsed, name) -- cgit v1.2.3 From dc0956c98f110ef0ff9c9c9cf150b8410a2a4200 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:45 -0700 Subject: tools: ynl-gen: move the response reading logic into YNL We generate send() and recv() calls and all msg handling for each operation. It's a lot of repeated code and will only grow with notification handling. Call back to a helper YNL lib instead. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 63 ++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 5318edfdb874..7d833a42e060 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1371,13 +1371,13 @@ def print_req(ri): ret_err = '-1' direction = "request" local_vars = ['struct nlmsghdr *nlh;', - 'int len, err;'] + 'int err;'] if 'reply' in ri.op[ri.op_mode]: ret_ok = 'rsp' ret_err = 'NULL' local_vars += [f'{type_name(ri, rdir(direction))} *rsp;', - 'struct ynl_parse_arg yarg = { .ys = ys, };'] + 'struct ynl_req_state yrs = { .yarg = { .ys = ys, }, };'] print_prototype(ri, direction, terminate=False) ri.cw.block_start() @@ -1387,41 +1387,39 @@ def print_req(ri): ri.cw.p(f"ys->req_policy = &{ri.struct['request'].render_name}_nest;") if 'reply' in ri.op[ri.op_mode]: - ri.cw.p(f"yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") + ri.cw.p(f"yrs.yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.nl() for _, attr in ri.struct["request"].member_list(): attr.attr_put(ri, "req") ri.cw.nl() - ri.cw.p('err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len);') - ri.cw.p('if (err < 0)') - ri.cw.p(f"return {ret_err};") - ri.cw.nl() - ri.cw.p('len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);') - ri.cw.p('if (len < 0)') - ri.cw.p(f"return {ret_err};") - ri.cw.nl() - + parse_arg = "NULL" if 'reply' in ri.op[ri.op_mode]: ri.cw.p('rsp = calloc(1, sizeof(*rsp));') - ri.cw.p('yarg.data = rsp;') + ri.cw.p('yrs.yarg.data = rsp;') + ri.cw.p(f"yrs.cb = {op_prefix(ri, 'reply')}_parse;") + if ri.op.value is not None: + ri.cw.p(f'yrs.rsp_cmd = {ri.op.enum_name};') + else: + ri.cw.p(f'yrs.rsp_cmd = {ri.op.rsp_value};') ri.cw.nl() - ri.cw.p(f"err = {ri.nl.parse_cb_run(op_prefix(ri, 'reply') + '_parse', '&yarg', False)};") - ri.cw.p('if (err < 0)') + parse_arg = '&yrs' + ri.cw.p(f"err = ynl_exec(ys, nlh, {parse_arg});") + ri.cw.p('if (err < 0)') + if 'reply' in ri.op[ri.op_mode]: ri.cw.p('goto err_free;') - ri.cw.nl() - - ri.cw.p('err = ynl_recv_ack(ys, err);') - ri.cw.p('if (err)') - ri.cw.p('goto err_free;') + else: + ri.cw.p('return -1;') ri.cw.nl() + ri.cw.p(f"return {ret_ok};") ri.cw.nl() - ri.cw.p('err_free:') if 'reply' in ri.op[ri.op_mode]: + ri.cw.p('err_free:') ri.cw.p(f"{call_free(ri, rdir(direction), 'rsp')}") - ri.cw.p(f"return {ret_err};") + ri.cw.p(f"return {ret_err};") + ri.cw.block_end() @@ -1431,7 +1429,7 @@ def print_dump(ri): ri.cw.block_start() local_vars = ['struct ynl_dump_state yds = {};', 'struct nlmsghdr *nlh;', - 'int len, err;'] + 'int err;'] for var in local_vars: ri.cw.p(f'{var}') @@ -1440,6 +1438,10 @@ def print_dump(ri): ri.cw.p('yds.ys = ys;') ri.cw.p(f"yds.alloc_sz = sizeof({type_name(ri, rdir(direction))});") ri.cw.p(f"yds.cb = {op_prefix(ri, 'reply', deref=True)}_parse;") + if ri.op.value is not None: + ri.cw.p(f'yds.rsp_cmd = {ri.op.enum_name};') + else: + ri.cw.p(f'yds.rsp_cmd = {ri.op.rsp_value};') ri.cw.p(f"yds.rsp_policy = &{ri.struct['reply'].render_name}_nest;") ri.cw.nl() ri.cw.p(f"nlh = ynl_gemsg_start_dump(ys, {ri.nl.get_family_id()}, {ri.op.enum_name}, 1);") @@ -1451,20 +1453,9 @@ def print_dump(ri): attr.attr_put(ri, "req") ri.cw.nl() - ri.cw.p('err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len);') - ri.cw.p('if (err < 0)') - ri.cw.p('return NULL;') - ri.cw.nl() - - ri.cw.block_start(line='do') - ri.cw.p('len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);') - ri.cw.p('if (len < 0)') - ri.cw.p('goto free_list;') - ri.cw.nl() - ri.cw.p(f"err = {ri.nl.parse_cb_run('ynl_dump_trampoline', '&yds', False, indent=2)};") + ri.cw.p('err = ynl_exec_dump(ys, nlh, &yds);') ri.cw.p('if (err < 0)') ri.cw.p('goto free_list;') - ri.cw.block_end(line='while (err > 0);') ri.cw.nl() ri.cw.p('return yds.first;') @@ -1631,7 +1622,7 @@ def print_dump_type_free(ri): ri.cw.block_start() ri.cw.p(f"{sub_type} *next = rsp;") ri.cw.nl() - ri.cw.block_start(line='while (next)') + ri.cw.block_start(line='while ((void *)next != YNL_LIST_END)') _free_type_members_iter(ri, ri.struct['reply']) ri.cw.p('rsp = next;') ri.cw.p('next = rsp->next;') -- cgit v1.2.3 From 5d58f911c75544eeb213e75a69912f330ad9f052 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:46 -0700 Subject: tools: ynl-gen: generate alloc and free helpers for req We expect user to allocate requests with calloc(), make things a bit more consistent and provide helpers. Generate free calls, too. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 7d833a42e060..4a7ca2823270 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1476,6 +1476,14 @@ def free_arg_name(direction): return 'obj' +def print_alloc_wrapper(ri, direction): + name = op_prefix(ri, direction) + ri.cw.write_func_prot(f'static inline struct {name} *', f"{name}_alloc", [f"void"]) + ri.cw.block_start() + ri.cw.p(f'return calloc(1, sizeof(struct {name}));') + ri.cw.block_end() + + def print_free_prototype(ri, direction, suffix=';'): name = op_prefix(ri, direction) arg = free_arg_name(direction) @@ -1523,6 +1531,7 @@ def print_type_full(ri, struct): def print_type_helpers(ri, direction, deref=False): print_free_prototype(ri, direction) + ri.cw.nl() if ri.ku_space == 'user' and direction == 'request': for _, attr in ri.struct[direction].member_list(): @@ -1531,6 +1540,7 @@ def print_type_helpers(ri, direction, deref=False): def print_req_type_helpers(ri): + print_alloc_wrapper(ri, "request") print_type_helpers(ri, "request") @@ -1554,6 +1564,12 @@ def print_req_type(ri): print_type(ri, "request") +def print_req_free(ri): + if 'request' not in ri.op[ri.op_mode]: + return + _free_type(ri, 'request', ri.struct['request']) + + def print_rsp_type(ri): if (ri.op_mode == 'do' or ri.op_mode == 'dump') and 'reply' in ri.op[ri.op_mode]: direction = 'reply' @@ -2344,6 +2360,7 @@ def main(): if 'do' in op and 'event' not in op: cw.p(f"/* {op.enum_name} - do */") ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do") + print_req_free(ri) print_rsp_free(ri) parse_rsp_msg(ri) print_req(ri) -- cgit v1.2.3 From 8cb6afb3354172360881d6a644967c35f767ca2b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:47 -0700 Subject: tools: ynl-gen: switch to family struct We'll want to store static info about the family soon. Generate a struct. This changes creation from, e.g.: ys = ynl_sock_create("netdev", &yerr); to: ys = ynl_sock_create(&ynl_netdev_family, &yerr); on user's side. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 4a7ca2823270..320e5e90920a 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -2109,6 +2109,16 @@ def render_uapi(family, cw): cw.p(f'#endif /* {hdr_prot} */') +def render_user_family(family, cw, prototype): + symbol = f'const struct ynl_family ynl_{family.c_name}_family' + if prototype: + cw.p(f'extern {symbol};') + else: + cw.block_start(f'{symbol} = ') + cw.p(f'.name = "{family.name}",') + cw.block_end(line=';') + + def find_kernel_root(full_path): sub_path = '' while True: @@ -2204,6 +2214,8 @@ def main(): cw.p(f'#include "{one}"') else: cw.p('struct ynl_sock;') + cw.nl() + render_user_family(parsed, cw, True) cw.nl() if args.mode == "kernel": @@ -2397,6 +2409,9 @@ def main(): cw.p('/* --------------- Common notification parsing --------------- */') print_ntf_type_parse(parsed, cw, args.mode) + cw.nl() + render_user_family(parsed, cw, False) + if args.header: cw.p(f'#endif /* {hdr_prot} */') -- cgit v1.2.3 From 59d814f0f28513ae632739634e3b869098beb093 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 1 Jun 2023 19:35:48 -0700 Subject: tools: ynl-gen: generate static descriptions of notifications Notifications may come in at any time. The family must be always ready to parse a random incoming notification. Generate notification table for parsing and tell YNL which request we're processing to distinguish responses from notifications. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 52 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 320e5e90920a..4c12c6f8968e 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -887,6 +887,12 @@ class Family(SpecFamily): self.hooks[when][op_mode]['set'].add(name) self.hooks[when][op_mode]['list'].append(name) + def has_notifications(self): + for op in self.ops.values(): + if 'notify' in op or 'event' in op: + return True + return False + class RenderInfo: def __init__(self, cw, family, ku_space, op, op_name, op_mode, attr_set=None): @@ -1587,6 +1593,7 @@ def print_wrapped_type(ri): elif ri.op_mode == 'notify' or ri.op_mode == 'event': ri.cw.p('__u16 family;') ri.cw.p('__u8 cmd;') + ri.cw.p('struct ynl_ntf_base_type *next;') ri.cw.p(f"void (*free)({type_name(ri, 'reply')} *ntf);") ri.cw.p(f"{type_name(ri, 'reply', deref=True)} obj __attribute__ ((aligned (8)));") ri.cw.block_end(line=';') @@ -2109,14 +2116,43 @@ def render_uapi(family, cw): cw.p(f'#endif /* {hdr_prot} */') +def _render_user_ntf_entry(ri, op): + ri.cw.block_start(line=f"[{op.enum_name}] = ") + ri.cw.p(f".alloc_sz\t= sizeof({type_name(ri, 'event')}),") + ri.cw.p(f".cb\t\t= {op_prefix(ri, 'reply', deref=True)}_parse,") + ri.cw.p(f".policy\t\t= &{ri.struct['reply'].render_name}_nest,") + ri.cw.p(f".free\t\t= (void *){op_prefix(ri, 'notify')}_free,") + ri.cw.block_end(line=',') + + def render_user_family(family, cw, prototype): symbol = f'const struct ynl_family ynl_{family.c_name}_family' if prototype: cw.p(f'extern {symbol};') - else: - cw.block_start(f'{symbol} = ') - cw.p(f'.name = "{family.name}",') - cw.block_end(line=';') + return + + ntf = family.has_notifications() + if ntf: + cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ") + for ntf_op in sorted(family.all_notify.keys()): + op = family.ops[ntf_op] + ri = RenderInfo(cw, family, "user", op, ntf_op, "notify") + for ntf in op['notify']['cmds']: + _render_user_ntf_entry(ri, ntf) + for op_name, op in family.ops.items(): + if 'event' not in op: + continue + ri = RenderInfo(cw, family, "user", op, op_name, "event") + _render_user_ntf_entry(ri, op) + cw.block_end(line=";") + cw.nl() + + cw.block_start(f'{symbol} = ') + cw.p(f'.name\t\t= "{family.name}",') + if ntf: + cw.p(f".ntf_info\t= {family['name']}_ntf_info,") + cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),") + cw.block_end(line=';') def find_kernel_root(full_path): @@ -2277,7 +2313,6 @@ def main(): print_kernel_family_struct_src(parsed, cw) if args.mode == "user": - has_ntf = False if args.header: cw.p('/* Enums */') put_op_name_fwd(parsed, cw) @@ -2322,7 +2357,6 @@ def main(): if 'notify' in op: cw.p(f"/* {op.enum_name} - notify */") ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify') - has_ntf = True if not ri.type_consistent: raise Exception(f'Only notifications with consistent types supported ({op.name})') print_wrapped_type(ri) @@ -2334,7 +2368,7 @@ def main(): cw.nl() print_wrapped_type(ri) - if has_ntf: + if parsed.has_notifications(): cw.p('/* --------------- Common notification parsing --------------- */') print_ntf_parse_prototype(parsed, cw) cw.nl() @@ -2390,14 +2424,12 @@ def main(): if 'notify' in op: cw.p(f"/* {op.enum_name} - notify */") ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify') - has_ntf = True if not ri.type_consistent: raise Exception(f'Only notifications with consistent types supported ({op.name})') print_ntf_type_free(ri) if 'event' in op: cw.p(f"/* {op.enum_name} - event */") - has_ntf = True ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do") parse_rsp_msg(ri) @@ -2405,7 +2437,7 @@ def main(): ri = RenderInfo(cw, parsed, args.mode, op, op_name, "event") print_ntf_type_free(ri) - if has_ntf: + if parsed.has_notifications(): cw.p('/* --------------- Common notification parsing --------------- */') print_ntf_type_parse(parsed, cw, args.mode) -- cgit v1.2.3 From 4ec7329517027db28c5683675ab3b3842ad60324 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 1 Jun 2023 16:48:12 +0100 Subject: net: phylib: fix phy_read*_poll_timeout() Dan Carpenter reported a signedness bug in genphy_loopback(). Andrew reports that: "It is common to get this wrong in general with PHY drivers. Dan regularly posts fixes like this soon after a PHY driver patch it merged. I really wish we could somehow get the compiler to warn when the result from phy_read() is stored into a unsigned type. It would save Dan a lot of work." Let's make phy_read*_poll_timeout() immune to further issues when "val" is an unsigned type by storing the read function's result in a signed int as well as "val", and using the signed variable both to check for an error and for propagating that error to the caller. The advantage of this method is we don't change where the cast from the signed return code to the user's variable occurs - so users will see no change. Previously Heiner changed phy_read_poll_timeout() to check for an error before evaluating the user supplied condition, but didn't update phy_read_mmd_poll_timeout(). Make that change there too. Link: https://lore.kernel.org/r/d7bb312e-2428-45f6-b9b3-59ba544e8b94@kili.mountain Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1q4kX6-00BNuM-Mx@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- include/linux/phy.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/include/linux/phy.h b/include/linux/phy.h index 7addde5d14c0..11c1e91563d4 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1206,10 +1206,12 @@ static inline int phy_read(struct phy_device *phydev, u32 regnum) #define phy_read_poll_timeout(phydev, regnum, val, cond, sleep_us, \ timeout_us, sleep_before_read) \ ({ \ - int __ret = read_poll_timeout(phy_read, val, val < 0 || (cond), \ + int __ret, __val; \ + __ret = read_poll_timeout(__val = phy_read, val, \ + __val < 0 || (cond), \ sleep_us, timeout_us, sleep_before_read, phydev, regnum); \ - if (val < 0) \ - __ret = val; \ + if (__val < 0) \ + __ret = __val; \ if (__ret) \ phydev_err(phydev, "%s failed: %d\n", __func__, __ret); \ __ret; \ @@ -1302,11 +1304,13 @@ int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum); #define phy_read_mmd_poll_timeout(phydev, devaddr, regnum, val, cond, \ sleep_us, timeout_us, sleep_before_read) \ ({ \ - int __ret = read_poll_timeout(phy_read_mmd, val, (cond) || val < 0, \ + int __ret, __val; \ + __ret = read_poll_timeout(__val = phy_read_mmd, val, \ + __val < 0 || (cond), \ sleep_us, timeout_us, sleep_before_read, \ phydev, devaddr, regnum); \ - if (val < 0) \ - __ret = val; \ + if (__val < 0) \ + __ret = __val; \ if (__ret) \ phydev_err(phydev, "%s failed: %d\n", __func__, __ret); \ __ret; \ -- cgit v1.2.3 From f69de8aa4752adae750892c71711a5b806ec0dff Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Fri, 2 Jun 2023 11:36:07 +0200 Subject: ipv6: lower "link become ready"'s level message This following message is printed in the console each time a network device configured with an IPv6 addresses is ready to be used: ADDRCONF(NETDEV_CHANGE): : link becomes ready When netns are being extensively used -- e.g. by re-creating netns' with veth to discuss with each others for testing purposes like mptcp_join.sh selftest does -- it generates a lot of messages like that: more than 700 when executing mptcp_join.sh with the latest version. It looks like this message is not that helpful after all: maybe it can be used as a sign to know if there is something wrong, e.g. if a device is being regularly reconfigured by accident? But even then, there are better ways to monitor and diagnose such issues. When looking at commit 3c21edbd1137 ("[IPV6]: Defer IPv6 device initialization until the link becomes ready.") which introduces this new message, it seems it had been added to verify that the new feature was working as expected. It could have then used a lower level than "info" from the beginning but it was fine like that back then: 17 years ago. It seems then OK today to simply lower its level, similar to commit 7c62b8dd5ca8 ("net/ipv6: lower the level of "link is not ready" messages") and as suggested by Mat [1], Stephen and David [2]. Link: https://lore.kernel.org/mptcp/614e76ac-184e-c553-af72-084f792e60b0@kernel.org/T/ [1] Link: https://lore.kernel.org/netdev/68035bad-b53e-91cb-0e4a-007f27d62b05@tessares.net/T/ [2] Suggested-by: Mat Martineau Suggested-by: Stephen Hemminger Suggested-by: David Ahern Signed-off-by: Matthieu Baerts Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3797917237d0..5479da08ef40 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3633,8 +3633,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, idev->if_flags |= IF_READY; } - pr_info("ADDRCONF(NETDEV_CHANGE): %s: link becomes ready\n", - dev->name); + pr_debug("ADDRCONF(NETDEV_CHANGE): %s: link becomes ready\n", + dev->name); run_pending = 1; } -- cgit v1.2.3 From 642af0f92cbe01c4b05eb38a0fe94867a3798b34 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Thu, 1 Jun 2023 16:14:51 +0200 Subject: net: mdio: Introduce a regmap-based mdio driver There exists several examples today of devices that embed an ethernet PHY or PCS directly inside an SoC. In this situation, either the device is controlled through a vendor-specific register set, or sometimes exposes the standard 802.3 registers that are typically accessed over MDIO. As phylib and phylink are designed to use mdiodevices, this driver allows creating a virtual MDIO bus, that translates mdiodev register accesses to regmap accesses. The reason we use regmap is because there are at least 3 such devices known today, 2 of them are Altera TSE PCS's, memory-mapped, exposed with a 4-byte stride in stmmac's dwmac-socfpga variant, and a 2-byte stride in altera-tse. The other one (nxp,sja1110-base-tx-mdio) is exposed over SPI. Signed-off-by: Maxime Chevallier Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- MAINTAINERS | 7 +++ drivers/net/mdio/Kconfig | 11 +++++ drivers/net/mdio/Makefile | 1 + drivers/net/mdio/mdio-regmap.c | 93 ++++++++++++++++++++++++++++++++++++++++ include/linux/mdio/mdio-regmap.h | 26 +++++++++++ 5 files changed, 138 insertions(+) create mode 100644 drivers/net/mdio/mdio-regmap.c create mode 100644 include/linux/mdio/mdio-regmap.h diff --git a/MAINTAINERS b/MAINTAINERS index 288d9a5edb9d..5a2ba8567be6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12844,6 +12844,13 @@ F: Documentation/devicetree/bindings/net/ieee802154/mcr20a.txt F: drivers/net/ieee802154/mcr20a.c F: drivers/net/ieee802154/mcr20a.h +MDIO REGMAP DRIVER +M: Maxime Chevallier +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/mdio/mdio-regmap.c +F: include/linux/mdio/mdio-regmap.h + MEASUREMENT COMPUTING CIO-DAC IIO DRIVER M: William Breathitt Gray L: linux-iio@vger.kernel.org diff --git a/drivers/net/mdio/Kconfig b/drivers/net/mdio/Kconfig index 9ff2e6f22f3f..4a7a303be2f7 100644 --- a/drivers/net/mdio/Kconfig +++ b/drivers/net/mdio/Kconfig @@ -185,6 +185,17 @@ config MDIO_IPQ8064 This driver supports the MDIO interface found in the network interface units of the IPQ8064 SoC +config MDIO_REGMAP + tristate + help + This driver allows using MDIO devices that are not sitting on a + regular MDIO bus, but still exposes the standard 802.3 register + layout. It's regmap-based so that it can be used on integrated, + memory-mapped PHYs, SPI PHYs and so on. A new virtual MDIO bus is + created, and its read/write operations are mapped to the underlying + regmap. Users willing to use this driver must explicitly select + REGMAP. + config MDIO_THUNDER tristate "ThunderX SOCs MDIO buses" depends on 64BIT diff --git a/drivers/net/mdio/Makefile b/drivers/net/mdio/Makefile index 7d4cb4c11e4e..1015f0db4531 100644 --- a/drivers/net/mdio/Makefile +++ b/drivers/net/mdio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o +obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.o obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o diff --git a/drivers/net/mdio/mdio-regmap.c b/drivers/net/mdio/mdio-regmap.c new file mode 100644 index 000000000000..8a742a8d6387 --- /dev/null +++ b/drivers/net/mdio/mdio-regmap.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Driver for MMIO-Mapped MDIO devices. Some IPs expose internal PHYs or PCS + * within the MMIO-mapped area + * + * Copyright (C) 2023 Maxime Chevallier + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "mdio-regmap" + +struct mdio_regmap_priv { + struct regmap *regmap; + u8 valid_addr; +}; + +static int mdio_regmap_read_c22(struct mii_bus *bus, int addr, int regnum) +{ + struct mdio_regmap_priv *ctx = bus->priv; + unsigned int val; + int ret; + + if (ctx->valid_addr != addr) + return -ENODEV; + + ret = regmap_read(ctx->regmap, regnum, &val); + if (ret < 0) + return ret; + + return val; +} + +static int mdio_regmap_write_c22(struct mii_bus *bus, int addr, int regnum, + u16 val) +{ + struct mdio_regmap_priv *ctx = bus->priv; + + if (ctx->valid_addr != addr) + return -ENODEV; + + return regmap_write(ctx->regmap, regnum, val); +} + +struct mii_bus *devm_mdio_regmap_register(struct device *dev, + const struct mdio_regmap_config *config) +{ + struct mdio_regmap_priv *mr; + struct mii_bus *mii; + int rc; + + if (!config->parent) + return ERR_PTR(-EINVAL); + + mii = devm_mdiobus_alloc_size(config->parent, sizeof(*mr)); + if (!mii) + return ERR_PTR(-ENOMEM); + + mr = mii->priv; + mr->regmap = config->regmap; + mr->valid_addr = config->valid_addr; + + mii->name = DRV_NAME; + strscpy(mii->id, config->name, MII_BUS_ID_SIZE); + mii->parent = config->parent; + mii->read = mdio_regmap_read_c22; + mii->write = mdio_regmap_write_c22; + + if (config->autoscan) + mii->phy_mask = ~BIT(config->valid_addr); + else + mii->phy_mask = ~0; + + rc = devm_mdiobus_register(dev, mii); + if (rc) { + dev_err(config->parent, "Cannot register MDIO bus![%s] (%d)\n", mii->id, rc); + return ERR_PTR(rc); + } + + return mii; +} +EXPORT_SYMBOL_GPL(devm_mdio_regmap_register); + +MODULE_DESCRIPTION("MDIO API over regmap"); +MODULE_AUTHOR("Maxime Chevallier "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mdio/mdio-regmap.h b/include/linux/mdio/mdio-regmap.h new file mode 100644 index 000000000000..679d9069846b --- /dev/null +++ b/include/linux/mdio/mdio-regmap.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Driver for MMIO-Mapped MDIO devices. Some IPs expose internal PHYs or PCS + * within the MMIO-mapped area + * + * Copyright (C) 2023 Maxime Chevallier + */ +#ifndef MDIO_REGMAP_H +#define MDIO_REGMAP_H + +#include + +struct device; +struct regmap; + +struct mdio_regmap_config { + struct device *parent; + struct regmap *regmap; + char name[MII_BUS_ID_SIZE]; + u8 valid_addr; + bool autoscan; +}; + +struct mii_bus *devm_mdio_regmap_register(struct device *dev, + const struct mdio_regmap_config *config); + +#endif -- cgit v1.2.3 From db48abbaa18e571106711b42affe68ca6f36ca5a Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Thu, 1 Jun 2023 16:14:52 +0200 Subject: net: ethernet: altera-tse: Convert to mdio-regmap and use PCS Lynx The newly introduced regmap-based MDIO driver allows for an easy mapping of an mdiodevice onto the memory-mapped TSE PCS, which is actually a Lynx PCS. Convert Altera TSE to use this PCS instead of the pcs-altera-tse, which is nothing more than a memory-mapped Lynx PCS. Signed-off-by: Maxime Chevallier Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/Kconfig | 2 + drivers/net/ethernet/altera/altera_tse_main.c | 57 ++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/altera/Kconfig index dd7fd41ccde5..93533ba03429 100644 --- a/drivers/net/ethernet/altera/Kconfig +++ b/drivers/net/ethernet/altera/Kconfig @@ -5,6 +5,8 @@ config ALTERA_TSE select PHYLIB select PHYLINK select PCS_ALTERA_TSE + select MDIO_REGMAP + select REGMAP_MMIO help This driver supports the Altera Triple-Speed (TSE) Ethernet MAC. diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 190ff1bcd94e..d866c0f1b503 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -27,14 +27,16 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include +#include #include #include @@ -1132,13 +1134,16 @@ static int request_and_map(struct platform_device *pdev, const char *name, static int altera_tse_probe(struct platform_device *pdev) { const struct of_device_id *of_id = NULL; + struct regmap_config pcs_regmap_cfg; struct altera_tse_private *priv; + struct mdio_regmap_config mrc; struct resource *control_port; + struct regmap *pcs_regmap; struct resource *dma_res; struct resource *pcs_res; + struct mii_bus *pcs_bus; struct net_device *ndev; void __iomem *descmap; - int pcs_reg_width = 2; int ret = -ENODEV; ndev = alloc_etherdev(sizeof(struct altera_tse_private)); @@ -1255,12 +1260,32 @@ static int altera_tse_probe(struct platform_device *pdev) * address space, but if it's not the case, we fallback to the mdiophy0 * from the MAC's address space */ - ret = request_and_map(pdev, "pcs", &pcs_res, - &priv->pcs_base); + ret = request_and_map(pdev, "pcs", &pcs_res, &priv->pcs_base); if (ret) { + /* If we can't find a dedicated resource for the PCS, fallback + * to the internal PCS, that has a different address stride + */ priv->pcs_base = priv->mac_dev + tse_csroffs(mdio_phy0); - pcs_reg_width = 4; + pcs_regmap_cfg.reg_bits = 32; + /* Values are MDIO-like values, on 16 bits */ + pcs_regmap_cfg.val_bits = 16; + pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(2); + } else { + pcs_regmap_cfg.reg_bits = 16; + pcs_regmap_cfg.val_bits = 16; + pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(1); + } + + /* Create a regmap for the PCS so that it can be used by the PCS driver */ + pcs_regmap = devm_regmap_init_mmio(&pdev->dev, priv->pcs_base, + &pcs_regmap_cfg); + if (IS_ERR(pcs_regmap)) { + ret = PTR_ERR(pcs_regmap); + goto err_free_netdev; } + mrc.regmap = pcs_regmap; + mrc.parent = &pdev->dev; + mrc.valid_addr = 0x0; /* Rx IRQ */ priv->rx_irq = platform_get_irq_byname(pdev, "rx_irq"); @@ -1384,7 +1409,18 @@ static int altera_tse_probe(struct platform_device *pdev) (unsigned long) control_port->start, priv->rx_irq, priv->tx_irq); - priv->pcs = alt_tse_pcs_create(ndev, priv->pcs_base, pcs_reg_width); + snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name); + pcs_bus = devm_mdio_regmap_register(&pdev->dev, &mrc); + if (IS_ERR(pcs_bus)) { + ret = PTR_ERR(pcs_bus); + goto err_init_pcs; + } + + priv->pcs = lynx_pcs_create_mdiodev(pcs_bus, 0); + if (IS_ERR(priv->pcs)) { + ret = PTR_ERR(priv->pcs); + goto err_init_pcs; + } priv->phylink_config.dev = &ndev->dev; priv->phylink_config.type = PHYLINK_NETDEV; @@ -1407,12 +1443,13 @@ static int altera_tse_probe(struct platform_device *pdev) if (IS_ERR(priv->phylink)) { dev_err(&pdev->dev, "failed to create phylink\n"); ret = PTR_ERR(priv->phylink); - goto err_init_phy; + goto err_init_phylink; } return 0; - -err_init_phy: +err_init_phylink: + lynx_pcs_destroy(priv->pcs); +err_init_pcs: unregister_netdev(ndev); err_register_netdev: netif_napi_del(&priv->napi); @@ -1433,6 +1470,8 @@ static int altera_tse_remove(struct platform_device *pdev) altera_tse_mdio_destroy(ndev); unregister_netdev(ndev); phylink_destroy(priv->phylink); + lynx_pcs_destroy(priv->pcs); + free_netdev(ndev); return 0; -- cgit v1.2.3 From 196eec4062b006575e441ef00339c3ebcea26b8d Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Thu, 1 Jun 2023 16:14:53 +0200 Subject: net: pcs: Drop the TSE PCS driver Now that we can easily create a mdio-device that represents a memory-mapped device that exposes an MDIO-like register layout, we don't need the Altera TSE PCS anymore, since we can use the Lynx PCS instead. Reviewed-by: Simon Horman Signed-off-by: Maxime Chevallier Signed-off-by: David S. Miller --- MAINTAINERS | 7 -- drivers/net/pcs/Kconfig | 6 -- drivers/net/pcs/Makefile | 1 - drivers/net/pcs/pcs-altera-tse.c | 160 --------------------------------------- include/linux/pcs-altera-tse.h | 17 ----- 5 files changed, 191 deletions(-) delete mode 100644 drivers/net/pcs/pcs-altera-tse.c delete mode 100644 include/linux/pcs-altera-tse.h diff --git a/MAINTAINERS b/MAINTAINERS index 5a2ba8567be6..081eb65ef865 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -909,13 +909,6 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/altera/ -ALTERA TSE PCS -M: Maxime Chevallier -L: netdev@vger.kernel.org -S: Supported -F: drivers/net/pcs/pcs-altera-tse.c -F: include/linux/pcs-altera-tse.h - ALTERA UART/JTAG UART SERIAL DRIVERS M: Tobias Klauser L: linux-serial@vger.kernel.org diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig index 7c34fb7cbf7b..87cf308fc6d8 100644 --- a/drivers/net/pcs/Kconfig +++ b/drivers/net/pcs/Kconfig @@ -33,10 +33,4 @@ config PCS_RZN1_MIIC on RZ/N1 SoCs. This PCS converts MII to RMII/RGMII or can be set in pass-through mode for MII. -config PCS_ALTERA_TSE - tristate - help - This module provides helper functions for the Altera Triple Speed - Ethernet SGMII PCS, that can be found on the Intel Socfpga family. - endmenu diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile index 9b9afd6b1c22..ea662a7989b2 100644 --- a/drivers/net/pcs/Makefile +++ b/drivers/net/pcs/Makefile @@ -7,4 +7,3 @@ obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o -obj-$(CONFIG_PCS_ALTERA_TSE) += pcs-altera-tse.o diff --git a/drivers/net/pcs/pcs-altera-tse.c b/drivers/net/pcs/pcs-altera-tse.c deleted file mode 100644 index d616749761f4..000000000000 --- a/drivers/net/pcs/pcs-altera-tse.c +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2022 Bootlin - * - * Maxime Chevallier - */ - -#include -#include -#include -#include - -/* SGMII PCS register addresses - */ -#define SGMII_PCS_LINK_TIMER_0 0x12 -#define SGMII_PCS_LINK_TIMER_1 0x13 -#define SGMII_PCS_IF_MODE 0x14 -#define PCS_IF_MODE_SGMII_ENA BIT(0) -#define PCS_IF_MODE_USE_SGMII_AN BIT(1) -#define PCS_IF_MODE_SGMI_HALF_DUPLEX BIT(4) -#define PCS_IF_MODE_SGMI_PHY_AN BIT(5) -#define SGMII_PCS_SW_RESET_TIMEOUT 100 /* usecs */ - -struct altera_tse_pcs { - struct phylink_pcs pcs; - void __iomem *base; - int reg_width; -}; - -static struct altera_tse_pcs *phylink_pcs_to_tse_pcs(struct phylink_pcs *pcs) -{ - return container_of(pcs, struct altera_tse_pcs, pcs); -} - -static u16 tse_pcs_read(struct altera_tse_pcs *tse_pcs, int regnum) -{ - if (tse_pcs->reg_width == 4) - return readl(tse_pcs->base + regnum * 4); - else - return readw(tse_pcs->base + regnum * 2); -} - -static void tse_pcs_write(struct altera_tse_pcs *tse_pcs, int regnum, - u16 value) -{ - if (tse_pcs->reg_width == 4) - writel(value, tse_pcs->base + regnum * 4); - else - writew(value, tse_pcs->base + regnum * 2); -} - -static int tse_pcs_reset(struct altera_tse_pcs *tse_pcs) -{ - u16 bmcr; - - /* Reset PCS block */ - bmcr = tse_pcs_read(tse_pcs, MII_BMCR); - bmcr |= BMCR_RESET; - tse_pcs_write(tse_pcs, MII_BMCR, bmcr); - - return read_poll_timeout(tse_pcs_read, bmcr, (bmcr & BMCR_RESET), - 10, SGMII_PCS_SW_RESET_TIMEOUT, 1, - tse_pcs, MII_BMCR); -} - -static int alt_tse_pcs_validate(struct phylink_pcs *pcs, - unsigned long *supported, - const struct phylink_link_state *state) -{ - if (state->interface == PHY_INTERFACE_MODE_SGMII || - state->interface == PHY_INTERFACE_MODE_1000BASEX) - return 1; - - return -EINVAL; -} - -static int alt_tse_pcs_config(struct phylink_pcs *pcs, unsigned int mode, - phy_interface_t interface, - const unsigned long *advertising, - bool permit_pause_to_mac) -{ - struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs); - u32 ctrl, if_mode; - - ctrl = tse_pcs_read(tse_pcs, MII_BMCR); - if_mode = tse_pcs_read(tse_pcs, SGMII_PCS_IF_MODE); - - /* Set link timer to 1.6ms, as per the MegaCore Function User Guide */ - tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_0, 0x0D40); - tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_1, 0x03); - - if (interface == PHY_INTERFACE_MODE_SGMII) { - if_mode |= PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA; - } else if (interface == PHY_INTERFACE_MODE_1000BASEX) { - if_mode &= ~(PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA); - } - - ctrl |= (BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_ANENABLE); - - tse_pcs_write(tse_pcs, MII_BMCR, ctrl); - tse_pcs_write(tse_pcs, SGMII_PCS_IF_MODE, if_mode); - - return tse_pcs_reset(tse_pcs); -} - -static void alt_tse_pcs_get_state(struct phylink_pcs *pcs, - struct phylink_link_state *state) -{ - struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs); - u16 bmsr, lpa; - - bmsr = tse_pcs_read(tse_pcs, MII_BMSR); - lpa = tse_pcs_read(tse_pcs, MII_LPA); - - phylink_mii_c22_pcs_decode_state(state, bmsr, lpa); -} - -static void alt_tse_pcs_an_restart(struct phylink_pcs *pcs) -{ - struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs); - u16 bmcr; - - bmcr = tse_pcs_read(tse_pcs, MII_BMCR); - bmcr |= BMCR_ANRESTART; - tse_pcs_write(tse_pcs, MII_BMCR, bmcr); - - /* This PCS seems to require a soft reset to re-sync the AN logic */ - tse_pcs_reset(tse_pcs); -} - -static const struct phylink_pcs_ops alt_tse_pcs_ops = { - .pcs_validate = alt_tse_pcs_validate, - .pcs_get_state = alt_tse_pcs_get_state, - .pcs_config = alt_tse_pcs_config, - .pcs_an_restart = alt_tse_pcs_an_restart, -}; - -struct phylink_pcs *alt_tse_pcs_create(struct net_device *ndev, - void __iomem *pcs_base, int reg_width) -{ - struct altera_tse_pcs *tse_pcs; - - if (reg_width != 4 && reg_width != 2) - return ERR_PTR(-EINVAL); - - tse_pcs = devm_kzalloc(&ndev->dev, sizeof(*tse_pcs), GFP_KERNEL); - if (!tse_pcs) - return ERR_PTR(-ENOMEM); - - tse_pcs->pcs.ops = &alt_tse_pcs_ops; - tse_pcs->base = pcs_base; - tse_pcs->reg_width = reg_width; - - return &tse_pcs->pcs; -} -EXPORT_SYMBOL_GPL(alt_tse_pcs_create); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Altera TSE PCS driver"); -MODULE_AUTHOR("Maxime Chevallier "); diff --git a/include/linux/pcs-altera-tse.h b/include/linux/pcs-altera-tse.h deleted file mode 100644 index 92ab9f08e835..000000000000 --- a/include/linux/pcs-altera-tse.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2022 Bootlin - * - * Maxime Chevallier - */ - -#ifndef __LINUX_PCS_ALTERA_TSE_H -#define __LINUX_PCS_ALTERA_TSE_H - -struct phylink_pcs; -struct net_device; - -struct phylink_pcs *alt_tse_pcs_create(struct net_device *ndev, - void __iomem *pcs_base, int reg_width); - -#endif /* __LINUX_PCS_ALTERA_TSE_H */ -- cgit v1.2.3 From 5d1f3fe7d2d54d04b44aa5b9b62b305fdcf653ec Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Thu, 1 Jun 2023 16:14:54 +0200 Subject: net: stmmac: dwmac-sogfpga: use the lynx pcs driver dwmac_socfpga re-implements support for the TSE PCS, which is identical to the already existing TSE PCS, which in turn is the same as the Lynx PCS. Drop the existing TSE re-implemenation and use the Lynx PCS instead, relying on the regmap-mdio driver to translate MDIO accesses into mmio accesses. Add a lynx_pcs reference in the stmmac's internal structure, and use .mac_select_pcs() to return the relevant PCS to be used. Signed-off-by: Maxime Chevallier Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 3 + drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c | 257 --------------------- drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h | 29 --- drivers/net/ethernet/stmicro/stmmac/common.h | 2 + .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 91 ++++++-- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 12 +- drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 3 + 8 files changed, 83 insertions(+), 316 deletions(-) delete mode 100644 drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c delete mode 100644 drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 5f5a997f21f3..5583f0b055ec 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -158,6 +158,9 @@ config DWMAC_SOCFPGA default ARCH_INTEL_SOCFPGA depends on OF && (ARCH_INTEL_SOCFPGA || COMPILE_TEST) select MFD_SYSCON + select MDIO_REGMAP + select REGMAP_MMIO + select PCS_LYNX help Support for ethernet controller on Altera SOCFPGA diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 8738fdbb4b2d..7dd3d388068b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_DWMAC_IMX8) += dwmac-imx.o obj-$(CONFIG_DWMAC_TEGRA) += dwmac-tegra.o obj-$(CONFIG_DWMAC_VISCONTI) += dwmac-visconti.o stmmac-platform-objs:= stmmac_platform.o -dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o +dwmac-altr-socfpga-objs := dwmac-socfpga.o obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o obj-$(CONFIG_DWMAC_INTEL) += dwmac-intel.o diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c deleted file mode 100644 index 00f6d347eaf7..000000000000 --- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* Copyright Altera Corporation (C) 2016. All rights reserved. - * - * Author: Tien Hock Loh - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "stmmac.h" -#include "stmmac_platform.h" -#include "altr_tse_pcs.h" - -#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0 -#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII BIT(1) -#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII BIT(2) -#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 -#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK GENMASK(1, 0) - -#define TSE_PCS_CONTROL_AN_EN_MASK BIT(12) -#define TSE_PCS_CONTROL_REG 0x00 -#define TSE_PCS_CONTROL_RESTART_AN_MASK BIT(9) -#define TSE_PCS_CTRL_AUTONEG_SGMII 0x1140 -#define TSE_PCS_IF_MODE_REG 0x28 -#define TSE_PCS_LINK_TIMER_0_REG 0x24 -#define TSE_PCS_LINK_TIMER_1_REG 0x26 -#define TSE_PCS_SIZE 0x40 -#define TSE_PCS_STATUS_AN_COMPLETED_MASK BIT(5) -#define TSE_PCS_STATUS_LINK_MASK 0x0004 -#define TSE_PCS_STATUS_REG 0x02 -#define TSE_PCS_SGMII_SPEED_1000 BIT(3) -#define TSE_PCS_SGMII_SPEED_100 BIT(2) -#define TSE_PCS_SGMII_SPEED_10 0x0 -#define TSE_PCS_SW_RST_MASK 0x8000 -#define TSE_PCS_PARTNER_ABILITY_REG 0x0A -#define TSE_PCS_PARTNER_DUPLEX_FULL 0x1000 -#define TSE_PCS_PARTNER_DUPLEX_HALF 0x0000 -#define TSE_PCS_PARTNER_DUPLEX_MASK 0x1000 -#define TSE_PCS_PARTNER_SPEED_MASK GENMASK(11, 10) -#define TSE_PCS_PARTNER_SPEED_1000 BIT(11) -#define TSE_PCS_PARTNER_SPEED_100 BIT(10) -#define TSE_PCS_PARTNER_SPEED_10 0x0000 -#define TSE_PCS_PARTNER_SPEED_1000 BIT(11) -#define TSE_PCS_PARTNER_SPEED_100 BIT(10) -#define TSE_PCS_PARTNER_SPEED_10 0x0000 -#define TSE_PCS_SGMII_SPEED_MASK GENMASK(3, 2) -#define TSE_PCS_SGMII_LINK_TIMER_0 0x0D40 -#define TSE_PCS_SGMII_LINK_TIMER_1 0x0003 -#define TSE_PCS_SW_RESET_TIMEOUT 100 -#define TSE_PCS_USE_SGMII_AN_MASK BIT(1) -#define TSE_PCS_USE_SGMII_ENA BIT(0) -#define TSE_PCS_IF_USE_SGMII 0x03 - -#define AUTONEGO_LINK_TIMER 20 - -static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs) -{ - int counter = 0; - u16 val; - - val = readw(base + TSE_PCS_CONTROL_REG); - val |= TSE_PCS_SW_RST_MASK; - writew(val, base + TSE_PCS_CONTROL_REG); - - while (counter < TSE_PCS_SW_RESET_TIMEOUT) { - val = readw(base + TSE_PCS_CONTROL_REG); - val &= TSE_PCS_SW_RST_MASK; - if (val == 0) - break; - counter++; - udelay(1); - } - if (counter >= TSE_PCS_SW_RESET_TIMEOUT) { - dev_err(pcs->dev, "PCS could not get out of sw reset\n"); - return -ETIMEDOUT; - } - - return 0; -} - -int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs) -{ - int ret = 0; - - writew(TSE_PCS_IF_USE_SGMII, base + TSE_PCS_IF_MODE_REG); - - writew(TSE_PCS_CTRL_AUTONEG_SGMII, base + TSE_PCS_CONTROL_REG); - - writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG); - writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG); - - ret = tse_pcs_reset(base, pcs); - if (ret == 0) - writew(SGMII_ADAPTER_ENABLE, - pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); - - return ret; -} - -static void pcs_link_timer_callback(struct tse_pcs *pcs) -{ - u16 val = 0; - void __iomem *tse_pcs_base = pcs->tse_pcs_base; - void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; - - val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); - val &= TSE_PCS_STATUS_LINK_MASK; - - if (val != 0) { - dev_dbg(pcs->dev, "Adapter: Link is established\n"); - writew(SGMII_ADAPTER_ENABLE, - sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); - } else { - mod_timer(&pcs->aneg_link_timer, jiffies + - msecs_to_jiffies(AUTONEGO_LINK_TIMER)); - } -} - -static void auto_nego_timer_callback(struct tse_pcs *pcs) -{ - u16 val = 0; - u16 speed = 0; - u16 duplex = 0; - void __iomem *tse_pcs_base = pcs->tse_pcs_base; - void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; - - val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); - val &= TSE_PCS_STATUS_AN_COMPLETED_MASK; - - if (val != 0) { - dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n"); - val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG); - speed = val & TSE_PCS_PARTNER_SPEED_MASK; - duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK; - - if (speed == TSE_PCS_PARTNER_SPEED_10 && - duplex == TSE_PCS_PARTNER_DUPLEX_FULL) - dev_dbg(pcs->dev, - "Adapter: Link Partner is Up - 10/Full\n"); - else if (speed == TSE_PCS_PARTNER_SPEED_100 && - duplex == TSE_PCS_PARTNER_DUPLEX_FULL) - dev_dbg(pcs->dev, - "Adapter: Link Partner is Up - 100/Full\n"); - else if (speed == TSE_PCS_PARTNER_SPEED_1000 && - duplex == TSE_PCS_PARTNER_DUPLEX_FULL) - dev_dbg(pcs->dev, - "Adapter: Link Partner is Up - 1000/Full\n"); - else if (speed == TSE_PCS_PARTNER_SPEED_10 && - duplex == TSE_PCS_PARTNER_DUPLEX_HALF) - dev_err(pcs->dev, - "Adapter does not support Half Duplex\n"); - else if (speed == TSE_PCS_PARTNER_SPEED_100 && - duplex == TSE_PCS_PARTNER_DUPLEX_HALF) - dev_err(pcs->dev, - "Adapter does not support Half Duplex\n"); - else if (speed == TSE_PCS_PARTNER_SPEED_1000 && - duplex == TSE_PCS_PARTNER_DUPLEX_HALF) - dev_err(pcs->dev, - "Adapter does not support Half Duplex\n"); - else - dev_err(pcs->dev, - "Adapter: Invalid Partner Speed and Duplex\n"); - - if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL && - (speed == TSE_PCS_PARTNER_SPEED_10 || - speed == TSE_PCS_PARTNER_SPEED_100 || - speed == TSE_PCS_PARTNER_SPEED_1000)) - writew(SGMII_ADAPTER_ENABLE, - sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); - } else { - val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); - val |= TSE_PCS_CONTROL_RESTART_AN_MASK; - writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); - - tse_pcs_reset(tse_pcs_base, pcs); - mod_timer(&pcs->aneg_link_timer, jiffies + - msecs_to_jiffies(AUTONEGO_LINK_TIMER)); - } -} - -static void aneg_link_timer_callback(struct timer_list *t) -{ - struct tse_pcs *pcs = from_timer(pcs, t, aneg_link_timer); - - if (pcs->autoneg == AUTONEG_ENABLE) - auto_nego_timer_callback(pcs); - else if (pcs->autoneg == AUTONEG_DISABLE) - pcs_link_timer_callback(pcs); -} - -void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, - unsigned int speed) -{ - void __iomem *tse_pcs_base = pcs->tse_pcs_base; - u32 val; - - pcs->autoneg = phy_dev->autoneg; - - if (phy_dev->autoneg == AUTONEG_ENABLE) { - val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); - val |= TSE_PCS_CONTROL_AN_EN_MASK; - writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); - - val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); - val |= TSE_PCS_USE_SGMII_AN_MASK; - writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); - - val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); - val |= TSE_PCS_CONTROL_RESTART_AN_MASK; - - tse_pcs_reset(tse_pcs_base, pcs); - - timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback, - 0); - mod_timer(&pcs->aneg_link_timer, jiffies + - msecs_to_jiffies(AUTONEGO_LINK_TIMER)); - } else if (phy_dev->autoneg == AUTONEG_DISABLE) { - val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); - val &= ~TSE_PCS_CONTROL_AN_EN_MASK; - writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); - - val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); - val &= ~TSE_PCS_USE_SGMII_AN_MASK; - writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); - - val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); - val &= ~TSE_PCS_SGMII_SPEED_MASK; - - switch (speed) { - case 1000: - val |= TSE_PCS_SGMII_SPEED_1000; - break; - case 100: - val |= TSE_PCS_SGMII_SPEED_100; - break; - case 10: - val |= TSE_PCS_SGMII_SPEED_10; - break; - default: - return; - } - writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); - - tse_pcs_reset(tse_pcs_base, pcs); - - timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback, - 0); - mod_timer(&pcs->aneg_link_timer, jiffies + - msecs_to_jiffies(AUTONEGO_LINK_TIMER)); - } -} diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h deleted file mode 100644 index 694ac25ef426..000000000000 --- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright Altera Corporation (C) 2016. All rights reserved. - * - * Author: Tien Hock Loh - */ - -#ifndef __TSE_PCS_H__ -#define __TSE_PCS_H__ - -#include -#include - -#define SGMII_ADAPTER_CTRL_REG 0x00 -#define SGMII_ADAPTER_ENABLE 0x0000 -#define SGMII_ADAPTER_DISABLE 0x0001 - -struct tse_pcs { - struct device *dev; - void __iomem *tse_pcs_base; - void __iomem *sgmii_adapter_base; - struct timer_list aneg_link_timer; - int autoneg; -}; - -int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs); -void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, - unsigned int speed); - -#endif /* __TSE_PCS_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 4ad692c4116c..52c5ec553276 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #if IS_ENABLED(CONFIG_VLAN_8021Q) #define STMMAC_VLAN_TAG_USED @@ -519,6 +520,7 @@ struct mac_device_info { const struct stmmac_tc_ops *tc; const struct stmmac_mmc_ops *mmc; struct dw_xpcs *xpcs; + struct phylink_pcs *lynx_pcs; /* Lynx external PCS */ struct mii_regs mii; /* MII register Addresses */ struct mac_link link; void __iomem *pcsr; /* vpointer to device CSRs */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 6ee050300b31..e399fccbafe5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -10,14 +10,13 @@ #include #include #include +#include #include #include #include "stmmac.h" #include "stmmac_platform.h" -#include "altr_tse_pcs.h" - #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2 @@ -37,6 +36,10 @@ #define EMAC_SPLITTER_CTRL_SPEED_100 0x3 #define EMAC_SPLITTER_CTRL_SPEED_1000 0x0 +#define SGMII_ADAPTER_CTRL_REG 0x00 +#define SGMII_ADAPTER_ENABLE 0x0000 +#define SGMII_ADAPTER_DISABLE 0x0001 + struct socfpga_dwmac; struct socfpga_dwmac_ops { int (*set_phy_mode)(struct socfpga_dwmac *dwmac_priv); @@ -50,16 +53,18 @@ struct socfpga_dwmac { struct reset_control *stmmac_rst; struct reset_control *stmmac_ocp_rst; void __iomem *splitter_base; + void __iomem *tse_pcs_base; + void __iomem *sgmii_adapter_base; bool f2h_ptp_ref_clk; - struct tse_pcs pcs; const struct socfpga_dwmac_ops *ops; + struct mdio_device *pcs_mdiodev; }; static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) { struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; void __iomem *splitter_base = dwmac->splitter_base; - void __iomem *sgmii_adapter_base = dwmac->pcs.sgmii_adapter_base; + void __iomem *sgmii_adapter_base = dwmac->sgmii_adapter_base; struct device *dev = dwmac->dev; struct net_device *ndev = dev_get_drvdata(dev); struct phy_device *phy_dev = ndev->phydev; @@ -89,11 +94,9 @@ static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); } - if (phy_dev && sgmii_adapter_base) { + if (phy_dev && sgmii_adapter_base) writew(SGMII_ADAPTER_ENABLE, sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); - tse_pcs_fix_mac_speed(&dwmac->pcs, phy_dev, speed); - } } static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) @@ -183,11 +186,11 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * goto err_node_put; } - dwmac->pcs.sgmii_adapter_base = + dwmac->sgmii_adapter_base = devm_ioremap_resource(dev, &res_sgmii_adapter); - if (IS_ERR(dwmac->pcs.sgmii_adapter_base)) { - ret = PTR_ERR(dwmac->pcs.sgmii_adapter_base); + if (IS_ERR(dwmac->sgmii_adapter_base)) { + ret = PTR_ERR(dwmac->sgmii_adapter_base); goto err_node_put; } } @@ -205,11 +208,11 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * goto err_node_put; } - dwmac->pcs.tse_pcs_base = + dwmac->tse_pcs_base = devm_ioremap_resource(dev, &res_tse_pcs); - if (IS_ERR(dwmac->pcs.tse_pcs_base)) { - ret = PTR_ERR(dwmac->pcs.tse_pcs_base); + if (IS_ERR(dwmac->tse_pcs_base)) { + ret = PTR_ERR(dwmac->tse_pcs_base); goto err_node_put; } } @@ -235,6 +238,13 @@ static int socfpga_get_plat_phymode(struct socfpga_dwmac *dwmac) return priv->plat->interface; } +static void socfpga_sgmii_config(struct socfpga_dwmac *dwmac, bool enable) +{ + u16 val = enable ? SGMII_ADAPTER_ENABLE : SGMII_ADAPTER_DISABLE; + + writew(val, dwmac->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); +} + static int socfpga_set_phy_mode_common(int phymode, u32 *val) { switch (phymode) { @@ -310,12 +320,8 @@ static int socfpga_gen5_set_phy_mode(struct socfpga_dwmac *dwmac) */ reset_control_deassert(dwmac->stmmac_ocp_rst); reset_control_deassert(dwmac->stmmac_rst); - if (phymode == PHY_INTERFACE_MODE_SGMII) { - if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) { - dev_err(dwmac->dev, "Unable to initialize TSE PCS"); - return -EINVAL; - } - } + if (phymode == PHY_INTERFACE_MODE_SGMII) + socfpga_sgmii_config(dwmac, true); return 0; } @@ -367,12 +373,8 @@ static int socfpga_gen10_set_phy_mode(struct socfpga_dwmac *dwmac) */ reset_control_deassert(dwmac->stmmac_ocp_rst); reset_control_deassert(dwmac->stmmac_rst); - if (phymode == PHY_INTERFACE_MODE_SGMII) { - if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) { - dev_err(dwmac->dev, "Unable to initialize TSE PCS"); - return -EINVAL; - } - } + if (phymode == PHY_INTERFACE_MODE_SGMII) + socfpga_sgmii_config(dwmac, true); return 0; } @@ -386,6 +388,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) struct net_device *ndev; struct stmmac_priv *stpriv; const struct socfpga_dwmac_ops *ops; + struct regmap_config pcs_regmap_cfg; ops = device_get_match_data(&pdev->dev); if (!ops) { @@ -443,6 +446,44 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) if (ret) goto err_dvr_remove; + memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg)); + pcs_regmap_cfg.reg_bits = 16; + pcs_regmap_cfg.val_bits = 16; + pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(1); + + /* Create a regmap for the PCS so that it can be used by the PCS driver, + * if we have such a PCS + */ + if (dwmac->tse_pcs_base) { + struct mdio_regmap_config mrc; + struct regmap *pcs_regmap; + struct mii_bus *pcs_bus; + + pcs_regmap = devm_regmap_init_mmio(&pdev->dev, dwmac->tse_pcs_base, + &pcs_regmap_cfg); + if (IS_ERR(pcs_regmap)) { + ret = PTR_ERR(pcs_regmap); + goto err_dvr_remove; + } + + mrc.regmap = pcs_regmap; + mrc.parent = &pdev->dev; + mrc.valid_addr = 0x0; + + snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name); + pcs_bus = devm_mdio_regmap_register(&pdev->dev, &mrc); + if (IS_ERR(pcs_bus)) { + ret = PTR_ERR(pcs_bus); + goto err_dvr_remove; + } + + stpriv->hw->lynx_pcs = lynx_pcs_create_mdiodev(pcs_bus, 0); + if (IS_ERR(stpriv->hw->lynx_pcs)) { + ret = PTR_ERR(stpriv->hw->lynx_pcs); + goto err_dvr_remove; + } + } + return 0; err_dvr_remove: diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 52cab9de05f2..fa07b0d50b46 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -937,10 +937,13 @@ static struct phylink_pcs *stmmac_mac_select_pcs(struct phylink_config *config, { struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); - if (!priv->hw->xpcs) - return NULL; + if (priv->hw->xpcs) + return &priv->hw->xpcs->pcs; + + if (priv->hw->lynx_pcs) + return priv->hw->lynx_pcs; - return &priv->hw->xpcs->pcs; + return NULL; } static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, @@ -3813,7 +3816,8 @@ static int __stmmac_open(struct net_device *dev, if (priv->hw->pcs != STMMAC_PCS_TBI && priv->hw->pcs != STMMAC_PCS_RTBI && (!priv->hw->xpcs || - xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73)) { + xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73) && + !priv->hw->lynx_pcs) { ret = stmmac_init_phy(dev); if (ret) { netdev_err(priv->dev, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 3db1cb0fd160..c784a6731f08 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -665,6 +665,9 @@ int stmmac_mdio_unregister(struct net_device *ndev) if (priv->hw->xpcs) xpcs_destroy(priv->hw->xpcs); + if (priv->hw->lynx_pcs) + lynx_pcs_destroy(priv->hw->lynx_pcs); + mdiobus_unregister(priv->mii); priv->mii->priv = NULL; mdiobus_free(priv->mii); -- cgit v1.2.3 From 9607eaadba68732b76c744bd22635fb1da5a7622 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 2 Jun 2023 14:58:35 +0100 Subject: net: dsa: sja1105: allow XPCS to handle mdiodev lifetime Put the mdiodev after xpcs_create() so that the XPCS driver can manage the lifetime of the mdiodev its using. Signed-off-by: Russell King (Oracle) Reviewed-by: Vladimir Oltean Tested-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_mdio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_mdio.c b/drivers/net/dsa/sja1105/sja1105_mdio.c index 01f1cb719042..166fe747f70a 100644 --- a/drivers/net/dsa/sja1105/sja1105_mdio.c +++ b/drivers/net/dsa/sja1105/sja1105_mdio.c @@ -417,6 +417,7 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) } xpcs = xpcs_create(mdiodev, priv->phy_mode[port]); + mdio_device_put(mdiodev); if (IS_ERR(xpcs)) { rc = PTR_ERR(xpcs); goto out_pcs_free; @@ -434,7 +435,6 @@ out_pcs_free: if (!priv->xpcs[port]) continue; - mdio_device_free(priv->xpcs[port]->mdiodev); xpcs_destroy(priv->xpcs[port]); priv->xpcs[port] = NULL; } @@ -457,7 +457,6 @@ static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv) if (!priv->xpcs[port]) continue; - mdio_device_free(priv->xpcs[port]->mdiodev); xpcs_destroy(priv->xpcs[port]); priv->xpcs[port] = NULL; } -- cgit v1.2.3 From bf9a17b04c85345df6e53e4058a56513f41265cf Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 2 Jun 2023 14:58:40 +0100 Subject: net: dsa: sja1105: use xpcs_create_mdiodev() Use the new xpcs_create_mdiodev() creator, which simplifies the creation and destruction of the mdio device associated with xpcs. Signed-off-by: Russell King (Oracle) Reviewed-by: Vladimir Oltean Tested-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_mdio.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_mdio.c b/drivers/net/dsa/sja1105/sja1105_mdio.c index 166fe747f70a..833e55e4b961 100644 --- a/drivers/net/dsa/sja1105/sja1105_mdio.c +++ b/drivers/net/dsa/sja1105/sja1105_mdio.c @@ -400,7 +400,6 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) } for (port = 0; port < ds->num_ports; port++) { - struct mdio_device *mdiodev; struct dw_xpcs *xpcs; if (dsa_is_unused_port(ds, port)) @@ -410,14 +409,7 @@ static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv) priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX) continue; - mdiodev = mdio_device_create(bus, port); - if (IS_ERR(mdiodev)) { - rc = PTR_ERR(mdiodev); - goto out_pcs_free; - } - - xpcs = xpcs_create(mdiodev, priv->phy_mode[port]); - mdio_device_put(mdiodev); + xpcs = xpcs_create_mdiodev(bus, port, priv->phy_mode[port]); if (IS_ERR(xpcs)) { rc = PTR_ERR(xpcs); goto out_pcs_free; -- cgit v1.2.3 From 4739b9f3d211b3c4ce9353fbfd9f22e2bcb64c17 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 2 Jun 2023 14:58:45 +0100 Subject: net: pcs: xpcs: remove xpcs_create() from public view There are now no callers of xpcs_create(), so let's remove it from public view to discourage future direct usage. Signed-off-by: Russell King (Oracle) Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/pcs/pcs-xpcs.c | 5 ++--- include/linux/pcs/pcs-xpcs.h | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 1ba214429e01..23223f0f8cad 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -1224,8 +1224,8 @@ static const struct phylink_pcs_ops xpcs_phylink_ops = { .pcs_link_up = xpcs_link_up, }; -struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, - phy_interface_t interface) +static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, + phy_interface_t interface) { struct dw_xpcs *xpcs; u32 xpcs_id; @@ -1273,7 +1273,6 @@ out: return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(xpcs_create); void xpcs_destroy(struct dw_xpcs *xpcs) { diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index a99972a6d046..914e387d5387 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -35,8 +35,6 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces); int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable); -struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, - phy_interface_t interface); struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr, phy_interface_t interface); void xpcs_destroy(struct dw_xpcs *xpcs); -- cgit v1.2.3 From be35db17c8729aa07aafec02e1201c06c03f22b0 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:05 +0200 Subject: mlxsw: spectrum_router: Clarify a comment "Reserved for X" usually means that only X is supposed to use a given object. Here, it is used in the sense that X should consider the object "reserved", as in "restricted". Replace the comment simply by "X", with the implication that that's where the field is used. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 4a73e2fe95ef..c905c8f153b4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -96,8 +96,8 @@ struct mlxsw_sp_rif_subport { struct mlxsw_sp_rif_ipip_lb { struct mlxsw_sp_rif common; struct mlxsw_sp_rif_ipip_lb_config lb_config; - u16 ul_vr_id; /* Reserved for Spectrum-2. */ - u16 ul_rif_id; /* Reserved for Spectrum. */ + u16 ul_vr_id; /* Spectrum-1. */ + u16 ul_rif_id; /* Spectrum-2+. */ }; struct mlxsw_sp_rif_params_ipip_lb { -- cgit v1.2.3 From 5afef6748c19032ef9953b0b97f75fd0593178f3 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:06 +0200 Subject: mlxsw: spectrum_router: Use extack in mlxsw_sp~_rif_ipip_lb_configure() In commit 26029225d992 ("mlxsw: spectrum_router: Propagate extack further"), the mlxsw_sp_rif_ops.configure callback got a new argument, extack. However the callbacks that deal with tunnel configuration, mlxsw_sp1_rif_ipip_lb_configure() and mlxsw_sp2_rif_ipip_lb_configure(), were never updated to pass the parameter further. Do that now. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index c905c8f153b4..20ece1b49175 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -9724,7 +9724,7 @@ mlxsw_sp1_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif, struct mlxsw_sp_vr *ul_vr; int err; - ul_vr = mlxsw_sp_vr_get(mlxsw_sp, ul_tb_id, NULL); + ul_vr = mlxsw_sp_vr_get(mlxsw_sp, ul_tb_id, extack); if (IS_ERR(ul_vr)) return PTR_ERR(ul_vr); @@ -9923,7 +9923,7 @@ mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif, struct mlxsw_sp_rif *ul_rif; int err; - ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL); + ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, extack); if (IS_ERR(ul_rif)) return PTR_ERR(ul_rif); -- cgit v1.2.3 From 3903249ee1afb9aa06d77e2c39c4be2d3df25e0e Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:07 +0200 Subject: mlxsw: spectrum_router: Do not query MAX_RIFS on each iteration MLXSW_CORE_RES_GET involves a call to spectrum_core, a separate module. Instead of making the call on every iteration, cache it up front, and use the value. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 20ece1b49175..f88b0197a6ac 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -7699,9 +7699,10 @@ static struct mlxsw_sp_rif * mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, const struct net_device *dev) { + int max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); int i; - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) + for (i = 0; i < max_rifs; i++) if (mlxsw_sp->router->rifs[i] && mlxsw_sp->router->rifs[i]->dev == dev) return mlxsw_sp->router->rifs[i]; @@ -10041,11 +10042,12 @@ err_rifs_table_init: static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp) { + int max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int i; WARN_ON_ONCE(atomic_read(&mlxsw_sp->router->rifs_count)); - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) + for (i = 0; i < max_rifs; i++) WARN_ON_ONCE(mlxsw_sp->router->rifs[i]); devl_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_RIFS); -- cgit v1.2.3 From 75426cc0b31616b11d635076bd1692f2ff2f4a5f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:08 +0200 Subject: mlxsw: spectrum_router: Do not query MAX_VRS on each iteration MLXSW_CORE_RES_GET involves a call to spectrum_core, a separate module. Instead of making the call on every iteration, cache it up front, and use the value. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index f88b0197a6ac..7304e8a29cf9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -748,10 +748,11 @@ static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr) static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp) { + int max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); struct mlxsw_sp_vr *vr; int i; - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { + for (i = 0; i < max_vrs; i++) { vr = &mlxsw_sp->router->vrs[i]; if (!mlxsw_sp_vr_is_used(vr)) return vr; @@ -792,12 +793,13 @@ static u32 mlxsw_sp_fix_tb_id(u32 tb_id) static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp, u32 tb_id) { + int max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); struct mlxsw_sp_vr *vr; int i; tb_id = mlxsw_sp_fix_tb_id(tb_id); - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { + for (i = 0; i < max_vrs; i++) { vr = &mlxsw_sp->router->vrs[i]; if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id) return vr; @@ -959,6 +961,7 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib *fib, struct mlxsw_sp_lpm_tree *new_tree) { + int max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); enum mlxsw_sp_l3proto proto = fib->proto; struct mlxsw_sp_lpm_tree *old_tree; u8 old_id, new_id = new_tree->id; @@ -968,7 +971,7 @@ static int mlxsw_sp_vrs_lpm_tree_replace(struct mlxsw_sp *mlxsw_sp, old_tree = mlxsw_sp->router->lpm.proto_trees[proto]; old_id = old_tree->id; - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { + for (i = 0; i < max_vrs; i++) { vr = &mlxsw_sp->router->vrs[i]; if (!mlxsw_sp_vr_lpm_tree_should_replace(vr, proto, old_id)) continue; @@ -7298,9 +7301,10 @@ static void mlxsw_sp_vr_fib_flush(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp) { + int max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); int i, j; - for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) { + for (i = 0; i < max_vrs; i++) { struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i]; if (!mlxsw_sp_vr_is_used(vr)) -- cgit v1.2.3 From 204cc3d04fe26c1794e50211393a050c7635cccc Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:09 +0200 Subject: selftests: mlxsw: ingress_rif_conf_1d: Fix the diagram The topology diagram implies that $swp1 and $swp2 are members of the bridge br0, when in fact only their uppers, $swp1.10 and $swp2.10 are. Adjust the diagram. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh b/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh index df2b09966886..7d7f862c809c 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/ingress_rif_conf_1d.sh @@ -15,10 +15,9 @@ # +----------------|--+ +--|-----------------+ # | | # +----------------|-------------------------|-----------------+ -# | SW | | | +# | SW $swp1 + + $swp2 | +# | | | | # | +--------------|-------------------------|---------------+ | -# | | $swp1 + + $swp2 | | -# | | | | | | # | | $swp1.10 + + $swp2.10 | | # | | | | # | | br0 | | -- cgit v1.2.3 From 34ad708d1b4346ec4b0ee9c7aa1204c2d9734698 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:10 +0200 Subject: selftests: mlxsw: egress_vid_classification: Fix the diagram The topology diagram implies that $swp1 and $swp2 are members of the bridge br0, when in fact only their uppers, $swp1.10 and $swp2.10 are. Adjust the diagram. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- .../testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh b/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh index 0cf9e47e3209..a5c2aec52898 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/egress_vid_classification.sh @@ -16,10 +16,9 @@ # +----------------|--+ +--|-----------------+ # | | # +----------------|-------------------------|-----------------+ -# | SW | | | +# | SW $swp1 + + $swp2 | +# | | | | # | +--------------|-------------------------|---------------+ | -# | | $swp1 + + $swp2 | | -# | | | | | | # | | $swp1.10 + + $swp2.10 | | # | | | | # | | br0 | | -- cgit v1.2.3 From 812de4dfab98640ebf0fd443b326c04724bf7eb0 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:11 +0200 Subject: selftests: router_bridge_vlan: Add a diagram Add a topology diagram to this selftest to make the configuration easier to understand. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_bridge_vlan.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh index fa6a88c50750..695ef1f12e56 100755 --- a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh +++ b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh @@ -1,6 +1,28 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 +# +------------------------+ +----------------------+ +# | H1 (vrf) | | H2 (vrf) | +# | + $h1.555 | | + $h2 | +# | | 192.0.2.1/28 | | | 192.0.2.130/28 | +# | | 2001:db8:1::1/64 | | | 2001:db8:2::2/64 | +# | | | | | | +# | + $h1 | | | | +# +----|-------------------+ +--|-------------------+ +# | | +# +----|--------------------------------------------------|-------------------+ +# | SW | | | +# | +--|-------------------------------+ + $swp2 | +# | | + $swp1 | 192.0.2.129/28 | +# | | vid 555 | 2001:db8:2::1/64 | +# | | | | +# | | + BR1 (802.1q) | | +# | | vid 555 pvid untagged | | +# | | 192.0.2.2/28 | | +# | | 2001:db8:1::2/64 | | +# | +----------------------------------+ | +# +---------------------------------------------------------------------------+ + ALL_TESTS=" ping_ipv4 ping_ipv6 -- cgit v1.2.3 From f5136877f421f298423e595fdf6a00e4e4c52706 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 2 Jun 2023 18:20:12 +0200 Subject: selftests: router_bridge_vlan: Set vlan_default_pvid 0 on the bridge When everything is configured, VLAN membership on the bridge in this selftest are as follows: # bridge vlan show port vlan-id swp2 1 PVID Egress Untagged 555 br1 1 Egress Untagged 555 PVID Egress Untagged Note that it is possible for untagged traffic to just flow through as VLAN 1, instead of using VLAN 555 as intended by the test. This configuration seems too close to "works by accident", and it would be better to just shut out VLAN 1 altogether. To that end, configure vlan_default_pvid of 0: # bridge vlan show port vlan-id swp2 555 br1 555 PVID Egress Untagged Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/router_bridge_vlan.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh index 695ef1f12e56..de2b2d5480dd 100755 --- a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh +++ b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh @@ -63,7 +63,7 @@ h2_destroy() router_create() { - ip link add name br1 type bridge vlan_filtering 1 + ip link add name br1 type bridge vlan_filtering 1 vlan_default_pvid 0 ip link set dev br1 up ip link set dev $swp1 master br1 -- cgit v1.2.3 From 2140a6e3422de22e6ebe77d4d18b6c0c9c425426 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Thu, 1 Jun 2023 19:26:40 -0700 Subject: bpf: Set kptr_struct_meta for node param to list and rbtree insert funcs In verifier.c, fixup_kfunc_call uses struct bpf_insn_aux_data's kptr_struct_meta field to pass information about local kptr types to various helpers and kfuncs at runtime. The recent bpf_refcount series added a few functions to the set that need this information: * bpf_refcount_acquire * Needs to know where the refcount field is in order to increment * Graph collection insert kfuncs: bpf_rbtree_add, bpf_list_push_{front,back} * Were migrated to possibly fail by the bpf_refcount series. If insert fails, the input node is bpf_obj_drop'd. bpf_obj_drop needs the kptr_struct_meta in order to decr refcount and properly free special fields. Unfortunately the verifier handling of collection insert kfuncs was not modified to actually populate kptr_struct_meta. Accordingly, when the node input to those kfuncs is passed to bpf_obj_drop, it is done so without the information necessary to decr refcount. This patch fixes the issue by populating kptr_struct_meta for those kfuncs. Fixes: d2dcc67df910 ("bpf: Migrate bpf_rbtree_add and bpf_list_push_{front,back} to possibly fail") Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20230602022647.1571784-3-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 086b2a14905b..34e56af5b0bc 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10475,6 +10475,8 @@ __process_kf_arg_ptr_to_graph_node(struct bpf_verifier_env *env, node_off, btf_name_by_offset(reg->btf, t->name_off)); return -EINVAL; } + meta->arg_btf = reg->btf; + meta->arg_btf_id = reg->btf_id; if (node_off != field->graph_root.node_offset) { verbose(env, "arg#1 offset=%d, but expected %s at offset=%d in struct %s\n", @@ -11044,6 +11046,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, meta.func_id == special_kfunc_list[KF_bpf_rbtree_add_impl]) { release_ref_obj_id = regs[BPF_REG_2].ref_obj_id; insn_aux->insert_off = regs[BPF_REG_2].off; + insn_aux->kptr_struct_meta = btf_find_struct_meta(meta.arg_btf, meta.arg_btf_id); err = ref_convert_owning_non_owning(env, release_ref_obj_id); if (err) { verbose(env, "kfunc %s#%d conversion of owning ref to non-owning failed\n", -- cgit v1.2.3 From cc0d76cafebbd3e1ffab9c4252d48ecc9e0737f6 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Thu, 1 Jun 2023 19:26:41 -0700 Subject: bpf: Fix __bpf_{list,rbtree}_add's beginning-of-node calculation Given the pointer to struct bpf_{rb,list}_node within a local kptr and the byte offset of that field within the kptr struct, the calculation changed by this patch is meant to find the beginning of the kptr so that it can be passed to bpf_obj_drop. Unfortunately instead of doing ptr_to_kptr = ptr_to_node_field - offset_bytes the calculation is erroneously doing ptr_to_ktpr = ptr_to_node_field - (offset_bytes * sizeof(struct bpf_rb_node)) or the bpf_list_node equivalent. This patch fixes the calculation. Fixes: d2dcc67df910 ("bpf: Migrate bpf_rbtree_add and bpf_list_push_{front,back} to possibly fail") Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20230602022647.1571784-4-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 4ef4c4f8a355..a4e437eabcb4 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1950,7 +1950,7 @@ static int __bpf_list_add(struct bpf_list_node *node, struct bpf_list_head *head INIT_LIST_HEAD(h); if (!list_empty(n)) { /* Only called from BPF prog, no need to migrate_disable */ - __bpf_obj_drop_impl(n - off, rec); + __bpf_obj_drop_impl((void *)n - off, rec); return -EINVAL; } @@ -2032,7 +2032,7 @@ static int __bpf_rbtree_add(struct bpf_rb_root *root, struct bpf_rb_node *node, if (!RB_EMPTY_NODE(n)) { /* Only called from BPF prog, no need to migrate_disable */ - __bpf_obj_drop_impl(n - off, rec); + __bpf_obj_drop_impl((void *)n - off, rec); return -EINVAL; } -- cgit v1.2.3 From 7793fc3babe9fea908e57f7c187ea819f9fd7e95 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Thu, 1 Jun 2023 19:26:42 -0700 Subject: bpf: Make bpf_refcount_acquire fallible for non-owning refs This patch fixes an incorrect assumption made in the original bpf_refcount series [0], specifically that the BPF program calling bpf_refcount_acquire on some node can always guarantee that the node is alive. In that series, the patch adding failure behavior to rbtree_add and list_push_{front, back} breaks this assumption for non-owning references. Consider the following program: n = bpf_kptr_xchg(&mapval, NULL); /* skip error checking */ bpf_spin_lock(&l); if(bpf_rbtree_add(&t, &n->rb, less)) { bpf_refcount_acquire(n); /* Failed to add, do something else with the node */ } bpf_spin_unlock(&l); It's incorrect to assume that bpf_refcount_acquire will always succeed in this scenario. bpf_refcount_acquire is being called in a critical section here, but the lock being held is associated with rbtree t, which isn't necessarily the lock associated with the tree that the node is already in. So after bpf_rbtree_add fails to add the node and calls bpf_obj_drop in it, the program has no ownership of the node's lifetime. Therefore the node's refcount can be decr'd to 0 at any time after the failing rbtree_add. If this happens before the refcount_acquire above, the node might be free'd, and regardless refcount_acquire will be incrementing a 0 refcount. Later patches in the series exercise this scenario, resulting in the expected complaint from the kernel (without this patch's changes): refcount_t: addition on 0; use-after-free. WARNING: CPU: 1 PID: 207 at lib/refcount.c:25 refcount_warn_saturate+0xbc/0x110 Modules linked in: bpf_testmod(O) CPU: 1 PID: 207 Comm: test_progs Tainted: G O 6.3.0-rc7-02231-g723de1a718a2-dirty #371 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b9b3f840-prebuilt.qemu.org 04/01/2014 RIP: 0010:refcount_warn_saturate+0xbc/0x110 Code: 6f 64 f6 02 01 e8 84 a3 5c ff 0f 0b eb 9d 80 3d 5e 64 f6 02 00 75 94 48 c7 c7 e0 13 d2 82 c6 05 4e 64 f6 02 01 e8 64 a3 5c ff <0f> 0b e9 7a ff ff ff 80 3d 38 64 f6 02 00 0f 85 6d ff ff ff 48 c7 RSP: 0018:ffff88810b9179b0 EFLAGS: 00010082 RAX: 0000000000000000 RBX: 0000000000000002 RCX: 0000000000000000 RDX: 0000000000000202 RSI: 0000000000000008 RDI: ffffffff857c3680 RBP: ffff88810027d3c0 R08: ffffffff8125f2a4 R09: ffff88810b9176e7 R10: ffffed1021722edc R11: 746e756f63666572 R12: ffff88810027d388 R13: ffff88810027d3c0 R14: ffffc900005fe030 R15: ffffc900005fe048 FS: 00007fee0584a700(0000) GS:ffff88811b280000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00005634a96f6c58 CR3: 0000000108ce9002 CR4: 0000000000770ee0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 PKRU: 55555554 Call Trace: bpf_refcount_acquire_impl+0xb5/0xc0 (rest of output snipped) The patch addresses this by changing bpf_refcount_acquire_impl to use refcount_inc_not_zero instead of refcount_inc and marking bpf_refcount_acquire KF_RET_NULL. For owning references, though, we know the above scenario is not possible and thus that bpf_refcount_acquire will always succeed. Some verifier bookkeeping is added to track "is input owning ref?" for bpf_refcount_acquire calls and return false from is_kfunc_ret_null for bpf_refcount_acquire on owning refs despite it being marked KF_RET_NULL. Existing selftests using bpf_refcount_acquire are modified where necessary to NULL-check its return value. [0]: https://lore.kernel.org/bpf/20230415201811.343116-1-davemarchevsky@fb.com/ Fixes: d2dcc67df910 ("bpf: Migrate bpf_rbtree_add and bpf_list_push_{front,back} to possibly fail") Reported-by: Kumar Kartikeya Dwivedi Signed-off-by: Dave Marchevsky Link: https://lore.kernel.org/r/20230602022647.1571784-5-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/helpers.c | 8 +++++-- kernel/bpf/verifier.c | 26 +++++++++++++++------- .../testing/selftests/bpf/progs/refcounted_kptr.c | 2 ++ .../selftests/bpf/progs/refcounted_kptr_fail.c | 4 +++- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index a4e437eabcb4..9e80efa59a5d 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1933,8 +1933,12 @@ __bpf_kfunc void *bpf_refcount_acquire_impl(void *p__refcounted_kptr, void *meta * bpf_refcount type so that it is emitted in vmlinux BTF */ ref = (struct bpf_refcount *)(p__refcounted_kptr + meta->record->refcount_off); + if (!refcount_inc_not_zero((refcount_t *)ref)) + return NULL; - refcount_inc((refcount_t *)ref); + /* Verifier strips KF_RET_NULL if input is owned ref, see is_kfunc_ret_null + * in verifier.c + */ return (void *)p__refcounted_kptr; } @@ -2406,7 +2410,7 @@ BTF_ID_FLAGS(func, crash_kexec, KF_DESTRUCTIVE) #endif BTF_ID_FLAGS(func, bpf_obj_new_impl, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_obj_drop_impl, KF_RELEASE) -BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE) +BTF_ID_FLAGS(func, bpf_refcount_acquire_impl, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_push_front_impl) BTF_ID_FLAGS(func, bpf_list_push_back_impl) BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 34e56af5b0bc..27b54266b4c7 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -298,16 +298,19 @@ struct bpf_kfunc_call_arg_meta { bool found; } arg_constant; - /* arg_btf and arg_btf_id are used by kfunc-specific handling, + /* arg_{btf,btf_id,owning_ref} are used by kfunc-specific handling, * generally to pass info about user-defined local kptr types to later * verification logic * bpf_obj_drop * Record the local kptr type to be drop'd * bpf_refcount_acquire (via KF_ARG_PTR_TO_REFCOUNTED_KPTR arg type) - * Record the local kptr type to be refcount_incr'd + * Record the local kptr type to be refcount_incr'd and use + * arg_owning_ref to determine whether refcount_acquire should be + * fallible */ struct btf *arg_btf; u32 arg_btf_id; + bool arg_owning_ref; struct { struct btf_field *field; @@ -9678,11 +9681,6 @@ static bool is_kfunc_acquire(struct bpf_kfunc_call_arg_meta *meta) return meta->kfunc_flags & KF_ACQUIRE; } -static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta) -{ - return meta->kfunc_flags & KF_RET_NULL; -} - static bool is_kfunc_release(struct bpf_kfunc_call_arg_meta *meta) { return meta->kfunc_flags & KF_RELEASE; @@ -9998,6 +9996,16 @@ BTF_ID(func, bpf_dynptr_slice) BTF_ID(func, bpf_dynptr_slice_rdwr) BTF_ID(func, bpf_dynptr_clone) +static bool is_kfunc_ret_null(struct bpf_kfunc_call_arg_meta *meta) +{ + if (meta->func_id == special_kfunc_list[KF_bpf_refcount_acquire_impl] && + meta->arg_owning_ref) { + return false; + } + + return meta->kfunc_flags & KF_RET_NULL; +} + static bool is_kfunc_bpf_rcu_read_lock(struct bpf_kfunc_call_arg_meta *meta) { return meta->func_id == special_kfunc_list[KF_bpf_rcu_read_lock]; @@ -10880,10 +10888,12 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ meta->subprogno = reg->subprogno; break; case KF_ARG_PTR_TO_REFCOUNTED_KPTR: - if (!type_is_ptr_alloc_obj(reg->type) && !type_is_non_owning_ref(reg->type)) { + if (!type_is_ptr_alloc_obj(reg->type)) { verbose(env, "arg#%d is neither owning or non-owning ref\n", i); return -EINVAL; } + if (!type_is_non_owning_ref(reg->type)) + meta->arg_owning_ref = true; rec = reg_btf_record(reg); if (!rec) { diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr.c b/tools/testing/selftests/bpf/progs/refcounted_kptr.c index 1d348a225140..a3da610b1e6b 100644 --- a/tools/testing/selftests/bpf/progs/refcounted_kptr.c +++ b/tools/testing/selftests/bpf/progs/refcounted_kptr.c @@ -375,6 +375,8 @@ long rbtree_refcounted_node_ref_escapes(void *ctx) bpf_rbtree_add(&aroot, &n->node, less_a); m = bpf_refcount_acquire(n); bpf_spin_unlock(&alock); + if (!m) + return 2; m->key = 2; bpf_obj_drop(m); diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c index efcb308f80ad..0b09e5c915b1 100644 --- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c @@ -29,7 +29,7 @@ static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b) } SEC("?tc") -__failure __msg("Unreleased reference id=3 alloc_insn=21") +__failure __msg("Unreleased reference id=4 alloc_insn=21") long rbtree_refcounted_node_ref_escapes(void *ctx) { struct node_acquire *n, *m; @@ -43,6 +43,8 @@ long rbtree_refcounted_node_ref_escapes(void *ctx) /* m becomes an owning ref but is never drop'd or added to a tree */ m = bpf_refcount_acquire(n); bpf_spin_unlock(&glock); + if (!m) + return 2; m->key = 2; return 0; -- cgit v1.2.3 From 411486626e5779bd85439282985ff3fc25a3f6d2 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Thu, 1 Jun 2023 18:21:54 +0200 Subject: bpf/xdp: optimize bpf_xdp_pointer to avoid reading sinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we observed a significant performance degradation in samples/bpf xdp1 and xdp2, due XDP multibuffer "xdp.frags" handling, added in commit 772251742262 ("samples/bpf: fixup some tools to be able to support xdp multibuffer"). This patch reduce the overhead by avoiding to read/load shared_info (sinfo) memory area, when XDP packet don't have any frags. This improves performance because sinfo is located in another cacheline. Function bpf_xdp_pointer() is used by BPF helpers bpf_xdp_load_bytes() and bpf_xdp_store_bytes(). As a help to reviewers, xdp_get_buff_len() can potentially access sinfo, but it uses xdp_buff_has_frags() flags bit check to avoid accessing sinfo in no-frags case. The likely/unlikely instrumentation lays out asm code such that sinfo access isn't interleaved with no-frags case (checked on GCC 12.2.1-4). The generated asm code is more compact towards the no-frags case. The BPF kfunc bpf_dynptr_slice() also use bpf_xdp_pointer(). Thus, it should also take effect for that. Signed-off-by: Jesper Dangaard Brouer Acked-by: Lorenzo Bianconi Acked-by: Toke Høiland-Jørgensen Link: https://lore.kernel.org/r/168563651438.3436004.17735707525651776648.stgit@firesoul Signed-off-by: Alexei Starovoitov --- net/core/filter.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index d25d52854c21..428df050d021 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -3948,20 +3948,21 @@ void bpf_xdp_copy_buf(struct xdp_buff *xdp, unsigned long off, void *bpf_xdp_pointer(struct xdp_buff *xdp, u32 offset, u32 len) { - struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp); u32 size = xdp->data_end - xdp->data; + struct skb_shared_info *sinfo; void *addr = xdp->data; int i; if (unlikely(offset > 0xffff || len > 0xffff)) return ERR_PTR(-EFAULT); - if (offset + len > xdp_get_buff_len(xdp)) + if (unlikely(offset + len > xdp_get_buff_len(xdp))) return ERR_PTR(-EINVAL); - if (offset < size) /* linear area */ + if (likely(offset < size)) /* linear area */ goto out; + sinfo = xdp_get_shared_info_from_buff(xdp); offset -= size; for (i = 0; i < sinfo->nr_frags; i++) { /* paged area */ u32 frag_size = skb_frag_size(&sinfo->frags[i]); -- cgit v1.2.3 From 503e4def5414fd0f9b6ffecb6eedbc4b1603693b Mon Sep 17 00:00:00 2001 From: "Daniel T. Lee" Date: Sat, 27 May 2023 21:27:06 +0900 Subject: bpf: Replace open code with for allocated object check >From commit 282de143ead9 ("bpf: Introduce allocated objects support"), With this allocated object with BPF program, (PTR_TO_BTF_ID | MEM_ALLOC) has been a way of indicating to check the type is the allocated object. commit d8939cb0a03c ("bpf: Loosen alloc obj test in verifier's reg_btf_record") >From the commit, there has been helper function for checking this, named type_is_ptr_alloc_obj(). But still, some of the code use open code to retrieve this info. This commit replaces the open code with the type_is_alloc(), and the type_is_ptr_alloc_obj() function. Signed-off-by: Daniel T. Lee Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230527122706.59315-1-danieltimlee@gmail.com --- kernel/bpf/verifier.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 27b54266b4c7..7acbd103f9ac 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5894,7 +5894,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, * program allocated objects (which always have ref_obj_id > 0), * but not for untrusted PTR_TO_BTF_ID | MEM_ALLOC. */ - if (atype != BPF_READ && reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) { + if (atype != BPF_READ && !type_is_ptr_alloc_obj(reg->type)) { verbose(env, "only read is supported\n"); return -EACCES; } @@ -7514,7 +7514,7 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno, if (base_type(arg_type) == ARG_PTR_TO_MEM) type &= ~DYNPTR_TYPE_FLAG_MASK; - if (meta->func_id == BPF_FUNC_kptr_xchg && type & MEM_ALLOC) + if (meta->func_id == BPF_FUNC_kptr_xchg && type_is_alloc(type)) type &= ~MEM_ALLOC; for (i = 0; i < ARRAY_SIZE(compatible->types); i++) { -- cgit v1.2.3 From 51302c951c8fd5c298565c7127c855bf1d4550b6 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 2 Jun 2023 10:01:11 -0500 Subject: bpf: Teach verifier that trusted PTR_TO_BTF_ID pointers are non-NULL In reg_type_not_null(), we currently assume that a pointer may be NULL if it has the PTR_MAYBE_NULL modifier, or if it doesn't belong to one of several base type of pointers that are never NULL-able. For example, PTR_TO_CTX, PTR_TO_MAP_VALUE, etc. It turns out that in some cases, PTR_TO_BTF_ID can never be NULL as well, though we currently don't specify it. For example, if you had the following program: SEC("tc") long example_refcnt_fail(void *ctx) { struct bpf_cpumask *mask1, *mask2; mask1 = bpf_cpumask_create(); mask2 = bpf_cpumask_create(); if (!mask1 || !mask2) goto error_release; bpf_cpumask_test_cpu(0, (const struct cpumask *)mask1); bpf_cpumask_test_cpu(0, (const struct cpumask *)mask2); error_release: if (mask1) bpf_cpumask_release(mask1); if (mask2) bpf_cpumask_release(mask2); return ret; } The verifier will incorrectly fail to load the program, thinking (unintuitively) that we have a possibly-unreleased reference if the mask is NULL, because we (correctly) don't issue a bpf_cpumask_release() on the NULL path. The reason the verifier gets confused is due to the fact that we don't explicitly tell the verifier that trusted PTR_TO_BTF_ID pointers can never be NULL. Basically, if we successfully get past the if check (meaning both pointers go from ptr_or_null_bpf_cpumask to ptr_bpf_cpumask), the verifier will correctly assume that the references need to be dropped on any possible branch that leads to program exit. However, it will _incorrectly_ think that the ptr == NULL branch is possible, and will erroneously detect it as a branch on which we failed to drop the reference. The solution is of course to teach the verifier that trusted PTR_TO_BTF_ID pointers can never be NULL, so that it doesn't incorrectly think it's possible for the reference to be present on the ptr == NULL branch. A follow-on patch will add a selftest that verifies this behavior. Signed-off-by: David Vernet Link: https://lore.kernel.org/r/20230602150112.1494194-1-void@manifault.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 7acbd103f9ac..1e38584d497c 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -197,6 +197,7 @@ static int ref_set_non_owning(struct bpf_verifier_env *env, struct bpf_reg_state *reg); static void specialize_kfunc(struct bpf_verifier_env *env, u32 func_id, u16 offset, unsigned long *addr); +static bool is_trusted_reg(const struct bpf_reg_state *reg); static bool bpf_map_ptr_poisoned(const struct bpf_insn_aux_data *aux) { @@ -442,8 +443,11 @@ static bool type_may_be_null(u32 type) return type & PTR_MAYBE_NULL; } -static bool reg_type_not_null(enum bpf_reg_type type) +static bool reg_not_null(const struct bpf_reg_state *reg) { + enum bpf_reg_type type; + + type = reg->type; if (type_may_be_null(type)) return false; @@ -453,6 +457,7 @@ static bool reg_type_not_null(enum bpf_reg_type type) type == PTR_TO_MAP_VALUE || type == PTR_TO_MAP_KEY || type == PTR_TO_SOCK_COMMON || + (type == PTR_TO_BTF_ID && is_trusted_reg(reg)) || type == PTR_TO_MEM; } @@ -13170,7 +13175,7 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode, bool is_jmp32) { if (__is_pointer_value(false, reg)) { - if (!reg_type_not_null(reg->type)) + if (!reg_not_null(reg)) return -1; /* If pointer is valid tests against zero will fail so we can -- cgit v1.2.3 From f904c67876c42c14a108d7f80459ef59d900b8fc Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 2 Jun 2023 10:01:12 -0500 Subject: selftests/bpf: Add test for non-NULLable PTR_TO_BTF_IDs In a recent patch, we taught the verifier that trusted PTR_TO_BTF_ID can never be NULL. This prevents the verifier from incorrectly failing to load certain programs where it gets confused and thinks a reference isn't dropped because it incorrectly assumes that a branch exists in which a NULL PTR_TO_BTF_ID pointer is never released. This patch adds a testcase that verifies this cannot happen. Signed-off-by: David Vernet Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/r/20230602150112.1494194-2-void@manifault.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/cpumask.c | 1 + .../testing/selftests/bpf/progs/cpumask_success.c | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/cpumask.c b/tools/testing/selftests/bpf/prog_tests/cpumask.c index cdf4acc18e4c..d89191440fb1 100644 --- a/tools/testing/selftests/bpf/prog_tests/cpumask.c +++ b/tools/testing/selftests/bpf/prog_tests/cpumask.c @@ -70,5 +70,6 @@ void test_cpumask(void) verify_success(cpumask_success_testcases[i]); } + RUN_TESTS(cpumask_success); RUN_TESTS(cpumask_failure); } diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index 2fcdd7f68ac7..602a88b03dbc 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -5,6 +5,7 @@ #include #include +#include "bpf_misc.h" #include "cpumask_common.h" char _license[] SEC("license") = "GPL"; @@ -426,3 +427,26 @@ int BPF_PROG(test_global_mask_rcu, struct task_struct *task, u64 clone_flags) return 0; } + +SEC("tp_btf/task_newtask") +__success +int BPF_PROG(test_refcount_null_tracking, struct task_struct *task, u64 clone_flags) +{ + struct bpf_cpumask *mask1, *mask2; + + mask1 = bpf_cpumask_create(); + mask2 = bpf_cpumask_create(); + + if (!mask1 || !mask2) + goto free_masks_return; + + bpf_cpumask_test_cpu(0, (const struct cpumask *)mask1); + bpf_cpumask_test_cpu(0, (const struct cpumask *)mask2); + +free_masks_return: + if (mask1) + bpf_cpumask_release(mask1); + if (mask2) + bpf_cpumask_release(mask2); + return 0; +} -- cgit v1.2.3 From 7a113ff6355944283402fb617dc97122f68d5a41 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 2 Jun 2023 12:21:33 +0200 Subject: lib/ref_tracker: add unlocked leak print helper To have reliable detection of leaks, caller must be able to check under the same lock both: tracked counter and the leaks. dir.lock is natural candidate for such lock and unlocked print helper can be called with this lock taken. As a bonus we can reuse this helper in ref_tracker_dir_exit. Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Reviewed-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- include/linux/ref_tracker.h | 8 ++++++ lib/ref_tracker.c | 66 ++++++++++++++++++++++++++------------------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 9ca353ab712b..87a92f2bec1b 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -36,6 +36,9 @@ static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir, void ref_tracker_dir_exit(struct ref_tracker_dir *dir); +void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, + unsigned int display_limit); + void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit); @@ -56,6 +59,11 @@ static inline void ref_tracker_dir_exit(struct ref_tracker_dir *dir) { } +static inline void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ +} + static inline void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit) { diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index dc7b14aa3431..d4eb0929af8f 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -14,6 +14,38 @@ struct ref_tracker { depot_stack_handle_t free_stack_handle; }; +void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + struct ref_tracker *tracker; + unsigned int i = 0; + + lockdep_assert_held(&dir->lock); + + list_for_each_entry(tracker, &dir->list, head) { + if (i < display_limit) { + pr_err("leaked reference.\n"); + if (tracker->alloc_stack_handle) + stack_depot_print(tracker->alloc_stack_handle); + i++; + } else { + break; + } + } +} +EXPORT_SYMBOL(ref_tracker_dir_print_locked); + +void ref_tracker_dir_print(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + unsigned long flags; + + spin_lock_irqsave(&dir->lock, flags); + ref_tracker_dir_print_locked(dir, display_limit); + spin_unlock_irqrestore(&dir->lock, flags); +} +EXPORT_SYMBOL(ref_tracker_dir_print); + void ref_tracker_dir_exit(struct ref_tracker_dir *dir) { struct ref_tracker *tracker, *n; @@ -27,13 +59,13 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) kfree(tracker); dir->quarantine_avail++; } - list_for_each_entry_safe(tracker, n, &dir->list, head) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); + if (!list_empty(&dir->list)) { + ref_tracker_dir_print_locked(dir, 16); leak = true; - list_del(&tracker->head); - kfree(tracker); + list_for_each_entry_safe(tracker, n, &dir->list, head) { + list_del(&tracker->head); + kfree(tracker); + } } spin_unlock_irqrestore(&dir->lock, flags); WARN_ON_ONCE(leak); @@ -42,28 +74,6 @@ void ref_tracker_dir_exit(struct ref_tracker_dir *dir) } EXPORT_SYMBOL(ref_tracker_dir_exit); -void ref_tracker_dir_print(struct ref_tracker_dir *dir, - unsigned int display_limit) -{ - struct ref_tracker *tracker; - unsigned long flags; - unsigned int i = 0; - - spin_lock_irqsave(&dir->lock, flags); - list_for_each_entry(tracker, &dir->list, head) { - if (i < display_limit) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); - i++; - } else { - break; - } - } - spin_unlock_irqrestore(&dir->lock, flags); -} -EXPORT_SYMBOL(ref_tracker_dir_print); - int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp) -- cgit v1.2.3 From b6d7c0eb2dcbd238fa233a3a1737654e380e784a Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 2 Jun 2023 12:21:34 +0200 Subject: lib/ref_tracker: improve printing stats In case the library is tracking busy subsystem, simply printing stack for every active reference will spam log with long, hard to read, redundant stack traces. To improve readabilty following changes have been made: - reports are printed per stack_handle - log is more compact, - added display name for ref_tracker_dir - it will differentiate multiple subsystems, - stack trace is printed indented, in the same printk call, - info about dropped references is printed as well. Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Reviewed-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- include/linux/ref_tracker.h | 9 ++++- lib/ref_tracker.c | 90 +++++++++++++++++++++++++++++++++++++++------ lib/test_ref_tracker.c | 2 +- net/core/dev.c | 2 +- net/core/net_namespace.c | 4 +- 5 files changed, 90 insertions(+), 17 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 87a92f2bec1b..19a69e7809d6 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -17,12 +17,15 @@ struct ref_tracker_dir { bool dead; struct list_head list; /* List of active trackers */ struct list_head quarantine; /* List of dead trackers */ + char name[32]; #endif }; #ifdef CONFIG_REF_TRACKER + static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir, - unsigned int quarantine_count) + unsigned int quarantine_count, + const char *name) { INIT_LIST_HEAD(&dir->list); INIT_LIST_HEAD(&dir->quarantine); @@ -31,6 +34,7 @@ static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir, dir->dead = false; refcount_set(&dir->untracked, 1); refcount_set(&dir->no_tracker, 1); + strscpy(dir->name, name, sizeof(dir->name)); stack_depot_init(); } @@ -51,7 +55,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir, #else /* CONFIG_REF_TRACKER */ static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir, - unsigned int quarantine_count) + unsigned int quarantine_count, + const char *name) { } diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index d4eb0929af8f..2ffe79c90c17 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later + +#define pr_fmt(fmt) "ref_tracker: " fmt + #include +#include #include #include #include #include #define REF_TRACKER_STACK_ENTRIES 16 +#define STACK_BUF_SIZE 1024 struct ref_tracker { struct list_head head; /* anchor into dir->list or dir->quarantine */ @@ -14,24 +19,87 @@ struct ref_tracker { depot_stack_handle_t free_stack_handle; }; -void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, - unsigned int display_limit) +struct ref_tracker_dir_stats { + int total; + int count; + struct { + depot_stack_handle_t stack_handle; + unsigned int count; + } stacks[]; +}; + +static struct ref_tracker_dir_stats * +ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit) { + struct ref_tracker_dir_stats *stats; struct ref_tracker *tracker; - unsigned int i = 0; - lockdep_assert_held(&dir->lock); + stats = kmalloc(struct_size(stats, stacks, limit), + GFP_NOWAIT | __GFP_NOWARN); + if (!stats) + return ERR_PTR(-ENOMEM); + stats->total = 0; + stats->count = 0; list_for_each_entry(tracker, &dir->list, head) { - if (i < display_limit) { - pr_err("leaked reference.\n"); - if (tracker->alloc_stack_handle) - stack_depot_print(tracker->alloc_stack_handle); - i++; - } else { - break; + depot_stack_handle_t stack = tracker->alloc_stack_handle; + int i; + + ++stats->total; + for (i = 0; i < stats->count; ++i) + if (stats->stacks[i].stack_handle == stack) + break; + if (i >= limit) + continue; + if (i >= stats->count) { + stats->stacks[i].stack_handle = stack; + stats->stacks[i].count = 0; + ++stats->count; } + ++stats->stacks[i].count; + } + + return stats; +} + +void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + struct ref_tracker_dir_stats *stats; + unsigned int i = 0, skipped; + depot_stack_handle_t stack; + char *sbuf; + + lockdep_assert_held(&dir->lock); + + if (list_empty(&dir->list)) + return; + + stats = ref_tracker_get_stats(dir, display_limit); + if (IS_ERR(stats)) { + pr_err("%s@%pK: couldn't get stats, error %pe\n", + dir->name, dir, stats); + return; } + + sbuf = kmalloc(STACK_BUF_SIZE, GFP_NOWAIT | __GFP_NOWARN); + + for (i = 0, skipped = stats->total; i < stats->count; ++i) { + stack = stats->stacks[i].stack_handle; + if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4)) + sbuf[0] = 0; + pr_err("%s@%pK has %d/%d users at\n%s\n", dir->name, dir, + stats->stacks[i].count, stats->total, sbuf); + skipped -= stats->stacks[i].count; + } + + if (skipped) + pr_err("%s@%pK skipped reports about %d/%d users.\n", + dir->name, dir, skipped, stats->total); + + kfree(sbuf); + + kfree(stats); } EXPORT_SYMBOL(ref_tracker_dir_print_locked); diff --git a/lib/test_ref_tracker.c b/lib/test_ref_tracker.c index 19d7dec70cc6..49970a7c96f3 100644 --- a/lib/test_ref_tracker.c +++ b/lib/test_ref_tracker.c @@ -64,7 +64,7 @@ static int __init test_ref_tracker_init(void) { int i; - ref_tracker_dir_init(&ref_dir, 100); + ref_tracker_dir_init(&ref_dir, 100, "selftest"); timer_setup(&test_ref_tracker_timer, test_ref_tracker_timer_func, 0); mod_timer(&test_ref_tracker_timer, jiffies + 1); diff --git a/net/core/dev.c b/net/core/dev.c index b3c13e041935..5ca7a133d3be 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -10630,7 +10630,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, dev = PTR_ALIGN(p, NETDEV_ALIGN); dev->padded = (char *)dev - (char *)p; - ref_tracker_dir_init(&dev->refcnt_tracker, 128); + ref_tracker_dir_init(&dev->refcnt_tracker, 128, name); #ifdef CONFIG_PCPU_DEV_REFCNT dev->pcpu_refcnt = alloc_percpu(int); if (!dev->pcpu_refcnt) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 3e3598cd49f2..f4183c4c1ec8 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -308,7 +308,7 @@ EXPORT_SYMBOL_GPL(get_net_ns_by_id); /* init code that must occur even if setup_net() is not called. */ static __net_init void preinit_net(struct net *net) { - ref_tracker_dir_init(&net->notrefcnt_tracker, 128); + ref_tracker_dir_init(&net->notrefcnt_tracker, 128, "net notrefcnt"); } /* @@ -322,7 +322,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) LIST_HEAD(net_exit_list); refcount_set(&net->ns.count, 1); - ref_tracker_dir_init(&net->refcnt_tracker, 128); + ref_tracker_dir_init(&net->refcnt_tracker, 128, "net refcnt"); refcount_set(&net->passive, 1); get_random_bytes(&net->hash_mix, sizeof(u32)); -- cgit v1.2.3 From 227c6c832303cec3941166d3335ecbccd980d615 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 2 Jun 2023 12:21:35 +0200 Subject: lib/ref_tracker: add printing to memory buffer Similar to stack_(depot|trace)_snprint the patch adds helper to printing stats to memory buffer. It will be helpful in case of debugfs. Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Reviewed-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- include/linux/ref_tracker.h | 8 +++++++ lib/ref_tracker.c | 56 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/include/linux/ref_tracker.h b/include/linux/ref_tracker.h index 19a69e7809d6..8eac4f3d5254 100644 --- a/include/linux/ref_tracker.h +++ b/include/linux/ref_tracker.h @@ -46,6 +46,8 @@ void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, void ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit); +int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf, size_t size); + int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp); @@ -74,6 +76,12 @@ static inline void ref_tracker_dir_print(struct ref_tracker_dir *dir, { } +static inline int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, + char *buf, size_t size) +{ + return 0; +} + static inline int ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp, gfp_t gfp) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index 2ffe79c90c17..cce4614b0794 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -62,8 +62,27 @@ ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit) return stats; } -void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, - unsigned int display_limit) +struct ostream { + char *buf; + int size, used; +}; + +#define pr_ostream(stream, fmt, args...) \ +({ \ + struct ostream *_s = (stream); \ +\ + if (!_s->buf) { \ + pr_err(fmt, ##args); \ + } else { \ + int ret, len = _s->size - _s->used; \ + ret = snprintf(_s->buf + _s->used, len, pr_fmt(fmt), ##args); \ + _s->used += min(ret, len); \ + } \ +}) + +static void +__ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir, + unsigned int display_limit, struct ostream *s) { struct ref_tracker_dir_stats *stats; unsigned int i = 0, skipped; @@ -77,8 +96,8 @@ void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, stats = ref_tracker_get_stats(dir, display_limit); if (IS_ERR(stats)) { - pr_err("%s@%pK: couldn't get stats, error %pe\n", - dir->name, dir, stats); + pr_ostream(s, "%s@%pK: couldn't get stats, error %pe\n", + dir->name, dir, stats); return; } @@ -88,19 +107,27 @@ void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, stack = stats->stacks[i].stack_handle; if (sbuf && !stack_depot_snprint(stack, sbuf, STACK_BUF_SIZE, 4)) sbuf[0] = 0; - pr_err("%s@%pK has %d/%d users at\n%s\n", dir->name, dir, - stats->stacks[i].count, stats->total, sbuf); + pr_ostream(s, "%s@%pK has %d/%d users at\n%s\n", dir->name, dir, + stats->stacks[i].count, stats->total, sbuf); skipped -= stats->stacks[i].count; } if (skipped) - pr_err("%s@%pK skipped reports about %d/%d users.\n", - dir->name, dir, skipped, stats->total); + pr_ostream(s, "%s@%pK skipped reports about %d/%d users.\n", + dir->name, dir, skipped, stats->total); kfree(sbuf); kfree(stats); } + +void ref_tracker_dir_print_locked(struct ref_tracker_dir *dir, + unsigned int display_limit) +{ + struct ostream os = {}; + + __ref_tracker_dir_pr_ostream(dir, display_limit, &os); +} EXPORT_SYMBOL(ref_tracker_dir_print_locked); void ref_tracker_dir_print(struct ref_tracker_dir *dir, @@ -114,6 +141,19 @@ void ref_tracker_dir_print(struct ref_tracker_dir *dir, } EXPORT_SYMBOL(ref_tracker_dir_print); +int ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf, size_t size) +{ + struct ostream os = { .buf = buf, .size = size }; + unsigned long flags; + + spin_lock_irqsave(&dir->lock, flags); + __ref_tracker_dir_pr_ostream(dir, 16, &os); + spin_unlock_irqrestore(&dir->lock, flags); + + return os.used; +} +EXPORT_SYMBOL(ref_tracker_dir_snprint); + void ref_tracker_dir_exit(struct ref_tracker_dir *dir) { struct ref_tracker *tracker, *n; -- cgit v1.2.3 From acd8f0e5d72741bee715867e8185e3d57ca93703 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 2 Jun 2023 12:21:36 +0200 Subject: lib/ref_tracker: remove warnings in case of allocation failure Library can handle allocation failures. To avoid allocation warnings __GFP_NOWARN has been added everywhere. Moreover GFP_ATOMIC has been replaced with GFP_NOWAIT in case of stack allocation on tracker free call. Signed-off-by: Andrzej Hajda Reviewed-by: Andi Shyti Reviewed-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- lib/ref_tracker.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ref_tracker.c b/lib/ref_tracker.c index cce4614b0794..cf5609b1ca79 100644 --- a/lib/ref_tracker.c +++ b/lib/ref_tracker.c @@ -189,7 +189,7 @@ int ref_tracker_alloc(struct ref_tracker_dir *dir, unsigned long entries[REF_TRACKER_STACK_ENTRIES]; struct ref_tracker *tracker; unsigned int nr_entries; - gfp_t gfp_mask = gfp; + gfp_t gfp_mask = gfp | __GFP_NOWARN; unsigned long flags; WARN_ON_ONCE(dir->dead); @@ -237,7 +237,8 @@ int ref_tracker_free(struct ref_tracker_dir *dir, return -EEXIST; } nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 1); - stack_handle = stack_depot_save(entries, nr_entries, GFP_ATOMIC); + stack_handle = stack_depot_save(entries, nr_entries, + GFP_NOWAIT | __GFP_NOWARN); spin_lock_irqsave(&dir->lock, flags); if (tracker->dead) { -- cgit v1.2.3 From edd75c802855271c8610f58a2fc9e54aefc49ce5 Mon Sep 17 00:00:00 2001 From: Viktor Malik Date: Tue, 30 May 2023 14:33:52 +0200 Subject: tools/resolve_btfids: Fix setting HOSTCFLAGS Building BPF selftests with custom HOSTCFLAGS yields an error: # make HOSTCFLAGS="-O2" [...] HOSTCC ./tools/testing/selftests/bpf/tools/build/resolve_btfids/main.o main.c:73:10: fatal error: linux/rbtree.h: No such file or directory 73 | #include | ^~~~~~~~~~~~~~~~ The reason is that tools/bpf/resolve_btfids/Makefile passes header include paths by extending HOSTCFLAGS which is overridden by setting HOSTCFLAGS in the make command (because of Makefile rules [1]). This patch fixes the above problem by passing the include paths via `HOSTCFLAGS_resolve_btfids` which is used by tools/build/Build.include and can be combined with overridding HOSTCFLAGS. [1] https://www.gnu.org/software/make/manual/html_node/Overriding.html Fixes: 56a2df7615fa ("tools/resolve_btfids: Compile resolve_btfids as host program") Signed-off-by: Viktor Malik Signed-off-by: Andrii Nakryiko Acked-by: Jiri Olsa Link: https://lore.kernel.org/bpf/20230530123352.1308488-1-vmalik@redhat.com --- tools/bpf/resolve_btfids/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile index ac548a7baa73..4b8079f294f6 100644 --- a/tools/bpf/resolve_btfids/Makefile +++ b/tools/bpf/resolve_btfids/Makefile @@ -67,7 +67,7 @@ $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OU LIBELF_FLAGS := $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null) LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf) -HOSTCFLAGS += -g \ +HOSTCFLAGS_resolve_btfids += -g \ -I$(srctree)/tools/include \ -I$(srctree)/tools/include/uapi \ -I$(LIBBPF_INCLUDE) \ @@ -76,7 +76,7 @@ HOSTCFLAGS += -g \ LIBS = $(LIBELF_LIBS) -lz -export srctree OUTPUT HOSTCFLAGS Q HOSTCC HOSTLD HOSTAR +export srctree OUTPUT HOSTCFLAGS_resolve_btfids Q HOSTCC HOSTLD HOSTAR include $(srctree)/tools/build/Makefile.include $(BINARY_IN): fixdep FORCE prepare | $(OUTPUT) -- cgit v1.2.3 From 3d272c2fa8045f31879a3beee230c1711367b697 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 2 Jun 2023 09:01:08 -0500 Subject: selftests/bpf: Add missing selftests kconfig options Our selftests of course rely on the kernel being built with CONFIG_DEBUG_INFO_BTF=y, though this (nor its dependencies of CONFIG_DEBUG_INFO=y and CONFIG_DEBUG_INFO_DWARF4=y) are not specified. This causes the wrong kernel to be built, and selftests to similarly fail to build. Additionally, in the BPF selftests kconfig file, CONFIG_NF_CONNTRACK_MARK=y is specified, so that the 'u_int32_t mark' field will be present in the definition of struct nf_conn. While a dependency of CONFIG_NF_CONNTRACK_MARK=y, CONFIG_NETFILTER_ADVANCED=y, should be enabled by default, I've run into instances of CONFIG_NF_CONNTRACK_MARK not being set because CONFIG_NETFILTER_ADVANCED isn't set, and have to manually enable them with make menuconfig. Let's add these missing kconfig options to the file so that the necessary dependencies are in place to build vmlinux. Otherwise, we'll get errors like this when we try to compile selftests and generate vmlinux.h: $ cd /path/to/bpf-next $ make mrproper; make defconfig $ cat tools/testing/selftests/config >> .config $ make -j ... $ cd tools/testing/selftests/bpf $ make clean $ make -j ... LD [M] tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.ko tools/testing/selftests/bpf/tools/build/bpftool/bootstrap/bpftool btf dump file vmlinux format c > tools/testing/selftests/bpf/tools/build/bpftool/vmlinux.h libbpf: failed to find '.BTF' ELF section in vmlinux Error: failed to load BTF from bpf-next/vmlinux: No data available make[1]: *** [Makefile:208: tools/testing/selftests/bpf/tools/build/bpftool/vmlinux.h] Error 195 make[1]: *** Deleting file 'tools/testing/selftests/bpf/tools/build/bpftool/vmlinux.h' make: *** [Makefile:261: tools/testing/selftests/bpf/tools/sbin/bpftool] Error 2 Signed-off-by: David Vernet Signed-off-by: Andrii Nakryiko Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230602140108.1177900-1-void@manifault.com --- tools/testing/selftests/bpf/config | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 63cd4ab70171..3b350bc31343 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -13,6 +13,9 @@ CONFIG_CGROUP_BPF=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_BTF=y +CONFIG_DEBUG_INFO_DWARF4=y CONFIG_DYNAMIC_FTRACE=y CONFIG_FPROBE=y CONFIG_FTRACE_SYSCALLS=y @@ -60,6 +63,7 @@ CONFIG_NET_SCH_INGRESS=y CONFIG_NET_SCHED=y CONFIG_NETDEVSIM=y CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y CONFIG_NETFILTER_SYNPROXY=y CONFIG_NETFILTER_XT_CONNMARK=y CONFIG_NETFILTER_XT_MATCH_STATE=y -- cgit v1.2.3 From 2b03bcae66c7b29f151e51d3109dbe1e31272235 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 31 May 2023 12:04:21 +0100 Subject: kcm: Support MSG_SPLICE_PAGES Make AF_KCM sendmsg() support MSG_SPLICE_PAGES. This causes pages to be spliced from the source iterator if possible. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Tom Herbert cc: Tom Herbert cc: Cong Wang cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/kcm/kcmsock.c | 57 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index cfe828bd7fc6..8555ede66333 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -989,29 +989,52 @@ start: merge = false; } - copy = min_t(int, msg_data_left(msg), - pfrag->size - pfrag->offset); + if (msg->msg_flags & MSG_SPLICE_PAGES) { + copy = msg_data_left(msg); + if (!sk_wmem_schedule(sk, copy)) + goto wait_for_memory; - if (!sk_wmem_schedule(sk, copy)) - goto wait_for_memory; + err = skb_splice_from_iter(skb, &msg->msg_iter, copy, + sk->sk_allocation); + if (err < 0) { + if (err == -EMSGSIZE) + goto wait_for_memory; + goto out_error; + } - err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb, - pfrag->page, - pfrag->offset, - copy); - if (err) - goto out_error; + copy = err; + skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; + sk_wmem_queued_add(sk, copy); + sk_mem_charge(sk, copy); - /* Update the skb. */ - if (merge) { - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); + if (head != skb) + head->truesize += copy; } else { - skb_fill_page_desc(skb, i, pfrag->page, - pfrag->offset, copy); - get_page(pfrag->page); + copy = min_t(int, msg_data_left(msg), + pfrag->size - pfrag->offset); + if (!sk_wmem_schedule(sk, copy)) + goto wait_for_memory; + + err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb, + pfrag->page, + pfrag->offset, + copy); + if (err) + goto out_error; + + /* Update the skb. */ + if (merge) { + skb_frag_size_add( + &skb_shinfo(skb)->frags[i - 1], copy); + } else { + skb_fill_page_desc(skb, i, pfrag->page, + pfrag->offset, copy); + get_page(pfrag->page); + } + + pfrag->offset += copy; } - pfrag->offset += copy; copied += copy; if (head != skb) { head->len += copy; -- cgit v1.2.3 From 5bb3a5cb3e217b838e85661f527818e16ce61bec Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 31 May 2023 12:04:22 +0100 Subject: kcm: Convert kcm_sendpage() to use MSG_SPLICE_PAGES Convert kcm_sendpage() to use sendmsg() with MSG_SPLICE_PAGES rather than directly splicing in the pages itself. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Tom Herbert cc: Tom Herbert cc: Cong Wang cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/kcm/kcmsock.c | 161 ++++++------------------------------------------------ 1 file changed, 18 insertions(+), 143 deletions(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 8555ede66333..ba22af16b96d 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -761,149 +761,6 @@ static void kcm_push(struct kcm_sock *kcm) kcm_write_msgs(kcm); } -static ssize_t kcm_sendpage(struct socket *sock, struct page *page, - int offset, size_t size, int flags) - -{ - struct sock *sk = sock->sk; - struct kcm_sock *kcm = kcm_sk(sk); - struct sk_buff *skb = NULL, *head = NULL; - long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); - bool eor; - int err = 0; - int i; - - if (flags & MSG_SENDPAGE_NOTLAST) - flags |= MSG_MORE; - - /* No MSG_EOR from splice, only look at MSG_MORE */ - eor = !(flags & MSG_MORE); - - lock_sock(sk); - - sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); - - err = -EPIPE; - if (sk->sk_err) - goto out_error; - - if (kcm->seq_skb) { - /* Previously opened message */ - head = kcm->seq_skb; - skb = kcm_tx_msg(head)->last_skb; - i = skb_shinfo(skb)->nr_frags; - - if (skb_can_coalesce(skb, i, page, offset)) { - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], size); - skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; - goto coalesced; - } - - if (i >= MAX_SKB_FRAGS) { - struct sk_buff *tskb; - - tskb = alloc_skb(0, sk->sk_allocation); - while (!tskb) { - kcm_push(kcm); - err = sk_stream_wait_memory(sk, &timeo); - if (err) - goto out_error; - } - - if (head == skb) - skb_shinfo(head)->frag_list = tskb; - else - skb->next = tskb; - - skb = tskb; - skb->ip_summed = CHECKSUM_UNNECESSARY; - i = 0; - } - } else { - /* Call the sk_stream functions to manage the sndbuf mem. */ - if (!sk_stream_memory_free(sk)) { - kcm_push(kcm); - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - err = sk_stream_wait_memory(sk, &timeo); - if (err) - goto out_error; - } - - head = alloc_skb(0, sk->sk_allocation); - while (!head) { - kcm_push(kcm); - err = sk_stream_wait_memory(sk, &timeo); - if (err) - goto out_error; - } - - skb = head; - i = 0; - } - - get_page(page); - skb_fill_page_desc_noacc(skb, i, page, offset, size); - skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; - -coalesced: - skb->len += size; - skb->data_len += size; - skb->truesize += size; - sk->sk_wmem_queued += size; - sk_mem_charge(sk, size); - - if (head != skb) { - head->len += size; - head->data_len += size; - head->truesize += size; - } - - if (eor) { - bool not_busy = skb_queue_empty(&sk->sk_write_queue); - - /* Message complete, queue it on send buffer */ - __skb_queue_tail(&sk->sk_write_queue, head); - kcm->seq_skb = NULL; - KCM_STATS_INCR(kcm->stats.tx_msgs); - - if (flags & MSG_BATCH) { - kcm->tx_wait_more = true; - } else if (kcm->tx_wait_more || not_busy) { - err = kcm_write_msgs(kcm); - if (err < 0) { - /* We got a hard error in write_msgs but have - * already queued this message. Report an error - * in the socket, but don't affect return value - * from sendmsg - */ - pr_warn("KCM: Hard failure on kcm_write_msgs\n"); - report_csk_error(&kcm->sk, -err); - } - } - } else { - /* Message not complete, save state */ - kcm->seq_skb = head; - kcm_tx_msg(head)->last_skb = skb; - } - - KCM_STATS_ADD(kcm->stats.tx_bytes, size); - - release_sock(sk); - return size; - -out_error: - kcm_push(kcm); - - err = sk_stream_error(sk, flags, err); - - /* make sure we wake any epoll edge trigger waiter */ - if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN)) - sk->sk_write_space(sk); - - release_sock(sk); - return err; -} - static int kcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; @@ -1111,6 +968,24 @@ out_error: return err; } +static ssize_t kcm_sendpage(struct socket *sock, struct page *page, + int offset, size_t size, int flags) + +{ + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; + + if (flags & MSG_SENDPAGE_NOTLAST) + msg.msg_flags |= MSG_MORE; + + if (flags & MSG_OOB) + return -EOPNOTSUPP; + + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + return kcm_sendmsg(sock, &msg, size); +} + static int kcm_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) { -- cgit v1.2.3 From 7b355b76e2b32cc516969c01984efdf49b11fc81 Mon Sep 17 00:00:00 2001 From: Richard Gobert Date: Thu, 1 Jun 2023 18:14:09 +0200 Subject: gro: decrease size of CB The GRO control block (NAPI_GRO_CB) is currently at its maximum size. This commit reduces its size by putting two groups of fields that are used only at different times into a union. Specifically, the fields frag0 and frag0_len are the fields that make up the frag0 optimisation mechanism, which is used during the initial parsing of the SKB. The fields last and age are used after the initial parsing, while the SKB is stored in the GRO list, waiting for other packets to arrive. There was one location in dev_gro_receive that modified the frag0 fields after setting last and age. I changed this accordingly without altering the code behaviour. Signed-off-by: Richard Gobert Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20230601161407.GA9253@debian Signed-off-by: Paolo Abeni --- include/net/gro.h | 26 ++++++++++++++++---------- net/core/gro.c | 19 ++++++++++++------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/include/net/gro.h b/include/net/gro.h index a4fab706240d..7b47dd6ce94f 100644 --- a/include/net/gro.h +++ b/include/net/gro.h @@ -11,11 +11,23 @@ #include struct napi_gro_cb { - /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */ - void *frag0; + union { + struct { + /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */ + void *frag0; - /* Length of frag0. */ - unsigned int frag0_len; + /* Length of frag0. */ + unsigned int frag0_len; + }; + + struct { + /* used in skb_gro_receive() slow path */ + struct sk_buff *last; + + /* jiffies when first packet was created/queued */ + unsigned long age; + }; + }; /* This indicates where we are processing relative to skb->data. */ int data_offset; @@ -32,9 +44,6 @@ struct napi_gro_cb { /* Used in ipv6_gro_receive() and foo-over-udp */ u16 proto; - /* jiffies when first packet was created/queued */ - unsigned long age; - /* Used in napi_gro_cb::free */ #define NAPI_GRO_FREE 1 #define NAPI_GRO_FREE_STOLEN_HEAD 2 @@ -77,9 +86,6 @@ struct napi_gro_cb { /* used to support CHECKSUM_COMPLETE for tunneling protocols */ __wsum csum; - - /* used in skb_gro_receive() slow path */ - struct sk_buff *last; }; #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb) diff --git a/net/core/gro.c b/net/core/gro.c index 6783a47a6136..4d45f78e2fac 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -458,6 +458,14 @@ static void gro_pull_from_frag0(struct sk_buff *skb, int grow) } } +static void gro_try_pull_from_frag0(struct sk_buff *skb) +{ + int grow = skb_gro_offset(skb) - skb_headlen(skb); + + if (grow > 0) + gro_pull_from_frag0(skb, grow); +} + static void gro_flush_oldest(struct napi_struct *napi, struct list_head *head) { struct sk_buff *oldest; @@ -487,7 +495,6 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff struct sk_buff *pp = NULL; enum gro_result ret; int same_flow; - int grow; if (netif_elide_gro(skb->dev)) goto normal; @@ -562,17 +569,14 @@ found_ptype: else gro_list->count++; + /* Must be called before setting NAPI_GRO_CB(skb)->{age|last} */ + gro_try_pull_from_frag0(skb); NAPI_GRO_CB(skb)->age = jiffies; NAPI_GRO_CB(skb)->last = skb; if (!skb_is_gso(skb)) skb_shinfo(skb)->gso_size = skb_gro_len(skb); list_add(&skb->list, &gro_list->list); ret = GRO_HELD; - -pull: - grow = skb_gro_offset(skb) - skb_headlen(skb); - if (grow > 0) - gro_pull_from_frag0(skb, grow); ok: if (gro_list->count) { if (!test_bit(bucket, &napi->gro_bitmask)) @@ -585,7 +589,8 @@ ok: normal: ret = GRO_NORMAL; - goto pull; + gro_try_pull_from_frag0(skb); + goto ok; } struct packet_offload *gro_find_receive_by_type(__be16 type) -- cgit v1.2.3 From 75f059d37b58d9082273dfdd097d57f788f57c27 Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Wed, 24 May 2023 20:41:58 +0300 Subject: wifi: iwlwifi: cfg: freeze 22500 devices FW API FW version is now frozen for 22500 devices. Don't allow newer versions in the driver. Signed-off-by: Golan Ben Ami Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.8a25ebf9134c.I3f1454498322ce28cb687d28c091c7ee092cefca@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index b6f82510e980..2cf3af284680 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -11,6 +11,7 @@ /* Highest firmware API version supported */ #define IWL_22000_UCODE_API_MAX 78 +#define IWL_22500_UCODE_API_MAX 77 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 @@ -222,7 +223,6 @@ static const struct iwl_ht_params iwl_gl_a_ht_params = { }; #define IWL_DEVICE_22000_COMMON \ - .ucode_api_max = IWL_22000_UCODE_API_MAX, \ .ucode_api_min = IWL_22000_UCODE_API_MIN, \ .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = 10, \ @@ -261,6 +261,7 @@ static const struct iwl_ht_params iwl_gl_a_ht_params = { #define IWL_DEVICE_22500 \ IWL_DEVICE_22000_COMMON, \ + .ucode_api_max = IWL_22500_UCODE_API_MAX, \ .trans.device_family = IWL_DEVICE_FAMILY_22000, \ .trans.base_params = &iwl_22000_base_params, \ .gp2_reg_addr = 0xa02c68, \ @@ -277,6 +278,7 @@ static const struct iwl_ht_params iwl_gl_a_ht_params = { #define IWL_DEVICE_AX210 \ IWL_DEVICE_22000_COMMON, \ + .ucode_api_max = IWL_22000_UCODE_API_MAX, \ .trans.umac_prph_offset = 0x300000, \ .trans.device_family = IWL_DEVICE_FAMILY_AX210, \ .trans.base_params = &iwl_ax210_base_params, \ @@ -1178,14 +1180,14 @@ const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = { .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; -MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QNJ_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QNJ_B_JF_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SO_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SO_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -- cgit v1.2.3 From d464550bb2e9cce2c377ed39c7e327e7db6e2be9 Mon Sep 17 00:00:00 2001 From: Yedidya Benshimol Date: Wed, 24 May 2023 20:41:59 +0300 Subject: wifi: iwlwifi: mvm: use link ID in missed beacon notification This new version of missed beacon notification uses link_id instead of mac_id. Also add an option to use link id for retrieving vif. Signed-off-by: Yedidya Benshimol Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.17fe1cc632f1.Id1fabb532e2174712fe17d4ad86a2c8c64ae84da@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/mac.h | 22 +++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/link.c | 5 ++++ drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 29 ++++++++++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 15 ++++++++++++ 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index e3eda251c728..c51c6c3a69ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -353,7 +353,7 @@ struct iwl_nonqos_seq_query_cmd { } __packed; /* NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */ /** - * struct iwl_missed_beacons_notif - information on missed beacons + * struct iwl_missed_beacons_notif_ver_3 - information on missed beacons * ( MISSED_BEACONS_NOTIFICATION = 0xa2 ) * @mac_id: interface ID * @consec_missed_beacons_since_last_rx: number of consecutive missed @@ -362,7 +362,7 @@ struct iwl_nonqos_seq_query_cmd { * @num_expected_beacons: number of expected beacons * @num_recvd_beacons: number of received beacons */ -struct iwl_missed_beacons_notif { +struct iwl_missed_beacons_notif_ver_3 { __le32 mac_id; __le32 consec_missed_beacons_since_last_rx; __le32 consec_missed_beacons; @@ -370,6 +370,24 @@ struct iwl_missed_beacons_notif { __le32 num_recvd_beacons; } __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ +/** + * struct iwl_missed_beacons_notif - information on missed beacons + * ( MISSED_BEACONS_NOTIFICATION = 0xa2 ) + * @link_id: fw link ID + * @consec_missed_beacons_since_last_rx: number of consecutive missed + * beacons since last RX. + * @consec_missed_beacons: number of consecutive missed beacons + * @num_expected_beacons: number of expected beacons + * @num_recvd_beacons: number of received beacons + */ +struct iwl_missed_beacons_notif { + __le32 link_id; + __le32 consec_missed_beacons_since_last_rx; + __le32 consec_missed_beacons; + __le32 num_expected_beacons; + __le32 num_recvd_beacons; +} __packed; /* MISSED_BEACON_NTFY_API_S_VER_4 */ + /** * struct iwl_he_backoff_conf - used for backoff configuration * Per each trigger-based AC, (set by MU EDCA Parameter set info-element) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index b35c96cf7ad2..08b1e15241ce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1591,6 +1591,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL); } + for (i = 0; i < IWL_MVM_FW_MAX_LINK_ID + 1; i++) + RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL); + memset(&mvm->fw_link_ids_map, 0, sizeof(mvm->fw_link_ids_map)); mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index eb828de40a3c..c94aca398789 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -63,6 +63,9 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmvif); if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) return -EINVAL; + + rcu_assign_pointer(mvm->link_id_to_link_conf[link_info->fw_link_id], + link_conf); } /* Update SF - Disable if needed. if this fails, SF might still be on @@ -260,6 +263,8 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)) return -EINVAL; + RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id], + NULL); cmd.link_id = cpu_to_le32(link_info->fw_link_id); iwl_mvm_release_fw_link_id(mvm, link_info->fw_link_id); link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index cc90f2884cff..0ecf4159e139 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1555,21 +1555,38 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, u32 stop_trig_missed_bcon, stop_trig_missed_bcon_since_rx; u32 rx_missed_bcon, rx_missed_bcon_since_rx; struct ieee80211_vif *vif; - u32 id = le32_to_cpu(mb->mac_id); + /* Id can be mac/link id depending on the notification version */ + u32 id = le32_to_cpu(mb->link_id); union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; u32 mac_type; + u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + MISSED_BEACONS_NOTIFICATION, + 0); + + rcu_read_lock(); + + /* before version four the ID in the notification refers to mac ID */ + if (notif_ver < 4) { + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); + } else { + struct ieee80211_bss_conf *bss_conf = + iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, true); + + if (!bss_conf) + goto out; + + vif = bss_conf->vif; + } IWL_DEBUG_INFO(mvm, - "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", - le32_to_cpu(mb->mac_id), + "missed bcn %s_id=%u, consecutive=%u (%u, %u, %u)\n", + notif_ver < 4 ? "mac" : "link", + id, le32_to_cpu(mb->consec_missed_beacons), le32_to_cpu(mb->consec_missed_beacons_since_last_rx), le32_to_cpu(mb->num_recvd_beacons), le32_to_cpu(mb->num_expected_beacons)); - rcu_read_lock(); - - vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); if (!vif) goto out; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 6e7470d3a826..b9975af671db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1003,6 +1003,8 @@ struct iwl_mvm { struct ieee80211_vif __rcu *vif_id_to_mac[NUM_MAC_INDEX_DRIVER]; + struct ieee80211_bss_conf __rcu *link_id_to_link_conf[IWL_MVM_FW_MAX_LINK_ID + 1]; + /* -1 for always, 0 for never, >0 for that many times */ s8 fw_restart; u8 *error_recovery_buf; @@ -1302,6 +1304,19 @@ iwl_mvm_rcu_dereference_vif_id(struct iwl_mvm *mvm, u8 vif_id, bool rcu) lockdep_is_held(&mvm->mutex)); } +static inline struct ieee80211_bss_conf * +iwl_mvm_rcu_fw_link_id_to_link_conf(struct iwl_mvm *mvm, u8 link_id, bool rcu) +{ + if (WARN_ON(link_id >= ARRAY_SIZE(mvm->link_id_to_link_conf))) + return NULL; + + if (rcu) + return rcu_dereference(mvm->link_id_to_link_conf[link_id]); + + return rcu_dereference_protected(mvm->link_id_to_link_conf[link_id], + lockdep_is_held(&mvm->mutex)); +} + static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, -- cgit v1.2.3 From a2906ea60a141e23d9ed635e6306d295d37427e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 May 2023 20:42:00 +0300 Subject: wifi: iwlwifi: mvm: make internal callback structs const There's no need for these to be writable, so they can be const (and static). Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.c41eb6687868.I2dac1158e5723187bda1973aa49fde8a794621c8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 28 +++++++++++----------- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 6 ++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 0f01b62357c6..5e28a53dad26 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3054,7 +3054,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u64 changes) { - struct iwl_mvm_bss_info_changed_ops callbacks = { + static const struct iwl_mvm_bss_info_changed_ops callbacks = { .bss_info_changed_sta = iwl_mvm_bss_info_changed_station, .bss_info_changed_ap_ibss = iwl_mvm_bss_info_changed_ap_ibss, }; @@ -3067,7 +3067,7 @@ void iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - struct iwl_mvm_bss_info_changed_ops *callbacks, + const struct iwl_mvm_bss_info_changed_ops *callbacks, u64 changes) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -3564,7 +3564,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { - struct iwl_mvm_sta_state_ops callbacks = { + static const struct iwl_mvm_sta_state_ops callbacks = { .add_sta = iwl_mvm_add_sta, .update_sta = iwl_mvm_update_sta, .rm_sta = iwl_mvm_rm_sta, @@ -3672,7 +3672,7 @@ static int iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); unsigned int i; @@ -3721,7 +3721,7 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw, struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); @@ -3778,7 +3778,7 @@ static int iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); @@ -3813,7 +3813,7 @@ static int iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -3851,7 +3851,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state, - struct iwl_mvm_sta_state_ops *callbacks) + const struct iwl_mvm_sta_state_ops *callbacks) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -4578,7 +4578,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, int duration, enum ieee80211_roc_type type) { - struct iwl_mvm_roc_ops ops = { + static const struct iwl_mvm_roc_ops ops = { .add_aux_sta_for_hs20 = iwl_mvm_add_aux_sta_for_hs20, .switch_phy_ctxt = iwl_mvm_roc_switch_binding, }; @@ -4590,7 +4590,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *channel, int duration, enum ieee80211_roc_type type, - struct iwl_mvm_roc_ops *ops) + const struct iwl_mvm_roc_ops *ops) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -5097,7 +5097,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, static int iwl_mvm_switch_vif_chanctx_swap(struct iwl_mvm *mvm, struct ieee80211_vif_chanctx_switch *vifs, - struct iwl_mvm_switch_vif_chanctx_ops *ops) + const struct iwl_mvm_switch_vif_chanctx_ops *ops) { int ret; @@ -5156,7 +5156,7 @@ out: static int iwl_mvm_switch_vif_chanctx_reassign(struct iwl_mvm *mvm, struct ieee80211_vif_chanctx_switch *vifs, - struct iwl_mvm_switch_vif_chanctx_ops *ops) + const struct iwl_mvm_switch_vif_chanctx_ops *ops) { int ret; @@ -5199,7 +5199,7 @@ iwl_mvm_switch_vif_chanctx_common(struct ieee80211_hw *hw, struct ieee80211_vif_chanctx_switch *vifs, int n_vifs, enum ieee80211_chanctx_switch_mode mode, - struct iwl_mvm_switch_vif_chanctx_ops *ops) + const struct iwl_mvm_switch_vif_chanctx_ops *ops) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; @@ -5228,7 +5228,7 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode) { - struct iwl_mvm_switch_vif_chanctx_ops ops = { + static const struct iwl_mvm_switch_vif_chanctx_ops ops = { .__assign_vif_chanctx = __iwl_mvm_assign_vif_chanctx, .__unassign_vif_chanctx = __iwl_mvm_unassign_vif_chanctx, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index fbc2d5ed1006..9dfb07db396e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -492,7 +492,7 @@ static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { - struct iwl_mvm_sta_state_ops callbacks = { + static const struct iwl_mvm_sta_state_ops callbacks = { .add_sta = iwl_mvm_mld_add_sta, .update_sta = iwl_mvm_mld_update_sta, .rm_sta = iwl_mvm_mld_rm_sta, @@ -779,7 +779,7 @@ iwl_mvm_mld_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode) { - struct iwl_mvm_switch_vif_chanctx_ops ops = { + static const struct iwl_mvm_switch_vif_chanctx_ops ops = { .__assign_vif_chanctx = __iwl_mvm_mld_assign_vif_chanctx, .__unassign_vif_chanctx = __iwl_mvm_mld_unassign_vif_chanctx, }; @@ -871,7 +871,7 @@ static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *channel, int duration, enum ieee80211_roc_type type) { - struct iwl_mvm_roc_ops ops = { + static const struct iwl_mvm_roc_ops ops = { .add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta, .switch_phy_ctxt = iwl_mvm_link_switch_phy_ctx, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b9975af671db..0f278a73a997 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1888,7 +1888,7 @@ void iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, - struct iwl_mvm_bss_info_changed_ops *callbacks, + const struct iwl_mvm_bss_info_changed_ops *callbacks, u64 changes); void iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm, @@ -1922,7 +1922,7 @@ struct iwl_mvm_roc_ops { int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *channel, int duration, enum ieee80211_roc_type type, - struct iwl_mvm_roc_ops *ops); + const struct iwl_mvm_roc_ops *ops); int iwl_mvm_cancel_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /*Session Protection */ @@ -2420,7 +2420,7 @@ iwl_mvm_switch_vif_chanctx_common(struct ieee80211_hw *hw, struct ieee80211_vif_chanctx_switch *vifs, int n_vifs, enum ieee80211_chanctx_switch_mode mode, - struct iwl_mvm_switch_vif_chanctx_ops *ops); + const struct iwl_mvm_switch_vif_chanctx_ops *ops); /* Channel info utils */ static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index a61d4f88125f..f5f8d41f5134 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -616,7 +616,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state, - struct iwl_mvm_sta_state_ops *callbacks); + const struct iwl_mvm_sta_state_ops *callbacks); /* New MLD STA related APIs */ /* STA */ -- cgit v1.2.3 From 1be4858ec43de04ef640022af6e6c9de40260ea4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 May 2023 20:42:01 +0300 Subject: wifi: iwlwifi: mvm: dissolve iwl_mvm_mac_add_interface_common() This wasn't really common anymore, so dissolve it, it has a pretty strange calling convention that's confusing. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.44320ab2e842.Ie1d6b9c28caca3b541ca383a4c0c8799b0e72fe0@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 90 ++++++++++------------- 1 file changed, 37 insertions(+), 53 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5e28a53dad26..cac4aa062cd4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1478,21 +1478,37 @@ iwl_mvm_chandef_get_primary_80(struct cfg80211_chan_def *chandef) return (control_start - data_start) / 80; } -/* - * Returns true if addding the interface is done - * (either with success or failure) - * - * FIXME: remove this again and merge it in - */ -static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm, - struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - int *ret) +static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ret; lockdep_assert_held(&mvm->mutex); + ret = iwl_mvm_alloc_bcast_sta(mvm, vif); + if (ret) { + IWL_ERR(mvm, "Failed to allocate bcast sta\n"); + return ret; + } + + /* Only queue for this station is the mcast queue, + * which shouldn't be in TFD mask anyway + */ + return iwl_mvm_allocate_int_sta(mvm, &mvmvif->deflink.mcast_sta, 0, + vif->type, + IWL_STA_MULTICAST); +} + +static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int ret; + + mutex_lock(&mvm->mutex); + mvmvif->mvm = mvm; /* the first link always points to the default one */ @@ -1510,12 +1526,18 @@ static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm, mvmvif->deflink.beacon_stats.num_beacons; /* Allocate resources for the MAC context, and add it to the fw */ - *ret = iwl_mvm_mac_ctxt_init(mvm, vif); - if (*ret) - return true; + ret = iwl_mvm_mac_ctxt_init(mvm, vif); + if (ret) + goto out; rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif); + /* Currently not much to do for NAN */ + if (vif->type == NL80211_IFTYPE_NAN) { + ret = 0; + goto out; + } + /* * The AP binding flow can be done only after the beacon * template is configured (which happens only in the mac80211 @@ -1530,50 +1552,12 @@ static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm, if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) { iwl_mvm_vif_dbgfs_register(mvm, vif); - return true; + ret = 0; + goto out; } mvmvif->features |= hw->netdev_features; - return false; -} - -static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_mvm_alloc_bcast_sta(mvm, vif); - if (ret) { - IWL_ERR(mvm, "Failed to allocate bcast sta\n"); - return ret; - } - - /* - * Only queue for this station is the mcast queue, - * which shouldn't be in TFD mask anyway - */ - return iwl_mvm_allocate_int_sta(mvm, &mvmvif->deflink.mcast_sta, 0, - vif->type, - IWL_STA_MULTICAST); -} - -static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int ret; - - mutex_lock(&mvm->mutex); - - /* Common for MLD and non-MLD API */ - if (iwl_mvm_mac_add_interface_common(mvm, hw, vif, &ret)) - goto out; - ret = iwl_mvm_mac_ctxt_add(mvm, vif); if (ret) goto out_unlock; -- cgit v1.2.3 From 0945f9762ec3766186a179f7ccd001a3e160e3a0 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 24 May 2023 20:42:02 +0300 Subject: wifi: iwlwifi: mvm: support PASN for MLO When adding a PASN station, the non MLD API was used. This results in assert when operating as MLD. Fix it to use the MLD API when operating as MLD. For now, the default link is used for the added station. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.7c35dccc8a12.I7bc78cd16d7c750f42fdd60e07e839a860d279d2@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 27 ++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 10 +++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++++ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 39 +++++++++++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 5 +++ 5 files changed, 65 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index 8853821b3716..3e6f86f644b5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -51,10 +51,10 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm, return iwl_mvm_sta_fw_id_mask(mvm, sta, keyconf->link_id); } -static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *keyconf) +u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *keyconf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); u32 flags = 0; @@ -164,13 +164,9 @@ static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask, return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd); } -int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *keyconf) +int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags, + struct ieee80211_key_conf *keyconf) { - u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); - u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); struct iwl_sec_key_cmd cmd = { .action = cpu_to_le32(FW_CTXT_ACTION_ADD), @@ -223,6 +219,17 @@ int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, return ret; } +int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *keyconf) +{ + u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); + u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); + + return iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf); +} + static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index 0bfdf4462755..401f94bd1f9c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -128,11 +128,11 @@ static int iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm *mvm, /* * Adds an internal sta to the FW table with its queues */ -static int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *sta, - const u8 *addr, int link_id, - u16 *queue, u8 tid, - unsigned int *_wdg_timeout) +int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + const u8 *addr, int link_id, + u16 *queue, u8 tid, + unsigned int *_wdg_timeout) { int ret, txq; unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout : diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 0f278a73a997..5f7469cfd092 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2361,6 +2361,12 @@ int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm, struct ieee80211_sta *sta, u32 old_sta_mask, u32 new_sta_mask); +int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags, + struct ieee80211_key_conf *keyconf); +u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *keyconf); int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm, struct iwl_rfi_lut_entry *rfi_table); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 5469d634e289..afccbd916a65 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -4301,16 +4301,27 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u16 queue; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_key_conf *keyconf; + unsigned int wdg_timeout = + iwl_mvm_get_wd_timeout(mvm, vif, false, false); + bool mld = iwl_mvm_has_mld_api(mvm->fw); + u32 type = mld ? STATION_TYPE_PEER : IWL_STA_LINK; ret = iwl_mvm_allocate_int_sta(mvm, sta, 0, - NL80211_IFTYPE_UNSPECIFIED, - IWL_STA_LINK); + NL80211_IFTYPE_UNSPECIFIED, type); if (ret) return ret; - ret = iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id, mvmvif->color, - addr, sta, &queue, - IWL_MVM_TX_FIFO_BE); + if (mld) + ret = iwl_mvm_mld_add_int_sta_with_queue(mvm, sta, addr, + mvmvif->deflink.fw_link_id, + &queue, + IWL_MAX_TID_COUNT, + &wdg_timeout); + else + ret = iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id, + mvmvif->color, addr, sta, + &queue, + IWL_MVM_TX_FIFO_BE); if (ret) goto out; @@ -4323,9 +4334,23 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, keyconf->cipher = cipher; memcpy(keyconf->key, key, key_len); keyconf->keylen = key_len; + keyconf->flags = IEEE80211_KEY_FLAG_PAIRWISE; + + if (mld) { + /* The MFP flag is set according to the station mfp field. Since + * we don't have a station, set it manually. + */ + u32 key_flags = + iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) | + IWL_SEC_KEY_FLAG_MFP; + u32 sta_mask = BIT(sta->sta_id); + + ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf); + } else { + ret = iwl_mvm_send_sta_key(mvm, sta->sta_id, keyconf, false, + 0, NULL, 0, 0, true); + } - ret = iwl_mvm_send_sta_key(mvm, sta->sta_id, keyconf, false, - 0, NULL, 0, 0, true); kfree(keyconf); return 0; out: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index f5f8d41f5134..e396034b8795 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -646,6 +646,11 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm, u16 old_links, u16 new_links); u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int filter_link_id); +int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + const u8 *addr, int link_id, + u16 *queue, u8 tid, + unsigned int *_wdg_timeout); /* Queues */ void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm, -- cgit v1.2.3 From cad7850ac0f597cd462b263a6395c5cd0ad8e760 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Wed, 24 May 2023 20:42:03 +0300 Subject: wifi: iwlwifi: don't silently ignore missing suspend or resume ops In case the driver doesn't implement suspend or resume operations on the transport layer, notify the driver's upper layer. Otherwise, we might access d3_status uninitialized. Signed-off-by: Haim Dreyfuss Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.0c55e0ca92f1.I6870fe1683215e65d3d036f9b576b03b7b7257be@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 9f1228b5a384..885581e636c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1160,7 +1160,7 @@ static inline int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, { might_sleep(); if (!trans->ops->d3_suspend) - return 0; + return -EOPNOTSUPP; return trans->ops->d3_suspend(trans, test, reset); } @@ -1171,7 +1171,7 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans, { might_sleep(); if (!trans->ops->d3_resume) - return 0; + return -EOPNOTSUPP; return trans->ops->d3_resume(trans, status, test, reset); } -- cgit v1.2.3 From cec74584dc19a604c39a9b77a819b35e684e6e4c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 24 May 2023 20:42:04 +0300 Subject: wifi: iwlwifi: mvm: Make iwl_mvm_diversity_iter() MLO aware This function is MLO related, so it should iterate over all the links, and not only on deflink. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.56a9c709e987.I9716195ec288cce2c929338c254ee9add8cfcc1f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index af31b09c3966..2a10d851d2e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -413,16 +413,20 @@ static void iwl_mvm_diversity_iter(void *_data, u8 *mac, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_diversity_iter_data *data = _data; - int i; + int i, link_id; - if (mvmvif->deflink.phy_ctxt != data->ctxt) - return; + for_each_mvm_vif_valid_link(mvmvif, link_id) { + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; - for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { - if (mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_STATIC || - mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_DYNAMIC) { - data->result = false; - break; + if (link_info->phy_ctxt != data->ctxt) + continue; + + for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { + if (link_info->smps_requests[i] == IEEE80211_SMPS_STATIC || + link_info->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) { + data->result = false; + break; + } } } } -- cgit v1.2.3 From 3f3022694f62476df562244ee2a72819e98eec89 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 24 May 2023 20:42:05 +0300 Subject: wifi: iwlwifi: mvm: update the FW apis for LINK and MAC commands The firmware added new fields to be able to pass the link_id as the AP knows it and the esr_transition_timeout. For now, pass only the link_id since we don't have access to the esr_transition_timeout yet. Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.bf80ce717458.Icd4174911227c00cd12783fe1f517ae8097809b9@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 29 ++++++++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/link.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 14 +++++------ drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c | 10 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 +-- 5 files changed, 37 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index 74f2efbad34e..edf9ac52a681 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -211,17 +211,30 @@ struct iwl_mac_low_latency_cmd { * struct iwl_mac_client_data - configuration data for client MAC context * * @is_assoc: 1 for associated state, 0 otherwise + * @esr_transition_timeout: the timeout required by the AP for the + * eSR transition. + * Available only from version 2 of the command. + * This values comes from the EMLSR transition delay in the EML + * Capabilities subfield. + * @reserved: alignment * @assoc_id: unique ID assigned by the AP during association + * @reserved1: alignment * @data_policy: see &enum iwl_mac_data_policy + * @reserved2: alignment * @ctwin: client traffic window in TU (period after TBTT when GO is present). * 0 indicates that there is no CT window. */ struct iwl_mac_client_data { - __le32 is_assoc; - __le32 assoc_id; - __le32 data_policy; + u8 is_assoc; + u8 esr_transition_timeout; + __le16 reserved; + + __le16 assoc_id; + __le16 reserved1; + __le16 data_policy; + __le16 reserved2; __le32 ctwin; -} __packed; /* MAC_CONTEXT_CONFIG_CLIENT_DATA_API_S_VER_1 */ +} __packed; /* MAC_CONTEXT_CONFIG_CLIENT_DATA_API_S_VER_2 */ /** * struct iwl_mac_p2p_dev_data - configuration data for P2P device MAC context @@ -292,12 +305,12 @@ struct iwl_mac_config_cmd { __le16 he_ap_support; __le32 eht_support; __le32 nic_not_ack_enabled; - /* MAC_CONTEXT_CONFIG_SPECIFIC_DATA_API_U_VER_1 */ + /* MAC_CONTEXT_CONFIG_SPECIFIC_DATA_API_U_VER_2 */ union { struct iwl_mac_client_data client; struct iwl_mac_p2p_dev_data p2p_dev; }; -} __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_1 */ +} __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_2 */ /** * enum iwl_link_ctx_modify_flags - indicate to the fw what fields are being @@ -430,6 +443,7 @@ enum iwl_link_ctx_flags { * @reserved_for_ref_bssid_addr: reserved * @bssid_index: index of the associated VAP * @bss_color: 11ax AP ID that is used in the HE SIG-A to mark inter BSS frame + * @spec_link_id: link_id as the AP knows it * @reserved: alignment * @ibss_bssid_addr: bssid for ibss * @reserved_for_ibss_bssid_addr: reserved @@ -469,7 +483,8 @@ struct iwl_link_config_cmd { __le16 reserved_for_ref_bssid_addr; u8 bssid_index; u8 bss_color; - u8 reserved[2]; + u8 spec_link_id; + u8 reserved; u8 ibss_bssid_addr[6]; __le16 reserved_for_ibss_bssid_addr; __le32 reserved1[8]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index c94aca398789..a1d31c6eab2c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -76,6 +76,7 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd.link_id = cpu_to_le32(link_info->fw_link_id); cmd.mac_id = cpu_to_le32(mvmvif->id); + cmd.spec_link_id = link_conf->link_id; /* P2P-Device already has a valid PHY context during add */ phyctxt = link_info->phy_ctxt; if (phyctxt) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 0ecf4159e139..f049ef6a8707 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -629,17 +629,17 @@ __le32 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(struct iwl_mvm *mvm, IEEE80211_P2P_OPPPS_CTWINDOW_MASK); } -__le32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +u32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { - __le32 twt_policy = cpu_to_le32(0); + u32 twt_policy = 0; if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT) - twt_policy |= cpu_to_le32(TWT_SUPPORTED); + twt_policy |= TWT_SUPPORTED; if (vif->bss_conf.twt_protected) - twt_policy |= cpu_to_le32(PROTECTED_TWT_SUPPORTED); + twt_policy |= PROTECTED_TWT_SUPPORTED; if (vif->bss_conf.twt_broadcast) - twt_policy |= cpu_to_le32(BROADCAST_TWT_SUPPORTED); + twt_policy |= BROADCAST_TWT_SUPPORTED; return twt_policy; } @@ -711,7 +711,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) { cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX); ctxt_sta->data_policy |= - iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif); + cpu_to_le32(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif)); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 1717fb52dc12..99bf71a2b690 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -115,16 +115,16 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, if (vif->cfg.assoc && !force_assoc_off) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - cmd.client.is_assoc = cpu_to_le32(1); + cmd.client.is_assoc = 1; if (!mvmvif->authorized && fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO)) cmd.client.data_policy |= - cpu_to_le32(COEX_HIGH_PRIORITY_ENABLE); + cpu_to_le16(COEX_HIGH_PRIORITY_ENABLE); } else { - cmd.client.is_assoc = cpu_to_le32(0); + cmd.client.is_assoc = 0; /* Allow beacons to pass through as long as we are not * associated, or we do not have dtim period information. @@ -132,14 +132,14 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON); } - cmd.client.assoc_id = cpu_to_le32(vif->cfg.aid); + cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid); if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p) cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ); if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) cmd.client.data_policy |= - iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif); + cpu_to_le16(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif)); return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 5f7469cfd092..bba3acd64131 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1789,8 +1789,8 @@ void iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(struct iwl_mvm *mvm, int iwl_mvm_get_mac_type(struct ieee80211_vif *vif); __le32 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -__le32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); +u32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool force_assoc_off); -- cgit v1.2.3 From fa53608b525fa8d32770783f4f9e59eafd905cc4 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 24 May 2023 20:42:06 +0300 Subject: wifi: iwlwifi: mvm: adjust csa notifications and commands to MLO In the following notifications and commands mac_id was replaced with link_id: * CANCEL_CHANNEL_SWITCH_CMD * CHANNEL_SWITCH_START_NOTIF * CHANNEL_SWITCH_ERROR_NOTIF The logic around was not changed, so only adjust handling mac/link id. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.6aa6e394f5fe.Ie9e78918511ca901f9f3966d774fa74a71a186e3@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 30 ++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 51 ++++++++++++++++------ drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 +- 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index edf9ac52a681..b4244fa0516b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -140,33 +140,53 @@ struct iwl_missed_vap_notif { * * @id_and_color: ID and color of the MAC */ -struct iwl_channel_switch_start_notif { +struct iwl_channel_switch_start_notif_v1 { __le32 id_and_color; } __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */ +/** + * struct iwl_channel_switch_start_notif - Channel switch start notification + * + * @link_id: FW link id + */ +struct iwl_channel_switch_start_notif { + __le32 link_id; +} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_3 */ + #define CS_ERR_COUNT_ERROR BIT(0) #define CS_ERR_LONG_DELAY_AFTER_CS BIT(1) #define CS_ERR_LONG_TX_BLOCK BIT(2) #define CS_ERR_TX_BLOCK_TIMER_EXPIRED BIT(3) /** - * struct iwl_channel_switch_error_notif - Channel switch error notification + * struct iwl_channel_switch_error_notif_v1 - Channel switch error notification * * @mac_id: the mac for which the ucode sends the notification for * @csa_err_mask: mask of channel switch error that can occur */ -struct iwl_channel_switch_error_notif { +struct iwl_channel_switch_error_notif_v1 { __le32 mac_id; __le32 csa_err_mask; } __packed; /* CHANNEL_SWITCH_ERROR_NTFY_API_S_VER_1 */ +/** + * struct iwl_channel_switch_error_notif - Channel switch error notification + * + * @link_id: FW link id + * @csa_err_mask: mask of channel switch error that can occur + */ +struct iwl_channel_switch_error_notif { + __le32 link_id; + __le32 csa_err_mask; +} __packed; /* CHANNEL_SWITCH_ERROR_NTFY_API_S_VER_2 */ + /** * struct iwl_cancel_channel_switch_cmd - Cancel Channel Switch command * - * @mac_id: the mac that should cancel the channel switch + * @id: the id of the link or mac that should cancel the channel switch */ struct iwl_cancel_channel_switch_cmd { - __le32 mac_id; + __le32 id; } __packed; /* MAC_CANCEL_CHANNEL_SWITCH_S_VER_1 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index f049ef6a8707..059ede6f7b65 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1747,20 +1747,44 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_channel_switch_start_notif *notif = (void *)pkt->data; struct ieee80211_vif *csa_vif, *vif; - struct iwl_mvm_vif *mvmvif; - u32 id_n_color, csa_id, mac_id; + struct iwl_mvm_vif *mvmvif, *csa_mvmvif; + u32 id_n_color, csa_id; + /* save mac_id or link_id to use later to cancel csa if needed */ + u32 id; + u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, + CHANNEL_SWITCH_START_NOTIF, 0); - id_n_color = le32_to_cpu(notif->id_and_color); - mac_id = id_n_color & FW_CTXT_ID_MSK; + rcu_read_lock(); - if (WARN_ON_ONCE(mac_id >= NUM_MAC_INDEX_DRIVER)) - return; + if (notif_ver < 3) { + struct iwl_channel_switch_start_notif_v1 *notif = (void *)pkt->data; + u32 mac_id; + + id_n_color = le32_to_cpu(notif->id_and_color); + mac_id = id_n_color & FW_CTXT_ID_MSK; + + vif = iwl_mvm_rcu_dereference_vif_id(mvm, mac_id, true); + if (!vif) + goto out_unlock; + + id = mac_id; + } else { + struct iwl_channel_switch_start_notif *notif = (void *)pkt->data; + u32 link_id = le32_to_cpu(notif->link_id); + struct ieee80211_bss_conf *bss_conf = + iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, link_id, true); + + if (!bss_conf) + goto out_unlock; + + id = link_id; + vif = bss_conf->vif; + } - rcu_read_lock(); - vif = rcu_dereference(mvm->vif_id_to_mac[mac_id]); mvmvif = iwl_mvm_vif_from_mac80211(vif); + if (notif_ver >= 3) + id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); switch (vif->type) { case NL80211_IFTYPE_AP: @@ -1769,7 +1793,8 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, csa_vif != vif)) goto out_unlock; - csa_id = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); + csa_mvmvif = iwl_mvm_vif_from_mac80211(csa_vif); + csa_id = FW_CMD_ID_AND_COLOR(csa_mvmvif->id, csa_mvmvif->color); if (WARN(csa_id != id_n_color, "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)", csa_id, id_n_color)) @@ -1796,7 +1821,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, CHANNEL_SWITCH_ERROR_NOTIF, 0) && !vif->bss_conf.csa_active) { IWL_DEBUG_INFO(mvm, "Channel Switch was canceled\n"); - iwl_mvm_cancel_channel_switch(mvm, vif, mac_id); + iwl_mvm_cancel_channel_switch(mvm, vif, id); break; } @@ -1819,7 +1844,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_channel_switch_error_notif *notif = (void *)pkt->data; struct ieee80211_vif *vif; - u32 id = le32_to_cpu(notif->mac_id); + u32 id = le32_to_cpu(notif->link_id); u32 csa_err_mask = le32_to_cpu(notif->csa_err_mask); rcu_read_lock(); @@ -1829,7 +1854,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, return; } - IWL_DEBUG_INFO(mvm, "FW reports CSA error: mac_id=%u, csa_err_mask=%u\n", + IWL_DEBUG_INFO(mvm, "FW reports CSA error: id=%u, csa_err_mask=%u\n", id, csa_err_mask); if (csa_err_mask & (CS_ERR_COUNT_ERROR | CS_ERR_LONG_DELAY_AFTER_CS | diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index afccbd916a65..4e3f994654c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -4360,10 +4360,10 @@ out: void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 mac_id) + u32 id) { struct iwl_cancel_channel_switch_cmd cancel_channel_switch_cmd = { - .mac_id = cpu_to_le32(mac_id), + .id = cpu_to_le32(id), }; int ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index e396034b8795..9acc01b7a4c9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -365,6 +365,7 @@ struct iwl_mvm_link_sta { * and from Tx response flow, it needs a spinlock. * @tid_data: per tid data + mgmt. Look at %iwl_mvm_tid_data. * @tid_to_baid: a simple map of TID to baid + * @vif: a vif pointer * @reserved_queue: the queue reserved for this STA for DQA purposes * Every STA has is given one reserved queue to allow it to operate. If no * such queue can be guaranteed, the STA addition will fail. @@ -378,6 +379,7 @@ struct iwl_mvm_link_sta { * debugfs. If it's set to 0, it means that it is it's not set via * debugfs. * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON) + * @sleeping: sta sleep transitions in power management * @sleep_tx_count: the number of frames that we told the firmware to let out * even when that station is asleep. This is useful in case the queue * gets empty before all the frames were sent, which can happen when @@ -580,7 +582,7 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u8 *key, u32 key_len); void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 mac_id); + u32 id); /* Queues */ int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta, -- cgit v1.2.3 From 58e682768938cd8e8cd9fbd46adcbdb9afa4cee4 Mon Sep 17 00:00:00 2001 From: Ariel Malamud Date: Wed, 24 May 2023 20:42:07 +0300 Subject: wifi: iwlwifi: fw: Add new ODM vendor to ppag approved list Add new oem/odm pair to ppag approved vendors list when specified by platform. Signed-off-by: Ariel Malamud Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.549a57a1cf11.I7392b1cd31f4f7ee60aafe2093f4e82b1d6fd3a7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 5f4a51310add..9dfd2497d495 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -41,6 +41,12 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek COMPUTER INC."), }, }, + { .ident = "GOOGLE-HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), + }, + }, {} }; -- cgit v1.2.3 From dbb6f2307b84e8aaaa60f7ba0b17cb1a333e2216 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 24 May 2023 20:42:08 +0300 Subject: wifi: iwlwifi: disable RX STBC when a device doesn't support it Some devices, like step A0 of GL FM device doesn't support RX STBC for VHT/HE. Add a workaround to remove it from capabilities in this case. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.65c3e09813e5.Iadfd8cdb0ea5a8088ae3daa555c780c423951894@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 7dcb1c3ab728..cf19e8a561e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -464,6 +464,9 @@ static void iwl_init_vht_hw_capab(struct iwl_trans *trans, IEEE80211_VHT_MAX_AMPDU_1024K << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; + if (!trans->cfg->ht_params->stbc) + vht_cap->cap &= ~IEEE80211_VHT_CAP_RXSTBC_MASK; + if (data->vht160_supported) vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | IEEE80211_VHT_CAP_SHORT_GI_160; @@ -986,6 +989,13 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, iftype_data->vendor_elems.data = iwl_vendor_caps; iftype_data->vendor_elems.len = ARRAY_SIZE(iwl_vendor_caps); } + + if (!trans->cfg->ht_params->stbc) { + iftype_data->he_cap.he_cap_elem.phy_cap_info[2] &= + ~IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; + iftype_data->he_cap.he_cap_elem.phy_cap_info[7] &= + ~IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; + } } static void iwl_init_he_hw_capab(struct iwl_trans *trans, -- cgit v1.2.3 From 8dd1039f8fab9ed9514d601be5988aa72ab2c077 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 24 May 2023 20:42:09 +0300 Subject: wifi: iwlwifi: mvm: remove useless code Setting the station to -EBUSY was originally done under this lock, and the comment still refers to it. But this no longer happens because that was removed when DQA was removed. Remove the leftover code as well. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.30048b1cd0fd.Ie2c2ff6fd7c6e3ebf5b736de350dc15515970792@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 4e3f994654c9..931562bb5bd2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2070,13 +2070,6 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cancel_delayed_work(&mvm->tdls_cs.dwork); } - /* - * Make sure that the tx response code sees the station as -EBUSY and - * calls the drain worker. - */ - spin_lock_bh(&mvm_sta->lock); - spin_unlock_bh(&mvm_sta->lock); - return false; } -- cgit v1.2.3 From 5cd4ef0d02737f3e8372cb388e7da78f1238782e Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Wed, 24 May 2023 20:42:10 +0300 Subject: wifi: iwlwifi: support PPAG in China for older FW cmd version Allows the China bit in the ppag flags to turn on also when FW cmd version is 1 (if FW has the capability). Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.3cc19e799eeb.I9054b1d63fd7ae2b5f0e416825b4b1dc9f79cc80@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 10 +++++++++- drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 9dfd2497d495..e6abd16f8677 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -1155,7 +1155,15 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c IWL_DEBUG_RADIO(fwrt, "PPAG table rev is %d but FW supports v1, sending truncated table\n", fwrt->ppag_ver); - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); + if (!fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) { + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); + IWL_DEBUG_RADIO(fwrt, + "FW doesn't support ppag China bit\n"); + } else { + IWL_DEBUG_RADIO(fwrt, + "FW supports ppag China bit\n"); + } } } else if (cmd_ver >= 2 && cmd_ver <= 4) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index cddf09d6be1c..ef2ff7517534 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -462,6 +462,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT = (__force iwl_ucode_tlv_capa_t)109, IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT = (__force iwl_ucode_tlv_capa_t)110, IWL_UCODE_TLV_CAPA_SCAN_DONT_TOGGLE_ANT = (__force iwl_ucode_tlv_capa_t)111, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT = (__force iwl_ucode_tlv_capa_t)112, #ifdef __CHECKER__ /* sparse says it cannot increment the previous enum member */ -- cgit v1.2.3 From 8d2b2281aea90ab265733c3cda83b73a01ca352f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 4 Jun 2023 16:28:58 +0300 Subject: mac_pton: Clean up the header inclusions Since hex_to_bin() is provided by hex.h there is no need to require kernel.h. Replace the latter by the former and add missing export.h. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230604132858.6650-1-andriy.shevchenko@linux.intel.com Signed-off-by: Paolo Abeni --- lib/net_utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/net_utils.c b/lib/net_utils.c index c17201df3d08..42bb0473fb22 100644 --- a/lib/net_utils.c +++ b/lib/net_utils.c @@ -2,7 +2,8 @@ #include #include #include -#include +#include +#include bool mac_pton(const char *s, u8 *mac) { -- cgit v1.2.3 From ae91f7e436f8b631c47e244b892ecac62a4d9430 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Mon, 5 Jun 2023 09:27:43 +0200 Subject: net/pppoe: fix a typo for the PPPOE_HASH_BITS_1 definition Instead of its intention to define PPPOE_HASH_BITS_1, commit 96ba44c637b0 ("net/pppoe: make number of hash bits configurable") actually defined config PPPOE_HASH_BITS_2 twice in the ppp's Kconfig file due to a quick typo with the numbers. Fix the typo and define PPPOE_HASH_BITS_1. Fixes: 96ba44c637b0 ("net/pppoe: make number of hash bits configurable") Signed-off-by: Lukas Bulwahn Reviewed-by: Simon Horman Reviewed-by: Jaco Kroon Link: https://lore.kernel.org/r/20230605072743.11247-1-lukas.bulwahn@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/ppp/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ppp/Kconfig b/drivers/net/ppp/Kconfig index 2fbcae31fc02..8c9ed1889d1a 100644 --- a/drivers/net/ppp/Kconfig +++ b/drivers/net/ppp/Kconfig @@ -141,7 +141,7 @@ choice This hash table is on a per outer ethernet interface. -config PPPOE_HASH_BITS_2 +config PPPOE_HASH_BITS_1 bool "1 bit (2 buckets)" config PPPOE_HASH_BITS_2 -- cgit v1.2.3 From b70813e4a88f231f1dc76fedbbd24ce4961b9a85 Mon Sep 17 00:00:00 2001 From: Abhishek Naik Date: Wed, 24 May 2023 20:42:11 +0300 Subject: wifi: iwlwifi: update response for mcc_update command Add support for the MCC update response version 8. Versions 5-6 are already covered by the existing flags conversion, and 7 isn't used. The capabilities field in iwl_mcc_update_resp is 32 bits wide now, and the flags moved, so some more changes are needed. While at it, convert the flags to bool (to avoid having to deal with BIT(16) specially etc.) and use the struct_size() macro for the memory allocation. Signed-off-by: Abhishek Naik Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230524203151.fd9016f8f994.Ibddcb9fbfa74895f742c0ac20968720691c94853@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 35 +++++- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 117 ++++++++++++++------- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 58 +++++++--- 6 files changed, 161 insertions(+), 59 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 91bfde6d5367..635e4ddfbca6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -317,7 +317,7 @@ struct iwl_mcc_update_resp_v3 { } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ /** - * struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD. + * struct iwl_mcc_update_resp_v4 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. @@ -333,7 +333,7 @@ struct iwl_mcc_update_resp_v3 { * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ -struct iwl_mcc_update_resp { +struct iwl_mcc_update_resp_v4 { __le32 status; __le16 mcc; __le16 cap; @@ -345,6 +345,37 @@ struct iwl_mcc_update_resp { __le32 channels[]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */ +/** + * struct iwl_mcc_update_resp_v8 - response to MCC_UPDATE_CMD. + * Contains the new channel control profile map, if changed, and the new MCC + * (mobile country code). + * The new MCC may be different than what was requested in MCC_UPDATE_CMD. + * @status: see &enum iwl_mcc_update_status + * @mcc: the new applied MCC + * @padding: padding for 2 bytes. + * @cap: capabilities for all channels which matches the MCC + * @time: time elapsed from the MCC test start (in units of 30 seconds) + * @geo_info: geographic specific profile information + * see &enum iwl_geo_information. + * @source_id: the MCC source, see iwl_mcc_source + * @reserved: for four bytes alignment. + * @n_channels: number of channels in @channels_data. + * @channels: channel control data map, DWORD for each channel. Only the first + * 16bits are used. + */ +struct iwl_mcc_update_resp_v8 { + __le32 status; + __le16 mcc; + u8 padding[2]; + __le32 cap; + __le16 time; + __le16 geo_info; + u8 source_id; + u8 reserved[3]; + __le32 n_channels; + __le32 channels[]; +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_8 */ + /** * struct iwl_mcc_chub_notif - chub notifies of mcc change * (MCC_CHUB_UPDATE_CMD = 0xc9) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index cf19e8a561e9..7edb98ef8093 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -173,34 +173,34 @@ enum iwl_nvm_channel_flags { }; /** - * enum iwl_reg_capa_flags - global flags applied for the whole regulatory + * enum iwl_reg_capa_flags_v1 - global flags applied for the whole regulatory * domain. - * @REG_CAPA_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the + * @REG_CAPA_V1_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the * 2.4Ghz band is allowed. - * @REG_CAPA_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the + * @REG_CAPA_V1_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the * 5Ghz band is allowed. - * @REG_CAPA_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed + * @REG_CAPA_V1_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed + * @REG_CAPA_V1_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. - * @REG_CAPA_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. - * @REG_CAPA_40MHZ_FORBIDDEN: 11n channel with a width of 40Mhz is forbidden + * @REG_CAPA_V1_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. + * @REG_CAPA_V1_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. + * @REG_CAPA_V1_40MHZ_FORBIDDEN: 11n channel with a width of 40Mhz is forbidden * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_DC_HIGH_ENABLED: DC HIGH allowed. - * @REG_CAPA_11AX_DISABLED: 11ax is forbidden for this regulatory domain. + * @REG_CAPA_V1_DC_HIGH_ENABLED: DC HIGH allowed. + * @REG_CAPA_V1_11AX_DISABLED: 11ax is forbidden for this regulatory domain. */ -enum iwl_reg_capa_flags { - REG_CAPA_BF_CCD_LOW_BAND = BIT(0), - REG_CAPA_BF_CCD_HIGH_BAND = BIT(1), - REG_CAPA_160MHZ_ALLOWED = BIT(2), - REG_CAPA_80MHZ_ALLOWED = BIT(3), - REG_CAPA_MCS_8_ALLOWED = BIT(4), - REG_CAPA_MCS_9_ALLOWED = BIT(5), - REG_CAPA_40MHZ_FORBIDDEN = BIT(7), - REG_CAPA_DC_HIGH_ENABLED = BIT(9), - REG_CAPA_11AX_DISABLED = BIT(10), -}; +enum iwl_reg_capa_flags_v1 { + REG_CAPA_V1_BF_CCD_LOW_BAND = BIT(0), + REG_CAPA_V1_BF_CCD_HIGH_BAND = BIT(1), + REG_CAPA_V1_160MHZ_ALLOWED = BIT(2), + REG_CAPA_V1_80MHZ_ALLOWED = BIT(3), + REG_CAPA_V1_MCS_8_ALLOWED = BIT(4), + REG_CAPA_V1_MCS_9_ALLOWED = BIT(5), + REG_CAPA_V1_40MHZ_FORBIDDEN = BIT(7), + REG_CAPA_V1_DC_HIGH_ENABLED = BIT(9), + REG_CAPA_V1_11AX_DISABLED = BIT(10), +}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_1 */ /** * enum iwl_reg_capa_flags_v2 - global flags applied for the whole regulatory @@ -234,7 +234,31 @@ enum iwl_reg_capa_flags_v2 { REG_CAPA_V2_WEATHER_DISABLED = BIT(7), REG_CAPA_V2_40MHZ_ALLOWED = BIT(8), REG_CAPA_V2_11AX_DISABLED = BIT(10), -}; +}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_2 */ + +/** + * enum iwl_reg_capa_flags_v4 - global flags applied for the whole regulatory + * domain. + * @REG_CAPA_V4_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed + * for this regulatory domain (valid only in 5Ghz). + * @REG_CAPA_V4_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed + * for this regulatory domain (valid only in 5Ghz). + * @REG_CAPA_V4_MCS_12_ALLOWED: 11ac with MCS 12 is allowed. + * @REG_CAPA_V4_MCS_13_ALLOWED: 11ac with MCS 13 is allowed. + * @REG_CAPA_V4_11BE_DISABLED: 11be is forbidden for this regulatory domain. + * @REG_CAPA_V4_11AX_DISABLED: 11ax is forbidden for this regulatory domain. + * @REG_CAPA_V4_320MHZ_ALLOWED: 11be channel with a width of 320Mhz is allowed + * for this regulatory domain (valid only in 5GHz). + */ +enum iwl_reg_capa_flags_v4 { + REG_CAPA_V4_160MHZ_ALLOWED = BIT(3), + REG_CAPA_V4_80MHZ_ALLOWED = BIT(4), + REG_CAPA_V4_MCS_12_ALLOWED = BIT(5), + REG_CAPA_V4_MCS_13_ALLOWED = BIT(6), + REG_CAPA_V4_11BE_DISABLED = BIT(8), + REG_CAPA_V4_11AX_DISABLED = BIT(13), + REG_CAPA_V4_320MHZ_ALLOWED = BIT(16), +}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_4 */ /* * API v2 for reg_capa_flags is relevant from version 6 and onwards of the @@ -242,23 +266,33 @@ enum iwl_reg_capa_flags_v2 { */ #define REG_CAPA_V2_RESP_VER 6 +/* API v4 for reg_capa_flags is relevant from version 8 and onwards of the + * MCC update command response. + */ +#define REG_CAPA_V4_RESP_VER 8 + /** * struct iwl_reg_capa - struct for global regulatory capabilities, Used for * handling the different APIs of reg_capa_flags. * * @allow_40mhz: 11n channel with a width of 40Mhz is allowed - * for this regulatory domain (valid only in 5Ghz). + * for this regulatory domain. * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed - * for this regulatory domain (valid only in 5Ghz). + * for this regulatory domain (valid only in 5 and 6 Ghz). * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed - * for this regulatory domain (valid only in 5Ghz). + * for this regulatory domain (valid only in 5 and 6 Ghz). + * @allow_320mhz: 11be channel with a width of 320Mhz is allowed + * for this regulatory domain (valid only in 6 Ghz). * @disable_11ax: 11ax is forbidden for this regulatory domain. + * @disable_11be: 11be is forbidden for this regulatory domain. */ struct iwl_reg_capa { - u16 allow_40mhz; - u16 allow_80mhz; - u16 allow_160mhz; - u16 disable_11ax; + bool allow_40mhz; + bool allow_80mhz; + bool allow_160mhz; + bool allow_320mhz; + bool disable_11ax; + bool disable_11be; }; static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, @@ -1538,20 +1572,27 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, return flags; } -static struct iwl_reg_capa iwl_get_reg_capa(u16 flags, u8 resp_ver) +static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver) { - struct iwl_reg_capa reg_capa; - - if (resp_ver >= REG_CAPA_V2_RESP_VER) { + struct iwl_reg_capa reg_capa = {}; + + if (resp_ver >= REG_CAPA_V4_RESP_VER) { + reg_capa.allow_40mhz = true; + reg_capa.allow_80mhz = flags & REG_CAPA_V4_80MHZ_ALLOWED; + reg_capa.allow_160mhz = flags & REG_CAPA_V4_160MHZ_ALLOWED; + reg_capa.allow_320mhz = flags & REG_CAPA_V4_320MHZ_ALLOWED; + reg_capa.disable_11ax = flags & REG_CAPA_V4_11AX_DISABLED; + reg_capa.disable_11be = flags & REG_CAPA_V4_11BE_DISABLED; + } else if (resp_ver >= REG_CAPA_V2_RESP_VER) { reg_capa.allow_40mhz = flags & REG_CAPA_V2_40MHZ_ALLOWED; reg_capa.allow_80mhz = flags & REG_CAPA_V2_80MHZ_ALLOWED; reg_capa.allow_160mhz = flags & REG_CAPA_V2_160MHZ_ALLOWED; reg_capa.disable_11ax = flags & REG_CAPA_V2_11AX_DISABLED; } else { - reg_capa.allow_40mhz = !(flags & REG_CAPA_40MHZ_FORBIDDEN); - reg_capa.allow_80mhz = flags & REG_CAPA_80MHZ_ALLOWED; - reg_capa.allow_160mhz = flags & REG_CAPA_160MHZ_ALLOWED; - reg_capa.disable_11ax = flags & REG_CAPA_11AX_DISABLED; + reg_capa.allow_40mhz = !(flags & REG_CAPA_V1_40MHZ_FORBIDDEN); + reg_capa.allow_80mhz = flags & REG_CAPA_V1_80MHZ_ALLOWED; + reg_capa.allow_160mhz = flags & REG_CAPA_V1_160MHZ_ALLOWED; + reg_capa.disable_11ax = flags & REG_CAPA_V1_11AX_DISABLED; } return reg_capa; } @@ -1559,7 +1600,7 @@ static struct iwl_reg_capa iwl_get_reg_capa(u16 flags, u8 resp_ver) struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc, - u16 geo_info, u16 cap, u8 resp_ver) + u16 geo_info, u32 cap, u8 resp_ver) { int ch_idx; u16 ch_flags; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index e01f7751cf11..c79f72d54482 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2015, 2018-2021 Intel Corporation + * Copyright (C) 2005-2015, 2018-2022 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_nvm_parse_h__ @@ -50,7 +50,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc, - u16 geo_info, u16 cap, u8 resp_ver); + u16 geo_info, u32 cap, u8 resp_ver); /** * struct iwl_nvm_section - describes an NVM section in memory. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index cac4aa062cd4..7ea200c85cac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -108,7 +108,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, struct ieee80211_regdomain *regd = NULL; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mcc_update_resp *resp; + struct iwl_mcc_update_resp_v8 *resp; u8 resp_ver; IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); @@ -138,7 +138,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, resp->channels, __le16_to_cpu(resp->mcc), __le16_to_cpu(resp->geo_info), - __le16_to_cpu(resp->cap), resp_ver); + le32_to_cpu(resp->cap), resp_ver); /* Store the return source id */ src_id = resp->source_id; if (IS_ERR_OR_NULL(regd)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index bba3acd64131..ee3a6d1ef07b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2219,7 +2219,7 @@ static inline void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) {} #endif /* Location Aware Regulatory */ -struct iwl_mcc_update_resp * +struct iwl_mcc_update_resp_v8 * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id); int iwl_mvm_init_mcc(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 6d18a1fd649b..435eba0ed506 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -404,7 +404,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm) return ret < 0 ? ret : 0; } -struct iwl_mcc_update_resp * +struct iwl_mcc_update_resp_v8 * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id) { @@ -412,7 +412,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), .source_id = (u8)src_id, }; - struct iwl_mcc_update_resp *resp_cp; + struct iwl_mcc_update_resp_v8 *resp_cp; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = MCC_UPDATE_CMD, @@ -420,7 +420,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .data = { &mcc_update_cmd }, }; - int ret; + int ret, resp_ver; u32 status; int resp_len, n_channels; u16 mcc; @@ -439,25 +439,55 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, pkt = cmd.resp_pkt; + resp_ver = iwl_fw_lookup_notif_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, + MCC_UPDATE_CMD, 0); + /* Extract MCC response */ - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { - struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data; - - n_channels = __le32_to_cpu(mcc_resp->n_channels); - resp_len = sizeof(struct iwl_mcc_update_resp) + - n_channels * sizeof(__le32); - resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); + if (resp_ver >= 8) { + struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (void *)pkt->data; + + n_channels = __le32_to_cpu(mcc_resp_v8->n_channels); + resp_len = struct_size(resp_cp, channels, n_channels); + resp_cp = kzalloc(resp_len, GFP_KERNEL); if (!resp_cp) { resp_cp = ERR_PTR(-ENOMEM); goto exit; } + resp_cp->status = mcc_resp_v8->status; + resp_cp->mcc = mcc_resp_v8->mcc; + resp_cp->cap = mcc_resp_v8->cap; + resp_cp->source_id = mcc_resp_v8->source_id; + resp_cp->time = mcc_resp_v8->time; + resp_cp->geo_info = mcc_resp_v8->geo_info; + resp_cp->n_channels = mcc_resp_v8->n_channels; + memcpy(resp_cp->channels, mcc_resp_v8->channels, + n_channels * sizeof(__le32)); + } else if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { + struct iwl_mcc_update_resp_v4 *mcc_resp_v4 = (void *)pkt->data; + + n_channels = __le32_to_cpu(mcc_resp_v4->n_channels); + resp_len = struct_size(resp_cp, channels, n_channels); + resp_cp = kzalloc(resp_len, GFP_KERNEL); + if (!resp_cp) { + resp_cp = ERR_PTR(-ENOMEM); + goto exit; + } + + resp_cp->status = mcc_resp_v4->status; + resp_cp->mcc = mcc_resp_v4->mcc; + resp_cp->cap = cpu_to_le32(le16_to_cpu(mcc_resp_v4->cap)); + resp_cp->source_id = mcc_resp_v4->source_id; + resp_cp->time = mcc_resp_v4->time; + resp_cp->geo_info = mcc_resp_v4->geo_info; + resp_cp->n_channels = mcc_resp_v4->n_channels; + memcpy(resp_cp->channels, mcc_resp_v4->channels, + n_channels * sizeof(__le32)); } else { struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data; n_channels = __le32_to_cpu(mcc_resp_v3->n_channels); - resp_len = sizeof(struct iwl_mcc_update_resp) + - n_channels * sizeof(__le32); + resp_len = struct_size(resp_cp, channels, n_channels); resp_cp = kzalloc(resp_len, GFP_KERNEL); if (!resp_cp) { resp_cp = ERR_PTR(-ENOMEM); @@ -466,7 +496,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_cp->status = mcc_resp_v3->status; resp_cp->mcc = mcc_resp_v3->mcc; - resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap); + resp_cp->cap = cpu_to_le32(mcc_resp_v3->cap); resp_cp->source_id = mcc_resp_v3->source_id; resp_cp->time = mcc_resp_v3->time; resp_cp->geo_info = mcc_resp_v3->geo_info; -- cgit v1.2.3 From 352d3ef47efb6f36d44f645387f7746a6fcb4035 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 31 May 2023 11:50:33 +0300 Subject: wifi: iwlwifi: iwlmei: fix compilation error The feature is still disabled (depends on BROKEN), but the code had a compilation error after one of the merges. Fix that. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531085033.216028-1-gregory.greenman@intel.com Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mei/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mei/main.c b/drivers/net/wireless/intel/iwlwifi/mei/main.c index 0a29fb013005..54445f39fd55 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/main.c +++ b/drivers/net/wireless/intel/iwlwifi/mei/main.c @@ -1791,9 +1791,8 @@ int iwl_mei_register(void *priv, const struct iwl_mei_ops *ops) if (iwl_mei_is_connected()) { if (mei->amt_enabled) iwl_mei_send_sap_msg(mei->cldev, - SAP_MSG_NOTIF_WIFIDR_UP, - false); - ops->rfkill(priv, mei->link_prot_state); + SAP_MSG_NOTIF_WIFIDR_UP); + ops->rfkill(priv, mei->link_prot_state, false); } } ret = 0; -- cgit v1.2.3 From 06471b67d42efeae151931f7ed95ed612734f1be Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Wed, 31 May 2023 19:49:54 +0300 Subject: wifi: iwlwifi: Add vendors to TAS approved list Allows vendors to use the time average sar feature. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194629.845c205e4def.Iab5c849617ed7e13304e4dfc7def668659439946@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 08b1e15241ce..3546638779c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1104,7 +1104,26 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), }, }, - + { .ident = "Acer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + }, + }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + }, + }, + { .ident = "MSI", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), + }, + }, + { .ident = "Honor", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + }, + }, /* keep last */ {} }; @@ -1176,6 +1195,10 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) "Unable to add US/Canada to TAS block list, disabling TAS\n"); return; } + } else { + IWL_DEBUG_RADIO(mvm, + "System vendor '%s' is in the approved list.\n", + dmi_get_system_info(DMI_SYS_VENDOR)); } /* v4 is the same size as v3, so no need to differentiate here */ -- cgit v1.2.3 From f9f5cc864533c4ac7afb476c57a3ae3f8998a837 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 May 2023 19:49:55 +0300 Subject: wifi: iwlwifi: mvm: support injection rate control Supporting controlling the frame rate during injection, HT/VHT are supported in addition to legacy rates. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194629.85a662792649.I0847b47dec0dfb0290d7b15ebc6bc0a575eed7b5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 62 +++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 10d7178f1071..59c91cf54cc1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -308,6 +308,54 @@ static u32 iwl_mvm_get_tx_ant(struct iwl_mvm *mvm, return BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS; } +static u32 iwl_mvm_get_inject_tx_rate(struct iwl_mvm *mvm, + struct ieee80211_tx_info *info) +{ + struct ieee80211_tx_rate *rate = &info->control.rates[0]; + u32 result; + + /* + * we only care about legacy/HT/VHT so far, so we can + * build in v1 and use iwl_new_rate_from_v1() + */ + + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + u8 mcs = ieee80211_rate_get_vht_mcs(rate); + u8 nss = ieee80211_rate_get_vht_nss(rate); + + result = RATE_MCS_VHT_MSK_V1; + result |= u32_encode_bits(mcs, RATE_VHT_MCS_RATE_CODE_MSK); + result |= u32_encode_bits(nss, RATE_MCS_NSS_MSK); + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + result |= RATE_MCS_SGI_MSK_V1; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1); + else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + result |= u32_encode_bits(2, RATE_MCS_CHAN_WIDTH_MSK_V1); + else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH) + result |= u32_encode_bits(3, RATE_MCS_CHAN_WIDTH_MSK_V1); + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + result = RATE_MCS_HT_MSK_V1; + result |= u32_encode_bits(rate->idx, + RATE_HT_MCS_RATE_CODE_MSK_V1 | + RATE_HT_MCS_NSS_MSK_V1); + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + result |= RATE_MCS_SGI_MSK_V1; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1); + if (rate->flags & IEEE80211_TX_CTL_LDPC) + result |= RATE_MCS_LDPC_MSK_V1; + if (u32_get_bits(rate->flags, IEEE80211_TX_CTL_STBC)) + result |= RATE_MCS_STBC_MSK; + } else { + return 0; + } + + if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) > 6) + return iwl_new_rate_from_v1(result); + return result; +} + static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, __le16 fc) @@ -317,8 +365,15 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, u32 rate_flags = 0; bool is_cck; - /* info->control is only relevant for non HW rate control */ - if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) { + if (unlikely(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) { + u32 result = iwl_mvm_get_inject_tx_rate(mvm, info); + + if (result) + return result; + rate_idx = info->control.rates[0].idx; + } else if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) { + /* info->control is only relevant for non HW rate control */ + /* HT rate doesn't make sense for a non data frame */ WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS && !ieee80211_is_data(fc), @@ -398,7 +453,8 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, * table is controlled by LINK_QUALITY commands */ - if (ieee80211_is_data(fc) && sta) { + if (likely(ieee80211_is_data(fc) && sta && + !(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT))) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED) { -- cgit v1.2.3 From 0e3941357a0be334413c96e57a18b54e31aaf55a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 May 2023 19:49:56 +0300 Subject: wifi: iwlwifi: mvm: clarify EHT RU allocation bits Calling this IWL_RX_PHY_DATA1_EHT_B0 is just confusing, it's the RU allocation bit 0. Also then align the name for B1-B7 accordingly. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194629.824edb28c0eb.Ia9f74573e3ac771911b679558984f1bfb36de674@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index fdd8b01f09e4..67af922fd3ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -367,8 +367,8 @@ enum iwl_rx_phy_eht_data1 { /* number of EHT-LTF symbols 0 - 1 EHT-LTF, 1 - 2 EHT-LTFs, 2 - 4 EHT-LTFs, * 3 - 6 EHT-LTFs, 4 - 8 EHT-LTFs */ IWL_RX_PHY_DATA1_EHT_SIG_LTF_NUM = 0x000000e0, - IWL_RX_PHY_DATA1_EHT_B0 = 0x00000100, - IWL_RX_PHY_DATA1_EHT_RU_B1_B7_ALLOC = 0x0000fe00, + IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B0 = 0x00000100, + IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7 = 0x0000fe00, }; /* goes into Metadata DW 7 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index e1d02c260e69..82ac0ef1c31b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1775,9 +1775,9 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm, eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT); eht->data[8] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PS160, IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160); - eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_B0, + eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B0, IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0); - eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_B1_B7_ALLOC, + eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7, IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1); iwl_mvm_decode_eht_ru(mvm, rx_status, eht); -- cgit v1.2.3 From 7bc57ca9b4129c4c2265832c79722d531308b072 Mon Sep 17 00:00:00 2001 From: Golan Ben Ami Date: Wed, 31 May 2023 19:49:57 +0300 Subject: wifi: iwlwifi: acpi: add other Google OEMs to the ppag approved list Add two new vendors to the PPAG approved vendor list as Google OEMs. Signed-off-by: Golan Ben Ami Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194629.b89a3f9e3ae0.Iab1e13285c58ef1fee2a8bad8429eda4547b0b74@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index e6abd16f8677..9ee9e0cb722c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -47,6 +47,18 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { DMI_MATCH(DMI_BOARD_VENDOR, "HP"), }, }, + { .ident = "GOOGLE-ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."), + }, + }, + { .ident = "GOOGLE-SAMSUNG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), + }, + }, {} }; -- cgit v1.2.3 From 3278c42ba992fd016baa7275feeb138c05cceb62 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 31 May 2023 19:49:58 +0300 Subject: wifi: iwlwifi: do not log undefined DRAM buffers unnecessarily DRAM buffers that are not defined in the TLVs (or are unused in the preset) would cause a log message. To avoid confusion, skip processing buffers with an invalid (i.e. uninitialized) DRAM path. This further reduces the noise of the message in cases where it is unlikely to be helpful. Also update a related debug log string to better describe what is happening. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194629.ecae60cf2d7f.Ib44a94d4aeb55dbb2e52edea8b69a09bc0f722c3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 898d5dcf1012..fb0277bd12cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -738,7 +738,8 @@ static int iwl_dbg_tlv_update_dram(struct iwl_fw_runtime *fwrt, if (le32_to_cpu(fwrt->trans->dbg.fw_mon_cfg[alloc_id].buf_location) != IWL_FW_INI_LOCATION_DRAM_PATH) { - IWL_DEBUG_FW(fwrt, "DRAM_PATH is not supported alloc_id %u\n", alloc_id); + IWL_DEBUG_FW(fwrt, "WRT: alloc_id %u location is not in DRAM_PATH\n", + alloc_id); return -1; } @@ -799,6 +800,10 @@ static void iwl_dbg_tlv_update_drams(struct iwl_fw_runtime *fwrt) for (i = IWL_FW_INI_ALLOCATION_ID_DBGC1; i < IWL_FW_INI_ALLOCATION_NUM; i++) { + if (fwrt->trans->dbg.fw_mon_cfg[i].buf_location == + IWL_FW_INI_LOCATION_INVALID) + continue; + ret = iwl_dbg_tlv_update_dram(fwrt, i, dram_info); if (!ret) dram_alloc = true; -- cgit v1.2.3 From 3b67a20bb0cb9e2f03dbe0af2074b7f4aa5fa811 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Wed, 31 May 2023 19:49:59 +0300 Subject: wifi: iwlwifi: mvm: offload BTM response during D3 There are mainly two types of BTM (BSS Transition Management) requests, recommendations and notifications. For the first type, a response is needed otherwise, most probably the STA will be disconnected. Since we don't want to wake up the host on it, set the BTM to reject offload flag (if the device supports it) and rely on the FW to take care of it. The FW will reject the BTM request and in case the AP sends DEAUTH the FW can wake up the host to let it decide on the next steps. Signed-off-by: Haim Dreyfuss Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194629.d95ae6f2804c.I9457acc55bc23ce715c714b5088058f52540c224@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/d3.h | 2 ++ drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/offloading.c | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 8a613e150a02..37ac2364e714 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -47,12 +47,14 @@ struct iwl_d3_manager_config { * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled * @IWL_D3_PROTO_IPV4_VALID: IPv4 data is valid * @IWL_D3_PROTO_IPV6_VALID: IPv6 data is valid + * @IWL_D3_PROTO_REJECT_BTM: reject BTM request */ enum iwl_proto_offloads { IWL_D3_PROTO_OFFLOAD_ARP = BIT(0), IWL_D3_PROTO_OFFLOAD_NS = BIT(1), IWL_D3_PROTO_IPV4_VALID = BIT(2), IWL_D3_PROTO_IPV6_VALID = BIT(3), + IWL_D3_PROTO_REJECT_BTM = BIT(4), }; #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index ef2ff7517534..42de95a22784 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -463,6 +463,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT = (__force iwl_ucode_tlv_capa_t)110, IWL_UCODE_TLV_CAPA_SCAN_DONT_TOGGLE_ANT = (__force iwl_ucode_tlv_capa_t)111, IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT = (__force iwl_ucode_tlv_capa_t)112, + IWL_UCODE_TLV_CAPA_OFFLOAD_REJ_BTM_SUPPORT = (__force iwl_ucode_tlv_capa_t)113, #ifdef __CHECKER__ /* sparse says it cannot increment the previous enum member */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index a8bd0f5f795c..797b1f70937e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -198,6 +198,10 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN); } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_OFFLOAD_REJ_BTM_SUPPORT)) + enabled |= IWL_D3_PROTO_REJECT_BTM; + if (!disable_offloading) common->enabled = cpu_to_le32(enabled); -- cgit v1.2.3 From ec80c23170465a123f7382120f1af04289adc465 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 May 2023 19:50:00 +0300 Subject: wifi: iwlwifi: pcie: adjust Bz device timings The 100ms shouldn't be needed, only 10ms. However after reset we should have 10ms as well for these devices. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194629.9a5627c1ff18.Ifcfbccd5458bd9ebd496aa834284fb0facfcaaef@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index b281850fbf7a..db10bd3c1058 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -131,13 +131,15 @@ static int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership) { /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_SW_RESET); - else + usleep_range(10000, 20000); + } else { iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - usleep_range(5000, 6000); + usleep_range(5000, 6000); + } if (retake_ownership) return iwl_pcie_prepare_card_hw(trans); @@ -475,7 +477,7 @@ void iwl_pcie_apm_stop_master(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, 100); - msleep(100); + usleep_range(10000, 20000); } else { iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); -- cgit v1.2.3 From 1bcbb1208e9a392fd850b7c8e0422d618d4ab565 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Wed, 31 May 2023 19:50:01 +0300 Subject: wifi: iwlwifi: mvm: FTM initiator MLO support When checking if the initiator is associated to the responder, iterate over all active links. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194629.a0d86655e7d2.I8f140ca55094da1d73c387fc036394fb2c148c85@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 45 +++++++++++++++------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 3963a0d4ed04..233ae81884a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -72,15 +72,24 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * the TK is already configured for this station, so it * shouldn't be set again here. */ - if (vif->cfg.assoc && - !memcmp(addr, vif->bss_conf.bssid, ETH_ALEN)) { + if (vif->cfg.assoc) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; struct ieee80211_sta *sta; + u8 sta_id; rcu_read_lock(); - sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); - if (!IS_ERR_OR_NULL(sta) && sta->mfp) - expected_tk_len = 0; + for_each_vif_active_link(vif, link_conf, link_id) { + if (memcmp(addr, link_conf->bssid, ETH_ALEN)) + continue; + + sta_id = mvmvif->link[link_id]->ap_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + if (!IS_ERR_OR_NULL(sta) && sta->mfp) + expected_tk_len = 0; + break; + } rcu_read_unlock(); } @@ -518,20 +527,30 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_ftm_put_target_common(mvm, peer, target); - if (vif->cfg.assoc && - !memcmp(peer->addr, vif->bss_conf.bssid, ETH_ALEN)) { + if (vif->cfg.assoc) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; rcu_read_lock(); + for_each_vif_active_link(vif, link_conf, link_id) { + if (memcmp(peer->addr, link_conf->bssid, ETH_ALEN)) + continue; + + target->sta_id = mvmvif->link[link_id]->ap_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[target->sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return PTR_ERR_OR_ZERO(sta); + } - sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); - if (sta->mfp && (peer->ftm.trigger_based || peer->ftm.non_trigger_based)) - FTM_PUT_FLAG(PMF); - + if (sta->mfp && (peer->ftm.trigger_based || + peer->ftm.non_trigger_based)) + FTM_PUT_FLAG(PMF); + break; + } rcu_read_unlock(); - - target->sta_id = mvmvif->deflink.ap_sta_id; } else { target->sta_id = IWL_MVM_INVALID_STA; } -- cgit v1.2.3 From 9e6942121e1956191dce0779cb8228f64d19e1d9 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Wed, 31 May 2023 19:50:03 +0300 Subject: wifi: iwlwifi: Add Dell to ppag approved list Add 2 new entries for Dell in PPAG approved list. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194630.a2696f0538ef.I324e4a0cc4696c27830a490b79c42dfeff8ba074@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 9ee9e0cb722c..ba94f6e6be62 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -59,6 +59,16 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), }, }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + }, + }, {} }; -- cgit v1.2.3 From 4784f3f9232fd295245d54abdf03002a91e4784f Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Wed, 31 May 2023 19:50:04 +0300 Subject: wifi: iwlwifi: remove dead code in iwl_dump_ini_imr_get_size() Remove the check for the IMR debug data size which leads to dead code. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194630.58eec8d40729.Ifb7d64706eed45726db804f36e785283dff7adab@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index d9faaae01abd..3180cabc0212 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2031,7 +2031,6 @@ static u32 iwl_dump_ini_imr_get_size(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data) { - u32 size = 0; u32 ranges = 0; u32 imr_enable = fwrt->trans->dbg.imr_data.imr_enable; u32 imr_size = fwrt->trans->dbg.imr_data.imr_size; @@ -2041,17 +2040,16 @@ iwl_dump_ini_imr_get_size(struct iwl_fw_runtime *fwrt, IWL_DEBUG_INFO(fwrt, "WRT: Invalid imr data enable: %d, imr_size: %d, sram_size: %d\n", imr_enable, imr_size, sram_size); - return size; + return 0; } - size = imr_size; ranges = iwl_dump_ini_imr_ranges(fwrt, reg_data); - if (!size && !ranges) { - IWL_ERR(fwrt, "WRT: imr_size :=%d, ranges :=%d\n", size, ranges); + if (!ranges) { + IWL_ERR(fwrt, "WRT: ranges :=%d\n", ranges); return 0; } - size += sizeof(struct iwl_fw_ini_error_dump) + + imr_size += sizeof(struct iwl_fw_ini_error_dump) + ranges * sizeof(struct iwl_fw_ini_error_dump_range); - return size; + return imr_size; } /** -- cgit v1.2.3 From fccf5ff14e00b264c03467186e6055dcb9959475 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 May 2023 19:50:05 +0300 Subject: wifi: iwlwifi: mvm: remove warning for beacon filtering error This warning is sometimes happening if we force a FW error while disconnecting, which is annoying but harmless. However, it's also pointless to throw a warning here, since the stack and driver state doesn't really help, so just remove that so the driver will ignore the error if any. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194630.29fe6990d372.I00ff5dc7bfb4025a609f380a0a3911d842b72449@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 7ea200c85cac..6a712e519bac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3801,7 +3801,6 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - int ret; lockdep_assert_held(&mvm->mutex); @@ -3820,10 +3819,7 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, mvmvif->authorized = 0; /* disable beacon filtering */ - ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); - WARN_ON(ret && - !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, - &mvm->status)); + iwl_mvm_disable_beacon_filter(mvm, vif, 0); } return 0; -- cgit v1.2.3 From ead65aa2d5155728baec90f6404cd02618ef29d0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 31 May 2023 19:50:06 +0300 Subject: wifi: iwlwifi: mvm: send time sync only if needed If there's no peer configured then there's no point in sending the command down to the firmware with an invalid peer address. Fixes: cf85123a210f ("wifi: iwlwifi: mvm: support enabling and disabling HW timestamping") Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230531194630.0fb9f81f1852.Idcc41b67d1fbb421e5ed9bac2177b948b7b4d1c9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 3546638779c4..a97969075b7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1725,9 +1725,11 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB); - iwl_mvm_time_sync_config(mvm, mvm->time_sync.peer_addr, - IWL_TIME_SYNC_PROTOCOL_TM | - IWL_TIME_SYNC_PROTOCOL_FTM); + + if (mvm->time_sync.active) + iwl_mvm_time_sync_config(mvm, mvm->time_sync.peer_addr, + IWL_TIME_SYNC_PROTOCOL_TM | + IWL_TIME_SYNC_PROTOCOL_FTM); } if (!mvm->ptp_data.ptp_clock) -- cgit v1.2.3 From 4c8d5c8d079e7ccdac959a2d909e1d2aca28b038 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2023 09:52:46 +0300 Subject: wifi: iwlwifi: mvm: tell firmware about per-STA MFP enablement Indicate to the firmware for each station whether or not MFP is used with this station. Note that we indicate MFP for it before authorized since we don't know yet, and that will make the firmware not handle should-be-protected management frames without being able to check them. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230601095201.b1052f39af4c.I1b46b751d5808e65ea3d0e7b8b38209c5aecf042@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 42de95a22784..319ab4d7188e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -464,6 +464,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_SCAN_DONT_TOGGLE_ANT = (__force iwl_ucode_tlv_capa_t)111, IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT = (__force iwl_ucode_tlv_capa_t)112, IWL_UCODE_TLV_CAPA_OFFLOAD_REJ_BTM_SUPPORT = (__force iwl_ucode_tlv_capa_t)113, + IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT = (__force iwl_ucode_tlv_capa_t)114, #ifdef __CHECKER__ /* sparse says it cannot increment the previous enum member */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index 401f94bd1f9c..b3296aa65f20 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -71,6 +71,11 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm, cmd.station_type = cpu_to_le32(sta->type); + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT) && + sta->type == STATION_TYPE_BCAST_MGMT) + cmd.mfp = cpu_to_le32(1); + if (addr) { memcpy(cmd.peer_mld_address, addr, ETH_ALEN); memcpy(cmd.peer_link_address, addr, ETH_ALEN); @@ -442,6 +447,11 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (mvm_sta->sta_state >= IEEE80211_STA_ASSOC) cmd.assoc_id = cpu_to_le32(sta->aid); + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT) && + (sta->mfp || mvm_sta->sta_state < IEEE80211_STA_AUTHORIZED)) + cmd.mfp = cpu_to_le32(1); + switch (link_sta->rx_nss) { case 1: cmd.mimo = cpu_to_le32(0); -- cgit v1.2.3 From 59505471a11b31a4296f4782dfcb36e0b459df5b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2023 17:20:03 +0300 Subject: wifi: iwlwifi: api: link context action in kernel-doc This is clearer in kernel-doc than spelling out the prefix. It also lets us generate better tracing data. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230601171633.e11ece794f60.I9874c7b0437071a2620d68ca5a16efed60da07a9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/binding.h | 6 +++--- drivers/net/wireless/intel/iwlwifi/fw/api/context.h | 13 +++++++++---- drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 6 +++--- drivers/net/wireless/intel/iwlwifi/fw/api/mac.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h | 6 +++--- drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h | 7 ++++--- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h index 29e2816e7052..b6b5959cb259 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2020 Intel Corporation + * Copyright (C) 2012-2014, 2020, 2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -18,7 +18,7 @@ * ( BINDING_CONTEXT_CMD = 0x2b ) * @id_and_color: ID and color of the relevant Binding, * &enum iwl_ctxt_id_and_color - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @macs: array of MAC id and colors which belong to the binding, * &enum iwl_ctxt_id_and_color * @phy: PHY id and color which belongs to the binding, @@ -38,7 +38,7 @@ struct iwl_binding_cmd_v1 { * ( BINDING_CONTEXT_CMD = 0x2b ) * @id_and_color: ID and color of the relevant Binding, * &enum iwl_ctxt_id_and_color - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @macs: array of MAC id and colors which belong to the binding * &enum iwl_ctxt_id_and_color * @phy: PHY id and color which belongs to the binding diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h index 105ba7170c3f..1fa5678c1cd6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2012-2014, 2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -26,13 +26,18 @@ enum iwl_ctxt_id_and_color { #define FW_CMD_ID_AND_COLOR(_id, _color) (((_id) << FW_CTXT_ID_POS) |\ ((_color) << FW_CTXT_COLOR_POS)) -/* Possible actions on PHYs, MACs and Bindings */ +/** + * enum iwl_ctxt_action - Posssible actions on PHYs, MACs, Bindings and other + * @FW_CTXT_ACTION_INVALID: unused, invalid action + * @FW_CTXT_ACTION_ADD: add the context + * @FW_CTXT_ACTION_MODIFY: modify the context + * @FW_CTXT_ACTION_REMOVE: remove the context + */ enum iwl_ctxt_action { - FW_CTXT_ACTION_STUB = 0, + FW_CTXT_ACTION_INVALID = 0, FW_CTXT_ACTION_ADD, FW_CTXT_ACTION_MODIFY, FW_CTXT_ACTION_REMOVE, - FW_CTXT_ACTION_NUM }; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ #endif /* __iwl_fw_api_context_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index b4244fa0516b..a4cb24934a01 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -193,7 +193,7 @@ struct iwl_cancel_channel_switch_cmd { * struct iwl_chan_switch_te_cmd - Channel Switch Time Event command * * @mac_id: MAC ID for channel switch - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @tsf: beacon tsf * @cs_count: channel switch count from CSA/eCSA IE * @cs_delayed_bcn_count: if set to N (!= 0) GO/AP can delay N beacon intervals @@ -296,7 +296,7 @@ enum iwl_mac_config_filter_flags { * ( MAC_CONTEXT_CONFIG_CMD = 0x8 ) * * @id_and_color: ID and color of the MAC - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @mac_type: one of &enum iwl_mac_types * @local_mld_addr: mld address * @reserved_for_local_mld_addr: reserved @@ -423,7 +423,7 @@ enum iwl_link_ctx_flags { * in MLD API * ( LINK_CONFIG_CMD =0x9 ) * - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @link_id: the id of the link that this cmd configures * @mac_id: interface ID. Relevant only if action is FW_CTXT_ACTION_ADD * @phy_id: PHY index. Can be changed only if the link was inactive diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index c51c6c3a69ad..55882190251c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -295,7 +295,7 @@ struct iwl_ac_qos { * struct iwl_mac_ctx_cmd - command structure to configure MAC contexts * ( MAC_CONTEXT_CMD = 0x28 ) * @id_and_color: ID and color of the MAC - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @mac_type: one of &enum iwl_mac_types * @tsf_id: TSF HW timer, one of &enum iwl_tsf_id * @node_addr: MAC address diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index 2f7d8558becd..8fe42cff1102 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018, 2020-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2020-2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -116,7 +116,7 @@ struct iwl_phy_context_cmd_tail { * struct iwl_phy_context_cmd - config of the PHY context * ( PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @apply_time: 0 means immediate apply and context switch. * other value means apply new params after X usecs * @tx_param_color: ??? @@ -138,7 +138,7 @@ struct iwl_phy_context_cmd_v1 { * struct iwl_phy_context_cmd - config of the PHY context * ( PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @lmac_id: the lmac id the phy context belongs to * @ci: channel info * @rxchain_info: ??? diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index 904cd78a9fa0..7cc706731d70 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2020, 2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -292,7 +292,7 @@ struct iwl_hs20_roc_req_tail { * ( HOT_SPOT_CMD 0x53 ) * * @id_and_color: ID and color of the MAC - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @event_unique_id: If the action FW_CTXT_ACTION_REMOVE then the * event_unique_id should be the id of the time event assigned by ucode. * Otherwise ignore the event_unique_id. @@ -377,7 +377,8 @@ enum iwl_mvm_session_prot_conf_id { * struct iwl_mvm_session_prot_cmd - configure a session protection * @id_and_color: the id and color of the mac for which this session protection * is sent - * @action: can be either FW_CTXT_ACTION_ADD or FW_CTXT_ACTION_REMOVE + * @action: can be either FW_CTXT_ACTION_ADD or FW_CTXT_ACTION_REMOVE, + * see &enum iwl_ctxt_action * @conf_id: see &enum iwl_mvm_session_prot_conf_id * @duration_tu: the duration of the whole protection in TUs. * @repetition_count: not used -- cgit v1.2.3 From 11b60071759de9d623feb478dfcdf1d1e63ce95d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2023 17:20:04 +0300 Subject: wifi: iwlwifi: api: use __le16 instead of u16 Even for reserved values we shouldn't use u16, that's just error prone. Fix this to __le16. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230601171633.29ebf70aa64e.I1263f6724e1c70ff5541f447b9744f143ee736a3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/power.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index f92cac1da764..85d89f559f6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -537,7 +537,7 @@ union iwl_ppag_table_cmd { struct iwl_sar_offset_mapping_cmd { u8 offset_map[MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE] [MCC_TO_SAR_OFFSET_TABLE_COL_SIZE]; - u16 reserved; + __le16 reserved; } __packed; /*SAR_OFFSET_MAPPING_TABLE_CMD_API_S*/ /** -- cgit v1.2.3 From d6b0e44e49bc55ec45b25133ba5de3bc20fbd82a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2023 17:20:05 +0300 Subject: wifi: iwlwifi: api: remove unused commands Some commands are no longer used and have broken kernel-doc links, so just remove them. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230601171633.3dad4ad9b53e.I018abd02d6925950b8748dfb7a59db87255fc670@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/commands.h | 11 ----------- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 2 -- 2 files changed, 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 111d96cbde6f..78d3ccab279d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -138,11 +138,6 @@ enum iwl_legacy_cmds { */ REMOVE_STA = 0x19, - /** - * @FW_GET_ITEM_CMD: uses &struct iwl_fw_get_item_cmd - */ - FW_GET_ITEM_CMD = 0x1a, - /** * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2 or * &struct iwl_tx_cmd_gen3, @@ -533,12 +528,6 @@ enum iwl_legacy_cmds { */ PROT_OFFLOAD_CONFIG_CMD = 0xd4, - /** - * @OFFLOADS_QUERY_CMD: - * No data in command, response in &struct iwl_wowlan_status - */ - OFFLOADS_QUERY_CMD = 0xd5, - /** * @D0I3_END_CMD: End D0i3/D3 state, no command data */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 32625bfacaae..8cc2e2145cf9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -449,7 +449,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(ADD_STA_KEY), HCMD_NAME(ADD_STA), HCMD_NAME(REMOVE_STA), - HCMD_NAME(FW_GET_ITEM_CMD), HCMD_NAME(TX_CMD), HCMD_NAME(SCD_QUEUE_CFG), HCMD_NAME(TXPATH_FLUSH), @@ -512,7 +511,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(REPLY_BEACON_FILTERING_CMD), HCMD_NAME(D3_CONFIG_CMD), HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD), - HCMD_NAME(OFFLOADS_QUERY_CMD), HCMD_NAME(MATCH_FOUND_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION), HCMD_NAME(WOWLAN_PATTERNS), -- cgit v1.2.3 From 43413a36b268f1a5049b8c1d44fdd892e080b563 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Jun 2023 17:20:06 +0300 Subject: wifi: iwlwifi: api: fix kernel-doc links Some of the kernel-doc links are outdated due to other changes, fix that. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230601171633.85e2cf489893.Ie3889ea6f755b80c988543ccca56c67420c51b1f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/commands.h | 12 ++++++++---- drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h | 6 ++++-- drivers/net/wireless/intel/iwlwifi/fw/api/location.h | 16 +++++++++++----- drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 11 ++++++++--- drivers/net/wireless/intel/iwlwifi/fw/api/offload.h | 3 ++- drivers/net/wireless/intel/iwlwifi/fw/api/phy.h | 10 +++++++--- 6 files changed, 40 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 78d3ccab279d..13cb0d53a1a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -555,18 +555,22 @@ enum iwl_legacy_cmds { WOWLAN_TKIP_PARAM = 0xe3, /** - * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd + * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd_v2, + * &struct iwl_wowlan_kek_kck_material_cmd_v3 or + * &struct iwl_wowlan_kek_kck_material_cmd_v4 */ WOWLAN_KEK_KCK_MATERIAL = 0xe4, /** - * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status + * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status_v6, + * &struct iwl_wowlan_status_v7, &struct iwl_wowlan_status_v9 or + * &struct iwl_wowlan_status_v12 */ WOWLAN_GET_STATUSES = 0xe5, /** - * @SCAN_OFFLOAD_PROFILES_QUERY_CMD: - * No command data, response is &struct iwl_scan_offload_profiles_query + * @SCAN_OFFLOAD_PROFILES_QUERY_CMD: No command data, response is + * &struct iwl_scan_offload_profiles_query_v1 */ SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 6f59381b9f9a..751b596ea1a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -38,7 +38,9 @@ enum iwl_data_path_subcmd_ids { WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD = 0x4, /** - * @STA_HE_CTXT_CMD: &struct iwl_he_sta_context_cmd + * @STA_HE_CTXT_CMD: &struct iwl_he_sta_context_cmd_v1, + * &struct iwl_he_sta_context_cmd_v2 or + * &struct iwl_he_sta_context_cmd_v3 */ STA_HE_CTXT_CMD = 0x7, @@ -447,7 +449,7 @@ struct iwl_sad_properties { * @phy_id: PHY index * @rlc: RLC properties, &struct iwl_rlc_properties * @sad: SAD (single antenna diversity) options, &struct iwl_sad_properties - * @flags: flags, &enum iwl_rlc_flags + * @flags: flags (unused) * @reserved: reserved */ struct iwl_rlc_config_cmd { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 12af94e166ed..b044990c7b87 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #ifndef __iwl_fw_api_location_h__ #define __iwl_fw_api_location_h__ @@ -35,8 +35,11 @@ enum iwl_location_subcmd_ids { */ TOF_RANGE_REQ_EXT_CMD = 0x3, /** - * @TOF_RESPONDER_CONFIG_CMD: FTM responder configuration, - * uses &struct iwl_tof_responder_config_cmd + * @TOF_RESPONDER_CONFIG_CMD: FTM responder configuration, one of + * &struct iwl_tof_responder_config_cmd_v6, + * &struct iwl_tof_responder_config_cmd_v7, + * &struct iwl_tof_responder_config_cmd_v8 or + * &struct iwl_tof_responder_config_cmd_v9 */ TOF_RESPONDER_CONFIG_CMD = 0x4, /** @@ -69,8 +72,11 @@ enum iwl_location_subcmd_ids { */ TOF_MCSI_DEBUG_NOTIF = 0xFE, /** - * @TOF_RANGE_RESPONSE_NOTIF: ranging response, using - * &struct iwl_tof_range_rsp_ntfy + * @TOF_RANGE_RESPONSE_NOTIF: ranging response, using one of + * &struct iwl_tof_range_rsp_ntfy_v5, + * &struct iwl_tof_range_rsp_ntfy_v6, + * &struct iwl_tof_range_rsp_ntfy_v7 or + * &struct iwl_tof_range_rsp_ntfy_v8 */ TOF_RANGE_RESPONSE_NOTIF = 0xFF, }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 635e4ddfbca6..28bfabb399b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -17,7 +17,12 @@ enum iwl_regulatory_and_nvm_subcmd_ids { NVM_ACCESS_COMPLETE = 0x0, /** - * @LARI_CONFIG_CHANGE: &struct iwl_lari_config_change_cmd + * @LARI_CONFIG_CHANGE: &struct iwl_lari_config_change_cmd_v1, + * &struct iwl_lari_config_change_cmd_v2, + * &struct iwl_lari_config_change_cmd_v3, + * &struct iwl_lari_config_change_cmd_v4, + * &struct iwl_lari_config_change_cmd_v5 or + * &struct iwl_lari_config_change_cmd_v6 */ LARI_CONFIG_CHANGE = 0x1, @@ -29,12 +34,12 @@ enum iwl_regulatory_and_nvm_subcmd_ids { NVM_GET_INFO = 0x2, /** - * @TAS_CONFIG: &struct iwl_tas_config_cmd + * @TAS_CONFIG: &union iwl_tas_config_cmd */ TAS_CONFIG = 0x3, /** - * @SAR_OFFSET_MAPPING_TABLE_CMD: &iwl_sar_offset_mapping_cmd + * @SAR_OFFSET_MAPPING_TABLE_CMD: &struct iwl_sar_offset_mapping_cmd */ SAR_OFFSET_MAPPING_TABLE_CMD = 0x4, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h index a0123f81f5d8..898bf351f6e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h @@ -28,7 +28,8 @@ enum iwl_prot_offload_subcmd_ids { D3_END_NOTIFICATION = 0xFE, /** - * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif + * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif_v2 or + * &struct iwl_stored_beacon_notif_v3 */ STORED_BEACON_NTF = 0xFF, }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h index b1b9c29859c1..5a3f30e5e06d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2019-2021 Intel Corporation + * Copyright (C) 2012-2014, 2019-2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -29,12 +29,16 @@ enum iwl_phy_ops_subcmd_ids { TEMP_REPORTING_THRESHOLDS_CMD = 0x04, /** - * @PER_CHAIN_LIMIT_OFFSET_CMD: &struct iwl_geo_tx_power_profiles_cmd + * @PER_CHAIN_LIMIT_OFFSET_CMD: &struct iwl_geo_tx_power_profiles_cmd_v1, + * &struct iwl_geo_tx_power_profiles_cmd_v2, + * &struct iwl_geo_tx_power_profiles_cmd_v3, + * &struct iwl_geo_tx_power_profiles_cmd_v4 or + * &struct iwl_geo_tx_power_profiles_cmd_v5 */ PER_CHAIN_LIMIT_OFFSET_CMD = 0x05, /** - * @PER_PLATFORM_ANT_GAIN_CMD: &struct iwl_ppag_table_cmd + * @PER_PLATFORM_ANT_GAIN_CMD: &union iwl_ppag_table_cmd */ PER_PLATFORM_ANT_GAIN_CMD = 0x07, -- cgit v1.2.3 From 5f40850399c61aec5f26861f4a5194aae64c27df Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:42:58 +0300 Subject: wifi: iwlwifi: Generalize the parsing of the pnvm image Generalize iwl_pnvm_parse(). This saves us from copying each payload twice (first in the parsing and later when copying it to the dram). Moreover, its more compatible for handling larger pnvm tables in the future (in which payloads won't be concatenated). The main changes are: 1. Take out the concatenating of the payloads from the parsing level 2. Start using iwl_pnvm_image structure that will hold pointers to payloads that should be delivered to fw, their sizes and number. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.06c02f380b6f.I03a3030fca194aa0c4bc2ecd18531f8914e98cfd@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 43 ++++++++-------------- .../wireless/intel/iwlwifi/iwl-context-info-gen3.h | 4 +- .../net/wireless/intel/iwlwifi/iwl-context-info.h | 5 ++- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 23 ++++++++++-- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 34 +++++++++++++---- .../net/wireless/intel/iwlwifi/pcie/ctxt-info.c | 8 ++-- 6 files changed, 72 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index c6f2672fdc73..bec3c7ec3f4c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -36,10 +36,8 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, const struct iwl_ucode_tlv *tlv; u32 sha1 = 0; u16 mac_type = 0, rf_id = 0; - u8 *pnvm_data = NULL, *tmp; + struct iwl_pnvm_image pnvm_data = {}; bool hw_match = false; - u32 size = 0; - int ret; IWL_DEBUG_FW(trans, "Handling PNVM section\n"); @@ -55,8 +53,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, if (len < tlv_len) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); - ret = -EINVAL; - goto out; + return -EINVAL; } data += sizeof(*tlv); @@ -112,23 +109,18 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, break; } - IWL_DEBUG_FW(trans, "Adding data (size %d)\n", - data_len); - - tmp = krealloc(pnvm_data, size + data_len, GFP_KERNEL); - if (!tmp) { + if (pnvm_data.n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { IWL_DEBUG_FW(trans, - "Couldn't allocate (more) pnvm_data\n"); - - ret = -ENOMEM; - goto out; + "too many payloads to allocate in DRAM.\n"); + return -EINVAL; } - pnvm_data = tmp; - - memcpy(pnvm_data + size, section->data, data_len); + IWL_DEBUG_FW(trans, "Adding data (size %d)\n", + data_len); - size += data_len; + pnvm_data.chunks[pnvm_data.n_chunks].data = section->data; + pnvm_data.chunks[pnvm_data.n_chunks].len = data_len; + pnvm_data.n_chunks++; break; } @@ -152,22 +144,17 @@ done: "HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n", CSR_HW_REV_TYPE(trans->hw_rev), CSR_HW_RFID_TYPE(trans->hw_rf_id)); - ret = -ENOENT; - goto out; + return -ENOENT; } - if (!size) { + if (!pnvm_data.n_chunks) { IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); - ret = -ENOENT; - goto out; + return -ENOENT; } IWL_INFO(trans, "loaded PNVM version %08x\n", sha1); - ret = iwl_trans_set_pnvm(trans, pnvm_data, size); -out: - kfree(pnvm_data); - return ret; + return iwl_trans_set_pnvm(trans, &pnvm_data); } static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, @@ -275,7 +262,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, * need to set it again. */ if (trans->pnvm_loaded) { - ret = iwl_trans_set_pnvm(trans, NULL, 0); + ret = iwl_trans_set_pnvm(trans, NULL); if (ret) return ret; goto skip_parse; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index 3f7278014009..9d2dcb64523c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -13,6 +13,8 @@ #define CSR_IML_SIZE_ADDR 0x128 #define CSR_IML_RESP_ADDR 0x12c +#define UNFRAGMENTED_PNVM_PAYLOADS_NUMBER 2 + /* Set bit for enabling automatic function boot */ #define CSR_AUTO_FUNC_BOOT_ENA BIT(1) /* Set bit for initiating function boot */ @@ -278,7 +280,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive); int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, - const void *data, u32 len); + const struct iwl_pnvm_image *pnvm_payloads); int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, const void *data, u32 len); int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h index 4354d5acac9f..1a1321db137c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2020, 2022 Intel Corporation */ #ifndef __iwl_context_info_file_h__ #define __iwl_context_info_file_h__ @@ -177,6 +177,9 @@ void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans); int iwl_pcie_init_fw_sec(struct iwl_trans *trans, const struct fw_img *fw, struct iwl_context_info_dram *ctxt_dram); +void *iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans, + size_t size, + dma_addr_t *phys); int iwl_pcie_ctxt_info_alloc_dma(struct iwl_trans *trans, const void *data, u32 len, struct iwl_dram_data *dram); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 885581e636c7..b7f43cfc35fb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -459,6 +459,22 @@ struct iwl_trans_rxq_dma_data { u64 ur_bd_cb; }; +/* maximal number of DRAM MAP entries supported by FW */ +#define IPC_DRAM_MAP_ENTRY_NUM_MAX 64 + +/** + * struct iwl_pnvm_image - contains info about the parsed pnvm image + * @chunks: array of pointers to pnvm payloads and their sizes + * @n_chunks: the number of the pnvm payloads. + */ +struct iwl_pnvm_image { + struct { + const void *data; + u32 len; + } chunks[IPC_DRAM_MAP_ENTRY_NUM_MAX]; + u32 n_chunks; +}; + /** * struct iwl_trans_ops - transport specific operations * @@ -614,7 +630,8 @@ struct iwl_trans_ops { void *sanitize_ctx); void (*debugfs_cleanup)(struct iwl_trans *trans); void (*sync_nmi)(struct iwl_trans *trans); - int (*set_pnvm)(struct iwl_trans *trans, const void *data, u32 len); + int (*set_pnvm)(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_data); int (*set_reduce_power)(struct iwl_trans *trans, const void *data, u32 len); void (*interrupts)(struct iwl_trans *trans, bool enable); @@ -1516,10 +1533,10 @@ void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, u32 sw_err_bit); static inline int iwl_trans_set_pnvm(struct iwl_trans *trans, - const void *data, u32 len) + const struct iwl_pnvm_image *pnvm_data) { if (trans->ops->set_pnvm) { - int ret = trans->ops->set_pnvm(trans, data, len); + int ret = trans->ops->set_pnvm(trans, pnvm_data); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index cb60ba40fe97..800857e61d65 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -282,28 +282,46 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive) } int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, - const void *data, u32 len) + const struct iwl_pnvm_image *pnvm_payloads) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; - int ret; + struct iwl_dram_data *dram = &trans_pcie->pnvm_dram; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return 0; /* only allocate the DRAM if not allocated yet */ if (!trans->pnvm_loaded) { + u32 len, len0, len1; + if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size)) return -EBUSY; - ret = iwl_pcie_ctxt_info_alloc_dma(trans, data, len, - &trans_pcie->pnvm_dram); - if (ret < 0) { - IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA %d.\n", - ret); - return ret; + if (pnvm_payloads->n_chunks != + UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) { + IWL_DEBUG_FW(trans, "expected 2 payloads, got %d.\n", + pnvm_payloads->n_chunks); + return -EINVAL; + } + len0 = pnvm_payloads->chunks[0].len; + len1 = pnvm_payloads->chunks[1].len; + if (len1 > 0xFFFFFFFF - len0) { + IWL_DEBUG_FW(trans, "sizes of payloads overflow.\n"); + return -EINVAL; + } + len = len0 + len1; + + dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent(trans, len, &dram->physical); + if (!dram->block) { + IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA.\n"); + return -ENOMEM; } + dram->size = len; + memcpy(dram->block, pnvm_payloads->chunks[0].data, len0); + memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data, + len1); } prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 74ce31fdf45e..5f55efe64bf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #include "iwl-trans.h" #include "iwl-fh.h" @@ -38,9 +38,9 @@ static void *_iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans, return result; } -static void *iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans, - size_t size, - dma_addr_t *phys) +void *iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans, + size_t size, + dma_addr_t *phys) { return _iwl_pcie_ctxt_info_dma_alloc_coherent(trans, size, phys, 0); } -- cgit v1.2.3 From 194d1f84d56e912459f166a80ef520037c84b0d3 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:42:59 +0300 Subject: wifi: iwlwifi: Separate loading and setting of pnvm image into two functions Take the part that is copying the pnvm image into DRAM, out of the the method that sets the prph_scratch. Makes the code cleaner since those 2 operations don't always happen together (loading should happen only once while setting can happen more than once). In addition, each operation will get more complex in the future when it will support also larger pnvm images. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.4c0728239fd6.Ibc30a9fbdb6123dadbe2dbb89318dbd5ec01080a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 12 ++-- .../wireless/intel/iwlwifi/iwl-context-info-gen3.h | 5 +- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 25 ++++---- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 69 +++++++++++++--------- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 1 + 5 files changed, 65 insertions(+), 47 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index bec3c7ec3f4c..f99328cc6b01 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -38,6 +38,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, u16 mac_type = 0, rf_id = 0; struct iwl_pnvm_image pnvm_data = {}; bool hw_match = false; + int ret; IWL_DEBUG_FW(trans, "Handling PNVM section\n"); @@ -152,9 +153,14 @@ done: return -ENOENT; } + ret = iwl_trans_load_pnvm(trans, &pnvm_data); + if (ret) + return ret; + IWL_INFO(trans, "loaded PNVM version %08x\n", sha1); - return iwl_trans_set_pnvm(trans, &pnvm_data); + iwl_trans_set_pnvm(trans); + return 0; } static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, @@ -262,9 +268,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, * need to set it again. */ if (trans->pnvm_loaded) { - ret = iwl_trans_set_pnvm(trans, NULL); - if (ret) - return ret; + iwl_trans_set_pnvm(trans); goto skip_parse; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index 9d2dcb64523c..9f718e43dd81 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -279,8 +279,9 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, const struct fw_img *fw); void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive); -int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_payloads); +int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_payloads); +void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans); int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, const void *data, u32 len); int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index b7f43cfc35fb..35782cba5b81 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -557,6 +557,7 @@ struct iwl_pnvm_image { * Note that the transport must fill in the proper file headers. * @debugfs_cleanup: used in the driver unload flow to make a proper cleanup * of the trans debugfs + * @load_pnvm: save the pnvm data in DRAM * @set_pnvm: set the pnvm data in the prph scratch buffer, inside the * context info. * @interrupts: disable/enable interrupts to transport @@ -630,8 +631,9 @@ struct iwl_trans_ops { void *sanitize_ctx); void (*debugfs_cleanup)(struct iwl_trans *trans); void (*sync_nmi)(struct iwl_trans *trans); - int (*set_pnvm)(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_data); + int (*load_pnvm)(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_payloads); + void (*set_pnvm)(struct iwl_trans *trans); int (*set_reduce_power)(struct iwl_trans *trans, const void *data, u32 len); void (*interrupts)(struct iwl_trans *trans, bool enable); @@ -1532,19 +1534,16 @@ static inline void iwl_trans_sync_nmi(struct iwl_trans *trans) void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, u32 sw_err_bit); -static inline int iwl_trans_set_pnvm(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_data) +static inline int iwl_trans_load_pnvm(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_data) { - if (trans->ops->set_pnvm) { - int ret = trans->ops->set_pnvm(trans, pnvm_data); - - if (ret) - return ret; - } - - trans->pnvm_loaded = true; + return trans->ops->load_pnvm(trans, pnvm_data); +} - return 0; +static inline void iwl_trans_set_pnvm(struct iwl_trans *trans) +{ + if (trans->ops->set_pnvm) + trans->ops->set_pnvm(trans); } static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 800857e61d65..e9f3799d4593 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -281,55 +281,68 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive) trans_pcie->prph_info = NULL; } -int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_payloads) +int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_payloads) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; struct iwl_dram_data *dram = &trans_pcie->pnvm_dram; + u32 len, len0, len1; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return 0; /* only allocate the DRAM if not allocated yet */ - if (!trans->pnvm_loaded) { - u32 len, len0, len1; + if (trans->pnvm_loaded) + return 0; - if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size)) - return -EBUSY; + if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size)) + return -EBUSY; - if (pnvm_payloads->n_chunks != - UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) { - IWL_DEBUG_FW(trans, "expected 2 payloads, got %d.\n", - pnvm_payloads->n_chunks); - return -EINVAL; - } - len0 = pnvm_payloads->chunks[0].len; - len1 = pnvm_payloads->chunks[1].len; - if (len1 > 0xFFFFFFFF - len0) { - IWL_DEBUG_FW(trans, "sizes of payloads overflow.\n"); + if (pnvm_payloads->n_chunks != UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) { + IWL_DEBUG_FW(trans, "expected 2 payloads, got %d.\n", + pnvm_payloads->n_chunks); return -EINVAL; - } - len = len0 + len1; + } - dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent(trans, len, &dram->physical); - if (!dram->block) { - IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA.\n"); - return -ENOMEM; - } - dram->size = len; - memcpy(dram->block, pnvm_payloads->chunks[0].data, len0); - memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data, - len1); + len0 = pnvm_payloads->chunks[0].len; + len1 = pnvm_payloads->chunks[1].len; + if (len1 > 0xFFFFFFFF - len0) { + IWL_DEBUG_FW(trans, "sizes of payloads overflow.\n"); + return -EINVAL; + } + len = len0 + len1; + + dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent(trans, len, + &dram->physical); + if (!dram->block) { + IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA.\n"); + return -ENOMEM; } + dram->size = len; + memcpy(dram->block, pnvm_payloads->chunks[0].data, len0); + memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data, len1); + + trans->pnvm_loaded = true; + return 0; +} + +void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = + &trans_pcie->prph_scratch->ctrl_cfg; + + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return; + prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = cpu_to_le64(trans_pcie->pnvm_dram.physical); prph_sc_ctrl->pnvm_cfg.pnvm_size = cpu_to_le32(trans_pcie->pnvm_dram.size); - return 0; } int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index db10bd3c1058..666dda554f30 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3536,6 +3536,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .txq_free = iwl_txq_dyn_free, .wait_txq_empty = iwl_trans_pcie_wait_txq_empty, .rxq_dma_data = iwl_trans_pcie_rxq_dma_data, + .load_pnvm = iwl_trans_pcie_ctx_info_gen3_load_pnvm, .set_pnvm = iwl_trans_pcie_ctx_info_gen3_set_pnvm, .set_reduce_power = iwl_trans_pcie_ctx_info_gen3_set_reduce_power, #ifdef CONFIG_IWLWIFI_DEBUGFS -- cgit v1.2.3 From b99e32cbfdf63a8acab18b0d44402172528ffe48 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:00 +0300 Subject: wifi: iwlwifi: Take loading and setting of pnvm image out of parsing part Change iwl_pnvm_parse so it will only save the information into the iwl_pnvm_image struct. This enables to use the parsing code for the power reduce tables in the future. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.504b42fc1611.I4ddf6ad76d922d118fcbcc4f0e9ec003753d0b75@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 130 +++++++++++++------------ drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 4 + 2 files changed, 73 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index f99328cc6b01..cb6a9191cf95 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright(c) 2020-2022 Intel Corporation + * Copyright(c) 2020-2023 Intel Corporation */ #include "iwl-drv.h" @@ -31,17 +31,18 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, } static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, - size_t len) + size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; u32 sha1 = 0; u16 mac_type = 0, rf_id = 0; - struct iwl_pnvm_image pnvm_data = {}; bool hw_match = false; - int ret; IWL_DEBUG_FW(trans, "Handling PNVM section\n"); + memset(pnvm_data, 0, sizeof(*pnvm_data)); + while (len >= sizeof(*tlv)) { u32 tlv_len, tlv_type; @@ -73,6 +74,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, IWL_DEBUG_FW(trans, "Got IWL_UCODE_TLV_PNVM_VERSION %0x\n", sha1); + pnvm_data->version = sha1; break; case IWL_UCODE_TLV_HW_TYPE: if (tlv_len < 2 * sizeof(__le16)) { @@ -110,7 +112,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, break; } - if (pnvm_data.n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { + if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { IWL_DEBUG_FW(trans, "too many payloads to allocate in DRAM.\n"); return -EINVAL; @@ -119,9 +121,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, IWL_DEBUG_FW(trans, "Adding data (size %d)\n", data_len); - pnvm_data.chunks[pnvm_data.n_chunks].data = section->data; - pnvm_data.chunks[pnvm_data.n_chunks].len = data_len; - pnvm_data.n_chunks++; + pnvm_data->chunks[pnvm_data->n_chunks].data = section->data; + pnvm_data->chunks[pnvm_data->n_chunks].len = data_len; + pnvm_data->n_chunks++; break; } @@ -148,23 +150,17 @@ done: return -ENOENT; } - if (!pnvm_data.n_chunks) { + if (!pnvm_data->n_chunks) { IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); return -ENOENT; } - ret = iwl_trans_load_pnvm(trans, &pnvm_data); - if (ret) - return ret; - - IWL_INFO(trans, "loaded PNVM version %08x\n", sha1); - - iwl_trans_set_pnvm(trans); return 0; } static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, - size_t len) + size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; @@ -205,7 +201,8 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { int ret; - ret = iwl_pnvm_handle_section(trans, data, len); + ret = iwl_pnvm_handle_section(trans, data, len, + pnvm_data); if (!ret) return 0; } else { @@ -248,70 +245,81 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) return 0; } +static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) +{ + struct pnvm_sku_package *package; + u8 *image = NULL; + + /* First attempt to get the PNVM from BIOS */ + package = iwl_uefi_get_pnvm(trans_p, len); + if (!IS_ERR_OR_NULL(package)) { + if (*len >= sizeof(*package)) { + /* we need only the data */ + *len -= sizeof(*package); + image = kmemdup(package->data, *len, GFP_KERNEL); + } + /* free package regardless of whether kmemdup succeeded */ + kfree(package); + if (image) + return image; + } + + /* If it's not available, try from the filesystem */ + if (iwl_pnvm_get_from_fs(trans_p, &image, len)) + return NULL; + return image; +} + int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait) { u8 *data; - size_t len; - struct pnvm_sku_package *package; + size_t length; struct iwl_notification_wait pnvm_wait; static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, PNVM_INIT_COMPLETE_NTFY) }; + struct iwl_pnvm_image pnvm_data; int ret; /* if the SKU_ID is empty, there's nothing to do */ if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2]) return 0; - /* - * If we already loaded (or tried to load) it before, we just - * need to set it again. - */ - if (trans->pnvm_loaded) { - iwl_trans_set_pnvm(trans); - goto skip_parse; - } + /* failed to get/parse the image in the past, no use to try again */ + if (trans->fail_to_parse_pnvm_image) + goto reduce_tables; - /* First attempt to get the PNVM from BIOS */ - package = iwl_uefi_get_pnvm(trans, &len); - if (!IS_ERR_OR_NULL(package)) { - if (len >= sizeof(*package)) { - /* we need only the data */ - len -= sizeof(*package); - data = kmemdup(package->data, len, GFP_KERNEL); - } else { - data = NULL; + /* get the image, parse and load it, if not loaded yet */ + if (!trans->pnvm_loaded) { + data = iwl_get_pnvm_image(trans, &length); + if (!data) { + trans->fail_to_parse_pnvm_image = true; + goto reduce_tables; + } + ret = iwl_pnvm_parse(trans, data, length, &pnvm_data); + if (ret) { + trans->fail_to_parse_pnvm_image = true; + kfree(data); + goto reduce_tables; } - /* free package regardless of whether kmemdup succeeded */ - kfree(package); - - if (data) - goto parse; - } - - /* If it's not available, try from the filesystem */ - ret = iwl_pnvm_get_from_fs(trans, &data, &len); - if (ret) { - /* - * Pretend we've loaded it - at least we've tried and - * couldn't load it at all, so there's no point in - * trying again over and over. + ret = iwl_trans_load_pnvm(trans, &pnvm_data); + /* can only free data after pvnm_data use, but + * pnvm_data.version used below is not a pointer */ - trans->pnvm_loaded = true; - - goto skip_parse; + kfree(data); + if (ret) + goto reduce_tables; + IWL_INFO(trans, "loaded PNVM version %08x\n", + pnvm_data.version); } -parse: - iwl_pnvm_parse(trans, data, len); - - kfree(data); + iwl_trans_set_pnvm(trans); -skip_parse: +reduce_tables: /* now try to get the reduce power table, if not loaded yet */ if (!trans->reduce_power_loaded) { - data = iwl_uefi_get_reduced_power(trans, &len); + data = iwl_uefi_get_reduced_power(trans, &length); if (IS_ERR_OR_NULL(data)) { /* * Pretend we've loaded it - at least we've tried and @@ -320,7 +328,7 @@ skip_parse: */ trans->reduce_power_loaded = true; } else { - ret = iwl_trans_set_reduce_power(trans, data, len); + ret = iwl_trans_set_reduce_power(trans, data, length); if (ret) IWL_DEBUG_FW(trans, "Failed to set reduce power table %d\n", diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 35782cba5b81..84485d69f195 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -466,6 +466,7 @@ struct iwl_trans_rxq_dma_data { * struct iwl_pnvm_image - contains info about the parsed pnvm image * @chunks: array of pointers to pnvm payloads and their sizes * @n_chunks: the number of the pnvm payloads. + * @version: the version of the loaded PNVM image */ struct iwl_pnvm_image { struct { @@ -473,6 +474,7 @@ struct iwl_pnvm_image { u32 len; } chunks[IPC_DRAM_MAP_ENTRY_NUM_MAX]; u32 n_chunks; + u32 version; }; /** @@ -1023,6 +1025,7 @@ struct iwl_trans_txqs { * @hw_rev_step: The mac step of the HW * @pm_support: set to true in start_hw if link pm is supported * @ltr_enabled: set to true if the LTR is enabled + * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed * @wide_cmd_header: true when ucode supports wide command header format * @wait_command_queue: wait queue for sync commands * @num_rx_queues: number of RX queues allocated by the transport; @@ -1070,6 +1073,7 @@ struct iwl_trans { bool pm_support; bool ltr_enabled; u8 pnvm_loaded:1; + u8 fail_to_parse_pnvm_image:1; u8 reduce_power_loaded:1; const struct iwl_hcmd_arr *command_groups; -- cgit v1.2.3 From f6fa5835652150734c57ccb2a21f3653cbe42a27 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:01 +0300 Subject: wifi: iwlwifi: Allow trans_pcie track more than 1 pnvm DRAM region Change the field pnvm_dram to an array that describes many regions and add a counter to the number of pnvm regions that were allocated in DRAM. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.bb206d71bf45.I627640701757bb2f234f8e18a3afbd6af1206658@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 13 +++++++++---- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 10 ++++++++-- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 18 ++++++++++++++---- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index e9f3799d4593..f43246b45a85 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -287,7 +287,7 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; - struct iwl_dram_data *dram = &trans_pcie->pnvm_dram; + struct iwl_dram_data *dram = &trans_pcie->pnvm_dram[0]; u32 len, len0, len1; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) @@ -324,6 +324,7 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, dram->size = len; memcpy(dram->block, pnvm_payloads->chunks[0].data, len0); memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data, len1); + trans_pcie->n_pnvm_regions = 1; trans->pnvm_loaded = true; return 0; @@ -337,11 +338,15 @@ void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans) if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return; - + /* FIXME: currently we concatenate payloads and save them only in + * pnvm_dram[0] - therefor only pnvm_dram[0] is delivered to the + * prph_sc. Need to add a UCODE sensitivity and another case in which + * we deliver to the prph_sc an array with all the DRAM addresses. + */ prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = - cpu_to_le64(trans_pcie->pnvm_dram.physical); + cpu_to_le64(trans_pcie->pnvm_dram[0].physical); prph_sc_ctrl->pnvm_cfg.pnvm_size = - cpu_to_le32(trans_pcie->pnvm_dram.size); + cpu_to_le32(trans_pcie->pnvm_dram[0].size); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 69b95ad5993b..ca2e7bb2def8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -23,6 +23,7 @@ #include "iwl-op-mode.h" #include "iwl-drv.h" #include "queue/tx.h" +#include "iwl-context-info.h" /* * RX related structures and functions @@ -306,7 +307,8 @@ enum iwl_pcie_imr_status { * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM * @kw: keep warm address - * @pnvm_dram: DRAM area that contains the PNVM data + * @pnvm_dram: array of several DRAM areas that contains the PNVM data + * @n_pnvm_regions: number of DRAM regions that were allocated for the pnvm * @pci_dev: basic pci-network driver stuff * @hw_base: pci hardware address support * @ucode_write_complete: indicates that the ucode has been copied. @@ -380,7 +382,9 @@ struct iwl_trans_pcie { u32 scd_base_addr; struct iwl_dma_ptr kw; - struct iwl_dram_data pnvm_dram; + /* pnvm data */ + struct iwl_dram_data pnvm_dram[IPC_DRAM_MAP_ENTRY_NUM_MAX]; + u8 n_pnvm_regions; struct iwl_dram_data reduce_power_dram; struct iwl_txq *txq_memory; @@ -478,6 +482,8 @@ struct iwl_trans const struct pci_device_id *ent, const struct iwl_cfg_trans_params *cfg_trans); void iwl_trans_pcie_free(struct iwl_trans *trans); +void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie, + struct device *dev); bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); #define _iwl_trans_pcie_grab_nic_access(trans) \ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 666dda554f30..c3b324d54b1d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1995,6 +1995,19 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->fw_reset_handshake = trans_cfg->fw_reset_handshake; } +void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie, + struct device *dev) +{ + u8 i; + + for (i = 0; i < trans_pcie->n_pnvm_regions; i++) { + dma_free_coherent(dev, trans_pcie->pnvm_dram[i].size, + trans_pcie->pnvm_dram[i].block, + trans_pcie->pnvm_dram[i].physical); + } + trans_pcie->n_pnvm_regions = 0; +} + void iwl_trans_pcie_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -2027,10 +2040,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) iwl_pcie_free_fw_monitor(trans); - if (trans_pcie->pnvm_dram.size) - dma_free_coherent(trans->dev, trans_pcie->pnvm_dram.size, - trans_pcie->pnvm_dram.block, - trans_pcie->pnvm_dram.physical); + iwl_trans_pcie_free_pnvm_dram(trans_pcie, trans->dev); if (trans_pcie->reduce_power_dram.size) dma_free_coherent(trans->dev, -- cgit v1.2.3 From 331828106e52d76170fed605aeeb9ba1b7321f46 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:02 +0300 Subject: wifi: iwlwifi: Add support for fragmented pnvm images Add support for fragmented pnvm images, depending on the FW capability. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.c49bfaf435a9.I0278312e7c3355b224cd870d4f8cf6578d12f03e@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 + drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 7 +- drivers/net/wireless/intel/iwlwifi/fw/pnvm.h | 5 +- .../wireless/intel/iwlwifi/iwl-context-info-gen3.h | 6 +- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 16 ++-- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 +- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 95 ++++++++++++++-------- 7 files changed, 88 insertions(+), 46 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 319ab4d7188e..a78b68c2ae3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -323,6 +323,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * is supported. * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan (no longer used) + * @IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG: supports fragmented PNVM image * @IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT: the firmware supports setting * stabilization latency for SoCs. * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification @@ -398,6 +399,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, /* set 1 */ + IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG = (__force iwl_ucode_tlv_capa_t)32, IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT = (__force iwl_ucode_tlv_capa_t)37, IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index cb6a9191cf95..91e1faef76f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -271,7 +271,8 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) } int iwl_pnvm_load(struct iwl_trans *trans, - struct iwl_notif_wait_data *notif_wait) + struct iwl_notif_wait_data *notif_wait, + const struct iwl_ucode_capabilities *capa) { u8 *data; size_t length; @@ -303,7 +304,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, goto reduce_tables; } - ret = iwl_trans_load_pnvm(trans, &pnvm_data); + ret = iwl_trans_load_pnvm(trans, &pnvm_data, capa); /* can only free data after pvnm_data use, but * pnvm_data.version used below is not a pointer */ @@ -314,7 +315,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, pnvm_data.version); } - iwl_trans_set_pnvm(trans); + iwl_trans_set_pnvm(trans, capa); reduce_tables: /* now try to get the reduce power table, if not loaded yet */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index 203c367dd4de..4e10baa01738 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /****************************************************************************** * - * Copyright(c) 2020-2021 Intel Corporation + * Copyright(c) 2020-2022 Intel Corporation * *****************************************************************************/ @@ -15,7 +15,8 @@ #define MAX_PNVM_NAME 64 int iwl_pnvm_load(struct iwl_trans *trans, - struct iwl_notif_wait_data *notif_wait); + struct iwl_notif_wait_data *notif_wait, + const struct iwl_ucode_capabilities *capa); static inline void iwl_pnvm_get_fs_name(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index 9f718e43dd81..23208be831f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -280,8 +280,10 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive); int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_payloads); -void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans); + const struct iwl_pnvm_image *pnvm_payloads, + const struct iwl_ucode_capabilities *capa); +void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa); int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, const void *data, u32 len); int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 84485d69f195..5993f11ef932 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -634,8 +634,10 @@ struct iwl_trans_ops { void (*debugfs_cleanup)(struct iwl_trans *trans); void (*sync_nmi)(struct iwl_trans *trans); int (*load_pnvm)(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_payloads); - void (*set_pnvm)(struct iwl_trans *trans); + const struct iwl_pnvm_image *pnvm_payloads, + const struct iwl_ucode_capabilities *capa); + void (*set_pnvm)(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa); int (*set_reduce_power)(struct iwl_trans *trans, const void *data, u32 len); void (*interrupts)(struct iwl_trans *trans, bool enable); @@ -1539,15 +1541,17 @@ void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, u32 sw_err_bit); static inline int iwl_trans_load_pnvm(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_data) + const struct iwl_pnvm_image *pnvm_data, + const struct iwl_ucode_capabilities *capa) { - return trans->ops->load_pnvm(trans, pnvm_data); + return trans->ops->load_pnvm(trans, pnvm_data, capa); } -static inline void iwl_trans_set_pnvm(struct iwl_trans *trans) +static inline void iwl_trans_set_pnvm(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) { if (trans->ops->set_pnvm) - trans->ops->set_pnvm(trans); + trans->ops->set_pnvm(trans, capa); } static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index a97969075b7b..a698ec461fcc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -433,7 +433,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, /* if reached this point, Alive notification was received */ iwl_mei_alive_notif(true); - ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait); + ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait, + &mvm->fw->ucode_capa); if (ret) { IWL_ERR(mvm, "Timeout waiting for PNVM load!\n"); iwl_fw_set_current_image(&mvm->fwrt, old_type); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index f43246b45a85..fc450c0d1145 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -281,33 +281,20 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive) trans_pcie->prph_info = NULL; } -int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_payloads) +static int iwl_pcie_load_payloads_continuously(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_data, + struct iwl_dram_data *dram) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = - &trans_pcie->prph_scratch->ctrl_cfg; - struct iwl_dram_data *dram = &trans_pcie->pnvm_dram[0]; u32 len, len0, len1; - if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) - return 0; - - /* only allocate the DRAM if not allocated yet */ - if (trans->pnvm_loaded) - return 0; - - if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size)) - return -EBUSY; - - if (pnvm_payloads->n_chunks != UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) { + if (pnvm_data->n_chunks != UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) { IWL_DEBUG_FW(trans, "expected 2 payloads, got %d.\n", - pnvm_payloads->n_chunks); - return -EINVAL; + pnvm_data->n_chunks); + return -EINVAL; } - len0 = pnvm_payloads->chunks[0].len; - len1 = pnvm_payloads->chunks[1].len; + len0 = pnvm_data->chunks[0].len; + len1 = pnvm_data->chunks[1].len; if (len1 > 0xFFFFFFFF - len0) { IWL_DEBUG_FW(trans, "sizes of payloads overflow.\n"); return -EINVAL; @@ -322,32 +309,76 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, } dram->size = len; - memcpy(dram->block, pnvm_payloads->chunks[0].data, len0); - memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data, len1); - trans_pcie->n_pnvm_regions = 1; + memcpy(dram->block, pnvm_data->chunks[0].data, len0); + memcpy((u8 *)dram->block + len0, pnvm_data->chunks[1].data, len1); - trans->pnvm_loaded = true; return 0; } -void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans) +/* FIXME: An implementation will be added with the next several commits. */ +static int iwl_pcie_load_payloads_segments(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_payloads) +{ + return -ENOMEM; +} + +int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_payloads, + const struct iwl_ucode_capabilities *capa) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; + struct iwl_dram_data *dram = &trans_pcie->pnvm_dram[0]; + int ret = 0; + + /* only allocate the DRAM if not allocated yet */ + if (trans->pnvm_loaded) + return 0; + + if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size)) + return -EBUSY; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) - return; - /* FIXME: currently we concatenate payloads and save them only in - * pnvm_dram[0] - therefor only pnvm_dram[0] is delivered to the - * prph_sc. Need to add a UCODE sensitivity and another case in which - * we deliver to the prph_sc an array with all the DRAM addresses. - */ + return 0; + + if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) + return iwl_pcie_load_payloads_segments(trans, pnvm_payloads); + + ret = iwl_pcie_load_payloads_continuously(trans, pnvm_payloads, dram); + if (!ret) { + trans_pcie->n_pnvm_regions = 1; + trans->pnvm_loaded = true; + } + + return ret; +} + +/* FIXME: An implementation will be added with the next several commits. */ +static void iwl_pcie_set_pnvm_segments(struct iwl_trans *trans) {} + +static void iwl_pcie_set_continuous_pnvm(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = + &trans_pcie->prph_scratch->ctrl_cfg; + prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = cpu_to_le64(trans_pcie->pnvm_dram[0].physical); prph_sc_ctrl->pnvm_cfg.pnvm_size = cpu_to_le32(trans_pcie->pnvm_dram[0].size); +} + +void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) +{ + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return; + if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) + iwl_pcie_set_pnvm_segments(trans); + else + iwl_pcie_set_continuous_pnvm(trans); } int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, -- cgit v1.2.3 From 63b9e7b9f02ee3b10b6998778e2ed11f23510d9c Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:03 +0300 Subject: wifi: iwlwifi: Implement loading and setting of fragmented pnvm image Save the pnvm payloads in several DRAM segments (not only in one as used to). In addition, allocate a FW structure in DRAM that holds the segments' addresses and forward its address to the FW. It's done when FW has the capability to handle pnvm images this way (helps to process large pnvm images). Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.dbdad8995ce1.I986213527982637042532de3851a1bd8a11be87a@changeid Signed-off-by: Johannes Berg --- .../wireless/intel/iwlwifi/iwl-context-info-gen3.h | 8 +++ .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 73 ++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 3 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 8 +++ 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index 23208be831f3..bbf4b18cd9de 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -109,6 +109,14 @@ struct iwl_prph_scratch_pnvm_cfg { __le32 reserved; } __packed; /* PERIPH_SCRATCH_PNVM_CFG_S */ +/** + * struct iwl_prph_scrath_mem_desc_addr_array + * @mem_descs: array of dram addresses. + * Each address is the beggining of a pnvm payload. + */ +struct iwl_prph_scrath_mem_desc_addr_array { + __le64 mem_descs[IPC_DRAM_MAP_ENTRY_NUM_MAX]; +} __packed; /* PERIPH_SCRATCH_MEM_DESC_ADDR_ARRAY_S_VER_1 */ /* * struct iwl_prph_scratch_hwm_cfg - hwm config * @hwm_base_addr: hwm start address diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index fc450c0d1145..e0477ca4ccc3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -315,11 +315,58 @@ static int iwl_pcie_load_payloads_continuously(struct iwl_trans *trans, return 0; } -/* FIXME: An implementation will be added with the next several commits. */ -static int iwl_pcie_load_payloads_segments(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_payloads) +static int iwl_pcie_load_payloads_segments + (struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_data) { - return -ENOMEM; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_dram_data *cur_pnvm_dram = &trans_pcie->pnvm_dram[0], + *desc_dram = &trans_pcie->pnvm_regions_desc_array; + struct iwl_prph_scrath_mem_desc_addr_array *addresses; + const void *data; + u32 len; + int i; + + /* allocate and init DRAM descriptors array */ + len = sizeof(struct iwl_prph_scrath_mem_desc_addr_array); + desc_dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent + (trans, + len, + &desc_dram->physical); + if (!desc_dram->block) { + IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA.\n"); + return -ENOMEM; + } + desc_dram->size = len; + memset(desc_dram->block, 0, len); + + /* allocate DRAM region for each payload */ + trans_pcie->n_pnvm_regions = 0; + for (i = 0; i < pnvm_data->n_chunks; i++) { + len = pnvm_data->chunks[i].len; + data = pnvm_data->chunks[i].data; + + if (iwl_pcie_ctxt_info_alloc_dma(trans, data, len, + cur_pnvm_dram)) { + iwl_trans_pcie_free_pnvm_dram(trans_pcie, trans->dev); + return -ENOMEM; + } + + trans_pcie->n_pnvm_regions++; + cur_pnvm_dram++; + } + + /* fill desc with the DRAM payloads addresses */ + addresses = desc_dram->block; + + for (i = 0; i < pnvm_data->n_chunks; i++) { + addresses->mem_descs[i] = + cpu_to_le64(trans_pcie->pnvm_dram[i].physical); + } + + trans->pnvm_loaded = true; + return 0; + } int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, @@ -342,9 +389,16 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return 0; + if (!pnvm_payloads->n_chunks) { + IWL_DEBUG_FW(trans, "no payloads\n"); + return -EINVAL; + } + + /* allocate several DRAM sections */ if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) return iwl_pcie_load_payloads_segments(trans, pnvm_payloads); + /* allocate one DRAM section */ ret = iwl_pcie_load_payloads_continuously(trans, pnvm_payloads, dram); if (!ret) { trans_pcie->n_pnvm_regions = 1; @@ -354,8 +408,15 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, return ret; } -/* FIXME: An implementation will be added with the next several commits. */ -static void iwl_pcie_set_pnvm_segments(struct iwl_trans *trans) {} +static void iwl_pcie_set_pnvm_segments(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = + &trans_pcie->prph_scratch->ctrl_cfg; + + prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = + cpu_to_le64(trans_pcie->pnvm_regions_desc_array.physical); +} static void iwl_pcie_set_continuous_pnvm(struct iwl_trans *trans) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index ca2e7bb2def8..d10f25da0eec 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -309,6 +309,8 @@ enum iwl_pcie_imr_status { * @kw: keep warm address * @pnvm_dram: array of several DRAM areas that contains the PNVM data * @n_pnvm_regions: number of DRAM regions that were allocated for the pnvm + * @pnvm_regions_desc_array: array of PNVM payloads addresses. + * allocated in DRAM and sent to FW. * @pci_dev: basic pci-network driver stuff * @hw_base: pci hardware address support * @ucode_write_complete: indicates that the ucode has been copied. @@ -385,6 +387,7 @@ struct iwl_trans_pcie { /* pnvm data */ struct iwl_dram_data pnvm_dram[IPC_DRAM_MAP_ENTRY_NUM_MAX]; u8 n_pnvm_regions; + struct iwl_dram_data pnvm_regions_desc_array; struct iwl_dram_data reduce_power_dram; struct iwl_txq *txq_memory; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index c3b324d54b1d..533b81222f89 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1999,6 +1999,7 @@ void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie, struct device *dev) { u8 i; + struct iwl_dram_data *desc_dram = &trans_pcie->pnvm_regions_desc_array; for (i = 0; i < trans_pcie->n_pnvm_regions; i++) { dma_free_coherent(dev, trans_pcie->pnvm_dram[i].size, @@ -2006,6 +2007,13 @@ void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie, trans_pcie->pnvm_dram[i].physical); } trans_pcie->n_pnvm_regions = 0; + + if (desc_dram->block) { + dma_free_coherent(dev, desc_dram->size, + desc_dram->block, + desc_dram->physical); + } + desc_dram->block = NULL; } void iwl_trans_pcie_free(struct iwl_trans *trans) -- cgit v1.2.3 From c738fb6163b213dd9565ba1951d4f130975db10f Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:04 +0300 Subject: wifi: iwlwifi: Separate loading and setting of power reduce tables Take the part that copies the tables into DRAM, out of the method that sets the prph_scratch to make the code cleaner. Each of the operations will get more complex in the future when it will also support larger power-reduce tables images. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.7695684dc848.I13626cd318e5d68efec9618b2045f52788bff114@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 9 ++++--- .../wireless/intel/iwlwifi/iwl-context-info-gen3.h | 5 ++-- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 28 ++++++++++++---------- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 18 ++++++++++---- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 1 + 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 91e1faef76f6..bb6300469f4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -329,14 +329,17 @@ reduce_tables: */ trans->reduce_power_loaded = true; } else { - ret = iwl_trans_set_reduce_power(trans, data, length); - if (ret) + ret = iwl_trans_load_reduce_power(trans, data, length); + if (ret) { IWL_DEBUG_FW(trans, - "Failed to set reduce power table %d\n", + "Failed to load reduce power table %d\n", ret); + trans->reduce_power_loaded = true; + } kfree(data); } } + iwl_trans_set_reduce_power(trans); iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index bbf4b18cd9de..e019aec027d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -292,8 +292,9 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); -int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, - const void *data, u32 len); +int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans, + const void *data, u32 len); +void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans); int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans, u32 mbx_addr_0_step, u32 mbx_addr_1_step); #endif /* __iwl_context_info_file_gen3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 5993f11ef932..0c8064473033 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -562,6 +562,8 @@ struct iwl_pnvm_image { * @load_pnvm: save the pnvm data in DRAM * @set_pnvm: set the pnvm data in the prph scratch buffer, inside the * context info. + * @load_reduce_power: copy reduce power table to the corresponding DRAM memory + * @set_reduce_power: set reduce power table addresses in the sratch buffer * @interrupts: disable/enable interrupts to transport */ struct iwl_trans_ops { @@ -638,8 +640,11 @@ struct iwl_trans_ops { const struct iwl_ucode_capabilities *capa); void (*set_pnvm)(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); - int (*set_reduce_power)(struct iwl_trans *trans, - const void *data, u32 len); + int (*load_reduce_power)(struct iwl_trans *trans, + const void *data, + u32 len); + void (*set_reduce_power)(struct iwl_trans *trans); + void (*interrupts)(struct iwl_trans *trans, bool enable); int (*imr_dma_data)(struct iwl_trans *trans, u32 dst_addr, u64 src_addr, @@ -1554,18 +1559,17 @@ static inline void iwl_trans_set_pnvm(struct iwl_trans *trans, trans->ops->set_pnvm(trans, capa); } -static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans, - const void *data, u32 len) +static inline int iwl_trans_load_reduce_power(struct iwl_trans *trans, + const void *data, + u32 len) { - if (trans->ops->set_reduce_power) { - int ret = trans->ops->set_reduce_power(trans, data, len); - - if (ret) - return ret; - } + return trans->ops->load_reduce_power(trans, data, len); +} - trans->reduce_power_loaded = true; - return 0; +static inline void iwl_trans_set_reduce_power(struct iwl_trans *trans) +{ + if (trans->ops->set_reduce_power) + trans->ops->set_reduce_power(trans); } static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index e0477ca4ccc3..2619c868b51f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -442,8 +442,9 @@ void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, iwl_pcie_set_continuous_pnvm(trans); } -int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, - const void *data, u32 len) +int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans, + const void *data, + u32 len) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = @@ -467,12 +468,21 @@ int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, return ret; } } + return 0; +} + +void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = + &trans_pcie->prph_scratch->ctrl_cfg; + + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return; prph_sc_ctrl->reduce_power_cfg.base_addr = cpu_to_le64(trans_pcie->reduce_power_dram.physical); prph_sc_ctrl->reduce_power_cfg.size = cpu_to_le32(trans_pcie->reduce_power_dram.size); - - return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 533b81222f89..45215feee609 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3556,6 +3556,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .rxq_dma_data = iwl_trans_pcie_rxq_dma_data, .load_pnvm = iwl_trans_pcie_ctx_info_gen3_load_pnvm, .set_pnvm = iwl_trans_pcie_ctx_info_gen3_set_pnvm, + .load_reduce_power = iwl_trans_pcie_ctx_info_gen3_load_reduce_power, .set_reduce_power = iwl_trans_pcie_ctx_info_gen3_set_reduce_power, #ifdef CONFIG_IWLWIFI_DEBUGFS .debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup, -- cgit v1.2.3 From ea3571f48953df2cf77a9c4200a7363236736673 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:05 +0300 Subject: wifi: iwlwifi: Use iwl_pnvm_image in reduce power tables flow Generalize the parsing, loading, and setting of the power-reduce tables, in order to support allocation of several DRAM payloads in the future. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.564f1eead99b.Iaba653b21dc09aafc72b9bbb3928abddce0db50a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 7 +- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 90 +++++++++------------- drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 8 +- .../wireless/intel/iwlwifi/iwl-context-info-gen3.h | 5 +- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 11 ++- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 25 +++--- 6 files changed, 63 insertions(+), 83 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index bb6300469f4a..42d994240b31 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -320,8 +320,9 @@ int iwl_pnvm_load(struct iwl_trans *trans, reduce_tables: /* now try to get the reduce power table, if not loaded yet */ if (!trans->reduce_power_loaded) { - data = iwl_uefi_get_reduced_power(trans, &length); - if (IS_ERR_OR_NULL(data)) { + memset(&pnvm_data, 0, sizeof(pnvm_data)); + ret = iwl_uefi_get_reduced_power(trans, &pnvm_data); + if (ret) { /* * Pretend we've loaded it - at least we've tried and * couldn't load it at all, so there's no point in @@ -329,7 +330,7 @@ reduce_tables: */ trans->reduce_power_loaded = true; } else { - ret = iwl_trans_load_reduce_power(trans, data, length); + ret = iwl_trans_load_reduce_power(trans, &pnvm_data); if (ret) { IWL_DEBUG_FW(trans, "Failed to load reduce power table %d\n", diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 01afea33c38c..64b45a5b767e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -55,14 +55,14 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) return data; } -static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, - const u8 *data, size_t len) +static int iwl_uefi_reduce_power_section(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; - u8 *reduce_power_data = NULL, *tmp; - u32 size = 0; IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n"); + memset(pnvm_data, 0, sizeof(*pnvm_data)); while (len >= sizeof(*tlv)) { u32 tlv_len, tlv_type; @@ -76,9 +76,7 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, if (len < tlv_len) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); - kfree(reduce_power_data); - reduce_power_data = ERR_PTR(-EINVAL); - goto out; + return -EINVAL; } data += sizeof(*tlv); @@ -89,23 +87,17 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, "Got IWL_UCODE_TLV_MEM_DESC len %d\n", tlv_len); - IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len); - - tmp = krealloc(reduce_power_data, size + tlv_len, GFP_KERNEL); - if (!tmp) { + if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { IWL_DEBUG_FW(trans, - "Couldn't allocate (more) reduce_power_data\n"); - - kfree(reduce_power_data); - reduce_power_data = ERR_PTR(-ENOMEM); - goto out; + "too many payloads to allocate in DRAM.\n"); + return -EINVAL; } - reduce_power_data = tmp; - - memcpy(reduce_power_data + size, data, tlv_len); + IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len); - size += tlv_len; + pnvm_data->chunks[pnvm_data->n_chunks].data = data; + pnvm_data->chunks[pnvm_data->n_chunks].len = tlv_len; + pnvm_data->n_chunks++; break; } @@ -124,27 +116,18 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, } done: - if (!size) { + if (!pnvm_data->n_chunks) { IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n"); - /* Better safe than sorry, but 'reduce_power_data' should - * always be NULL if !size. - */ - kfree(reduce_power_data); - reduce_power_data = ERR_PTR(-ENOENT); - goto out; + return -ENOENT; } - - IWL_INFO(trans, "loaded REDUCE_POWER\n"); - -out: - return reduce_power_data; + return 0; } -static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, - const u8 *data, size_t len) +static int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; - void *sec_data; IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n"); @@ -160,7 +143,7 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, if (len < tlv_len) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); - return ERR_PTR(-EINVAL); + return -EINVAL; } if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) { @@ -181,11 +164,11 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) && trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) && trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { - sec_data = iwl_uefi_reduce_power_section(trans, - data, - len); - if (!IS_ERR(sec_data)) - return sec_data; + int ret = iwl_uefi_reduce_power_section(trans, + data, len, + pnvm_data); + if (!ret) + return 0; } else { IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); } @@ -195,20 +178,20 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, } } - return ERR_PTR(-ENOENT); + return -ENOENT; } -void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +int iwl_uefi_get_reduced_power(struct iwl_trans *trans, + struct iwl_pnvm_image *pnvm_data) { struct pnvm_sku_package *package; - void *data = NULL; unsigned long package_size; efi_status_t status; - - *len = 0; + int ret; + size_t len = 0; if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) - return ERR_PTR(-ENODEV); + return -ENODEV; /* * TODO: we hardcode a maximum length here, because reading @@ -219,7 +202,7 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) package = kmalloc(package_size, GFP_KERNEL); if (!package) - return ERR_PTR(-ENOMEM); + return -ENOMEM; status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID, NULL, &package_size, package); @@ -228,22 +211,23 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) "Reduced Power UEFI variable not found 0x%lx (len %lu)\n", status, package_size); kfree(package); - return ERR_PTR(-ENOENT); + return -ENOENT; } IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n", package_size); - *len = package_size; + len = package_size; IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", package->rev, package->total_size, package->n_skus); - data = iwl_uefi_reduce_power_parse(trans, package->data, - *len - sizeof(*package)); + ret = iwl_uefi_reduce_power_parse(trans, package->data, + len - sizeof(*package), + pnvm_data); kfree(package); - return data; + return ret; } static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 17089bc74cf9..03176f73151a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -50,7 +50,8 @@ struct uefi_cnv_common_step_data { */ #ifdef CONFIG_EFI void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len); -void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); +int iwl_uefi_get_reduced_power(struct iwl_trans *trans, + struct iwl_pnvm_image *pnvm_data); void iwl_uefi_get_step_table(struct iwl_trans *trans); #else /* CONFIG_EFI */ static inline @@ -60,9 +61,10 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) } static inline -void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +int iwl_uefi_get_reduced_power(struct iwl_trans *trans, + struct iwl_pnvm_image *pnvm_data) { - return ERR_PTR(-EOPNOTSUPP); + return -EOPNOTSUPP; } static inline diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index e019aec027d6..7e7d135e85b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -292,8 +292,9 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); -int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans, - const void *data, u32 len); +int iwl_trans_pcie_ctx_info_gen3_load_reduce_power + (struct iwl_trans *trans, + const struct iwl_pnvm_image *payloads); void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans); int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans, u32 mbx_addr_0_step, u32 mbx_addr_1_step); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 0c8064473033..4faf9fc6bbe4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -641,8 +641,7 @@ struct iwl_trans_ops { void (*set_pnvm)(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); int (*load_reduce_power)(struct iwl_trans *trans, - const void *data, - u32 len); + const struct iwl_pnvm_image *payloads); void (*set_reduce_power)(struct iwl_trans *trans); void (*interrupts)(struct iwl_trans *trans, bool enable); @@ -1559,11 +1558,11 @@ static inline void iwl_trans_set_pnvm(struct iwl_trans *trans, trans->ops->set_pnvm(trans, capa); } -static inline int iwl_trans_load_reduce_power(struct iwl_trans *trans, - const void *data, - u32 len) +static inline int iwl_trans_load_reduce_power + (struct iwl_trans *trans, + const struct iwl_pnvm_image *payloads) { - return trans->ops->load_reduce_power(trans, data, len); + return trans->ops->load_reduce_power(trans, payloads); } static inline void iwl_trans_set_reduce_power(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 2619c868b51f..26d5ba777d24 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -443,31 +443,24 @@ void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, } int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans, - const void *data, - u32 len) + const struct iwl_pnvm_image *payloads) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; - int ret; + struct iwl_dram_data *dram = &trans_pcie->reduce_power_dram; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return 0; - /* only allocate the DRAM if not allocated yet */ - if (!trans->reduce_power_loaded) { - if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size)) - return -EBUSY; + if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size)) + return -EBUSY; - ret = iwl_pcie_ctxt_info_alloc_dma(trans, data, len, - &trans_pcie->reduce_power_dram); - if (ret < 0) { - IWL_DEBUG_FW(trans, - "Failed to allocate reduce power DMA %d.\n", - ret); - return ret; - } - } + /* only allocate the DRAM if not allocated yet */ + if (!trans->reduce_power_loaded) + return iwl_pcie_load_payloads_continuously(trans, + payloads, + dram); return 0; } -- cgit v1.2.3 From 7c9c8477170d32def5df9d88823ea10d65749341 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:06 +0300 Subject: wifi: iwlwifi: Enable loading of reduce-power tables into several segments Replace the field reduce_power_dram with a struct that holds data about the reduced-power tables drams regions. Generalize load_payloads_segments() to work for both pnvm tables and reduction power tables. Make required adjustments in the data structures. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.6fe66958f049.I85d80682229fc02fe354462cc9da40937558f30c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 4 +- .../wireless/intel/iwlwifi/iwl-context-info-gen3.h | 17 ++- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 30 ++++- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 150 +++++++++++++++------ drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 17 +-- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 31 +++-- 6 files changed, 169 insertions(+), 80 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 42d994240b31..b556abece896 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -330,7 +330,7 @@ reduce_tables: */ trans->reduce_power_loaded = true; } else { - ret = iwl_trans_load_reduce_power(trans, &pnvm_data); + ret = iwl_trans_load_reduce_power(trans, &pnvm_data, capa); if (ret) { IWL_DEBUG_FW(trans, "Failed to load reduce power table %d\n", @@ -340,7 +340,7 @@ reduce_tables: kfree(data); } } - iwl_trans_set_reduce_power(trans); + iwl_trans_set_reduce_power(trans, capa); iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h index 7e7d135e85b1..96bf353469b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h @@ -98,9 +98,9 @@ struct iwl_prph_scratch_control { } __packed; /* PERIPH_SCRATCH_CONTROL_S */ /* - * struct iwl_prph_scratch_pnvm_cfg - ror config + * struct iwl_prph_scratch_pnvm_cfg - PNVM scratch * @pnvm_base_addr: PNVM start address - * @pnvm_size: PNVM size in DWs + * @pnvm_size: the size of the PNVM image in bytes * @reserved: reserved */ struct iwl_prph_scratch_pnvm_cfg { @@ -142,7 +142,7 @@ struct iwl_prph_scratch_rbd_cfg { /* * struct iwl_prph_scratch_uefi_cfg - prph scratch reduce power table * @base_addr: reduce power table address - * @size: table size in dwords + * @size: the size of the entire power table image */ struct iwl_prph_scratch_uefi_cfg { __le64 base_addr; @@ -292,10 +292,13 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); -int iwl_trans_pcie_ctx_info_gen3_load_reduce_power - (struct iwl_trans *trans, - const struct iwl_pnvm_image *payloads); -void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans); +int +iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans, + const struct iwl_pnvm_image *payloads, + const struct iwl_ucode_capabilities *capa); +void +iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa); int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans, u32 mbx_addr_0_step, u32 mbx_addr_1_step); #endif /* __iwl_context_info_file_gen3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 4faf9fc6bbe4..eb32683c36fb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -641,8 +641,10 @@ struct iwl_trans_ops { void (*set_pnvm)(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa); int (*load_reduce_power)(struct iwl_trans *trans, - const struct iwl_pnvm_image *payloads); - void (*set_reduce_power)(struct iwl_trans *trans); + const struct iwl_pnvm_image *payloads, + const struct iwl_ucode_capabilities *capa); + void (*set_reduce_power)(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa); void (*interrupts)(struct iwl_trans *trans, bool enable); int (*imr_dma_data)(struct iwl_trans *trans, @@ -731,6 +733,19 @@ struct iwl_dram_data { int size; }; +/** + * @drams: array of several DRAM areas that contains the pnvm and power + * reduction table payloads. + * @n_regions: number of DRAM regions that were allocated + * @prph_scratch_mem_desc: points to a structure allocated in dram, + * designed to show FW where all the payloads are. + */ +struct iwl_dram_regions { + struct iwl_dram_data drams[IPC_DRAM_MAP_ENTRY_NUM_MAX]; + struct iwl_dram_data prph_scratch_mem_desc; + u8 n_regions; +}; + /** * struct iwl_fw_mon - fw monitor per allocation id * @num_frags: number of fragments @@ -1560,15 +1575,18 @@ static inline void iwl_trans_set_pnvm(struct iwl_trans *trans, static inline int iwl_trans_load_reduce_power (struct iwl_trans *trans, - const struct iwl_pnvm_image *payloads) + const struct iwl_pnvm_image *payloads, + const struct iwl_ucode_capabilities *capa) { - return trans->ops->load_reduce_power(trans, payloads); + return trans->ops->load_reduce_power(trans, payloads, capa); } -static inline void iwl_trans_set_reduce_power(struct iwl_trans *trans) +static inline void +iwl_trans_set_reduce_power(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) { if (trans->ops->set_reduce_power) - trans->ops->set_reduce_power(trans); + trans->ops->set_reduce_power(trans, capa); } static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index 26d5ba777d24..fa4a14546860 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include "iwl-trans.h" #include "iwl-fh.h" @@ -317,11 +317,11 @@ static int iwl_pcie_load_payloads_continuously(struct iwl_trans *trans, static int iwl_pcie_load_payloads_segments (struct iwl_trans *trans, + struct iwl_dram_regions *dram_regions, const struct iwl_pnvm_image *pnvm_data) { - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct iwl_dram_data *cur_pnvm_dram = &trans_pcie->pnvm_dram[0], - *desc_dram = &trans_pcie->pnvm_regions_desc_array; + struct iwl_dram_data *cur_payload_dram = &dram_regions->drams[0]; + struct iwl_dram_data *desc_dram = &dram_regions->prph_scratch_mem_desc; struct iwl_prph_scrath_mem_desc_addr_array *addresses; const void *data; u32 len; @@ -341,30 +341,31 @@ static int iwl_pcie_load_payloads_segments memset(desc_dram->block, 0, len); /* allocate DRAM region for each payload */ - trans_pcie->n_pnvm_regions = 0; + dram_regions->n_regions = 0; for (i = 0; i < pnvm_data->n_chunks; i++) { len = pnvm_data->chunks[i].len; data = pnvm_data->chunks[i].data; - if (iwl_pcie_ctxt_info_alloc_dma(trans, data, len, - cur_pnvm_dram)) { - iwl_trans_pcie_free_pnvm_dram(trans_pcie, trans->dev); + if (iwl_pcie_ctxt_info_alloc_dma(trans, + data, + len, + cur_payload_dram)) { + iwl_trans_pcie_free_pnvm_dram_regions(dram_regions, + trans->dev); return -ENOMEM; } - trans_pcie->n_pnvm_regions++; - cur_pnvm_dram++; + dram_regions->n_regions++; + cur_payload_dram++; } /* fill desc with the DRAM payloads addresses */ addresses = desc_dram->block; - for (i = 0; i < pnvm_data->n_chunks; i++) { addresses->mem_descs[i] = - cpu_to_le64(trans_pcie->pnvm_dram[i].physical); + cpu_to_le64(dram_regions->drams[i].physical); } - trans->pnvm_loaded = true; return 0; } @@ -376,7 +377,7 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; - struct iwl_dram_data *dram = &trans_pcie->pnvm_dram[0]; + struct iwl_dram_regions *dram_regions = &trans_pcie->pnvm_data; int ret = 0; /* only allocate the DRAM if not allocated yet */ @@ -394,28 +395,51 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans, return -EINVAL; } - /* allocate several DRAM sections */ - if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) - return iwl_pcie_load_payloads_segments(trans, pnvm_payloads); - - /* allocate one DRAM section */ - ret = iwl_pcie_load_payloads_continuously(trans, pnvm_payloads, dram); - if (!ret) { - trans_pcie->n_pnvm_regions = 1; - trans->pnvm_loaded = true; + /* save payloads in several DRAM sections */ + if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) { + ret = iwl_pcie_load_payloads_segments(trans, + dram_regions, + pnvm_payloads); + if (!ret) + trans->pnvm_loaded = true; + } else { + /* save only in one DRAM section */ + ret = iwl_pcie_load_payloads_continuously + (trans, + pnvm_payloads, + &dram_regions->drams[0]); + if (!ret) { + dram_regions->n_regions = 1; + trans->pnvm_loaded = true; + } } return ret; } +static inline size_t +iwl_dram_regions_size(const struct iwl_dram_regions *dram_regions) +{ + size_t total_size = 0; + int i; + + for (i = 0; i < dram_regions->n_regions; i++) + total_size += dram_regions->drams[i].size; + + return total_size; +} + static void iwl_pcie_set_pnvm_segments(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; + struct iwl_dram_regions *dram_regions = &trans_pcie->pnvm_data; prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = - cpu_to_le64(trans_pcie->pnvm_regions_desc_array.physical); + cpu_to_le64(dram_regions->prph_scratch_mem_desc.physical); + prph_sc_ctrl->pnvm_cfg.pnvm_size = + cpu_to_le32(iwl_dram_regions_size(dram_regions)); } static void iwl_pcie_set_continuous_pnvm(struct iwl_trans *trans) @@ -425,9 +449,9 @@ static void iwl_pcie_set_continuous_pnvm(struct iwl_trans *trans) &trans_pcie->prph_scratch->ctrl_cfg; prph_sc_ctrl->pnvm_cfg.pnvm_base_addr = - cpu_to_le64(trans_pcie->pnvm_dram[0].physical); + cpu_to_le64(trans_pcie->pnvm_data.drams[0].physical); prph_sc_ctrl->pnvm_cfg.pnvm_size = - cpu_to_le32(trans_pcie->pnvm_dram[0].size); + cpu_to_le32(trans_pcie->pnvm_data.drams[0].size); } void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, @@ -443,12 +467,18 @@ void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans, } int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans, - const struct iwl_pnvm_image *payloads) + const struct iwl_pnvm_image *payloads, + const struct iwl_ucode_capabilities *capa) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; - struct iwl_dram_data *dram = &trans_pcie->reduce_power_dram; + struct iwl_dram_regions *dram_regions = &trans_pcie->reduced_tables_data; + int ret = 0; + + /* only allocate the DRAM if not allocated yet */ + if (trans->reduce_power_loaded) + return 0; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return 0; @@ -456,26 +486,68 @@ int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans, if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size)) return -EBUSY; - /* only allocate the DRAM if not allocated yet */ - if (!trans->reduce_power_loaded) - return iwl_pcie_load_payloads_continuously(trans, - payloads, - dram); - return 0; + if (!payloads->n_chunks) { + IWL_DEBUG_FW(trans, "no payloads\n"); + return -EINVAL; + } + + /* save payloads in several DRAM sections */ + if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) { + ret = iwl_pcie_load_payloads_segments(trans, + dram_regions, + payloads); + if (!ret) + trans->reduce_power_loaded = true; + } else { + /* save only in one DRAM section */ + ret = iwl_pcie_load_payloads_continuously + (trans, + payloads, + &dram_regions->drams[0]); + if (!ret) { + dram_regions->n_regions = 1; + trans->reduce_power_loaded = true; + } + } + + return ret; } -void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans) +static void iwl_pcie_set_reduce_power_segments(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = &trans_pcie->prph_scratch->ctrl_cfg; + struct iwl_dram_regions *dram_regions = &trans_pcie->reduced_tables_data; - if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) - return; + prph_sc_ctrl->reduce_power_cfg.base_addr = + cpu_to_le64(dram_regions->prph_scratch_mem_desc.physical); + prph_sc_ctrl->reduce_power_cfg.size = + cpu_to_le32(iwl_dram_regions_size(dram_regions)); +} + +static void iwl_pcie_set_continuous_reduce_power(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl = + &trans_pcie->prph_scratch->ctrl_cfg; prph_sc_ctrl->reduce_power_cfg.base_addr = - cpu_to_le64(trans_pcie->reduce_power_dram.physical); + cpu_to_le64(trans_pcie->reduced_tables_data.drams[0].physical); prph_sc_ctrl->reduce_power_cfg.size = - cpu_to_le32(trans_pcie->reduce_power_dram.size); + cpu_to_le32(trans_pcie->reduced_tables_data.drams[0].size); +} + +void +iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) +{ + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return; + + if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) + iwl_pcie_set_reduce_power_segments(trans); + else + iwl_pcie_set_continuous_reduce_power(trans); } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index d10f25da0eec..0adcf0e13e85 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -307,10 +307,9 @@ enum iwl_pcie_imr_status { * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM * @kw: keep warm address - * @pnvm_dram: array of several DRAM areas that contains the PNVM data - * @n_pnvm_regions: number of DRAM regions that were allocated for the pnvm - * @pnvm_regions_desc_array: array of PNVM payloads addresses. - * allocated in DRAM and sent to FW. + * @pnvm_data: holds info about pnvm payloads allocated in DRAM + * @reduced_tables_data: holds info about power reduced tablse + * payloads allocated in DRAM * @pci_dev: basic pci-network driver stuff * @hw_base: pci hardware address support * @ucode_write_complete: indicates that the ucode has been copied. @@ -385,10 +384,8 @@ struct iwl_trans_pcie { struct iwl_dma_ptr kw; /* pnvm data */ - struct iwl_dram_data pnvm_dram[IPC_DRAM_MAP_ENTRY_NUM_MAX]; - u8 n_pnvm_regions; - struct iwl_dram_data pnvm_regions_desc_array; - struct iwl_dram_data reduce_power_dram; + struct iwl_dram_regions pnvm_data; + struct iwl_dram_regions reduced_tables_data; struct iwl_txq *txq_memory; @@ -485,8 +482,8 @@ struct iwl_trans const struct pci_device_id *ent, const struct iwl_cfg_trans_params *cfg_trans); void iwl_trans_pcie_free(struct iwl_trans *trans); -void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie, - struct device *dev); +void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions, + struct device *dev); bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); #define _iwl_trans_pcie_grab_nic_access(trans) \ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 45215feee609..15419397ac73 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1995,25 +1995,27 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, trans_pcie->fw_reset_handshake = trans_cfg->fw_reset_handshake; } -void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie, - struct device *dev) +void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions, + struct device *dev) { u8 i; - struct iwl_dram_data *desc_dram = &trans_pcie->pnvm_regions_desc_array; + struct iwl_dram_data *desc_dram = &dram_regions->prph_scratch_mem_desc; - for (i = 0; i < trans_pcie->n_pnvm_regions; i++) { - dma_free_coherent(dev, trans_pcie->pnvm_dram[i].size, - trans_pcie->pnvm_dram[i].block, - trans_pcie->pnvm_dram[i].physical); + /* free DRAM payloads */ + for (i = 0; i < dram_regions->n_regions; i++) { + dma_free_coherent(dev, dram_regions->drams[i].size, + dram_regions->drams[i].block, + dram_regions->drams[i].physical); } - trans_pcie->n_pnvm_regions = 0; + dram_regions->n_regions = 0; + /* free DRAM addresses array */ if (desc_dram->block) { dma_free_coherent(dev, desc_dram->size, desc_dram->block, desc_dram->physical); } - desc_dram->block = NULL; + memset(desc_dram, 0, sizeof(*desc_dram)); } void iwl_trans_pcie_free(struct iwl_trans *trans) @@ -2048,13 +2050,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) iwl_pcie_free_fw_monitor(trans); - iwl_trans_pcie_free_pnvm_dram(trans_pcie, trans->dev); - - if (trans_pcie->reduce_power_dram.size) - dma_free_coherent(trans->dev, - trans_pcie->reduce_power_dram.size, - trans_pcie->reduce_power_dram.block, - trans_pcie->reduce_power_dram.physical); + iwl_trans_pcie_free_pnvm_dram_regions(&trans_pcie->pnvm_data, + trans->dev); + iwl_trans_pcie_free_pnvm_dram_regions(&trans_pcie->reduced_tables_data, + trans->dev); mutex_destroy(&trans_pcie->mutex); iwl_trans_free(trans); -- cgit v1.2.3 From 380bf72d1b1dc3cb2572acd9b61153e79413b036 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:07 +0300 Subject: wifi: iwlwifi: Separate reading and parsing of reduce power table It enables to better handle error cases. Also save the image till the end of the loading and only then free it. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.71e3b3e0e794.Ifbe69ad99a7e805eb70e09280365821eb146b1c9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 40 ++++++++++++++++---------- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 31 +++++++++----------- drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 27 ++++++++++------- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 2 ++ 4 files changed, 58 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index b556abece896..3b5a3c89fedf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -319,29 +319,39 @@ int iwl_pnvm_load(struct iwl_trans *trans, reduce_tables: /* now try to get the reduce power table, if not loaded yet */ + if (trans->failed_to_load_reduce_power_image) + goto notification; + if (!trans->reduce_power_loaded) { memset(&pnvm_data, 0, sizeof(pnvm_data)); - ret = iwl_uefi_get_reduced_power(trans, &pnvm_data); + data = iwl_uefi_get_reduced_power(trans, &length); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + trans->failed_to_load_reduce_power_image = true; + goto notification; + } + + ret = iwl_uefi_reduce_power_parse(trans, data, length, + &pnvm_data); if (ret) { - /* - * Pretend we've loaded it - at least we've tried and - * couldn't load it at all, so there's no point in - * trying again over and over. - */ - trans->reduce_power_loaded = true; - } else { - ret = iwl_trans_load_reduce_power(trans, &pnvm_data, capa); - if (ret) { - IWL_DEBUG_FW(trans, - "Failed to load reduce power table %d\n", - ret); - trans->reduce_power_loaded = true; - } + trans->failed_to_load_reduce_power_image = true; kfree(data); + goto notification; + } + + ret = iwl_trans_load_reduce_power(trans, &pnvm_data, capa); + kfree(data); + if (ret) { + IWL_DEBUG_FW(trans, + "Failed to load reduce power table %d\n", + ret); + trans->failed_to_load_reduce_power_image = true; + goto notification; } } iwl_trans_set_reduce_power(trans, capa); +notification: iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), iwl_pnvm_complete_fn, trans); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 64b45a5b767e..1666ef3a482e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright(c) 2021-2022 Intel Corporation + * Copyright(c) 2021-2023 Intel Corporation */ #include "iwl-drv.h" @@ -123,9 +123,9 @@ done: return 0; } -static int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, - const u8 *data, size_t len, - struct iwl_pnvm_image *pnvm_data) +int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; @@ -181,17 +181,15 @@ static int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, return -ENOENT; } -int iwl_uefi_get_reduced_power(struct iwl_trans *trans, - struct iwl_pnvm_image *pnvm_data) +u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) { struct pnvm_sku_package *package; unsigned long package_size; efi_status_t status; - int ret; - size_t len = 0; + u8 *data; if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) - return -ENODEV; + return ERR_PTR(-ENODEV); /* * TODO: we hardcode a maximum length here, because reading @@ -202,7 +200,7 @@ int iwl_uefi_get_reduced_power(struct iwl_trans *trans, package = kmalloc(package_size, GFP_KERNEL); if (!package) - return -ENOMEM; + return ERR_PTR(-ENOMEM); status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID, NULL, &package_size, package); @@ -211,23 +209,22 @@ int iwl_uefi_get_reduced_power(struct iwl_trans *trans, "Reduced Power UEFI variable not found 0x%lx (len %lu)\n", status, package_size); kfree(package); - return -ENOENT; + return ERR_PTR(-ENOENT); } IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n", package_size); - len = package_size; IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", package->rev, package->total_size, package->n_skus); - ret = iwl_uefi_reduce_power_parse(trans, package->data, - len - sizeof(*package), - pnvm_data); - + *len = package_size - sizeof(*package); + data = kmemdup(package->data, *len, GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); kfree(package); - return ret; + return data; } static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 03176f73151a..10bed372e67c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright(c) 2021-2022 Intel Corporation + * Copyright(c) 2021-2023 Intel Corporation */ #ifndef __iwl_fw_uefi__ #define __iwl_fw_uefi__ @@ -50,25 +50,32 @@ struct uefi_cnv_common_step_data { */ #ifdef CONFIG_EFI void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len); -int iwl_uefi_get_reduced_power(struct iwl_trans *trans, - struct iwl_pnvm_image *pnvm_data); +u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); +int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data); void iwl_uefi_get_step_table(struct iwl_trans *trans); #else /* CONFIG_EFI */ -static inline -void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { return ERR_PTR(-EOPNOTSUPP); } -static inline -int iwl_uefi_get_reduced_power(struct iwl_trans *trans, - struct iwl_pnvm_image *pnvm_data) +static inline int +iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data) { return -EOPNOTSUPP; } -static inline -void iwl_uefi_get_step_table(struct iwl_trans *trans) +static inline u8 * +iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +static inline void iwl_uefi_get_step_table(struct iwl_trans *trans) { } #endif /* CONFIG_EFI */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index eb32683c36fb..d9e465d0f4af 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1047,6 +1047,7 @@ struct iwl_trans_txqs { * @pm_support: set to true in start_hw if link pm is supported * @ltr_enabled: set to true if the LTR is enabled * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed + * @failed_to_load_reduce_power_image: set to true if pnvm loading failed * @wide_cmd_header: true when ucode supports wide command header format * @wait_command_queue: wait queue for sync commands * @num_rx_queues: number of RX queues allocated by the transport; @@ -1096,6 +1097,7 @@ struct iwl_trans { u8 pnvm_loaded:1; u8 fail_to_parse_pnvm_image:1; u8 reduce_power_loaded:1; + u8 failed_to_load_reduce_power_image:1; const struct iwl_hcmd_arr *command_groups; int command_groups_size; -- cgit v1.2.3 From 875d035f37ec06a27c61abd9103178ae5a674672 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 10:43:08 +0300 Subject: wifi: iwlwifi: fw: clean up PNVM loading code This code is a bit of a maze of gotos etc. Clean up the code a bit to make the intent clearer. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.51fb5ee63f21.I20f270b2d47612e84643dc235c2940b8d9ed9930@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 155 +++++++++++++++------------ 1 file changed, 89 insertions(+), 66 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 3b5a3c89fedf..82eb32e67a2c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -270,88 +270,111 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) return image; } -int iwl_pnvm_load(struct iwl_trans *trans, - struct iwl_notif_wait_data *notif_wait, - const struct iwl_ucode_capabilities *capa) +static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) { - u8 *data; + struct iwl_pnvm_image *pnvm_data = NULL; + u8 *data = NULL; size_t length; - struct iwl_notification_wait pnvm_wait; - static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, - PNVM_INIT_COMPLETE_NTFY) }; - struct iwl_pnvm_image pnvm_data; int ret; - /* if the SKU_ID is empty, there's nothing to do */ - if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2]) - return 0; - - /* failed to get/parse the image in the past, no use to try again */ + /* failed to get/parse the image in the past, no use trying again */ if (trans->fail_to_parse_pnvm_image) - goto reduce_tables; - - /* get the image, parse and load it, if not loaded yet */ - if (!trans->pnvm_loaded) { - data = iwl_get_pnvm_image(trans, &length); - if (!data) { - trans->fail_to_parse_pnvm_image = true; - goto reduce_tables; - } - ret = iwl_pnvm_parse(trans, data, length, &pnvm_data); - if (ret) { - trans->fail_to_parse_pnvm_image = true; - kfree(data); - goto reduce_tables; - } + return; + + if (trans->pnvm_loaded) + goto set; - ret = iwl_trans_load_pnvm(trans, &pnvm_data, capa); - /* can only free data after pvnm_data use, but - * pnvm_data.version used below is not a pointer - */ - kfree(data); - if (ret) - goto reduce_tables; - IWL_INFO(trans, "loaded PNVM version %08x\n", - pnvm_data.version); + data = iwl_get_pnvm_image(trans, &length); + if (!data) { + trans->fail_to_parse_pnvm_image = true; + return; } + pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); + if (!pnvm_data) + goto free; + + ret = iwl_pnvm_parse(trans, data, length, pnvm_data); + if (ret) { + trans->fail_to_parse_pnvm_image = true; + goto free; + } + + ret = iwl_trans_load_pnvm(trans, pnvm_data, capa); + if (ret) + goto free; + IWL_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); + +set: iwl_trans_set_pnvm(trans, capa); +free: + kfree(data); + kfree(pnvm_data); +} + +static void +iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) +{ + struct iwl_pnvm_image *pnvm_data = NULL; + u8 *data = NULL; + size_t length; + int ret; -reduce_tables: - /* now try to get the reduce power table, if not loaded yet */ if (trans->failed_to_load_reduce_power_image) - goto notification; - - if (!trans->reduce_power_loaded) { - memset(&pnvm_data, 0, sizeof(pnvm_data)); - data = iwl_uefi_get_reduced_power(trans, &length); - if (IS_ERR(data)) { - ret = PTR_ERR(data); - trans->failed_to_load_reduce_power_image = true; - goto notification; - } + return; - ret = iwl_uefi_reduce_power_parse(trans, data, length, - &pnvm_data); - if (ret) { - trans->failed_to_load_reduce_power_image = true; - kfree(data); - goto notification; - } + if (trans->reduce_power_loaded) + goto set; - ret = iwl_trans_load_reduce_power(trans, &pnvm_data, capa); - kfree(data); - if (ret) { - IWL_DEBUG_FW(trans, - "Failed to load reduce power table %d\n", - ret); - trans->failed_to_load_reduce_power_image = true; - goto notification; - } + data = iwl_uefi_get_reduced_power(trans, &length); + if (IS_ERR(data)) { + trans->failed_to_load_reduce_power_image = true; + return; } + + pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); + if (!pnvm_data) + goto free; + + ret = iwl_uefi_reduce_power_parse(trans, data, length, pnvm_data); + if (ret) { + trans->failed_to_load_reduce_power_image = true; + goto free; + } + + ret = iwl_trans_load_reduce_power(trans, pnvm_data, capa); + if (ret) { + IWL_DEBUG_FW(trans, + "Failed to load reduce power table %d\n", + ret); + trans->failed_to_load_reduce_power_image = true; + goto free; + } + +set: iwl_trans_set_reduce_power(trans, capa); +free: + kfree(data); + kfree(pnvm_data); +} + +int iwl_pnvm_load(struct iwl_trans *trans, + struct iwl_notif_wait_data *notif_wait, + const struct iwl_ucode_capabilities *capa) +{ + struct iwl_notification_wait pnvm_wait; + static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, + PNVM_INIT_COMPLETE_NTFY) }; + + /* if the SKU_ID is empty, there's nothing to do */ + if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2]) + return 0; + + iwl_pnvm_load_pnvm_to_trans(trans, capa); + iwl_pnvm_load_reduce_power_to_trans(trans, capa); -notification: iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), iwl_pnvm_complete_fn, trans); -- cgit v1.2.3 From 8ae3e23195188a925b9a3e05f34f114441d97e14 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 6 Jun 2023 10:43:09 +0300 Subject: wifi: iwlwifi: fw: don't use constant size with efi.get_variable Use efi.get_variable() with NULL pointer for data in order to obtain entry size and then call it again with the correct size to get the entry itself. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.ef95a8055a50.Iae5389baaf0a9a3c89469f7502275ee119d378b6@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 143 ++++++++++++++------------- drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 13 +-- 2 files changed, 74 insertions(+), 82 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 1666ef3a482e..488b9fb79743 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -17,38 +17,53 @@ 0xb2, 0xec, 0xf5, 0xa3, \ 0x59, 0x4f, 0x4a, 0xea) -void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid, + unsigned long *data_size) { - void *data; - unsigned long package_size; efi_status_t status; + void *data; - *len = 0; + if (!data_size) + return ERR_PTR(-EINVAL); if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) return ERR_PTR(-ENODEV); - /* - * TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_PNVM_SIZE; + /* first call with NULL data to get the exact entry size */ + *data_size = 0; + status = efi.get_variable(name, guid, NULL, data_size, NULL); + if (status != EFI_BUFFER_TOO_SMALL || !*data_size) + return ERR_PTR(-EIO); - data = kmalloc(package_size, GFP_KERNEL); + data = kmalloc(*data_size, GFP_KERNEL); if (!data) return ERR_PTR(-ENOMEM); - status = efi.get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID, - NULL, &package_size, data); + status = efi.get_variable(name, guid, NULL, data_size, data); if (status != EFI_SUCCESS) { - IWL_DEBUG_FW(trans, - "PNVM UEFI variable not found 0x%lx (len %lu)\n", - status, package_size); kfree(data); return ERR_PTR(-ENOENT); } + return data; +} + +void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +{ + unsigned long package_size; + void *data; + + *len = 0; + + data = iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID, + &package_size); + if (IS_ERR(data)) { + IWL_DEBUG_FW(trans, + "PNVM UEFI variable not found 0x%lx (len %lu)\n", + PTR_ERR(data), package_size); + return data; + } + IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %lu\n", package_size); *len = package_size; @@ -185,31 +200,24 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) { struct pnvm_sku_package *package; unsigned long package_size; - efi_status_t status; u8 *data; - if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) - return ERR_PTR(-ENODEV); - - /* - * TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_REDUCE_POWER_SIZE; + package = iwl_uefi_get_variable(IWL_UEFI_REDUCED_POWER_NAME, + &IWL_EFI_VAR_GUID, &package_size); - package = kmalloc(package_size, GFP_KERNEL); - if (!package) - return ERR_PTR(-ENOMEM); - - status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID, - NULL, &package_size, package); - if (status != EFI_SUCCESS) { + if (IS_ERR(package)) { IWL_DEBUG_FW(trans, "Reduced Power UEFI variable not found 0x%lx (len %lu)\n", - status, package_size); + PTR_ERR(package), package_size); + return ERR_CAST(package); + } + + if (package_size < sizeof(*package)) { + IWL_DEBUG_FW(trans, + "Invalid Reduced Power UEFI variable len (%lu)\n", + package_size); kfree(package); - return ERR_PTR(-ENOENT); + return ERR_PTR(-EINVAL); } IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n", @@ -220,8 +228,11 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) *len = package_size - sizeof(*package); data = kmemdup(package->data, *len, GFP_KERNEL); - if (!data) + if (!data) { + kfree(package); return ERR_PTR(-ENOMEM); + } + kfree(package); return data; @@ -245,31 +256,27 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans) { struct uefi_cnv_common_step_data *data; unsigned long package_size; - efi_status_t status; int ret; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return; - if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) - return; + data = iwl_uefi_get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID, + &package_size); - /* TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_STEP_SIZE; - - data = kmalloc(package_size, GFP_KERNEL); - if (!data) + if (IS_ERR(data)) { + IWL_DEBUG_FW(trans, + "STEP UEFI variable not found 0x%lx\n", + PTR_ERR(data)); return; + } - status = efi.get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID, - NULL, &package_size, data); - if (status != EFI_SUCCESS) { + if (package_size < sizeof(*data)) { IWL_DEBUG_FW(trans, - "STEP UEFI variable not found 0x%lx\n", status); - goto out_free; + "Invalid STEP table UEFI variable len (%lu)\n", + package_size); + kfree(data); + return; } IWL_DEBUG_FW(trans, "Read STEP from UEFI with size %lu\n", @@ -279,7 +286,6 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans) if (ret < 0) IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n"); -out_free: kfree(data); } IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table); @@ -322,29 +328,26 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, { struct uefi_cnv_wlan_sgom_data *data; unsigned long package_size; - efi_status_t status; int ret; - if (!fwrt->geo_enabled || - !efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) + if (!fwrt->geo_enabled) return; - /* TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_SGOM_SIZE; - - data = kmalloc(package_size, GFP_KERNEL); - if (!data) + data = iwl_uefi_get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID, + &package_size); + if (IS_ERR(data)) { + IWL_DEBUG_FW(trans, + "SGOM UEFI variable not found 0x%lx\n", + PTR_ERR(data)); return; + } - status = efi.get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID, - NULL, &package_size, data); - if (status != EFI_SUCCESS) { + if (package_size < sizeof(*data)) { IWL_DEBUG_FW(trans, - "SGOM UEFI variable not found 0x%lx\n", status); - goto out_free; + "Invalid SGOM table UEFI variable len (%lu)\n", + package_size); + kfree(data); + return; } IWL_DEBUG_FW(trans, "Read SGOM from UEFI with size %lu\n", @@ -354,9 +357,7 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, if (ret < 0) IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n"); -out_free: kfree(data); - } IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table); #endif /* CONFIG_ACPI */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 10bed372e67c..dc7ccf49d92d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -10,16 +10,7 @@ #define IWL_UEFI_SGOM_NAME L"UefiCnvWlanSarGeoOffsetMapping" #define IWL_UEFI_STEP_NAME L"UefiCnvCommonSTEP" -/* - * TODO: we have these hardcoded values that the caller must pass, - * because reading from the UEFI is not working. To implement this - * properly, we have to change iwl_pnvm_get_from_uefi() to call - * efivar_entry_size() and return the value to the caller instead. - */ -#define IWL_HARDCODED_PNVM_SIZE 4096 -#define IWL_HARDCODED_REDUCE_POWER_SIZE 32768 -#define IWL_HARDCODED_SGOM_SIZE 339 -#define IWL_HARDCODED_STEP_SIZE 6 +#define IWL_SGOM_MAP_SIZE 339 struct pnvm_sku_package { u8 rev; @@ -31,7 +22,7 @@ struct pnvm_sku_package { struct uefi_cnv_wlan_sgom_data { u8 revision; - u8 offset_map[IWL_HARDCODED_SGOM_SIZE - 1]; + u8 offset_map[IWL_SGOM_MAP_SIZE - 1]; } __packed; struct uefi_cnv_common_step_data { -- cgit v1.2.3 From 372a714808c8ec4f4ae4915c734d80d7f504997c Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 6 Jun 2023 10:43:10 +0300 Subject: wifi: iwlwifi: pnvm: handle memory descriptor tlv When PNVM is obtained from UEFI, there's an additional memory descriptor TLV that has to be handled. It is the same TLV that holds data in the reduced power tables. Also, in this TLV, the actual data is located after address and size, so add the corresponding offset. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.8c5f5ee8e30b.Id1893c9dec140b5ba4abe8a121c2e1a1d121d2d7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 5 +++ drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 62 ++++++++++++++++++++-------- drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 9 ++++ 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 82eb32e67a2c..650e4bde9c17 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -127,6 +127,11 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, break; } + case IWL_UCODE_TLV_MEM_DESC: + if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len, + pnvm_data)) + return -EINVAL; + break; case IWL_UCODE_TLV_PNVM_SKU: IWL_DEBUG_FW(trans, "New PNVM section started, stop parsing.\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 488b9fb79743..9877988db0d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -17,6 +17,12 @@ 0xb2, 0xec, 0xf5, 0xa3, \ 0x59, 0x4f, 0x4a, 0xea) +struct iwl_uefi_pnvm_mem_desc { + __le32 addr; + __le32 size; + const u8 data[]; +} __packed; + static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid, unsigned long *data_size) { @@ -70,6 +76,42 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) return data; } +int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, + u32 tlv_len, struct iwl_pnvm_image *pnvm_data) +{ + const struct iwl_uefi_pnvm_mem_desc *desc = (const void *)data; + u32 data_len; + + if (tlv_len < sizeof(*desc)) { + IWL_DEBUG_FW(trans, "TLV len (%d) is too small\n", tlv_len); + return -EINVAL; + } + + data_len = tlv_len - sizeof(*desc); + + IWL_DEBUG_FW(trans, + "Handle IWL_UCODE_TLV_MEM_DESC, len %d data_len %d\n", + tlv_len, data_len); + + if (le32_to_cpu(desc->size) != data_len) { + IWL_DEBUG_FW(trans, "invalid mem desc size %d\n", desc->size); + return -EINVAL; + } + + if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { + IWL_DEBUG_FW(trans, "too many payloads to allocate in DRAM.\n"); + return -EINVAL; + } + + IWL_DEBUG_FW(trans, "Adding data (size %d)\n", data_len); + + pnvm_data->chunks[pnvm_data->n_chunks].data = desc->data; + pnvm_data->chunks[pnvm_data->n_chunks].len = data_len; + pnvm_data->n_chunks++; + + return 0; +} + static int iwl_uefi_reduce_power_section(struct iwl_trans *trans, const u8 *data, size_t len, struct iwl_pnvm_image *pnvm_data) @@ -97,25 +139,11 @@ static int iwl_uefi_reduce_power_section(struct iwl_trans *trans, data += sizeof(*tlv); switch (tlv_type) { - case IWL_UCODE_TLV_MEM_DESC: { - IWL_DEBUG_FW(trans, - "Got IWL_UCODE_TLV_MEM_DESC len %d\n", - tlv_len); - - if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { - IWL_DEBUG_FW(trans, - "too many payloads to allocate in DRAM.\n"); + case IWL_UCODE_TLV_MEM_DESC: + if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len, + pnvm_data)) return -EINVAL; - } - - IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len); - - pnvm_data->chunks[pnvm_data->n_chunks].data = data; - pnvm_data->chunks[pnvm_data->n_chunks].len = tlv_len; - pnvm_data->n_chunks++; - break; - } case IWL_UCODE_TLV_PNVM_SKU: IWL_DEBUG_FW(trans, "New REDUCE_POWER section started, stop parsing.\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index dc7ccf49d92d..1369cc4855c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -46,6 +46,8 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, const u8 *data, size_t len, struct iwl_pnvm_image *pnvm_data); void iwl_uefi_get_step_table(struct iwl_trans *trans); +int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, + u32 tlv_len, struct iwl_pnvm_image *pnvm_data); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -69,6 +71,13 @@ iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) static inline void iwl_uefi_get_step_table(struct iwl_trans *trans) { } + +static inline int +iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, + u32 tlv_len, struct iwl_pnvm_image *pnvm_data) +{ + return 0; +} #endif /* CONFIG_EFI */ #if defined(CONFIG_EFI) && defined(CONFIG_ACPI) -- cgit v1.2.3 From acb8bca343f8d5b8697d027771abf8a371580d53 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 May 2023 16:45:05 +0300 Subject: wifi: mac80211: HW restart for MLO Implement proper reconfiguration for interfaces that are doing MLO, in order to be able to recover from HW restart correctly. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230504134511.828474-6-gregory.greenman@intel.com Signed-off-by: Johannes Berg --- net/mac80211/util.c | 107 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1527d6aafc14..75c517dc8bee 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2624,21 +2624,55 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { + /* common change flags for all interface types - link only */ + u32 changed = BSS_CHANGED_ERP_CTS_PROT | + BSS_CHANGED_ERP_PREAMBLE | + BSS_CHANGED_ERP_SLOT | + BSS_CHANGED_HT | + BSS_CHANGED_BASIC_RATES | + BSS_CHANGED_BEACON_INT | + BSS_CHANGED_BSSID | + BSS_CHANGED_CQM | + BSS_CHANGED_QOS | + BSS_CHANGED_TXPOWER | + BSS_CHANGED_MCAST_RATE; + struct ieee80211_link_data *link = NULL; unsigned int link_id; - u32 changed; + u32 active_links = 0; if (!ieee80211_sdata_running(sdata)) continue; sdata_lock(sdata); + if (sdata->vif.valid_links) { + struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS] = { + [0] = &sdata->vif.bss_conf, + }; + + if (sdata->vif.type == NL80211_IFTYPE_STATION) { + /* start with a single active link */ + active_links = sdata->vif.active_links; + link_id = ffs(active_links) - 1; + sdata->vif.active_links = BIT(link_id); + } + + drv_change_vif_links(local, sdata, 0, + sdata->vif.active_links, + old); + } + for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) { - struct ieee80211_link_data *link; + if (sdata->vif.valid_links && + !(sdata->vif.active_links & BIT(link_id))) + continue; link = sdata_dereference(sdata->link[link_id], sdata); - if (link) - ieee80211_assign_chanctx(local, sdata, link); + if (!link) + continue; + + ieee80211_assign_chanctx(local, sdata, link); } switch (sdata->vif.type) { @@ -2658,42 +2692,42 @@ int ieee80211_reconfig(struct ieee80211_local *local) &sdata->deflink.tx_conf[i]); break; } - sdata_unlock(sdata); - - /* common change flags for all interface types */ - changed = BSS_CHANGED_ERP_CTS_PROT | - BSS_CHANGED_ERP_PREAMBLE | - BSS_CHANGED_ERP_SLOT | - BSS_CHANGED_HT | - BSS_CHANGED_BASIC_RATES | - BSS_CHANGED_BEACON_INT | - BSS_CHANGED_BSSID | - BSS_CHANGED_CQM | - BSS_CHANGED_QOS | - BSS_CHANGED_IDLE | - BSS_CHANGED_TXPOWER | - BSS_CHANGED_MCAST_RATE; if (sdata->vif.bss_conf.mu_mimo_owner) changed |= BSS_CHANGED_MU_GROUPS; + if (!sdata->vif.valid_links) + changed |= BSS_CHANGED_IDLE; + switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: - changed |= BSS_CHANGED_ASSOC | - BSS_CHANGED_ARP_FILTER | - BSS_CHANGED_PS; - - /* Re-send beacon info report to the driver */ - if (sdata->deflink.u.mgd.have_beacon) - changed |= BSS_CHANGED_BEACON_INFO; - - if (sdata->vif.bss_conf.max_idle_period || - sdata->vif.bss_conf.protected_keep_alive) - changed |= BSS_CHANGED_KEEP_ALIVE; - - sdata_lock(sdata); - ieee80211_bss_info_change_notify(sdata, changed); - sdata_unlock(sdata); + if (!sdata->vif.valid_links) { + changed |= BSS_CHANGED_ASSOC | + BSS_CHANGED_ARP_FILTER | + BSS_CHANGED_PS; + + /* Re-send beacon info report to the driver */ + if (sdata->deflink.u.mgd.have_beacon) + changed |= BSS_CHANGED_BEACON_INFO; + + if (sdata->vif.bss_conf.max_idle_period || + sdata->vif.bss_conf.protected_keep_alive) + changed |= BSS_CHANGED_KEEP_ALIVE; + + if (sdata->vif.bss_conf.eht_puncturing) + changed |= BSS_CHANGED_EHT_PUNCTURING; + + ieee80211_bss_info_change_notify(sdata, + changed); + } else if (!WARN_ON(!link)) { + ieee80211_link_info_change_notify(sdata, link, + changed); + changed = BSS_CHANGED_ASSOC | + BSS_CHANGED_IDLE | + BSS_CHANGED_PS | + BSS_CHANGED_ARP_FILTER; + ieee80211_vif_cfg_change_notify(sdata, changed); + } break; case NL80211_IFTYPE_OCB: changed |= BSS_CHANGED_OCB; @@ -2728,6 +2762,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_NAN: res = ieee80211_reconfig_nan(sdata); if (res < 0) { + sdata_unlock(sdata); ieee80211_handle_reconfig_failure(local); return res; } @@ -2745,6 +2780,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) WARN_ON(1); break; } + sdata_unlock(sdata); + + if (active_links) + ieee80211_set_active_links(&sdata->vif, active_links); } ieee80211_recalc_ps(local); -- cgit v1.2.3 From 91f53ae97cb1a8c1c26f6cbcf9e2dc1cdff9b012 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:13:20 +0200 Subject: wifi: mac80211: remove element scratch_len This isn't used, and there isn't really a good way it could be used, so just remove that. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 3 --- net/mac80211/util.c | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a0a7839cb961..007b36c7db53 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2269,8 +2269,6 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, * (or re-association) response frame if this is given * @from_ap: frame is received from an AP (currently used only * for EHT capabilities parsing) - * @scratch_len: if non zero, specifies the requested length of the scratch - * buffer; otherwise, 'len' is used. */ struct ieee80211_elems_parse_params { const u8 *start; @@ -2281,7 +2279,6 @@ struct ieee80211_elems_parse_params { struct cfg80211_bss *bss; int link_id; bool from_ap; - size_t scratch_len; }; struct ieee802_11_elems * diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 75c517dc8bee..22871e4a9f0f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1604,7 +1604,7 @@ ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params) const struct element *non_inherit = NULL; u8 *nontransmitted_profile; int nontransmitted_profile_len = 0; - size_t scratch_len = params->scratch_len ?: 3 * params->len; + size_t scratch_len = 3 * params->len; elems = kzalloc(sizeof(*elems) + scratch_len, GFP_ATOMIC); if (!elems) -- cgit v1.2.3 From 2d22be01b844c47771421ff8e0e68cecf967b7e3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 May 2023 16:45:07 +0300 Subject: wifi: mac80211_hwsim: avoid warning with MLO PS stations If the station disables all links it's in powersave and we shouldn't transmit anything to it, but we don't handle that correctly yet. For now, just avoid the warning, once we really add support for this case we can revert to the old warning. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230504134511.828474-8-gregory.greenman@intel.com Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 9a8faaf4c6b6..5ff193bcd4b9 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -1940,7 +1940,14 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, hdr, &link_sta); } - if (WARN_ON(!bss_conf)) { + if (unlikely(!bss_conf)) { + /* if it's an MLO STA, it might have deactivated all + * links temporarily - but we don't handle real PS in + * this code yet, so just drop the frame in that case + */ + WARN(link != IEEE80211_LINK_UNSPECIFIED || !sta || !sta->mlo, + "link:%d, sta:%pM, sta->mlo:%d\n", + link, sta ? sta->addr : NULL, sta ? sta->mlo : -1); ieee80211_free_txskb(hw, skb); return; } -- cgit v1.2.3 From 08dbff230048ec2812c33e78f81855635a3c1734 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 May 2023 16:45:08 +0300 Subject: wifi: mac80211: skip EHT BSS membership selector Skip the EHT BSS membership selector for getting rates. While at it, add the definitions for GLK and EPS, and sort the list. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230504134511.828474-9-gregory.greenman@intel.com Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 5 ++++- net/mac80211/mlme.c | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index c4cf296e7eaf..c271184a3968 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1349,8 +1349,11 @@ struct ieee80211_mgmt { /* Supported rates membership selectors */ #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 -#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122 +#define BSS_MEMBERSHIP_SELECTOR_GLK 125 +#define BSS_MEMBERSHIP_SELECTOR_EPS 124 #define BSS_MEMBERSHIP_SELECTOR_SAE_H2E 123 +#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122 +#define BSS_MEMBERSHIP_SELECTOR_EHT_PHY 121 /* mgmt header + 1 byte category code */ #define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e13a0354c397..0020c9e41caa 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3902,8 +3902,8 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, *have_higher_than_11mbit = true; /* - * Skip HT, VHT, HE and SAE H2E only BSS membership selectors - * since they're not rates. + * Skip HT, VHT, HE, EHT and SAE H2E only BSS membership + * selectors since they're not rates. * * Note: Even though the membership selector and the basic * rate flag share the same bit, they are not exactly @@ -3912,6 +3912,7 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, if (supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY) || supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY) || supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY) || + supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_EHT_PHY) || supp_rates[i] == (0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E)) continue; -- cgit v1.2.3 From ce2bb3b66273d7d122c5dbf8f1e58e8ebc82c5fb Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 4 May 2023 16:45:10 +0300 Subject: wifi: mac80211: fetch and store the EML capability information We need to teach the low level driver about the EML capability which includes information for EMLSR / EMLMR operation. Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230504134511.828474-11-gregory.greenman@intel.com Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 35 +++++++++++++++++++++++++++++++++++ include/net/mac80211.h | 2 ++ net/mac80211/mlme.c | 11 +++++++++++ 3 files changed, 48 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index c271184a3968..fba4c44da832 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4635,6 +4635,41 @@ static inline u8 ieee80211_mle_common_size(const u8 *data) return sizeof(*mle) + common + mle->variable[0]; } +/** + * ieee80211_mle_get_eml_cap - returns the EML capability + * @data: pointer to the multi link EHT IE + * + * The element is assumed to be big enough. This must be checked by + * ieee80211_mle_size_ok(). + * If the EML capability can't be found (the type is not basic, or + * the EML capability presence bit is clear), 0 will be returned. + */ +static inline u16 ieee80211_mle_get_eml_cap(const u8 *data) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u16 control = le16_to_cpu(mle->control); + const u8 *common = mle->variable; + + if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) != + IEEE80211_ML_CONTROL_TYPE_BASIC) + return 0; + + /* common points now at the beginning of ieee80211_mle_basic_common_info */ + common += sizeof(struct ieee80211_mle_basic_common_info); + + if (!(control & IEEE80211_MLC_BASIC_PRES_EML_CAPA)) + return 0; + + if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY) + common += 2; + + return get_unaligned_le16(common); +} + /** * ieee80211_mle_size_ok - validate multi-link element size * @data: pointer to the element data diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ac0370e76874..f75d941eece8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1790,6 +1790,7 @@ enum ieee80211_offload_flags { * @ps: power-save mode (STA only). This flag is NOT affected by * offchannel/dynamic_ps operations. * @aid: association ID number, valid only when @assoc is true + * @eml_cap: EML capabilities as described in P802.11be_D2.2 Figure 9-1002k. * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The * may filter ARP queries targeted for other addresses than listed here. * The driver must allow ARP queries targeted for all address listed here @@ -1812,6 +1813,7 @@ struct ieee80211_vif_cfg { bool ibss_creator; bool ps; u16 aid; + u16 eml_cap; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; int arp_addr_cnt; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0020c9e41caa..4ea383aafcac 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4838,6 +4838,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, IEEE80211_CONN_DISABLE_EHT)) && he_oper) { const struct cfg80211_bss_ies *cbss_ies; + const struct element *eht_ml_elem; const u8 *eht_oper_ie; cbss_ies = rcu_dereference(cbss->ies); @@ -4848,6 +4849,16 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, eht_oper = (void *)(eht_oper_ie + 3); else eht_oper = NULL; + + eht_ml_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK, + cbss_ies->data, cbss_ies->len); + + /* data + 1 / datalen - 1 since it's an extended element */ + if (eht_ml_elem && + ieee80211_mle_size_ok(eht_ml_elem->data + 1, + eht_ml_elem->datalen - 1)) + sdata->vif.cfg.eml_cap = + ieee80211_mle_get_eml_cap(eht_ml_elem->data + 1); } /* Allow VHT if at least one channel on the sband supports 80 MHz */ -- cgit v1.2.3 From 61403414e1719f929386dda8fb954bb302628ef3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 May 2023 16:45:11 +0300 Subject: wifi: mac80211: implement proper AP MLD HW restart Previously, I didn't implement restarting here at all if the interface is an MLD, so it only worked for non-MLO. Add the needed code to restart an AP MLD correctly. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230504134511.828474-12-gregory.greenman@intel.com Signed-off-by: Johannes Berg --- net/mac80211/util.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 22871e4a9f0f..7a9abe8bf438 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2475,6 +2475,35 @@ static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata) return 0; } +static void ieee80211_reconfig_ap_links(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + u32 changed) +{ + int link_id; + + for (link_id = 0; link_id < ARRAY_SIZE(sdata->link); link_id++) { + struct ieee80211_link_data *link; + + if (!(sdata->vif.active_links & BIT(link_id))) + continue; + + link = sdata_dereference(sdata->link[link_id], sdata); + if (!link) + continue; + + if (rcu_access_pointer(link->u.ap.beacon)) + drv_start_ap(local, sdata, link->conf); + + if (!link->conf->enable_beacon) + continue; + + changed |= BSS_CHANGED_BEACON | + BSS_CHANGED_BEACON_ENABLED; + + ieee80211_link_info_change_notify(sdata, link, changed); + } +} + int ieee80211_reconfig(struct ieee80211_local *local) { struct ieee80211_hw *hw = &local->hw; @@ -2737,7 +2766,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) changed |= BSS_CHANGED_IBSS; fallthrough; case NL80211_IFTYPE_AP: - changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS; + changed |= BSS_CHANGED_P2P_PS; + + if (sdata->vif.valid_links) + ieee80211_vif_cfg_change_notify(sdata, + BSS_CHANGED_SSID); + else + changed |= BSS_CHANGED_SSID; if (sdata->vif.bss_conf.ftm_responder == 1 && wiphy_ext_feature_isset(sdata->local->hw.wiphy, @@ -2747,6 +2782,13 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (sdata->vif.type == NL80211_IFTYPE_AP) { changed |= BSS_CHANGED_AP_PROBE_RESP; + if (sdata->vif.valid_links) { + ieee80211_reconfig_ap_links(local, + sdata, + changed); + break; + } + if (rcu_access_pointer(sdata->deflink.u.ap.beacon)) drv_start_ap(local, sdata, sdata->deflink.conf); -- cgit v1.2.3 From 2a5325f802863c399fe40de935ba01195d4c43c8 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Sun, 4 Jun 2023 12:11:13 +0300 Subject: wifi: mac80211: use u64 to hold enum ieee80211_bss_change flags The size of enum ieee80211_bss_change is bigger that 32, so we need u64 to be used in a flag. Also pass u64 instead of u32 to ieee80211_reconfig_ap_links() for the same reason. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.d53b7018a4eb.I1adaa041de51d50d84a11226573e81ceac0fe90d@changeid Signed-off-by: Johannes Berg --- net/mac80211/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7a9abe8bf438..3f24b6e59652 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2477,7 +2477,7 @@ static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata) static void ieee80211_reconfig_ap_links(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, - u32 changed) + u64 changed) { int link_id; @@ -2654,7 +2654,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Finally also reconfigure all the BSS information */ list_for_each_entry(sdata, &local->interfaces, list) { /* common change flags for all interface types - link only */ - u32 changed = BSS_CHANGED_ERP_CTS_PROT | + u64 changed = BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_SLOT | BSS_CHANGED_HT | -- cgit v1.2.3 From 1d10575bced5b65e138b029a35e6ef657f3b3273 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Sun, 4 Jun 2023 12:11:14 +0300 Subject: wifi: mac80211: refactor ieee80211_select_link_key() Simplify ieee80211_select_link_key(), no functional changes are made. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.a4e332755bb0.Iff4a2b6ed767b2a329c51c29bb597ece9ebe2af8@changeid Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1a3327407552..e809c4236f78 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -581,25 +581,9 @@ ieee80211_select_link_key(struct ieee80211_tx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); - enum { - USE_NONE, - USE_MGMT_KEY, - USE_MCAST_KEY, - } which_key = USE_NONE; struct ieee80211_link_data *link; unsigned int link_id; - if (ieee80211_is_group_privacy_action(tx->skb)) - which_key = USE_MCAST_KEY; - else if (ieee80211_is_mgmt(hdr->frame_control) && - is_multicast_ether_addr(hdr->addr1) && - ieee80211_is_robust_mgmt_frame(tx->skb)) - which_key = USE_MGMT_KEY; - else if (is_multicast_ether_addr(hdr->addr1)) - which_key = USE_MCAST_KEY; - else - return NULL; - link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK); if (link_id == IEEE80211_LINK_UNSPECIFIED) { link = &tx->sdata->deflink; @@ -609,14 +593,14 @@ ieee80211_select_link_key(struct ieee80211_tx_data *tx) return NULL; } - switch (which_key) { - case USE_NONE: - break; - case USE_MGMT_KEY: + if (ieee80211_is_group_privacy_action(tx->skb)) + return rcu_dereference(link->default_multicast_key); + else if (ieee80211_is_mgmt(hdr->frame_control) && + is_multicast_ether_addr(hdr->addr1) && + ieee80211_is_robust_mgmt_frame(tx->skb)) return rcu_dereference(link->default_mgmt_key); - case USE_MCAST_KEY: + else if (is_multicast_ether_addr(hdr->addr1)) return rcu_dereference(link->default_multicast_key); - } return NULL; } -- cgit v1.2.3 From 29c6e2dc3d12a188a48f2a45759e8da44840546b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 4 Jun 2023 12:11:17 +0300 Subject: wifi: mac80211: provide a helper to fetch the medium synchronization delay There are drivers which need this information. Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.b1043f3126e2.Iad3806f8bf8df07f52ef0a02cc3d0373c44a8c93@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 35 +++++++++++++++++++++++++++++++++++ include/net/mac80211.h | 3 +++ net/mac80211/mlme.c | 5 ++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index fba4c44da832..516cd32d6196 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4635,6 +4635,41 @@ static inline u8 ieee80211_mle_common_size(const u8 *data) return sizeof(*mle) + common + mle->variable[0]; } +/** + * ieee80211_mle_get_eml_sync_delay - returns the medium sync delay + * @data: pointer to the multi link EHT IE + * + * The element is assumed to be big enough. This must be checked by + * ieee80211_mle_size_ok(). + * If the medium synchronization can't be found (the type is not basic, or + * the medium sync presence bit is clear), 0 will be returned. + */ +static inline u16 ieee80211_mle_get_eml_med_sync_delay(const u8 *data) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u16 control = le16_to_cpu(mle->control); + const u8 *common = mle->variable; + + if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) != + IEEE80211_ML_CONTROL_TYPE_BASIC) + return 0; + + /* common points now at the beginning of + * ieee80211_mle_basic_common_info + */ + common += sizeof(struct ieee80211_mle_basic_common_info); + + if (!(control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) + return 0; + + if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) + common += 1; + if (control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) + common += 1; + + return get_unaligned_le16(common); +} + /** * ieee80211_mle_get_eml_cap - returns the EML capability * @data: pointer to the multi link EHT IE diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f75d941eece8..f4516c034da2 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1791,6 +1791,8 @@ enum ieee80211_offload_flags { * offchannel/dynamic_ps operations. * @aid: association ID number, valid only when @assoc is true * @eml_cap: EML capabilities as described in P802.11be_D2.2 Figure 9-1002k. + * @eml_med_sync_delay: Medium Synchronization delay as described in + * P802.11be_D2.2 Figure 9-1002j. * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The * may filter ARP queries targeted for other addresses than listed here. * The driver must allow ARP queries targeted for all address listed here @@ -1814,6 +1816,7 @@ struct ieee80211_vif_cfg { bool ps; u16 aid; u16 eml_cap; + u16 eml_med_sync_delay; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; int arp_addr_cnt; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 4ea383aafcac..56c375213202 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4856,9 +4856,12 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, /* data + 1 / datalen - 1 since it's an extended element */ if (eht_ml_elem && ieee80211_mle_size_ok(eht_ml_elem->data + 1, - eht_ml_elem->datalen - 1)) + eht_ml_elem->datalen - 1)) { sdata->vif.cfg.eml_cap = ieee80211_mle_get_eml_cap(eht_ml_elem->data + 1); + sdata->vif.cfg.eml_med_sync_delay = + ieee80211_mle_get_eml_med_sync_delay(eht_ml_elem->data + 1); + } } /* Allow VHT if at least one channel on the sband supports 80 MHz */ -- cgit v1.2.3 From b970ac68e0c46aec8049ba69e621a3e62353d2ce Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Sun, 4 Jun 2023 12:11:19 +0300 Subject: wifi: mac80211_hwsim: check the return value of nla_put_u32 Check the return value of nla_put_u32() and handle it accordingly. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.de5168568cf6.Ie16442af9be879fd835506ba5dade780edecfb60@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 5ff193bcd4b9..b06a6e78169d 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -582,8 +582,9 @@ static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy, */ /* Add vendor data */ - nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1); - + err = nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1); + if (err) + return err; /* Send the event - this will call nla_nest_end() */ cfg80211_vendor_event(skb, GFP_KERNEL); } -- cgit v1.2.3 From ba7af2654e3b7b810c750b3c6106f6f20b81cc88 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Jun 2023 12:11:20 +0300 Subject: wifi: mac80211: recalc min chandef for new STA links When adding a new link to a station, this needs to cause a recalculation of the minimum chandef since otherwise we can have a higher bandwidth station connected on that link than the link is operating at. Do the appropriate recalc. Fixes: cb71f1d136a6 ("wifi: mac80211: add sta link addition/removal") Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.377adf3c789a.I91bf28f399e16e6ac1f83bacd1029a698b4e6685@changeid Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1400512e0dde..a1cd5c234f47 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2913,6 +2913,8 @@ int ieee80211_sta_activate_link(struct sta_info *sta, unsigned int link_id) if (!test_sta_flag(sta, WLAN_STA_INSERTED)) goto hash; + ieee80211_recalc_min_chandef(sdata, link_id); + /* Ensure the values are updated for the driver, * redone by sta_remove_link on failure. */ -- cgit v1.2.3 From 10a7ba92c7ab6cbac3c805ab3ee0642e91f1da97 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Jun 2023 12:11:21 +0300 Subject: wifi: mac80211: move sta_info_move_state() up To fix a sequencing issue, this code needs to be changed a bit. Move it up in the file to prepare for that. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.05bb735d7075.I984b5c194a0f84580247d73620a4e61a5f82a774@changeid Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 201 ++++++++++++++++++++++++------------------------ 1 file changed, 100 insertions(+), 101 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a1cd5c234f47..dc76bc40350f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -4,7 +4,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include @@ -1274,6 +1274,105 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta) return 0; } +int sta_info_move_state(struct sta_info *sta, + enum ieee80211_sta_state new_state) +{ + might_sleep(); + + if (sta->sta_state == new_state) + return 0; + + /* check allowed transitions first */ + + switch (new_state) { + case IEEE80211_STA_NONE: + if (sta->sta_state != IEEE80211_STA_AUTH) + return -EINVAL; + break; + case IEEE80211_STA_AUTH: + if (sta->sta_state != IEEE80211_STA_NONE && + sta->sta_state != IEEE80211_STA_ASSOC) + return -EINVAL; + break; + case IEEE80211_STA_ASSOC: + if (sta->sta_state != IEEE80211_STA_AUTH && + sta->sta_state != IEEE80211_STA_AUTHORIZED) + return -EINVAL; + break; + case IEEE80211_STA_AUTHORIZED: + if (sta->sta_state != IEEE80211_STA_ASSOC) + return -EINVAL; + break; + default: + WARN(1, "invalid state %d", new_state); + return -EINVAL; + } + + sta_dbg(sta->sdata, "moving STA %pM to state %d\n", + sta->sta.addr, new_state); + + /* notify the driver before the actual changes so it can + * fail the transition + */ + if (test_sta_flag(sta, WLAN_STA_INSERTED)) { + int err = drv_sta_state(sta->local, sta->sdata, sta, + sta->sta_state, new_state); + if (err) + return err; + } + + /* reflect the change in all state variables */ + + switch (new_state) { + case IEEE80211_STA_NONE: + if (sta->sta_state == IEEE80211_STA_AUTH) + clear_bit(WLAN_STA_AUTH, &sta->_flags); + break; + case IEEE80211_STA_AUTH: + if (sta->sta_state == IEEE80211_STA_NONE) { + set_bit(WLAN_STA_AUTH, &sta->_flags); + } else if (sta->sta_state == IEEE80211_STA_ASSOC) { + clear_bit(WLAN_STA_ASSOC, &sta->_flags); + ieee80211_recalc_min_chandef(sta->sdata, -1); + if (!sta->sta.support_p2p_ps) + ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); + } + break; + case IEEE80211_STA_ASSOC: + if (sta->sta_state == IEEE80211_STA_AUTH) { + set_bit(WLAN_STA_ASSOC, &sta->_flags); + sta->assoc_at = ktime_get_boottime_ns(); + ieee80211_recalc_min_chandef(sta->sdata, -1); + if (!sta->sta.support_p2p_ps) + ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); + } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { + ieee80211_vif_dec_num_mcast(sta->sdata); + clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); + ieee80211_clear_fast_xmit(sta); + ieee80211_clear_fast_rx(sta); + } + break; + case IEEE80211_STA_AUTHORIZED: + if (sta->sta_state == IEEE80211_STA_ASSOC) { + ieee80211_vif_inc_num_mcast(sta->sdata); + set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); + ieee80211_check_fast_xmit(sta); + ieee80211_check_fast_rx(sta); + } + if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN || + sta->sdata->vif.type == NL80211_IFTYPE_AP) + cfg80211_send_layer2_update(sta->sdata->dev, + sta->sta.addr); + break; + default: + break; + } + + sta->sta_state = new_state; + + return 0; +} + static void __sta_info_destroy_part2(struct sta_info *sta) { struct ieee80211_local *local = sta->local; @@ -2252,106 +2351,6 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, } } -int sta_info_move_state(struct sta_info *sta, - enum ieee80211_sta_state new_state) -{ - might_sleep(); - - if (sta->sta_state == new_state) - return 0; - - /* check allowed transitions first */ - - switch (new_state) { - case IEEE80211_STA_NONE: - if (sta->sta_state != IEEE80211_STA_AUTH) - return -EINVAL; - break; - case IEEE80211_STA_AUTH: - if (sta->sta_state != IEEE80211_STA_NONE && - sta->sta_state != IEEE80211_STA_ASSOC) - return -EINVAL; - break; - case IEEE80211_STA_ASSOC: - if (sta->sta_state != IEEE80211_STA_AUTH && - sta->sta_state != IEEE80211_STA_AUTHORIZED) - return -EINVAL; - break; - case IEEE80211_STA_AUTHORIZED: - if (sta->sta_state != IEEE80211_STA_ASSOC) - return -EINVAL; - break; - default: - WARN(1, "invalid state %d", new_state); - return -EINVAL; - } - - sta_dbg(sta->sdata, "moving STA %pM to state %d\n", - sta->sta.addr, new_state); - - /* - * notify the driver before the actual changes so it can - * fail the transition - */ - if (test_sta_flag(sta, WLAN_STA_INSERTED)) { - int err = drv_sta_state(sta->local, sta->sdata, sta, - sta->sta_state, new_state); - if (err) - return err; - } - - /* reflect the change in all state variables */ - - switch (new_state) { - case IEEE80211_STA_NONE: - if (sta->sta_state == IEEE80211_STA_AUTH) - clear_bit(WLAN_STA_AUTH, &sta->_flags); - break; - case IEEE80211_STA_AUTH: - if (sta->sta_state == IEEE80211_STA_NONE) { - set_bit(WLAN_STA_AUTH, &sta->_flags); - } else if (sta->sta_state == IEEE80211_STA_ASSOC) { - clear_bit(WLAN_STA_ASSOC, &sta->_flags); - ieee80211_recalc_min_chandef(sta->sdata, -1); - if (!sta->sta.support_p2p_ps) - ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); - } - break; - case IEEE80211_STA_ASSOC: - if (sta->sta_state == IEEE80211_STA_AUTH) { - set_bit(WLAN_STA_ASSOC, &sta->_flags); - sta->assoc_at = ktime_get_boottime_ns(); - ieee80211_recalc_min_chandef(sta->sdata, -1); - if (!sta->sta.support_p2p_ps) - ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); - } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { - ieee80211_vif_dec_num_mcast(sta->sdata); - clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); - ieee80211_clear_fast_xmit(sta); - ieee80211_clear_fast_rx(sta); - } - break; - case IEEE80211_STA_AUTHORIZED: - if (sta->sta_state == IEEE80211_STA_ASSOC) { - ieee80211_vif_inc_num_mcast(sta->sdata); - set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); - ieee80211_check_fast_xmit(sta); - ieee80211_check_fast_rx(sta); - } - if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN || - sta->sdata->vif.type == NL80211_IFTYPE_AP) - cfg80211_send_layer2_update(sta->sdata->dev, - sta->sta.addr); - break; - default: - break; - } - - sta->sta_state = new_state; - - return 0; -} - static struct ieee80211_sta_rx_stats * sta_get_last_rx_stats(struct sta_info *sta) { -- cgit v1.2.3 From 92747f17c431a75967b461bedbb36ff259acead1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Jun 2023 12:11:22 +0300 Subject: wifi: mac80211: batch recalc during STA flush When we flush stations, we first take them off the list and then destroy them one by one. If we do the different mode recalculations while destroying them, we cause the following scenario: - STA 1 has 80 MHz - min chanctx width is now 80 MHz - STA 2 has 80 MHz - empty STA list - destroy STA 2 - recalc min chanctx width -> results in 20 MHz as the STA list is already empty This is broken, since as far as the driver is concerned STA 1 still exists at this point, and this causes issues at least with iwlwifi. Fix - and also optimize - this by doing the recalc of min chanctx width (and also P2P PS) only after all the stations were removed. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.48d262b6b42d.Ia15532657c17535c28ec0c5df263b65f0f80663c@changeid Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index dc76bc40350f..731b832b257c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1274,8 +1274,9 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta) return 0; } -int sta_info_move_state(struct sta_info *sta, - enum ieee80211_sta_state new_state) +static int _sta_info_move_state(struct sta_info *sta, + enum ieee80211_sta_state new_state, + bool recalc) { might_sleep(); @@ -1333,18 +1334,22 @@ int sta_info_move_state(struct sta_info *sta, set_bit(WLAN_STA_AUTH, &sta->_flags); } else if (sta->sta_state == IEEE80211_STA_ASSOC) { clear_bit(WLAN_STA_ASSOC, &sta->_flags); - ieee80211_recalc_min_chandef(sta->sdata, -1); - if (!sta->sta.support_p2p_ps) - ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); + if (recalc) { + ieee80211_recalc_min_chandef(sta->sdata, -1); + if (!sta->sta.support_p2p_ps) + ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); + } } break; case IEEE80211_STA_ASSOC: if (sta->sta_state == IEEE80211_STA_AUTH) { set_bit(WLAN_STA_ASSOC, &sta->_flags); sta->assoc_at = ktime_get_boottime_ns(); - ieee80211_recalc_min_chandef(sta->sdata, -1); - if (!sta->sta.support_p2p_ps) - ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); + if (recalc) { + ieee80211_recalc_min_chandef(sta->sdata, -1); + if (!sta->sta.support_p2p_ps) + ieee80211_recalc_p2p_go_ps_allowed(sta->sdata); + } } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { ieee80211_vif_dec_num_mcast(sta->sdata); clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); @@ -1373,7 +1378,13 @@ int sta_info_move_state(struct sta_info *sta, return 0; } -static void __sta_info_destroy_part2(struct sta_info *sta) +int sta_info_move_state(struct sta_info *sta, + enum ieee80211_sta_state new_state) +{ + return _sta_info_move_state(sta, new_state, true); +} + +static void __sta_info_destroy_part2(struct sta_info *sta, bool recalc) { struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; @@ -1389,7 +1400,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta) lockdep_assert_held(&local->sta_mtx); if (sta->sta_state == IEEE80211_STA_AUTHORIZED) { - ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC); + ret = _sta_info_move_state(sta, IEEE80211_STA_ASSOC, recalc); WARN_ON_ONCE(ret); } @@ -1417,7 +1428,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta) local->sta_generation++; while (sta->sta_state > IEEE80211_STA_NONE) { - ret = sta_info_move_state(sta, sta->sta_state - 1); + ret = _sta_info_move_state(sta, sta->sta_state - 1, recalc); if (ret) { WARN_ON_ONCE(1); break; @@ -1454,7 +1465,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta) synchronize_net(); - __sta_info_destroy_part2(sta); + __sta_info_destroy_part2(sta, true); return 0; } @@ -1561,9 +1572,18 @@ int __sta_info_flush(struct ieee80211_sub_if_data *sdata, bool vlans) } if (!list_empty(&free_list)) { + bool support_p2p_ps = true; + synchronize_net(); - list_for_each_entry_safe(sta, tmp, &free_list, free_list) - __sta_info_destroy_part2(sta); + list_for_each_entry_safe(sta, tmp, &free_list, free_list) { + if (!sta->sta.support_p2p_ps) + support_p2p_ps = false; + __sta_info_destroy_part2(sta, false); + } + + ieee80211_recalc_min_chandef(sdata, -1); + if (!support_p2p_ps) + ieee80211_recalc_p2p_go_ps_allowed(sdata); } mutex_unlock(&local->sta_mtx); -- cgit v1.2.3 From 15ddba5f43114c1fd9cd83676e04a9e1acf8e37f Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Sun, 4 Jun 2023 12:11:26 +0300 Subject: wifi: mac80211: consistently use u64 for BSS changes Currently, enum ieee80211_bss_change has more than 32 flags. Change the type of the corresponding variables from u32 to u64. Signed-off-by: Anjaneyulu Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.10354a05eaf1.If19359262fe2728dd523ea6d7c3aa7dc50940411@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 79 ++++++++++++++++++++++------------------------ net/mac80211/chan.c | 4 +-- net/mac80211/ibss.c | 16 ++++++---- net/mac80211/ieee80211_i.h | 14 +++++--- net/mac80211/iface.c | 4 +-- net/mac80211/main.c | 4 +-- net/mac80211/mesh.c | 30 ++++++++++-------- net/mac80211/mesh.h | 19 +++++------ net/mac80211/mesh_plink.c | 37 +++++++++++----------- net/mac80211/mesh_ps.c | 7 ++-- net/mac80211/mlme.c | 12 +++---- net/mac80211/ocb.c | 4 +-- 12 files changed, 119 insertions(+), 111 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7317e4a5d1ff..801aaa62b68f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1101,18 +1101,20 @@ ieee80211_copy_rnr_beacon(u8 *pos, struct cfg80211_rnr_elems *dst, return offset; } -static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, - struct ieee80211_link_data *link, - struct cfg80211_beacon_data *params, - const struct ieee80211_csa_settings *csa, - const struct ieee80211_color_change_settings *cca) +static int +ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, + struct ieee80211_link_data *link, + struct cfg80211_beacon_data *params, + const struct ieee80211_csa_settings *csa, + const struct ieee80211_color_change_settings *cca, + u64 *changed) { struct cfg80211_mbssid_elems *mbssid = NULL; struct cfg80211_rnr_elems *rnr = NULL; struct beacon_data *new, *old; int new_head_len, new_tail_len; int size, err; - u32 changed = BSS_CHANGED_BEACON; + u64 _changed = BSS_CHANGED_BEACON; struct ieee80211_bss_conf *link_conf = link->conf; old = sdata_dereference(link->u.ap.beacon, sdata); @@ -1219,7 +1221,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, return err; } if (err == 0) - changed |= BSS_CHANGED_AP_PROBE_RESP; + _changed |= BSS_CHANGED_AP_PROBE_RESP; if (params->ftm_responder != -1) { link_conf->ftm_responder = params->ftm_responder; @@ -1235,7 +1237,7 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, return err; } - changed |= BSS_CHANGED_FTM_RESPONDER; + _changed |= BSS_CHANGED_FTM_RESPONDER; } rcu_assign_pointer(link->u.ap.beacon, new); @@ -1244,7 +1246,8 @@ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, if (old) kfree_rcu(old, rcu_head); - return changed; + *changed |= _changed; + return 0; } static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, @@ -1446,10 +1449,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) link_conf->beacon_tx_rate = params->beacon_rate; - err = ieee80211_assign_beacon(sdata, link, ¶ms->beacon, NULL, NULL); + err = ieee80211_assign_beacon(sdata, link, ¶ms->beacon, NULL, NULL, + &changed); if (err < 0) goto error; - changed |= err; if (params->fils_discovery.max_interval) { err = ieee80211_set_fils_discovery(sdata, @@ -1506,6 +1509,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, struct beacon_data *old; int err; struct ieee80211_bss_conf *link_conf; + u64 changed = 0; sdata_assert_lock(sdata); @@ -1525,17 +1529,18 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, if (!old) return -ENOENT; - err = ieee80211_assign_beacon(sdata, link, params, NULL, NULL); + err = ieee80211_assign_beacon(sdata, link, params, NULL, NULL, + &changed); if (err < 0) return err; if (params->he_bss_color_valid && params->he_bss_color.enabled != link_conf->he_bss_color.enabled) { link_conf->he_bss_color.enabled = params->he_bss_color.enabled; - err |= BSS_CHANGED_HE_BSS_COLOR; + changed |= BSS_CHANGED_HE_BSS_COLOR; } - ieee80211_link_info_change_notify(sdata, link, err); + ieee80211_link_info_change_notify(sdata, link, changed); return 0; } @@ -1717,7 +1722,7 @@ static void sta_apply_mesh_params(struct ieee80211_local *local, { #ifdef CONFIG_MAC80211_MESH struct ieee80211_sub_if_data *sdata = sta->sdata; - u32 changed = 0; + u64 changed = 0; if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) { switch (params->plink_state) { @@ -2664,7 +2669,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_link_data *link; struct ieee80211_supported_band *sband; - u32 changed = 0; + u64 changed = 0; link = ieee80211_link_or_deflink(sdata, params->link_id, true); if (IS_ERR(link)) @@ -3589,7 +3594,7 @@ void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_t EXPORT_SYMBOL(ieee80211_channel_switch_disconnect); static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, - u32 *changed) + u64 *changed) { int err; @@ -3600,25 +3605,22 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, err = ieee80211_assign_beacon(sdata, &sdata->deflink, sdata->deflink.u.ap.next_beacon, - NULL, NULL); + NULL, NULL, changed); ieee80211_free_next_beacon(&sdata->deflink); if (err < 0) return err; - *changed |= err; break; case NL80211_IFTYPE_ADHOC: - err = ieee80211_ibss_finish_csa(sdata); + err = ieee80211_ibss_finish_csa(sdata, changed); if (err < 0) return err; - *changed |= err; break; #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: - err = ieee80211_mesh_finish_csa(sdata); + err = ieee80211_mesh_finish_csa(sdata, changed); if (err < 0) return err; - *changed |= err; break; #endif default: @@ -3632,7 +3634,7 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata, static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - u32 changed = 0; + u64 changed = 0; int err; sdata_assert_lock(sdata); @@ -3729,7 +3731,7 @@ unlock: static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, struct cfg80211_csa_settings *params, - u32 *changed) + u64 *changed) { struct ieee80211_csa_settings csa = {}; int err; @@ -3776,12 +3778,11 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, err = ieee80211_assign_beacon(sdata, &sdata->deflink, ¶ms->beacon_csa, &csa, - NULL); + NULL, changed); if (err < 0) { ieee80211_free_next_beacon(&sdata->deflink); return err; } - *changed |= err; break; case NL80211_IFTYPE_ADHOC: @@ -3813,10 +3814,9 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, /* see comments in the NL80211_IFTYPE_AP block */ if (params->count > 1) { - err = ieee80211_ibss_csa_beacon(sdata, params); + err = ieee80211_ibss_csa_beacon(sdata, params, changed); if (err < 0) return err; - *changed |= err; } ieee80211_send_action_csa(sdata, params); @@ -3841,12 +3841,11 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata, /* see comments in the NL80211_IFTYPE_AP block */ if (params->count > 1) { - err = ieee80211_mesh_csa_beacon(sdata, params); + err = ieee80211_mesh_csa_beacon(sdata, params, changed); if (err < 0) { ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; return err; } - *changed |= err; } if (ifmsh->csa_role == IEEE80211_MESH_CSA_ROLE_INIT) @@ -3880,7 +3879,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel_switch ch_switch; struct ieee80211_chanctx_conf *conf; struct ieee80211_chanctx *chanctx; - u32 changed = 0; + u64 changed = 0; int err; sdata_assert_lock(sdata); @@ -4613,7 +4612,7 @@ static int ieee80211_set_sar_specs(struct wiphy *wiphy, static int ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata, - u32 *changed) + u64 *changed) { switch (sdata->vif.type) { case NL80211_IFTYPE_AP: { @@ -4624,13 +4623,12 @@ ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata, ret = ieee80211_assign_beacon(sdata, &sdata->deflink, sdata->deflink.u.ap.next_beacon, - NULL, NULL); + NULL, NULL, changed); ieee80211_free_next_beacon(&sdata->deflink); if (ret < 0) return ret; - *changed |= ret; break; } default: @@ -4644,7 +4642,7 @@ ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata, static int ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata, struct cfg80211_color_change_settings *params, - u32 *changed) + u64 *changed) { struct ieee80211_color_change_settings color_change = {}; int err; @@ -4667,12 +4665,11 @@ ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata, err = ieee80211_assign_beacon(sdata, &sdata->deflink, ¶ms->beacon_color_change, - NULL, &color_change); + NULL, &color_change, changed); if (err < 0) { ieee80211_free_next_beacon(&sdata->deflink); return err; } - *changed |= err; break; default: return -EOPNOTSUPP; @@ -4683,7 +4680,7 @@ ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata, static void ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, - u8 color, int enable, u32 changed) + u8 color, int enable, u64 changed) { sdata->vif.bss_conf.he_bss_color.color = color; sdata->vif.bss_conf.he_bss_color.enabled = enable; @@ -4711,7 +4708,7 @@ ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - u32 changed = 0; + u64 changed = 0; int err; sdata_assert_lock(sdata); @@ -4808,7 +4805,7 @@ ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; - u32 changed = 0; + u64 changed = 0; int err; sdata_assert_lock(sdata); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index dbc34fbe7c8f..88b24a69b891 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1238,7 +1238,7 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) struct ieee80211_vif_chanctx_switch vif_chsw[1] = {}; struct ieee80211_chanctx *old_ctx, *new_ctx; const struct cfg80211_chan_def *chandef; - u32 changed = 0; + u64 changed = 0; int err; lockdep_assert_held(&local->mtx); @@ -1634,7 +1634,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) reserved_chanctx_list) { struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_bss_conf *link_conf = link->conf; - u32 changed = 0; + u64 changed = 0; if (!ieee80211_link_has_in_place_reservation(link)) continue; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 9dffc3079588..faa01ee11d32 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -9,7 +9,7 @@ * Copyright 2009, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2016 Intel Deutschland GmbH - * Copyright(c) 2018-2022 Intel Corporation + * Copyright(c) 2018-2023 Intel Corporation */ #include @@ -226,7 +226,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_mgmt *mgmt; struct cfg80211_bss *bss; - u32 bss_change; + u64 bss_change; struct cfg80211_chan_def chandef; struct ieee80211_channel *chan; struct beacon_data *presp; @@ -478,7 +478,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, } int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, - struct cfg80211_csa_settings *csa_settings) + struct cfg80211_csa_settings *csa_settings, + u64 *changed) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct beacon_data *presp, *old_presp; @@ -520,10 +521,11 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, if (old_presp) kfree_rcu(old_presp, rcu_head); - return BSS_CHANGED_BEACON; + *changed |= BSS_CHANGED_BEACON; + return 0; } -int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) +int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata, u64 *changed) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; struct cfg80211_bss *cbss; @@ -552,7 +554,7 @@ int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata) ifibss->chandef = sdata->deflink.csa_chandef; /* generate the beacon */ - return ieee80211_ibss_csa_beacon(sdata, NULL); + return ieee80211_ibss_csa_beacon(sdata, NULL, changed); } void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata) @@ -1754,7 +1756,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, struct cfg80211_ibss_params *params) { - u32 changed = 0; + u64 changed = 0; u32 rate_flags; struct ieee80211_supported_band *sband; enum ieee80211_chanctx_mode chanmode; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 007b36c7db53..c80e552b6197 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1827,7 +1827,7 @@ void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, struct ieee80211_link_data *link, u64 changed); void ieee80211_configure_filter(struct ieee80211_local *local); -u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); +u64 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); u64 ieee80211_mgmt_tx_cookie(struct ieee80211_local *local); int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb, @@ -1887,8 +1887,10 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata); void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata, - struct cfg80211_csa_settings *csa_settings); -int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); + struct cfg80211_csa_settings *csa_settings, + u64 *changed); +int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata, + u64 *changed); void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); /* OCB code */ @@ -1905,8 +1907,10 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, - struct cfg80211_csa_settings *csa_settings); -int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata); + struct cfg80211_csa_settings *csa_settings, + u64 *changed); +int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata, + u64 *changed); /* scan/BSS handling */ void ieee80211_scan_work(struct work_struct *work); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index bd2c48870add..f1e01f7a9b2e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -8,7 +8,7 @@ * Copyright 2008, Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (c) 2016 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include #include @@ -1221,7 +1221,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct net_device *dev = wdev->netdev; struct ieee80211_local *local = sdata->local; - u32 changed = 0; + u64 changed = 0; int res; u32 hw_reconf_flags = 0; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 55cdfaef0f5d..3db178b1d50c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include @@ -291,7 +291,7 @@ void ieee80211_link_info_change_notify(struct ieee80211_sub_if_data *sdata, drv_link_info_changed(local, sdata, link->conf, link->link_id, changed); } -u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) +u64 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) { sdata->vif.bss_conf.use_cts_prot = false; sdata->vif.bss_conf.use_short_preamble = false; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f72333201903..a4d8764073bf 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2018 - 2022 Intel Corporation + * Copyright (C) 2018 - 2023 Intel Corporation * Authors: Luis Carlos Cobo * Javier Cardona */ @@ -133,10 +133,10 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) * * Returns: beacon changed flag if the beacon content changed. */ -u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) +u64 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) { bool free_plinks; - u32 changed = 0; + u64 changed = 0; /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, * the mesh interface might be able to establish plinks with peers that @@ -162,7 +162,7 @@ u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) void mesh_sta_cleanup(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - u32 changed = mesh_plink_deactivate(sta); + u64 changed = mesh_plink_deactivate(sta); if (changed) ieee80211_mbss_info_change_notify(sdata, changed); @@ -923,7 +923,7 @@ unsigned int ieee80211_new_mesh_header(struct ieee80211_sub_if_data *sdata, static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - u32 changed; + u64 changed; if (ifmsh->mshcfg.plink_timeout > 0) ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ); @@ -1164,7 +1164,7 @@ ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata) } void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed) + u64 changed) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; unsigned long bits = changed; @@ -1184,7 +1184,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct ieee80211_local *local = sdata->local; - u32 changed = BSS_CHANGED_BEACON | + u64 changed = BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_HT | BSS_CHANGED_BASIC_RATES | @@ -1525,12 +1525,11 @@ free: kfree(elems); } -int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) +int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata, u64 *changed) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_csa_settings *tmp_csa_settings; int ret = 0; - int changed = 0; /* Reset the TTL value and Initiator flag */ ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; @@ -1545,15 +1544,16 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata) if (ret) return -EINVAL; - changed |= BSS_CHANGED_BEACON; + *changed |= BSS_CHANGED_BEACON; mcsa_dbg(sdata, "complete switching to center freq %d MHz", sdata->vif.bss_conf.chandef.chan->center_freq); - return changed; + return 0; } int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, - struct cfg80211_csa_settings *csa_settings) + struct cfg80211_csa_settings *csa_settings, + u64 *changed) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_csa_settings *tmp_csa_settings; @@ -1579,7 +1579,8 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, return ret; } - return BSS_CHANGED_BEACON; + *changed |= BSS_CHANGED_BEACON; + return 0; } static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata, @@ -1720,7 +1721,8 @@ out: static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - u32 bit, changed = 0; + u32 bit; + u64 changed = 0; for_each_set_bit(bit, &ifmsh->mbss_changed, sizeof(changed) * BITS_PER_BYTE) { diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 022f41292a05..6c94222a9df5 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2008, 2009 open80211s Ltd. + * Copyright (C) 2023 Intel Corporation * Authors: Luis Carlos Cobo * Javier Cardona */ @@ -252,11 +253,11 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); /* wrapper for ieee80211_bss_info_change_notify() */ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed); + u64 changed); /* mesh power save */ -u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata); -u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, +u64 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata); +u64 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, enum nl80211_mesh_power_mode pm); void ieee80211_mps_set_frame_flags(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, @@ -303,12 +304,12 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, u8 *hw_addr, struct ieee802_11_elems *ie, struct ieee80211_rx_status *rx_status); bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); -u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); +u64 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); void mesh_plink_timer(struct timer_list *t); void mesh_plink_broken(struct sta_info *sta); -u32 mesh_plink_deactivate(struct sta_info *sta); -u32 mesh_plink_open(struct sta_info *sta); -u32 mesh_plink_block(struct sta_info *sta); +u64 mesh_plink_deactivate(struct sta_info *sta); +u64 mesh_plink_open(struct sta_info *sta); +u64 mesh_plink_block(struct sta_info *sta); void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status); @@ -349,14 +350,14 @@ void mesh_path_refresh(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_MESH static inline -u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) +u64 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) { atomic_inc(&sdata->u.mesh.estab_plinks); return mesh_accept_plinks_update(sdata) | BSS_CHANGED_BEACON; } static inline -u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) +u64 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) { atomic_dec(&sdata->u.mesh.estab_plinks); return mesh_accept_plinks_update(sdata) | BSS_CHANGED_BEACON; diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8f168bc4e4b8..f3d5bb0a59f1 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2019, 2021-2022 Intel Corporation + * Copyright (C) 2019, 2021-2023 Intel Corporation * Author: Luis Carlos Cobo */ #include @@ -90,12 +90,13 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) * * Returns BSS_CHANGED_ERP_SLOT or 0 for no change. */ -static u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata) +static u64 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; struct sta_info *sta; - u32 erp_rates = 0, changed = 0; + u32 erp_rates = 0; + u64 changed = 0; int i; bool short_slot = false; @@ -153,7 +154,7 @@ out: * is selected if all peers in our 20/40MHz MBSS support HT and at least one * HT20 peer is present. Otherwise no-protection mode is selected. */ -static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) +static u64 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct sta_info *sta; @@ -365,10 +366,10 @@ free: * * Locking: the caller must hold sta->mesh->plink_lock */ -static u32 __mesh_plink_deactivate(struct sta_info *sta) +static u64 __mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - u32 changed = 0; + u64 changed = 0; lockdep_assert_held(&sta->mesh->plink_lock); @@ -390,10 +391,10 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta) * * All mesh paths with this peer as next hop will be flushed */ -u32 mesh_plink_deactivate(struct sta_info *sta) +u64 mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - u32 changed; + u64 changed; spin_lock_bh(&sta->mesh->plink_lock); changed = __mesh_plink_deactivate(sta); @@ -622,7 +623,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, struct ieee80211_rx_status *rx_status) { struct sta_info *sta; - u32 changed = 0; + u64 changed = 0; sta = mesh_sta_info_get(sdata, hw_addr, elems, rx_status); if (!sta) @@ -775,10 +776,10 @@ static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) return llid; } -u32 mesh_plink_open(struct sta_info *sta) +u64 mesh_plink_open(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - u32 changed; + u64 changed; if (!test_sta_flag(sta, WLAN_STA_AUTH)) return 0; @@ -805,9 +806,9 @@ u32 mesh_plink_open(struct sta_info *sta) return changed; } -u32 mesh_plink_block(struct sta_info *sta) +u64 mesh_plink_block(struct sta_info *sta) { - u32 changed; + u64 changed; spin_lock_bh(&sta->mesh->plink_lock); changed = __mesh_plink_deactivate(sta); @@ -831,11 +832,11 @@ static void mesh_plink_close(struct ieee80211_sub_if_data *sdata, mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); } -static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, +static u64 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, struct sta_info *sta) { struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; - u32 changed = 0; + u64 changed = 0; del_timer(&sta->mesh->plink_timer); sta->mesh->plink_state = NL80211_PLINK_ESTAB; @@ -857,12 +858,12 @@ static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, * * Return: changed MBSS flags */ -static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, +static u64 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, enum plink_event event) { struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; enum ieee80211_self_protected_actioncode action = 0; - u32 changed = 0; + u64 changed = 0; bool flush = false; mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr, @@ -1117,7 +1118,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, struct sta_info *sta; enum plink_event event; enum ieee80211_self_protected_actioncode ftype; - u32 changed = 0; + u64 changed = 0; u8 ie_len = elems->peering_len; u16 plid, llid = 0; diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index 3fbd0b9ff913..35eacca43e49 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c @@ -3,6 +3,7 @@ * Copyright 2012-2013, Marco Porsch * Copyright 2012-2013, cozybit Inc. * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2023 Intel Corporation */ #include "mesh.h" @@ -77,14 +78,14 @@ static void mps_qos_null_tx(struct sta_info *sta) * sets the non-peer power mode and triggers the driver PS (re-)configuration * Return BSS_CHANGED_BEACON if a beacon update is necessary. */ -u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) +u64 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct sta_info *sta; bool peering = false; int light_sleep_cnt = 0; int deep_sleep_cnt = 0; - u32 changed = 0; + u64 changed = 0; enum nl80211_mesh_power_mode nonpeer_pm; rcu_read_lock(); @@ -148,7 +149,7 @@ u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) * @pm: the power mode to set * Return BSS_CHANGED_BEACON if a beacon update is in order. */ -u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, +u64 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, enum nl80211_mesh_power_mode pm) { struct ieee80211_sub_if_data *sdata = sta->sdata; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 56c375213202..9af755388171 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2109,7 +2109,7 @@ static void ieee80211_find_cisco_dtpc(struct ieee80211_sub_if_data *sdata, *pwr_level = (__s8)cisco_dtpc_ie[4]; } -static u32 ieee80211_handle_pwr_constr(struct ieee80211_link_data *link, +static u64 ieee80211_handle_pwr_constr(struct ieee80211_link_data *link, struct ieee80211_channel *channel, struct ieee80211_mgmt *mgmt, const u8 *country_ie, u8 country_ie_len, @@ -2699,12 +2699,12 @@ static void ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) mutex_unlock(&sdata->local->mtx); } -static u32 ieee80211_handle_bss_capability(struct ieee80211_link_data *link, +static u64 ieee80211_handle_bss_capability(struct ieee80211_link_data *link, u16 capab, bool erp_valid, u8 erp) { struct ieee80211_bss_conf *bss_conf = link->conf; struct ieee80211_supported_band *sband; - u32 changed = 0; + u64 changed = 0; bool use_protection; bool use_short_preamble; bool use_short_slot; @@ -2750,7 +2750,7 @@ static u64 ieee80211_link_set_associated(struct ieee80211_link_data *link, struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_bss_conf *bss_conf = link->conf; struct ieee80211_bss *bss = (void *)cbss->priv; - u32 changed = BSS_CHANGED_QOS; + u64 changed = BSS_CHANGED_QOS; /* not really used in MLO */ sdata->u.mgd.beacon_timeout = @@ -2888,7 +2888,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; unsigned int link_id; - u32 changed = 0; + u64 changed = 0; struct ieee80211_prep_tx_info info = { .subtype = stype, }; @@ -3959,7 +3959,7 @@ static bool ieee80211_twt_req_supported(struct ieee80211_sub_if_data *sdata, IEEE80211_HE_MAC_CAP0_TWT_REQ); } -static int ieee80211_recalc_twt_req(struct ieee80211_sub_if_data *sdata, +static u64 ieee80211_recalc_twt_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband, struct ieee80211_link_data *link, struct link_sta_info *link_sta, diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index a57dcbe99a0d..cf205762ab96 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -4,7 +4,7 @@ * * Copyright: (c) 2014 Czech Technical University in Prague * (c) 2014 Volkswagen Group Research - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022 - 2023 Intel Corporation * Author: Rostislav Lisovy * Funded by: Volkswagen Group Research */ @@ -175,7 +175,7 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; - u32 changed = BSS_CHANGED_OCB | BSS_CHANGED_BSSID; + u64 changed = BSS_CHANGED_OCB | BSS_CHANGED_BSSID; int err; if (ifocb->joined == true) -- cgit v1.2.3 From 0cc80943ef518a1c51a1111e9346d1daf11dd545 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 4 Jun 2023 12:11:27 +0300 Subject: wifi: mac80211_hwsim: Fix possible NULL dereference In a call to mac80211_hwsim_select_tx_link() the sta pointer might be NULL, thus need to check that it is not NULL before accessing it. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.f4d889fc98c4.Iae85f527ed245a37637a874bb8b8c83d79812512@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index b06a6e78169d..c706abbdaa17 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -4,7 +4,7 @@ * Copyright (c) 2008, Jouni Malinen * Copyright (c) 2011, Javier Lopez * Copyright (c) 2016 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2022 Intel Corporation + * Copyright (C) 2018 - 2023 Intel Corporation */ /* @@ -1865,7 +1865,7 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, WARN_ON(is_multicast_ether_addr(hdr->addr1)); - if (WARN_ON_ONCE(!sta->valid_links)) + if (WARN_ON_ONCE(!sta || !sta->valid_links)) return &vif->bss_conf; for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { -- cgit v1.2.3 From c4fdb0818d38fbe1ea7021fb51346df70bbca284 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Jun 2023 12:11:28 +0300 Subject: wifi: mac80211: stop warning after reconfig failures If we have a reconfig failure in the driver, then we need to shut down the network interface(s) at the network stack level through cfg80211, which can result in a lot of those "Failed check-sdata-in-driver check, ..." warnings, since interfaces are considered to not be in the driver when the reconfiguration fails, but we still need to go through all the shutdown flow. Avoid many of these warnings by storing the fact that the stack experienced a reconfiguration failure and not doing the warning in that case. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.3750c4ae6e76.I9e80d6026f59263c008a1a68f6cd6891ca0b93b0@changeid Signed-off-by: Johannes Berg --- net/mac80211/driver-ops.h | 10 ++++++---- net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/iface.c | 3 +++ net/mac80211/util.c | 1 + 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 45d3e53c7383..c4505593ba7a 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -2,7 +2,7 @@ /* * Portions of this file * Copyright(c) 2016 Intel Deutschland GmbH -* Copyright (C) 2018 - 2019, 2021 Intel Corporation +* Copyright (C) 2018 - 2019, 2021 - 2023 Intel Corporation */ #ifndef __MAC80211_DRIVER_OPS @@ -13,9 +13,11 @@ #include "trace.h" #define check_sdata_in_driver(sdata) ({ \ - !WARN_ONCE(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER), \ - "%s: Failed check-sdata-in-driver check, flags: 0x%x\n", \ - sdata->dev ? sdata->dev->name : sdata->name, sdata->flags); \ + WARN_ONCE(!sdata->local->reconfig_failure && \ + !(sdata->flags & IEEE80211_SDATA_IN_DRIVER), \ + "%s: Failed check-sdata-in-driver check, flags: 0x%x\n", \ + sdata->dev ? sdata->dev->name : sdata->name, sdata->flags); \ + !!(sdata->flags & IEEE80211_SDATA_IN_DRIVER); \ }) static inline struct ieee80211_sub_if_data * diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c80e552b6197..865210726d54 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1394,6 +1394,9 @@ struct ieee80211_local { /* device is during a HW reconfig */ bool in_reconfig; + /* reconfiguration failed ... suppress some warnings etc. */ + bool reconfig_failure; + /* wowlan is enabled -- don't reconfig on resume */ bool wowlan; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f1e01f7a9b2e..2e2115af38f5 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1281,6 +1281,9 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) } if (local->open_count == 0) { + /* here we can consider everything in good order (again) */ + local->reconfig_failure = false; + res = drv_start(local); if (res) goto err_del_bss; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3f24b6e59652..a027b9e24160 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2373,6 +2373,7 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) local->resuming = false; local->suspended = false; local->in_reconfig = false; + local->reconfig_failure = true; ieee80211_flush_completed_scan(local, true); -- cgit v1.2.3 From 8b4580ab5612b34e2d05e60cb0efdc26e1bd6f39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 15:26:05 +0200 Subject: Revert "wifi: iwlwifi: mvm: FTM initiator MLO support" This reverts commit 1bcbb1208e9a ("wifi: iwlwifi: mvm: FTM initiator MLO support") as it causes a merge conflict, and we can defer and re-do those changes later. Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 45 +++++++--------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 233ae81884a0..3963a0d4ed04 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -72,24 +72,15 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * the TK is already configured for this station, so it * shouldn't be set again here. */ - if (vif->cfg.assoc) { + if (vif->cfg.assoc && + !memcmp(addr, vif->bss_conf.bssid, ETH_ALEN)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct ieee80211_bss_conf *link_conf; - unsigned int link_id; struct ieee80211_sta *sta; - u8 sta_id; rcu_read_lock(); - for_each_vif_active_link(vif, link_conf, link_id) { - if (memcmp(addr, link_conf->bssid, ETH_ALEN)) - continue; - - sta_id = mvmvif->link[link_id]->ap_sta_id; - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); - if (!IS_ERR_OR_NULL(sta) && sta->mfp) - expected_tk_len = 0; - break; - } + sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); + if (!IS_ERR_OR_NULL(sta) && sta->mfp) + expected_tk_len = 0; rcu_read_unlock(); } @@ -527,30 +518,20 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_ftm_put_target_common(mvm, peer, target); - if (vif->cfg.assoc) { + if (vif->cfg.assoc && + !memcmp(peer->addr, vif->bss_conf.bssid, ETH_ALEN)) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; - struct ieee80211_bss_conf *link_conf; - unsigned int link_id; rcu_read_lock(); - for_each_vif_active_link(vif, link_conf, link_id) { - if (memcmp(peer->addr, link_conf->bssid, ETH_ALEN)) - continue; - - target->sta_id = mvmvif->link[link_id]->ap_sta_id; - sta = rcu_dereference(mvm->fw_id_to_mac_id[target->sta_id]); - if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { - rcu_read_unlock(); - return PTR_ERR_OR_ZERO(sta); - } - if (sta->mfp && (peer->ftm.trigger_based || - peer->ftm.non_trigger_based)) - FTM_PUT_FLAG(PMF); - break; - } + sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); + if (sta->mfp && (peer->ftm.trigger_based || peer->ftm.non_trigger_based)) + FTM_PUT_FLAG(PMF); + rcu_read_unlock(); + + target->sta_id = mvmvif->deflink.ap_sta_id; } else { target->sta_id = IWL_MVM_INVALID_STA; } -- cgit v1.2.3 From 7d528eafc5290bed18551a22ff25ce8587b603e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 15:28:05 +0200 Subject: Revert "wifi: iwlwifi: update response for mcc_update command" This reverts commit b70813e4a88f ("wifi: iwlwifi: update response for mcc_update command") since it causes a merge conflict, and it seems easier to redo the patch later. Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 35 +----- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 117 +++++++-------------- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 58 +++------- 6 files changed, 59 insertions(+), 161 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 28bfabb399b2..71cce6dfeaf9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -322,7 +322,7 @@ struct iwl_mcc_update_resp_v3 { } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ /** - * struct iwl_mcc_update_resp_v4 - response to MCC_UPDATE_CMD. + * struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. @@ -338,7 +338,7 @@ struct iwl_mcc_update_resp_v3 { * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ -struct iwl_mcc_update_resp_v4 { +struct iwl_mcc_update_resp { __le32 status; __le16 mcc; __le16 cap; @@ -350,37 +350,6 @@ struct iwl_mcc_update_resp_v4 { __le32 channels[]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */ -/** - * struct iwl_mcc_update_resp_v8 - response to MCC_UPDATE_CMD. - * Contains the new channel control profile map, if changed, and the new MCC - * (mobile country code). - * The new MCC may be different than what was requested in MCC_UPDATE_CMD. - * @status: see &enum iwl_mcc_update_status - * @mcc: the new applied MCC - * @padding: padding for 2 bytes. - * @cap: capabilities for all channels which matches the MCC - * @time: time elapsed from the MCC test start (in units of 30 seconds) - * @geo_info: geographic specific profile information - * see &enum iwl_geo_information. - * @source_id: the MCC source, see iwl_mcc_source - * @reserved: for four bytes alignment. - * @n_channels: number of channels in @channels_data. - * @channels: channel control data map, DWORD for each channel. Only the first - * 16bits are used. - */ -struct iwl_mcc_update_resp_v8 { - __le32 status; - __le16 mcc; - u8 padding[2]; - __le32 cap; - __le16 time; - __le16 geo_info; - u8 source_id; - u8 reserved[3]; - __le32 n_channels; - __le32 channels[]; -} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_8 */ - /** * struct iwl_mcc_chub_notif - chub notifies of mcc change * (MCC_CHUB_UPDATE_CMD = 0xc9) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 7edb98ef8093..cf19e8a561e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -173,34 +173,34 @@ enum iwl_nvm_channel_flags { }; /** - * enum iwl_reg_capa_flags_v1 - global flags applied for the whole regulatory + * enum iwl_reg_capa_flags - global flags applied for the whole regulatory * domain. - * @REG_CAPA_V1_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the + * @REG_CAPA_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the * 2.4Ghz band is allowed. - * @REG_CAPA_V1_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the + * @REG_CAPA_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the * 5Ghz band is allowed. - * @REG_CAPA_V1_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed + * @REG_CAPA_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_V1_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed + * @REG_CAPA_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_V1_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. - * @REG_CAPA_V1_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. - * @REG_CAPA_V1_40MHZ_FORBIDDEN: 11n channel with a width of 40Mhz is forbidden + * @REG_CAPA_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. + * @REG_CAPA_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. + * @REG_CAPA_40MHZ_FORBIDDEN: 11n channel with a width of 40Mhz is forbidden * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_V1_DC_HIGH_ENABLED: DC HIGH allowed. - * @REG_CAPA_V1_11AX_DISABLED: 11ax is forbidden for this regulatory domain. + * @REG_CAPA_DC_HIGH_ENABLED: DC HIGH allowed. + * @REG_CAPA_11AX_DISABLED: 11ax is forbidden for this regulatory domain. */ -enum iwl_reg_capa_flags_v1 { - REG_CAPA_V1_BF_CCD_LOW_BAND = BIT(0), - REG_CAPA_V1_BF_CCD_HIGH_BAND = BIT(1), - REG_CAPA_V1_160MHZ_ALLOWED = BIT(2), - REG_CAPA_V1_80MHZ_ALLOWED = BIT(3), - REG_CAPA_V1_MCS_8_ALLOWED = BIT(4), - REG_CAPA_V1_MCS_9_ALLOWED = BIT(5), - REG_CAPA_V1_40MHZ_FORBIDDEN = BIT(7), - REG_CAPA_V1_DC_HIGH_ENABLED = BIT(9), - REG_CAPA_V1_11AX_DISABLED = BIT(10), -}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_1 */ +enum iwl_reg_capa_flags { + REG_CAPA_BF_CCD_LOW_BAND = BIT(0), + REG_CAPA_BF_CCD_HIGH_BAND = BIT(1), + REG_CAPA_160MHZ_ALLOWED = BIT(2), + REG_CAPA_80MHZ_ALLOWED = BIT(3), + REG_CAPA_MCS_8_ALLOWED = BIT(4), + REG_CAPA_MCS_9_ALLOWED = BIT(5), + REG_CAPA_40MHZ_FORBIDDEN = BIT(7), + REG_CAPA_DC_HIGH_ENABLED = BIT(9), + REG_CAPA_11AX_DISABLED = BIT(10), +}; /** * enum iwl_reg_capa_flags_v2 - global flags applied for the whole regulatory @@ -234,31 +234,7 @@ enum iwl_reg_capa_flags_v2 { REG_CAPA_V2_WEATHER_DISABLED = BIT(7), REG_CAPA_V2_40MHZ_ALLOWED = BIT(8), REG_CAPA_V2_11AX_DISABLED = BIT(10), -}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_2 */ - -/** - * enum iwl_reg_capa_flags_v4 - global flags applied for the whole regulatory - * domain. - * @REG_CAPA_V4_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed - * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_V4_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed - * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_V4_MCS_12_ALLOWED: 11ac with MCS 12 is allowed. - * @REG_CAPA_V4_MCS_13_ALLOWED: 11ac with MCS 13 is allowed. - * @REG_CAPA_V4_11BE_DISABLED: 11be is forbidden for this regulatory domain. - * @REG_CAPA_V4_11AX_DISABLED: 11ax is forbidden for this regulatory domain. - * @REG_CAPA_V4_320MHZ_ALLOWED: 11be channel with a width of 320Mhz is allowed - * for this regulatory domain (valid only in 5GHz). - */ -enum iwl_reg_capa_flags_v4 { - REG_CAPA_V4_160MHZ_ALLOWED = BIT(3), - REG_CAPA_V4_80MHZ_ALLOWED = BIT(4), - REG_CAPA_V4_MCS_12_ALLOWED = BIT(5), - REG_CAPA_V4_MCS_13_ALLOWED = BIT(6), - REG_CAPA_V4_11BE_DISABLED = BIT(8), - REG_CAPA_V4_11AX_DISABLED = BIT(13), - REG_CAPA_V4_320MHZ_ALLOWED = BIT(16), -}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_4 */ +}; /* * API v2 for reg_capa_flags is relevant from version 6 and onwards of the @@ -266,33 +242,23 @@ enum iwl_reg_capa_flags_v4 { */ #define REG_CAPA_V2_RESP_VER 6 -/* API v4 for reg_capa_flags is relevant from version 8 and onwards of the - * MCC update command response. - */ -#define REG_CAPA_V4_RESP_VER 8 - /** * struct iwl_reg_capa - struct for global regulatory capabilities, Used for * handling the different APIs of reg_capa_flags. * * @allow_40mhz: 11n channel with a width of 40Mhz is allowed - * for this regulatory domain. + * for this regulatory domain (valid only in 5Ghz). * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed - * for this regulatory domain (valid only in 5 and 6 Ghz). + * for this regulatory domain (valid only in 5Ghz). * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed - * for this regulatory domain (valid only in 5 and 6 Ghz). - * @allow_320mhz: 11be channel with a width of 320Mhz is allowed - * for this regulatory domain (valid only in 6 Ghz). + * for this regulatory domain (valid only in 5Ghz). * @disable_11ax: 11ax is forbidden for this regulatory domain. - * @disable_11be: 11be is forbidden for this regulatory domain. */ struct iwl_reg_capa { - bool allow_40mhz; - bool allow_80mhz; - bool allow_160mhz; - bool allow_320mhz; - bool disable_11ax; - bool disable_11be; + u16 allow_40mhz; + u16 allow_80mhz; + u16 allow_160mhz; + u16 disable_11ax; }; static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, @@ -1572,27 +1538,20 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, return flags; } -static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver) +static struct iwl_reg_capa iwl_get_reg_capa(u16 flags, u8 resp_ver) { - struct iwl_reg_capa reg_capa = {}; - - if (resp_ver >= REG_CAPA_V4_RESP_VER) { - reg_capa.allow_40mhz = true; - reg_capa.allow_80mhz = flags & REG_CAPA_V4_80MHZ_ALLOWED; - reg_capa.allow_160mhz = flags & REG_CAPA_V4_160MHZ_ALLOWED; - reg_capa.allow_320mhz = flags & REG_CAPA_V4_320MHZ_ALLOWED; - reg_capa.disable_11ax = flags & REG_CAPA_V4_11AX_DISABLED; - reg_capa.disable_11be = flags & REG_CAPA_V4_11BE_DISABLED; - } else if (resp_ver >= REG_CAPA_V2_RESP_VER) { + struct iwl_reg_capa reg_capa; + + if (resp_ver >= REG_CAPA_V2_RESP_VER) { reg_capa.allow_40mhz = flags & REG_CAPA_V2_40MHZ_ALLOWED; reg_capa.allow_80mhz = flags & REG_CAPA_V2_80MHZ_ALLOWED; reg_capa.allow_160mhz = flags & REG_CAPA_V2_160MHZ_ALLOWED; reg_capa.disable_11ax = flags & REG_CAPA_V2_11AX_DISABLED; } else { - reg_capa.allow_40mhz = !(flags & REG_CAPA_V1_40MHZ_FORBIDDEN); - reg_capa.allow_80mhz = flags & REG_CAPA_V1_80MHZ_ALLOWED; - reg_capa.allow_160mhz = flags & REG_CAPA_V1_160MHZ_ALLOWED; - reg_capa.disable_11ax = flags & REG_CAPA_V1_11AX_DISABLED; + reg_capa.allow_40mhz = !(flags & REG_CAPA_40MHZ_FORBIDDEN); + reg_capa.allow_80mhz = flags & REG_CAPA_80MHZ_ALLOWED; + reg_capa.allow_160mhz = flags & REG_CAPA_160MHZ_ALLOWED; + reg_capa.disable_11ax = flags & REG_CAPA_11AX_DISABLED; } return reg_capa; } @@ -1600,7 +1559,7 @@ static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver) struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc, - u16 geo_info, u32 cap, u8 resp_ver) + u16 geo_info, u16 cap, u8 resp_ver) { int ch_idx; u16 ch_flags; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index c79f72d54482..e01f7751cf11 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2015, 2018-2022 Intel Corporation + * Copyright (C) 2005-2015, 2018-2021 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_nvm_parse_h__ @@ -50,7 +50,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc, - u16 geo_info, u32 cap, u8 resp_ver); + u16 geo_info, u16 cap, u8 resp_ver); /** * struct iwl_nvm_section - describes an NVM section in memory. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 6a712e519bac..bd5ba933e5ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -108,7 +108,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, struct ieee80211_regdomain *regd = NULL; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mcc_update_resp_v8 *resp; + struct iwl_mcc_update_resp *resp; u8 resp_ver; IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); @@ -138,7 +138,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, resp->channels, __le16_to_cpu(resp->mcc), __le16_to_cpu(resp->geo_info), - le32_to_cpu(resp->cap), resp_ver); + __le16_to_cpu(resp->cap), resp_ver); /* Store the return source id */ src_id = resp->source_id; if (IS_ERR_OR_NULL(regd)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ee3a6d1ef07b..bba3acd64131 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2219,7 +2219,7 @@ static inline void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) {} #endif /* Location Aware Regulatory */ -struct iwl_mcc_update_resp_v8 * +struct iwl_mcc_update_resp * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id); int iwl_mvm_init_mcc(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index 435eba0ed506..6d18a1fd649b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -404,7 +404,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm) return ret < 0 ? ret : 0; } -struct iwl_mcc_update_resp_v8 * +struct iwl_mcc_update_resp * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id) { @@ -412,7 +412,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), .source_id = (u8)src_id, }; - struct iwl_mcc_update_resp_v8 *resp_cp; + struct iwl_mcc_update_resp *resp_cp; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = MCC_UPDATE_CMD, @@ -420,7 +420,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .data = { &mcc_update_cmd }, }; - int ret, resp_ver; + int ret; u32 status; int resp_len, n_channels; u16 mcc; @@ -439,55 +439,25 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, pkt = cmd.resp_pkt; - resp_ver = iwl_fw_lookup_notif_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, - MCC_UPDATE_CMD, 0); - /* Extract MCC response */ - if (resp_ver >= 8) { - struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (void *)pkt->data; - - n_channels = __le32_to_cpu(mcc_resp_v8->n_channels); - resp_len = struct_size(resp_cp, channels, n_channels); - resp_cp = kzalloc(resp_len, GFP_KERNEL); + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { + struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data; + + n_channels = __le32_to_cpu(mcc_resp->n_channels); + resp_len = sizeof(struct iwl_mcc_update_resp) + + n_channels * sizeof(__le32); + resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); if (!resp_cp) { resp_cp = ERR_PTR(-ENOMEM); goto exit; } - resp_cp->status = mcc_resp_v8->status; - resp_cp->mcc = mcc_resp_v8->mcc; - resp_cp->cap = mcc_resp_v8->cap; - resp_cp->source_id = mcc_resp_v8->source_id; - resp_cp->time = mcc_resp_v8->time; - resp_cp->geo_info = mcc_resp_v8->geo_info; - resp_cp->n_channels = mcc_resp_v8->n_channels; - memcpy(resp_cp->channels, mcc_resp_v8->channels, - n_channels * sizeof(__le32)); - } else if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { - struct iwl_mcc_update_resp_v4 *mcc_resp_v4 = (void *)pkt->data; - - n_channels = __le32_to_cpu(mcc_resp_v4->n_channels); - resp_len = struct_size(resp_cp, channels, n_channels); - resp_cp = kzalloc(resp_len, GFP_KERNEL); - if (!resp_cp) { - resp_cp = ERR_PTR(-ENOMEM); - goto exit; - } - - resp_cp->status = mcc_resp_v4->status; - resp_cp->mcc = mcc_resp_v4->mcc; - resp_cp->cap = cpu_to_le32(le16_to_cpu(mcc_resp_v4->cap)); - resp_cp->source_id = mcc_resp_v4->source_id; - resp_cp->time = mcc_resp_v4->time; - resp_cp->geo_info = mcc_resp_v4->geo_info; - resp_cp->n_channels = mcc_resp_v4->n_channels; - memcpy(resp_cp->channels, mcc_resp_v4->channels, - n_channels * sizeof(__le32)); } else { struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data; n_channels = __le32_to_cpu(mcc_resp_v3->n_channels); - resp_len = struct_size(resp_cp, channels, n_channels); + resp_len = sizeof(struct iwl_mcc_update_resp) + + n_channels * sizeof(__le32); resp_cp = kzalloc(resp_len, GFP_KERNEL); if (!resp_cp) { resp_cp = ERR_PTR(-ENOMEM); @@ -496,7 +466,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_cp->status = mcc_resp_v3->status; resp_cp->mcc = mcc_resp_v3->mcc; - resp_cp->cap = cpu_to_le32(mcc_resp_v3->cap); + resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap); resp_cp->source_id = mcc_resp_v3->source_id; resp_cp->time = mcc_resp_v3->time; resp_cp->geo_info = mcc_resp_v3->geo_info; -- cgit v1.2.3 From aa6182707a53c5e4df7b3da7ba4faa7e29dc71a0 Mon Sep 17 00:00:00 2001 From: Ruiqi Gong Date: Tue, 6 Jun 2023 10:10:47 +0800 Subject: bpf: Cleanup unused function declaration All usage and the definition of `bpf_prog_free_linfo()` has been removed in commit e16301fbe183 ("bpf: Simplify freeing logic in linfo and jited_linfo"). Clean up its declaration in the header file. Signed-off-by: Ruiqi Gong Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/all/20230602030842.279262-1-gongruiqi@huaweicloud.com/ Link: https://lore.kernel.org/bpf/20230606021047.170667-1-gongruiqi@huaweicloud.com --- include/linux/filter.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index bbce89937fde..f69114083ec7 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -874,7 +874,6 @@ void bpf_prog_free(struct bpf_prog *fp); bool bpf_opcode_in_insntable(u8 code); -void bpf_prog_free_linfo(struct bpf_prog *prog); void bpf_prog_fill_jited_linfo(struct bpf_prog *prog, const u32 *insn_to_jit_off); int bpf_prog_alloc_jited_linfo(struct bpf_prog *prog); -- cgit v1.2.3 From 095641817e1bf6aa2560e025e47575188ee3edaf Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 6 Jun 2023 13:30:47 +0200 Subject: selftests/bpf: Fix check_mtu using wrong variable type Dan Carpenter found via Smatch static checker, that unsigned 'mtu_lo' is never less than zero. Variable mtu_lo should have been an 'int', because read_mtu_device_lo() uses minus as error indications. Fixes: b62eba563229 ("selftests/bpf: Tests using bpf_check_mtu BPF-helper") Reported-by: Dan Carpenter Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Daniel Borkmann Reviewed-by: Simon Horman Link: https://lore.kernel.org/bpf/168605104733.3636467.17945947801753092590.stgit@firesoul --- tools/testing/selftests/bpf/prog_tests/check_mtu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/check_mtu.c b/tools/testing/selftests/bpf/prog_tests/check_mtu.c index 5338d2ea0460..2a9a30650350 100644 --- a/tools/testing/selftests/bpf/prog_tests/check_mtu.c +++ b/tools/testing/selftests/bpf/prog_tests/check_mtu.c @@ -183,7 +183,7 @@ cleanup: void serial_test_check_mtu(void) { - __u32 mtu_lo; + int mtu_lo; if (test__start_subtest("bpf_check_mtu XDP-attach")) test_check_mtu_xdp_attach(); -- cgit v1.2.3 From 18b849f12dcc34ec4cb9c8fadeb503b069499ba4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 28 May 2023 17:09:38 +0300 Subject: ieee802154: ca8210: Remove stray gpiod_unexport() call There is no gpiod_export() and gpiod_unexport() looks pretty much stray. The gpiod_export() and gpiod_unexport() shouldn't be used in the code, GPIO sysfs is deprecated. That said, simply drop the stray call. Signed-off-by: Andy Shevchenko Reviewed-by: Simon Horman Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-wpan/20230528140938.34034-1-andriy.shevchenko@linux.intel.com --- drivers/net/ieee802154/ca8210.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c index a2d242034220..f9b10e84de06 100644 --- a/drivers/net/ieee802154/ca8210.c +++ b/drivers/net/ieee802154/ca8210.c @@ -2855,7 +2855,6 @@ static int ca8210_interrupt_init(struct spi_device *spi) ); if (ret) { dev_crit(&spi->dev, "request_irq %d failed\n", pdata->irq_id); - gpiod_unexport(gpio_to_desc(pdata->gpio_irq)); gpio_free(pdata->gpio_irq); } -- cgit v1.2.3 From a99bfdf647953f8ac4ae71f373113e8ac194f1c0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2023 12:01:05 -0700 Subject: tools: ynl-gen: clean up stray new lines at the end of reply-less requests Do not print empty lines before closing brackets. Reviewed-by: Willem de Bruijn Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 4c12c6f8968e..1e64c5c2a087 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -944,9 +944,10 @@ class CodeWriter: def _is_cond(cls, line): return line.startswith('if') or line.startswith('while') or line.startswith('for') - def p(self, line, add_ind=0): + def p(self, line, add_ind=0, eat_nl=False): if self._nl: - self._out.write('\n') + if not eat_nl: + self._out.write('\n') self._nl = False ind = self._ind if line[-1] == ':': @@ -971,7 +972,7 @@ class CodeWriter: if line and line[0] not in {';', ','}: line = ' ' + line self._ind -= 1 - self.p('}' + line) + self.p('}' + line, eat_nl=True) def write_doc_line(self, doc, indent=True): words = doc.split() -- cgit v1.2.3 From 86878f14d71af89149a955122afd8b7af1ee9bf2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2023 12:01:06 -0700 Subject: tools: ynl: user space helpers Add "fixed" part of the user space Netlink Spec-based library. This will get linked with the protocol implementations to form a full API. Acked-by: Willem de Bruijn Signed-off-by: Jakub Kicinski --- .../userspace-api/netlink/intro-specs.rst | 79 ++ tools/net/ynl/Makefile | 19 + tools/net/ynl/generated/Makefile | 45 + tools/net/ynl/lib/Makefile | 28 + tools/net/ynl/lib/ynl.c | 901 +++++++++++++++++++++ tools/net/ynl/lib/ynl.h | 237 ++++++ tools/net/ynl/ynl-regen.sh | 2 +- 7 files changed, 1310 insertions(+), 1 deletion(-) create mode 100644 tools/net/ynl/Makefile create mode 100644 tools/net/ynl/generated/Makefile create mode 100644 tools/net/ynl/lib/Makefile create mode 100644 tools/net/ynl/lib/ynl.c create mode 100644 tools/net/ynl/lib/ynl.h diff --git a/Documentation/userspace-api/netlink/intro-specs.rst b/Documentation/userspace-api/netlink/intro-specs.rst index a3b847eafff7..bada89699455 100644 --- a/Documentation/userspace-api/netlink/intro-specs.rst +++ b/Documentation/userspace-api/netlink/intro-specs.rst @@ -78,3 +78,82 @@ to see other examples. The code generation itself is performed by ``tools/net/ynl/ynl-gen-c.py`` but it takes a few arguments so calling it directly for each file quickly becomes tedious. + +YNL lib +======= + +``tools/net/ynl/lib/`` contains an implementation of a C library +(based on libmnl) which integrates with code generated by +``tools/net/ynl/ynl-gen-c.py`` to create easy to use netlink wrappers. + +YNL basics +---------- + +The YNL library consists of two parts - the generic code (functions +prefix by ``ynl_``) and per-family auto-generated code (prefixed +with the name of the family). + +To create a YNL socket call ynl_sock_create() passing the family +struct (family structs are exported by the auto-generated code). +ynl_sock_destroy() closes the socket. + +YNL requests +------------ + +Steps for issuing YNL requests are best explained on an example. +All the functions and types in this example come from the auto-generated +code (for the netdev family in this case): + +.. code-block:: c + + // 0. Request and response pointers + struct netdev_dev_get_req *req; + struct netdev_dev_get_rsp *d; + + // 1. Allocate a request + req = netdev_dev_get_req_alloc(); + // 2. Set request parameters (as needed) + netdev_dev_get_req_set_ifindex(req, ifindex); + + // 3. Issues the request + d = netdev_dev_get(ys, req); + // 4. Free the request arguments + netdev_dev_get_req_free(req); + // 5. Error check (the return value from step 3) + if (!d) { + // 6. Print the YNL-generated error + fprintf(stderr, "YNL: %s\n", ys->err.msg); + return -1; + } + + // ... do stuff with the response @d + + // 7. Free response + netdev_dev_get_rsp_free(d); + +YNL dumps +--------- + +Performing dumps follows similar pattern as requests. +Dumps return a list of objects terminated by a special marker, +or NULL on error. Use ``ynl_dump_foreach()`` to iterate over +the result. + +YNL notifications +----------------- + +YNL lib supports using the same socket for notifications and +requests. In case notifications arrive during processing of a request +they are queued internally and can be retrieved at a later time. + +To subscribed to notifications use ``ynl_subscribe()``. +The notifications have to be read out from the socket, +``ynl_socket_get_fd()`` returns the underlying socket fd which can +be plugged into appropriate asynchronous IO API like ``poll``, +or ``select``. + +Notifications can be retrieved using ``ynl_ntf_dequeue()`` and have +to be freed using ``ynl_ntf_free()``. Since we don't know the notification +type upfront the notifications are returned as ``struct ynl_ntf_base_type *`` +and user is expected to cast them to the appropriate full type based +on the ``cmd`` member. diff --git a/tools/net/ynl/Makefile b/tools/net/ynl/Makefile new file mode 100644 index 000000000000..d664b36deb5b --- /dev/null +++ b/tools/net/ynl/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0 + +SUBDIRS = lib generated samples + +all: $(SUBDIRS) + +$(SUBDIRS): + @if [ -f "$@/Makefile" ] ; then \ + $(MAKE) -C $@ ; \ + fi + +clean hardclean: + @for dir in $(SUBDIRS) ; do \ + if [ -f "$$dir/Makefile" ] ; then \ + $(MAKE) -C $$dir $@; \ + fi \ + done + +.PHONY: clean all $(SUBDIRS) diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile new file mode 100644 index 000000000000..9a09e581906e --- /dev/null +++ b/tools/net/ynl/generated/Makefile @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0 + +CC=gcc +CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ + -I../lib/ +ifeq ("$(DEBUG)","1") + CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan +endif + +TOOL:=../ynl-gen-c.py + +GENS:= +SRCS=$(patsubst %,%-user.c,${GENS}) +HDRS=$(patsubst %,%-user.h,${GENS}) +OBJS=$(patsubst %,%-user.o,${GENS}) + +all: protos.a $(HDRS) $(SRCS) $(KHDRS) $(KSRCS) $(UAPI) regen + +protos.a: $(OBJS) + @echo -e "\tAR $@" + @ar rcs $@ $(OBJS) + +%-user.h: ../../../../Documentation/netlink/specs/%.yaml $(TOOL) + @echo -e "\tGEN $@" + @$(TOOL) --mode user --header --spec $< > $@ + +%-user.c: ../../../../Documentation/netlink/specs/%.yaml $(TOOL) + @echo -e "\tGEN $@" + @$(TOOL) --mode user --source --spec $< > $@ + +%-user.o: %-user.c %-user.h + @echo -e "\tCC $@" + @$(COMPILE.c) -c -o $@ $< + +clean: + rm -f *.o + +hardclean: clean + rm -f *.c *.h *.a + +regen: + @../ynl-regen.sh + +.PHONY: all clean hardclean regen +.DEFAULT_GOAL: all diff --git a/tools/net/ynl/lib/Makefile b/tools/net/ynl/lib/Makefile new file mode 100644 index 000000000000..d2e50fd0a52d --- /dev/null +++ b/tools/net/ynl/lib/Makefile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 + +CC=gcc +CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow +ifeq ("$(DEBUG)","1") + CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan +endif + +SRCS=$(wildcard *.c) +OBJS=$(patsubst %.c,%.o,${SRCS}) + +include $(wildcard *.d) + +all: ynl.a + +ynl.a: $(OBJS) + ar rcs $@ $(OBJS) +clean: + rm -f *.o *.d *~ + +hardclean: clean + rm -f *.a + +%.o: %.c + $(COMPILE.c) -MMD -c -o $@ $< + +.PHONY: all clean +.DEFAULT_GOAL=all diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c new file mode 100644 index 000000000000..514e0d69e731 --- /dev/null +++ b/tools/net/ynl/lib/ynl.c @@ -0,0 +1,901 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +#include +#include +#include +#include +#include + +#include +#include + +#include "ynl.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*arr)) + +#define __yerr_msg(yse, _msg...) \ + ({ \ + struct ynl_error *_yse = (yse); \ + \ + if (_yse) { \ + snprintf(_yse->msg, sizeof(_yse->msg) - 1, _msg); \ + _yse->msg[sizeof(_yse->msg) - 1] = 0; \ + } \ + }) + +#define __yerr_code(yse, _code...) \ + ({ \ + struct ynl_error *_yse = (yse); \ + \ + if (_yse) { \ + _yse->code = _code; \ + } \ + }) + +#define __yerr(yse, _code, _msg...) \ + ({ \ + __yerr_msg(yse, _msg); \ + __yerr_code(yse, _code); \ + }) + +#define __perr(yse, _msg) __yerr(yse, errno, _msg) + +#define yerr_msg(_ys, _msg...) __yerr_msg(&(_ys)->err, _msg) +#define yerr(_ys, _code, _msg...) __yerr(&(_ys)->err, _code, _msg) +#define perr(_ys, _msg) __yerr(&(_ys)->err, errno, _msg) + +/* -- Netlink boiler plate */ +static int +ynl_err_walk_report_one(struct ynl_policy_nest *policy, unsigned int type, + char *str, int str_sz, int *n) +{ + if (!policy) { + if (*n < str_sz) + *n += snprintf(str, str_sz, "!policy"); + return 1; + } + + if (type > policy->max_attr) { + if (*n < str_sz) + *n += snprintf(str, str_sz, "!oob"); + return 1; + } + + if (!policy->table[type].name) { + if (*n < str_sz) + *n += snprintf(str, str_sz, "!name"); + return 1; + } + + if (*n < str_sz) + *n += snprintf(str, str_sz - *n, + ".%s", policy->table[type].name); + return 0; +} + +static int +ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, + struct ynl_policy_nest *policy, char *str, int str_sz, + struct ynl_policy_nest **nest_pol) +{ + unsigned int astart_off, aend_off; + const struct nlattr *attr; + unsigned int data_len; + unsigned int type; + bool found = false; + int n = 0; + + if (!policy) { + if (n < str_sz) + n += snprintf(str, str_sz, "!policy"); + return n; + } + + data_len = end - start; + + mnl_attr_for_each_payload(start, data_len) { + astart_off = (char *)attr - (char *)start; + aend_off = astart_off + mnl_attr_get_payload_len(attr); + if (aend_off <= off) + continue; + + found = true; + break; + } + if (!found) + return 0; + + off -= astart_off; + + type = mnl_attr_get_type(attr); + + if (ynl_err_walk_report_one(policy, type, str, str_sz, &n)) + return n; + + if (!off) { + if (nest_pol) + *nest_pol = policy->table[type].nest; + return n; + } + + if (!policy->table[type].nest) { + if (n < str_sz) + n += snprintf(str, str_sz, "!nest"); + return n; + } + + off -= sizeof(struct nlattr); + start = mnl_attr_get_payload(attr); + end = start + mnl_attr_get_payload_len(attr); + + return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest, + &str[n], str_sz - n, nest_pol); +} + +#define NLMSGERR_ATTR_MISS_TYPE (NLMSGERR_ATTR_POLICY + 1) +#define NLMSGERR_ATTR_MISS_NEST (NLMSGERR_ATTR_POLICY + 2) +#define NLMSGERR_ATTR_MAX (NLMSGERR_ATTR_MAX + 2) + +static int +ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, + unsigned int hlen) +{ + const struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {}; + char miss_attr[sizeof(ys->err.msg)]; + char bad_attr[sizeof(ys->err.msg)]; + const struct nlattr *attr; + const char *str = NULL; + + if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) + return MNL_CB_OK; + + mnl_attr_for_each(attr, nlh, hlen) { + unsigned int len, type; + + len = mnl_attr_get_payload_len(attr); + type = mnl_attr_get_type(attr); + + if (type > NLMSGERR_ATTR_MAX) + continue; + + tb[type] = attr; + + switch (type) { + case NLMSGERR_ATTR_OFFS: + case NLMSGERR_ATTR_MISS_TYPE: + case NLMSGERR_ATTR_MISS_NEST: + if (len != sizeof(__u32)) + return MNL_CB_ERROR; + break; + case NLMSGERR_ATTR_MSG: + str = mnl_attr_get_payload(attr); + if (str[len - 1]) + return MNL_CB_ERROR; + break; + default: + break; + } + } + + bad_attr[0] = '\0'; + miss_attr[0] = '\0'; + + if (tb[NLMSGERR_ATTR_OFFS]) { + unsigned int n, off; + void *start, *end; + + ys->err.attr_offs = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]); + + n = snprintf(bad_attr, sizeof(bad_attr), "%sbad attribute: ", + str ? " (" : ""); + + start = mnl_nlmsg_get_payload_offset(ys->nlh, + sizeof(struct genlmsghdr)); + end = mnl_nlmsg_get_payload_tail(ys->nlh); + + off = ys->err.attr_offs; + off -= sizeof(struct nlmsghdr); + off -= sizeof(struct genlmsghdr); + + n += ynl_err_walk(ys, start, end, off, ys->req_policy, + &bad_attr[n], sizeof(bad_attr) - n, NULL); + + if (n >= sizeof(bad_attr)) + n = sizeof(bad_attr) - 1; + bad_attr[n] = '\0'; + } + if (tb[NLMSGERR_ATTR_MISS_TYPE]) { + struct ynl_policy_nest *nest_pol = NULL; + unsigned int n, off, type; + void *start, *end; + int n2; + + type = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]); + + n = snprintf(miss_attr, sizeof(miss_attr), "%smissing attribute: ", + bad_attr[0] ? ", " : (str ? " (" : "")); + + start = mnl_nlmsg_get_payload_offset(ys->nlh, + sizeof(struct genlmsghdr)); + end = mnl_nlmsg_get_payload_tail(ys->nlh); + + nest_pol = ys->req_policy; + if (tb[NLMSGERR_ATTR_MISS_NEST]) { + off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_NEST]); + off -= sizeof(struct nlmsghdr); + off -= sizeof(struct genlmsghdr); + + n += ynl_err_walk(ys, start, end, off, ys->req_policy, + &miss_attr[n], sizeof(miss_attr) - n, + &nest_pol); + } + + n2 = 0; + ynl_err_walk_report_one(nest_pol, type, &miss_attr[n], + sizeof(miss_attr) - n, &n2); + n += n2; + + if (n >= sizeof(miss_attr)) + n = sizeof(miss_attr) - 1; + miss_attr[n] = '\0'; + } + + /* Implicitly depend on ys->err.code already set */ + if (str) + yerr_msg(ys, "Kernel %s: '%s'%s%s%s", + ys->err.code ? "error" : "warning", + str, bad_attr, miss_attr, + bad_attr[0] || miss_attr[0] ? ")" : ""); + else if (bad_attr[0] || miss_attr[0]) + yerr_msg(ys, "Kernel %s: %s%s", + ys->err.code ? "error" : "warning", + bad_attr, miss_attr); + + return MNL_CB_OK; +} + +static int ynl_cb_error(const struct nlmsghdr *nlh, void *data) +{ + const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); + struct ynl_parse_arg *yarg = data; + unsigned int hlen; + int code; + + code = err->error >= 0 ? err->error : -err->error; + yarg->ys->err.code = code; + errno = code; + + hlen = sizeof(*err); + if (!(nlh->nlmsg_flags & NLM_F_CAPPED)) + hlen += mnl_nlmsg_get_payload_len(&err->msg); + + ynl_ext_ack_check(yarg->ys, nlh, hlen); + + return code ? MNL_CB_ERROR : MNL_CB_STOP; +} + +static int ynl_cb_done(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + int err; + + err = *(int *)NLMSG_DATA(nlh); + if (err < 0) { + yarg->ys->err.code = -err; + errno = -err; + + ynl_ext_ack_check(yarg->ys, nlh, sizeof(int)); + + return MNL_CB_ERROR; + } + return MNL_CB_STOP; +} + +static int ynl_cb_noop(const struct nlmsghdr *nlh, void *data) +{ + return MNL_CB_OK; +} + +mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE] = { + [NLMSG_NOOP] = ynl_cb_noop, + [NLMSG_ERROR] = ynl_cb_error, + [NLMSG_DONE] = ynl_cb_done, + [NLMSG_OVERRUN] = ynl_cb_noop, +}; + +/* Attribute validation */ + +int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) +{ + struct ynl_policy_attr *policy; + unsigned int type, len; + unsigned char *data; + + data = mnl_attr_get_payload(attr); + len = mnl_attr_get_payload_len(attr); + type = mnl_attr_get_type(attr); + if (type > yarg->rsp_policy->max_attr) { + yerr(yarg->ys, YNL_ERROR_INTERNAL, + "Internal error, validating unknown attribute"); + return -1; + } + + policy = &yarg->rsp_policy->table[type]; + + switch (policy->type) { + case YNL_PT_REJECT: + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Rejected attribute (%s)", policy->name); + return -1; + case YNL_PT_IGNORE: + break; + case YNL_PT_U8: + if (len == sizeof(__u8)) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (u8 %s)", policy->name); + return -1; + case YNL_PT_U16: + if (len == sizeof(__u16)) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (u16 %s)", policy->name); + return -1; + case YNL_PT_U32: + if (len == sizeof(__u32)) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (u32 %s)", policy->name); + return -1; + case YNL_PT_U64: + if (len == sizeof(__u64)) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (u64 %s)", policy->name); + return -1; + case YNL_PT_FLAG: + /* Let flags grow into real attrs, why not.. */ + break; + case YNL_PT_NEST: + if (!len || len >= sizeof(*attr)) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (nest %s)", policy->name); + return -1; + case YNL_PT_BINARY: + if (!policy->len || len == policy->len) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (binary %s)", policy->name); + return -1; + case YNL_PT_NUL_STR: + if ((!policy->len || len <= policy->len) && !data[len - 1]) + break; + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (string %s)", policy->name); + return -1; + default: + yerr(yarg->ys, YNL_ERROR_ATTR_INVALID, + "Invalid attribute (unknown %s)", policy->name); + return -1; + } + + return 0; +} + +/* Generic code */ + +static void ynl_err_reset(struct ynl_sock *ys) +{ + ys->err.code = 0; + ys->err.attr_offs = 0; + ys->err.msg[0] = 0; +} + +struct nlmsghdr *ynl_msg_start(struct ynl_sock *ys, __u32 id, __u16 flags) +{ + struct nlmsghdr *nlh; + + ynl_err_reset(ys); + + nlh = ys->nlh = mnl_nlmsg_put_header(ys->tx_buf); + nlh->nlmsg_type = id; + nlh->nlmsg_flags = flags; + nlh->nlmsg_seq = ++ys->seq; + + return nlh; +} + +struct nlmsghdr * +ynl_gemsg_start(struct ynl_sock *ys, __u32 id, __u16 flags, + __u8 cmd, __u8 version) +{ + struct genlmsghdr gehdr; + struct nlmsghdr *nlh; + void *data; + + nlh = ynl_msg_start(ys, id, flags); + + memset(&gehdr, 0, sizeof(gehdr)); + gehdr.cmd = cmd; + gehdr.version = version; + + data = mnl_nlmsg_put_extra_header(nlh, sizeof(gehdr)); + memcpy(data, &gehdr, sizeof(gehdr)); + + return nlh; +} + +void ynl_msg_start_req(struct ynl_sock *ys, __u32 id) +{ + ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK); +} + +void ynl_msg_start_dump(struct ynl_sock *ys, __u32 id) +{ + ynl_msg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); +} + +struct nlmsghdr * +ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version) +{ + return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK, cmd, version); +} + +struct nlmsghdr * +ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version) +{ + return ynl_gemsg_start(ys, id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, + cmd, version); +} + +int ynl_recv_ack(struct ynl_sock *ys, int ret) +{ + if (!ret) { + yerr(ys, YNL_ERROR_EXPECT_ACK, + "Expecting an ACK but nothing received"); + return -1; + } + + ret = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); + if (ret < 0) { + perr(ys, "Socket receive failed"); + return ret; + } + return mnl_cb_run(ys->rx_buf, ret, ys->seq, ys->portid, + ynl_cb_null, ys); +} + +int ynl_cb_null(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + + yerr(yarg->ys, YNL_ERROR_UNEXPECT_MSG, + "Received a message when none were expected"); + + return MNL_CB_ERROR; +} + +/* Init/fini and genetlink boiler plate */ +static int +ynl_get_family_info_mcast(struct ynl_sock *ys, const struct nlattr *mcasts) +{ + const struct nlattr *entry, *attr; + unsigned int i; + + mnl_attr_for_each_nested(attr, mcasts) + ys->n_mcast_groups++; + + if (!ys->n_mcast_groups) + return 0; + + ys->mcast_groups = calloc(ys->n_mcast_groups, + sizeof(*ys->mcast_groups)); + if (!ys->mcast_groups) + return MNL_CB_ERROR; + + i = 0; + mnl_attr_for_each_nested(entry, mcasts) { + mnl_attr_for_each_nested(attr, entry) { + if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_ID) + ys->mcast_groups[i].id = mnl_attr_get_u32(attr); + if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GRP_NAME) { + strncpy(ys->mcast_groups[i].name, + mnl_attr_get_str(attr), + GENL_NAMSIZ - 1); + ys->mcast_groups[i].name[GENL_NAMSIZ - 1] = 0; + } + } + } + + return 0; +} + +static int ynl_get_family_info_cb(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct ynl_sock *ys = yarg->ys; + const struct nlattr *attr; + bool found_id = true; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == CTRL_ATTR_MCAST_GROUPS) + if (ynl_get_family_info_mcast(ys, attr)) + return MNL_CB_ERROR; + + if (mnl_attr_get_type(attr) != CTRL_ATTR_FAMILY_ID) + continue; + + if (mnl_attr_get_payload_len(attr) != sizeof(__u16)) { + yerr(ys, YNL_ERROR_ATTR_INVALID, "Invalid family ID"); + return MNL_CB_ERROR; + } + + ys->family_id = mnl_attr_get_u16(attr); + found_id = true; + } + + if (!found_id) { + yerr(ys, YNL_ERROR_ATTR_MISSING, "Family ID missing"); + return MNL_CB_ERROR; + } + return MNL_CB_OK; +} + +static int ynl_sock_read_family(struct ynl_sock *ys, const char *family_name) +{ + struct ynl_parse_arg yarg = { .ys = ys, }; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, 1); + mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name); + + err = mnl_socket_sendto(ys->sock, nlh, nlh->nlmsg_len); + if (err < 0) { + perr(ys, "failed to request socket family info"); + return err; + } + + err = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); + if (err <= 0) { + perr(ys, "failed to receive the socket family info"); + return err; + } + err = mnl_cb_run2(ys->rx_buf, err, ys->seq, ys->portid, + ynl_get_family_info_cb, &yarg, + ynl_cb_array, ARRAY_SIZE(ynl_cb_array)); + if (err < 0) { + free(ys->mcast_groups); + perr(ys, "failed to receive the socket family info - no such family?"); + return err; + } + + return ynl_recv_ack(ys, err); +} + +struct ynl_sock * +ynl_sock_create(const struct ynl_family *yf, struct ynl_error *yse) +{ + struct ynl_sock *ys; + int one = 1; + + ys = malloc(sizeof(*ys) + 2 * MNL_SOCKET_BUFFER_SIZE); + if (!ys) + return NULL; + memset(ys, 0, sizeof(*ys)); + + ys->family = yf; + ys->tx_buf = &ys->raw_buf[0]; + ys->rx_buf = &ys->raw_buf[MNL_SOCKET_BUFFER_SIZE]; + ys->ntf_last_next = &ys->ntf_first; + + ys->sock = mnl_socket_open(NETLINK_GENERIC); + if (!ys->sock) { + __perr(yse, "failed to create a netlink socket"); + goto err_free_sock; + } + + if (mnl_socket_setsockopt(ys->sock, NETLINK_CAP_ACK, + &one, sizeof(one))) { + __perr(yse, "failed to enable netlink ACK"); + goto err_close_sock; + } + if (mnl_socket_setsockopt(ys->sock, NETLINK_EXT_ACK, + &one, sizeof(one))) { + __perr(yse, "failed to enable netlink ext ACK"); + goto err_close_sock; + } + + ys->seq = random(); + ys->portid = mnl_socket_get_portid(ys->sock); + + if (ynl_sock_read_family(ys, yf->name)) { + if (yse) + memcpy(yse, &ys->err, sizeof(*yse)); + goto err_close_sock; + } + + return ys; + +err_close_sock: + mnl_socket_close(ys->sock); +err_free_sock: + free(ys); + return NULL; +} + +void ynl_sock_destroy(struct ynl_sock *ys) +{ + struct ynl_ntf_base_type *ntf; + + mnl_socket_close(ys->sock); + while ((ntf = ynl_ntf_dequeue(ys))) + ynl_ntf_free(ntf); + free(ys->mcast_groups); + free(ys); +} + +/* YNL multicast handling */ + +void ynl_ntf_free(struct ynl_ntf_base_type *ntf) +{ + ntf->free(ntf); +} + +int ynl_subscribe(struct ynl_sock *ys, const char *grp_name) +{ + unsigned int i; + int err; + + for (i = 0; i < ys->n_mcast_groups; i++) + if (!strcmp(ys->mcast_groups[i].name, grp_name)) + break; + if (i == ys->n_mcast_groups) { + yerr(ys, ENOENT, "Multicast group '%s' not found", grp_name); + return -1; + } + + err = mnl_socket_setsockopt(ys->sock, NETLINK_ADD_MEMBERSHIP, + &ys->mcast_groups[i].id, + sizeof(ys->mcast_groups[i].id)); + if (err < 0) { + perr(ys, "Subscribing to multicast group failed"); + return -1; + } + + return 0; +} + +int ynl_socket_get_fd(struct ynl_sock *ys) +{ + return mnl_socket_get_fd(ys->sock); +} + +struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys) +{ + struct ynl_ntf_base_type *ntf; + + if (!ynl_has_ntf(ys)) + return NULL; + + ntf = ys->ntf_first; + ys->ntf_first = ntf->next; + if (ys->ntf_last_next == &ntf->next) + ys->ntf_last_next = &ys->ntf_first; + + return ntf; +} + +static int ynl_ntf_parse(struct ynl_sock *ys, const struct nlmsghdr *nlh) +{ + struct ynl_parse_arg yarg = { .ys = ys, }; + const struct ynl_ntf_info *info; + struct ynl_ntf_base_type *rsp; + struct genlmsghdr *gehdr; + int ret; + + gehdr = mnl_nlmsg_get_payload(nlh); + if (gehdr->cmd >= ys->family->ntf_info_size) + return MNL_CB_ERROR; + info = &ys->family->ntf_info[gehdr->cmd]; + if (!info->cb) + return MNL_CB_ERROR; + + rsp = calloc(1, info->alloc_sz); + rsp->free = info->free; + yarg.data = rsp->data; + yarg.rsp_policy = info->policy; + + ret = info->cb(nlh, &yarg); + if (ret <= MNL_CB_STOP) + goto err_free; + + rsp->family = nlh->nlmsg_type; + rsp->cmd = gehdr->cmd; + + *ys->ntf_last_next = rsp; + ys->ntf_last_next = &rsp->next; + + return MNL_CB_OK; + +err_free: + info->free(rsp); + return MNL_CB_ERROR; +} + +static int ynl_ntf_trampoline(const struct nlmsghdr *nlh, void *data) +{ + return ynl_ntf_parse((struct ynl_sock *)data, nlh); +} + +int ynl_ntf_check(struct ynl_sock *ys) +{ + ssize_t len; + int err; + + do { + /* libmnl doesn't let us pass flags to the recv to make + * it non-blocking so we need to poll() or peek() :| + */ + struct pollfd pfd = { }; + + pfd.fd = mnl_socket_get_fd(ys->sock); + pfd.events = POLLIN; + err = poll(&pfd, 1, 1); + if (err < 1) + return err; + + len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, + MNL_SOCKET_BUFFER_SIZE); + if (len < 0) + return len; + + err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, + ynl_ntf_trampoline, ys, + ynl_cb_array, NLMSG_MIN_TYPE); + if (err < 0) + return err; + } while (err > 0); + + return 0; +} + +/* YNL specific helpers used by the auto-generated code */ + +struct ynl_dump_list_type *YNL_LIST_END = (void *)(0xb4d123); + +void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd) +{ + yerr(ys, YNL_ERROR_UNKNOWN_NTF, + "Unknown notification message type '%d'", cmd); +} + +int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg) +{ + yerr(yarg->ys, YNL_ERROR_INV_RESP, "Error parsing response: %s", msg); + return MNL_CB_ERROR; +} + +static int +ynl_check_alien(struct ynl_sock *ys, const struct nlmsghdr *nlh, __u32 rsp_cmd) +{ + struct genlmsghdr *gehdr; + + if (mnl_nlmsg_get_payload_len(nlh) < sizeof(*gehdr)) { + yerr(ys, YNL_ERROR_INV_RESP, + "Kernel responded with truncated message"); + return -1; + } + + gehdr = mnl_nlmsg_get_payload(nlh); + if (gehdr->cmd != rsp_cmd) + return ynl_ntf_parse(ys, nlh); + + return 0; +} + +static int ynl_req_trampoline(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_req_state *yrs = data; + int ret; + + ret = ynl_check_alien(yrs->yarg.ys, nlh, yrs->rsp_cmd); + if (ret) + return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK; + + return yrs->cb(nlh, &yrs->yarg); +} + +int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_req_state *yrs) +{ + ssize_t len; + int err; + + err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len); + if (err < 0) + return err; + + do { + len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, + MNL_SOCKET_BUFFER_SIZE); + if (len < 0) + return len; + + err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, + ynl_req_trampoline, yrs, + ynl_cb_array, NLMSG_MIN_TYPE); + if (err < 0) + return err; + } while (err > 0); + + return 0; +} + +static int ynl_dump_trampoline(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_dump_state *ds = data; + struct ynl_dump_list_type *obj; + struct ynl_parse_arg yarg = {}; + int ret; + + ret = ynl_check_alien(ds->ys, nlh, ds->rsp_cmd); + if (ret) + return ret < 0 ? MNL_CB_ERROR : MNL_CB_OK; + + obj = calloc(1, ds->alloc_sz); + if (!obj) + return MNL_CB_ERROR; + + if (!ds->first) + ds->first = obj; + if (ds->last) + ds->last->next = obj; + ds->last = obj; + + yarg.ys = ds->ys; + yarg.rsp_policy = ds->rsp_policy; + yarg.data = &obj->data; + + return ds->cb(nlh, &yarg); +} + +static void *ynl_dump_end(struct ynl_dump_state *ds) +{ + if (!ds->first) + return YNL_LIST_END; + + ds->last->next = YNL_LIST_END; + return ds->first; +} + +int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_dump_state *yds) +{ + ssize_t len; + int err; + + err = mnl_socket_sendto(ys->sock, req_nlh, req_nlh->nlmsg_len); + if (err < 0) + return err; + + do { + len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, + MNL_SOCKET_BUFFER_SIZE); + if (len < 0) + goto err_close_list; + + err = mnl_cb_run2(ys->rx_buf, len, ys->seq, ys->portid, + ynl_dump_trampoline, yds, + ynl_cb_array, NLMSG_MIN_TYPE); + if (err < 0) + goto err_close_list; + } while (err > 0); + + yds->first = ynl_dump_end(yds); + return 0; + +err_close_list: + yds->first = ynl_dump_end(yds); + return -1; +} diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h new file mode 100644 index 000000000000..9eafa3552c16 --- /dev/null +++ b/tools/net/ynl/lib/ynl.h @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +#ifndef __YNL_C_H +#define __YNL_C_H 1 + +#include +#include +#include +#include + +struct mnl_socket; +struct nlmsghdr; + +/* + * User facing code + */ + +struct ynl_ntf_base_type; +struct ynl_ntf_info; +struct ynl_sock; + +enum ynl_error_code { + YNL_ERROR_NONE = 0, + __YNL_ERRNO_END = 4096, + YNL_ERROR_INTERNAL, + YNL_ERROR_EXPECT_ACK, + YNL_ERROR_EXPECT_MSG, + YNL_ERROR_UNEXPECT_MSG, + YNL_ERROR_ATTR_MISSING, + YNL_ERROR_ATTR_INVALID, + YNL_ERROR_UNKNOWN_NTF, + YNL_ERROR_INV_RESP, +}; + +/** + * struct ynl_error - error encountered by YNL + * @code: errno (low values) or YNL error code (enum ynl_error_code) + * @attr_offs: offset of bad attribute (for very advanced users) + * @msg: error message + * + * Error information for when YNL operations fail. + * Users should interact with the err member of struct ynl_sock directly. + * The main exception to that rule is ynl_sock_create(). + */ +struct ynl_error { + enum ynl_error_code code; + unsigned int attr_offs; + char msg[512]; +}; + +/** + * struct ynl_family - YNL family info + * Family description generated by codegen. Pass to ynl_sock_create(). + */ +struct ynl_family { +/* private: */ + const char *name; + const struct ynl_ntf_info *ntf_info; + unsigned int ntf_info_size; +}; + +/** + * struct ynl_sock - YNL wrapped netlink socket + * @err: YNL error descriptor, cleared on every request. + */ +struct ynl_sock { + struct ynl_error err; + +/* private: */ + const struct ynl_family *family; + struct mnl_socket *sock; + __u32 seq; + __u32 portid; + __u16 family_id; + + unsigned int n_mcast_groups; + struct { + unsigned int id; + char name[GENL_NAMSIZ]; + } *mcast_groups; + + struct ynl_ntf_base_type *ntf_first; + struct ynl_ntf_base_type **ntf_last_next; + + struct nlmsghdr *nlh; + struct ynl_policy_nest *req_policy; + unsigned char *tx_buf; + unsigned char *rx_buf; + unsigned char raw_buf[]; +}; + +struct ynl_sock * +ynl_sock_create(const struct ynl_family *yf, struct ynl_error *e); +void ynl_sock_destroy(struct ynl_sock *ys); + +#define ynl_dump_foreach(dump, iter) \ + for (typeof(dump->obj) *iter = &dump->obj; \ + !ynl_dump_obj_is_last(iter); \ + iter = ynl_dump_obj_next(iter)) + +int ynl_subscribe(struct ynl_sock *ys, const char *grp_name); +int ynl_socket_get_fd(struct ynl_sock *ys); +int ynl_ntf_check(struct ynl_sock *ys); + +/** + * ynl_has_ntf() - check if socket has *parsed* notifications + * @ys: active YNL socket + * + * Note that this does not take into account notifications sitting + * in netlink socket, just the notifications which have already been + * read and parsed (e.g. during a ynl_ntf_check() call). + */ +static inline bool ynl_has_ntf(struct ynl_sock *ys) +{ + return ys->ntf_last_next != &ys->ntf_first; +} +struct ynl_ntf_base_type *ynl_ntf_dequeue(struct ynl_sock *ys); + +void ynl_ntf_free(struct ynl_ntf_base_type *ntf); + +/* + * YNL internals / low level stuff + */ + +/* Generic mnl helper code */ + +enum ynl_policy_type { + YNL_PT_REJECT = 1, + YNL_PT_IGNORE, + YNL_PT_NEST, + YNL_PT_FLAG, + YNL_PT_BINARY, + YNL_PT_U8, + YNL_PT_U16, + YNL_PT_U32, + YNL_PT_U64, + YNL_PT_NUL_STR, +}; + +struct ynl_policy_attr { + enum ynl_policy_type type; + unsigned int len; + const char *name; + struct ynl_policy_nest *nest; +}; + +struct ynl_policy_nest { + unsigned int max_attr; + struct ynl_policy_attr *table; +}; + +struct ynl_parse_arg { + struct ynl_sock *ys; + struct ynl_policy_nest *rsp_policy; + void *data; +}; + +struct ynl_dump_list_type { + struct ynl_dump_list_type *next; + unsigned char data[] __attribute__ ((aligned (8))); +}; +extern struct ynl_dump_list_type *YNL_LIST_END; + +static inline bool ynl_dump_obj_is_last(void *obj) +{ + unsigned long uptr = (unsigned long)obj; + + uptr -= offsetof(struct ynl_dump_list_type, data); + return uptr == (unsigned long)YNL_LIST_END; +} + +static inline void *ynl_dump_obj_next(void *obj) +{ + unsigned long uptr = (unsigned long)obj; + struct ynl_dump_list_type *list; + + uptr -= offsetof(struct ynl_dump_list_type, data); + list = (void *)uptr; + uptr = (unsigned long)list->next; + uptr += offsetof(struct ynl_dump_list_type, data); + + return (void *)uptr; +} + +struct ynl_ntf_base_type { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ynl_ntf_base_type *ntf); + unsigned char data[] __attribute__ ((aligned (8))); +}; + +extern mnl_cb_t ynl_cb_array[NLMSG_MIN_TYPE]; + +struct nlmsghdr * +ynl_gemsg_start_req(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); +struct nlmsghdr * +ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); + +int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); + +int ynl_recv_ack(struct ynl_sock *ys, int ret); +int ynl_cb_null(const struct nlmsghdr *nlh, void *data); + +/* YNL specific helpers used by the auto-generated code */ + +struct ynl_req_state { + struct ynl_parse_arg yarg; + mnl_cb_t cb; + __u32 rsp_cmd; +}; + +struct ynl_dump_state { + struct ynl_sock *ys; + struct ynl_policy_nest *rsp_policy; + void *first; + struct ynl_dump_list_type *last; + size_t alloc_sz; + mnl_cb_t cb; + __u32 rsp_cmd; +}; + +struct ynl_ntf_info { + struct ynl_policy_nest *policy; + mnl_cb_t cb; + size_t alloc_sz; + void (*free)(struct ynl_ntf_base_type *ntf); +}; + +int ynl_exec(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_req_state *yrs); +int ynl_exec_dump(struct ynl_sock *ys, struct nlmsghdr *req_nlh, + struct ynl_dump_state *yds); + +void ynl_error_unknown_notification(struct ynl_sock *ys, __u8 cmd); +int ynl_error_parse(struct ynl_parse_arg *yarg, const char *msg); + +#endif diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh index 74f5de1c2399..2a4525e2aa17 100755 --- a/tools/net/ynl/ynl-regen.sh +++ b/tools/net/ynl/ynl-regen.sh @@ -14,7 +14,7 @@ done KDIR=$(dirname $(dirname $(dirname $(dirname $(realpath $0))))) -files=$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\)') +files=$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\|user\)') for f in $files; do # params: 0 1 2 3 # $YAML YNL-GEN kernel $mode -- cgit v1.2.3 From d75fdfbc6f260f50cde5d1d566ab010a370df62e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2023 12:01:07 -0700 Subject: tools: ynl: support fou and netdev in C Generate the code for netdev and fou families. They are simple and already supported by the code gen. Reviewed-by: Willem de Bruijn Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/Makefile | 2 +- tools/net/ynl/generated/fou-user.c | 340 ++++++++++++++++++++++++++++++++++ tools/net/ynl/generated/fou-user.h | 337 +++++++++++++++++++++++++++++++++ tools/net/ynl/generated/netdev-user.c | 250 +++++++++++++++++++++++++ tools/net/ynl/generated/netdev-user.h | 88 +++++++++ 5 files changed, 1016 insertions(+), 1 deletion(-) create mode 100644 tools/net/ynl/generated/fou-user.c create mode 100644 tools/net/ynl/generated/fou-user.h create mode 100644 tools/net/ynl/generated/netdev-user.c create mode 100644 tools/net/ynl/generated/netdev-user.h diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 9a09e581906e..bbf5d83755c9 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -9,7 +9,7 @@ endif TOOL:=../ynl-gen-c.py -GENS:= +GENS:=fou netdev SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c new file mode 100644 index 000000000000..c99b5d438021 --- /dev/null +++ b/tools/net/ynl/generated/fou-user.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/fou.yaml */ +/* YNL-GEN user source */ + +#include +#include "fou-user.h" +#include "ynl.h" +#include + +#include +#include +#include +#include +#include + +/* Enums */ +static const char * const fou_op_strmap[] = { + [FOU_CMD_UNSPEC] = "unspec", + [FOU_CMD_ADD] = "add", + [FOU_CMD_DEL] = "del", + [FOU_CMD_GET] = "get", +}; + +const char *fou_op_str(int op) +{ + if (op < 0 || op >= (int)MNL_ARRAY_SIZE(fou_op_strmap)) + return NULL; + return fou_op_strmap[op]; +} + +static const char * const fou_encap_type_strmap[] = { + [0] = "unspec", + [1] = "direct", + [2] = "gue", +}; + +const char *fou_encap_type_str(int value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(fou_encap_type_strmap)) + return NULL; + return fou_encap_type_strmap[value]; +} + +/* Policies */ +extern struct ynl_policy_nest fou_nest; + +struct ynl_policy_attr fou_policy[FOU_ATTR_MAX + 1] = { + [FOU_ATTR_UNSPEC] = { .name = "unspec", .type = YNL_PT_REJECT, }, + [FOU_ATTR_PORT] = { .name = "port", .type = YNL_PT_U16, }, + [FOU_ATTR_AF] = { .name = "af", .type = YNL_PT_U8, }, + [FOU_ATTR_IPPROTO] = { .name = "ipproto", .type = YNL_PT_U8, }, + [FOU_ATTR_TYPE] = { .name = "type", .type = YNL_PT_U8, }, + [FOU_ATTR_REMCSUM_NOPARTIAL] = { .name = "remcsum_nopartial", .type = YNL_PT_FLAG, }, + [FOU_ATTR_LOCAL_V4] = { .name = "local_v4", .type = YNL_PT_U32, }, + [FOU_ATTR_LOCAL_V6] = { .name = "local_v6", .type = YNL_PT_BINARY,}, + [FOU_ATTR_PEER_V4] = { .name = "peer_v4", .type = YNL_PT_U32, }, + [FOU_ATTR_PEER_V6] = { .name = "peer_v6", .type = YNL_PT_BINARY,}, + [FOU_ATTR_PEER_PORT] = { .name = "peer_port", .type = YNL_PT_U16, }, + [FOU_ATTR_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest fou_nest = { + .max_attr = FOU_ATTR_MAX, + .table = fou_policy, +}; + +/* Common nested types */ +/* ============== FOU_CMD_ADD ============== */ +/* FOU_CMD_ADD - do */ +void fou_add_req_free(struct fou_add_req *req) +{ + free(req->local_v6); + free(req->peer_v6); + free(req); +} + +int fou_add(struct ynl_sock *ys, struct fou_add_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_ADD, 1); + ys->req_policy = &fou_nest; + + if (req->_present.port) + mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); + if (req->_present.ipproto) + mnl_attr_put_u8(nlh, FOU_ATTR_IPPROTO, req->ipproto); + if (req->_present.type) + mnl_attr_put_u8(nlh, FOU_ATTR_TYPE, req->type); + if (req->_present.remcsum_nopartial) + mnl_attr_put(nlh, FOU_ATTR_REMCSUM_NOPARTIAL, 0, NULL); + if (req->_present.local_v4) + mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); + if (req->_present.peer_v4) + mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); + if (req->_present.local_v6_len) + mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); + if (req->_present.peer_v6_len) + mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); + if (req->_present.peer_port) + mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); + if (req->_present.ifindex) + mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== FOU_CMD_DEL ============== */ +/* FOU_CMD_DEL - do */ +void fou_del_req_free(struct fou_del_req *req) +{ + free(req->local_v6); + free(req->peer_v6); + free(req); +} + +int fou_del(struct ynl_sock *ys, struct fou_del_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_DEL, 1); + ys->req_policy = &fou_nest; + + if (req->_present.af) + mnl_attr_put_u8(nlh, FOU_ATTR_AF, req->af); + if (req->_present.ifindex) + mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); + if (req->_present.port) + mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); + if (req->_present.peer_port) + mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); + if (req->_present.local_v4) + mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); + if (req->_present.peer_v4) + mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); + if (req->_present.local_v6_len) + mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); + if (req->_present.peer_v6_len) + mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== FOU_CMD_GET ============== */ +/* FOU_CMD_GET - do */ +void fou_get_req_free(struct fou_get_req *req) +{ + free(req->local_v6); + free(req->peer_v6); + free(req); +} + +void fou_get_rsp_free(struct fou_get_rsp *rsp) +{ + free(rsp->local_v6); + free(rsp->peer_v6); + free(rsp); +} + +int fou_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct fou_get_rsp *dst; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == FOU_ATTR_PORT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port = 1; + dst->port = mnl_attr_get_u16(attr); + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_IPPROTO) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ipproto = 1; + dst->ipproto = mnl_attr_get_u8(attr); + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_TYPE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.type = 1; + dst->type = mnl_attr_get_u8(attr); + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_REMCSUM_NOPARTIAL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.remcsum_nopartial = 1; + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_LOCAL_V4) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.local_v4 = 1; + dst->local_v4 = mnl_attr_get_u32(attr); + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_PEER_V4) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.peer_v4 = 1; + dst->peer_v4 = mnl_attr_get_u32(attr); + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_LOCAL_V6) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.local_v6_len = len; + dst->local_v6 = malloc(len); + memcpy(dst->local_v6, mnl_attr_get_payload(attr), len); + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_PEER_V6) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.peer_v6_len = len; + dst->peer_v6 = malloc(len); + memcpy(dst->peer_v6, mnl_attr_get_payload(attr), len); + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_PEER_PORT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.peer_port = 1; + dst->peer_port = mnl_attr_get_u16(attr); + } + else if (mnl_attr_get_type(attr) == FOU_ATTR_IFINDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ifindex = 1; + dst->ifindex = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct fou_get_rsp *fou_get(struct ynl_sock *ys, struct fou_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct fou_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, FOU_CMD_GET, 1); + ys->req_policy = &fou_nest; + yrs.yarg.rsp_policy = &fou_nest; + + if (req->_present.af) + mnl_attr_put_u8(nlh, FOU_ATTR_AF, req->af); + if (req->_present.ifindex) + mnl_attr_put_u32(nlh, FOU_ATTR_IFINDEX, req->ifindex); + if (req->_present.port) + mnl_attr_put_u16(nlh, FOU_ATTR_PORT, req->port); + if (req->_present.peer_port) + mnl_attr_put_u16(nlh, FOU_ATTR_PEER_PORT, req->peer_port); + if (req->_present.local_v4) + mnl_attr_put_u32(nlh, FOU_ATTR_LOCAL_V4, req->local_v4); + if (req->_present.peer_v4) + mnl_attr_put_u32(nlh, FOU_ATTR_PEER_V4, req->peer_v4); + if (req->_present.local_v6_len) + mnl_attr_put(nlh, FOU_ATTR_LOCAL_V6, req->_present.local_v6_len, req->local_v6); + if (req->_present.peer_v6_len) + mnl_attr_put(nlh, FOU_ATTR_PEER_V6, req->_present.peer_v6_len, req->peer_v6); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = fou_get_rsp_parse; + yrs.rsp_cmd = FOU_CMD_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + fou_get_rsp_free(rsp); + return NULL; +} + +/* FOU_CMD_GET - dump */ +void fou_get_list_free(struct fou_get_list *rsp) +{ + struct fou_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp->obj.local_v6); + free(rsp->obj.peer_v6); + free(rsp); + } +} + +struct fou_get_list *fou_get_dump(struct ynl_sock *ys) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct fou_get_list); + yds.cb = fou_get_rsp_parse; + yds.rsp_cmd = FOU_CMD_GET; + yds.rsp_policy = &fou_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, FOU_CMD_GET, 1); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + fou_get_list_free(yds.first); + return NULL; +} + +const struct ynl_family ynl_fou_family = { + .name = "fou", +}; diff --git a/tools/net/ynl/generated/fou-user.h b/tools/net/ynl/generated/fou-user.h new file mode 100644 index 000000000000..d8ab50579cd1 --- /dev/null +++ b/tools/net/ynl/generated/fou-user.h @@ -0,0 +1,337 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/fou.yaml */ +/* YNL-GEN user header */ + +#ifndef _LINUX_FOU_GEN_H +#define _LINUX_FOU_GEN_H + +#include +#include +#include +#include + +struct ynl_sock; + +extern const struct ynl_family ynl_fou_family; + +/* Enums */ +const char *fou_op_str(int op); +const char *fou_encap_type_str(int value); + +/* Common nested types */ +/* ============== FOU_CMD_ADD ============== */ +/* FOU_CMD_ADD - do */ +struct fou_add_req { + struct { + __u32 port:1; + __u32 ipproto:1; + __u32 type:1; + __u32 remcsum_nopartial:1; + __u32 local_v4:1; + __u32 peer_v4:1; + __u32 local_v6_len; + __u32 peer_v6_len; + __u32 peer_port:1; + __u32 ifindex:1; + } _present; + + __u16 port /* big-endian */; + __u8 ipproto; + __u8 type; + __u32 local_v4; + __u32 peer_v4; + void *local_v6; + void *peer_v6; + __u16 peer_port /* big-endian */; + __s32 ifindex; +}; + +static inline struct fou_add_req *fou_add_req_alloc(void) +{ + return calloc(1, sizeof(struct fou_add_req)); +} +void fou_add_req_free(struct fou_add_req *req); + +static inline void +fou_add_req_set_port(struct fou_add_req *req, __u16 port /* big-endian */) +{ + req->_present.port = 1; + req->port = port; +} +static inline void +fou_add_req_set_ipproto(struct fou_add_req *req, __u8 ipproto) +{ + req->_present.ipproto = 1; + req->ipproto = ipproto; +} +static inline void fou_add_req_set_type(struct fou_add_req *req, __u8 type) +{ + req->_present.type = 1; + req->type = type; +} +static inline void fou_add_req_set_remcsum_nopartial(struct fou_add_req *req) +{ + req->_present.remcsum_nopartial = 1; +} +static inline void +fou_add_req_set_local_v4(struct fou_add_req *req, __u32 local_v4) +{ + req->_present.local_v4 = 1; + req->local_v4 = local_v4; +} +static inline void +fou_add_req_set_peer_v4(struct fou_add_req *req, __u32 peer_v4) +{ + req->_present.peer_v4 = 1; + req->peer_v4 = peer_v4; +} +static inline void +fou_add_req_set_local_v6(struct fou_add_req *req, const void *local_v6, + size_t len) +{ + free(req->local_v6); + req->local_v6 = malloc(req->_present.local_v6_len); + memcpy(req->local_v6, local_v6, req->_present.local_v6_len); +} +static inline void +fou_add_req_set_peer_v6(struct fou_add_req *req, const void *peer_v6, + size_t len) +{ + free(req->peer_v6); + req->peer_v6 = malloc(req->_present.peer_v6_len); + memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); +} +static inline void +fou_add_req_set_peer_port(struct fou_add_req *req, + __u16 peer_port /* big-endian */) +{ + req->_present.peer_port = 1; + req->peer_port = peer_port; +} +static inline void +fou_add_req_set_ifindex(struct fou_add_req *req, __s32 ifindex) +{ + req->_present.ifindex = 1; + req->ifindex = ifindex; +} + +/* + * Add port. + */ +int fou_add(struct ynl_sock *ys, struct fou_add_req *req); + +/* ============== FOU_CMD_DEL ============== */ +/* FOU_CMD_DEL - do */ +struct fou_del_req { + struct { + __u32 af:1; + __u32 ifindex:1; + __u32 port:1; + __u32 peer_port:1; + __u32 local_v4:1; + __u32 peer_v4:1; + __u32 local_v6_len; + __u32 peer_v6_len; + } _present; + + __u8 af; + __s32 ifindex; + __u16 port /* big-endian */; + __u16 peer_port /* big-endian */; + __u32 local_v4; + __u32 peer_v4; + void *local_v6; + void *peer_v6; +}; + +static inline struct fou_del_req *fou_del_req_alloc(void) +{ + return calloc(1, sizeof(struct fou_del_req)); +} +void fou_del_req_free(struct fou_del_req *req); + +static inline void fou_del_req_set_af(struct fou_del_req *req, __u8 af) +{ + req->_present.af = 1; + req->af = af; +} +static inline void +fou_del_req_set_ifindex(struct fou_del_req *req, __s32 ifindex) +{ + req->_present.ifindex = 1; + req->ifindex = ifindex; +} +static inline void +fou_del_req_set_port(struct fou_del_req *req, __u16 port /* big-endian */) +{ + req->_present.port = 1; + req->port = port; +} +static inline void +fou_del_req_set_peer_port(struct fou_del_req *req, + __u16 peer_port /* big-endian */) +{ + req->_present.peer_port = 1; + req->peer_port = peer_port; +} +static inline void +fou_del_req_set_local_v4(struct fou_del_req *req, __u32 local_v4) +{ + req->_present.local_v4 = 1; + req->local_v4 = local_v4; +} +static inline void +fou_del_req_set_peer_v4(struct fou_del_req *req, __u32 peer_v4) +{ + req->_present.peer_v4 = 1; + req->peer_v4 = peer_v4; +} +static inline void +fou_del_req_set_local_v6(struct fou_del_req *req, const void *local_v6, + size_t len) +{ + free(req->local_v6); + req->local_v6 = malloc(req->_present.local_v6_len); + memcpy(req->local_v6, local_v6, req->_present.local_v6_len); +} +static inline void +fou_del_req_set_peer_v6(struct fou_del_req *req, const void *peer_v6, + size_t len) +{ + free(req->peer_v6); + req->peer_v6 = malloc(req->_present.peer_v6_len); + memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); +} + +/* + * Delete port. + */ +int fou_del(struct ynl_sock *ys, struct fou_del_req *req); + +/* ============== FOU_CMD_GET ============== */ +/* FOU_CMD_GET - do */ +struct fou_get_req { + struct { + __u32 af:1; + __u32 ifindex:1; + __u32 port:1; + __u32 peer_port:1; + __u32 local_v4:1; + __u32 peer_v4:1; + __u32 local_v6_len; + __u32 peer_v6_len; + } _present; + + __u8 af; + __s32 ifindex; + __u16 port /* big-endian */; + __u16 peer_port /* big-endian */; + __u32 local_v4; + __u32 peer_v4; + void *local_v6; + void *peer_v6; +}; + +static inline struct fou_get_req *fou_get_req_alloc(void) +{ + return calloc(1, sizeof(struct fou_get_req)); +} +void fou_get_req_free(struct fou_get_req *req); + +static inline void fou_get_req_set_af(struct fou_get_req *req, __u8 af) +{ + req->_present.af = 1; + req->af = af; +} +static inline void +fou_get_req_set_ifindex(struct fou_get_req *req, __s32 ifindex) +{ + req->_present.ifindex = 1; + req->ifindex = ifindex; +} +static inline void +fou_get_req_set_port(struct fou_get_req *req, __u16 port /* big-endian */) +{ + req->_present.port = 1; + req->port = port; +} +static inline void +fou_get_req_set_peer_port(struct fou_get_req *req, + __u16 peer_port /* big-endian */) +{ + req->_present.peer_port = 1; + req->peer_port = peer_port; +} +static inline void +fou_get_req_set_local_v4(struct fou_get_req *req, __u32 local_v4) +{ + req->_present.local_v4 = 1; + req->local_v4 = local_v4; +} +static inline void +fou_get_req_set_peer_v4(struct fou_get_req *req, __u32 peer_v4) +{ + req->_present.peer_v4 = 1; + req->peer_v4 = peer_v4; +} +static inline void +fou_get_req_set_local_v6(struct fou_get_req *req, const void *local_v6, + size_t len) +{ + free(req->local_v6); + req->local_v6 = malloc(req->_present.local_v6_len); + memcpy(req->local_v6, local_v6, req->_present.local_v6_len); +} +static inline void +fou_get_req_set_peer_v6(struct fou_get_req *req, const void *peer_v6, + size_t len) +{ + free(req->peer_v6); + req->peer_v6 = malloc(req->_present.peer_v6_len); + memcpy(req->peer_v6, peer_v6, req->_present.peer_v6_len); +} + +struct fou_get_rsp { + struct { + __u32 port:1; + __u32 ipproto:1; + __u32 type:1; + __u32 remcsum_nopartial:1; + __u32 local_v4:1; + __u32 peer_v4:1; + __u32 local_v6_len; + __u32 peer_v6_len; + __u32 peer_port:1; + __u32 ifindex:1; + } _present; + + __u16 port /* big-endian */; + __u8 ipproto; + __u8 type; + __u32 local_v4; + __u32 peer_v4; + void *local_v6; + void *peer_v6; + __u16 peer_port /* big-endian */; + __s32 ifindex; +}; + +void fou_get_rsp_free(struct fou_get_rsp *rsp); + +/* + * Get tunnel info. + */ +struct fou_get_rsp *fou_get(struct ynl_sock *ys, struct fou_get_req *req); + +/* FOU_CMD_GET - dump */ +struct fou_get_list { + struct fou_get_list *next; + struct fou_get_rsp obj __attribute__ ((aligned (8))); +}; + +void fou_get_list_free(struct fou_get_list *rsp); + +struct fou_get_list *fou_get_dump(struct ynl_sock *ys); + +#endif /* _LINUX_FOU_GEN_H */ diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c new file mode 100644 index 000000000000..aea5c7cc8ead --- /dev/null +++ b/tools/net/ynl/generated/netdev-user.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/netdev.yaml */ +/* YNL-GEN user source */ + +#include +#include "netdev-user.h" +#include "ynl.h" +#include + +#include +#include +#include +#include +#include + +/* Enums */ +static const char * const netdev_op_strmap[] = { + [NETDEV_CMD_DEV_GET] = "dev-get", + [NETDEV_CMD_DEV_ADD_NTF] = "dev-add-ntf", + [NETDEV_CMD_DEV_DEL_NTF] = "dev-del-ntf", + [NETDEV_CMD_DEV_CHANGE_NTF] = "dev-change-ntf", +}; + +const char *netdev_op_str(int op) +{ + if (op < 0 || op >= (int)MNL_ARRAY_SIZE(netdev_op_strmap)) + return NULL; + return netdev_op_strmap[op]; +} + +static const char * const netdev_xdp_act_strmap[] = { + [0] = "basic", + [1] = "redirect", + [2] = "ndo-xmit", + [3] = "xsk-zerocopy", + [4] = "hw-offload", + [5] = "rx-sg", + [6] = "ndo-xmit-sg", +}; + +const char *netdev_xdp_act_str(enum netdev_xdp_act value) +{ + value = ffs(value) - 1; + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(netdev_xdp_act_strmap)) + return NULL; + return netdev_xdp_act_strmap[value]; +} + +/* Policies */ +extern struct ynl_policy_nest netdev_dev_nest; + +struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = { + [NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, + [NETDEV_A_DEV_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, + [NETDEV_A_DEV_XDP_FEATURES] = { .name = "xdp-features", .type = YNL_PT_U64, }, +}; + +struct ynl_policy_nest netdev_dev_nest = { + .max_attr = NETDEV_A_DEV_MAX, + .table = netdev_dev_policy, +}; + +/* Common nested types */ +/* ============== NETDEV_CMD_DEV_GET ============== */ +/* NETDEV_CMD_DEV_GET - do */ +void netdev_dev_get_req_free(struct netdev_dev_get_req *req) +{ + free(req); +} + +void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp) +{ + free(rsp); +} + +int netdev_dev_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct netdev_dev_get_rsp *dst; + const struct nlattr *attr; + + dst = yarg->data; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == NETDEV_A_DEV_IFINDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ifindex = 1; + dst->ifindex = mnl_attr_get_u32(attr); + } + else if (mnl_attr_get_type(attr) == NETDEV_A_DEV_XDP_FEATURES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.xdp_features = 1; + dst->xdp_features = mnl_attr_get_u64(attr); + } + } + + return MNL_CB_OK; +} + +struct netdev_dev_get_rsp * +netdev_dev_get(struct ynl_sock *ys, struct netdev_dev_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct netdev_dev_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, NETDEV_CMD_DEV_GET, 1); + ys->req_policy = &netdev_dev_nest; + yrs.yarg.rsp_policy = &netdev_dev_nest; + + if (req->_present.ifindex) + mnl_attr_put_u32(nlh, NETDEV_A_DEV_IFINDEX, req->ifindex); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = netdev_dev_get_rsp_parse; + yrs.rsp_cmd = NETDEV_CMD_DEV_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + netdev_dev_get_rsp_free(rsp); + return NULL; +} + +/* NETDEV_CMD_DEV_GET - dump */ +void netdev_dev_get_list_free(struct netdev_dev_get_list *rsp) +{ + struct netdev_dev_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp); + } +} + +struct netdev_dev_get_list *netdev_dev_get_dump(struct ynl_sock *ys) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct netdev_dev_get_list); + yds.cb = netdev_dev_get_rsp_parse; + yds.rsp_cmd = NETDEV_CMD_DEV_GET; + yds.rsp_policy = &netdev_dev_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, NETDEV_CMD_DEV_GET, 1); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + netdev_dev_get_list_free(yds.first); + return NULL; +} + +/* NETDEV_CMD_DEV_GET - notify */ +void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp) +{ + free(rsp); +} + +/* --------------- Common notification parsing --------------- */ +struct ynl_ntf_base_type *netdev_ntf_parse(struct ynl_sock *ys) +{ + struct ynl_parse_arg yarg = { .ys = ys, }; + struct ynl_ntf_base_type *rsp; + struct genlmsghdr *genlh; + struct nlmsghdr *nlh; + mnl_cb_t parse; + int len, err; + + len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); + if (len < (ssize_t)(sizeof(*nlh) + sizeof(*genlh))) + return NULL; + + nlh = (struct nlmsghdr *)ys->rx_buf; + genlh = mnl_nlmsg_get_payload(nlh); + + switch (genlh->cmd) { + case NETDEV_CMD_DEV_ADD_NTF: + case NETDEV_CMD_DEV_DEL_NTF: + case NETDEV_CMD_DEV_CHANGE_NTF: + rsp = calloc(1, sizeof(struct netdev_dev_get_ntf)); + parse = netdev_dev_get_rsp_parse; + yarg.rsp_policy = &netdev_dev_nest; + rsp->free = (void *)netdev_dev_get_ntf_free; + break; + default: + ynl_error_unknown_notification(ys, genlh->cmd); + return NULL; + } + + yarg.data = rsp->data; + + err = mnl_cb_run2(ys->rx_buf, len, 0, 0, parse, &yarg, + ynl_cb_array, NLMSG_MIN_TYPE); + if (err < 0) + goto err_free; + + rsp->family = nlh->nlmsg_type; + rsp->cmd = genlh->cmd; + return rsp; + +err_free: + free(rsp); + return NULL; +} + +static const struct ynl_ntf_info netdev_ntf_info[] = { + [NETDEV_CMD_DEV_ADD_NTF] = { + .alloc_sz = sizeof(struct netdev_dev_get_ntf), + .cb = netdev_dev_get_rsp_parse, + .policy = &netdev_dev_nest, + .free = (void *)netdev_dev_get_ntf_free, + }, + [NETDEV_CMD_DEV_DEL_NTF] = { + .alloc_sz = sizeof(struct netdev_dev_get_ntf), + .cb = netdev_dev_get_rsp_parse, + .policy = &netdev_dev_nest, + .free = (void *)netdev_dev_get_ntf_free, + }, + [NETDEV_CMD_DEV_CHANGE_NTF] = { + .alloc_sz = sizeof(struct netdev_dev_get_ntf), + .cb = netdev_dev_get_rsp_parse, + .policy = &netdev_dev_nest, + .free = (void *)netdev_dev_get_ntf_free, + }, +}; + +const struct ynl_family ynl_netdev_family = { + .name = "netdev", + .ntf_info = netdev_ntf_info, + .ntf_info_size = MNL_ARRAY_SIZE(netdev_ntf_info), +}; diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h new file mode 100644 index 000000000000..d146bc4b2112 --- /dev/null +++ b/tools/net/ynl/generated/netdev-user.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/netdev.yaml */ +/* YNL-GEN user header */ + +#ifndef _LINUX_NETDEV_GEN_H +#define _LINUX_NETDEV_GEN_H + +#include +#include +#include +#include + +struct ynl_sock; + +extern const struct ynl_family ynl_netdev_family; + +/* Enums */ +const char *netdev_op_str(int op); +const char *netdev_xdp_act_str(enum netdev_xdp_act value); + +/* Common nested types */ +/* ============== NETDEV_CMD_DEV_GET ============== */ +/* NETDEV_CMD_DEV_GET - do */ +struct netdev_dev_get_req { + struct { + __u32 ifindex:1; + } _present; + + __u32 ifindex; +}; + +static inline struct netdev_dev_get_req *netdev_dev_get_req_alloc(void) +{ + return calloc(1, sizeof(struct netdev_dev_get_req)); +} +void netdev_dev_get_req_free(struct netdev_dev_get_req *req); + +static inline void +netdev_dev_get_req_set_ifindex(struct netdev_dev_get_req *req, __u32 ifindex) +{ + req->_present.ifindex = 1; + req->ifindex = ifindex; +} + +struct netdev_dev_get_rsp { + struct { + __u32 ifindex:1; + __u32 xdp_features:1; + } _present; + + __u32 ifindex; + __u64 xdp_features; +}; + +void netdev_dev_get_rsp_free(struct netdev_dev_get_rsp *rsp); + +/* + * Get / dump information about a netdev. + */ +struct netdev_dev_get_rsp * +netdev_dev_get(struct ynl_sock *ys, struct netdev_dev_get_req *req); + +/* NETDEV_CMD_DEV_GET - dump */ +struct netdev_dev_get_list { + struct netdev_dev_get_list *next; + struct netdev_dev_get_rsp obj __attribute__ ((aligned (8))); +}; + +void netdev_dev_get_list_free(struct netdev_dev_get_list *rsp); + +struct netdev_dev_get_list *netdev_dev_get_dump(struct ynl_sock *ys); + +/* NETDEV_CMD_DEV_GET - notify */ +struct netdev_dev_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct netdev_dev_get_ntf *ntf); + struct netdev_dev_get_rsp obj __attribute__ ((aligned (8))); +}; + +void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp); + +/* --------------- Common notification parsing --------------- */ +struct ynl_ntf_base_type *netdev_ntf_parse(struct ynl_sock *ys); + +#endif /* _LINUX_NETDEV_GEN_H */ -- cgit v1.2.3 From ee0202e2e731d074639461b3db2296bf44d847ce Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 5 Jun 2023 12:01:08 -0700 Subject: tools: ynl: add sample for netdev Add a sample application using the C library. My main goal is to make writing selftests easier but until I have some of those ready I think it's useful to show off the functionality and let people poke and tinker. Sample outputs - dump: $ ./netdev Select ifc ($ifindex; or 0 = dump; or -2 ntf check): 0 lo[1] 0: enp1s0[2] 23: basic redirect rx-sg Notifications (watching veth pair getting added and deleted): $ ./netdev Select ifc ($ifindex; or 0 = dump; or -2 ntf check): -2 [53] 0: (ntf: dev-add-ntf) [54] 0: (ntf: dev-add-ntf) [54] 23: basic redirect rx-sg (ntf: dev-change-ntf) [53] 23: basic redirect rx-sg (ntf: dev-change-ntf) [53] 23: basic redirect rx-sg (ntf: dev-del-ntf) [54] 23: basic redirect rx-sg (ntf: dev-del-ntf) Reviewed-by: Willem de Bruijn Signed-off-by: Jakub Kicinski --- tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/Makefile | 28 ++++++++++ tools/net/ynl/samples/netdev.c | 108 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 tools/net/ynl/samples/.gitignore create mode 100644 tools/net/ynl/samples/Makefile create mode 100644 tools/net/ynl/samples/netdev.c diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore new file mode 100644 index 000000000000..7b1f5179cb54 --- /dev/null +++ b/tools/net/ynl/samples/.gitignore @@ -0,0 +1 @@ +netdev diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile new file mode 100644 index 000000000000..714316cad45f --- /dev/null +++ b/tools/net/ynl/samples/Makefile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 + +CC=gcc +CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ + -I../lib/ -I../generated/ +ifeq ("$(DEBUG)","1") + CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan +endif + +LDLIBS=-lmnl ../lib/ynl.a ../generated/protos.a + +SRCS=$(wildcard *.c) +BINS=$(patsubst %.c,%,${SRCS}) + +include $(wildcard *.d) + +all: $(BINS) + +$(BINS): ../lib/ynl.a ../generated/protos.a + +clean: + rm -f *.o *.d *~ + +hardclean: clean + rm -f $(BINS) + +.PHONY: all clean +.DEFAULT_GOAL=all diff --git a/tools/net/ynl/samples/netdev.c b/tools/net/ynl/samples/netdev.c new file mode 100644 index 000000000000..d31268aa47c5 --- /dev/null +++ b/tools/net/ynl/samples/netdev.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include + +#include + +#include "netdev-user.h" + +/* netdev genetlink family code sample + * This sample shows off basics of the netdev family but also notification + * handling, hence the somewhat odd UI. We subscribe to notifications first + * then wait for ifc selection, so the socket may already accumulate + * notifications as we wait. This allows us to test that YNL can handle + * requests and notifications getting interleaved. + */ + +static void netdev_print_device(struct netdev_dev_get_rsp *d, unsigned int op) +{ + char ifname[IF_NAMESIZE]; + const char *name; + + if (!d->_present.ifindex) + return; + + name = if_indextoname(d->ifindex, ifname); + if (name) + printf("%8s", name); + printf("[%d]\t", d->ifindex); + + if (!d->_present.xdp_features) + return; + + printf("%llx:", d->xdp_features); + for (int i = 0; d->xdp_features > 1U << i; i++) { + if (d->xdp_features & (1U << i)) + printf(" %s", netdev_xdp_act_str(1 << i)); + } + + name = netdev_op_str(op); + if (name) + printf(" (ntf: %s)", name); + printf("\n"); +} + +int main(int argc, char **argv) +{ + struct netdev_dev_get_list *devs; + struct ynl_ntf_base_type *ntf; + struct ynl_error yerr; + struct ynl_sock *ys; + int ifindex = 0; + + if (argc > 1) + ifindex = strtol(argv[1], NULL, 0); + + ys = ynl_sock_create(&ynl_netdev_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + if (ynl_subscribe(ys, "mgmt")) + goto err_close; + + printf("Select ifc ($ifindex; or 0 = dump; or -2 ntf check): "); + scanf("%d", &ifindex); + + if (ifindex > 0) { + struct netdev_dev_get_req *req; + struct netdev_dev_get_rsp *d; + + req = netdev_dev_get_req_alloc(); + netdev_dev_get_req_set_ifindex(req, ifindex); + + d = netdev_dev_get(ys, req); + netdev_dev_get_req_free(req); + if (!d) + goto err_close; + + netdev_print_device(d, 0); + netdev_dev_get_rsp_free(d); + } else if (!ifindex) { + devs = netdev_dev_get_dump(ys); + if (!devs) + goto err_close; + + ynl_dump_foreach(devs, d) + netdev_print_device(d, 0); + netdev_dev_get_list_free(devs); + } else if (ifindex == -2) { + ynl_ntf_check(ys); + } + while ((ntf = ynl_ntf_dequeue(ys))) { + netdev_print_device((struct netdev_dev_get_rsp *)&ntf->data, + ntf->cmd); + ynl_ntf_free(ntf); + } + + ynl_sock_destroy(ys); + return 0; + +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); + ynl_sock_destroy(ys); + return 2; +} -- cgit v1.2.3 From aa7881fcfe9d328484265d589bc2785533e33c4d Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 6 Jun 2023 11:53:08 +0800 Subject: bpf: Factor out a common helper free_all() Factor out a common helper free_all() to free all normal elements or per-cpu elements on a lock-less list. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230606035310.4026145-2-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/memalloc.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/kernel/bpf/memalloc.c b/kernel/bpf/memalloc.c index 410637c225fb..0668bcd7c926 100644 --- a/kernel/bpf/memalloc.c +++ b/kernel/bpf/memalloc.c @@ -211,9 +211,9 @@ static void alloc_bulk(struct bpf_mem_cache *c, int cnt, int node) mem_cgroup_put(memcg); } -static void free_one(struct bpf_mem_cache *c, void *obj) +static void free_one(void *obj, bool percpu) { - if (c->percpu_size) { + if (percpu) { free_percpu(((void **)obj)[1]); kfree(obj); return; @@ -222,14 +222,19 @@ static void free_one(struct bpf_mem_cache *c, void *obj) kfree(obj); } -static void __free_rcu(struct rcu_head *head) +static void free_all(struct llist_node *llnode, bool percpu) { - struct bpf_mem_cache *c = container_of(head, struct bpf_mem_cache, rcu); - struct llist_node *llnode = llist_del_all(&c->waiting_for_gp); struct llist_node *pos, *t; llist_for_each_safe(pos, t, llnode) - free_one(c, pos); + free_one(pos, percpu); +} + +static void __free_rcu(struct rcu_head *head) +{ + struct bpf_mem_cache *c = container_of(head, struct bpf_mem_cache, rcu); + + free_all(llist_del_all(&c->waiting_for_gp), !!c->percpu_size); atomic_set(&c->call_rcu_in_progress, 0); } @@ -432,7 +437,7 @@ int bpf_mem_alloc_init(struct bpf_mem_alloc *ma, int size, bool percpu) static void drain_mem_cache(struct bpf_mem_cache *c) { - struct llist_node *llnode, *t; + bool percpu = !!c->percpu_size; /* No progs are using this bpf_mem_cache, but htab_map_free() called * bpf_mem_cache_free() for all remaining elements and they can be in @@ -441,14 +446,10 @@ static void drain_mem_cache(struct bpf_mem_cache *c) * Except for waiting_for_gp list, there are no concurrent operations * on these lists, so it is safe to use __llist_del_all(). */ - llist_for_each_safe(llnode, t, __llist_del_all(&c->free_by_rcu)) - free_one(c, llnode); - llist_for_each_safe(llnode, t, llist_del_all(&c->waiting_for_gp)) - free_one(c, llnode); - llist_for_each_safe(llnode, t, __llist_del_all(&c->free_llist)) - free_one(c, llnode); - llist_for_each_safe(llnode, t, __llist_del_all(&c->free_llist_extra)) - free_one(c, llnode); + free_all(__llist_del_all(&c->free_by_rcu), percpu); + free_all(llist_del_all(&c->waiting_for_gp), percpu); + free_all(__llist_del_all(&c->free_llist), percpu); + free_all(__llist_del_all(&c->free_llist_extra), percpu); } static void free_mem_alloc_no_barrier(struct bpf_mem_alloc *ma) -- cgit v1.2.3 From 26dd2974c5b5caef358784530c9e72715adc8f5b Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Mon, 5 Jun 2023 09:39:42 -0600 Subject: net: phy: micrel: Move KSZ9477 errata fixes to PHY driver The ksz9477 DSA switch driver is currently updating some MMD registers on the internal port PHYs to address some chip errata. However, these errata are really a property of the PHY itself, not the switch they are part of, so this is kind of a layering violation. It makes more sense for these writes to be done inside the driver which binds to the PHY and not the driver for the containing device. This also addresses some issues where the ordering of when these writes are done may have been incorrect, causing the link to erratically fail to come up at the proper speed or at all. Doing this in the PHY driver during config_init ensures that they happen before anything else tries to change the state of the PHY on the port. The new code also ensures that autonegotiation is disabled during the register writes and re-enabled afterwards, as indicated by the latest version of the errata documentation from Microchip. Signed-off-by: Robert Hancock Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/phy/micrel.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2094d49025a7..6d18ea19e442 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1774,6 +1774,79 @@ static int ksz886x_read_status(struct phy_device *phydev) return genphy_read_status(phydev); } +struct ksz9477_errata_write { + u8 dev_addr; + u8 reg_addr; + u16 val; +}; + +static const struct ksz9477_errata_write ksz9477_errata_writes[] = { + /* Register settings are needed to improve PHY receive performance */ + {0x01, 0x6f, 0xdd0b}, + {0x01, 0x8f, 0x6032}, + {0x01, 0x9d, 0x248c}, + {0x01, 0x75, 0x0060}, + {0x01, 0xd3, 0x7777}, + {0x1c, 0x06, 0x3008}, + {0x1c, 0x08, 0x2000}, + + /* Transmit waveform amplitude can be improved (1000BASE-T, 100BASE-TX, 10BASE-Te) */ + {0x1c, 0x04, 0x00d0}, + + /* Energy Efficient Ethernet (EEE) feature select must be manually disabled */ + {0x07, 0x3c, 0x0000}, + + /* Register settings are required to meet data sheet supply current specifications */ + {0x1c, 0x13, 0x6eff}, + {0x1c, 0x14, 0xe6ff}, + {0x1c, 0x15, 0x6eff}, + {0x1c, 0x16, 0xe6ff}, + {0x1c, 0x17, 0x00ff}, + {0x1c, 0x18, 0x43ff}, + {0x1c, 0x19, 0xc3ff}, + {0x1c, 0x1a, 0x6fff}, + {0x1c, 0x1b, 0x07ff}, + {0x1c, 0x1c, 0x0fff}, + {0x1c, 0x1d, 0xe7ff}, + {0x1c, 0x1e, 0xefff}, + {0x1c, 0x20, 0xeeee}, +}; + +static int ksz9477_config_init(struct phy_device *phydev) +{ + int err; + int i; + + /* Apply PHY settings to address errata listed in + * KSZ9477, KSZ9897, KSZ9896, KSZ9567, KSZ8565 + * Silicon Errata and Data Sheet Clarification documents. + * + * Document notes: Before configuring the PHY MMD registers, it is + * necessary to set the PHY to 100 Mbps speed with auto-negotiation + * disabled by writing to register 0xN100-0xN101. After writing the + * MMD registers, and after all errata workarounds that involve PHY + * register settings, write register 0xN100-0xN101 again to enable + * and restart auto-negotiation. + */ + err = phy_write(phydev, MII_BMCR, BMCR_SPEED100 | BMCR_FULLDPLX); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(ksz9477_errata_writes); ++i) { + const struct ksz9477_errata_write *errata = &ksz9477_errata_writes[i]; + + err = phy_write_mmd(phydev, errata->dev_addr, errata->reg_addr, errata->val); + if (err) + return err; + } + + err = genphy_restart_aneg(phydev); + if (err) + return err; + + return kszphy_config_init(phydev); +} + static int kszphy_get_sset_count(struct phy_device *phydev) { return ARRAY_SIZE(kszphy_hw_stats); @@ -4735,7 +4808,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = MICREL_PHY_ID_MASK, .name = "Microchip KSZ9477", /* PHY_GBIT_FEATURES */ - .config_init = kszphy_config_init, + .config_init = ksz9477_config_init, .config_intr = kszphy_config_intr, .handle_interrupt = kszphy_handle_interrupt, .suspend = genphy_suspend, -- cgit v1.2.3 From 6068e6d7ba5001dfb96bb8b7b92e2ed2a5877786 Mon Sep 17 00:00:00 2001 From: Robert Hancock Date: Mon, 5 Jun 2023 09:39:43 -0600 Subject: net: dsa: microchip: remove KSZ9477 PHY errata handling The KSZ9477 PHY errata handling code has now been moved into the Micrel PHY driver, so it is no longer needed inside the DSA switch driver. Remove it. Signed-off-by: Robert Hancock Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz9477.c | 74 ++-------------------------------- drivers/net/dsa/microchip/ksz_common.c | 4 -- drivers/net/dsa/microchip/ksz_common.h | 1 - 3 files changed, 4 insertions(+), 75 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 3019f54049fc..fc5157a10af5 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -889,62 +889,6 @@ static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port) return interface; } -static void ksz9477_port_mmd_write(struct ksz_device *dev, int port, - u8 dev_addr, u16 reg_addr, u16 val) -{ - ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP, - MMD_SETUP(PORT_MMD_OP_INDEX, dev_addr)); - ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, reg_addr); - ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP, - MMD_SETUP(PORT_MMD_OP_DATA_NO_INCR, dev_addr)); - ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, val); -} - -static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port) -{ - /* Apply PHY settings to address errata listed in - * KSZ9477, KSZ9897, KSZ9896, KSZ9567, KSZ8565 - * Silicon Errata and Data Sheet Clarification documents: - * - * Register settings are needed to improve PHY receive performance - */ - ksz9477_port_mmd_write(dev, port, 0x01, 0x6f, 0xdd0b); - ksz9477_port_mmd_write(dev, port, 0x01, 0x8f, 0x6032); - ksz9477_port_mmd_write(dev, port, 0x01, 0x9d, 0x248c); - ksz9477_port_mmd_write(dev, port, 0x01, 0x75, 0x0060); - ksz9477_port_mmd_write(dev, port, 0x01, 0xd3, 0x7777); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x06, 0x3008); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x08, 0x2001); - - /* Transmit waveform amplitude can be improved - * (1000BASE-T, 100BASE-TX, 10BASE-Te) - */ - ksz9477_port_mmd_write(dev, port, 0x1c, 0x04, 0x00d0); - - /* Energy Efficient Ethernet (EEE) feature select must - * be manually disabled (except on KSZ8565 which is 100Mbit) - */ - if (dev->info->gbit_capable[port]) - ksz9477_port_mmd_write(dev, port, 0x07, 0x3c, 0x0000); - - /* Register settings are required to meet data sheet - * supply current specifications - */ - ksz9477_port_mmd_write(dev, port, 0x1c, 0x13, 0x6eff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x14, 0xe6ff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x15, 0x6eff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x16, 0xe6ff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x17, 0x00ff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x18, 0x43ff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x19, 0xc3ff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x1a, 0x6fff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x1b, 0x07ff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x1c, 0x0fff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x1d, 0xe7ff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x1e, 0xefff); - ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee); -} - void ksz9477_get_caps(struct ksz_device *dev, int port, struct phylink_config *config) { @@ -1029,20 +973,10 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port) /* enable 802.1p priority */ ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true); - if (dev->info->internal_phy[port]) { - /* do not force flow control */ - ksz_port_cfg(dev, port, REG_PORT_CTRL_0, - PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, - false); - - if (dev->info->phy_errata_9477) - ksz9477_phy_errata_setup(dev, port); - } else { - /* force flow control */ - ksz_port_cfg(dev, port, REG_PORT_CTRL_0, - PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, - true); - } + /* force flow control for non-PHY ports only */ + ksz_port_cfg(dev, port, REG_PORT_CTRL_0, + PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL, + !dev->info->internal_phy[port]); if (cpu_port) member = dsa_user_ports(ds); diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 768f649d2f40..813b91a816bb 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1270,7 +1270,6 @@ const struct ksz_chip_data ksz_switch_chips[] = { .tc_cbs_supported = true, .tc_ets_supported = true, .ops = &ksz9477_dev_ops, - .phy_errata_9477 = true, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, @@ -1303,7 +1302,6 @@ const struct ksz_chip_data ksz_switch_chips[] = { .port_nirqs = 2, .num_tx_queues = 4, .ops = &ksz9477_dev_ops, - .phy_errata_9477 = true, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, @@ -1336,7 +1334,6 @@ const struct ksz_chip_data ksz_switch_chips[] = { .port_nirqs = 2, .num_tx_queues = 4, .ops = &ksz9477_dev_ops, - .phy_errata_9477 = true, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, @@ -1423,7 +1420,6 @@ const struct ksz_chip_data ksz_switch_chips[] = { .tc_cbs_supported = true, .tc_ets_supported = true, .ops = &ksz9477_dev_ops, - .phy_errata_9477 = true, .mib_names = ksz9477_mib_names, .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), .reg_mib_cnt = MIB_COUNTER_NUM, diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 5aa58aac3e07..a66b56857ec6 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -60,7 +60,6 @@ struct ksz_chip_data { bool tc_cbs_supported; bool tc_ets_supported; const struct ksz_dev_ops *ops; - bool phy_errata_9477; bool ksz87xx_eee_link_erratum; const struct ksz_mib_names *mib_names; int mib_cnt; -- cgit v1.2.3 From 4b095281cacab0b62e7f11d6d8c4a6d49ecaae42 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 5 Jun 2023 23:55:25 +0200 Subject: ipv4: Set correct scope in inet_csk_route_*(). RT_CONN_FLAGS(sk) overloads the tos parameter with the RTO_ONLINK bit when sk has the SOCK_LOCALROUTE flag set. This is only useful for ip_route_output_key_hash() to eventually adjust the route scope. Let's drop RTO_ONLINK and set the correct scope directly to avoid this special case in the future and to allow converting ->flowi4_tos to dscp_t. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: Jakub Kicinski --- net/ipv4/inet_connection_sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 1386787eaf1a..15424dec4584 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -792,7 +792,7 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk, opt = rcu_dereference(ireq->ireq_opt); flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, - RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, + ip_sock_rt_tos(sk), ip_sock_rt_scope(sk), sk->sk_protocol, inet_sk_flowi_flags(sk), (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, ireq->ir_loc_addr, ireq->ir_rmt_port, @@ -830,7 +830,7 @@ struct dst_entry *inet_csk_route_child_sock(const struct sock *sk, fl4 = &newinet->cork.fl.u.ip4; flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, - RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, + ip_sock_rt_tos(sk), ip_sock_rt_scope(sk), sk->sk_protocol, inet_sk_flowi_flags(sk), (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, ireq->ir_loc_addr, ireq->ir_rmt_port, -- cgit v1.2.3 From 6f8a76f8022121f7e4dc9cc29da7fb716b7db45f Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 5 Jun 2023 23:55:30 +0200 Subject: tcp: Set route scope properly in cookie_v4_check(). RT_CONN_FLAGS(sk) overloads flowi4_tos with the RTO_ONLINK bit when sk has the SOCK_LOCALROUTE flag set. This allows ip_route_output_key_hash() to eventually adjust flowi4_scope. Instead of relying on special handling of the RTO_ONLINK bit, we can just set the route scope correctly. This will eventually allow to avoid special interpretation of tos variables and to convert ->flowi4_tos to dscp_t. Signed-off-by: Guillaume Nault Reviewed-by: David Ahern Signed-off-by: Jakub Kicinski --- net/ipv4/syncookies.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 26fb97d1d4d9..dc478a0574cb 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -418,8 +418,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb) * no easy way to do this. */ flowi4_init_output(&fl4, ireq->ir_iif, ireq->ir_mark, - RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP, - inet_sk_flowi_flags(sk), + ip_sock_rt_tos(sk), ip_sock_rt_scope(sk), + IPPROTO_TCP, inet_sk_flowi_flags(sk), opt->srr ? opt->faddr : ireq->ir_rmt_addr, ireq->ir_loc_addr, th->source, th->dest, sk->sk_uid); security_req_classify_flow(req, flowi4_to_flowi_common(&fl4)); -- cgit v1.2.3 From ae28ea5cbdee9956464223b304d6c767238b2506 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 5 Jun 2023 10:40:44 -0400 Subject: tipc: replace open-code bearer rcu_dereference access in bearer.c Replace these open-code bearer rcu_dereference access with bearer_get(), like other places in bearer.c. While at it, also use tipc_net() instead of net_generic(net, tipc_net_id) to get "tn" in bearer.c. Signed-off-by: Xin Long Reviewed-by: Larysa Zaremba Reviewed-by: Tung Nguyen Link: https://lore.kernel.org/r/1072588a8691f970bda950c7e2834d1f2983f58e.1685976044.git.lucien.xin@gmail.com Signed-off-by: Jakub Kicinski --- net/tipc/bearer.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 114140c49108..1d5d3677bdaf 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -176,7 +176,7 @@ static int bearer_name_validate(const char *name, */ struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name) { - struct tipc_net *tn = net_generic(net, tipc_net_id); + struct tipc_net *tn = tipc_net(net); struct tipc_bearer *b; u32 i; @@ -211,11 +211,10 @@ int tipc_bearer_get_name(struct net *net, char *name, u32 bearer_id) void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest) { - struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_bearer *b; rcu_read_lock(); - b = rcu_dereference(tn->bearer_list[bearer_id]); + b = bearer_get(net, bearer_id); if (b) tipc_disc_add_dest(b->disc); rcu_read_unlock(); @@ -223,11 +222,10 @@ void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest) void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest) { - struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_bearer *b; rcu_read_lock(); - b = rcu_dereference(tn->bearer_list[bearer_id]); + b = bearer_get(net, bearer_id); if (b) tipc_disc_remove_dest(b->disc); rcu_read_unlock(); @@ -534,7 +532,7 @@ int tipc_bearer_mtu(struct net *net, u32 bearer_id) struct tipc_bearer *b; rcu_read_lock(); - b = rcu_dereference(tipc_net(net)->bearer_list[bearer_id]); + b = bearer_get(net, bearer_id); if (b) mtu = b->mtu; rcu_read_unlock(); @@ -745,7 +743,7 @@ void tipc_bearer_cleanup(void) void tipc_bearer_stop(struct net *net) { - struct tipc_net *tn = net_generic(net, tipc_net_id); + struct tipc_net *tn = tipc_net(net); struct tipc_bearer *b; u32 i; @@ -881,7 +879,7 @@ int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb) struct tipc_bearer *bearer; struct tipc_nl_msg msg; struct net *net = sock_net(skb->sk); - struct tipc_net *tn = net_generic(net, tipc_net_id); + struct tipc_net *tn = tipc_net(net); if (i == MAX_BEARERS) return 0; -- cgit v1.2.3 From 4cab498f33f7adaa01ad15909c0f34a81e5a0b0a Mon Sep 17 00:00:00 2001 From: Shradha Gupta Date: Mon, 5 Jun 2023 04:30:06 -0700 Subject: hv_netvsc: Allocate rx indirection table size dynamically Allocate the size of rx indirection table dynamically in netvsc from the value of size provided by OID_GEN_RECEIVE_SCALE_CAPABILITIES query instead of using a constant value of ITAB_NUM. Signed-off-by: Shradha Gupta Reviewed-by: Haiyang Zhang Tested-on: Ubuntu22 (azure VM, SKU size: Standard_F72s_v2) Testcases: 1. ethtool -x eth0 output 2. LISA testcase:PERF-NETWORK-TCP-THROUGHPUT-MULTICONNECTION-NTTTCP-Synthetic 3. LISA testcase:PERF-NETWORK-TCP-THROUGHPUT-MULTICONNECTION-NTTTCP-SRIOV Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 5 ++++- drivers/net/hyperv/netvsc_drv.c | 10 ++++++---- drivers/net/hyperv/rndis_filter.c | 29 +++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 33d51e363913..c9dd69dbe1b8 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -74,6 +74,7 @@ struct ndis_recv_scale_cap { /* NDIS_RECEIVE_SCALE_CAPABILITIES */ #define NDIS_RSS_HASH_SECRET_KEY_MAX_SIZE_REVISION_2 40 #define ITAB_NUM 128 +#define ITAB_NUM_MAX 256 struct ndis_recv_scale_param { /* NDIS_RECEIVE_SCALE_PARAMETERS */ struct ndis_obj_header hdr; @@ -1034,7 +1035,9 @@ struct net_device_context { u32 tx_table[VRSS_SEND_TAB_SIZE]; - u16 rx_table[ITAB_NUM]; + u16 *rx_table; + + u32 rx_table_sz; /* Ethtool settings */ u8 duplex; diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 0103ff914024..3ba3c8fb28a5 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1747,7 +1747,9 @@ static u32 netvsc_get_rxfh_key_size(struct net_device *dev) static u32 netvsc_rss_indir_size(struct net_device *dev) { - return ITAB_NUM; + struct net_device_context *ndc = netdev_priv(dev); + + return ndc->rx_table_sz; } static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, @@ -1766,7 +1768,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, rndis_dev = ndev->extension; if (indir) { - for (i = 0; i < ITAB_NUM; i++) + for (i = 0; i < ndc->rx_table_sz; i++) indir[i] = ndc->rx_table[i]; } @@ -1792,11 +1794,11 @@ static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir, rndis_dev = ndev->extension; if (indir) { - for (i = 0; i < ITAB_NUM; i++) + for (i = 0; i < ndc->rx_table_sz; i++) if (indir[i] >= ndev->num_chn) return -EINVAL; - for (i = 0; i < ITAB_NUM; i++) + for (i = 0; i < ndc->rx_table_sz; i++) ndc->rx_table[i] = indir[i]; } diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index eea777ec2541..af95947a87c5 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "hyperv_net.h" #include "netvsc_trace.h" @@ -927,7 +928,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, struct rndis_set_request *set; struct rndis_set_complete *set_complete; u32 extlen = sizeof(struct ndis_recv_scale_param) + - 4 * ITAB_NUM + NETVSC_HASH_KEYLEN; + 4 * ndc->rx_table_sz + NETVSC_HASH_KEYLEN; struct ndis_recv_scale_param *rssp; u32 *itab; u8 *keyp; @@ -953,7 +954,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, rssp->hashinfo = NDIS_HASH_FUNC_TOEPLITZ | NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 | NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6; - rssp->indirect_tabsize = 4*ITAB_NUM; + rssp->indirect_tabsize = 4 * ndc->rx_table_sz; rssp->indirect_taboffset = sizeof(struct ndis_recv_scale_param); rssp->hashkey_size = NETVSC_HASH_KEYLEN; rssp->hashkey_offset = rssp->indirect_taboffset + @@ -961,7 +962,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, /* Set indirection table entries */ itab = (u32 *)(rssp + 1); - for (i = 0; i < ITAB_NUM; i++) + for (i = 0; i < ndc->rx_table_sz; i++) itab[i] = ndc->rx_table[i]; /* Set hask key values */ @@ -1548,6 +1549,18 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, if (ret || rsscap.num_recv_que < 2) goto out; + if (rsscap.num_indirect_tabent && + rsscap.num_indirect_tabent <= ITAB_NUM_MAX) + ndc->rx_table_sz = rsscap.num_indirect_tabent; + else + ndc->rx_table_sz = ITAB_NUM; + + ndc->rx_table = kcalloc(ndc->rx_table_sz, sizeof(u16), GFP_KERNEL); + if (!ndc->rx_table) { + ret = -ENOMEM; + goto err_dev_remv; + } + /* This guarantees that num_possible_rss_qs <= num_online_cpus */ num_possible_rss_qs = min_t(u32, num_online_cpus(), rsscap.num_recv_que); @@ -1558,7 +1571,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, net_device->num_chn = min(net_device->max_chn, device_info->num_chn); if (!netif_is_rxfh_configured(net)) { - for (i = 0; i < ITAB_NUM; i++) + for (i = 0; i < ndc->rx_table_sz; i++) ndc->rx_table[i] = ethtool_rxfh_indir_default( i, net_device->num_chn); } @@ -1596,11 +1609,19 @@ void rndis_filter_device_remove(struct hv_device *dev, struct netvsc_device *net_dev) { struct rndis_device *rndis_dev = net_dev->extension; + struct net_device *net = hv_get_drvdata(dev); + struct net_device_context *ndc; + + ndc = netdev_priv(net); /* Halt and release the rndis device */ rndis_filter_halt_device(net_dev, rndis_dev); netvsc_device_remove(dev); + + ndc->rx_table_sz = 0; + kfree(ndc->rx_table); + ndc->rx_table = NULL; } int rndis_filter_open(struct netvsc_device *nvdev) -- cgit v1.2.3 From 7300c9b574cc2b259ef112d34affa0671ae4810a Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Mon, 5 Jun 2023 11:40:08 -0400 Subject: net: phy: realtek: Add optional external PHY clock In some cases, the PHY can use an external clock source instead of a crystal. Add an optional clock in the phy node to make sure that the clock source is enabled, if specified, before probing. Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: Detlev Casanova Signed-off-by: David S. Miller --- drivers/net/phy/realtek.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 3d99fd6664d7..b13dd0b3c99e 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -12,6 +12,7 @@ #include #include #include +#include #define RTL821x_PHYSR 0x11 #define RTL821x_PHYSR_DUPLEX BIT(13) @@ -80,6 +81,7 @@ struct rtl821x_priv { u16 phycr1; u16 phycr2; bool has_phycr2; + struct clk *clk; }; static int rtl821x_read_page(struct phy_device *phydev) @@ -103,6 +105,11 @@ static int rtl821x_probe(struct phy_device *phydev) if (!priv) return -ENOMEM; + priv->clk = devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), + "failed to get phy clock\n"); + ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1); if (ret < 0) return ret; -- cgit v1.2.3 From 350b7a258f20427a411a888e5af0684327d49e3a Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Mon, 5 Jun 2023 11:40:09 -0400 Subject: dt-bindings: net: phy: Document support for external PHY clk Ethern PHYs can have external an clock that needs to be activated before communicating with the PHY. Acked-by: Krzysztof Kozlowski Signed-off-by: Detlev Casanova Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/ethernet-phy.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/net/ethernet-phy.yaml b/Documentation/devicetree/bindings/net/ethernet-phy.yaml index 4f574532ee13..c1241c8a3b77 100644 --- a/Documentation/devicetree/bindings/net/ethernet-phy.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-phy.yaml @@ -93,6 +93,12 @@ properties: the turn around line low at end of the control phase of the MDIO transaction. + clocks: + maxItems: 1 + description: + External clock connected to the PHY. If not specified it is assumed + that the PHY uses a fixed crystal or an internal oscillator. + enet-phy-lane-swap: $ref: /schemas/types.yaml#/definitions/flag description: -- cgit v1.2.3 From 59e227e2894b28c4409e89d04a33868c176587b2 Mon Sep 17 00:00:00 2001 From: Detlev Casanova Date: Mon, 5 Jun 2023 11:40:10 -0400 Subject: net: phy: realtek: Disable clock on suspend For PHYs that call rtl821x_probe() where an external clock can be configured, make sure that the clock is disabled when ->suspend() is called and enabled on resume. The PHY_ALWAYS_CALL_SUSPEND is added to ensure that the suspend function is actually always called. Reviewed-by: Florian Fainelli Signed-off-by: Detlev Casanova Signed-off-by: David S. Miller --- drivers/net/phy/realtek.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index b13dd0b3c99e..894172a3e15f 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -426,10 +426,31 @@ static int rtl8211f_config_init(struct phy_device *phydev) return genphy_soft_reset(phydev); } +static int rtl821x_suspend(struct phy_device *phydev) +{ + struct rtl821x_priv *priv = phydev->priv; + int ret = 0; + + if (!phydev->wol_enabled) { + ret = genphy_suspend(phydev); + + if (ret) + return ret; + + clk_disable_unprepare(priv->clk); + } + + return ret; +} + static int rtl821x_resume(struct phy_device *phydev) { + struct rtl821x_priv *priv = phydev->priv; int ret; + if (!phydev->wol_enabled) + clk_prepare_enable(priv->clk); + ret = genphy_resume(phydev); if (ret < 0) return ret; @@ -934,10 +955,11 @@ static struct phy_driver realtek_drvs[] = { .read_status = rtlgen_read_status, .config_intr = &rtl8211f_config_intr, .handle_interrupt = rtl8211f_handle_interrupt, - .suspend = genphy_suspend, + .suspend = rtl821x_suspend, .resume = rtl821x_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, + .flags = PHY_ALWAYS_CALL_SUSPEND, }, { PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID), .name = "RTL8211F-VD Gigabit Ethernet", @@ -946,10 +968,11 @@ static struct phy_driver realtek_drvs[] = { .read_status = rtlgen_read_status, .config_intr = &rtl8211f_config_intr, .handle_interrupt = rtl8211f_handle_interrupt, - .suspend = genphy_suspend, + .suspend = rtl821x_suspend, .resume = rtl821x_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, + .flags = PHY_ALWAYS_CALL_SUSPEND, }, { .name = "Generic FE-GE Realtek PHY", .match_phy_device = rtlgen_match_phy_device, -- cgit v1.2.3 From cad7526f33ce1e7d387d1d0568a089e41deec5c2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 6 Jun 2023 11:24:37 +0300 Subject: net: dsa: ocelot: unlock on error in vsc9959_qos_port_tas_set() This error path needs call mutex_unlock(&ocelot->tas_lock) before returning. Fixes: 2d800bc500fb ("net/sched: taprio: replace tc_taprio_qopt_offload :: enable with a "cmd" enum") Signed-off-by: Dan Carpenter Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index 5de6a27052fc..903532ea9fa4 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -1424,7 +1424,8 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port, mutex_unlock(&ocelot->tas_lock); return 0; } else if (taprio->cmd != TAPRIO_CMD_REPLACE) { - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto err_unlock; } ret = ocelot_port_mqprio(ocelot, port, &taprio->mqprio); -- cgit v1.2.3 From 0824a987a58070470351906590a89fa5e0f88ba1 Mon Sep 17 00:00:00 2001 From: David Morley Date: Tue, 6 Jun 2023 18:12:33 +0000 Subject: tcp: fix formatting in sysctl_net_ipv4.c Fix incorrectly formatted tcp_syn_linear_timeouts sysctl in the ipv4_net_table. Fixes: ccce324dabfe ("tcp: make the first N SYN RTO backoffs linear") Signed-off-by: David Morley Signed-off-by: Neal Cardwell Tested-by: David Morley Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/sysctl_net_ipv4.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 6ae3345a3bdf..ef26f9013a0f 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1472,13 +1472,13 @@ static struct ctl_table ipv4_net_table[] = { .extra2 = &tcp_plb_max_cong_thresh, }, { - .procname = "tcp_syn_linear_timeouts", - .data = &init_net.ipv4.sysctl_tcp_syn_linear_timeouts, - .maxlen = sizeof(u8), - .mode = 0644, - .proc_handler = proc_dou8vec_minmax, - .extra1 = SYSCTL_ZERO, - .extra2 = &tcp_syn_linear_timeouts_max, + .procname = "tcp_syn_linear_timeouts", + .data = &init_net.ipv4.sysctl_tcp_syn_linear_timeouts, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = &tcp_syn_linear_timeouts_max, }, { } }; -- cgit v1.2.3 From f71be9d084c92e0ef36e248303f32f8e4cf623da Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 7 Jun 2023 02:18:49 +0900 Subject: net: liquidio: fix mixed module-builtin object With CONFIG_LIQUIDIO=m and CONFIG_LIQUIDIO_VF=y (or vice versa), $(common-objs) are linked to a module and also to vmlinux even though the expected CFLAGS are different between builtins and modules. This is the same situation as fixed by commit 637a642f5ca5 ("zstd: Fixing mixed module-builtin objects"). Introduce the new module, liquidio-core, to provide the common functions to liquidio and liquidio-vf. Signed-off-by: Masahiro Yamada Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/Kconfig | 5 +++++ drivers/net/ethernet/cavium/liquidio/Makefile | 8 +++++--- .../ethernet/cavium/liquidio/cn23xx_pf_device.c | 4 ++++ .../ethernet/cavium/liquidio/cn23xx_vf_device.c | 3 +++ .../net/ethernet/cavium/liquidio/cn66xx_device.c | 1 + .../net/ethernet/cavium/liquidio/cn68xx_device.c | 1 + drivers/net/ethernet/cavium/liquidio/lio_core.c | 16 +++++++++++++++ drivers/net/ethernet/cavium/liquidio/lio_ethtool.c | 1 + .../net/ethernet/cavium/liquidio/octeon_device.c | 24 ++++++++++++++++++++++ drivers/net/ethernet/cavium/liquidio/octeon_droq.c | 4 ++++ .../net/ethernet/cavium/liquidio/octeon_mem_ops.c | 5 +++++ drivers/net/ethernet/cavium/liquidio/octeon_nic.c | 3 +++ .../net/ethernet/cavium/liquidio/request_manager.c | 14 +++++++++++++ .../ethernet/cavium/liquidio/response_manager.c | 3 +++ 14 files changed, 89 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig index 1c76c95b0b27..ca742cc146d7 100644 --- a/drivers/net/ethernet/cavium/Kconfig +++ b/drivers/net/ethernet/cavium/Kconfig @@ -62,6 +62,9 @@ config CAVIUM_PTP Precision Time Protocol or other purposes. Timestamps can be used in BGX, TNS, GTI, and NIC blocks. +config LIQUIDIO_CORE + tristate + config LIQUIDIO tristate "Cavium LiquidIO support" depends on 64BIT && PCI @@ -69,6 +72,7 @@ config LIQUIDIO depends on PTP_1588_CLOCK_OPTIONAL select FW_LOADER select LIBCRC32C + select LIQUIDIO_CORE select NET_DEVLINK help This driver supports Cavium LiquidIO Intelligent Server Adapters @@ -92,6 +96,7 @@ config LIQUIDIO_VF tristate "Cavium LiquidIO VF support" depends on 64BIT && PCI_MSI depends on PTP_1588_CLOCK_OPTIONAL + select LIQUIDIO_CORE help This driver supports Cavium LiquidIO Intelligent Server Adapter based on CN23XX chips. diff --git a/drivers/net/ethernet/cavium/liquidio/Makefile b/drivers/net/ethernet/cavium/liquidio/Makefile index bc9937502043..4ee80af88e79 100644 --- a/drivers/net/ethernet/cavium/liquidio/Makefile +++ b/drivers/net/ethernet/cavium/liquidio/Makefile @@ -3,7 +3,9 @@ # Cavium Liquidio ethernet device driver # -common-objs := lio_ethtool.o \ +obj-$(CONFIG_LIQUIDIO_CORE) += liquidio-core.o +liquidio-core-y := \ + lio_ethtool.o \ lio_core.o \ request_manager.o \ response_manager.o \ @@ -18,7 +20,7 @@ common-objs := lio_ethtool.o \ octeon_nic.o obj-$(CONFIG_LIQUIDIO) += liquidio.o -liquidio-y := lio_main.o octeon_console.o lio_vf_rep.o $(common-objs) +liquidio-y := lio_main.o octeon_console.o lio_vf_rep.o obj-$(CONFIG_LIQUIDIO_VF) += liquidio_vf.o -liquidio_vf-y := lio_vf_main.o $(common-objs) +liquidio_vf-y := lio_vf_main.o diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index 285d3825cad3..068ed52b66c9 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -1375,6 +1375,7 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(setup_cn23xx_octeon_pf_device); int validate_cn23xx_pf_config_info(struct octeon_device *oct, struct octeon_config *conf23xx) @@ -1433,6 +1434,7 @@ int cn23xx_fw_loaded(struct octeon_device *oct) val = octeon_read_csr64(oct, CN23XX_SLI_SCRATCH2); return (val >> SCR2_BIT_FW_LOADED) & 1ULL; } +EXPORT_SYMBOL_GPL(cn23xx_fw_loaded); void cn23xx_tell_vf_its_macaddr_changed(struct octeon_device *oct, int vfidx, u8 *mac) @@ -1454,6 +1456,7 @@ void cn23xx_tell_vf_its_macaddr_changed(struct octeon_device *oct, int vfidx, octeon_mbox_write(oct, &mbox_cmd); } } +EXPORT_SYMBOL_GPL(cn23xx_tell_vf_its_macaddr_changed); static void cn23xx_get_vf_stats_callback(struct octeon_device *oct, @@ -1508,3 +1511,4 @@ int cn23xx_get_vf_stats(struct octeon_device *oct, int vfidx, return 0; } +EXPORT_SYMBOL_GPL(cn23xx_get_vf_stats); diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c index b3bd2767d3dd..dd5d80fee24f 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c @@ -384,6 +384,7 @@ void cn23xx_vf_ask_pf_to_do_flr(struct octeon_device *oct) octeon_mbox_write(oct, &mbox_cmd); } +EXPORT_SYMBOL_GPL(cn23xx_vf_ask_pf_to_do_flr); static void octeon_pfvf_hs_callback(struct octeon_device *oct, struct octeon_mbox_cmd *cmd, @@ -466,6 +467,7 @@ int cn23xx_octeon_pfvf_handshake(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(cn23xx_octeon_pfvf_handshake); static void cn23xx_handle_vf_mbox_intr(struct octeon_ioq_vector *ioq_vector) { @@ -678,3 +680,4 @@ int cn23xx_setup_octeon_vf_device(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(cn23xx_setup_octeon_vf_device); diff --git a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c index 39643be8c30a..93fccfec288d 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn66xx_device.c @@ -697,6 +697,7 @@ int lio_setup_cn66xx_octeon_device(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(lio_setup_cn66xx_octeon_device); int lio_validate_cn6xxx_config_info(struct octeon_device *oct, struct octeon_config *conf6xxx) diff --git a/drivers/net/ethernet/cavium/liquidio/cn68xx_device.c b/drivers/net/ethernet/cavium/liquidio/cn68xx_device.c index 30254e4cf70f..b5103def3761 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn68xx_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn68xx_device.c @@ -181,3 +181,4 @@ int lio_setup_cn68xx_octeon_device(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(lio_setup_cn68xx_octeon_device); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 882b2be06ea0..9cc6303c82ff 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -26,6 +26,9 @@ #include "octeon_main.h" #include "octeon_network.h" +MODULE_AUTHOR("Cavium Networks, "); +MODULE_LICENSE("GPL"); + /* OOM task polling interval */ #define LIO_OOM_POLL_INTERVAL_MS 250 @@ -71,6 +74,7 @@ void lio_delete_glists(struct lio *lio) kfree(lio->glist); lio->glist = NULL; } +EXPORT_SYMBOL_GPL(lio_delete_glists); /** * lio_setup_glists - Setup gather lists @@ -154,6 +158,7 @@ int lio_setup_glists(struct octeon_device *oct, struct lio *lio, int num_iqs) return 0; } +EXPORT_SYMBOL_GPL(lio_setup_glists); int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1) { @@ -180,6 +185,7 @@ int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1) } return ret; } +EXPORT_SYMBOL_GPL(liquidio_set_feature); void octeon_report_tx_completion_to_bql(void *txq, unsigned int pkts_compl, unsigned int bytes_compl) @@ -395,6 +401,7 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr) nctrl->ncmd.s.cmd); } } +EXPORT_SYMBOL_GPL(liquidio_link_ctrl_cmd_completion); void octeon_pf_changed_vf_macaddr(struct octeon_device *oct, u8 *mac) { @@ -478,6 +485,7 @@ int setup_rx_oom_poll_fn(struct net_device *netdev) return 0; } +EXPORT_SYMBOL_GPL(setup_rx_oom_poll_fn); void cleanup_rx_oom_poll_fn(struct net_device *netdev) { @@ -495,6 +503,7 @@ void cleanup_rx_oom_poll_fn(struct net_device *netdev) } } } +EXPORT_SYMBOL_GPL(cleanup_rx_oom_poll_fn); /* Runs in interrupt context. */ static void lio_update_txq_status(struct octeon_device *oct, int iq_num) @@ -899,6 +908,7 @@ int liquidio_setup_io_queues(struct octeon_device *octeon_dev, int ifidx, return 0; } +EXPORT_SYMBOL_GPL(liquidio_setup_io_queues); static int liquidio_schedule_msix_droq_pkt_handler(struct octeon_droq *droq, u64 ret) @@ -1194,6 +1204,7 @@ int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs) } return 0; } +EXPORT_SYMBOL_GPL(octeon_setup_interrupt); /** * liquidio_change_mtu - Net device change_mtu @@ -1256,6 +1267,7 @@ int liquidio_change_mtu(struct net_device *netdev, int new_mtu) WRITE_ONCE(sc->caller_is_done, true); return 0; } +EXPORT_SYMBOL_GPL(liquidio_change_mtu); int lio_wait_for_clean_oq(struct octeon_device *oct) { @@ -1279,6 +1291,7 @@ int lio_wait_for_clean_oq(struct octeon_device *oct) return pending_pkts; } +EXPORT_SYMBOL_GPL(lio_wait_for_clean_oq); static void octnet_nic_stats_callback(struct octeon_device *oct_dev, @@ -1509,6 +1522,7 @@ lio_fetch_stats_exit: return; } +EXPORT_SYMBOL_GPL(lio_fetch_stats); int liquidio_set_speed(struct lio *lio, int speed) { @@ -1659,6 +1673,7 @@ int liquidio_get_speed(struct lio *lio) return retval; } +EXPORT_SYMBOL_GPL(liquidio_get_speed); int liquidio_set_fec(struct lio *lio, int on_off) { @@ -1812,3 +1827,4 @@ int liquidio_get_fec(struct lio *lio) return retval; } +EXPORT_SYMBOL_GPL(liquidio_get_fec); diff --git a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c index 2c10ae3f7fc1..9d56181a301f 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_ethtool.c @@ -3180,3 +3180,4 @@ void liquidio_set_ethtool_ops(struct net_device *netdev) else netdev->ethtool_ops = &lio_ethtool_ops; } +EXPORT_SYMBOL_GPL(liquidio_set_ethtool_ops); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_device.c b/drivers/net/ethernet/cavium/liquidio/octeon_device.c index e159194d0aef..364f4f912dc2 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_device.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_device.c @@ -564,6 +564,7 @@ void octeon_init_device_list(int conf_type) for (i = 0; i < MAX_OCTEON_DEVICES; i++) oct_set_config_info(i, conf_type); } +EXPORT_SYMBOL_GPL(octeon_init_device_list); static void *__retrieve_octeon_config_info(struct octeon_device *oct, u16 card_type) @@ -633,6 +634,7 @@ char *lio_get_state_string(atomic_t *state_ptr) return oct_dev_state_str[OCT_DEV_STATE_INVALID]; return oct_dev_state_str[istate]; } +EXPORT_SYMBOL_GPL(lio_get_state_string); static char *get_oct_app_string(u32 app_mode) { @@ -661,6 +663,7 @@ void octeon_free_device_mem(struct octeon_device *oct) octeon_device[i] = NULL; octeon_device_count--; } +EXPORT_SYMBOL_GPL(octeon_free_device_mem); static struct octeon_device *octeon_allocate_device_mem(u32 pci_id, u32 priv_size) @@ -747,6 +750,7 @@ struct octeon_device *octeon_allocate_device(u32 pci_id, return oct; } +EXPORT_SYMBOL_GPL(octeon_allocate_device); /** Register a device's bus location at initialization time. * @param octeon_dev - pointer to the octeon device structure. @@ -804,6 +808,7 @@ int octeon_register_device(struct octeon_device *oct, return refcount; } +EXPORT_SYMBOL_GPL(octeon_register_device); /** Deregister a device at de-initialization time. * @param octeon_dev - pointer to the octeon device structure. @@ -821,6 +826,7 @@ int octeon_deregister_device(struct octeon_device *oct) return refcount; } +EXPORT_SYMBOL_GPL(octeon_deregister_device); int octeon_allocate_ioq_vector(struct octeon_device *oct, u32 num_ioqs) @@ -853,12 +859,14 @@ octeon_allocate_ioq_vector(struct octeon_device *oct, u32 num_ioqs) return 0; } +EXPORT_SYMBOL_GPL(octeon_allocate_ioq_vector); void octeon_free_ioq_vector(struct octeon_device *oct) { vfree(oct->ioq_vector); } +EXPORT_SYMBOL_GPL(octeon_free_ioq_vector); /* this function is only for setting up the first queue */ int octeon_setup_instr_queues(struct octeon_device *oct) @@ -904,6 +912,7 @@ int octeon_setup_instr_queues(struct octeon_device *oct) oct->num_iqs++; return 0; } +EXPORT_SYMBOL_GPL(octeon_setup_instr_queues); int octeon_setup_output_queues(struct octeon_device *oct) { @@ -940,6 +949,7 @@ int octeon_setup_output_queues(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(octeon_setup_output_queues); int octeon_set_io_queues_off(struct octeon_device *oct) { @@ -989,6 +999,7 @@ int octeon_set_io_queues_off(struct octeon_device *oct) } return 0; } +EXPORT_SYMBOL_GPL(octeon_set_io_queues_off); void octeon_set_droq_pkt_op(struct octeon_device *oct, u32 q_no, @@ -1027,6 +1038,7 @@ int octeon_init_dispatch_list(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(octeon_init_dispatch_list); void octeon_delete_dispatch_list(struct octeon_device *oct) { @@ -1058,6 +1070,7 @@ void octeon_delete_dispatch_list(struct octeon_device *oct) kfree(temp); } } +EXPORT_SYMBOL_GPL(octeon_delete_dispatch_list); octeon_dispatch_fn_t octeon_get_dispatch(struct octeon_device *octeon_dev, u16 opcode, @@ -1180,6 +1193,7 @@ octeon_register_dispatch_fn(struct octeon_device *oct, return 0; } +EXPORT_SYMBOL_GPL(octeon_register_dispatch_fn); int octeon_core_drv_init(struct octeon_recv_info *recv_info, void *buf) { @@ -1262,6 +1276,7 @@ core_drv_init_err: octeon_free_recv_info(recv_info); return 0; } +EXPORT_SYMBOL_GPL(octeon_core_drv_init); int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no) @@ -1272,6 +1287,7 @@ int octeon_get_tx_qsize(struct octeon_device *oct, u32 q_no) return -1; } +EXPORT_SYMBOL_GPL(octeon_get_tx_qsize); int octeon_get_rx_qsize(struct octeon_device *oct, u32 q_no) { @@ -1280,6 +1296,7 @@ int octeon_get_rx_qsize(struct octeon_device *oct, u32 q_no) return oct->droq[q_no]->max_count; return -1; } +EXPORT_SYMBOL_GPL(octeon_get_rx_qsize); /* Retruns the host firmware handshake OCTEON specific configuration */ struct octeon_config *octeon_get_conf(struct octeon_device *oct) @@ -1302,6 +1319,7 @@ struct octeon_config *octeon_get_conf(struct octeon_device *oct) } return default_oct_conf; } +EXPORT_SYMBOL_GPL(octeon_get_conf); /* scratch register address is same in all the OCT-II and CN70XX models */ #define CNXX_SLI_SCRATCH1 0x3C0 @@ -1318,6 +1336,7 @@ struct octeon_device *lio_get_device(u32 octeon_id) else return octeon_device[octeon_id]; } +EXPORT_SYMBOL_GPL(lio_get_device); u64 lio_pci_readq(struct octeon_device *oct, u64 addr) { @@ -1349,6 +1368,7 @@ u64 lio_pci_readq(struct octeon_device *oct, u64 addr) return val64; } +EXPORT_SYMBOL_GPL(lio_pci_readq); void lio_pci_writeq(struct octeon_device *oct, u64 val, @@ -1369,6 +1389,7 @@ void lio_pci_writeq(struct octeon_device *oct, spin_unlock_irqrestore(&oct->pci_win_lock, flags); } +EXPORT_SYMBOL_GPL(lio_pci_writeq); int octeon_mem_access_ok(struct octeon_device *oct) { @@ -1388,6 +1409,7 @@ int octeon_mem_access_ok(struct octeon_device *oct) return access_okay ? 0 : 1; } +EXPORT_SYMBOL_GPL(octeon_mem_access_ok); int octeon_wait_for_ddr_init(struct octeon_device *oct, u32 *timeout) { @@ -1408,6 +1430,7 @@ int octeon_wait_for_ddr_init(struct octeon_device *oct, u32 *timeout) return ret; } +EXPORT_SYMBOL_GPL(octeon_wait_for_ddr_init); /* Get the octeon id assigned to the octeon device passed as argument. * This function is exported to other modules. @@ -1462,3 +1485,4 @@ void lio_enable_irq(struct octeon_droq *droq, struct octeon_instr_queue *iq) } } } +EXPORT_SYMBOL_GPL(lio_enable_irq); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c index d4080bddcb6b..0d6ee30affb9 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_droq.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_droq.c @@ -107,6 +107,7 @@ u32 octeon_droq_check_hw_for_pkts(struct octeon_droq *droq) return last_count; } +EXPORT_SYMBOL_GPL(octeon_droq_check_hw_for_pkts); static void octeon_droq_compute_max_packet_bufs(struct octeon_droq *droq) { @@ -216,6 +217,7 @@ int octeon_delete_droq(struct octeon_device *oct, u32 q_no) return 0; } +EXPORT_SYMBOL_GPL(octeon_delete_droq); int octeon_init_droq(struct octeon_device *oct, u32 q_no, @@ -773,6 +775,7 @@ octeon_droq_process_packets(struct octeon_device *oct, return 0; } +EXPORT_SYMBOL_GPL(octeon_droq_process_packets); /* * Utility function to poll for packets. check_hw_for_packets must be @@ -921,6 +924,7 @@ int octeon_unregister_droq_ops(struct octeon_device *oct, u32 q_no) return 0; } +EXPORT_SYMBOL_GPL(octeon_unregister_droq_ops); int octeon_create_droq(struct octeon_device *oct, u32 q_no, u32 num_descs, diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c index 7ccab36143c1..d70132437af3 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_mem_ops.c @@ -164,6 +164,7 @@ octeon_pci_read_core_mem(struct octeon_device *oct, { __octeon_pci_rw_core_mem(oct, coreaddr, buf, len, 1); } +EXPORT_SYMBOL_GPL(octeon_pci_read_core_mem); void octeon_pci_write_core_mem(struct octeon_device *oct, @@ -173,6 +174,7 @@ octeon_pci_write_core_mem(struct octeon_device *oct, { __octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)buf, len, 0); } +EXPORT_SYMBOL_GPL(octeon_pci_write_core_mem); u64 octeon_read_device_mem64(struct octeon_device *oct, u64 coreaddr) { @@ -182,6 +184,7 @@ u64 octeon_read_device_mem64(struct octeon_device *oct, u64 coreaddr) return be64_to_cpu(ret); } +EXPORT_SYMBOL_GPL(octeon_read_device_mem64); u32 octeon_read_device_mem32(struct octeon_device *oct, u64 coreaddr) { @@ -191,6 +194,7 @@ u32 octeon_read_device_mem32(struct octeon_device *oct, u64 coreaddr) return be32_to_cpu(ret); } +EXPORT_SYMBOL_GPL(octeon_read_device_mem32); void octeon_write_device_mem32(struct octeon_device *oct, u64 coreaddr, u32 val) @@ -199,3 +203,4 @@ void octeon_write_device_mem32(struct octeon_device *oct, u64 coreaddr, __octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)&t, 4, 0); } +EXPORT_SYMBOL_GPL(octeon_write_device_mem32); diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c index 1a706f81bbb0..dee56ea740e7 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c @@ -79,6 +79,7 @@ octeon_alloc_soft_command_resp(struct octeon_device *oct, return sc; } +EXPORT_SYMBOL_GPL(octeon_alloc_soft_command_resp); int octnet_send_nic_data_pkt(struct octeon_device *oct, struct octnic_data_pkt *ndata, @@ -90,6 +91,7 @@ int octnet_send_nic_data_pkt(struct octeon_device *oct, ndata->buf, ndata->datasize, ndata->reqtype); } +EXPORT_SYMBOL_GPL(octnet_send_nic_data_pkt); static inline struct octeon_soft_command *octnic_alloc_ctrl_pkt_sc(struct octeon_device *oct, @@ -196,3 +198,4 @@ octnet_send_nic_ctrl_pkt(struct octeon_device *oct, return retval; } +EXPORT_SYMBOL_GPL(octnet_send_nic_ctrl_pkt); diff --git a/drivers/net/ethernet/cavium/liquidio/request_manager.c b/drivers/net/ethernet/cavium/liquidio/request_manager.c index 32f854c0cd79..de8a6ce86ad7 100644 --- a/drivers/net/ethernet/cavium/liquidio/request_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/request_manager.c @@ -185,6 +185,7 @@ int octeon_delete_instr_queue(struct octeon_device *oct, u32 iq_no) } return 1; } +EXPORT_SYMBOL_GPL(octeon_delete_instr_queue); /* Return 0 on success, 1 on failure */ int octeon_setup_iq(struct octeon_device *oct, @@ -258,6 +259,7 @@ int lio_wait_for_instr_fetch(struct octeon_device *oct) return instr_cnt; } +EXPORT_SYMBOL_GPL(lio_wait_for_instr_fetch); static inline void ring_doorbell(struct octeon_device *oct, struct octeon_instr_queue *iq) @@ -282,6 +284,7 @@ octeon_ring_doorbell_locked(struct octeon_device *oct, u32 iq_no) ring_doorbell(oct, iq); spin_unlock(&iq->post_lock); } +EXPORT_SYMBOL_GPL(octeon_ring_doorbell_locked); static inline void __copy_cmd_into_iq(struct octeon_instr_queue *iq, u8 *cmd) @@ -345,6 +348,7 @@ octeon_register_reqtype_free_fn(struct octeon_device *oct, int reqtype, return 0; } +EXPORT_SYMBOL_GPL(octeon_register_reqtype_free_fn); static inline void __add_to_request_list(struct octeon_instr_queue *iq, @@ -430,6 +434,7 @@ lio_process_iq_request_list(struct octeon_device *oct, return inst_count; } +EXPORT_SYMBOL_GPL(lio_process_iq_request_list); /* Can only be called from process context */ int @@ -566,6 +571,7 @@ octeon_send_command(struct octeon_device *oct, u32 iq_no, return st.status; } +EXPORT_SYMBOL_GPL(octeon_send_command); void octeon_prepare_soft_command(struct octeon_device *oct, @@ -673,6 +679,7 @@ octeon_prepare_soft_command(struct octeon_device *oct, } } } +EXPORT_SYMBOL_GPL(octeon_prepare_soft_command); int octeon_send_soft_command(struct octeon_device *oct, struct octeon_soft_command *sc) @@ -726,6 +733,7 @@ int octeon_send_soft_command(struct octeon_device *oct, return (octeon_send_command(oct, sc->iq_no, 1, &sc->cmd, sc, len, REQTYPE_SOFT_COMMAND)); } +EXPORT_SYMBOL_GPL(octeon_send_soft_command); int octeon_setup_sc_buffer_pool(struct octeon_device *oct) { @@ -755,6 +763,7 @@ int octeon_setup_sc_buffer_pool(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(octeon_setup_sc_buffer_pool); int octeon_free_sc_done_list(struct octeon_device *oct) { @@ -794,6 +803,7 @@ int octeon_free_sc_done_list(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(octeon_free_sc_done_list); int octeon_free_sc_zombie_list(struct octeon_device *oct) { @@ -818,6 +828,7 @@ int octeon_free_sc_zombie_list(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(octeon_free_sc_zombie_list); int octeon_free_sc_buffer_pool(struct octeon_device *oct) { @@ -842,6 +853,7 @@ int octeon_free_sc_buffer_pool(struct octeon_device *oct) return 0; } +EXPORT_SYMBOL_GPL(octeon_free_sc_buffer_pool); struct octeon_soft_command *octeon_alloc_soft_command(struct octeon_device *oct, u32 datasize, @@ -913,6 +925,7 @@ struct octeon_soft_command *octeon_alloc_soft_command(struct octeon_device *oct, return sc; } +EXPORT_SYMBOL_GPL(octeon_alloc_soft_command); void octeon_free_soft_command(struct octeon_device *oct, struct octeon_soft_command *sc) @@ -925,3 +938,4 @@ void octeon_free_soft_command(struct octeon_device *oct, spin_unlock_bh(&oct->sc_buf_pool.lock); } +EXPORT_SYMBOL_GPL(octeon_free_soft_command); diff --git a/drivers/net/ethernet/cavium/liquidio/response_manager.c b/drivers/net/ethernet/cavium/liquidio/response_manager.c index ac7747ccf56a..861050966e18 100644 --- a/drivers/net/ethernet/cavium/liquidio/response_manager.c +++ b/drivers/net/ethernet/cavium/liquidio/response_manager.c @@ -52,12 +52,14 @@ int octeon_setup_response_list(struct octeon_device *oct) return ret; } +EXPORT_SYMBOL_GPL(octeon_setup_response_list); void octeon_delete_response_list(struct octeon_device *oct) { cancel_delayed_work_sync(&oct->dma_comp_wq.wk.work); destroy_workqueue(oct->dma_comp_wq.wq); } +EXPORT_SYMBOL_GPL(octeon_delete_response_list); int lio_process_ordered_list(struct octeon_device *octeon_dev, u32 force_quit) @@ -219,6 +221,7 @@ int lio_process_ordered_list(struct octeon_device *octeon_dev, return 0; } +EXPORT_SYMBOL_GPL(lio_process_ordered_list); static void oct_poll_req_completion(struct work_struct *work) { -- cgit v1.2.3 From 92db9e2e0498b92d0a57cc48ea869ddabda934d9 Mon Sep 17 00:00:00 2001 From: Atin Bainada Date: Tue, 6 Jun 2023 12:23:08 +0000 Subject: net: dsa: qca8k: remove unnecessary (void*) conversions Pointer variables of (void*) type do not require type cast. Signed-off-by: Atin Bainada Signed-off-by: David S. Miller --- drivers/net/dsa/qca/ar9331.c | 16 ++++++++-------- drivers/net/dsa/qca/qca8k-8xxx.c | 2 +- drivers/net/dsa/qca/qca8k-common.c | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/dsa/qca/ar9331.c b/drivers/net/dsa/qca/ar9331.c index e7b98b864fa1..b2bf78ac485e 100644 --- a/drivers/net/dsa/qca/ar9331.c +++ b/drivers/net/dsa/qca/ar9331.c @@ -391,7 +391,7 @@ static int ar9331_sw_mbus_init(struct ar9331_sw_priv *priv) static int ar9331_sw_setup_port(struct dsa_switch *ds, int port) { - struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; + struct ar9331_sw_priv *priv = ds->priv; struct regmap *regmap = priv->regmap; u32 port_mask, port_ctrl, val; int ret; @@ -439,7 +439,7 @@ error: static int ar9331_sw_setup(struct dsa_switch *ds) { - struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; + struct ar9331_sw_priv *priv = ds->priv; struct regmap *regmap = priv->regmap; int ret, i; @@ -484,7 +484,7 @@ error: static void ar9331_sw_port_disable(struct dsa_switch *ds, int port) { - struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; + struct ar9331_sw_priv *priv = ds->priv; struct regmap *regmap = priv->regmap; int ret; @@ -527,7 +527,7 @@ static void ar9331_sw_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) { - struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; + struct ar9331_sw_priv *priv = ds->priv; struct regmap *regmap = priv->regmap; int ret; @@ -542,7 +542,7 @@ static void ar9331_sw_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) { - struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; + struct ar9331_sw_priv *priv = ds->priv; struct ar9331_sw_port *p = &priv->port[port]; struct regmap *regmap = priv->regmap; int ret; @@ -562,7 +562,7 @@ static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port, int speed, int duplex, bool tx_pause, bool rx_pause) { - struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; + struct ar9331_sw_priv *priv = ds->priv; struct ar9331_sw_port *p = &priv->port[port]; struct regmap *regmap = priv->regmap; u32 val; @@ -665,7 +665,7 @@ static void ar9331_do_stats_poll(struct work_struct *work) static void ar9331_get_stats64(struct dsa_switch *ds, int port, struct rtnl_link_stats64 *s) { - struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; + struct ar9331_sw_priv *priv = ds->priv; struct ar9331_sw_port *p = &priv->port[port]; spin_lock(&p->stats_lock); @@ -676,7 +676,7 @@ static void ar9331_get_stats64(struct dsa_switch *ds, int port, static void ar9331_get_pause_stats(struct dsa_switch *ds, int port, struct ethtool_pause_stats *pause_stats) { - struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv; + struct ar9331_sw_priv *priv = ds->priv; struct ar9331_sw_port *p = &priv->port[port]; spin_lock(&p->stats_lock); diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index 6d5ac7588a69..dee7b6579916 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -1756,7 +1756,7 @@ static int qca8k_connect_tag_protocol(struct dsa_switch *ds, static int qca8k_setup(struct dsa_switch *ds) { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + struct qca8k_priv *priv = ds->priv; int cpu_port, ret, i; u32 mask; diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c index 96773e432558..8c2dc0e48ff4 100644 --- a/drivers/net/dsa/qca/qca8k-common.c +++ b/drivers/net/dsa/qca/qca8k-common.c @@ -760,7 +760,7 @@ int qca8k_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid, struct dsa_db db) { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + struct qca8k_priv *priv = ds->priv; u16 port_mask = BIT(port); return qca8k_port_fdb_insert(priv, addr, port_mask, vid); @@ -770,7 +770,7 @@ int qca8k_port_fdb_del(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid, struct dsa_db db) { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + struct qca8k_priv *priv = ds->priv; u16 port_mask = BIT(port); if (!vid) @@ -782,7 +782,7 @@ int qca8k_port_fdb_del(struct dsa_switch *ds, int port, int qca8k_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb, void *data) { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + struct qca8k_priv *priv = ds->priv; struct qca8k_fdb _fdb = { 0 }; int cnt = QCA8K_NUM_FDB_RECORDS; bool is_static; -- cgit v1.2.3 From e7214663e023be5e518e8d0d8f2dca6848731652 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 6 Jun 2023 15:49:45 +0200 Subject: net: txgbe: Avoid passing uninitialised parameter to pci_wake_from_d3() txgbe_shutdown() relies on txgbe_dev_shutdown() to initialise wake by passing it by reference. However, txgbe_dev_shutdown() doesn't use this parameter at all. wake is then passed uninitialised by txgbe_dev_shutdown() to pci_wake_from_d3(). Resolve this problem by: * Removing the unused parameter from txgbe_dev_shutdown() * Removing the uninitialised variable wake from txgbe_dev_shutdown() * Passing false to pci_wake_from_d3() - this assumes that although uninitialised wake was in practice false (0). I'm not sure that this counts as a bug, as I'm not sure that it manifests in any unwanted behaviour. But in any case, the issue was introduced by: 3ce7547e5b71 ("net: txgbe: Add build support for txgbe") Flagged by Smatch as: .../txgbe_main.c:486 txgbe_shutdown() error: uninitialized symbol 'wake'. No functional change intended. Compile tested only. Signed-off-by: Simon Horman Reviewed-by: Jiawen Wu Reviewed-by: Maciej Fijalkowski Signed-off-by: David S. Miller --- drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 0f0d9fa1cde1..cfe47f3d2503 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -457,7 +457,7 @@ static int txgbe_close(struct net_device *netdev) return 0; } -static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) +static void txgbe_dev_shutdown(struct pci_dev *pdev) { struct wx *wx = pci_get_drvdata(pdev); struct net_device *netdev; @@ -477,12 +477,10 @@ static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake) static void txgbe_shutdown(struct pci_dev *pdev) { - bool wake; - - txgbe_dev_shutdown(pdev, &wake); + txgbe_dev_shutdown(pdev); if (system_state == SYSTEM_POWER_OFF) { - pci_wake_from_d3(pdev, wake); + pci_wake_from_d3(pdev, false); pci_set_power_state(pdev, PCI_D3hot); } } -- cgit v1.2.3 From e9da6df7492a981b071bafd169fb4c35b45f5ebf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:20 +0200 Subject: wifi: cfg80211: hold wiphy lock in auto-disconnect Most code paths in cfg80211 already hold the wiphy lock, mostly by virtue of being called from nl80211, so make the auto-disconnect worker also hold it, aligning the locking promises between different parts of cfg80211. Signed-off-by: Johannes Berg --- net/wireless/core.c | 6 ++---- net/wireless/sme.c | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index b3ec9eaec36b..061f7a6dd279 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1178,10 +1178,6 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev, kfree_sensitive(wdev->wext.keys); wdev->wext.keys = NULL; #endif - /* only initialized if we have a netdev */ - if (wdev->netdev) - flush_work(&wdev->disconnect_wk); - cfg80211_cqm_config_free(wdev); /* @@ -1455,6 +1451,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, cfg80211_leave(rdev, wdev); cfg80211_remove_links(wdev); wiphy_unlock(&rdev->wiphy); + /* since we just did cfg80211_leave() nothing to do there */ + cancel_work_sync(&wdev->disconnect_wk); break; case NETDEV_DOWN: wiphy_lock(&rdev->wiphy); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 7bdeb8eea92d..247369004aaa 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -5,7 +5,7 @@ * (for nl80211's connect() and wext) * * Copyright 2009 Johannes Berg - * Copyright (C) 2009, 2020, 2022 Intel Corporation. All rights reserved. + * Copyright (C) 2009, 2020, 2022-2023 Intel Corporation. All rights reserved. * Copyright 2017 Intel Deutschland GmbH */ @@ -1569,6 +1569,7 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) container_of(work, struct wireless_dev, disconnect_wk); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + wiphy_lock(wdev->wiphy); wdev_lock(wdev); if (wdev->conn_owner_nlportid) { @@ -1607,4 +1608,5 @@ void cfg80211_autodisconnect_wk(struct work_struct *work) } wdev_unlock(wdev); + wiphy_unlock(wdev->wiphy); } -- cgit v1.2.3 From 0dcb84ede5b0a99fc125df2f82ca1f539d41446d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:21 +0200 Subject: wifi: cfg80211: hold wiphy lock in pmsr work Most code paths in cfg80211 already hold the wiphy lock, mostly by virtue of being called from nl80211, so make the pmsr cleanup worker also hold it, aligning the locking promises between different parts of cfg80211. Signed-off-by: Johannes Berg --- net/wireless/core.c | 3 +-- net/wireless/pmsr.c | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 061f7a6dd279..2e12b166c6fc 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1145,8 +1145,6 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev, ASSERT_RTNL(); lockdep_assert_held(&rdev->wiphy.mtx); - flush_work(&wdev->pmsr_free_wk); - nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); wdev->registered = false; @@ -1453,6 +1451,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, wiphy_unlock(&rdev->wiphy); /* since we just did cfg80211_leave() nothing to do there */ cancel_work_sync(&wdev->disconnect_wk); + cancel_work_sync(&wdev->pmsr_free_wk); break; case NETDEV_DOWN: wiphy_lock(&rdev->wiphy); diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c index 2bc647720cda..77000a264855 100644 --- a/net/wireless/pmsr.c +++ b/net/wireless/pmsr.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright (C) 2018 - 2021 Intel Corporation + * Copyright (C) 2018 - 2021, 2023 Intel Corporation */ #include #include "core.h" @@ -623,9 +623,11 @@ void cfg80211_pmsr_free_wk(struct work_struct *work) struct wireless_dev *wdev = container_of(work, struct wireless_dev, pmsr_free_wk); + wiphy_lock(wdev->wiphy); wdev_lock(wdev); cfg80211_pmsr_process_abort(wdev); wdev_unlock(wdev); + wiphy_unlock(wdev->wiphy); } void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev) -- cgit v1.2.3 From a993df0f9143e63eca38c96a30daf08db99a98a3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:22 +0200 Subject: wifi: cfg80211: move wowlan disable under locks This is a driver callback, and the driver should be able to assume that it's called with the wiphy lock held. Move the call up so that's true, it has no other effect since the device is already unregistering and we cannot reach this function through other paths. Signed-off-by: Johannes Berg --- net/wireless/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index 2e12b166c6fc..a04b6eeb55f8 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1065,6 +1065,10 @@ void wiphy_unregister(struct wiphy *wiphy) cfg80211_rdev_list_generation++; device_del(&rdev->wiphy.dev); +#ifdef CONFIG_PM + if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) + rdev_set_wakeup(rdev, false); +#endif wiphy_unlock(&rdev->wiphy); rtnl_unlock(); @@ -1080,10 +1084,6 @@ void wiphy_unregister(struct wiphy *wiphy) flush_work(&rdev->mgmt_registrations_update_wk); flush_work(&rdev->background_cac_abort_wk); -#ifdef CONFIG_PM - if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) - rdev_set_wakeup(rdev, false); -#endif cfg80211_rdev_free_wowlan(rdev); cfg80211_rdev_free_coalesce(rdev); } -- cgit v1.2.3 From 7d2d0ff49dfdb38ad37baa9a27c0132d5e51a923 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:23 +0200 Subject: wifi: cfg80211: wext: hold wiphy lock in siwgenie Missed this ioctl since it's in wext-sme.c where we usually get via a front-level ioctl handler in the other files, but it should also hold the wiphy lock to align the locking contract towards the driver. Signed-off-by: Johannes Berg --- net/wireless/wext-sme.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index f231207ca210..f3eaa3388694 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -3,7 +3,7 @@ * cfg80211 wext compat for managed mode. * * Copyright 2009 Johannes Berg - * Copyright (C) 2009, 2020-2022 Intel Corporation + * Copyright (C) 2009, 2020-2023 Intel Corporation */ #include @@ -338,6 +338,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev, if (!ie_len) ie = NULL; + wiphy_lock(wdev->wiphy); wdev_lock(wdev); /* no change */ @@ -370,6 +371,7 @@ int cfg80211_wext_siwgenie(struct net_device *dev, err = 0; out: wdev_unlock(wdev); + wiphy_unlock(wdev->wiphy); return err; } -- cgit v1.2.3 From 4d45145ba6e2e1c0eba4ebda7d6273319191f4e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:24 +0200 Subject: wifi: cfg80211: hold wiphy lock when sending wiphy Sending the wiphy out might cause calls to the driver, notably get_txq_stats() and get_antenna(). These aren't very important, since the normally have their own locks and/or just send out static data, but if the contract should be that the wiphy lock is always held, these are also affected. Fix that. Signed-off-by: Johannes Berg --- net/wireless/core.c | 8 ++++++++ net/wireless/nl80211.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/net/wireless/core.c b/net/wireless/core.c index a04b6eeb55f8..151a8567d2a5 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -129,6 +129,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, int result; ASSERT_RTNL(); + lockdep_assert_wiphy(&rdev->wiphy); /* Ignore nop renames */ if (strcmp(newname, wiphy_name(&rdev->wiphy)) == 0) @@ -195,6 +196,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, continue; nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); } + + wiphy_lock(&rdev->wiphy); nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY); wiphy_net_set(&rdev->wiphy, net); @@ -203,6 +206,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, WARN_ON(err); nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); + wiphy_unlock(&rdev->wiphy); + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (!wdev->netdev) continue; @@ -941,8 +946,10 @@ int wiphy_register(struct wiphy *wiphy) rdev->wiphy.features |= NL80211_FEATURE_SCAN_FLUSH; rtnl_lock(); + wiphy_lock(&rdev->wiphy); res = device_add(&rdev->wiphy.dev); if (res) { + wiphy_unlock(&rdev->wiphy); rtnl_unlock(); return res; } @@ -956,6 +963,7 @@ int wiphy_register(struct wiphy *wiphy) cfg80211_debugfs_rdev_add(rdev); nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); + wiphy_unlock(&rdev->wiphy); /* set up regulatory info */ wiphy_regulatory_register(wiphy); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 087d60c0f6e4..a52bd739cf84 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3081,6 +3081,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) if (state->filter_wiphy != -1 && state->filter_wiphy != rdev->wiphy_idx) continue; + wiphy_lock(&rdev->wiphy); /* attempt to fit multiple wiphy data chunks into the skb */ do { ret = nl80211_send_wiphy(rdev, NL80211_CMD_NEW_WIPHY, @@ -3107,6 +3108,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) cb->min_dump_alloc < 4096) { cb->min_dump_alloc = 4096; state->split_start = 0; + wiphy_unlock(&rdev->wiphy); rtnl_unlock(); return 1; } @@ -3114,6 +3116,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) break; } } while (state->split_start > 0); + wiphy_unlock(&rdev->wiphy); break; } rtnl_unlock(); -- cgit v1.2.3 From a3ee4dc84c4e9d14cb34dad095fd678127aca5b6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:25 +0200 Subject: wifi: cfg80211: add a work abstraction with special semantics Add a work abstraction at the cfg80211 level that will always hold the wiphy_lock() for any work executed and therefore also can be canceled safely (without waiting) while holding that. This improves on what we do now as with the new wiphy works we don't have to worry about locking while cancelling them safely. Also, don't let such works run while the device is suspended, since they'll likely need to interact with the device. Flush them before suspend though. Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 95 ++++++++++++++++++++++++++++++++++++-- net/wireless/core.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ net/wireless/core.h | 7 +++ net/wireless/sysfs.c | 8 +++- 4 files changed, 227 insertions(+), 5 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9e04f69712b1..1b8619685bf6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5724,12 +5724,17 @@ struct cfg80211_cqm_config; * wiphy_lock - lock the wiphy * @wiphy: the wiphy to lock * - * This is mostly exposed so it can be done around registering and - * unregistering netdevs that aren't created through cfg80211 calls, - * since that requires locking in cfg80211 when the notifiers is - * called, but that cannot differentiate which way it's called. + * This is needed around registering and unregistering netdevs that + * aren't created through cfg80211 calls, since that requires locking + * in cfg80211 when the notifiers is called, but that cannot + * differentiate which way it's called. + * + * It can also be used by drivers for their own purposes. * * When cfg80211 ops are called, the wiphy is already locked. + * + * Note that this makes sure that no workers that have been queued + * with wiphy_queue_work() are running. */ static inline void wiphy_lock(struct wiphy *wiphy) __acquires(&wiphy->mtx) @@ -5749,6 +5754,88 @@ static inline void wiphy_unlock(struct wiphy *wiphy) mutex_unlock(&wiphy->mtx); } +struct wiphy_work; +typedef void (*wiphy_work_func_t)(struct wiphy *, struct wiphy_work *); + +struct wiphy_work { + struct list_head entry; + wiphy_work_func_t func; +}; + +static inline void wiphy_work_init(struct wiphy_work *work, + wiphy_work_func_t func) +{ + INIT_LIST_HEAD(&work->entry); + work->func = func; +} + +/** + * wiphy_work_queue - queue work for the wiphy + * @wiphy: the wiphy to queue for + * @work: the work item + * + * This is useful for work that must be done asynchronously, and work + * queued here has the special property that the wiphy mutex will be + * held as if wiphy_lock() was called, and that it cannot be running + * after wiphy_lock() was called. Therefore, wiphy_cancel_work() can + * use just cancel_work() instead of cancel_work_sync(), it requires + * being in a section protected by wiphy_lock(). + */ +void wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *work); + +/** + * wiphy_work_cancel - cancel previously queued work + * @wiphy: the wiphy, for debug purposes + * @work: the work to cancel + * + * Cancel the work *without* waiting for it, this assumes being + * called under the wiphy mutex acquired by wiphy_lock(). + */ +void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work); + +struct wiphy_delayed_work { + struct wiphy_work work; + struct wiphy *wiphy; + struct timer_list timer; +}; + +void wiphy_delayed_work_timer(struct timer_list *t); + +static inline void wiphy_delayed_work_init(struct wiphy_delayed_work *dwork, + wiphy_work_func_t func) +{ + timer_setup(&dwork->timer, wiphy_delayed_work_timer, 0); + wiphy_work_init(&dwork->work, func); +} + +/** + * wiphy_delayed_work_queue - queue delayed work for the wiphy + * @wiphy: the wiphy to queue for + * @dwork: the delayable worker + * @delay: number of jiffies to wait before queueing + * + * This is useful for work that must be done asynchronously, and work + * queued here has the special property that the wiphy mutex will be + * held as if wiphy_lock() was called, and that it cannot be running + * after wiphy_lock() was called. Therefore, wiphy_cancel_work() can + * use just cancel_work() instead of cancel_work_sync(), it requires + * being in a section protected by wiphy_lock(). + */ +void wiphy_delayed_work_queue(struct wiphy *wiphy, + struct wiphy_delayed_work *dwork, + unsigned long delay); + +/** + * wiphy_delayed_work_cancel - cancel previously queued delayed work + * @wiphy: the wiphy, for debug purposes + * @dwork: the delayed work to cancel + * + * Cancel the work *without* waiting for it, this assumes being + * called under the wiphy mutex acquired by wiphy_lock(). + */ +void wiphy_delayed_work_cancel(struct wiphy *wiphy, + struct wiphy_delayed_work *dwork); + /** * struct wireless_dev - wireless device state * diff --git a/net/wireless/core.c b/net/wireless/core.c index 151a8567d2a5..ca585e96d535 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -413,6 +413,34 @@ static void cfg80211_propagate_cac_done_wk(struct work_struct *work) rtnl_unlock(); } +static void cfg80211_wiphy_work(struct work_struct *work) +{ + struct cfg80211_registered_device *rdev; + struct wiphy_work *wk; + + rdev = container_of(work, struct cfg80211_registered_device, wiphy_work); + + wiphy_lock(&rdev->wiphy); + if (rdev->suspended) + goto out; + + spin_lock_irq(&rdev->wiphy_work_lock); + wk = list_first_entry_or_null(&rdev->wiphy_work_list, + struct wiphy_work, entry); + if (wk) { + list_del_init(&wk->entry); + if (!list_empty(&rdev->wiphy_work_list)) + schedule_work(work); + spin_unlock_irq(&rdev->wiphy_work_lock); + + wk->func(&rdev->wiphy, wk); + } else { + spin_unlock_irq(&rdev->wiphy_work_lock); + } +out: + wiphy_unlock(&rdev->wiphy); +} + /* exported functions */ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, @@ -538,6 +566,9 @@ use_default_name: return NULL; } + INIT_WORK(&rdev->wiphy_work, cfg80211_wiphy_work); + INIT_LIST_HEAD(&rdev->wiphy_work_list); + spin_lock_init(&rdev->wiphy_work_lock); INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); INIT_WORK(&rdev->conn_work, cfg80211_conn_work); INIT_WORK(&rdev->event_work, cfg80211_event_work); @@ -1035,6 +1066,31 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy) } EXPORT_SYMBOL(wiphy_rfkill_start_polling); +void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev) +{ + unsigned int runaway_limit = 100; + unsigned long flags; + + lockdep_assert_held(&rdev->wiphy.mtx); + + spin_lock_irqsave(&rdev->wiphy_work_lock, flags); + while (!list_empty(&rdev->wiphy_work_list)) { + struct wiphy_work *wk; + + wk = list_first_entry(&rdev->wiphy_work_list, + struct wiphy_work, entry); + list_del_init(&wk->entry); + spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags); + + wk->func(&rdev->wiphy, wk); + + spin_lock_irqsave(&rdev->wiphy_work_lock, flags); + if (WARN_ON(--runaway_limit == 0)) + INIT_LIST_HEAD(&rdev->wiphy_work_list); + } + spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags); +} + void wiphy_unregister(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); @@ -1077,9 +1133,15 @@ void wiphy_unregister(struct wiphy *wiphy) if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) rdev_set_wakeup(rdev, false); #endif + + /* surely nothing is reachable now, clean up work */ + cfg80211_process_wiphy_works(rdev); wiphy_unlock(&rdev->wiphy); rtnl_unlock(); + /* this has nothing to do now but make sure it's gone */ + cancel_work_sync(&rdev->wiphy_work); + flush_work(&rdev->scan_done_wk); cancel_work_sync(&rdev->conn_work); flush_work(&rdev->event_work); @@ -1569,6 +1631,66 @@ static struct pernet_operations cfg80211_pernet_ops = { .exit = cfg80211_pernet_exit, }; +void wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + unsigned long flags; + + spin_lock_irqsave(&rdev->wiphy_work_lock, flags); + if (list_empty(&work->entry)) + list_add_tail(&work->entry, &rdev->wiphy_work_list); + spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags); + + schedule_work(&rdev->wiphy_work); +} +EXPORT_SYMBOL_GPL(wiphy_work_queue); + +void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + unsigned long flags; + + lockdep_assert_held(&wiphy->mtx); + + spin_lock_irqsave(&rdev->wiphy_work_lock, flags); + if (!list_empty(&work->entry)) + list_del_init(&work->entry); + spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags); +} +EXPORT_SYMBOL_GPL(wiphy_work_cancel); + +void wiphy_delayed_work_timer(struct timer_list *t) +{ + struct wiphy_delayed_work *dwork = from_timer(dwork, t, timer); + + wiphy_work_queue(dwork->wiphy, &dwork->work); +} +EXPORT_SYMBOL(wiphy_delayed_work_timer); + +void wiphy_delayed_work_queue(struct wiphy *wiphy, + struct wiphy_delayed_work *dwork, + unsigned long delay) +{ + if (!delay) { + wiphy_work_queue(wiphy, &dwork->work); + return; + } + + dwork->wiphy = wiphy; + mod_timer(&dwork->timer, jiffies + delay); +} +EXPORT_SYMBOL_GPL(wiphy_delayed_work_queue); + +void wiphy_delayed_work_cancel(struct wiphy *wiphy, + struct wiphy_delayed_work *dwork) +{ + lockdep_assert_held(&wiphy->mtx); + + del_timer_sync(&dwork->timer); + wiphy_work_cancel(wiphy, &dwork->work); +} +EXPORT_SYMBOL_GPL(wiphy_delayed_work_cancel); + static int __init cfg80211_init(void) { int err; diff --git a/net/wireless/core.h b/net/wireless/core.h index 7c61752f6d83..435060dad81e 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -108,6 +108,12 @@ struct cfg80211_registered_device { /* lock for all wdev lists */ spinlock_t mgmt_registrations_lock; + struct work_struct wiphy_work; + struct list_head wiphy_work_list; + /* protects the list above */ + spinlock_t wiphy_work_lock; + bool suspended; + /* must be last because of the way we do wiphy_priv(), * and it should at least be aligned to NETDEV_ALIGN */ struct wiphy wiphy __aligned(NETDEV_ALIGN); @@ -453,6 +459,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, struct net_device *dev, enum nl80211_iftype ntype, struct vif_params *params); void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); +void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev); void cfg80211_process_wdev_events(struct wireless_dev *wdev); bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range, diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 268f670835e9..c629bac3f298 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -5,7 +5,7 @@ * * Copyright 2005-2006 Jiri Benc * Copyright 2006 Johannes Berg - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2021, 2023 Intel Corporation */ #include @@ -105,14 +105,18 @@ static int wiphy_suspend(struct device *dev) cfg80211_leave_all(rdev); cfg80211_process_rdev_events(rdev); } + cfg80211_process_wiphy_works(rdev); if (rdev->ops->suspend) ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); if (ret == 1) { /* Driver refuse to configure wowlan */ cfg80211_leave_all(rdev); cfg80211_process_rdev_events(rdev); + cfg80211_process_wiphy_works(rdev); ret = rdev_suspend(rdev, NULL); } + if (ret == 0) + rdev->suspended = true; } wiphy_unlock(&rdev->wiphy); rtnl_unlock(); @@ -132,6 +136,8 @@ static int wiphy_resume(struct device *dev) wiphy_lock(&rdev->wiphy); if (rdev->wiphy.registered && rdev->ops->resume) ret = rdev_resume(rdev); + rdev->suspended = false; + schedule_work(&rdev->wiphy_work); wiphy_unlock(&rdev->wiphy); if (ret) -- cgit v1.2.3 From 16114496d684a3df4ce09f7c6b7557a8b2922795 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:26 +0200 Subject: wifi: mac80211: use wiphy work for sdata->work We'll need this later to convert other works that might be cancelled from here, so convert this one first. Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 8 ++++---- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/iface.c | 10 +++++----- net/mac80211/mesh.c | 10 +++++----- net/mac80211/mesh_hwmp.c | 6 +++--- net/mac80211/mlme.c | 6 +++--- net/mac80211/ocb.c | 6 +++--- net/mac80211/rx.c | 2 +- net/mac80211/scan.c | 2 +- net/mac80211/status.c | 6 +++--- net/mac80211/util.c | 2 +- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index faa01ee11d32..19017810024b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -743,7 +743,7 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work) skb_queue_purge(&sdata->skb_queue); /* trigger a scan to find another IBSS network to join */ - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); sdata_unlock(sdata); } @@ -1244,7 +1244,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, spin_lock(&ifibss->incomplete_lock); list_add(&sta->list, &ifibss->incomplete_stations); spin_unlock(&ifibss->incomplete_lock); - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); } static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) @@ -1723,7 +1723,7 @@ static void ieee80211_ibss_timer(struct timer_list *t) struct ieee80211_sub_if_data *sdata = from_timer(sdata, t, u.ibss.timer); - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) @@ -1858,7 +1858,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, sdata->deflink.needed_rx_chains = local->rx_chains; sdata->control_port_over_nl80211 = params->control_port_over_nl80211; - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); return 0; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 037040787194..1cefe69706ef 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1061,7 +1061,7 @@ struct ieee80211_sub_if_data { /* used to reconfigure hardware SM PS */ struct work_struct recalc_smps; - struct work_struct work; + struct wiphy_work work; struct sk_buff_head skb_queue; struct sk_buff_head status_queue; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 2e2115af38f5..f820098e6a70 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -43,7 +43,7 @@ * by either the RTNL, the iflist_mtx or RCU. */ -static void ieee80211_iface_work(struct work_struct *work); +static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work); bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) { @@ -614,7 +614,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do RCU_INIT_POINTER(local->p2p_sdata, NULL); fallthrough; default: - cancel_work_sync(&sdata->work); + wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work); /* * When we get here, the interface is marked down. * Free the remaining keys, if there are any @@ -1173,7 +1173,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) skb_queue_head_init(&sdata->skb_queue); skb_queue_head_init(&sdata->status_queue); - INIT_WORK(&sdata->work, ieee80211_iface_work); + wiphy_work_init(&sdata->work, ieee80211_iface_work); return 0; } @@ -1625,7 +1625,7 @@ static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata, } } -static void ieee80211_iface_work(struct work_struct *work) +static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, work); @@ -1737,7 +1737,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, skb_queue_head_init(&sdata->skb_queue); skb_queue_head_init(&sdata->status_queue); - INIT_WORK(&sdata->work, ieee80211_iface_work); + wiphy_work_init(&sdata->work, ieee80211_iface_work); INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); INIT_WORK(&sdata->activate_links_work, ieee80211_activate_links_work); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index a4d8764073bf..af8c5fc2db14 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -45,7 +45,7 @@ static void ieee80211_mesh_housekeeping_timer(struct timer_list *t) set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); } /** @@ -703,7 +703,7 @@ static void ieee80211_mesh_path_timer(struct timer_list *t) struct ieee80211_sub_if_data *sdata = from_timer(sdata, t, u.mesh.mesh_path_timer); - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } static void ieee80211_mesh_path_root_timer(struct timer_list *t) @@ -714,7 +714,7 @@ static void ieee80211_mesh_path_root_timer(struct timer_list *t) set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) @@ -1177,7 +1177,7 @@ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE) set_bit(bit, &ifmsh->mbss_changed); set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags); - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) @@ -1202,7 +1202,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) ifmsh->sync_offset_clockdrift_max = 0; set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); ieee80211_mesh_root_setup(ifmsh); - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); sdata->vif.bss_conf.ht_operation_mode = ifmsh->mshcfg.ht_opmode; sdata->vif.bss_conf.enable_beacon = true; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 5217e1d97dd6..51369072984e 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008, 2009 open80211s Ltd. - * Copyright (C) 2019, 2021-2022 Intel Corporation + * Copyright (C) 2019, 2021-2023 Intel Corporation * Author: Luis Carlos Cobo */ @@ -1026,14 +1026,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); else if (time_before(jiffies, ifmsh->last_preq)) { /* avoid long wait if did not send preqs for a long time * and jiffies wrapped around */ ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } else mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + min_preq_int_jiff(sdata)); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7ec0ad29b8c9..03251a725d65 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3161,7 +3161,7 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.probe_send_count = 0; else sdata->u.mgd.nullfunc_failed = true; - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata, @@ -6074,7 +6074,7 @@ static void ieee80211_sta_timer(struct timer_list *t) struct ieee80211_sub_if_data *sdata = from_timer(sdata, t, u.mgd.timer); - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, @@ -6218,7 +6218,7 @@ void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata, sdata->u.mgd.status_acked = acked; sdata->u.mgd.status_received = true; - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); } void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c index cf205762ab96..b44896e14522 100644 --- a/net/mac80211/ocb.c +++ b/net/mac80211/ocb.c @@ -81,7 +81,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, spin_lock(&ifocb->incomplete_lock); list_add(&sta->list, &ifocb->incomplete_stations); spin_unlock(&ifocb->incomplete_lock); - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); } static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta) @@ -157,7 +157,7 @@ static void ieee80211_ocb_housekeeping_timer(struct timer_list *t) set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); } void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata) @@ -197,7 +197,7 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, ifocb->joined = true; set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); netif_carrier_on(sdata->dev); return 0; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d996aa2579df..ed9939466198 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -229,7 +229,7 @@ static void __ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata, } skb_queue_tail(&sdata->skb_queue, skb); - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); if (sta) sta->deflink.rx_stats.packets++; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 32fa8aca7005..ea5383136fff 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -502,7 +502,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) */ list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (ieee80211_sdata_running(sdata)) - ieee80211_queue_work(&sdata->local->hw, &sdata->work); + wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work); } if (was_scanning) diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 2b13a52ce96c..44d83da60aee 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -5,7 +5,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2008-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright 2021-2022 Intel Corporation + * Copyright 2021-2023 Intel Corporation */ #include @@ -747,8 +747,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, if (qskb) { skb_queue_tail(&sdata->status_queue, qskb); - ieee80211_queue_work(&local->hw, - &sdata->work); + wiphy_work_queue(local->hw.wiphy, + &sdata->work); } } } else { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 4f29c307b3f6..083ad56d08d9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2942,7 +2942,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* Requeue all works */ list_for_each_entry(sdata, &local->interfaces, list) - ieee80211_queue_work(&local->hw, &sdata->work); + wiphy_work_queue(local->hw.wiphy, &sdata->work); } ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, -- cgit v1.2.3 From a3df43b16fc49213ab4b925711d4725e1e2f2305 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:27 +0200 Subject: wifi: mac80211: unregister netdevs through cfg80211 Since we want to have wiphy_lock() for the unregistration in the future, unregister also netdevs via cfg80211 now to be able to hold the wiphy_lock() for it. Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f820098e6a70..5b67b44e3f89 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -2258,7 +2258,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata, *tmp; LIST_HEAD(unreg_list); - LIST_HEAD(wdev_list); ASSERT_RTNL(); @@ -2281,23 +2280,18 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) ieee80211_txq_teardown_flows(local); mutex_lock(&local->iflist_mtx); - list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { - list_del(&sdata->list); - - if (sdata->dev) - unregister_netdevice_queue(sdata->dev, &unreg_list); - else - list_add(&sdata->list, &wdev_list); - } + list_splice_init(&local->interfaces, &unreg_list); mutex_unlock(&local->iflist_mtx); - unregister_netdevice_many(&unreg_list); - wiphy_lock(local->hw.wiphy); - list_for_each_entry_safe(sdata, tmp, &wdev_list, list) { + list_for_each_entry_safe(sdata, tmp, &unreg_list, list) { + bool netdev = sdata->dev; + list_del(&sdata->list); cfg80211_unregister_wdev(&sdata->wdev); - kfree(sdata); + + if (!netdev) + kfree(sdata); } wiphy_unlock(local->hw.wiphy); } -- cgit v1.2.3 From 1444f58931ef5227532cf5436bb55c1dd511d9a2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:28 +0200 Subject: wifi: mac80211: use wiphy work for SMPS SMPS requests are per link, and currently there's a potential deadlock with canceling. Use the new wiphy work to handle SMPS instead, so that the cancel cannot deadlock. Signed-off-by: Johannes Berg --- net/mac80211/ht.c | 5 +++-- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mlme.c | 10 ++++++---- net/mac80211/tdls.c | 4 ++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 5315ab750280..33729870ad8a 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -9,7 +9,7 @@ * Copyright 2007, Michael Wu * Copyright 2007-2010, Intel Corporation * Copyright 2017 Intel Deutschland GmbH - * Copyright(c) 2020-2022 Intel Corporation + * Copyright(c) 2020-2023 Intel Corporation */ #include @@ -602,7 +602,8 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, unsigned int link_id, goto out; link->u.mgd.driver_smps_mode = smps_mode; - ieee80211_queue_work(&sdata->local->hw, &link->u.mgd.request_smps_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &link->u.mgd.request_smps_work); out: rcu_read_unlock(); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1cefe69706ef..0ecb725f5307 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -921,7 +921,7 @@ struct ieee80211_link_data_managed { struct timer_list chswitch_timer; struct work_struct chswitch_work; - struct work_struct request_smps_work; + struct wiphy_work request_smps_work; bool beacon_crc_valid; u32 beacon_crc; struct ewma_beacon_signal ave_beacon_signal; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 03251a725d65..c4a1bf6b6fb4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6538,7 +6538,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) sdata_unlock(sdata); } -static void ieee80211_request_smps_mgd_work(struct work_struct *work) +static void ieee80211_request_smps_mgd_work(struct wiphy *wiphy, + struct wiphy_work *work) { struct ieee80211_link_data *link = container_of(work, struct ieee80211_link_data, @@ -6588,8 +6589,8 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link) link->u.mgd.conn_flags = 0; link->conf->bssid = link->u.mgd.bssid; - INIT_WORK(&link->u.mgd.request_smps_work, - ieee80211_request_smps_mgd_work); + wiphy_work_init(&link->u.mgd.request_smps_work, + ieee80211_request_smps_mgd_work); if (local->hw.wiphy->features & NL80211_FEATURE_DYNAMIC_SMPS) link->u.mgd.req_smps = IEEE80211_SMPS_AUTOMATIC; else @@ -7552,7 +7553,8 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, void ieee80211_mgd_stop_link(struct ieee80211_link_data *link) { - cancel_work_sync(&link->u.mgd.request_smps_work); + wiphy_work_cancel(link->sdata->local->hw.wiphy, + &link->u.mgd.request_smps_work); cancel_work_sync(&link->u.mgd.chswitch_work); } diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index b255f3b5bf01..52c47674a554 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1431,8 +1431,8 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, } if (ret == 0) - ieee80211_queue_work(&sdata->local->hw, - &sdata->deflink.u.mgd.request_smps_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &sdata->deflink.u.mgd.request_smps_work); mutex_unlock(&local->mtx); sdata_unlock(sdata); -- cgit v1.2.3 From ec3252bff7b60fd2ee1a51a11054c54d63435ed2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:29 +0200 Subject: wifi: mac80211: use wiphy work for channel switch Channel switch obviously must be handled per link, and we have a (potential) deadlock when canceling that work. Use the new delayed wiphy work to handle this instead and get rid of the explicit timer that way too. Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 4 ++-- net/mac80211/ieee80211_i.h | 3 +-- net/mac80211/mlme.c | 40 +++++++++++++++++----------------------- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 4d50e95dd75f..168bf3edd4b4 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -1205,8 +1205,8 @@ ieee80211_link_chanctx_reservation_complete(struct ieee80211_link_data *link) &link->csa_finalize_work); break; case NL80211_IFTYPE_STATION: - ieee80211_queue_work(&sdata->local->hw, - &link->u.mgd.chswitch_work); + wiphy_delayed_work_queue(sdata->local->hw.wiphy, + &link->u.mgd.chswitch_work, 0); break; case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_AP_VLAN: diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0ecb725f5307..b39a923cdd0e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -918,8 +918,7 @@ struct ieee80211_link_data_managed { bool csa_waiting_bcn; bool csa_ignored_same_chan; - struct timer_list chswitch_timer; - struct work_struct chswitch_work; + struct wiphy_delayed_work chswitch_work; struct wiphy_work request_smps_work; bool beacon_crc_valid; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c4a1bf6b6fb4..0e68ede2a9f3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1679,10 +1679,12 @@ void ieee80211_send_4addr_nullfunc(struct ieee80211_local *local, } /* spectrum management related things */ -static void ieee80211_chswitch_work(struct work_struct *work) +static void ieee80211_chswitch_work(struct wiphy *wiphy, + struct wiphy_work *work) { struct ieee80211_link_data *link = - container_of(work, struct ieee80211_link_data, u.mgd.chswitch_work); + container_of(work, struct ieee80211_link_data, + u.mgd.chswitch_work.work); struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -1802,21 +1804,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) ieee80211_queue_work(&sdata->local->hw, &ifmgd->csa_connection_drop_work); } else { - ieee80211_queue_work(&sdata->local->hw, - &sdata->deflink.u.mgd.chswitch_work); + wiphy_delayed_work_queue(sdata->local->hw.wiphy, + &sdata->deflink.u.mgd.chswitch_work, + 0); } } EXPORT_SYMBOL(ieee80211_chswitch_done); -static void ieee80211_chswitch_timer(struct timer_list *t) -{ - struct ieee80211_link_data *link = - from_timer(link, t, u.mgd.chswitch_timer); - - ieee80211_queue_work(&link->sdata->local->hw, - &link->u.mgd.chswitch_work); -} - static void ieee80211_sta_abort_chanswitch(struct ieee80211_link_data *link) { @@ -1860,6 +1854,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, struct ieee80211_csa_ie csa_ie; struct ieee80211_channel_switch ch_switch; struct ieee80211_bss *bss; + unsigned long timeout; int res; sdata_assert_lock(sdata); @@ -2003,12 +1998,11 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, } /* channel switch handled in software */ - if (csa_ie.count <= 1) - ieee80211_queue_work(&local->hw, &link->u.mgd.chswitch_work); - else - mod_timer(&link->u.mgd.chswitch_timer, - TU_TO_EXP_TIME((csa_ie.count - 1) * - cbss->beacon_interval)); + timeout = TU_TO_JIFFIES((max_t(int, csa_ie.count, 1) - 1) * + cbss->beacon_interval); + wiphy_delayed_work_queue(local->hw.wiphy, + &link->u.mgd.chswitch_work, + timeout); return; lock_and_drop_connection: mutex_lock(&local->mtx); @@ -3030,7 +3024,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, del_timer_sync(&sdata->u.mgd.conn_mon_timer); del_timer_sync(&sdata->u.mgd.bcn_mon_timer); del_timer_sync(&sdata->u.mgd.timer); - del_timer_sync(&sdata->deflink.u.mgd.chswitch_timer); sdata->vif.bss_conf.dtim_period = 0; sdata->vif.bss_conf.beacon_rate = NULL; @@ -6596,8 +6589,8 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link) else link->u.mgd.req_smps = IEEE80211_SMPS_OFF; - INIT_WORK(&link->u.mgd.chswitch_work, ieee80211_chswitch_work); - timer_setup(&link->u.mgd.chswitch_timer, ieee80211_chswitch_timer, 0); + wiphy_delayed_work_init(&link->u.mgd.chswitch_work, + ieee80211_chswitch_work); if (sdata->u.mgd.assoc_data) ether_addr_copy(link->conf->addr, @@ -7555,7 +7548,8 @@ void ieee80211_mgd_stop_link(struct ieee80211_link_data *link) { wiphy_work_cancel(link->sdata->local->hw.wiphy, &link->u.mgd.request_smps_work); - cancel_work_sync(&link->u.mgd.chswitch_work); + wiphy_delayed_work_cancel(link->sdata->local->hw.wiphy, + &link->u.mgd.chswitch_work); } void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) -- cgit v1.2.3 From 87351d09261308472ddb6d700e182c34db4fce7a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:30 +0200 Subject: wifi: mac80211: ibss: move disconnect to wiphy work Move the IBSS disconnect work to be a wiphy work. Signed-off-by: Johannes Berg --- net/mac80211/ibss.c | 14 ++++++++------ net/mac80211/ieee80211_i.h | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 19017810024b..e1900077bc4b 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -561,7 +561,8 @@ void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - cancel_work_sync(&ifibss->csa_connection_drop_work); + wiphy_work_cancel(sdata->local->hw.wiphy, + &ifibss->csa_connection_drop_work); } static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta) @@ -730,7 +731,8 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata) mutex_unlock(&local->mtx); } -static void ieee80211_csa_connection_drop_work(struct work_struct *work) +static void ieee80211_csa_connection_drop_work(struct wiphy *wiphy, + struct wiphy_work *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, @@ -896,8 +898,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata, return true; disconnect: ibss_dbg(sdata, "Can't handle channel switch, disconnect\n"); - ieee80211_queue_work(&sdata->local->hw, - &ifibss->csa_connection_drop_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &ifibss->csa_connection_drop_work); ieee80211_ibss_csa_mark_radar(sdata); @@ -1733,8 +1735,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) timer_setup(&ifibss->timer, ieee80211_ibss_timer, 0); INIT_LIST_HEAD(&ifibss->incomplete_stations); spin_lock_init(&ifibss->incomplete_lock); - INIT_WORK(&ifibss->csa_connection_drop_work, - ieee80211_csa_connection_drop_work); + wiphy_work_init(&ifibss->csa_connection_drop_work, + ieee80211_csa_connection_drop_work); } /* scan finished notification */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b39a923cdd0e..78ac71b66fce 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -553,7 +553,7 @@ struct ieee80211_if_managed { struct ieee80211_if_ibss { struct timer_list timer; - struct work_struct csa_connection_drop_work; + struct wiphy_work csa_connection_drop_work; unsigned long last_scan_completed; -- cgit v1.2.3 From 4b8d43f1137cb9f6e8bb3b77251ad9429ab7ef34 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:31 +0200 Subject: wifi: mac80211: mlme: move disconnects to wiphy work Move the beacon loss work that might cause a disconnect and the CSA disconnect work to be wiphy work, so we hold the wiphy lock for them. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 2 +- net/mac80211/ieee80211_i.h | 4 ++-- net/mac80211/main.c | 3 ++- net/mac80211/mlme.c | 49 +++++++++++++++++++++++++--------------------- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index cf090abda400..1b78a2ae7a83 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -3590,7 +3590,7 @@ void ieee80211_channel_switch_disconnect(struct ieee80211_vif *vif, bool block_t sdata->deflink.csa_block_tx = block_tx; sdata_info(sdata, "channel switch failed, disconnecting\n"); - ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); + wiphy_work_queue(local->hw.wiphy, &ifmgd->csa_connection_drop_work); } EXPORT_SYMBOL(ieee80211_channel_switch_disconnect); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 78ac71b66fce..f918e73469a7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -466,8 +466,8 @@ struct ieee80211_if_managed { struct timer_list conn_mon_timer; struct timer_list bcn_mon_timer; struct work_struct monitor_work; - struct work_struct beacon_connection_loss_work; - struct work_struct csa_connection_drop_work; + struct wiphy_work beacon_connection_loss_work; + struct wiphy_work csa_connection_drop_work; unsigned long beacon_timeout; unsigned long probe_timeout; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3db178b1d50c..24315d7b3126 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -364,7 +364,8 @@ static void ieee80211_restart_work(struct work_struct *work) * The exception is ieee80211_chswitch_done. * Then we can have a race... */ - cancel_work_sync(&sdata->u.mgd.csa_connection_drop_work); + wiphy_work_cancel(local->hw.wiphy, + &sdata->u.mgd.csa_connection_drop_work); if (sdata->vif.bss_conf.csa_active) { sdata_lock(sdata); ieee80211_sta_connection_lost(sdata, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0e68ede2a9f3..3827b5dcdb03 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1724,8 +1724,8 @@ static void ieee80211_chswitch_work(struct wiphy *wiphy, sdata_info(sdata, "failed to use reserved channel context, disconnecting (err=%d)\n", ret); - ieee80211_queue_work(&sdata->local->hw, - &ifmgd->csa_connection_drop_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &ifmgd->csa_connection_drop_work); goto out; } @@ -1736,8 +1736,8 @@ static void ieee80211_chswitch_work(struct wiphy *wiphy, &link->csa_chandef)) { sdata_info(sdata, "failed to finalize channel switch, disconnecting\n"); - ieee80211_queue_work(&sdata->local->hw, - &ifmgd->csa_connection_drop_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &ifmgd->csa_connection_drop_work); goto out; } @@ -1781,8 +1781,8 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_link_data *link) if (ret) { sdata_info(sdata, "driver post channel switch failed, disconnecting\n"); - ieee80211_queue_work(&local->hw, - &ifmgd->csa_connection_drop_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &ifmgd->csa_connection_drop_work); return; } @@ -1801,8 +1801,8 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) if (!success) { sdata_info(sdata, "driver channel switch failed, disconnecting\n"); - ieee80211_queue_work(&sdata->local->hw, - &ifmgd->csa_connection_drop_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &ifmgd->csa_connection_drop_work); } else { wiphy_delayed_work_queue(sdata->local->hw.wiphy, &sdata->deflink.u.mgd.chswitch_work, @@ -2018,7 +2018,8 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, link->conf->csa_active = true; link->csa_block_tx = csa_ie.mode; - ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &ifmgd->csa_connection_drop_work); mutex_unlock(&local->chanctx_mtx); mutex_unlock(&local->mtx); } @@ -3415,7 +3416,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) sdata_unlock(sdata); } -static void ieee80211_beacon_connection_loss_work(struct work_struct *work) +static void ieee80211_beacon_connection_loss_work(struct wiphy *wiphy, + struct wiphy_work *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, @@ -3440,7 +3442,8 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) } } -static void ieee80211_csa_connection_drop_work(struct work_struct *work) +static void ieee80211_csa_connection_drop_work(struct wiphy *wiphy, + struct wiphy_work *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, @@ -3457,7 +3460,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) trace_api_beacon_loss(sdata); sdata->u.mgd.connection_loss = false; - ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); + wiphy_work_queue(hw->wiphy, &sdata->u.mgd.beacon_connection_loss_work); } EXPORT_SYMBOL(ieee80211_beacon_loss); @@ -3469,7 +3472,7 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif) trace_api_connection_loss(sdata); sdata->u.mgd.connection_loss = true; - ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); + wiphy_work_queue(hw->wiphy, &sdata->u.mgd.beacon_connection_loss_work); } EXPORT_SYMBOL(ieee80211_connection_loss); @@ -3485,7 +3488,7 @@ void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect) sdata->u.mgd.driver_disconnect = true; sdata->u.mgd.reconnect = reconnect; - ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); + wiphy_work_queue(hw->wiphy, &sdata->u.mgd.beacon_connection_loss_work); } EXPORT_SYMBOL(ieee80211_disconnect); @@ -6374,8 +6377,8 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) return; sdata->u.mgd.connection_loss = false; - ieee80211_queue_work(&sdata->local->hw, - &sdata->u.mgd.beacon_connection_loss_work); + wiphy_work_queue(sdata->local->hw.wiphy, + &sdata->u.mgd.beacon_connection_loss_work); } static void ieee80211_sta_conn_mon_timer(struct timer_list *t) @@ -6550,10 +6553,10 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work); - INIT_WORK(&ifmgd->beacon_connection_loss_work, - ieee80211_beacon_connection_loss_work); - INIT_WORK(&ifmgd->csa_connection_drop_work, - ieee80211_csa_connection_drop_work); + wiphy_work_init(&ifmgd->beacon_connection_loss_work, + ieee80211_beacon_connection_loss_work); + wiphy_work_init(&ifmgd->csa_connection_drop_work, + ieee80211_csa_connection_drop_work); INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work, ieee80211_tdls_peer_del_work); timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0); @@ -7562,8 +7565,10 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) * cancelled when disconnecting. */ cancel_work_sync(&ifmgd->monitor_work); - cancel_work_sync(&ifmgd->beacon_connection_loss_work); - cancel_work_sync(&ifmgd->csa_connection_drop_work); + wiphy_work_cancel(sdata->local->hw.wiphy, + &ifmgd->beacon_connection_loss_work); + wiphy_work_cancel(sdata->local->hw.wiphy, + &ifmgd->csa_connection_drop_work); cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work); sdata_lock(sdata); -- cgit v1.2.3 From c88d7178229b7b9482ab4cc0b781aef0f20c3dfb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:32 +0200 Subject: wifi: cfg80211: move sched scan stop to wiphy work This work can now trivially be converted, it behaves identical either way. Signed-off-by: Johannes Berg --- net/wireless/core.c | 8 +++----- net/wireless/core.h | 2 +- net/wireless/nl80211.c | 3 ++- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index ca585e96d535..f59624f008fb 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -365,7 +365,8 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work) rtnl_unlock(); } -static void cfg80211_sched_scan_stop_wk(struct work_struct *work) +static void cfg80211_sched_scan_stop_wk(struct wiphy *wiphy, + struct wiphy_work *work) { struct cfg80211_registered_device *rdev; struct cfg80211_sched_scan_request *req, *tmp; @@ -373,12 +374,10 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work) rdev = container_of(work, struct cfg80211_registered_device, sched_scan_stop_wk); - wiphy_lock(&rdev->wiphy); list_for_each_entry_safe(req, tmp, &rdev->sched_scan_req_list, list) { if (req->nl_owner_dead) cfg80211_stop_sched_scan_req(rdev, req, false); } - wiphy_unlock(&rdev->wiphy); } static void cfg80211_propagate_radar_detect_wk(struct work_struct *work) @@ -541,7 +540,7 @@ use_default_name: device_enable_async_suspend(&rdev->wiphy.dev); INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); - INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk); + wiphy_work_init(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk); INIT_WORK(&rdev->sched_scan_res_wk, cfg80211_sched_scan_results_wk); INIT_WORK(&rdev->propagate_radar_detect_wk, cfg80211_propagate_radar_detect_wk); @@ -1148,7 +1147,6 @@ void wiphy_unregister(struct wiphy *wiphy) cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); cancel_delayed_work_sync(&rdev->background_cac_done_wk); flush_work(&rdev->destroy_work); - flush_work(&rdev->sched_scan_stop_wk); flush_work(&rdev->propagate_radar_detect_wk); flush_work(&rdev->propagate_cac_done_wk); flush_work(&rdev->mgmt_registrations_update_wk); diff --git a/net/wireless/core.h b/net/wireless/core.h index 435060dad81e..468957a0be24 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -95,7 +95,7 @@ struct cfg80211_registered_device { struct cfg80211_coalesce *coalesce; struct work_struct destroy_work; - struct work_struct sched_scan_stop_wk; + struct wiphy_work sched_scan_stop_wk; struct work_struct sched_scan_res_wk; struct cfg80211_chan_def radar_chandef; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a52bd739cf84..772671b9bc42 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -19777,7 +19777,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb, list) { if (sched_scan_req->owner_nlportid == notify->portid) { sched_scan_req->nl_owner_dead = true; - schedule_work(&rdev->sched_scan_stop_wk); + wiphy_work_queue(&rdev->wiphy, + &rdev->sched_scan_stop_wk); } } -- cgit v1.2.3 From fe0af9fe54d0ff53aa49eef390c8962355b274e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 14:49:33 +0200 Subject: wifi: cfg80211: move scan done work to wiphy work Move the scan done work to the new wiphy work to simplify the code a bit. Signed-off-by: Johannes Berg --- net/wireless/core.c | 3 +-- net/wireless/core.h | 4 ++-- net/wireless/scan.c | 14 ++++---------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index f59624f008fb..fc449bea39a1 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -527,7 +527,7 @@ use_default_name: spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); INIT_LIST_HEAD(&rdev->sched_scan_req_list); - INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); + wiphy_work_init(&rdev->scan_done_wk, __cfg80211_scan_done); INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk, cfg80211_dfs_channels_update_work); #ifdef CONFIG_CFG80211_WEXT @@ -1141,7 +1141,6 @@ void wiphy_unregister(struct wiphy *wiphy) /* this has nothing to do now but make sure it's gone */ cancel_work_sync(&rdev->wiphy_work); - flush_work(&rdev->scan_done_wk); cancel_work_sync(&rdev->conn_work); flush_work(&rdev->event_work); cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); diff --git a/net/wireless/core.h b/net/wireless/core.h index 468957a0be24..291c6d83d56f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -75,7 +75,7 @@ struct cfg80211_registered_device { struct sk_buff *scan_msg; struct list_head sched_scan_req_list; time64_t suspend_at; - struct work_struct scan_done_wk; + struct wiphy_work scan_done_wk; struct genl_info *cur_cmd_info; @@ -441,7 +441,7 @@ bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev, int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, struct key_params *params, int key_idx, bool pairwise, const u8 *mac_addr); -void __cfg80211_scan_done(struct work_struct *wk); +void __cfg80211_scan_done(struct wiphy *wiphy, struct wiphy_work *wk); void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool send_message); void cfg80211_add_sched_scan_req(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/scan.c b/net/wireless/scan.c index c501db7bbdb3..ce2104dc05c6 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1004,16 +1004,9 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, nl80211_send_scan_msg(rdev, msg); } -void __cfg80211_scan_done(struct work_struct *wk) +void __cfg80211_scan_done(struct wiphy *wiphy, struct wiphy_work *wk) { - struct cfg80211_registered_device *rdev; - - rdev = container_of(wk, struct cfg80211_registered_device, - scan_done_wk); - - wiphy_lock(&rdev->wiphy); - ___cfg80211_scan_done(rdev, true); - wiphy_unlock(&rdev->wiphy); + ___cfg80211_scan_done(wiphy_to_rdev(wiphy), true); } void cfg80211_scan_done(struct cfg80211_scan_request *request, @@ -1039,7 +1032,8 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, } request->notified = true; - queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk); + wiphy_work_queue(request->wiphy, + &wiphy_to_rdev(request->wiphy)->scan_done_wk); } EXPORT_SYMBOL(cfg80211_scan_done); -- cgit v1.2.3 From 2cc9671a82e3ba8911f01b04fd8f8f2da3a238a7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 6 Jun 2023 12:43:00 -0700 Subject: tools: ynl-gen: fill in support for MultiAttr scalars The handshake family needs support for MultiAttr scalars. Right now we only support code gen for MultiAttr nested types. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 47 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 1e64c5c2a087..0a043edf5e03 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -94,7 +94,10 @@ class Type(SpecAttr): def arg_member(self, ri): member = self._complex_member_type(ri) if member: - return [member + ' *' + self.c_name] + arg = [member + ' *' + self.c_name] + if self.presence_type() == 'count': + arg += ['unsigned int n_' + self.c_name] + return arg raise Exception(f"Struct member not implemented for class type {self.type}") def struct_member(self, ri): @@ -188,9 +191,12 @@ class Type(SpecAttr): code.append(presence + ' = 1;') code += self._setter_lines(ri, member, presence) - ri.cw.write_func('static inline void', - f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}", - body=code, + func_name = f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}" + free = bool([x for x in code if 'free(' in x]) + alloc = bool([x for x in code if 'alloc(' in x]) + if free and not alloc: + func_name = '__' + func_name + ri.cw.write_func('static inline void', func_name, body=code, args=[f'{type_name(ri, direction, deref=deref)} *{var}'] + self.arg_member(ri)) @@ -444,6 +450,13 @@ class TypeMultiAttr(Type): def presence_type(self): return 'count' + def _mnl_type(self): + t = self.type + # mnl does not have a helper for signed types + if t[0] == 's': + t = 'u' + t[1:] + return t + def _complex_member_type(self, ri): if 'type' not in self.attr or self.attr['type'] == 'nest': return f"struct {self.nested_render_name}" @@ -457,9 +470,14 @@ class TypeMultiAttr(Type): return 'type' not in self.attr or self.attr['type'] == 'nest' def free(self, ri, var, ref): - if 'type' not in self.attr or self.attr['type'] == 'nest': + if self.attr['type'] in scalars: + ri.cw.p(f"free({var}->{ref}{self.c_name});") + elif 'type' not in self.attr or self.attr['type'] == 'nest': ri.cw.p(f"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)") ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);') + ri.cw.p(f"free({var}->{ref}{self.c_name});") + else: + raise Exception(f"Free of MultiAttr sub-type {self.attr['type']} not supported yet") def _attr_typol(self): if 'type' not in self.attr or self.attr['type'] == 'nest': @@ -472,6 +490,25 @@ class TypeMultiAttr(Type): def _attr_get(self, ri, var): return f'{var}->n_{self.c_name}++;', None, None + def attr_put(self, ri, var): + if self.attr['type'] in scalars: + put_type = self._mnl_type() + ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") + ri.cw.p(f"mnl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);") + elif 'type' not in self.attr or self.attr['type'] == 'nest': + ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)") + self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " + + f"{self.enum_name}, &{var}->{self.c_name}[i])") + else: + raise Exception(f"Put of MultiAttr sub-type {self.attr['type']} not supported yet") + + def _setter_lines(self, ri, member, presence): + # For multi-attr we have a count, not presence, hack up the presence + presence = presence[:-(len('_present.') + len(self.c_name))] + "n_" + self.c_name + return [f"free({member});", + f"{member} = {self.c_name};", + f"{presence} = n_{self.c_name};"] + class TypeArrayNest(Type): def is_multi_val(self): -- cgit v1.2.3 From 58da455b31baf87dd74b71fc54d0356e05c0bf49 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 6 Jun 2023 12:43:01 -0700 Subject: tools: ynl-gen: improve unwind on parsing errors When parsing multi-attr we count the objects and then allocate an array to hold the parsed objects. If an attr space has multiple multi-attr objects, however, if parsing the first array fails we'll leave the object count for the second even tho the second array was never allocated. This may cause crashes when freeing objects on error. Count attributes to a variable on the stack and only set the count in the object once the memory was allocated. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 0a043edf5e03..c07340715601 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -488,7 +488,7 @@ class TypeMultiAttr(Type): raise Exception(f"Sub-type {self.attr['type']} not supported yet") def _attr_get(self, ri, var): - return f'{var}->n_{self.c_name}++;', None, None + return f'n_{self.c_name}++;', None, None def attr_put(self, ri, var): if self.attr['type'] in scalars: @@ -1306,6 +1306,11 @@ def _multi_parse(ri, struct, init_lines, local_vars): local_vars.append('struct ynl_parse_arg parg;') init_lines.append('parg.ys = yarg->ys;') + all_multi = array_nests | multi_attrs + + for anest in sorted(all_multi): + local_vars.append(f"unsigned int n_{struct[anest].c_name} = 0;") + ri.cw.block_start() ri.cw.write_func_lvar(local_vars) @@ -1316,6 +1321,11 @@ def _multi_parse(ri, struct, init_lines, local_vars): for arg in struct.inherited: ri.cw.p(f'dst->{arg} = {arg};') + for anest in sorted(all_multi): + aspec = struct[anest] + ri.cw.p(f"if (dst->{aspec.c_name})") + ri.cw.p(f'return ynl_error_parse(yarg, "attribute already present ({struct.attr_set.name}.{aspec.name})");') + ri.cw.nl() ri.cw.block_start(line=iter_line) @@ -1331,8 +1341,9 @@ def _multi_parse(ri, struct, init_lines, local_vars): for anest in sorted(array_nests): aspec = struct[anest] - ri.cw.block_start(line=f"if (dst->n_{aspec.c_name})") - ri.cw.p(f"dst->{aspec.c_name} = calloc(dst->n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") + ri.cw.block_start(line=f"if (n_{aspec.c_name})") + ri.cw.p(f"dst->{aspec.c_name} = calloc({aspec.c_name}, sizeof(*dst->{aspec.c_name}));") + ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};") ri.cw.p('i = 0;') ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") ri.cw.block_start(line=f"mnl_attr_for_each_nested(attr, attr_{aspec.c_name})") @@ -1346,8 +1357,9 @@ def _multi_parse(ri, struct, init_lines, local_vars): for anest in sorted(multi_attrs): aspec = struct[anest] - ri.cw.block_start(line=f"if (dst->n_{aspec.c_name})") - ri.cw.p(f"dst->{aspec.c_name} = calloc(dst->n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") + ri.cw.block_start(line=f"if (n_{aspec.c_name})") + ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") + ri.cw.p(f"dst->n_{aspec.c_name} = n_{aspec.c_name};") ri.cw.p('i = 0;') if 'nested-attributes' in aspec: ri.cw.p(f"parg.rsp_policy = &{aspec.nested_render_name}_nest;") -- cgit v1.2.3 From 7a11f70ce8820d13db6bdde913e6520ad58daf20 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 6 Jun 2023 12:43:02 -0700 Subject: tools: ynl: generate code for the handshake family Generate support for the handshake family. Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/Makefile | 2 +- tools/net/ynl/generated/handshake-user.c | 385 +++++++++++++++++++++++++++++++ tools/net/ynl/generated/handshake-user.h | 148 ++++++++++++ 3 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 tools/net/ynl/generated/handshake-user.c create mode 100644 tools/net/ynl/generated/handshake-user.h diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index bbf5d83755c9..916723193b60 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -9,7 +9,7 @@ endif TOOL:=../ynl-gen-c.py -GENS:=fou netdev +GENS:=handshake fou netdev SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c new file mode 100644 index 000000000000..fe99c4ef7373 --- /dev/null +++ b/tools/net/ynl/generated/handshake-user.c @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/handshake.yaml */ +/* YNL-GEN user source */ + +#include +#include "handshake-user.h" +#include "ynl.h" +#include + +#include +#include +#include +#include +#include + +/* Enums */ +static const char * const handshake_op_strmap[] = { + [HANDSHAKE_CMD_READY] = "ready", + [HANDSHAKE_CMD_ACCEPT] = "accept", + [HANDSHAKE_CMD_DONE] = "done", +}; + +const char *handshake_op_str(int op) +{ + if (op < 0 || op >= (int)MNL_ARRAY_SIZE(handshake_op_strmap)) + return NULL; + return handshake_op_strmap[op]; +} + +static const char * const handshake_handler_class_strmap[] = { + [0] = "none", + [1] = "tlshd", + [2] = "max", +}; + +const char *handshake_handler_class_str(enum handshake_handler_class value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_handler_class_strmap)) + return NULL; + return handshake_handler_class_strmap[value]; +} + +static const char * const handshake_msg_type_strmap[] = { + [0] = "unspec", + [1] = "clienthello", + [2] = "serverhello", +}; + +const char *handshake_msg_type_str(enum handshake_msg_type value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_msg_type_strmap)) + return NULL; + return handshake_msg_type_strmap[value]; +} + +static const char * const handshake_auth_strmap[] = { + [0] = "unspec", + [1] = "unauth", + [2] = "psk", + [3] = "x509", +}; + +const char *handshake_auth_str(enum handshake_auth value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(handshake_auth_strmap)) + return NULL; + return handshake_auth_strmap[value]; +} + +/* Policies */ +extern struct ynl_policy_nest handshake_x509_nest; +extern struct ynl_policy_nest handshake_accept_nest; +extern struct ynl_policy_nest handshake_done_nest; + +struct ynl_policy_attr handshake_x509_policy[HANDSHAKE_A_X509_MAX + 1] = { + [HANDSHAKE_A_X509_CERT] = { .name = "cert", .type = YNL_PT_U32, }, + [HANDSHAKE_A_X509_PRIVKEY] = { .name = "privkey", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest handshake_x509_nest = { + .max_attr = HANDSHAKE_A_X509_MAX, + .table = handshake_x509_policy, +}; + +struct ynl_policy_attr handshake_accept_policy[HANDSHAKE_A_ACCEPT_MAX + 1] = { + [HANDSHAKE_A_ACCEPT_SOCKFD] = { .name = "sockfd", .type = YNL_PT_U32, }, + [HANDSHAKE_A_ACCEPT_HANDLER_CLASS] = { .name = "handler-class", .type = YNL_PT_U32, }, + [HANDSHAKE_A_ACCEPT_MESSAGE_TYPE] = { .name = "message-type", .type = YNL_PT_U32, }, + [HANDSHAKE_A_ACCEPT_TIMEOUT] = { .name = "timeout", .type = YNL_PT_U32, }, + [HANDSHAKE_A_ACCEPT_AUTH_MODE] = { .name = "auth-mode", .type = YNL_PT_U32, }, + [HANDSHAKE_A_ACCEPT_PEER_IDENTITY] = { .name = "peer-identity", .type = YNL_PT_U32, }, + [HANDSHAKE_A_ACCEPT_CERTIFICATE] = { .name = "certificate", .type = YNL_PT_NEST, .nest = &handshake_x509_nest, }, + [HANDSHAKE_A_ACCEPT_PEERNAME] = { .name = "peername", .type = YNL_PT_NUL_STR, }, +}; + +struct ynl_policy_nest handshake_accept_nest = { + .max_attr = HANDSHAKE_A_ACCEPT_MAX, + .table = handshake_accept_policy, +}; + +struct ynl_policy_attr handshake_done_policy[HANDSHAKE_A_DONE_MAX + 1] = { + [HANDSHAKE_A_DONE_STATUS] = { .name = "status", .type = YNL_PT_U32, }, + [HANDSHAKE_A_DONE_SOCKFD] = { .name = "sockfd", .type = YNL_PT_U32, }, + [HANDSHAKE_A_DONE_REMOTE_AUTH] = { .name = "remote-auth", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest handshake_done_nest = { + .max_attr = HANDSHAKE_A_DONE_MAX, + .table = handshake_done_policy, +}; + +/* Common nested types */ +void handshake_x509_free(struct handshake_x509 *obj) +{ +} + +int handshake_x509_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct handshake_x509 *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == HANDSHAKE_A_X509_CERT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.cert = 1; + dst->cert = mnl_attr_get_u32(attr); + } + else if (mnl_attr_get_type(attr) == HANDSHAKE_A_X509_PRIVKEY) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.privkey = 1; + dst->privkey = mnl_attr_get_u32(attr); + } + } + + return 0; +} + +/* ============== HANDSHAKE_CMD_ACCEPT ============== */ +/* HANDSHAKE_CMD_ACCEPT - do */ +void handshake_accept_req_free(struct handshake_accept_req *req) +{ + free(req); +} + +void handshake_accept_rsp_free(struct handshake_accept_rsp *rsp) +{ + unsigned int i; + + free(rsp->peer_identity); + for (i = 0; i < rsp->n_certificate; i++) + handshake_x509_free(&rsp->certificate[i]); + free(rsp->certificate); + free(rsp->peername); + free(rsp); +} + +int handshake_accept_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct handshake_accept_rsp *dst; + unsigned int n_peer_identity = 0; + unsigned int n_certificate = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + dst = yarg->data; + parg.ys = yarg->ys; + + if (dst->certificate) + return ynl_error_parse(yarg, "attribute already present (accept.certificate)"); + if (dst->peer_identity) + return ynl_error_parse(yarg, "attribute already present (accept.peer-identity)"); + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_SOCKFD) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sockfd = 1; + dst->sockfd = mnl_attr_get_u32(attr); + } + else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_MESSAGE_TYPE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.message_type = 1; + dst->message_type = mnl_attr_get_u32(attr); + } + else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_TIMEOUT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.timeout = 1; + dst->timeout = mnl_attr_get_u32(attr); + } + else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_AUTH_MODE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.auth_mode = 1; + dst->auth_mode = mnl_attr_get_u32(attr); + } + else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { + n_peer_identity++; + } + else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_CERTIFICATE) { + n_certificate++; + } + else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_PEERNAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.peername_len = len; + dst->peername = malloc(len + 1); + memcpy(dst->peername, mnl_attr_get_str(attr), len); + dst->peername[len] = 0; + } + } + + if (n_certificate) { + dst->certificate = calloc(n_certificate, sizeof(*dst->certificate)); + dst->n_certificate = n_certificate; + i = 0; + parg.rsp_policy = &handshake_x509_nest; + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_CERTIFICATE) { + parg.data = &dst->certificate[i]; + if (handshake_x509_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + if (n_peer_identity) { + dst->peer_identity = calloc(n_peer_identity, sizeof(*dst->peer_identity)); + dst->n_peer_identity = n_peer_identity; + i = 0; + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { + dst->peer_identity[i] = mnl_attr_get_u32(attr); + i++; + } + } + } + + return MNL_CB_OK; +} + +struct handshake_accept_rsp * +handshake_accept(struct ynl_sock *ys, struct handshake_accept_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct handshake_accept_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, HANDSHAKE_CMD_ACCEPT, 1); + ys->req_policy = &handshake_accept_nest; + yrs.yarg.rsp_policy = &handshake_accept_nest; + + if (req->_present.handler_class) + mnl_attr_put_u32(nlh, HANDSHAKE_A_ACCEPT_HANDLER_CLASS, req->handler_class); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = handshake_accept_rsp_parse; + yrs.rsp_cmd = HANDSHAKE_CMD_ACCEPT; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + handshake_accept_rsp_free(rsp); + return NULL; +} + +/* HANDSHAKE_CMD_ACCEPT - notify */ +void handshake_accept_ntf_free(struct handshake_accept_ntf *rsp) +{ + unsigned int i; + + free(rsp->obj.peer_identity); + for (i = 0; i < rsp->obj.n_certificate; i++) + handshake_x509_free(&rsp->obj.certificate[i]); + free(rsp->obj.certificate); + free(rsp->obj.peername); + free(rsp); +} + +/* ============== HANDSHAKE_CMD_DONE ============== */ +/* HANDSHAKE_CMD_DONE - do */ +void handshake_done_req_free(struct handshake_done_req *req) +{ + free(req->remote_auth); + free(req); +} + +int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, HANDSHAKE_CMD_DONE, 1); + ys->req_policy = &handshake_done_nest; + + if (req->_present.status) + mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_STATUS, req->status); + if (req->_present.sockfd) + mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_SOCKFD, req->sockfd); + for (unsigned int i = 0; i < req->n_remote_auth; i++) + mnl_attr_put_u32(nlh, HANDSHAKE_A_DONE_REMOTE_AUTH, req->remote_auth[i]); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* --------------- Common notification parsing --------------- */ +struct ynl_ntf_base_type *handshake_ntf_parse(struct ynl_sock *ys) +{ + struct ynl_parse_arg yarg = { .ys = ys, }; + struct ynl_ntf_base_type *rsp; + struct genlmsghdr *genlh; + struct nlmsghdr *nlh; + mnl_cb_t parse; + int len, err; + + len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); + if (len < (ssize_t)(sizeof(*nlh) + sizeof(*genlh))) + return NULL; + + nlh = (struct nlmsghdr *)ys->rx_buf; + genlh = mnl_nlmsg_get_payload(nlh); + + switch (genlh->cmd) { + case HANDSHAKE_CMD_READY: + rsp = calloc(1, sizeof(struct handshake_accept_ntf)); + parse = handshake_accept_rsp_parse; + yarg.rsp_policy = &handshake_accept_nest; + rsp->free = (void *)handshake_accept_ntf_free; + break; + default: + ynl_error_unknown_notification(ys, genlh->cmd); + return NULL; + } + + yarg.data = rsp->data; + + err = mnl_cb_run2(ys->rx_buf, len, 0, 0, parse, &yarg, + ynl_cb_array, NLMSG_MIN_TYPE); + if (err < 0) + goto err_free; + + rsp->family = nlh->nlmsg_type; + rsp->cmd = genlh->cmd; + return rsp; + +err_free: + free(rsp); + return NULL; +} + +static const struct ynl_ntf_info handshake_ntf_info[] = { + [HANDSHAKE_CMD_READY] = { + .alloc_sz = sizeof(struct handshake_accept_ntf), + .cb = handshake_accept_rsp_parse, + .policy = &handshake_accept_nest, + .free = (void *)handshake_accept_ntf_free, + }, +}; + +const struct ynl_family ynl_handshake_family = { + .name = "handshake", + .ntf_info = handshake_ntf_info, + .ntf_info_size = MNL_ARRAY_SIZE(handshake_ntf_info), +}; diff --git a/tools/net/ynl/generated/handshake-user.h b/tools/net/ynl/generated/handshake-user.h new file mode 100644 index 000000000000..38e0844f2efd --- /dev/null +++ b/tools/net/ynl/generated/handshake-user.h @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/handshake.yaml */ +/* YNL-GEN user header */ + +#ifndef _LINUX_HANDSHAKE_GEN_H +#define _LINUX_HANDSHAKE_GEN_H + +#include +#include +#include +#include + +struct ynl_sock; + +extern const struct ynl_family ynl_handshake_family; + +/* Enums */ +const char *handshake_op_str(int op); +const char *handshake_handler_class_str(enum handshake_handler_class value); +const char *handshake_msg_type_str(enum handshake_msg_type value); +const char *handshake_auth_str(enum handshake_auth value); + +/* Common nested types */ +struct handshake_x509 { + struct { + __u32 cert:1; + __u32 privkey:1; + } _present; + + __u32 cert; + __u32 privkey; +}; + +/* ============== HANDSHAKE_CMD_ACCEPT ============== */ +/* HANDSHAKE_CMD_ACCEPT - do */ +struct handshake_accept_req { + struct { + __u32 handler_class:1; + } _present; + + enum handshake_handler_class handler_class; +}; + +static inline struct handshake_accept_req *handshake_accept_req_alloc(void) +{ + return calloc(1, sizeof(struct handshake_accept_req)); +} +void handshake_accept_req_free(struct handshake_accept_req *req); + +static inline void +handshake_accept_req_set_handler_class(struct handshake_accept_req *req, + enum handshake_handler_class handler_class) +{ + req->_present.handler_class = 1; + req->handler_class = handler_class; +} + +struct handshake_accept_rsp { + struct { + __u32 sockfd:1; + __u32 message_type:1; + __u32 timeout:1; + __u32 auth_mode:1; + __u32 peername_len; + } _present; + + __u32 sockfd; + enum handshake_msg_type message_type; + __u32 timeout; + enum handshake_auth auth_mode; + unsigned int n_peer_identity; + __u32 *peer_identity; + unsigned int n_certificate; + struct handshake_x509 *certificate; + char *peername; +}; + +void handshake_accept_rsp_free(struct handshake_accept_rsp *rsp); + +/* + * Handler retrieves next queued handshake request + */ +struct handshake_accept_rsp * +handshake_accept(struct ynl_sock *ys, struct handshake_accept_req *req); + +/* HANDSHAKE_CMD_ACCEPT - notify */ +struct handshake_accept_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct handshake_accept_ntf *ntf); + struct handshake_accept_rsp obj __attribute__ ((aligned (8))); +}; + +void handshake_accept_ntf_free(struct handshake_accept_ntf *rsp); + +/* ============== HANDSHAKE_CMD_DONE ============== */ +/* HANDSHAKE_CMD_DONE - do */ +struct handshake_done_req { + struct { + __u32 status:1; + __u32 sockfd:1; + } _present; + + __u32 status; + __u32 sockfd; + unsigned int n_remote_auth; + __u32 *remote_auth; +}; + +static inline struct handshake_done_req *handshake_done_req_alloc(void) +{ + return calloc(1, sizeof(struct handshake_done_req)); +} +void handshake_done_req_free(struct handshake_done_req *req); + +static inline void +handshake_done_req_set_status(struct handshake_done_req *req, __u32 status) +{ + req->_present.status = 1; + req->status = status; +} +static inline void +handshake_done_req_set_sockfd(struct handshake_done_req *req, __u32 sockfd) +{ + req->_present.sockfd = 1; + req->sockfd = sockfd; +} +static inline void +__handshake_done_req_set_remote_auth(struct handshake_done_req *req, + __u32 *remote_auth, + unsigned int n_remote_auth) +{ + free(req->remote_auth); + req->remote_auth = remote_auth; + req->n_remote_auth = n_remote_auth; +} + +/* + * Handler reports handshake completion + */ +int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req); + +/* --------------- Common notification parsing --------------- */ +struct ynl_ntf_base_type *handshake_ntf_parse(struct ynl_sock *ys); + +#endif /* _LINUX_HANDSHAKE_GEN_H */ -- cgit v1.2.3 From 2d830f7a41343302ab19e73d4f44f5ccb6940a25 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Wed, 7 Jun 2023 15:59:37 +0200 Subject: net: altera-tse: Initialize local structs before using it The regmap_config and mdio_regmap_config objects needs to be zeroed before using them. This will cause spurious errors at probe time as config->pad_bits is containing random uninitialized data. Fixes: db48abbaa18e ("net: ethernet: altera-tse: Convert to mdio-regmap and use PCS Lynx") Signed-off-by: Maxime Chevallier Reviewed-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/altera/altera_tse_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index d866c0f1b503..215f9fb89c5b 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1255,6 +1255,8 @@ static int altera_tse_probe(struct platform_device *pdev) if (ret) goto err_free_netdev; + memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg)); + memset(&mrc, 0, sizeof(mrc)); /* SGMII PCS address space. The location can vary depending on how the * IP is integrated. We can have a resource dedicated to it at a specific * address space, but if it's not the case, we fallback to the mdiophy0 -- cgit v1.2.3 From fae555f5a56f1d10cc5dc6ec3ad4f07243f6ce3c Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Wed, 7 Jun 2023 15:59:38 +0200 Subject: net: altera_tse: Use the correct Kconfig option for the PCS_LYNX dependency Use the correct Kconfig dependency for altera_tse as PCS_ALTERA_TSE was replaced by PCS_LYNX. Fixes: db48abbaa18e ("net: ethernet: altera-tse: Convert to mdio-regmap and use PCS Lynx") Signed-off-by: Maxime Chevallier Reviewed-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/altera/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/altera/Kconfig index 93533ba03429..17985319088c 100644 --- a/drivers/net/ethernet/altera/Kconfig +++ b/drivers/net/ethernet/altera/Kconfig @@ -4,7 +4,7 @@ config ALTERA_TSE depends on HAS_DMA select PHYLIB select PHYLINK - select PCS_ALTERA_TSE + select PCS_LYNX select MDIO_REGMAP select REGMAP_MMIO help -- cgit v1.2.3 From a8dd7404c21447b46e792a483f4d73af66ccaf8d Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Wed, 7 Jun 2023 15:59:39 +0200 Subject: net: stmmac: make the pcs_lynx cleanup sequence specific to dwmac_socfpga So far, only the dwmac_socfpga variant of stmmac uses PCS Lynx. Use a dedicated cleanup sequence for dwmac_socfpga instead of using the generic stmmac one. Fixes: 5d1f3fe7d2d5 ("net: stmmac: dwmac-sogfpga: use the lynx pcs driver") Suggested-by: Russell King (Oracle) Signed-off-by: Maxime Chevallier Reviewed-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/common.h | 1 - drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 14 +++++++++++++- drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 3 --- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 52c5ec553276..16e67c18b6f7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -16,7 +16,6 @@ #include #include #include -#include #include #if IS_ENABLED(CONFIG_VLAN_8021Q) #define STMMAC_VLAN_TAG_USED diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index e399fccbafe5..1fb808be843b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -494,6 +495,17 @@ err_remove_config_dt: return ret; } +static void socfpga_dwmac_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(ndev); + struct phylink_pcs *pcs = priv->hw->lynx_pcs; + + stmmac_pltfr_remove(pdev); + + lynx_pcs_destroy(pcs); +} + #ifdef CONFIG_PM_SLEEP static int socfpga_dwmac_resume(struct device *dev) { @@ -565,7 +577,7 @@ MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); static struct platform_driver socfpga_dwmac_driver = { .probe = socfpga_dwmac_probe, - .remove_new = stmmac_pltfr_remove, + .remove_new = socfpga_dwmac_remove, .driver = { .name = "socfpga-dwmac", .pm = &socfpga_dwmac_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index c784a6731f08..3db1cb0fd160 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -665,9 +665,6 @@ int stmmac_mdio_unregister(struct net_device *ndev) if (priv->hw->xpcs) xpcs_destroy(priv->hw->xpcs); - if (priv->hw->lynx_pcs) - lynx_pcs_destroy(priv->hw->lynx_pcs); - mdiobus_unregister(priv->mii); priv->mii->priv = NULL; mdiobus_free(priv->mii); -- cgit v1.2.3 From fa19a5d9dcffddae2cb5774df98b09ca3f2ea783 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Wed, 7 Jun 2023 15:59:40 +0200 Subject: net: altera_tse: explicitly disable autoscan on the regmap-mdio bus Set the .autoscan flag to false on the regmap-mdio bus, to avoid using a random uninitialized value. We don't want autoscan in this case as the mdio device is a PCS and not a PHY. Fixes: db48abbaa18e ("net: ethernet: altera-tse: Convert to mdio-regmap and use PCS Lynx") Suggested-by: Russell King (Oracle) Signed-off-by: Maxime Chevallier Reviewed-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/altera/altera_tse_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 215f9fb89c5b..2e15800e5310 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1288,6 +1288,7 @@ static int altera_tse_probe(struct platform_device *pdev) mrc.regmap = pcs_regmap; mrc.parent = &pdev->dev; mrc.valid_addr = 0x0; + mrc.autoscan = false; /* Rx IRQ */ priv->rx_irq = platform_get_irq_byname(pdev, "rx_irq"); -- cgit v1.2.3 From 06b9dede1e7d8b7a199f8014aca5a7d7137b41b0 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Wed, 7 Jun 2023 15:59:41 +0200 Subject: net: dwmac_socfpga: initialize local data for mdio regmap configuration Explicitly zero-ize the local mdio_regmap_config data, and explicitly set the .autoscan parameter, as we only have a PCS on this bus. Fixes: 5d1f3fe7d2d5 ("net: stmmac: dwmac-sogfpga: use the lynx pcs driver") Suggested-by: Russell King (Oracle) Suggested-by: Maciej Fijalkowski Signed-off-by: Maxime Chevallier Reviewed-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 1fb808be843b..6267bcb60206 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -389,7 +389,6 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) struct net_device *ndev; struct stmmac_priv *stpriv; const struct socfpga_dwmac_ops *ops; - struct regmap_config pcs_regmap_cfg; ops = device_get_match_data(&pdev->dev); if (!ops) { @@ -447,19 +446,22 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) if (ret) goto err_dvr_remove; - memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg)); - pcs_regmap_cfg.reg_bits = 16; - pcs_regmap_cfg.val_bits = 16; - pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(1); - /* Create a regmap for the PCS so that it can be used by the PCS driver, * if we have such a PCS */ if (dwmac->tse_pcs_base) { + struct regmap_config pcs_regmap_cfg; struct mdio_regmap_config mrc; struct regmap *pcs_regmap; struct mii_bus *pcs_bus; + memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg)); + memset(&mrc, 0, sizeof(mrc)); + + pcs_regmap_cfg.reg_bits = 16; + pcs_regmap_cfg.val_bits = 16; + pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(1); + pcs_regmap = devm_regmap_init_mmio(&pdev->dev, dwmac->tse_pcs_base, &pcs_regmap_cfg); if (IS_ERR(pcs_regmap)) { @@ -470,6 +472,7 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) mrc.regmap = pcs_regmap; mrc.parent = &pdev->dev; mrc.valid_addr = 0x0; + mrc.autoscan = false; snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name); pcs_bus = devm_mdio_regmap_register(&pdev->dev, &mrc); -- cgit v1.2.3 From 962825e534a998025bc23a187c457ec7f9fac764 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 6 Jun 2023 00:12:05 -0700 Subject: RDMA/mlx5: Free second uplink ib port The cited patch introduce ib port for the slave device uplink in case of multiport eswitch. However, this ib port didn't perform anything when unloaded. Unload the new ib port properly. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/ib_rep.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/ib_rep.c b/drivers/infiniband/hw/mlx5/ib_rep.c index ddcfc116b19a..a4db22fe1883 100644 --- a/drivers/infiniband/hw/mlx5/ib_rep.c +++ b/drivers/infiniband/hw/mlx5/ib_rep.c @@ -126,7 +126,7 @@ mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep) !mlx5_lag_is_master(mdev)) { struct mlx5_core_dev *peer_mdev; - if (rep->vport == MLX5_VPORT_UPLINK) + if (rep->vport == MLX5_VPORT_UPLINK && !mlx5_lag_is_mpesw(mdev)) return; peer_mdev = mlx5_lag_get_peer_mdev(mdev); vport_index += mlx5_eswitch_get_total_vports(peer_mdev); @@ -146,6 +146,9 @@ mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep) struct mlx5_core_dev *peer_mdev; struct mlx5_eswitch *esw; + if (mlx5_lag_is_shared_fdb(mdev) && !mlx5_lag_is_master(mdev)) + return; + if (mlx5_lag_is_shared_fdb(mdev)) { peer_mdev = mlx5_lag_get_peer_mdev(mdev); esw = peer_mdev->priv.eswitch; -- cgit v1.2.3 From 222dd185833e464faad2d175c14bca584b6b6dad Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 6 Jun 2023 00:12:06 -0700 Subject: {net/RDMA}/mlx5: introduce lag_for_each_peer Introduce a generic APIs to iterate over all the devices which are part of the LAG. This API replace mlx5_lag_get_peer_mdev() which retrieve only a single peer device from the lag. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/infiniband/hw/mlx5/ib_rep.c | 98 ++++++++++++++--------- drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 24 +++--- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 21 +++-- include/linux/mlx5/driver.h | 8 +- 4 files changed, 100 insertions(+), 51 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/ib_rep.c b/drivers/infiniband/hw/mlx5/ib_rep.c index a4db22fe1883..c7a4ee896121 100644 --- a/drivers/infiniband/hw/mlx5/ib_rep.c +++ b/drivers/infiniband/hw/mlx5/ib_rep.c @@ -30,45 +30,65 @@ mlx5_ib_set_vport_rep(struct mlx5_core_dev *dev, static void mlx5_ib_register_peer_vport_reps(struct mlx5_core_dev *mdev); +static void mlx5_ib_num_ports_update(struct mlx5_core_dev *dev, u32 *num_ports) +{ + struct mlx5_core_dev *peer_dev; + int i; + + mlx5_lag_for_each_peer_mdev(dev, peer_dev, i) { + u32 peer_num_ports = mlx5_eswitch_get_total_vports(peer_dev); + + if (mlx5_lag_is_mpesw(peer_dev)) + *num_ports += peer_num_ports; + else + /* Only 1 ib port is the representor for all uplinks */ + *num_ports += peer_num_ports - 1; + } +} + static int mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) { u32 num_ports = mlx5_eswitch_get_total_vports(dev); + struct mlx5_core_dev *lag_master = dev; const struct mlx5_ib_profile *profile; struct mlx5_core_dev *peer_dev; struct mlx5_ib_dev *ibdev; - int second_uplink = false; - u32 peer_num_ports; + int new_uplink = false; int vport_index; int ret; + int i; vport_index = rep->vport_index; if (mlx5_lag_is_shared_fdb(dev)) { - peer_dev = mlx5_lag_get_peer_mdev(dev); - peer_num_ports = mlx5_eswitch_get_total_vports(peer_dev); if (mlx5_lag_is_master(dev)) { - if (mlx5_lag_is_mpesw(dev)) - num_ports += peer_num_ports; - else - num_ports += peer_num_ports - 1; - + mlx5_ib_num_ports_update(dev, &num_ports); } else { if (rep->vport == MLX5_VPORT_UPLINK) { if (!mlx5_lag_is_mpesw(dev)) return 0; - second_uplink = true; + new_uplink = true; } + mlx5_lag_for_each_peer_mdev(dev, peer_dev, i) { + u32 peer_n_ports = mlx5_eswitch_get_total_vports(peer_dev); + + if (mlx5_lag_is_master(peer_dev)) + lag_master = peer_dev; + else if (!mlx5_lag_is_mpesw(dev)) + /* Only 1 ib port is the representor for all uplinks */ + peer_n_ports--; - vport_index += peer_num_ports; - dev = peer_dev; + if (mlx5_get_dev_index(peer_dev) < mlx5_get_dev_index(dev)) + vport_index += peer_n_ports; + } } } - if (rep->vport == MLX5_VPORT_UPLINK && !second_uplink) + if (rep->vport == MLX5_VPORT_UPLINK && !new_uplink) profile = &raw_eth_profile; else - return mlx5_ib_set_vport_rep(dev, rep, vport_index); + return mlx5_ib_set_vport_rep(lag_master, rep, vport_index); ibdev = ib_alloc_device(mlx5_ib_dev, ib_dev); if (!ibdev) @@ -85,8 +105,8 @@ mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) vport_index = rep->vport_index; ibdev->port[vport_index].rep = rep; ibdev->port[vport_index].roce.netdev = - mlx5_ib_get_rep_netdev(dev->priv.eswitch, rep->vport); - ibdev->mdev = dev; + mlx5_ib_get_rep_netdev(lag_master->priv.eswitch, rep->vport); + ibdev->mdev = lag_master; ibdev->num_ports = num_ports; ret = __mlx5_ib_add(ibdev, profile); @@ -94,8 +114,8 @@ mlx5_ib_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) goto fail_add; rep->rep_data[REP_IB].priv = ibdev; - if (mlx5_lag_is_shared_fdb(dev)) - mlx5_ib_register_peer_vport_reps(dev); + if (mlx5_lag_is_shared_fdb(lag_master)) + mlx5_ib_register_peer_vport_reps(lag_master); return 0; @@ -118,23 +138,27 @@ mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep) struct mlx5_ib_dev *dev = mlx5_ib_rep_to_dev(rep); int vport_index = rep->vport_index; struct mlx5_ib_port *port; + int i; if (WARN_ON(!mdev)) return; + if (!dev) + return; + if (mlx5_lag_is_shared_fdb(mdev) && !mlx5_lag_is_master(mdev)) { - struct mlx5_core_dev *peer_mdev; - if (rep->vport == MLX5_VPORT_UPLINK && !mlx5_lag_is_mpesw(mdev)) return; - peer_mdev = mlx5_lag_get_peer_mdev(mdev); - vport_index += mlx5_eswitch_get_total_vports(peer_mdev); + for (i = 0; i < dev->num_ports; i++) { + if (dev->port[i].rep == rep) + break; + } + if (WARN_ON(i == dev->num_ports)) + return; + vport_index = i; } - if (!dev) - return; - port = &dev->port[vport_index]; write_lock(&port->roce.netdev_lock); port->roce.netdev = NULL; @@ -143,16 +167,18 @@ mlx5_ib_vport_rep_unload(struct mlx5_eswitch_rep *rep) port->rep = NULL; if (rep->vport == MLX5_VPORT_UPLINK) { - struct mlx5_core_dev *peer_mdev; - struct mlx5_eswitch *esw; if (mlx5_lag_is_shared_fdb(mdev) && !mlx5_lag_is_master(mdev)) return; if (mlx5_lag_is_shared_fdb(mdev)) { - peer_mdev = mlx5_lag_get_peer_mdev(mdev); - esw = peer_mdev->priv.eswitch; - mlx5_eswitch_unregister_vport_reps(esw, REP_IB); + struct mlx5_core_dev *peer_mdev; + struct mlx5_eswitch *esw; + + mlx5_lag_for_each_peer_mdev(mdev, peer_mdev, i) { + esw = peer_mdev->priv.eswitch; + mlx5_eswitch_unregister_vport_reps(esw, REP_IB); + } } __mlx5_ib_remove(dev, dev->profile, MLX5_IB_STAGE_MAX); } @@ -166,14 +192,14 @@ static const struct mlx5_eswitch_rep_ops rep_ops = { static void mlx5_ib_register_peer_vport_reps(struct mlx5_core_dev *mdev) { - struct mlx5_core_dev *peer_mdev = mlx5_lag_get_peer_mdev(mdev); + struct mlx5_core_dev *peer_mdev; struct mlx5_eswitch *esw; + int i; - if (!peer_mdev) - return; - - esw = peer_mdev->priv.eswitch; - mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB); + mlx5_lag_for_each_peer_mdev(mdev, peer_mdev, i) { + esw = peer_mdev->priv.eswitch; + mlx5_eswitch_register_vport_reps(esw, &rep_ops, REP_IB); + } } struct net_device *mlx5_ib_get_rep_netdev(struct mlx5_eswitch *esw, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 11374c3744c5..8a10ed4d8cbb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -244,16 +244,22 @@ static int mlx5_cmd_update_root_ft(struct mlx5_flow_root_namespace *ns, ft->type == FS_FT_FDB && mlx5_lag_is_shared_fdb(dev) && mlx5_lag_is_master(dev)) { - err = mlx5_cmd_set_slave_root_fdb(dev, - mlx5_lag_get_peer_mdev(dev), - !disconnect, (!disconnect) ? - ft->id : 0); - if (err && !disconnect) { - MLX5_SET(set_flow_table_root_in, in, op_mod, 0); - MLX5_SET(set_flow_table_root_in, in, table_id, - ns->root_ft->id); - mlx5_cmd_exec_in(dev, set_flow_table_root, in); + struct mlx5_core_dev *peer_dev; + int i; + + mlx5_lag_for_each_peer_mdev(dev, peer_dev, i) { + err = mlx5_cmd_set_slave_root_fdb(dev, peer_dev, !disconnect, + (!disconnect) ? ft->id : 0); + if (err && !disconnect) { + MLX5_SET(set_flow_table_root_in, in, op_mod, 0); + MLX5_SET(set_flow_table_root_in, in, table_id, + ns->root_ft->id); + mlx5_cmd_exec_in(dev, set_flow_table_root, in); + } + if (err) + break; } + } return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index c820f7d266de..c55e36e0571d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -1519,26 +1519,37 @@ u8 mlx5_lag_get_num_ports(struct mlx5_core_dev *dev) } EXPORT_SYMBOL(mlx5_lag_get_num_ports); -struct mlx5_core_dev *mlx5_lag_get_peer_mdev(struct mlx5_core_dev *dev) +struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int *i) { struct mlx5_core_dev *peer_dev = NULL; struct mlx5_lag *ldev; unsigned long flags; + int idx; spin_lock_irqsave(&lag_lock, flags); ldev = mlx5_lag_dev(dev); if (!ldev) goto unlock; - peer_dev = ldev->pf[MLX5_LAG_P1].dev == dev ? - ldev->pf[MLX5_LAG_P2].dev : - ldev->pf[MLX5_LAG_P1].dev; + if (*i == ldev->ports) + goto unlock; + for (idx = *i; idx < ldev->ports; idx++) + if (ldev->pf[idx].dev != dev) + break; + + if (idx == ldev->ports) { + *i = idx; + goto unlock; + } + *i = idx + 1; + + peer_dev = ldev->pf[idx].dev; unlock: spin_unlock_irqrestore(&lag_lock, flags); return peer_dev; } -EXPORT_SYMBOL(mlx5_lag_get_peer_mdev); +EXPORT_SYMBOL(mlx5_lag_get_next_peer_mdev); int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev, u64 *values, diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 94d2be5848ae..9a744c48eec2 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -1174,7 +1174,13 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev, u64 *values, int num_counters, size_t *offsets); -struct mlx5_core_dev *mlx5_lag_get_peer_mdev(struct mlx5_core_dev *dev); +struct mlx5_core_dev *mlx5_lag_get_next_peer_mdev(struct mlx5_core_dev *dev, int *i); + +#define mlx5_lag_for_each_peer_mdev(dev, peer, i) \ + for (i = 0, peer = mlx5_lag_get_next_peer_mdev(dev, &i); \ + peer; \ + peer = mlx5_lag_get_next_peer_mdev(dev, &i)) + u8 mlx5_lag_get_num_ports(struct mlx5_core_dev *dev); struct mlx5_uars_page *mlx5_get_uars_page(struct mlx5_core_dev *mdev); void mlx5_put_uars_page(struct mlx5_core_dev *mdev, struct mlx5_uars_page *up); -- cgit v1.2.3 From 4c103aea4bedfb109e91bed2023178059947fc4c Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 6 Jun 2023 00:12:07 -0700 Subject: net/mlx5: LAG, check if all eswitches are paired for shared FDB Shared FDB LAG can only work if all eswitches are paired. Also, whenever two eswitches are paired, devcom is marked as ready. Therefore, in case of device with two eswitches, checking devcom was sufficient. However, this is not correct for device with more than two eswitches, which will be introduced in downstream patch. Hence, check all eswitches are paired explicitly. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 9 +++++++++ drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index c42c16d9ccbc..d3608f198e0a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -779,6 +779,13 @@ static inline int mlx5_eswitch_num_vfs(struct mlx5_eswitch *esw) return 0; } +static inline int mlx5_eswitch_get_npeers(struct mlx5_eswitch *esw) +{ + if (mlx5_esw_allowed(esw)) + return esw->num_peers; + return 0; +} + static inline struct mlx5_flow_table * mlx5_eswitch_get_slow_fdb(struct mlx5_eswitch *esw) { @@ -826,6 +833,8 @@ static inline void mlx5_eswitch_offloads_single_fdb_del_one(struct mlx5_eswitch *master_esw, struct mlx5_eswitch *slave_esw) {} +static inline int mlx5_eswitch_get_npeers(struct mlx5_eswitch *esw) { return 0; } + static inline int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index c55e36e0571d..dd8a19d85617 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -828,7 +828,9 @@ bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev) MLX5_DEVCOM_ESW_OFFLOADS) && MLX5_CAP_GEN(dev1, lag_native_fdb_selection) && MLX5_CAP_ESW(dev1, root_ft_on_other_esw) && - MLX5_CAP_ESW(dev0, esw_shared_ingress_acl)) + MLX5_CAP_ESW(dev0, esw_shared_ingress_acl) && + mlx5_eswitch_get_npeers(dev0->priv.eswitch) == MLX5_CAP_GEN(dev0, num_lag_ports) - 1 && + mlx5_eswitch_get_npeers(dev1->priv.eswitch) == MLX5_CAP_GEN(dev1, num_lag_ports) - 1) return true; return false; -- cgit v1.2.3 From 86a12124dc0249d60bb5f01497b3a86e99efae6d Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 6 Jun 2023 00:12:08 -0700 Subject: net/mlx5: LAG, generalize handling of shared FDB Shared FDB handling is using the assumption that shared FDB can only be created from two devices. In order to support shared FDB of more than two devices, iterate over all LAG ports instead of hard coding only the first two LAG ports whenever handling shared FDB. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 66 +++++++++++++---------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index dd8a19d85617..00773aab9d20 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -512,8 +512,11 @@ static void mlx5_lag_set_port_sel_mode_offloads(struct mlx5_lag *ldev, return; if (MLX5_CAP_PORT_SELECTION(dev0->dev, port_select_flow_table) && - tracker->tx_type == NETDEV_LAG_TX_TYPE_HASH) + tracker->tx_type == NETDEV_LAG_TX_TYPE_HASH) { + if (ldev->ports > 2) + ldev->buckets = MLX5_LAG_MAX_HASH_BUCKETS; set_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, flags); + } } static int mlx5_lag_set_flags(struct mlx5_lag *ldev, enum mlx5_lag_mode mode, @@ -782,7 +785,6 @@ void mlx5_disable_lag(struct mlx5_lag *ldev) { bool shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags); struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; - struct mlx5_core_dev *dev1 = ldev->pf[MLX5_LAG_P2].dev; bool roce_lag; int err; int i; @@ -807,30 +809,35 @@ void mlx5_disable_lag(struct mlx5_lag *ldev) if (shared_fdb || roce_lag) mlx5_lag_add_devices(ldev); - if (shared_fdb) { - if (!(dev0->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)) - mlx5_eswitch_reload_reps(dev0->priv.eswitch); - if (!(dev1->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)) - mlx5_eswitch_reload_reps(dev1->priv.eswitch); - } + if (shared_fdb) + for (i = 0; i < ldev->ports; i++) + if (!(ldev->pf[i].dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV)) + mlx5_eswitch_reload_reps(ldev->pf[i].dev->priv.eswitch); } bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev) { - struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; - struct mlx5_core_dev *dev1 = ldev->pf[MLX5_LAG_P2].dev; - - if (is_mdev_switchdev_mode(dev0) && - is_mdev_switchdev_mode(dev1) && - mlx5_eswitch_vport_match_metadata_enabled(dev0->priv.eswitch) && - mlx5_eswitch_vport_match_metadata_enabled(dev1->priv.eswitch) && - mlx5_devcom_comp_is_ready(dev0->priv.devcom, - MLX5_DEVCOM_ESW_OFFLOADS) && - MLX5_CAP_GEN(dev1, lag_native_fdb_selection) && - MLX5_CAP_ESW(dev1, root_ft_on_other_esw) && - MLX5_CAP_ESW(dev0, esw_shared_ingress_acl) && - mlx5_eswitch_get_npeers(dev0->priv.eswitch) == MLX5_CAP_GEN(dev0, num_lag_ports) - 1 && - mlx5_eswitch_get_npeers(dev1->priv.eswitch) == MLX5_CAP_GEN(dev1, num_lag_ports) - 1) + struct mlx5_core_dev *dev; + int i; + + for (i = MLX5_LAG_P1 + 1; i < ldev->ports; i++) { + dev = ldev->pf[i].dev; + if (is_mdev_switchdev_mode(dev) && + mlx5_eswitch_vport_match_metadata_enabled(dev->priv.eswitch) && + MLX5_CAP_GEN(dev, lag_native_fdb_selection) && + MLX5_CAP_ESW(dev, root_ft_on_other_esw) && + mlx5_eswitch_get_npeers(dev->priv.eswitch) == + MLX5_CAP_GEN(dev, num_lag_ports) - 1) + continue; + return false; + } + + dev = ldev->pf[MLX5_LAG_P1].dev; + if (is_mdev_switchdev_mode(dev) && + mlx5_eswitch_vport_match_metadata_enabled(dev->priv.eswitch) && + mlx5_devcom_comp_is_ready(dev->priv.devcom, MLX5_DEVCOM_ESW_OFFLOADS) && + MLX5_CAP_ESW(dev, esw_shared_ingress_acl) && + mlx5_eswitch_get_npeers(dev->priv.eswitch) == MLX5_CAP_GEN(dev, num_lag_ports) - 1) return true; return false; @@ -867,7 +874,6 @@ static bool mlx5_lag_should_disable_lag(struct mlx5_lag *ldev, bool do_bond) static void mlx5_do_bond(struct mlx5_lag *ldev) { struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; - struct mlx5_core_dev *dev1 = ldev->pf[MLX5_LAG_P2].dev; struct lag_tracker tracker = { }; bool do_bond, roce_lag; int err; @@ -908,20 +914,24 @@ static void mlx5_do_bond(struct mlx5_lag *ldev) for (i = 1; i < ldev->ports; i++) mlx5_nic_vport_enable_roce(ldev->pf[i].dev); } else if (shared_fdb) { + int i; + dev0->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; mlx5_rescan_drivers_locked(dev0); - err = mlx5_eswitch_reload_reps(dev0->priv.eswitch); - if (!err) - err = mlx5_eswitch_reload_reps(dev1->priv.eswitch); + for (i = 0; i < ldev->ports; i++) { + err = mlx5_eswitch_reload_reps(ldev->pf[i].dev->priv.eswitch); + if (err) + break; + } if (err) { dev0->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV; mlx5_rescan_drivers_locked(dev0); mlx5_deactivate_lag(ldev); mlx5_lag_add_devices(ldev); - mlx5_eswitch_reload_reps(dev0->priv.eswitch); - mlx5_eswitch_reload_reps(dev1->priv.eswitch); + for (i = 0; i < ldev->ports; i++) + mlx5_eswitch_reload_reps(ldev->pf[i].dev->priv.eswitch); mlx5_core_err(dev0, "Failed to enable lag\n"); return; } -- cgit v1.2.3 From c83e6ab96ef20bcdb5bfb12f42bd2e6734920bfd Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 6 Jun 2023 00:12:09 -0700 Subject: net/mlx5: LAG, change mlx5_shared_fdb_supported() to static mlx5_shared_fdb_supported() is used only in a single file. Change the function to be static. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index 00773aab9d20..6ce71c42c755 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -815,7 +815,7 @@ void mlx5_disable_lag(struct mlx5_lag *ldev) mlx5_eswitch_reload_reps(ldev->pf[i].dev->priv.eswitch); } -bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev) +static bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev) { struct mlx5_core_dev *dev; int i; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h index bc1f1dd3e283..d7e7fa2348a5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h @@ -111,7 +111,6 @@ int mlx5_activate_lag(struct mlx5_lag *ldev, bool shared_fdb); int mlx5_lag_dev_get_netdev_idx(struct mlx5_lag *ldev, struct net_device *ndev); -bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev); char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags); void mlx5_infer_tx_enabled(struct lag_tracker *tracker, u8 num_ports, -- cgit v1.2.3 From d61bab396115dafc9ad572afa57d464e2e00b396 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 6 Jun 2023 00:12:10 -0700 Subject: net/mlx5: LAG, block multipath LAG in case ldev have more than 2 ports multipath LAG is not supported over more than two ports. Add a check in order to block multipath LAG over such configurations. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c index d85a8dfc153d..976caa8e6922 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c @@ -14,6 +14,7 @@ static bool __mlx5_lag_is_multipath(struct mlx5_lag *ldev) return ldev->mode == MLX5_LAG_MODE_MULTIPATH; } +#define MLX5_LAG_MULTIPATH_OFFLOADS_SUPPORTED_PORTS 2 static bool mlx5_lag_multipath_check_prereq(struct mlx5_lag *ldev) { if (!mlx5_lag_is_ready(ldev)) @@ -22,6 +23,9 @@ static bool mlx5_lag_multipath_check_prereq(struct mlx5_lag *ldev) if (__mlx5_lag_is_active(ldev) && !__mlx5_lag_is_multipath(ldev)) return false; + if (ldev->ports > MLX5_LAG_MULTIPATH_OFFLOADS_SUPPORTED_PORTS) + return false; + return mlx5_esw_multipath_prereq(ldev->pf[MLX5_LAG_P1].dev, ldev->pf[MLX5_LAG_P2].dev); } -- cgit v1.2.3 From 7718c1c8ac325019a3d727e994faab9cf2438263 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 6 Jun 2023 00:12:11 -0700 Subject: net/mlx5: LAG, block multiport eswitch LAG in case ldev have more than 2 ports multiport eswitch LAG is not supported over more than two ports. Add a check in order to block multiport eswitch LAG over such devices. Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c index 0c0ef600f643..0e869a76dfe4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c @@ -65,6 +65,7 @@ err_metadata: return err; } +#define MLX5_LAG_MPESW_OFFLOADS_SUPPORTED_PORTS 2 static int enable_mpesw(struct mlx5_lag *ldev) { struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; @@ -74,6 +75,9 @@ static int enable_mpesw(struct mlx5_lag *ldev) if (ldev->mode != MLX5_LAG_MODE_NONE) return -EINVAL; + if (ldev->ports > MLX5_LAG_MPESW_OFFLOADS_SUPPORTED_PORTS) + return -EOPNOTSUPP; + if (mlx5_eswitch_mode(dev0) != MLX5_ESWITCH_OFFLOADS || !MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table) || !MLX5_CAP_GEN(dev0, create_lag_when_not_master_up) || -- cgit v1.2.3 From 6ec0b55e72a5c6fb056ad1eea12a3b5a74a402fe Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Tue, 6 Jun 2023 00:12:12 -0700 Subject: net/mlx5: Enable 4 ports VF LAG Now, after all preparation are done, enable 4 ports VF LAG Signed-off-by: Shay Drory Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c | 5 +++-- drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index 6ce71c42c755..ffd7e17b8ebe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -711,7 +711,7 @@ int mlx5_deactivate_lag(struct mlx5_lag *ldev) return 0; } -#define MLX5_LAG_OFFLOADS_SUPPORTED_PORTS 2 +#define MLX5_LAG_OFFLOADS_SUPPORTED_PORTS 4 bool mlx5_lag_check_prereq(struct mlx5_lag *ldev) { #ifdef CONFIG_MLX5_ESWITCH @@ -737,7 +737,7 @@ bool mlx5_lag_check_prereq(struct mlx5_lag *ldev) if (mlx5_eswitch_mode(ldev->pf[i].dev) != mode) return false; - if (mode == MLX5_ESWITCH_OFFLOADS && ldev->ports != MLX5_LAG_OFFLOADS_SUPPORTED_PORTS) + if (mode == MLX5_ESWITCH_OFFLOADS && ldev->ports > MLX5_LAG_OFFLOADS_SUPPORTED_PORTS) return false; #else for (i = 0; i < ldev->ports; i++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c index 8472bbb3cd58..78c94b22bdc0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c @@ -75,13 +75,14 @@ struct mlx5_devcom *mlx5_devcom_register_device(struct mlx5_core_dev *dev) if (!mlx5_core_is_pf(dev)) return NULL; - if (MLX5_CAP_GEN(dev, num_lag_ports) != MLX5_DEVCOM_PORTS_SUPPORTED) + if (MLX5_CAP_GEN(dev, num_lag_ports) > MLX5_DEVCOM_PORTS_SUPPORTED) return NULL; mlx5_dev_list_lock(); sguid0 = mlx5_query_nic_system_image_guid(dev); list_for_each_entry(iter, &devcom_list, list) { - struct mlx5_core_dev *tmp_dev = NULL; + /* There is at least one device in iter */ + struct mlx5_core_dev *tmp_dev; idx = -1; for (i = 0; i < MLX5_DEVCOM_PORTS_SUPPORTED; i++) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h index bb1970ba8730..d953a01b8eaa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h @@ -6,7 +6,7 @@ #include -#define MLX5_DEVCOM_PORTS_SUPPORTED 2 +#define MLX5_DEVCOM_PORTS_SUPPORTED 4 enum mlx5_devcom_components { MLX5_DEVCOM_ESW_OFFLOADS, -- cgit v1.2.3 From a33682e4e78e249155abbe5e8ee880d5760b5e28 Mon Sep 17 00:00:00 2001 From: Lama Kayal Date: Tue, 6 Jun 2023 00:12:14 -0700 Subject: net/mlx5e: Expose catastrophic steering error counters Add generated_pkt_steering_fail and handled_pkt_steering_fail to devlink heatlth reporter. generated_pkt_steering_fail indicates the number of packets dropped due to illegal steering operation within the vport steering domain. handled_pkt_steering_fail indicates the number of packets dropped due to illegal steering operation, originated by the vport. Also, update devlink reporter functionality documentation with the newly exposed counters. Signed-off-by: Lama Kayal Reviewed-by: Rahul Rameshbabu Signed-off-by: Saeed Mahameed --- .../device_drivers/ethernet/mellanox/mlx5/devlink.rst | 7 +++++++ drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c | 10 ++++++++++ include/linux/mlx5/mlx5_ifc.h | 12 ++++++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst index 3354ca3608ee..a4edf908b707 100644 --- a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst +++ b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst @@ -290,6 +290,13 @@ Description of the vnic counters: - nic_receive_steering_discard number of packets that completed RX flow steering but were discarded due to a mismatch in flow table. +- generated_pkt_steering_fail + number of packets generated by the VNIC experiencing unexpected steering + failure (at any point in steering flow). +- handled_pkt_steering_fail + number of packets handled by the VNIC experiencing unexpected steering + failure (at any point in steering flow owned by the VNIC, including the FDB + for the eswitch owner). User commands examples: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c index 9114661cd967..b0128336ff01 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/reporter_vnic.c @@ -76,6 +76,16 @@ int mlx5_reporter_vnic_diagnose_counters(struct mlx5_core_dev *dev, if (err) return err; + err = devlink_fmsg_u64_pair_put(fmsg, "generated_pkt_steering_fail", + VNIC_ENV_GET64(&vnic, generated_pkt_steering_fail)); + if (err) + return err; + + err = devlink_fmsg_u64_pair_put(fmsg, "handled_pkt_steering_fail", + VNIC_ENV_GET64(&vnic, handled_pkt_steering_fail)); + if (err) + return err; + err = devlink_fmsg_obj_nest_end(fmsg); if (err) return err; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index b89778d0d326..af3a92ad2e6b 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1755,7 +1755,9 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 reserved_at_328[0x2]; u8 relaxed_ordering_read[0x1]; u8 log_max_pd[0x5]; - u8 reserved_at_330[0x9]; + u8 reserved_at_330[0x7]; + u8 vnic_env_cnt_steering_fail[0x1]; + u8 reserved_at_338[0x1]; u8 q_counter_aggregation[0x1]; u8 q_counter_other_vport[0x1]; u8 log_max_xrcd[0x5]; @@ -3673,7 +3675,13 @@ struct mlx5_ifc_vnic_diagnostic_statistics_bits { u8 eth_wqe_too_small[0x20]; - u8 reserved_at_220[0xdc0]; + u8 reserved_at_220[0xc0]; + + u8 generated_pkt_steering_fail[0x40]; + + u8 handled_pkt_steering_fail[0x40]; + + u8 reserved_at_360[0xc80]; }; struct mlx5_ifc_traffic_counter_bits { -- cgit v1.2.3 From f4692ab13a1f7ad2c2098b838c2820c113ce8a07 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Tue, 6 Jun 2023 00:12:15 -0700 Subject: net/mlx5e: Remove RX page cache leftovers Remove unused definitions left after the removal of the RX page cache feature. Signed-off-by: Tariq Toukan Reviewed-by: Dragos Tatulea Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 8e999f238194..ceabe57c511a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -594,13 +594,6 @@ struct mlx5e_mpw_info { #define MLX5E_MAX_RX_FRAGS 4 -/* a single cache unit is capable to serve one napi call (for non-striding rq) - * or a MPWQE (for striding rq). - */ -#define MLX5E_CACHE_UNIT (MLX5_MPWRQ_MAX_PAGES_PER_WQE > NAPI_POLL_WEIGHT ? \ - MLX5_MPWRQ_MAX_PAGES_PER_WQE : NAPI_POLL_WEIGHT) -#define MLX5E_CACHE_SIZE (4 * roundup_pow_of_two(MLX5E_CACHE_UNIT)) - struct mlx5e_rq; typedef void (*mlx5e_fp_handle_rx_cqe)(struct mlx5e_rq*, struct mlx5_cqe64*); typedef struct sk_buff * -- cgit v1.2.3 From de1f0a650824ed1905d5d48190f65f309cee5163 Mon Sep 17 00:00:00 2001 From: Oz Shlomo Date: Tue, 6 Jun 2023 00:12:16 -0700 Subject: net/mlx5e: TC, refactor access to hash key Currently, a temp object is filled and used as a key for rhashtable_lookup. Lookups will only works while key remains the first attribute in the relevant rhashtable node object. Fix this by passing a key, instead of a object containing the key. Signed-off-by: Oz Shlomo Reviewed-by: Paul Blakey Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c index 07c1895a2b23..7aa926e542d3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act_stats.c @@ -25,8 +25,8 @@ struct mlx5e_tc_act_stats { static const struct rhashtable_params act_counters_ht_params = { .head_offset = offsetof(struct mlx5e_tc_act_stats, hash), - .key_offset = 0, - .key_len = offsetof(struct mlx5e_tc_act_stats, counter), + .key_offset = offsetof(struct mlx5e_tc_act_stats, tc_act_cookie), + .key_len = sizeof_field(struct mlx5e_tc_act_stats, tc_act_cookie), .automatic_shrinking = true, }; @@ -169,14 +169,11 @@ mlx5e_tc_act_stats_fill_stats(struct mlx5e_tc_act_stats_handle *handle, { struct rhashtable *ht = &handle->ht; struct mlx5e_tc_act_stats *item; - struct mlx5e_tc_act_stats key; u64 pkts, bytes, lastused; int err = 0; - key.tc_act_cookie = fl_act->cookie; - rcu_read_lock(); - item = rhashtable_lookup(ht, &key, act_counters_ht_params); + item = rhashtable_lookup(ht, &fl_act->cookie, act_counters_ht_params); if (!item) { rcu_read_unlock(); err = -ENOENT; -- cgit v1.2.3 From 97bd788efb9052963b43ba41c8aaff3ed12e1ede Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 6 Jun 2023 00:12:17 -0700 Subject: net/mlx5: Skip inline mode check after mlx5_eswitch_enable_locked() failure Commit bffaa916588e ("net/mlx5: E-Switch, Add control for inline mode") added inline mode checking to esw_offloads_start() with a warning printed out in case there is a problem. Tne inline mode checking was done even after mlx5_eswitch_enable_locked() call failed, which is pointless. Later on, commit 8c98ee77d911 ("net/mlx5e: E-Switch, Add extack messages to devlink callbacks") converted the error/warning prints to extack setting, which caused that the inline mode check error to overwrite possible previous extack message when mlx5_eswitch_enable_locked() failed. User then gets confusing error message. Fix this by skipping check of inline mode after mlx5_eswitch_enable_locked() call failed. Signed-off-by: Jiri Pirko Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 29de4e759f4f..eafb098db6b0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2178,6 +2178,7 @@ static int esw_offloads_start(struct mlx5_eswitch *esw, "Failed setting eswitch to offloads"); esw->mode = MLX5_ESWITCH_LEGACY; mlx5_rescan_drivers(esw->dev); + return err; } if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) { if (mlx5_eswitch_inline_mode_get(esw, @@ -2187,7 +2188,7 @@ static int esw_offloads_start(struct mlx5_eswitch *esw, "Inline mode is different between vports"); } } - return err; + return 0; } static void mlx5_esw_offloads_rep_mark_set(struct mlx5_eswitch *esw, -- cgit v1.2.3 From eb8e9fae0a22d07c6a09983ec52a2dcdc9d4d82b Mon Sep 17 00:00:00 2001 From: Bodong Wang Date: Tue, 6 Jun 2023 00:12:18 -0700 Subject: mlx5/core: E-Switch, Allocate ECPF vport if it's an eswitch manager Eswitch vport is needed for eswitch manager when creating LAG, to create egress rules. However, this was not handled when ECPF is an eswitch manager. Signed-off-by: Bodong Wang Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 31956cd9d1bb..ecd8864d5d11 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1601,7 +1601,8 @@ static int mlx5_esw_vports_init(struct mlx5_eswitch *esw) idx++; } - if (mlx5_ecpf_vport_exists(dev)) { + if (mlx5_ecpf_vport_exists(dev) || + mlx5_core_is_ecpf_esw_manager(dev)) { err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_ECPF); if (err) goto err; -- cgit v1.2.3 From 803ea346bd3ff1ac80fc65cf5899c0ad045d1788 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 6 Jun 2023 00:12:19 -0700 Subject: net/mlx5e: simplify condition after napi budget handling change Since recent commit budget can't be 0 here. Signed-off-by: Jakub Kicinski Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c index fbb2d963fb7e..a7d9b7cb4297 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c @@ -207,7 +207,7 @@ int mlx5e_napi_poll(struct napi_struct *napi, int budget) } ch_stats->aff_change++; aff_change = true; - if (budget && work_done == budget) + if (work_done == budget) work_done--; } -- cgit v1.2.3 From 4a56212774acf71a7356026fb11b78228a7ad24d Mon Sep 17 00:00:00 2001 From: Michal Smulski Date: Mon, 5 Jun 2023 10:44:42 -0700 Subject: net: dsa: mv88e6xxx: implement USXGMII mode for mv88e6393x Enable USXGMII mode for mv88e6393x chips. Tested on Marvell 88E6191X. Signed-off-by: Michal Smulski Link: https://lore.kernel.org/r/20230605174442.12493-1-msmulski2@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 3 +-- drivers/net/dsa/mv88e6xxx/port.c | 3 +++ drivers/net/dsa/mv88e6xxx/serdes.c | 47 ++++++++++++++++++++++++++++++++++++-- drivers/net/dsa/mv88e6xxx/serdes.h | 4 ++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 2af0c1145d36..8b51756bd805 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -812,11 +812,10 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port, if (!is_6361) { __set_bit(PHY_INTERFACE_MODE_5GBASER, supported); __set_bit(PHY_INTERFACE_MODE_10GBASER, supported); + __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); config->mac_capabilities |= MAC_5000FD | MAC_10000FD; } - /* FIXME: USXGMII is not supported yet */ - /* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */ } } diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index e9b4a6ea4d09..dd66ec902d4c 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -566,6 +566,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, case PHY_INTERFACE_MODE_10GBASER: cmode = MV88E6393X_PORT_STS_CMODE_10GBASER; break; + case PHY_INTERFACE_MODE_USXGMII: + cmode = MV88E6393X_PORT_STS_CMODE_USXGMII; + break; default: cmode = 0; } diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 72faec8f44dc..80167d53212f 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -683,7 +683,8 @@ int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode == MV88E6393X_PORT_STS_CMODE_5GBASER || - cmode == MV88E6393X_PORT_STS_CMODE_10GBASER) + cmode == MV88E6393X_PORT_STS_CMODE_10GBASER || + cmode == MV88E6393X_PORT_STS_CMODE_USXGMII) lane = port; return lane; @@ -984,7 +985,42 @@ static int mv88e6393x_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip, state->speed = SPEED_10000; state->duplex = DUPLEX_FULL; } + return 0; +} + +/* USXGMII registers for Marvell switch 88e639x are undocumented and this function is based + * on some educated guesses. It appears that there are no status bits related to + * autonegotiation complete or flow control. + */ +static int mv88e639x_serdes_pcs_get_state_usxgmii(struct mv88e6xxx_chip *chip, + int port, int lane, + struct phylink_link_state *state) +{ + u16 status, lp_status; + int err; + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_USXGMII_PHY_STATUS, &status); + if (err) { + dev_err(chip->dev, "can't read Serdes USXGMII PHY status: %d\n", err); + return err; + } + dev_dbg(chip->dev, "USXGMII PHY status: 0x%x\n", status); + + state->link = !!(status & MDIO_USXGMII_LINK); + state->an_complete = state->link; + + if (state->link) { + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_USXGMII_LP_STATUS, &lp_status); + if (err) { + dev_err(chip->dev, "can't read Serdes USXGMII LP status: %d\n", err); + return err; + } + dev_dbg(chip->dev, "USXGMII LP status: 0x%x\n", lp_status); + /* lp_status appears to include the "link" bit as per USXGMII spec. */ + phylink_decode_usxgmii_word(state, lp_status); + } return 0; } @@ -1020,6 +1056,9 @@ int mv88e6393x_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, case PHY_INTERFACE_MODE_10GBASER: return mv88e6393x_serdes_pcs_get_state_10g(chip, port, lane, state); + case PHY_INTERFACE_MODE_USXGMII: + return mv88e639x_serdes_pcs_get_state_usxgmii(chip, port, lane, + state); default: return -EOPNOTSUPP; @@ -1173,6 +1212,7 @@ int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable); case MV88E6393X_PORT_STS_CMODE_5GBASER: case MV88E6393X_PORT_STS_CMODE_10GBASER: + case MV88E6393X_PORT_STS_CMODE_USXGMII: return mv88e6393x_serdes_irq_enable_10g(chip, lane, enable); } @@ -1213,6 +1253,7 @@ irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, break; case MV88E6393X_PORT_STS_CMODE_5GBASER: case MV88E6393X_PORT_STS_CMODE_10GBASER: + case MV88E6393X_PORT_STS_CMODE_USXGMII: err = mv88e6393x_serdes_irq_status_10g(chip, lane, &status); if (err) return err; @@ -1477,7 +1518,8 @@ static int mv88e6393x_serdes_erratum_5_2(struct mv88e6xxx_chip *chip, int lane, * to SERDES operating in 10G mode. These registers only apply to 10G * operation and have no effect on other speeds. */ - if (cmode != MV88E6393X_PORT_STS_CMODE_10GBASER) + if (cmode != MV88E6393X_PORT_STS_CMODE_10GBASER && + cmode != MV88E6393X_PORT_STS_CMODE_USXGMII) return 0; for (i = 0; i < ARRAY_SIZE(fixes); ++i) { @@ -1582,6 +1624,7 @@ int mv88e6393x_serdes_power(struct mv88e6xxx_chip *chip, int port, int lane, break; case MV88E6393X_PORT_STS_CMODE_5GBASER: case MV88E6393X_PORT_STS_CMODE_10GBASER: + case MV88E6393X_PORT_STS_CMODE_USXGMII: err = mv88e6390_serdes_power_10g(chip, lane, on); break; default: diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 29bb4e91e2f6..e245687ddb1d 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -48,6 +48,10 @@ #define MV88E6393X_10G_INT_LINK_CHANGE BIT(2) #define MV88E6393X_10G_INT_STATUS 0x9001 +/* USXGMII */ +#define MV88E6390_USXGMII_LP_STATUS 0xf0a2 +#define MV88E6390_USXGMII_PHY_STATUS 0xf0a6 + /* 1000BASE-X and SGMII */ #define MV88E6390_SGMII_BMCR (0x2000 + MII_BMCR) #define MV88E6390_SGMII_BMSR (0x2000 + MII_BMSR) -- cgit v1.2.3 From c3e382ad6d15a8041ab8a168ad3ff90137ee8a45 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 6 Jun 2023 17:21:00 +0800 Subject: net: txgbe: Add software nodes to support phylink Register software nodes for GPIO, I2C, SFP and PHYLINK. Define the device properties. Signed-off-by: Jiawen Wu Reviewed-by: Andrew Lunn Reviewed-by: Piotr Raczynski Reviewed-by: Maciej Fijalkowski Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 + drivers/net/ethernet/wangxun/txgbe/Makefile | 1 + drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 22 +++++- drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 89 +++++++++++++++++++++++++ drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h | 10 +++ drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 49 ++++++++++++++ 6 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 5063846e1b52..c61c18a842c4 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -814,6 +814,7 @@ enum wx_isb_idx { struct wx { unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; + void *priv; u8 __iomem *hw_addr; struct pci_dev *pdev; struct net_device *netdev; diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile index 6db14a2cb2d0..7507f762edfe 100644 --- a/drivers/net/ethernet/wangxun/txgbe/Makefile +++ b/drivers/net/ethernet/wangxun/txgbe/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_TXGBE) += txgbe.o txgbe-objs := txgbe_main.o \ txgbe_hw.o \ + txgbe_phy.o \ txgbe_ethtool.o diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index cfe47f3d2503..920ee3a3bfa3 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -15,6 +15,7 @@ #include "../libwx/wx_hw.h" #include "txgbe_type.h" #include "txgbe_hw.h" +#include "txgbe_phy.h" #include "txgbe_ethtool.h" char txgbe_driver_name[] = "txgbe"; @@ -516,6 +517,7 @@ static int txgbe_probe(struct pci_dev *pdev, struct net_device *netdev; int err, expected_gts; struct wx *wx = NULL; + struct txgbe *txgbe; u16 eeprom_verh = 0, eeprom_verl = 0, offset = 0; u16 eeprom_cfg_blkh = 0, eeprom_cfg_blkl = 0; @@ -680,10 +682,23 @@ static int txgbe_probe(struct pci_dev *pdev, "0x%08x", etrack_id); } - err = register_netdev(netdev); + txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL); + if (!txgbe) { + err = -ENOMEM; + goto err_release_hw; + } + + txgbe->wx = wx; + wx->priv = txgbe; + + err = txgbe_init_phy(txgbe); if (err) goto err_release_hw; + err = register_netdev(netdev); + if (err) + goto err_remove_phy; + pci_set_drvdata(pdev, wx); netif_tx_stop_all_queues(netdev); @@ -711,6 +726,8 @@ static int txgbe_probe(struct pci_dev *pdev, return 0; +err_remove_phy: + txgbe_remove_phy(txgbe); err_release_hw: wx_clear_interrupt_scheme(wx); wx_control_hw(wx, false); @@ -736,11 +753,14 @@ err_pci_disable_dev: static void txgbe_remove(struct pci_dev *pdev) { struct wx *wx = pci_get_drvdata(pdev); + struct txgbe *txgbe = wx->priv; struct net_device *netdev; netdev = wx->netdev; unregister_netdev(netdev); + txgbe_remove_phy(txgbe); + pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c new file mode 100644 index 000000000000..be4b5ad74a3c --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ + +#include +#include +#include + +#include "../libwx/wx_type.h" +#include "txgbe_type.h" +#include "txgbe_phy.h" + +static int txgbe_swnodes_register(struct txgbe *txgbe) +{ + struct txgbe_nodes *nodes = &txgbe->nodes; + struct pci_dev *pdev = txgbe->wx->pdev; + struct software_node *swnodes; + u32 id; + + id = (pdev->bus->number << 8) | pdev->devfn; + + snprintf(nodes->gpio_name, sizeof(nodes->gpio_name), "txgbe_gpio-%x", id); + snprintf(nodes->i2c_name, sizeof(nodes->i2c_name), "txgbe_i2c-%x", id); + snprintf(nodes->sfp_name, sizeof(nodes->sfp_name), "txgbe_sfp-%x", id); + snprintf(nodes->phylink_name, sizeof(nodes->phylink_name), "txgbe_phylink-%x", id); + + swnodes = nodes->swnodes; + + /* GPIO 0: tx fault + * GPIO 1: tx disable + * GPIO 2: sfp module absent + * GPIO 3: rx signal lost + * GPIO 4: rate select, 1G(0) 10G(1) + * GPIO 5: rate select, 1G(0) 10G(1) + */ + nodes->gpio_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names", "default"); + swnodes[SWNODE_GPIO] = NODE_PROP(nodes->gpio_name, nodes->gpio_props); + nodes->gpio0_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 0, GPIO_ACTIVE_HIGH); + nodes->gpio1_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 1, GPIO_ACTIVE_HIGH); + nodes->gpio2_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 2, GPIO_ACTIVE_LOW); + nodes->gpio3_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 3, GPIO_ACTIVE_HIGH); + nodes->gpio4_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 4, GPIO_ACTIVE_HIGH); + nodes->gpio5_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 5, GPIO_ACTIVE_HIGH); + + nodes->i2c_props[0] = PROPERTY_ENTRY_STRING("compatible", "snps,designware-i2c"); + nodes->i2c_props[1] = PROPERTY_ENTRY_BOOL("wx,i2c-snps-model"); + nodes->i2c_props[2] = PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ); + swnodes[SWNODE_I2C] = NODE_PROP(nodes->i2c_name, nodes->i2c_props); + nodes->i2c_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_I2C]); + + nodes->sfp_props[0] = PROPERTY_ENTRY_STRING("compatible", "sff,sfp"); + nodes->sfp_props[1] = PROPERTY_ENTRY_REF_ARRAY("i2c-bus", nodes->i2c_ref); + nodes->sfp_props[2] = PROPERTY_ENTRY_REF_ARRAY("tx-fault-gpios", nodes->gpio0_ref); + nodes->sfp_props[3] = PROPERTY_ENTRY_REF_ARRAY("tx-disable-gpios", nodes->gpio1_ref); + nodes->sfp_props[4] = PROPERTY_ENTRY_REF_ARRAY("mod-def0-gpios", nodes->gpio2_ref); + nodes->sfp_props[5] = PROPERTY_ENTRY_REF_ARRAY("los-gpios", nodes->gpio3_ref); + nodes->sfp_props[6] = PROPERTY_ENTRY_REF_ARRAY("rate-select1-gpios", nodes->gpio4_ref); + nodes->sfp_props[7] = PROPERTY_ENTRY_REF_ARRAY("rate-select0-gpios", nodes->gpio5_ref); + swnodes[SWNODE_SFP] = NODE_PROP(nodes->sfp_name, nodes->sfp_props); + nodes->sfp_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_SFP]); + + nodes->phylink_props[0] = PROPERTY_ENTRY_STRING("managed", "in-band-status"); + nodes->phylink_props[1] = PROPERTY_ENTRY_REF_ARRAY("sfp", nodes->sfp_ref); + swnodes[SWNODE_PHYLINK] = NODE_PROP(nodes->phylink_name, nodes->phylink_props); + + nodes->group[SWNODE_GPIO] = &swnodes[SWNODE_GPIO]; + nodes->group[SWNODE_I2C] = &swnodes[SWNODE_I2C]; + nodes->group[SWNODE_SFP] = &swnodes[SWNODE_SFP]; + nodes->group[SWNODE_PHYLINK] = &swnodes[SWNODE_PHYLINK]; + + return software_node_register_node_group(nodes->group); +} + +int txgbe_init_phy(struct txgbe *txgbe) +{ + int ret; + + ret = txgbe_swnodes_register(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to register software nodes\n"); + return ret; + } + + return 0; +} + +void txgbe_remove_phy(struct txgbe *txgbe) +{ + software_node_unregister_node_group(txgbe->nodes.group); +} diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h new file mode 100644 index 000000000000..1ab592124986 --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ + +#ifndef _TXGBE_PHY_H_ +#define _TXGBE_PHY_H_ + +int txgbe_init_phy(struct txgbe *txgbe); +void txgbe_remove_phy(struct txgbe *txgbe); + +#endif /* _TXGBE_NODE_H_ */ diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 032972369965..9aa399acd9a0 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -4,6 +4,8 @@ #ifndef _TXGBE_TYPE_H_ #define _TXGBE_TYPE_H_ +#include + /* Device IDs */ #define TXGBE_DEV_ID_SP1000 0x1001 #define TXGBE_DEV_ID_WX1820 0x2001 @@ -100,4 +102,51 @@ extern char txgbe_driver_name[]; +static inline struct txgbe *netdev_to_txgbe(struct net_device *netdev) +{ + struct wx *wx = netdev_priv(netdev); + + return wx->priv; +} + +#define NODE_PROP(_NAME, _PROP) \ + (const struct software_node) { \ + .name = _NAME, \ + .properties = _PROP, \ + } + +enum txgbe_swnodes { + SWNODE_GPIO = 0, + SWNODE_I2C, + SWNODE_SFP, + SWNODE_PHYLINK, + SWNODE_MAX +}; + +struct txgbe_nodes { + char gpio_name[32]; + char i2c_name[32]; + char sfp_name[32]; + char phylink_name[32]; + struct property_entry gpio_props[1]; + struct property_entry i2c_props[3]; + struct property_entry sfp_props[8]; + struct property_entry phylink_props[2]; + struct software_node_ref_args i2c_ref[1]; + struct software_node_ref_args gpio0_ref[1]; + struct software_node_ref_args gpio1_ref[1]; + struct software_node_ref_args gpio2_ref[1]; + struct software_node_ref_args gpio3_ref[1]; + struct software_node_ref_args gpio4_ref[1]; + struct software_node_ref_args gpio5_ref[1]; + struct software_node_ref_args sfp_ref[1]; + struct software_node swnodes[SWNODE_MAX]; + const struct software_node *group[SWNODE_MAX + 1]; +}; + +struct txgbe { + struct wx *wx; + struct txgbe_nodes nodes; +}; + #endif /* _TXGBE_TYPE_H_ */ -- cgit v1.2.3 From b63f20485e433e6e548df81f5c76556d7f187266 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 6 Jun 2023 17:21:01 +0800 Subject: net: txgbe: Register fixed rate clock In order for I2C to be able to work in standard mode, register a fixed rate clock for each I2C device. Signed-off-by: Jiawen Wu Reviewed-by: Andrew Lunn Reviewed-by: Maciej Fijalkowski Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/Kconfig | 1 + drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 41 +++++++++++++++++++++++++ drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 2 ++ 3 files changed, 44 insertions(+) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index c9d88673d306..190d42a203b4 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -40,6 +40,7 @@ config NGBE config TXGBE tristate "Wangxun(R) 10GbE PCI Express adapters support" depends on PCI + depends on COMMON_CLK select LIBWX help This driver supports Wangxun(R) 10GbE PCI Express family of diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index be4b5ad74a3c..06506cfb8d06 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -2,6 +2,8 @@ /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ #include +#include +#include #include #include @@ -70,6 +72,32 @@ static int txgbe_swnodes_register(struct txgbe *txgbe) return software_node_register_node_group(nodes->group); } +static int txgbe_clock_register(struct txgbe *txgbe) +{ + struct pci_dev *pdev = txgbe->wx->pdev; + struct clk_lookup *clock; + char clk_name[32]; + struct clk *clk; + + snprintf(clk_name, sizeof(clk_name), "i2c_designware.%d", + (pdev->bus->number << 8) | pdev->devfn); + + clk = clk_register_fixed_rate(NULL, clk_name, NULL, 0, 156250000); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + clock = clkdev_create(clk, NULL, clk_name); + if (!clock) { + clk_unregister(clk); + return -ENOMEM; + } + + txgbe->clk = clk; + txgbe->clock = clock; + + return 0; +} + int txgbe_init_phy(struct txgbe *txgbe) { int ret; @@ -80,10 +108,23 @@ int txgbe_init_phy(struct txgbe *txgbe) return ret; } + ret = txgbe_clock_register(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to register clock: %d\n", ret); + goto err_unregister_swnode; + } + return 0; + +err_unregister_swnode: + software_node_unregister_node_group(txgbe->nodes.group); + + return ret; } void txgbe_remove_phy(struct txgbe *txgbe) { + clkdev_drop(txgbe->clock); + clk_unregister(txgbe->clk); software_node_unregister_node_group(txgbe->nodes.group); } diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 9aa399acd9a0..856d0f9d045b 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -147,6 +147,8 @@ struct txgbe_nodes { struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct clk_lookup *clock; + struct clk *clk; }; #endif /* _TXGBE_TYPE_H_ */ -- cgit v1.2.3 From c625e72561f6c9bd5d1a86aa4d1d5a68db43d2e0 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 6 Jun 2023 17:21:02 +0800 Subject: net: txgbe: Register I2C platform device Register the platform device to use Designware I2C bus master driver. Use regmap to read/write I2C device region from given base offset. Signed-off-by: Jiawen Wu Reviewed-by: Andrew Lunn Reviewed-by: Piotr Raczynski Reviewed-by: Andy Shevchenko Reviewed-by: Maciej Fijalkowski Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/Kconfig | 3 ++ drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 70 +++++++++++++++++++++++++ drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 4 ++ 3 files changed, 77 insertions(+) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index 190d42a203b4..128cc1cb0605 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -41,6 +41,9 @@ config TXGBE tristate "Wangxun(R) 10GbE PCI Express adapters support" depends on PCI depends on COMMON_CLK + select REGMAP + select I2C + select I2C_DESIGNWARE_PLATFORM select LIBWX help This driver supports Wangxun(R) 10GbE PCI Express family of diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 06506cfb8d06..24a729150e08 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "../libwx/wx_type.h" #include "txgbe_type.h" @@ -98,6 +100,64 @@ static int txgbe_clock_register(struct txgbe *txgbe) return 0; } +static int txgbe_i2c_read(void *context, unsigned int reg, unsigned int *val) +{ + struct wx *wx = context; + + *val = rd32(wx, reg + TXGBE_I2C_BASE); + + return 0; +} + +static int txgbe_i2c_write(void *context, unsigned int reg, unsigned int val) +{ + struct wx *wx = context; + + wr32(wx, reg + TXGBE_I2C_BASE, val); + + return 0; +} + +static const struct regmap_config i2c_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_read = txgbe_i2c_read, + .reg_write = txgbe_i2c_write, + .fast_io = true, +}; + +static int txgbe_i2c_register(struct txgbe *txgbe) +{ + struct platform_device_info info = {}; + struct platform_device *i2c_dev; + struct regmap *i2c_regmap; + struct pci_dev *pdev; + struct wx *wx; + + wx = txgbe->wx; + pdev = wx->pdev; + i2c_regmap = devm_regmap_init(&pdev->dev, NULL, wx, &i2c_regmap_config); + if (IS_ERR(i2c_regmap)) { + wx_err(wx, "failed to init I2C regmap\n"); + return PTR_ERR(i2c_regmap); + } + + info.parent = &pdev->dev; + info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_I2C]); + info.name = "i2c_designware"; + info.id = (pdev->bus->number << 8) | pdev->devfn; + + info.res = &DEFINE_RES_IRQ(pdev->irq); + info.num_res = 1; + i2c_dev = platform_device_register_full(&info); + if (IS_ERR(i2c_dev)) + return PTR_ERR(i2c_dev); + + txgbe->i2c_dev = i2c_dev; + + return 0; +} + int txgbe_init_phy(struct txgbe *txgbe) { int ret; @@ -114,8 +174,17 @@ int txgbe_init_phy(struct txgbe *txgbe) goto err_unregister_swnode; } + ret = txgbe_i2c_register(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret); + goto err_unregister_clk; + } + return 0; +err_unregister_clk: + clkdev_drop(txgbe->clock); + clk_unregister(txgbe->clk); err_unregister_swnode: software_node_unregister_node_group(txgbe->nodes.group); @@ -124,6 +193,7 @@ err_unregister_swnode: void txgbe_remove_phy(struct txgbe *txgbe) { + platform_device_unregister(txgbe->i2c_dev); clkdev_drop(txgbe->clock); clk_unregister(txgbe->clk); software_node_unregister_node_group(txgbe->nodes.group); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 856d0f9d045b..6e471a4d68cc 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -55,6 +55,9 @@ #define TXGBE_TS_CTL 0x10300 #define TXGBE_TS_CTL_EVAL_MD BIT(31) +/* I2C registers */ +#define TXGBE_I2C_BASE 0x14900 + /* Part Number String Length */ #define TXGBE_PBANUM_LENGTH 32 @@ -147,6 +150,7 @@ struct txgbe_nodes { struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct platform_device *i2c_dev; struct clk_lookup *clock; struct clk *clk; }; -- cgit v1.2.3 From 04d94236182e4f46bea6a48e3830b27f361f090f Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 6 Jun 2023 17:21:03 +0800 Subject: net: txgbe: Add SFP module identify Register SFP platform device to get modules information. Signed-off-by: Jiawen Wu Reviewed-by: Andrew Lunn Reviewed-by: Piotr Raczynski Reviewed-by: Maciej Fijalkowski Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/Kconfig | 3 +++ drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 28 +++++++++++++++++++++++++ drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 1 + 3 files changed, 32 insertions(+) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index 128cc1cb0605..59f3a3f492cf 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -44,6 +44,9 @@ config TXGBE select REGMAP select I2C select I2C_DESIGNWARE_PLATFORM + select PHYLINK + select HWMON if TXGBE=y + select SFP select LIBWX help This driver supports Wangxun(R) 10GbE PCI Express family of diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 24a729150e08..d95dc131e91b 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -158,6 +158,25 @@ static int txgbe_i2c_register(struct txgbe *txgbe) return 0; } +static int txgbe_sfp_register(struct txgbe *txgbe) +{ + struct pci_dev *pdev = txgbe->wx->pdev; + struct platform_device_info info = {}; + struct platform_device *sfp_dev; + + info.parent = &pdev->dev; + info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_SFP]); + info.name = "sfp"; + info.id = (pdev->bus->number << 8) | pdev->devfn; + sfp_dev = platform_device_register_full(&info); + if (IS_ERR(sfp_dev)) + return PTR_ERR(sfp_dev); + + txgbe->sfp_dev = sfp_dev; + + return 0; +} + int txgbe_init_phy(struct txgbe *txgbe) { int ret; @@ -180,8 +199,16 @@ int txgbe_init_phy(struct txgbe *txgbe) goto err_unregister_clk; } + ret = txgbe_sfp_register(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to register sfp\n"); + goto err_unregister_i2c; + } + return 0; +err_unregister_i2c: + platform_device_unregister(txgbe->i2c_dev); err_unregister_clk: clkdev_drop(txgbe->clock); clk_unregister(txgbe->clk); @@ -193,6 +220,7 @@ err_unregister_swnode: void txgbe_remove_phy(struct txgbe *txgbe) { + platform_device_unregister(txgbe->sfp_dev); platform_device_unregister(txgbe->i2c_dev); clkdev_drop(txgbe->clock); clk_unregister(txgbe->clk); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 6e471a4d68cc..f420e2569247 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -150,6 +150,7 @@ struct txgbe_nodes { struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct platform_device *sfp_dev; struct platform_device *i2c_dev; struct clk_lookup *clock; struct clk *clk; -- cgit v1.2.3 From b83c37315a620fc8dcb5f3cffe4753765228d1f4 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 6 Jun 2023 17:21:04 +0800 Subject: net: txgbe: Support GPIO to SFP socket Register GPIO chip and handle GPIO IRQ for SFP socket. Signed-off-by: Jiawen Wu Reviewed-by: Andy Shevchenko Reviewed-by: Maciej Fijalkowski Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/Kconfig | 2 + drivers/net/ethernet/wangxun/libwx/wx_lib.c | 3 +- drivers/net/ethernet/wangxun/libwx/wx_type.h | 3 + drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 20 +- drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 251 ++++++++++++++++++++++++ drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 23 +++ 6 files changed, 283 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index 59f3a3f492cf..3744735fa708 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -47,6 +47,8 @@ config TXGBE select PHYLINK select HWMON if TXGBE=y select SFP + select GPIOLIB + select GPIOLIB_IRQCHIP select LIBWX help This driver supports Wangxun(R) 10GbE PCI Express family of diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 3dd328d33fcc..2c3f08be8c37 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -2048,7 +2048,8 @@ void wx_free_irq(struct wx *wx) free_irq(entry->vector, q_vector); } - free_irq(wx->msix_entries[vector].vector, wx); + if (wx->mac.type == wx_mac_em) + free_irq(wx->msix_entries[vector].vector, wx); } EXPORT_SYMBOL(wx_free_irq); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index c61c18a842c4..29dfb561887d 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -83,7 +83,9 @@ #define WX_GPIO_INTMASK 0x14834 #define WX_GPIO_INTTYPE_LEVEL 0x14838 #define WX_GPIO_POLARITY 0x1483C +#define WX_GPIO_INTSTATUS 0x14844 #define WX_GPIO_EOI 0x1484C +#define WX_GPIO_EXT 0x14850 /*********************** Transmit DMA registers **************************/ /* transmit global control */ @@ -847,6 +849,7 @@ struct wx { bool wol_enabled; bool ncsi_enabled; bool gpio_ctrl; + raw_spinlock_t gpio_lock; /* Tx fast path data */ int num_tx_queues; diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 920ee3a3bfa3..edfab3859dc3 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -82,6 +82,8 @@ static int txgbe_enumerate_functions(struct wx *wx) **/ static void txgbe_irq_enable(struct wx *wx, bool queues) { + wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); + /* unmask interrupt */ wx_intr_enable(wx, TXGBE_INTR_MISC(wx)); if (queues) @@ -129,17 +131,6 @@ static irqreturn_t txgbe_intr(int __always_unused irq, void *data) return IRQ_HANDLED; } -static irqreturn_t txgbe_msix_other(int __always_unused irq, void *data) -{ - struct wx *wx = data; - - /* re-enable the original interrupt state */ - if (netif_running(wx->netdev)) - txgbe_irq_enable(wx, false); - - return IRQ_HANDLED; -} - /** * txgbe_request_msix_irqs - Initialize MSI-X interrupts * @wx: board private structure @@ -171,13 +162,6 @@ static int txgbe_request_msix_irqs(struct wx *wx) } } - err = request_irq(wx->msix_entries[vector].vector, - txgbe_msix_other, 0, netdev->name, wx); - if (err) { - wx_err(wx, "request_irq for msix_other failed: %d\n", err); - goto free_queue_irqs; - } - return 0; free_queue_irqs: diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index d95dc131e91b..97c018a10c39 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ +#include +#include #include #include #include @@ -10,6 +12,7 @@ #include #include "../libwx/wx_type.h" +#include "../libwx/wx_hw.h" #include "txgbe_type.h" #include "txgbe_phy.h" @@ -74,6 +77,248 @@ static int txgbe_swnodes_register(struct txgbe *txgbe) return software_node_register_node_group(nodes->group); } +static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct wx *wx = gpiochip_get_data(chip); + int val; + + val = rd32m(wx, WX_GPIO_EXT, BIT(offset)); + + return !!(val & BIT(offset)); +} + +static int txgbe_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct wx *wx = gpiochip_get_data(chip); + u32 val; + + val = rd32(wx, WX_GPIO_DDR); + if (BIT(offset) & val) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +static int txgbe_gpio_direction_in(struct gpio_chip *chip, unsigned int offset) +{ + struct wx *wx = gpiochip_get_data(chip); + unsigned long flags; + + raw_spin_lock_irqsave(&wx->gpio_lock, flags); + wr32m(wx, WX_GPIO_DDR, BIT(offset), 0); + raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); + + return 0; +} + +static int txgbe_gpio_direction_out(struct gpio_chip *chip, unsigned int offset, + int val) +{ + struct wx *wx = gpiochip_get_data(chip); + unsigned long flags; + u32 set; + + set = val ? BIT(offset) : 0; + + raw_spin_lock_irqsave(&wx->gpio_lock, flags); + wr32m(wx, WX_GPIO_DR, BIT(offset), set); + wr32m(wx, WX_GPIO_DDR, BIT(offset), BIT(offset)); + raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); + + return 0; +} + +static void txgbe_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct wx *wx = gpiochip_get_data(gc); + unsigned long flags; + + raw_spin_lock_irqsave(&wx->gpio_lock, flags); + wr32(wx, WX_GPIO_EOI, BIT(hwirq)); + raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); +} + +static void txgbe_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct wx *wx = gpiochip_get_data(gc); + unsigned long flags; + + gpiochip_disable_irq(gc, hwirq); + + raw_spin_lock_irqsave(&wx->gpio_lock, flags); + wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), BIT(hwirq)); + raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); +} + +static void txgbe_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct wx *wx = gpiochip_get_data(gc); + unsigned long flags; + + gpiochip_enable_irq(gc, hwirq); + + raw_spin_lock_irqsave(&wx->gpio_lock, flags); + wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), 0); + raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); +} + +static void txgbe_toggle_trigger(struct gpio_chip *gc, unsigned int offset) +{ + struct wx *wx = gpiochip_get_data(gc); + u32 pol, val; + + pol = rd32(wx, WX_GPIO_POLARITY); + val = rd32(wx, WX_GPIO_EXT); + + if (val & BIT(offset)) + pol &= ~BIT(offset); + else + pol |= BIT(offset); + + wr32(wx, WX_GPIO_POLARITY, pol); +} + +static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct wx *wx = gpiochip_get_data(gc); + u32 level, polarity, mask; + unsigned long flags; + + mask = BIT(hwirq); + + if (type & IRQ_TYPE_LEVEL_MASK) { + level = 0; + irq_set_handler_locked(d, handle_level_irq); + } else { + level = mask; + irq_set_handler_locked(d, handle_edge_irq); + } + + if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) + polarity = mask; + else + polarity = 0; + + raw_spin_lock_irqsave(&wx->gpio_lock, flags); + + wr32m(wx, WX_GPIO_INTEN, mask, mask); + wr32m(wx, WX_GPIO_INTTYPE_LEVEL, mask, level); + if (type == IRQ_TYPE_EDGE_BOTH) + txgbe_toggle_trigger(gc, hwirq); + else + wr32m(wx, WX_GPIO_POLARITY, mask, polarity); + + raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); + + return 0; +} + +static const struct irq_chip txgbe_gpio_irq_chip = { + .name = "txgbe_gpio_irq", + .irq_ack = txgbe_gpio_irq_ack, + .irq_mask = txgbe_gpio_irq_mask, + .irq_unmask = txgbe_gpio_irq_unmask, + .irq_set_type = txgbe_gpio_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void txgbe_irq_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct wx *wx = irq_desc_get_handler_data(desc); + struct txgbe *txgbe = wx->priv; + irq_hw_number_t hwirq; + unsigned long gpioirq; + struct gpio_chip *gc; + unsigned long flags; + + chained_irq_enter(chip, desc); + + gpioirq = rd32(wx, WX_GPIO_INTSTATUS); + + gc = txgbe->gpio; + for_each_set_bit(hwirq, &gpioirq, gc->ngpio) { + int gpio = irq_find_mapping(gc->irq.domain, hwirq); + u32 irq_type = irq_get_trigger_type(gpio); + + generic_handle_domain_irq(gc->irq.domain, hwirq); + + if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { + raw_spin_lock_irqsave(&wx->gpio_lock, flags); + txgbe_toggle_trigger(gc, hwirq); + raw_spin_unlock_irqrestore(&wx->gpio_lock, flags); + } + } + + chained_irq_exit(chip, desc); + + /* unmask interrupt */ + wx_intr_enable(wx, TXGBE_INTR_MISC(wx)); +} + +static int txgbe_gpio_init(struct txgbe *txgbe) +{ + struct gpio_irq_chip *girq; + struct gpio_chip *gc; + struct device *dev; + struct wx *wx; + int ret; + + wx = txgbe->wx; + dev = &wx->pdev->dev; + + raw_spin_lock_init(&wx->gpio_lock); + + gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; + + gc->label = devm_kasprintf(dev, GFP_KERNEL, "txgbe_gpio-%x", + (wx->pdev->bus->number << 8) | wx->pdev->devfn); + if (!gc->label) + return -ENOMEM; + + gc->base = -1; + gc->ngpio = 6; + gc->owner = THIS_MODULE; + gc->parent = dev; + gc->fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_GPIO]); + gc->get = txgbe_gpio_get; + gc->get_direction = txgbe_gpio_get_direction; + gc->direction_input = txgbe_gpio_direction_in; + gc->direction_output = txgbe_gpio_direction_out; + + girq = &gc->irq; + gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip); + girq->parent_handler = txgbe_irq_handler; + girq->parent_handler_data = wx; + girq->num_parents = 1; + girq->parents = devm_kcalloc(dev, girq->num_parents, + sizeof(*girq->parents), GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = wx->msix_entries[wx->num_q_vectors].vector; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + + ret = devm_gpiochip_add_data(dev, gc, wx); + if (ret) + return ret; + + txgbe->gpio = gc; + + return 0; +} + static int txgbe_clock_register(struct txgbe *txgbe) { struct pci_dev *pdev = txgbe->wx->pdev; @@ -187,6 +432,12 @@ int txgbe_init_phy(struct txgbe *txgbe) return ret; } + ret = txgbe_gpio_init(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to init gpio\n"); + goto err_unregister_swnode; + } + ret = txgbe_clock_register(txgbe); if (ret) { wx_err(txgbe->wx, "failed to register clock: %d\n", ret); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index f420e2569247..60ecc5a90203 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -55,6 +55,28 @@ #define TXGBE_TS_CTL 0x10300 #define TXGBE_TS_CTL_EVAL_MD BIT(31) +/* GPIO register bit */ +#define TXGBE_GPIOBIT_0 BIT(0) /* I:tx fault */ +#define TXGBE_GPIOBIT_1 BIT(1) /* O:tx disabled */ +#define TXGBE_GPIOBIT_2 BIT(2) /* I:sfp module absent */ +#define TXGBE_GPIOBIT_3 BIT(3) /* I:rx signal lost */ +#define TXGBE_GPIOBIT_4 BIT(4) /* O:rate select, 1G(0) 10G(1) */ +#define TXGBE_GPIOBIT_5 BIT(5) /* O:rate select, 1G(0) 10G(1) */ + +/* Extended Interrupt Enable Set */ +#define TXGBE_PX_MISC_ETH_LKDN BIT(8) +#define TXGBE_PX_MISC_DEV_RST BIT(10) +#define TXGBE_PX_MISC_ETH_EVENT BIT(17) +#define TXGBE_PX_MISC_ETH_LK BIT(18) +#define TXGBE_PX_MISC_ETH_AN BIT(19) +#define TXGBE_PX_MISC_INT_ERR BIT(20) +#define TXGBE_PX_MISC_GPIO BIT(26) +#define TXGBE_PX_MISC_IEN_MASK \ + (TXGBE_PX_MISC_ETH_LKDN | TXGBE_PX_MISC_DEV_RST | \ + TXGBE_PX_MISC_ETH_EVENT | TXGBE_PX_MISC_ETH_LK | \ + TXGBE_PX_MISC_ETH_AN | TXGBE_PX_MISC_INT_ERR | \ + TXGBE_PX_MISC_GPIO) + /* I2C registers */ #define TXGBE_I2C_BASE 0x14900 @@ -154,6 +176,7 @@ struct txgbe { struct platform_device *i2c_dev; struct clk_lookup *clock; struct clk *clk; + struct gpio_chip *gpio; }; #endif /* _TXGBE_TYPE_H_ */ -- cgit v1.2.3 From af8de1e307bf1ecbd17d220122832cd093f7a3f8 Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 6 Jun 2023 17:21:05 +0800 Subject: net: pcs: Add 10GBASE-R mode for Synopsys Designware XPCS Add basic support for XPCS using 10GBASE-R interface. This mode will be extended to use interrupt, so set pcs.poll false. And avoid soft reset so that the device using this mode is in the default configuration. Signed-off-by: Jiawen Wu Reviewed-by: Andrew Lunn Reviewed-by: Maciej Fijalkowski Signed-off-by: Paolo Abeni --- drivers/net/pcs/pcs-xpcs.c | 30 ++++++++++++++++++++++++++++++ include/linux/pcs/pcs-xpcs.h | 1 + 2 files changed, 31 insertions(+) diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 23223f0f8cad..e4e59aa9faf7 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -64,6 +64,16 @@ static const int xpcs_xlgmii_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; +static const int xpcs_10gbaser_features[] = { + ETHTOOL_LINK_MODE_Pause_BIT, + ETHTOOL_LINK_MODE_Asym_Pause_BIT, + ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, + ETHTOOL_LINK_MODE_10000baseER_Full_BIT, + __ETHTOOL_LINK_MODE_MASK_NBITS, +}; + static const int xpcs_sgmii_features[] = { ETHTOOL_LINK_MODE_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT, @@ -106,6 +116,10 @@ static const phy_interface_t xpcs_xlgmii_interfaces[] = { PHY_INTERFACE_MODE_XLGMII, }; +static const phy_interface_t xpcs_10gbaser_interfaces[] = { + PHY_INTERFACE_MODE_10GBASER, +}; + static const phy_interface_t xpcs_sgmii_interfaces[] = { PHY_INTERFACE_MODE_SGMII, }; @@ -123,6 +137,7 @@ enum { DW_XPCS_USXGMII, DW_XPCS_10GKR, DW_XPCS_XLGMII, + DW_XPCS_10GBASER, DW_XPCS_SGMII, DW_XPCS_1000BASEX, DW_XPCS_2500BASEX, @@ -246,6 +261,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs, switch (compat->an_mode) { case DW_AN_C73: + case DW_10GBASER: dev = MDIO_MMD_PCS; break; case DW_AN_C37_SGMII: @@ -802,6 +818,8 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, return -ENODEV; switch (compat->an_mode) { + case DW_10GBASER: + break; case DW_AN_C73: if (test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) { ret = xpcs_config_aneg_c73(xpcs, compat); @@ -998,6 +1016,9 @@ static void xpcs_get_state(struct phylink_pcs *pcs, return; switch (compat->an_mode) { + case DW_10GBASER: + phylink_mii_c45_pcs_get_state(xpcs->mdiodev, state); + break; case DW_AN_C73: ret = xpcs_get_state_c73(xpcs, state, compat); if (ret) { @@ -1153,6 +1174,12 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = { .num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces), .an_mode = DW_AN_C73, }, + [DW_XPCS_10GBASER] = { + .supported = xpcs_10gbaser_features, + .interface = xpcs_10gbaser_interfaces, + .num_interfaces = ARRAY_SIZE(xpcs_10gbaser_interfaces), + .an_mode = DW_10GBASER, + }, [DW_XPCS_SGMII] = { .supported = xpcs_sgmii_features, .interface = xpcs_sgmii_interfaces, @@ -1256,6 +1283,9 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, } xpcs->pcs.ops = &xpcs_phylink_ops; + if (compat->an_mode == DW_10GBASER) + return xpcs; + xpcs->pcs.poll = true; ret = xpcs_soft_reset(xpcs, compat); diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index 914e387d5387..ec8175b847cc 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -18,6 +18,7 @@ #define DW_AN_C37_SGMII 2 #define DW_2500BASEX 3 #define DW_AN_C37_1000BASEX 4 +#define DW_10GBASER 5 struct xpcs_id; -- cgit v1.2.3 From 854cace61387b6f60734d9ec254443a6894c480d Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 6 Jun 2023 17:21:06 +0800 Subject: net: txgbe: Implement phylink pcs Register MDIO bus for PCS layer to use Synopsys designware XPCS, support 10GBASE-R interface to the controller. Signed-off-by: Jiawen Wu Reviewed-by: Andrew Lunn Reviewed-by: Maciej Fijalkowski Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/Kconfig | 1 + drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 89 ++++++++++++++++++++++++- drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 5 ++ 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index 3744735fa708..39596cd13539 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -49,6 +49,7 @@ config TXGBE select SFP select GPIOLIB select GPIOLIB_IRQCHIP + select PCS_XPCS select LIBWX help This driver supports Wangxun(R) 10GbE PCI Express family of diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 97c018a10c39..58e12c35627a 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "../libwx/wx_type.h" #include "../libwx/wx_hw.h" @@ -77,6 +78,81 @@ static int txgbe_swnodes_register(struct txgbe *txgbe) return software_node_register_node_group(nodes->group); } +static int txgbe_pcs_read(struct mii_bus *bus, int addr, int devnum, int regnum) +{ + struct wx *wx = bus->priv; + u32 offset, val; + + if (addr) + return -EOPNOTSUPP; + + offset = devnum << 16 | regnum; + + /* Set the LAN port indicator to IDA_ADDR */ + wr32(wx, TXGBE_XPCS_IDA_ADDR, offset); + + /* Read the data from IDA_DATA register */ + val = rd32(wx, TXGBE_XPCS_IDA_DATA); + + return (u16)val; +} + +static int txgbe_pcs_write(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val) +{ + struct wx *wx = bus->priv; + u32 offset; + + if (addr) + return -EOPNOTSUPP; + + offset = devnum << 16 | regnum; + + /* Set the LAN port indicator to IDA_ADDR */ + wr32(wx, TXGBE_XPCS_IDA_ADDR, offset); + + /* Write the data to IDA_DATA register */ + wr32(wx, TXGBE_XPCS_IDA_DATA, val); + + return 0; +} + +static int txgbe_mdio_pcs_init(struct txgbe *txgbe) +{ + struct mii_bus *mii_bus; + struct dw_xpcs *xpcs; + struct pci_dev *pdev; + struct wx *wx; + int ret = 0; + + wx = txgbe->wx; + pdev = wx->pdev; + + mii_bus = devm_mdiobus_alloc(&pdev->dev); + if (!mii_bus) + return -ENOMEM; + + mii_bus->name = "txgbe_pcs_mdio_bus"; + mii_bus->read_c45 = &txgbe_pcs_read; + mii_bus->write_c45 = &txgbe_pcs_write; + mii_bus->parent = &pdev->dev; + mii_bus->phy_mask = ~0; + mii_bus->priv = wx; + snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe_pcs-%x", + (pdev->bus->number << 8) | pdev->devfn); + + ret = devm_mdiobus_register(&pdev->dev, mii_bus); + if (ret) + return ret; + + xpcs = xpcs_create_mdiodev(mii_bus, 0, PHY_INTERFACE_MODE_10GBASER); + if (IS_ERR(xpcs)) + return PTR_ERR(xpcs); + + txgbe->xpcs = xpcs; + + return 0; +} + static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct wx *wx = gpiochip_get_data(chip); @@ -432,16 +508,22 @@ int txgbe_init_phy(struct txgbe *txgbe) return ret; } + ret = txgbe_mdio_pcs_init(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to init mdio pcs: %d\n", ret); + goto err_unregister_swnode; + } + ret = txgbe_gpio_init(txgbe); if (ret) { wx_err(txgbe->wx, "failed to init gpio\n"); - goto err_unregister_swnode; + goto err_destroy_xpcs; } ret = txgbe_clock_register(txgbe); if (ret) { wx_err(txgbe->wx, "failed to register clock: %d\n", ret); - goto err_unregister_swnode; + goto err_destroy_xpcs; } ret = txgbe_i2c_register(txgbe); @@ -463,6 +545,8 @@ err_unregister_i2c: err_unregister_clk: clkdev_drop(txgbe->clock); clk_unregister(txgbe->clk); +err_destroy_xpcs: + xpcs_destroy(txgbe->xpcs); err_unregister_swnode: software_node_unregister_node_group(txgbe->nodes.group); @@ -475,5 +559,6 @@ void txgbe_remove_phy(struct txgbe *txgbe) platform_device_unregister(txgbe->i2c_dev); clkdev_drop(txgbe->clock); clk_unregister(txgbe->clk); + xpcs_destroy(txgbe->xpcs); software_node_unregister_node_group(txgbe->nodes.group); } diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 60ecc5a90203..76470582ba1e 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -80,6 +80,10 @@ /* I2C registers */ #define TXGBE_I2C_BASE 0x14900 +/************************************** ETH PHY ******************************/ +#define TXGBE_XPCS_IDA_ADDR 0x13000 +#define TXGBE_XPCS_IDA_DATA 0x13004 + /* Part Number String Length */ #define TXGBE_PBANUM_LENGTH 32 @@ -172,6 +176,7 @@ struct txgbe_nodes { struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct dw_xpcs *xpcs; struct platform_device *sfp_dev; struct platform_device *i2c_dev; struct clk_lookup *clock; -- cgit v1.2.3 From 08f08f9390e4d7770e400b98eb4a25909593508e Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Tue, 6 Jun 2023 17:21:07 +0800 Subject: net: txgbe: Support phylink MAC layer Add phylink support to Wangxun 10Gb Ethernet controller for the 10GBASE-R interface. Signed-off-by: Jiawen Wu Reviewed-by: Maciej Fijalkowski Signed-off-by: Paolo Abeni --- drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c | 28 +++++ drivers/net/ethernet/wangxun/txgbe/txgbe_main.c | 23 ++--- drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c | 113 ++++++++++++++++++++- drivers/net/ethernet/wangxun/txgbe/txgbe_type.h | 5 + 4 files changed, 154 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c index d914e9a05404..859da112586a 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c @@ -6,11 +6,39 @@ #include #include "../libwx/wx_ethtool.h" +#include "../libwx/wx_type.h" +#include "txgbe_type.h" #include "txgbe_ethtool.h" +static int txgbe_nway_reset(struct net_device *netdev) +{ + struct txgbe *txgbe = netdev_to_txgbe(netdev); + + return phylink_ethtool_nway_reset(txgbe->phylink); +} + +static int txgbe_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) +{ + struct txgbe *txgbe = netdev_to_txgbe(netdev); + + return phylink_ethtool_ksettings_get(txgbe->phylink, cmd); +} + +static int txgbe_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *cmd) +{ + struct txgbe *txgbe = netdev_to_txgbe(netdev); + + return phylink_ethtool_ksettings_set(txgbe->phylink, cmd); +} + static const struct ethtool_ops txgbe_ethtool_ops = { .get_drvinfo = wx_get_drvinfo, + .nway_reset = txgbe_nway_reset, .get_link = ethtool_op_get_link, + .get_link_ksettings = txgbe_get_link_ksettings, + .set_link_ksettings = txgbe_set_link_ksettings, }; void txgbe_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index edfab3859dc3..46eba6d6188b 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -204,7 +205,8 @@ static int txgbe_request_irq(struct wx *wx) static void txgbe_up_complete(struct wx *wx) { - u32 reg; + struct net_device *netdev = wx->netdev; + struct txgbe *txgbe; wx_control_hw(wx, true); wx_configure_vectors(wx); @@ -213,24 +215,17 @@ static void txgbe_up_complete(struct wx *wx) smp_mb__before_atomic(); wx_napi_enable_all(wx); + txgbe = netdev_to_txgbe(netdev); + phylink_start(txgbe->phylink); + /* clear any pending interrupts, may auto mask */ rd32(wx, WX_PX_IC(0)); rd32(wx, WX_PX_IC(1)); rd32(wx, WX_PX_MISC_IC); txgbe_irq_enable(wx, true); - /* Configure MAC Rx and Tx when link is up */ - reg = rd32(wx, WX_MAC_RX_CFG); - wr32(wx, WX_MAC_RX_CFG, reg); - wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR); - reg = rd32(wx, WX_MAC_WDG_TIMEOUT); - wr32(wx, WX_MAC_WDG_TIMEOUT, reg); - reg = rd32(wx, WX_MAC_TX_CFG); - wr32(wx, WX_MAC_TX_CFG, (reg & ~WX_MAC_TX_CFG_SPEED_MASK) | WX_MAC_TX_CFG_SPEED_10G); - /* enable transmits */ - netif_tx_start_all_queues(wx->netdev); - netif_carrier_on(wx->netdev); + netif_tx_start_all_queues(netdev); } static void txgbe_reset(struct wx *wx) @@ -265,7 +260,6 @@ static void txgbe_disable_device(struct wx *wx) wx_disable_rx_queue(wx, wx->rx_ring[i]); netif_tx_stop_all_queues(netdev); - netif_carrier_off(netdev); netif_tx_disable(netdev); wx_irq_disable(wx); @@ -296,8 +290,11 @@ static void txgbe_disable_device(struct wx *wx) static void txgbe_down(struct wx *wx) { + struct txgbe *txgbe = netdev_to_txgbe(wx->netdev); + txgbe_disable_device(wx); txgbe_reset(wx); + phylink_stop(txgbe->phylink); wx_clean_all_tx_rings(wx); wx_clean_all_rx_rings(wx); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 58e12c35627a..8779645a54be 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -11,8 +11,10 @@ #include #include #include +#include #include "../libwx/wx_type.h" +#include "../libwx/wx_lib.h" #include "../libwx/wx_hw.h" #include "txgbe_type.h" #include "txgbe_phy.h" @@ -153,6 +155,95 @@ static int txgbe_mdio_pcs_init(struct txgbe *txgbe) return 0; } +static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *config, + phy_interface_t interface) +{ + struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev)); + + return &txgbe->xpcs->pcs; +} + +static void txgbe_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void txgbe_mac_link_down(struct phylink_config *config, + unsigned int mode, phy_interface_t interface) +{ + struct wx *wx = netdev_priv(to_net_dev(config->dev)); + + wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0); +} + +static void txgbe_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + struct wx *wx = netdev_priv(to_net_dev(config->dev)); + u32 txcfg, wdg; + + txcfg = rd32(wx, WX_MAC_TX_CFG); + txcfg &= ~WX_MAC_TX_CFG_SPEED_MASK; + + switch (speed) { + case SPEED_10000: + txcfg |= WX_MAC_TX_CFG_SPEED_10G; + break; + case SPEED_1000: + case SPEED_100: + case SPEED_10: + txcfg |= WX_MAC_TX_CFG_SPEED_1G; + break; + default: + break; + } + + wr32(wx, WX_MAC_TX_CFG, txcfg | WX_MAC_TX_CFG_TE); + + /* Re configure MAC Rx */ + wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE); + wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR); + wdg = rd32(wx, WX_MAC_WDG_TIMEOUT); + wr32(wx, WX_MAC_WDG_TIMEOUT, wdg); +} + +static const struct phylink_mac_ops txgbe_mac_ops = { + .mac_select_pcs = txgbe_phylink_mac_select, + .mac_config = txgbe_mac_config, + .mac_link_down = txgbe_mac_link_down, + .mac_link_up = txgbe_mac_link_up, +}; + +static int txgbe_phylink_init(struct txgbe *txgbe) +{ + struct phylink_config *config; + struct fwnode_handle *fwnode; + struct wx *wx = txgbe->wx; + phy_interface_t phy_mode; + struct phylink *phylink; + + config = devm_kzalloc(&wx->pdev->dev, sizeof(*config), GFP_KERNEL); + if (!config) + return -ENOMEM; + + config->dev = &wx->netdev->dev; + config->type = PHYLINK_NETDEV; + config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE; + phy_mode = PHY_INTERFACE_MODE_10GBASER; + __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces); + fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]); + phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops); + if (IS_ERR(phylink)) + return PTR_ERR(phylink); + + txgbe->phylink = phylink; + + return 0; +} + static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct wx *wx = gpiochip_get_data(chip); @@ -316,6 +407,9 @@ static void txgbe_irq_handler(struct irq_desc *desc) unsigned long gpioirq; struct gpio_chip *gc; unsigned long flags; + u32 eicr; + + eicr = wx_misc_isb(wx, WX_ISB_MISC); chained_irq_enter(chip, desc); @@ -337,6 +431,12 @@ static void txgbe_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); + if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN)) { + u32 reg = rd32(wx, TXGBE_CFG_PORT_ST); + + phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP)); + } + /* unmask interrupt */ wx_intr_enable(wx, TXGBE_INTR_MISC(wx)); } @@ -514,16 +614,22 @@ int txgbe_init_phy(struct txgbe *txgbe) goto err_unregister_swnode; } + ret = txgbe_phylink_init(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to init phylink\n"); + goto err_destroy_xpcs; + } + ret = txgbe_gpio_init(txgbe); if (ret) { wx_err(txgbe->wx, "failed to init gpio\n"); - goto err_destroy_xpcs; + goto err_destroy_phylink; } ret = txgbe_clock_register(txgbe); if (ret) { wx_err(txgbe->wx, "failed to register clock: %d\n", ret); - goto err_destroy_xpcs; + goto err_destroy_phylink; } ret = txgbe_i2c_register(txgbe); @@ -545,6 +651,8 @@ err_unregister_i2c: err_unregister_clk: clkdev_drop(txgbe->clock); clk_unregister(txgbe->clk); +err_destroy_phylink: + phylink_destroy(txgbe->phylink); err_destroy_xpcs: xpcs_destroy(txgbe->xpcs); err_unregister_swnode: @@ -559,6 +667,7 @@ void txgbe_remove_phy(struct txgbe *txgbe) platform_device_unregister(txgbe->i2c_dev); clkdev_drop(txgbe->clock); clk_unregister(txgbe->clk); + phylink_destroy(txgbe->phylink); xpcs_destroy(txgbe->xpcs); software_node_unregister_node_group(txgbe->nodes.group); } diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 76470582ba1e..51199c355f95 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -77,6 +77,10 @@ TXGBE_PX_MISC_ETH_AN | TXGBE_PX_MISC_INT_ERR | \ TXGBE_PX_MISC_GPIO) +/* Port cfg registers */ +#define TXGBE_CFG_PORT_ST 0x14404 +#define TXGBE_CFG_PORT_ST_LINK_UP BIT(0) + /* I2C registers */ #define TXGBE_I2C_BASE 0x14900 @@ -177,6 +181,7 @@ struct txgbe { struct wx *wx; struct txgbe_nodes nodes; struct dw_xpcs *xpcs; + struct phylink *phylink; struct platform_device *sfp_dev; struct platform_device *i2c_dev; struct clk_lookup *clock; -- cgit v1.2.3 From 67faabbde36b7dc006cb0a71811098e7277976d0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 7 Jun 2023 15:40:46 -0700 Subject: selftests/bpf: Add missing prototypes for several test kfuncs Adding missing prototypes for several kfuncs that are used by test_verifier tests. We don't really need kfunc prototypes for these tests, but adding them to silence 'make W=1' build and to have all test kfuncs declarations in bpf_testmod_kfunc.h. Also moving __diag_pop for -Wmissing-prototypes to cover also bpf_testmod_test_write and bpf_testmod_test_read and adding bpf_fentry_shadow_test in there as well. All of them need to be exported, but there's no need for declarations. Fixes: 65eb006d85a2 ("bpf: Move kernel test kfuncs to bpf_testmod") Reported-by: kernel test robot Signed-off-by: Jiri Olsa Signed-off-by: Daniel Borkmann Closes: https://lore.kernel.org/oe-kbuild-all/202306051319.EihCQZPs-lkp@intel.com Link: https://lore.kernel.org/bpf/20230607224046.236510-1-jolsa@kernel.org --- tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c | 16 ++++++++-------- .../selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h | 7 +++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index cf216041876c..aaf6ef1201c7 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -191,8 +191,6 @@ noinline int bpf_testmod_fentry_test3(char a, int b, u64 c) return a + b + c; } -__diag_pop(); - int bpf_testmod_fentry_ok; noinline ssize_t @@ -273,6 +271,14 @@ bpf_testmod_test_write(struct file *file, struct kobject *kobj, EXPORT_SYMBOL(bpf_testmod_test_write); ALLOW_ERROR_INJECTION(bpf_testmod_test_write, ERRNO); +noinline int bpf_fentry_shadow_test(int a) +{ + return a + 2; +} +EXPORT_SYMBOL_GPL(bpf_fentry_shadow_test); + +__diag_pop(); + static struct bin_attribute bin_attr_bpf_testmod_file __ro_after_init = { .attr = { .name = "bpf_testmod", .mode = 0666, }, .read = bpf_testmod_test_read, @@ -462,12 +468,6 @@ static const struct btf_kfunc_id_set bpf_testmod_kfunc_set = { .set = &bpf_testmod_check_kfunc_ids, }; -noinline int bpf_fentry_shadow_test(int a) -{ - return a + 2; -} -EXPORT_SYMBOL_GPL(bpf_fentry_shadow_test); - extern int bpf_fentry_test1(int a); static int bpf_testmod_init(void) diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h index 9693c626646b..f5c5b1375c24 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h @@ -97,4 +97,11 @@ void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; void bpf_kfunc_call_test_destructive(void) __ksym; +void bpf_kfunc_call_test_offset(struct prog_test_ref_kfunc *p); +struct prog_test_member *bpf_kfunc_call_memb_acquire(void); +void bpf_kfunc_call_memb1_release(struct prog_test_member1 *p); +void bpf_kfunc_call_test_fail1(struct prog_test_fail1 *p); +void bpf_kfunc_call_test_fail2(struct prog_test_fail2 *p); +void bpf_kfunc_call_test_fail3(struct prog_test_fail3 *p); +void bpf_kfunc_call_test_mem_len_fail1(void *mem, int len); #endif /* _BPF_TESTMOD_KFUNC_H */ -- cgit v1.2.3 From 0d7aeb68700ff87b4d2acafb789408a065225e1e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:47 +0100 Subject: Drop the netfs_ prefix from netfs_extract_iter_to_sg() Rename netfs_extract_iter_to_sg() and its auxiliary functions to drop the netfs_ prefix. Signed-off-by: David Howells cc: Jeff Layton cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jens Axboe cc: Herbert Xu cc: "Matthew Wilcox (Oracle)" cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: linux-crypto@vger.kernel.org cc: linux-cachefs@redhat.com cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: netdev@vger.kernel.org Signed-off-by: Paolo Abeni --- fs/netfs/iterator.c | 66 +++++++++++++++++++++++------------------------ fs/smb/client/smb2ops.c | 4 +-- fs/smb/client/smbdirect.c | 2 +- include/linux/netfs.h | 6 ++--- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c index 8a4c86687429..f8eba3de1a97 100644 --- a/fs/netfs/iterator.c +++ b/fs/netfs/iterator.c @@ -106,11 +106,11 @@ EXPORT_SYMBOL_GPL(netfs_extract_user_iter); * Extract and pin a list of up to sg_max pages from UBUF- or IOVEC-class * iterators, and add them to the scatterlist. */ -static ssize_t netfs_extract_user_to_sg(struct iov_iter *iter, - ssize_t maxsize, - struct sg_table *sgtable, - unsigned int sg_max, - iov_iter_extraction_t extraction_flags) +static ssize_t extract_user_to_sg(struct iov_iter *iter, + ssize_t maxsize, + struct sg_table *sgtable, + unsigned int sg_max, + iov_iter_extraction_t extraction_flags) { struct scatterlist *sg = sgtable->sgl + sgtable->nents; struct page **pages; @@ -159,11 +159,11 @@ failed: * Extract up to sg_max pages from a BVEC-type iterator and add them to the * scatterlist. The pages are not pinned. */ -static ssize_t netfs_extract_bvec_to_sg(struct iov_iter *iter, - ssize_t maxsize, - struct sg_table *sgtable, - unsigned int sg_max, - iov_iter_extraction_t extraction_flags) +static ssize_t extract_bvec_to_sg(struct iov_iter *iter, + ssize_t maxsize, + struct sg_table *sgtable, + unsigned int sg_max, + iov_iter_extraction_t extraction_flags) { const struct bio_vec *bv = iter->bvec; struct scatterlist *sg = sgtable->sgl + sgtable->nents; @@ -205,11 +205,11 @@ static ssize_t netfs_extract_bvec_to_sg(struct iov_iter *iter, * scatterlist. This can deal with vmalloc'd buffers as well as kmalloc'd or * static buffers. The pages are not pinned. */ -static ssize_t netfs_extract_kvec_to_sg(struct iov_iter *iter, - ssize_t maxsize, - struct sg_table *sgtable, - unsigned int sg_max, - iov_iter_extraction_t extraction_flags) +static ssize_t extract_kvec_to_sg(struct iov_iter *iter, + ssize_t maxsize, + struct sg_table *sgtable, + unsigned int sg_max, + iov_iter_extraction_t extraction_flags) { const struct kvec *kv = iter->kvec; struct scatterlist *sg = sgtable->sgl + sgtable->nents; @@ -266,11 +266,11 @@ static ssize_t netfs_extract_kvec_to_sg(struct iov_iter *iter, * Extract up to sg_max folios from an XARRAY-type iterator and add them to * the scatterlist. The pages are not pinned. */ -static ssize_t netfs_extract_xarray_to_sg(struct iov_iter *iter, - ssize_t maxsize, - struct sg_table *sgtable, - unsigned int sg_max, - iov_iter_extraction_t extraction_flags) +static ssize_t extract_xarray_to_sg(struct iov_iter *iter, + ssize_t maxsize, + struct sg_table *sgtable, + unsigned int sg_max, + iov_iter_extraction_t extraction_flags) { struct scatterlist *sg = sgtable->sgl + sgtable->nents; struct xarray *xa = iter->xarray; @@ -312,7 +312,7 @@ static ssize_t netfs_extract_xarray_to_sg(struct iov_iter *iter, } /** - * netfs_extract_iter_to_sg - Extract pages from an iterator and add ot an sglist + * extract_iter_to_sg - Extract pages from an iterator and add ot an sglist * @iter: The iterator to extract from * @maxsize: The amount of iterator to copy * @sgtable: The scatterlist table to fill in @@ -339,9 +339,9 @@ static ssize_t netfs_extract_xarray_to_sg(struct iov_iter *iter, * The iov_iter_extract_mode() function should be used to query how cleanup * should be performed. */ -ssize_t netfs_extract_iter_to_sg(struct iov_iter *iter, size_t maxsize, - struct sg_table *sgtable, unsigned int sg_max, - iov_iter_extraction_t extraction_flags) +ssize_t extract_iter_to_sg(struct iov_iter *iter, size_t maxsize, + struct sg_table *sgtable, unsigned int sg_max, + iov_iter_extraction_t extraction_flags) { if (maxsize == 0) return 0; @@ -349,21 +349,21 @@ ssize_t netfs_extract_iter_to_sg(struct iov_iter *iter, size_t maxsize, switch (iov_iter_type(iter)) { case ITER_UBUF: case ITER_IOVEC: - return netfs_extract_user_to_sg(iter, maxsize, sgtable, sg_max, - extraction_flags); + return extract_user_to_sg(iter, maxsize, sgtable, sg_max, + extraction_flags); case ITER_BVEC: - return netfs_extract_bvec_to_sg(iter, maxsize, sgtable, sg_max, - extraction_flags); + return extract_bvec_to_sg(iter, maxsize, sgtable, sg_max, + extraction_flags); case ITER_KVEC: - return netfs_extract_kvec_to_sg(iter, maxsize, sgtable, sg_max, - extraction_flags); + return extract_kvec_to_sg(iter, maxsize, sgtable, sg_max, + extraction_flags); case ITER_XARRAY: - return netfs_extract_xarray_to_sg(iter, maxsize, sgtable, sg_max, - extraction_flags); + return extract_xarray_to_sg(iter, maxsize, sgtable, sg_max, + extraction_flags); default: pr_err("%s(%u) unsupported\n", __func__, iov_iter_type(iter)); WARN_ON_ONCE(1); return -EIO; } } -EXPORT_SYMBOL_GPL(netfs_extract_iter_to_sg); +EXPORT_SYMBOL_GPL(extract_iter_to_sg); diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 6e3be58cfe49..38d2265c77fd 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4333,8 +4333,8 @@ static void *smb2_get_aead_req(struct crypto_aead *tfm, struct smb_rqst *rqst, } sgtable.orig_nents = sgtable.nents; - rc = netfs_extract_iter_to_sg(iter, count, &sgtable, - num_sgs - sgtable.nents, 0); + rc = extract_iter_to_sg(iter, count, &sgtable, + num_sgs - sgtable.nents, 0); iov_iter_revert(iter, rc); sgtable.orig_nents = sgtable.nents; } diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 0362ebd4fa0f..223e17c16b60 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -2227,7 +2227,7 @@ static int smbd_iter_to_mr(struct smbd_connection *info, memset(sgt->sgl, 0, max_sg * sizeof(struct scatterlist)); - ret = netfs_extract_iter_to_sg(iter, iov_iter_count(iter), sgt, max_sg, 0); + ret = extract_iter_to_sg(iter, iov_iter_count(iter), sgt, max_sg, 0); WARN_ON(ret < 0); if (sgt->nents > 0) sg_mark_end(&sgt->sgl[sgt->nents - 1]); diff --git a/include/linux/netfs.h b/include/linux/netfs.h index a1f3522daa69..55e201c3a841 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -301,9 +301,9 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, struct iov_iter *new, iov_iter_extraction_t extraction_flags); struct sg_table; -ssize_t netfs_extract_iter_to_sg(struct iov_iter *iter, size_t len, - struct sg_table *sgtable, unsigned int sg_max, - iov_iter_extraction_t extraction_flags); +ssize_t extract_iter_to_sg(struct iov_iter *iter, size_t len, + struct sg_table *sgtable, unsigned int sg_max, + iov_iter_extraction_t extraction_flags); /** * netfs_inode - Get the netfs inode context from the inode -- cgit v1.2.3 From 3b9e9f72badfbb03415459126498d524bcb25225 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:48 +0100 Subject: Fix a couple of spelling mistakes Fix a couple of spelling mistakes in a comment. Suggested-by: Simon Horman Link: https://lore.kernel.org/r/ZHH2mSRqeL4Gs1ft@corigine.com/ Link: https://lore.kernel.org/r/ZHH1nqZWOGzxlidT@corigine.com/ Signed-off-by: David Howells Reviewed-by: Simon Horman cc: Jeff Layton cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jens Axboe cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: linux-cachefs@redhat.com cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: netdev@vger.kernel.org Signed-off-by: Paolo Abeni --- fs/netfs/iterator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c index f8eba3de1a97..f41a37bca1e8 100644 --- a/fs/netfs/iterator.c +++ b/fs/netfs/iterator.c @@ -312,7 +312,7 @@ static ssize_t extract_xarray_to_sg(struct iov_iter *iter, } /** - * extract_iter_to_sg - Extract pages from an iterator and add ot an sglist + * extract_iter_to_sg - Extract pages from an iterator and add to an sglist * @iter: The iterator to extract from * @maxsize: The amount of iterator to copy * @sgtable: The scatterlist table to fill in @@ -332,7 +332,7 @@ static ssize_t extract_xarray_to_sg(struct iov_iter *iter, * @extraction_flags can have ITER_ALLOW_P2PDMA set to request peer-to-peer DMA * be allowed on the pages extracted. * - * If successul, @sgtable->nents is updated to include the number of elements + * If successful, @sgtable->nents is updated to include the number of elements * added and the number of bytes added is returned. @sgtable->orig_nents is * left unaltered. * -- cgit v1.2.3 From 936dc763c52e05cb2e7302af30a69c826916d89e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:49 +0100 Subject: Wrap lines at 80 Wrap a line at 80 to stop checkpatch complaining. Signed-off-by: David Howells cc: Jeff Layton cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jens Axboe cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Matthew Wilcox cc: Simon Horman cc: linux-crypto@vger.kernel.org cc: linux-cachefs@redhat.com cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: netdev@vger.kernel.org Signed-off-by: Paolo Abeni --- fs/netfs/iterator.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c index f41a37bca1e8..9f09dc30ceb6 100644 --- a/fs/netfs/iterator.c +++ b/fs/netfs/iterator.c @@ -119,7 +119,8 @@ static ssize_t extract_user_to_sg(struct iov_iter *iter, size_t len, off; /* We decant the page list into the tail of the scatterlist */ - pages = (void *)sgtable->sgl + array_size(sg_max, sizeof(struct scatterlist)); + pages = (void *)sgtable->sgl + + array_size(sg_max, sizeof(struct scatterlist)); pages -= sg_max; do { -- cgit v1.2.3 From f5f82cd18732d828bcd1ec308c4e8c55012e84b0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:50 +0100 Subject: Move netfs_extract_iter_to_sg() to lib/scatterlist.c Move netfs_extract_iter_to_sg() to lib/scatterlist.c as it's going to be used by more than just network filesystems (AF_ALG, for example). Signed-off-by: David Howells cc: Jeff Layton cc: Steve French cc: Shyam Prasad N cc: Rohith Surabattula cc: Jens Axboe cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: linux-cachefs@redhat.com cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: netdev@vger.kernel.org Signed-off-by: Paolo Abeni --- fs/netfs/iterator.c | 267 ------------------------------------------------- include/linux/netfs.h | 4 - include/linux/uio.h | 5 + lib/scatterlist.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 271 deletions(-) diff --git a/fs/netfs/iterator.c b/fs/netfs/iterator.c index 9f09dc30ceb6..2ff07ba655a0 100644 --- a/fs/netfs/iterator.c +++ b/fs/netfs/iterator.c @@ -101,270 +101,3 @@ ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, return npages; } EXPORT_SYMBOL_GPL(netfs_extract_user_iter); - -/* - * Extract and pin a list of up to sg_max pages from UBUF- or IOVEC-class - * iterators, and add them to the scatterlist. - */ -static ssize_t extract_user_to_sg(struct iov_iter *iter, - ssize_t maxsize, - struct sg_table *sgtable, - unsigned int sg_max, - iov_iter_extraction_t extraction_flags) -{ - struct scatterlist *sg = sgtable->sgl + sgtable->nents; - struct page **pages; - unsigned int npages; - ssize_t ret = 0, res; - size_t len, off; - - /* We decant the page list into the tail of the scatterlist */ - pages = (void *)sgtable->sgl + - array_size(sg_max, sizeof(struct scatterlist)); - pages -= sg_max; - - do { - res = iov_iter_extract_pages(iter, &pages, maxsize, sg_max, - extraction_flags, &off); - if (res < 0) - goto failed; - - len = res; - maxsize -= len; - ret += len; - npages = DIV_ROUND_UP(off + len, PAGE_SIZE); - sg_max -= npages; - - for (; npages > 0; npages--) { - struct page *page = *pages; - size_t seg = min_t(size_t, PAGE_SIZE - off, len); - - *pages++ = NULL; - sg_set_page(sg, page, seg, off); - sgtable->nents++; - sg++; - len -= seg; - off = 0; - } - } while (maxsize > 0 && sg_max > 0); - - return ret; - -failed: - while (sgtable->nents > sgtable->orig_nents) - put_page(sg_page(&sgtable->sgl[--sgtable->nents])); - return res; -} - -/* - * Extract up to sg_max pages from a BVEC-type iterator and add them to the - * scatterlist. The pages are not pinned. - */ -static ssize_t extract_bvec_to_sg(struct iov_iter *iter, - ssize_t maxsize, - struct sg_table *sgtable, - unsigned int sg_max, - iov_iter_extraction_t extraction_flags) -{ - const struct bio_vec *bv = iter->bvec; - struct scatterlist *sg = sgtable->sgl + sgtable->nents; - unsigned long start = iter->iov_offset; - unsigned int i; - ssize_t ret = 0; - - for (i = 0; i < iter->nr_segs; i++) { - size_t off, len; - - len = bv[i].bv_len; - if (start >= len) { - start -= len; - continue; - } - - len = min_t(size_t, maxsize, len - start); - off = bv[i].bv_offset + start; - - sg_set_page(sg, bv[i].bv_page, len, off); - sgtable->nents++; - sg++; - sg_max--; - - ret += len; - maxsize -= len; - if (maxsize <= 0 || sg_max == 0) - break; - start = 0; - } - - if (ret > 0) - iov_iter_advance(iter, ret); - return ret; -} - -/* - * Extract up to sg_max pages from a KVEC-type iterator and add them to the - * scatterlist. This can deal with vmalloc'd buffers as well as kmalloc'd or - * static buffers. The pages are not pinned. - */ -static ssize_t extract_kvec_to_sg(struct iov_iter *iter, - ssize_t maxsize, - struct sg_table *sgtable, - unsigned int sg_max, - iov_iter_extraction_t extraction_flags) -{ - const struct kvec *kv = iter->kvec; - struct scatterlist *sg = sgtable->sgl + sgtable->nents; - unsigned long start = iter->iov_offset; - unsigned int i; - ssize_t ret = 0; - - for (i = 0; i < iter->nr_segs; i++) { - struct page *page; - unsigned long kaddr; - size_t off, len, seg; - - len = kv[i].iov_len; - if (start >= len) { - start -= len; - continue; - } - - kaddr = (unsigned long)kv[i].iov_base + start; - off = kaddr & ~PAGE_MASK; - len = min_t(size_t, maxsize, len - start); - kaddr &= PAGE_MASK; - - maxsize -= len; - ret += len; - do { - seg = min_t(size_t, len, PAGE_SIZE - off); - if (is_vmalloc_or_module_addr((void *)kaddr)) - page = vmalloc_to_page((void *)kaddr); - else - page = virt_to_page(kaddr); - - sg_set_page(sg, page, len, off); - sgtable->nents++; - sg++; - sg_max--; - - len -= seg; - kaddr += PAGE_SIZE; - off = 0; - } while (len > 0 && sg_max > 0); - - if (maxsize <= 0 || sg_max == 0) - break; - start = 0; - } - - if (ret > 0) - iov_iter_advance(iter, ret); - return ret; -} - -/* - * Extract up to sg_max folios from an XARRAY-type iterator and add them to - * the scatterlist. The pages are not pinned. - */ -static ssize_t extract_xarray_to_sg(struct iov_iter *iter, - ssize_t maxsize, - struct sg_table *sgtable, - unsigned int sg_max, - iov_iter_extraction_t extraction_flags) -{ - struct scatterlist *sg = sgtable->sgl + sgtable->nents; - struct xarray *xa = iter->xarray; - struct folio *folio; - loff_t start = iter->xarray_start + iter->iov_offset; - pgoff_t index = start / PAGE_SIZE; - ssize_t ret = 0; - size_t offset, len; - XA_STATE(xas, xa, index); - - rcu_read_lock(); - - xas_for_each(&xas, folio, ULONG_MAX) { - if (xas_retry(&xas, folio)) - continue; - if (WARN_ON(xa_is_value(folio))) - break; - if (WARN_ON(folio_test_hugetlb(folio))) - break; - - offset = offset_in_folio(folio, start); - len = min_t(size_t, maxsize, folio_size(folio) - offset); - - sg_set_page(sg, folio_page(folio, 0), len, offset); - sgtable->nents++; - sg++; - sg_max--; - - maxsize -= len; - ret += len; - if (maxsize <= 0 || sg_max == 0) - break; - } - - rcu_read_unlock(); - if (ret > 0) - iov_iter_advance(iter, ret); - return ret; -} - -/** - * extract_iter_to_sg - Extract pages from an iterator and add to an sglist - * @iter: The iterator to extract from - * @maxsize: The amount of iterator to copy - * @sgtable: The scatterlist table to fill in - * @sg_max: Maximum number of elements in @sgtable that may be filled - * @extraction_flags: Flags to qualify the request - * - * Extract the page fragments from the given amount of the source iterator and - * add them to a scatterlist that refers to all of those bits, to a maximum - * addition of @sg_max elements. - * - * The pages referred to by UBUF- and IOVEC-type iterators are extracted and - * pinned; BVEC-, KVEC- and XARRAY-type are extracted but aren't pinned; PIPE- - * and DISCARD-type are not supported. - * - * No end mark is placed on the scatterlist; that's left to the caller. - * - * @extraction_flags can have ITER_ALLOW_P2PDMA set to request peer-to-peer DMA - * be allowed on the pages extracted. - * - * If successful, @sgtable->nents is updated to include the number of elements - * added and the number of bytes added is returned. @sgtable->orig_nents is - * left unaltered. - * - * The iov_iter_extract_mode() function should be used to query how cleanup - * should be performed. - */ -ssize_t extract_iter_to_sg(struct iov_iter *iter, size_t maxsize, - struct sg_table *sgtable, unsigned int sg_max, - iov_iter_extraction_t extraction_flags) -{ - if (maxsize == 0) - return 0; - - switch (iov_iter_type(iter)) { - case ITER_UBUF: - case ITER_IOVEC: - return extract_user_to_sg(iter, maxsize, sgtable, sg_max, - extraction_flags); - case ITER_BVEC: - return extract_bvec_to_sg(iter, maxsize, sgtable, sg_max, - extraction_flags); - case ITER_KVEC: - return extract_kvec_to_sg(iter, maxsize, sgtable, sg_max, - extraction_flags); - case ITER_XARRAY: - return extract_xarray_to_sg(iter, maxsize, sgtable, sg_max, - extraction_flags); - default: - pr_err("%s(%u) unsupported\n", __func__, iov_iter_type(iter)); - WARN_ON_ONCE(1); - return -EIO; - } -} -EXPORT_SYMBOL_GPL(extract_iter_to_sg); diff --git a/include/linux/netfs.h b/include/linux/netfs.h index 55e201c3a841..b11a84f6c32b 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -300,10 +300,6 @@ void netfs_stats_show(struct seq_file *); ssize_t netfs_extract_user_iter(struct iov_iter *orig, size_t orig_len, struct iov_iter *new, iov_iter_extraction_t extraction_flags); -struct sg_table; -ssize_t extract_iter_to_sg(struct iov_iter *iter, size_t len, - struct sg_table *sgtable, unsigned int sg_max, - iov_iter_extraction_t extraction_flags); /** * netfs_inode - Get the netfs inode context from the inode diff --git a/include/linux/uio.h b/include/linux/uio.h index 044c1d8c230c..0ccb983cf645 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -433,4 +433,9 @@ static inline bool iov_iter_extract_will_pin(const struct iov_iter *iter) return user_backed_iter(iter); } +struct sg_table; +ssize_t extract_iter_to_sg(struct iov_iter *iter, size_t len, + struct sg_table *sgtable, unsigned int sg_max, + iov_iter_extraction_t extraction_flags); + #endif diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 8d7519a8f308..e97d7060329e 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include /** * sg_next - return the next scatterlist entry in a list @@ -1095,3 +1097,270 @@ size_t sg_zero_buffer(struct scatterlist *sgl, unsigned int nents, return offset; } EXPORT_SYMBOL(sg_zero_buffer); + +/* + * Extract and pin a list of up to sg_max pages from UBUF- or IOVEC-class + * iterators, and add them to the scatterlist. + */ +static ssize_t extract_user_to_sg(struct iov_iter *iter, + ssize_t maxsize, + struct sg_table *sgtable, + unsigned int sg_max, + iov_iter_extraction_t extraction_flags) +{ + struct scatterlist *sg = sgtable->sgl + sgtable->nents; + struct page **pages; + unsigned int npages; + ssize_t ret = 0, res; + size_t len, off; + + /* We decant the page list into the tail of the scatterlist */ + pages = (void *)sgtable->sgl + + array_size(sg_max, sizeof(struct scatterlist)); + pages -= sg_max; + + do { + res = iov_iter_extract_pages(iter, &pages, maxsize, sg_max, + extraction_flags, &off); + if (res < 0) + goto failed; + + len = res; + maxsize -= len; + ret += len; + npages = DIV_ROUND_UP(off + len, PAGE_SIZE); + sg_max -= npages; + + for (; npages > 0; npages--) { + struct page *page = *pages; + size_t seg = min_t(size_t, PAGE_SIZE - off, len); + + *pages++ = NULL; + sg_set_page(sg, page, seg, off); + sgtable->nents++; + sg++; + len -= seg; + off = 0; + } + } while (maxsize > 0 && sg_max > 0); + + return ret; + +failed: + while (sgtable->nents > sgtable->orig_nents) + put_page(sg_page(&sgtable->sgl[--sgtable->nents])); + return res; +} + +/* + * Extract up to sg_max pages from a BVEC-type iterator and add them to the + * scatterlist. The pages are not pinned. + */ +static ssize_t extract_bvec_to_sg(struct iov_iter *iter, + ssize_t maxsize, + struct sg_table *sgtable, + unsigned int sg_max, + iov_iter_extraction_t extraction_flags) +{ + const struct bio_vec *bv = iter->bvec; + struct scatterlist *sg = sgtable->sgl + sgtable->nents; + unsigned long start = iter->iov_offset; + unsigned int i; + ssize_t ret = 0; + + for (i = 0; i < iter->nr_segs; i++) { + size_t off, len; + + len = bv[i].bv_len; + if (start >= len) { + start -= len; + continue; + } + + len = min_t(size_t, maxsize, len - start); + off = bv[i].bv_offset + start; + + sg_set_page(sg, bv[i].bv_page, len, off); + sgtable->nents++; + sg++; + sg_max--; + + ret += len; + maxsize -= len; + if (maxsize <= 0 || sg_max == 0) + break; + start = 0; + } + + if (ret > 0) + iov_iter_advance(iter, ret); + return ret; +} + +/* + * Extract up to sg_max pages from a KVEC-type iterator and add them to the + * scatterlist. This can deal with vmalloc'd buffers as well as kmalloc'd or + * static buffers. The pages are not pinned. + */ +static ssize_t extract_kvec_to_sg(struct iov_iter *iter, + ssize_t maxsize, + struct sg_table *sgtable, + unsigned int sg_max, + iov_iter_extraction_t extraction_flags) +{ + const struct kvec *kv = iter->kvec; + struct scatterlist *sg = sgtable->sgl + sgtable->nents; + unsigned long start = iter->iov_offset; + unsigned int i; + ssize_t ret = 0; + + for (i = 0; i < iter->nr_segs; i++) { + struct page *page; + unsigned long kaddr; + size_t off, len, seg; + + len = kv[i].iov_len; + if (start >= len) { + start -= len; + continue; + } + + kaddr = (unsigned long)kv[i].iov_base + start; + off = kaddr & ~PAGE_MASK; + len = min_t(size_t, maxsize, len - start); + kaddr &= PAGE_MASK; + + maxsize -= len; + ret += len; + do { + seg = min_t(size_t, len, PAGE_SIZE - off); + if (is_vmalloc_or_module_addr((void *)kaddr)) + page = vmalloc_to_page((void *)kaddr); + else + page = virt_to_page(kaddr); + + sg_set_page(sg, page, len, off); + sgtable->nents++; + sg++; + sg_max--; + + len -= seg; + kaddr += PAGE_SIZE; + off = 0; + } while (len > 0 && sg_max > 0); + + if (maxsize <= 0 || sg_max == 0) + break; + start = 0; + } + + if (ret > 0) + iov_iter_advance(iter, ret); + return ret; +} + +/* + * Extract up to sg_max folios from an XARRAY-type iterator and add them to + * the scatterlist. The pages are not pinned. + */ +static ssize_t extract_xarray_to_sg(struct iov_iter *iter, + ssize_t maxsize, + struct sg_table *sgtable, + unsigned int sg_max, + iov_iter_extraction_t extraction_flags) +{ + struct scatterlist *sg = sgtable->sgl + sgtable->nents; + struct xarray *xa = iter->xarray; + struct folio *folio; + loff_t start = iter->xarray_start + iter->iov_offset; + pgoff_t index = start / PAGE_SIZE; + ssize_t ret = 0; + size_t offset, len; + XA_STATE(xas, xa, index); + + rcu_read_lock(); + + xas_for_each(&xas, folio, ULONG_MAX) { + if (xas_retry(&xas, folio)) + continue; + if (WARN_ON(xa_is_value(folio))) + break; + if (WARN_ON(folio_test_hugetlb(folio))) + break; + + offset = offset_in_folio(folio, start); + len = min_t(size_t, maxsize, folio_size(folio) - offset); + + sg_set_page(sg, folio_page(folio, 0), len, offset); + sgtable->nents++; + sg++; + sg_max--; + + maxsize -= len; + ret += len; + if (maxsize <= 0 || sg_max == 0) + break; + } + + rcu_read_unlock(); + if (ret > 0) + iov_iter_advance(iter, ret); + return ret; +} + +/** + * extract_iter_to_sg - Extract pages from an iterator and add to an sglist + * @iter: The iterator to extract from + * @maxsize: The amount of iterator to copy + * @sgtable: The scatterlist table to fill in + * @sg_max: Maximum number of elements in @sgtable that may be filled + * @extraction_flags: Flags to qualify the request + * + * Extract the page fragments from the given amount of the source iterator and + * add them to a scatterlist that refers to all of those bits, to a maximum + * addition of @sg_max elements. + * + * The pages referred to by UBUF- and IOVEC-type iterators are extracted and + * pinned; BVEC-, KVEC- and XARRAY-type are extracted but aren't pinned; PIPE- + * and DISCARD-type are not supported. + * + * No end mark is placed on the scatterlist; that's left to the caller. + * + * @extraction_flags can have ITER_ALLOW_P2PDMA set to request peer-to-peer DMA + * be allowed on the pages extracted. + * + * If successful, @sgtable->nents is updated to include the number of elements + * added and the number of bytes added is returned. @sgtable->orig_nents is + * left unaltered. + * + * The iov_iter_extract_mode() function should be used to query how cleanup + * should be performed. + */ +ssize_t extract_iter_to_sg(struct iov_iter *iter, size_t maxsize, + struct sg_table *sgtable, unsigned int sg_max, + iov_iter_extraction_t extraction_flags) +{ + if (maxsize == 0) + return 0; + + switch (iov_iter_type(iter)) { + case ITER_UBUF: + case ITER_IOVEC: + return extract_user_to_sg(iter, maxsize, sgtable, sg_max, + extraction_flags); + case ITER_BVEC: + return extract_bvec_to_sg(iter, maxsize, sgtable, sg_max, + extraction_flags); + case ITER_KVEC: + return extract_kvec_to_sg(iter, maxsize, sgtable, sg_max, + extraction_flags); + case ITER_XARRAY: + return extract_xarray_to_sg(iter, maxsize, sgtable, sg_max, + extraction_flags); + default: + pr_err("%s(%u) unsupported\n", __func__, iov_iter_type(iter)); + WARN_ON_ONCE(1); + return -EIO; + } +} +EXPORT_SYMBOL_GPL(extract_iter_to_sg); -- cgit v1.2.3 From f9e7a5fa51fbb6fcb9c1c7e2c89dd7df9e7fe253 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:51 +0100 Subject: crypto: af_alg: Pin pages rather than ref'ing if appropriate Convert AF_ALG to use iov_iter_extract_pages() instead of iov_iter_get_pages(). This will pin pages or leave them unaltered rather than getting a ref on them as appropriate to the iterator. The pages need to be pinned for DIO-read rather than having refs taken on them to prevent VM copy-on-write from malfunctioning during a concurrent fork() (the result of the I/O would otherwise end up only visible to the child process and not the parent). Signed-off-by: David Howells cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org Acked-by: Herbert Xu Signed-off-by: Paolo Abeni --- crypto/af_alg.c | 10 +++++++--- include/crypto/if_alg.h | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 5f7252a5b7b4..7caff10df643 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -533,14 +533,17 @@ static const struct net_proto_family alg_family = { int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len) { + struct page **pages = sgl->pages; size_t off; ssize_t n; int npages, i; - n = iov_iter_get_pages2(iter, sgl->pages, len, ALG_MAX_PAGES, &off); + n = iov_iter_extract_pages(iter, &pages, len, ALG_MAX_PAGES, 0, &off); if (n < 0) return n; + sgl->need_unpin = iov_iter_extract_will_pin(iter); + npages = DIV_ROUND_UP(off + n, PAGE_SIZE); if (WARN_ON(npages == 0)) return -EINVAL; @@ -573,8 +576,9 @@ void af_alg_free_sg(struct af_alg_sgl *sgl) { int i; - for (i = 0; i < sgl->npages; i++) - put_page(sgl->pages[i]); + if (sgl->need_unpin) + for (i = 0; i < sgl->npages; i++) + unpin_user_page(sgl->pages[i]); } EXPORT_SYMBOL_GPL(af_alg_free_sg); diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 7e76623f9ec3..46494b33f5bc 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -59,6 +59,7 @@ struct af_alg_sgl { struct scatterlist sg[ALG_MAX_PAGES + 1]; struct page *pages[ALG_MAX_PAGES]; unsigned int npages; + bool need_unpin; }; /* TX SGL entry */ -- cgit v1.2.3 From c1abe6f570aff4b6d396dc551e60570d2f50bd79 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:52 +0100 Subject: crypto: af_alg: Use extract_iter_to_sg() to create scatterlists Use extract_iter_to_sg() to decant the destination iterator into a scatterlist in af_alg_get_rsgl(). af_alg_make_sg() can then be removed. Signed-off-by: David Howells cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org Acked-by: Herbert Xu Signed-off-by: Paolo Abeni --- crypto/af_alg.c | 57 +++++++++++++------------------------------------ crypto/algif_aead.c | 16 ++++++++------ crypto/algif_hash.c | 18 +++++++++++----- crypto/algif_skcipher.c | 2 +- include/crypto/if_alg.h | 6 ++---- 5 files changed, 40 insertions(+), 59 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 7caff10df643..b8bf6d8525ba 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -531,45 +531,11 @@ static const struct net_proto_family alg_family = { .owner = THIS_MODULE, }; -int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len) -{ - struct page **pages = sgl->pages; - size_t off; - ssize_t n; - int npages, i; - - n = iov_iter_extract_pages(iter, &pages, len, ALG_MAX_PAGES, 0, &off); - if (n < 0) - return n; - - sgl->need_unpin = iov_iter_extract_will_pin(iter); - - npages = DIV_ROUND_UP(off + n, PAGE_SIZE); - if (WARN_ON(npages == 0)) - return -EINVAL; - /* Add one extra for linking */ - sg_init_table(sgl->sg, npages + 1); - - for (i = 0, len = n; i < npages; i++) { - int plen = min_t(int, len, PAGE_SIZE - off); - - sg_set_page(sgl->sg + i, sgl->pages[i], plen, off); - - off = 0; - len -= plen; - } - sg_mark_end(sgl->sg + npages - 1); - sgl->npages = npages; - - return n; -} -EXPORT_SYMBOL_GPL(af_alg_make_sg); - static void af_alg_link_sg(struct af_alg_sgl *sgl_prev, struct af_alg_sgl *sgl_new) { - sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); - sg_chain(sgl_prev->sg, sgl_prev->npages + 1, sgl_new->sg); + sg_unmark_end(sgl_prev->sgt.sgl + sgl_prev->sgt.nents - 1); + sg_chain(sgl_prev->sgt.sgl, sgl_prev->sgt.nents + 1, sgl_new->sgt.sgl); } void af_alg_free_sg(struct af_alg_sgl *sgl) @@ -577,8 +543,8 @@ void af_alg_free_sg(struct af_alg_sgl *sgl) int i; if (sgl->need_unpin) - for (i = 0; i < sgl->npages; i++) - unpin_user_page(sgl->pages[i]); + for (i = 0; i < sgl->sgt.nents; i++) + unpin_user_page(sg_page(&sgl->sgt.sgl[i])); } EXPORT_SYMBOL_GPL(af_alg_free_sg); @@ -1292,8 +1258,8 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, while (maxsize > len && msg_data_left(msg)) { struct af_alg_rsgl *rsgl; + ssize_t err; size_t seglen; - int err; /* limit the amount of readable buffers */ if (!af_alg_readable(sk)) @@ -1310,16 +1276,23 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, return -ENOMEM; } - rsgl->sgl.npages = 0; + rsgl->sgl.sgt.sgl = rsgl->sgl.sgl; + rsgl->sgl.sgt.nents = 0; + rsgl->sgl.sgt.orig_nents = 0; list_add_tail(&rsgl->list, &areq->rsgl_list); - /* make one iovec available as scatterlist */ - err = af_alg_make_sg(&rsgl->sgl, &msg->msg_iter, seglen); + sg_init_table(rsgl->sgl.sgt.sgl, ALG_MAX_PAGES); + err = extract_iter_to_sg(&msg->msg_iter, seglen, &rsgl->sgl.sgt, + ALG_MAX_PAGES, 0); if (err < 0) { rsgl->sg_num_bytes = 0; return err; } + sg_mark_end(rsgl->sgl.sgt.sgl + rsgl->sgl.sgt.nents - 1); + rsgl->sgl.need_unpin = + iov_iter_extract_will_pin(&msg->msg_iter); + /* chain the new scatterlist with previous one */ if (areq->last_rsgl) af_alg_link_sg(&areq->last_rsgl->sgl, &rsgl->sgl); diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 42493b4d8ce4..829878025dba 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -210,7 +210,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, */ /* Use the RX SGL as source (and destination) for crypto op. */ - rsgl_src = areq->first_rsgl.sgl.sg; + rsgl_src = areq->first_rsgl.sgl.sgt.sgl; if (ctx->enc) { /* @@ -224,7 +224,8 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, * RX SGL: AAD || PT || Tag */ err = crypto_aead_copy_sgl(null_tfm, tsgl_src, - areq->first_rsgl.sgl.sg, processed); + areq->first_rsgl.sgl.sgt.sgl, + processed); if (err) goto free; af_alg_pull_tsgl(sk, processed, NULL, 0); @@ -242,7 +243,8 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, /* Copy AAD || CT to RX SGL buffer for in-place operation. */ err = crypto_aead_copy_sgl(null_tfm, tsgl_src, - areq->first_rsgl.sgl.sg, outlen); + areq->first_rsgl.sgl.sgt.sgl, + outlen); if (err) goto free; @@ -267,10 +269,10 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, if (usedpages) { /* RX SGL present */ struct af_alg_sgl *sgl_prev = &areq->last_rsgl->sgl; + struct scatterlist *sg = sgl_prev->sgt.sgl; - sg_unmark_end(sgl_prev->sg + sgl_prev->npages - 1); - sg_chain(sgl_prev->sg, sgl_prev->npages + 1, - areq->tsgl); + sg_unmark_end(sg + sgl_prev->sgt.nents - 1); + sg_chain(sg, sgl_prev->sgt.nents + 1, areq->tsgl); } else /* no RX SGL present (e.g. authentication only) */ rsgl_src = areq->tsgl; @@ -278,7 +280,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, /* Initialize the crypto operation */ aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, - areq->first_rsgl.sgl.sg, used, ctx->iv); + areq->first_rsgl.sgl.sgt.sgl, used, ctx->iv); aead_request_set_ad(&areq->cra_u.aead_req, ctx->aead_assoclen); aead_request_set_tfm(&areq->cra_u.aead_req, tfm); diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 63af72e19fa8..16c69c4b9c62 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -91,13 +91,21 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, if (len > limit) len = limit; - len = af_alg_make_sg(&ctx->sgl, &msg->msg_iter, len); + ctx->sgl.sgt.sgl = ctx->sgl.sgl; + ctx->sgl.sgt.nents = 0; + ctx->sgl.sgt.orig_nents = 0; + + len = extract_iter_to_sg(&msg->msg_iter, len, &ctx->sgl.sgt, + ALG_MAX_PAGES, 0); if (len < 0) { err = copied ? 0 : len; goto unlock; } + sg_mark_end(ctx->sgl.sgt.sgl + ctx->sgl.sgt.nents); + + ctx->sgl.need_unpin = iov_iter_extract_will_pin(&msg->msg_iter); - ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, NULL, len); + ahash_request_set_crypt(&ctx->req, ctx->sgl.sgt.sgl, NULL, len); err = crypto_wait_req(crypto_ahash_update(&ctx->req), &ctx->wait); @@ -141,8 +149,8 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page, flags |= MSG_MORE; lock_sock(sk); - sg_init_table(ctx->sgl.sg, 1); - sg_set_page(ctx->sgl.sg, page, size, offset); + sg_init_table(ctx->sgl.sgl, 1); + sg_set_page(ctx->sgl.sgl, page, size, offset); if (!(flags & MSG_MORE)) { err = hash_alloc_result(sk, ctx); @@ -151,7 +159,7 @@ static ssize_t hash_sendpage(struct socket *sock, struct page *page, } else if (!ctx->more) hash_free_result(sk, ctx); - ahash_request_set_crypt(&ctx->req, ctx->sgl.sg, ctx->result, size); + ahash_request_set_crypt(&ctx->req, ctx->sgl.sgl, ctx->result, size); if (!(flags & MSG_MORE)) { if (ctx->more) diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index ee8890ee8f33..a251cd6bd5b9 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -105,7 +105,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, /* Initialize the crypto operation */ skcipher_request_set_tfm(&areq->cra_u.skcipher_req, tfm); skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, - areq->first_rsgl.sgl.sg, len, ctx->iv); + areq->first_rsgl.sgl.sgt.sgl, len, ctx->iv); if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { /* AIO operation */ diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 46494b33f5bc..34224e77f5a2 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -56,9 +56,8 @@ struct af_alg_type { }; struct af_alg_sgl { - struct scatterlist sg[ALG_MAX_PAGES + 1]; - struct page *pages[ALG_MAX_PAGES]; - unsigned int npages; + struct sg_table sgt; + struct scatterlist sgl[ALG_MAX_PAGES + 1]; bool need_unpin; }; @@ -164,7 +163,6 @@ int af_alg_release(struct socket *sock); void af_alg_release_parent(struct sock *sk); int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern); -int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len); void af_alg_free_sg(struct af_alg_sgl *sgl); static inline struct alg_sock *alg_sk(struct sock *sk) -- cgit v1.2.3 From 73d7409cfdad7fd08a9203eb2912c1c77e527776 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:53 +0100 Subject: crypto: af_alg: Indent the loop in af_alg_sendmsg() Put the loop in af_alg_sendmsg() into an if-statement to indent it to make the next patch easier to review as that will add another branch to handle MSG_SPLICE_PAGES to the if-statement. Signed-off-by: David Howells cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org Acked-by: Herbert Xu Signed-off-by: Paolo Abeni --- crypto/af_alg.c | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index b8bf6d8525ba..fd56ccff6fed 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1030,35 +1030,38 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, if (sgl->cur) sg_unmark_end(sg + sgl->cur - 1); - do { - struct page *pg; - unsigned int i = sgl->cur; + if (1 /* TODO check MSG_SPLICE_PAGES */) { + do { + struct page *pg; + unsigned int i = sgl->cur; - plen = min_t(size_t, len, PAGE_SIZE); + plen = min_t(size_t, len, PAGE_SIZE); - pg = alloc_page(GFP_KERNEL); - if (!pg) { - err = -ENOMEM; - goto unlock; - } + pg = alloc_page(GFP_KERNEL); + if (!pg) { + err = -ENOMEM; + goto unlock; + } - sg_assign_page(sg + i, pg); + sg_assign_page(sg + i, pg); - err = memcpy_from_msg(page_address(sg_page(sg + i)), - msg, plen); - if (err) { - __free_page(sg_page(sg + i)); - sg_assign_page(sg + i, NULL); - goto unlock; - } + err = memcpy_from_msg( + page_address(sg_page(sg + i)), + msg, plen); + if (err) { + __free_page(sg_page(sg + i)); + sg_assign_page(sg + i, NULL); + goto unlock; + } - sg[i].length = plen; - len -= plen; - ctx->used += plen; - copied += plen; - size -= plen; - sgl->cur++; - } while (len && sgl->cur < MAX_SGL_ENTS); + sg[i].length = plen; + len -= plen; + ctx->used += plen; + copied += plen; + size -= plen; + sgl->cur++; + } while (len && sgl->cur < MAX_SGL_ENTS); + } if (!size) sg_mark_end(sg + sgl->cur - 1); -- cgit v1.2.3 From bf63e250c4b1f21696599e0ab7117f4429dcbdc0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:54 +0100 Subject: crypto: af_alg: Support MSG_SPLICE_PAGES Make AF_ALG sendmsg() support MSG_SPLICE_PAGES. This causes pages to be spliced from the source iterator. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org Acked-by: Herbert Xu Signed-off-by: Paolo Abeni --- crypto/af_alg.c | 24 ++++++++++++++++++++++-- crypto/algif_aead.c | 22 +++++++++++----------- crypto/algif_skcipher.c | 8 ++++---- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index fd56ccff6fed..9c12530d604a 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -985,7 +985,7 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, while (size) { struct scatterlist *sg; size_t len = size; - size_t plen; + ssize_t plen; /* use the existing memory in an allocated page */ if (ctx->merge) { @@ -1030,7 +1030,27 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, if (sgl->cur) sg_unmark_end(sg + sgl->cur - 1); - if (1 /* TODO check MSG_SPLICE_PAGES */) { + if (msg->msg_flags & MSG_SPLICE_PAGES) { + struct sg_table sgtable = { + .sgl = sg, + .nents = sgl->cur, + .orig_nents = sgl->cur, + }; + + plen = extract_iter_to_sg(&msg->msg_iter, len, &sgtable, + MAX_SGL_ENTS, 0); + if (plen < 0) { + err = plen; + goto unlock; + } + + for (; sgl->cur < sgtable.nents; sgl->cur++) + get_page(sg_page(&sg[sgl->cur])); + len -= plen; + ctx->used += plen; + copied += plen; + size -= plen; + } else { do { struct page *pg; unsigned int i = sgl->cur; diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 829878025dba..35bfa283748d 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -9,8 +9,8 @@ * The following concept of the memory management is used: * * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is - * filled by user space with the data submitted via sendpage/sendmsg. Filling - * up the TX SGL does not cause a crypto operation -- the data will only be + * filled by user space with the data submitted via sendpage. Filling up + * the TX SGL does not cause a crypto operation -- the data will only be * tracked by the kernel. Upon receipt of one recvmsg call, the caller must * provide a buffer which is tracked with the RX SGL. * @@ -113,19 +113,19 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, } /* - * Data length provided by caller via sendmsg/sendpage that has not - * yet been processed. + * Data length provided by caller via sendmsg that has not yet been + * processed. */ used = ctx->used; /* - * Make sure sufficient data is present -- note, the same check is - * also present in sendmsg/sendpage. The checks in sendpage/sendmsg - * shall provide an information to the data sender that something is - * wrong, but they are irrelevant to maintain the kernel integrity. - * We need this check here too in case user space decides to not honor - * the error message in sendmsg/sendpage and still call recvmsg. This - * check here protects the kernel integrity. + * Make sure sufficient data is present -- note, the same check is also + * present in sendmsg. The checks in sendmsg shall provide an + * information to the data sender that something is wrong, but they are + * irrelevant to maintain the kernel integrity. We need this check + * here too in case user space decides to not honor the error message + * in sendmsg and still call recvmsg. This check here protects the + * kernel integrity. */ if (!aead_sufficient_data(sk)) return -EINVAL; diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index a251cd6bd5b9..b1f321b9f846 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -9,10 +9,10 @@ * The following concept of the memory management is used: * * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is - * filled by user space with the data submitted via sendpage/sendmsg. Filling - * up the TX SGL does not cause a crypto operation -- the data will only be - * tracked by the kernel. Upon receipt of one recvmsg call, the caller must - * provide a buffer which is tracked with the RX SGL. + * filled by user space with the data submitted via sendmsg. Filling up the TX + * SGL does not cause a crypto operation -- the data will only be tracked by + * the kernel. Upon receipt of one recvmsg call, the caller must provide a + * buffer which is tracked with the RX SGL. * * During the processing of the recvmsg operation, the cipher request is * allocated and prepared. As part of the recvmsg operation, the processed -- cgit v1.2.3 From fb800fa4c1f5aee1238267252e88a7837e645c02 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:55 +0100 Subject: crypto: af_alg: Convert af_alg_sendpage() to use MSG_SPLICE_PAGES Convert af_alg_sendpage() to use sendmsg() with MSG_SPLICE_PAGES rather than directly splicing in the pages itself. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org Acked-by: Herbert Xu Signed-off-by: Paolo Abeni --- crypto/af_alg.c | 52 ++++++++-------------------------------------------- 1 file changed, 8 insertions(+), 44 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 9c12530d604a..3cf734835ccb 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1114,53 +1114,17 @@ EXPORT_SYMBOL_GPL(af_alg_sendmsg); ssize_t af_alg_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) { - struct sock *sk = sock->sk; - struct alg_sock *ask = alg_sk(sk); - struct af_alg_ctx *ctx = ask->private; - struct af_alg_tsgl *sgl; - int err = -EINVAL; + struct bio_vec bvec; + struct msghdr msg = { + .msg_flags = flags | MSG_SPLICE_PAGES, + }; if (flags & MSG_SENDPAGE_NOTLAST) - flags |= MSG_MORE; - - lock_sock(sk); - if (!ctx->more && ctx->used) - goto unlock; - - if (!size) - goto done; - - if (!af_alg_writable(sk)) { - err = af_alg_wait_for_wmem(sk, flags); - if (err) - goto unlock; - } - - err = af_alg_alloc_tsgl(sk); - if (err) - goto unlock; - - ctx->merge = 0; - sgl = list_entry(ctx->tsgl_list.prev, struct af_alg_tsgl, list); - - if (sgl->cur) - sg_unmark_end(sgl->sg + sgl->cur - 1); - - sg_mark_end(sgl->sg + sgl->cur); - - get_page(page); - sg_set_page(sgl->sg + sgl->cur, page, size, offset); - sgl->cur++; - ctx->used += size; - -done: - ctx->more = flags & MSG_MORE; - -unlock: - af_alg_data_wakeup(sk); - release_sock(sk); + msg.msg_flags |= MSG_MORE; - return err ?: size; + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + return sock_sendmsg(sock, &msg); } EXPORT_SYMBOL_GPL(af_alg_sendpage); -- cgit v1.2.3 From c662b043cdca89bf0f03fc37251000ac69a3a548 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 6 Jun 2023 14:08:56 +0100 Subject: crypto: af_alg/hash: Support MSG_SPLICE_PAGES Make AF_ALG sendmsg() support MSG_SPLICE_PAGES in the hashing code. This causes pages to be spliced from the source iterator if possible. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org Acked-by: Herbert Xu Signed-off-by: Paolo Abeni --- crypto/af_alg.c | 11 ++++-- crypto/algif_hash.c | 100 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 70 insertions(+), 41 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 3cf734835ccb..7d4b6016b83d 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -542,9 +542,14 @@ void af_alg_free_sg(struct af_alg_sgl *sgl) { int i; - if (sgl->need_unpin) - for (i = 0; i < sgl->sgt.nents; i++) - unpin_user_page(sg_page(&sgl->sgt.sgl[i])); + if (sgl->sgt.sgl) { + if (sgl->need_unpin) + for (i = 0; i < sgl->sgt.nents; i++) + unpin_user_page(sg_page(&sgl->sgt.sgl[i])); + if (sgl->sgt.sgl != sgl->sgl) + kvfree(sgl->sgt.sgl); + sgl->sgt.sgl = NULL; + } } EXPORT_SYMBOL_GPL(af_alg_free_sg); diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 16c69c4b9c62..1a2d80c6c91a 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -63,78 +63,102 @@ static void hash_free_result(struct sock *sk, struct hash_ctx *ctx) static int hash_sendmsg(struct socket *sock, struct msghdr *msg, size_t ignored) { - int limit = ALG_MAX_PAGES * PAGE_SIZE; struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); struct hash_ctx *ctx = ask->private; - long copied = 0; + ssize_t copied = 0; + size_t len, max_pages, npages; + bool continuing = ctx->more, need_init = false; int err; - if (limit > sk->sk_sndbuf) - limit = sk->sk_sndbuf; + max_pages = min_t(size_t, ALG_MAX_PAGES, + DIV_ROUND_UP(sk->sk_sndbuf, PAGE_SIZE)); lock_sock(sk); - if (!ctx->more) { + if (!continuing) { if ((msg->msg_flags & MSG_MORE)) hash_free_result(sk, ctx); - - err = crypto_wait_req(crypto_ahash_init(&ctx->req), &ctx->wait); - if (err) - goto unlock; + need_init = true; } ctx->more = false; while (msg_data_left(msg)) { - int len = msg_data_left(msg); - - if (len > limit) - len = limit; - ctx->sgl.sgt.sgl = ctx->sgl.sgl; ctx->sgl.sgt.nents = 0; ctx->sgl.sgt.orig_nents = 0; - len = extract_iter_to_sg(&msg->msg_iter, len, &ctx->sgl.sgt, - ALG_MAX_PAGES, 0); - if (len < 0) { - err = copied ? 0 : len; - goto unlock; + err = -EIO; + npages = iov_iter_npages(&msg->msg_iter, max_pages); + if (npages == 0) + goto unlock_free; + + if (npages > ARRAY_SIZE(ctx->sgl.sgl)) { + err = -ENOMEM; + ctx->sgl.sgt.sgl = + kvmalloc(array_size(npages, + sizeof(*ctx->sgl.sgt.sgl)), + GFP_KERNEL); + if (!ctx->sgl.sgt.sgl) + goto unlock_free; } - sg_mark_end(ctx->sgl.sgt.sgl + ctx->sgl.sgt.nents); + sg_init_table(ctx->sgl.sgl, npages); ctx->sgl.need_unpin = iov_iter_extract_will_pin(&msg->msg_iter); - ahash_request_set_crypt(&ctx->req, ctx->sgl.sgt.sgl, NULL, len); + err = extract_iter_to_sg(&msg->msg_iter, LONG_MAX, + &ctx->sgl.sgt, npages, 0); + if (err < 0) + goto unlock_free; + len = err; + sg_mark_end(ctx->sgl.sgt.sgl + ctx->sgl.sgt.nents - 1); - err = crypto_wait_req(crypto_ahash_update(&ctx->req), - &ctx->wait); - af_alg_free_sg(&ctx->sgl); - if (err) { - iov_iter_revert(&msg->msg_iter, len); - goto unlock; + if (!msg_data_left(msg)) { + err = hash_alloc_result(sk, ctx); + if (err) + goto unlock_free; } - copied += len; - } + ahash_request_set_crypt(&ctx->req, ctx->sgl.sgt.sgl, + ctx->result, len); - err = 0; + if (!msg_data_left(msg) && !continuing && + !(msg->msg_flags & MSG_MORE)) { + err = crypto_ahash_digest(&ctx->req); + } else { + if (need_init) { + err = crypto_wait_req( + crypto_ahash_init(&ctx->req), + &ctx->wait); + if (err) + goto unlock_free; + need_init = false; + } + + if (msg_data_left(msg) || (msg->msg_flags & MSG_MORE)) + err = crypto_ahash_update(&ctx->req); + else + err = crypto_ahash_finup(&ctx->req); + continuing = true; + } - ctx->more = msg->msg_flags & MSG_MORE; - if (!ctx->more) { - err = hash_alloc_result(sk, ctx); + err = crypto_wait_req(err, &ctx->wait); if (err) - goto unlock; + goto unlock_free; - ahash_request_set_crypt(&ctx->req, NULL, ctx->result, 0); - err = crypto_wait_req(crypto_ahash_final(&ctx->req), - &ctx->wait); + copied += len; + af_alg_free_sg(&ctx->sgl); } + ctx->more = msg->msg_flags & MSG_MORE; + err = 0; unlock: release_sock(sk); + return copied ?: err; - return err ?: copied; +unlock_free: + af_alg_free_sg(&ctx->sgl); + goto unlock; } static ssize_t hash_sendpage(struct socket *sock, struct page *page, -- cgit v1.2.3 From 9c52e8bf07c7097e09503fcad7cb156deffef619 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Wed, 31 May 2023 14:07:10 +0800 Subject: wifi: rtw89: 8851b: enable hw_scan support This enables hw_scan for 8851b after firmware version 0.29.37.1. Extend the channel info struct with padding zeros so newer firmware can work properly, this change is backward compatible with older firmware. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230531060713.57203-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + drivers/net/wireless/realtek/rtw89/fw.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index f7f40a261c96..4bb90d9e00d2 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -257,6 +257,7 @@ struct __fw_feat_cfg { static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index dd71beb152ae..78d808f1e8c8 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -243,7 +243,7 @@ struct rtw89_fw_macid_pause_grp { #define RTW89_SCANOFLD_MAX_IE_LEN 512 #define RTW89_SCANOFLD_PKT_NONE 0xFF #define RTW89_SCANOFLD_DEBUG_MASK 0x1F -#define RTW89_MAC_CHINFO_SIZE 24 +#define RTW89_MAC_CHINFO_SIZE 28 #define RTW89_SCAN_LIST_GUARD 4 #define RTW89_SCAN_LIST_LIMIT \ ((RTW89_H2C_MAX_SIZE / RTW89_MAC_CHINFO_SIZE) - RTW89_SCAN_LIST_GUARD) -- cgit v1.2.3 From b25e755e5e418aa7b537b8b2a2506c34c53df2d5 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 May 2023 14:07:11 +0800 Subject: wifi: rtw89: debug: txpwr table access only valid page according to chip We now support RTL8851B which has only single RF path. For chip with single RF path, TX power page is valid only in single path section. So, we refine debugfs txpwr table to access TX power page according to RF path number of runtime chip. It can prevent us from reading beyond valid sections. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230531060713.57203-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/debug.c | 13 ++++++++++++- drivers/net/wireless/realtek/rtw89/reg.h | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index 39f6b7f5f656..1db2d59d33ff 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -376,6 +376,7 @@ struct txpwr_map { u8 size; u32 addr_from; u32 addr_to; + u32 addr_to_1ss; }; #define __GEN_TXPWR_ENT2(_t, _e0, _e1) \ @@ -413,6 +414,7 @@ static const struct txpwr_map __txpwr_map_byr = { .size = ARRAY_SIZE(__txpwr_ent_byr), .addr_from = R_AX_PWR_BY_RATE, .addr_to = R_AX_PWR_BY_RATE_MAX, + .addr_to_1ss = R_AX_PWR_BY_RATE_1SS_MAX, }; static const struct txpwr_ent __txpwr_ent_lmt[] = { @@ -468,6 +470,7 @@ static const struct txpwr_map __txpwr_map_lmt = { .size = ARRAY_SIZE(__txpwr_ent_lmt), .addr_from = R_AX_PWR_LMT, .addr_to = R_AX_PWR_LMT_MAX, + .addr_to_1ss = R_AX_PWR_LMT_1SS_MAX, }; static const struct txpwr_ent __txpwr_ent_lmt_ru[] = { @@ -495,6 +498,7 @@ static const struct txpwr_map __txpwr_map_lmt_ru = { .size = ARRAY_SIZE(__txpwr_ent_lmt_ru), .addr_from = R_AX_PWR_RU_LMT, .addr_to = R_AX_PWR_RU_LMT_MAX, + .addr_to_1ss = R_AX_PWR_RU_LMT_1SS_MAX, }; static u8 __print_txpwr_ent(struct seq_file *m, const struct txpwr_ent *ent, @@ -527,6 +531,8 @@ static int __print_txpwr_map(struct seq_file *m, struct rtw89_dev *rtwdev, const struct txpwr_map *map) { u8 fct = rtwdev->chip->txpwr_factor_mac; + u8 path_num = rtwdev->chip->rf_path_num; + u32 max_valid_addr; u32 val, addr; s8 *buf, tmp; u8 cur, i; @@ -536,7 +542,12 @@ static int __print_txpwr_map(struct seq_file *m, struct rtw89_dev *rtwdev, if (!buf) return -ENOMEM; - for (addr = map->addr_from; addr <= map->addr_to; addr += 4) { + if (path_num == 1) + max_valid_addr = map->addr_to_1ss; + else + max_valid_addr = map->addr_to; + + for (addr = map->addr_from; addr <= max_valid_addr; addr += 4) { ret = rtw89_mac_txpwr_read32(rtwdev, RTW89_PHY_0, addr, &val); if (ret) val = MASKDWORD; diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 7c2807345f60..b6ffa923133d 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3342,16 +3342,22 @@ #define B_AX_PWR_UL_TB_2T_MASK GENMASK(4, 0) #define B_AX_PWR_UL_TB_2T_V1_MASK GENMASK(7, 0) #define R_AX_PWR_BY_RATE_TABLE0 0xD2C0 +#define R_AX_PWR_BY_RATE_TABLE6 0xD2D8 #define R_AX_PWR_BY_RATE_TABLE10 0xD2E8 #define R_AX_PWR_BY_RATE R_AX_PWR_BY_RATE_TABLE0 +#define R_AX_PWR_BY_RATE_1SS_MAX R_AX_PWR_BY_RATE_TABLE6 #define R_AX_PWR_BY_RATE_MAX R_AX_PWR_BY_RATE_TABLE10 #define R_AX_PWR_LMT_TABLE0 0xD2EC +#define R_AX_PWR_LMT_TABLE9 0xD310 #define R_AX_PWR_LMT_TABLE19 0xD338 #define R_AX_PWR_LMT R_AX_PWR_LMT_TABLE0 +#define R_AX_PWR_LMT_1SS_MAX R_AX_PWR_LMT_TABLE9 #define R_AX_PWR_LMT_MAX R_AX_PWR_LMT_TABLE19 #define R_AX_PWR_RU_LMT_TABLE0 0xD33C +#define R_AX_PWR_RU_LMT_TABLE5 0xD350 #define R_AX_PWR_RU_LMT_TABLE11 0xD368 #define R_AX_PWR_RU_LMT R_AX_PWR_RU_LMT_TABLE0 +#define R_AX_PWR_RU_LMT_1SS_MAX R_AX_PWR_RU_LMT_TABLE5 #define R_AX_PWR_RU_LMT_MAX R_AX_PWR_RU_LMT_TABLE11 #define R_AX_PWR_MACID_LMT_TABLE0 0xD36C #define R_AX_PWR_MACID_LMT_TABLE127 0xD568 -- cgit v1.2.3 From db67b03b04b4363251c0d8eecaf7a631449b6f3d Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 May 2023 14:07:12 +0800 Subject: wifi: rtw89: set TX power without precondition during setting channel The key condition to check in wrapper of setting TX power is whether entity is active or not. Before entity is active, we restrict TX power from being set by outside callers, e.g. SAR/regulatory. We mark entity as inactive when powering off MAC. Then, we will mark it as active when we initialize HW channel stuffs after MAC power on. Although we can get an active entity after leaving idle phase, TX power doesn't be set well for default channel until stack set target channel for connection. It causes that RF things cannot use better TX power during this interval. Below are some cases which may encounter this or a similar situation. * hw scan process before connection As described above. * right after restart hardware process (SER L2) HW stuffs of target channel is initialized after mac80211 restart hardware, but we unexpectedly need to wait one more command to set channel again or to set TX power. To fix it and improve RF behavior in that interval, during setting channel, we don't need to check entity state before setting TX power, which actually is used to restrict outside callers. It means we call chip ops directly to replace the wrapper call. Then, TX power can be initialized as long as we initialize/setup HW stuffs on one channel. Besides, all chips should configure ops of setting TX power, so we remove trivial check on pointer. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230531060713.57203-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 65581ca506d3..5b5337890c76 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -336,8 +336,7 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev) sub_entity_idx = RTW89_SUB_ENTITY_0; phy_idx = RTW89_PHY_0; chan = rtw89_chan_get(rtwdev, sub_entity_idx); - if (chip->ops->set_txpwr) - chip->ops->set_txpwr(rtwdev, chan, phy_idx); + chip->ops->set_txpwr(rtwdev, chan, phy_idx); } void rtw89_set_channel(struct rtw89_dev *rtwdev) @@ -373,7 +372,7 @@ void rtw89_set_channel(struct rtw89_dev *rtwdev) chip->ops->set_channel(rtwdev, &chan, mac_idx, phy_idx); - rtw89_core_set_chip_txpwr(rtwdev); + chip->ops->set_txpwr(rtwdev, &chan, phy_idx); rtw89_chip_set_channel_done(rtwdev, &bak, &chan, mac_idx, phy_idx); -- cgit v1.2.3 From 57369e2aa2eb9812368c6cf3c4378d1fbe9e8c8a Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 31 May 2023 14:07:13 +0800 Subject: wifi: rtw89: 8851b: configure CRASH_TRIGGER feature for 8851B RTL8851B firmware supports CRASH_TRIGGER feature from v0.29.41.0. After this is configured, debugfs fw_crash can support type 1 on RTL8851B to trigger firmware crash and verify L2 recovery through simulation. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230531060713.57203-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 4bb90d9e00d2..65202f82e3be 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -258,6 +258,7 @@ struct __fw_feat_cfg { static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), -- cgit v1.2.3 From b7d170d5a670de8d30d2db94179099f52f8df485 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 2 Jun 2023 23:05:49 +0800 Subject: wifi: rtw89: refine clearing supported bands to check 2/5 GHz first We refine to check if supported bands of NL80211_BAND_2GHZ and NL80211_BAND_5GHZ exist before freeing their iftype_data. For now, it does not really encounter problems because all current chips support both 2 GHz and 5 GHz. But, driver actually allows chips to declare whether 2/5 GHz are supported or not. In case some future chips really don't support them, we refine this code. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602150556.36777-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 5b5337890c76..33d47933eafc 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -3386,8 +3386,10 @@ static void rtw89_core_clr_supported_band(struct rtw89_dev *rtwdev) { struct ieee80211_hw *hw = rtwdev->hw; - kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data); - kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data); + if (hw->wiphy->bands[NL80211_BAND_2GHZ]) + kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data); + if (hw->wiphy->bands[NL80211_BAND_5GHZ]) + kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data); if (hw->wiphy->bands[NL80211_BAND_6GHZ]) kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data); kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]); -- cgit v1.2.3 From ffc23511531341936dbddd24ba0e3a08bcdda01c Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 2 Jun 2023 23:05:50 +0800 Subject: wifi: rtw89: regd: judge 6 GHz according to chip and BIOS We allow platform to disable 6 GHz on chips, which supports 6 GHz, through BIOS. Driver will evaluate Realtek acpi DSM with RTW89_ACPI_DSM_FUNC_6G_DIS (function 3) to get whether 6 GHz should be disabled. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602150556.36777-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/regd.c | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 377a7a1c560b..43e589c023af 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -330,6 +330,55 @@ bottom: sband->n_channels -= 3; } +static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + bool chip_support_6ghz = chip->support_bands & BIT(NL80211_BAND_6GHZ); + bool regd_allow_6ghz = chip_support_6ghz; + struct ieee80211_supported_band *sband; + int ret; + u8 val; + + if (!chip_support_6ghz) + goto bottom; + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &val); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval 6ghz: %d\n", ret); + goto bottom; + } + + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: eval if disallow 6ghz: %d\n", val); + + switch (val) { + case 0: + regd_allow_6ghz = true; + break; + case 1: + regd_allow_6ghz = false; + break; + default: + break; + } + +bottom: + rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow 6ghz: %d\n", + regd_allow_6ghz); + + if (regd_allow_6ghz) + return; + + sband = wiphy->bands[NL80211_BAND_6GHZ]; + if (!sband) + return; + + wiphy->bands[NL80211_BAND_6GHZ] = NULL; + kfree(sband->iftype_data); + kfree(sband); +} + int rtw89_regd_setup(struct rtw89_dev *rtwdev) { struct wiphy *wiphy = rtwdev->hw->wiphy; @@ -338,6 +387,7 @@ int rtw89_regd_setup(struct rtw89_dev *rtwdev) return -EINVAL; rtw89_regd_setup_unii4(rtwdev, wiphy); + rtw89_regd_setup_6ghz(rtwdev, wiphy); wiphy->reg_notifier = rtw89_regd_notifier; return 0; -- cgit v1.2.3 From 9468046ff54eb5b72616c8126105bbf2df711253 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 2 Jun 2023 23:05:51 +0800 Subject: wifi: rtw89: regd: update regulatory map to R64-R40 Update notes: According to Realtek Regulatory R40 and Realtek Channel Plan R64, configure rtw89_regulatory mapping of 6 GHz for more countries and adjust rtw89_regulatory mapping of 2/5 GHz for a few countries. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602150556.36777-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/regd.c | 122 +++++++++++++++--------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 43e589c023af..89e027d846af 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -16,20 +16,20 @@ static const struct rtw89_regulatory rtw89_ww_regd = static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("AR", RTW89_MEXICO, RTW89_MEXICO, RTW89_NA), - COUNTRY_REGD("BO", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("BO", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("BR", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("CL", RTW89_CHILE, RTW89_CHILE, RTW89_CHILE), - COUNTRY_REGD("CO", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("CO", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("CR", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("EC", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("SV", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("GT", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("SV", RTW89_FCC, RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("GT", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("HN", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("MX", RTW89_MEXICO, RTW89_MEXICO, RTW89_NA), COUNTRY_REGD("NI", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("PA", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("PY", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("PE", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("PE", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("US", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("UY", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("VE", RTW89_FCC, RTW89_FCC, RTW89_NA), @@ -66,37 +66,37 @@ static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("CH", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("GB", RTW89_UK, RTW89_UK, RTW89_UK), COUNTRY_REGD("AL", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("AZ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("BH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("AZ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("BH", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("BA", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("BG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("HR", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("BG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("HR", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("EG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("GH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("GH", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("IQ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("IL", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("JO", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("IL", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("JO", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("KZ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("KE", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("KW", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("KG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("KE", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KW", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("KG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("LB", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("LS", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("MK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("MA", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("MA", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("MZ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("NA", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("NG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("OM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("QA", RTW89_QATAR, RTW89_QATAR, RTW89_QATAR), - COUNTRY_REGD("RO", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("RO", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("RU", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("SA", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("SA", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("SN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("RS", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("RS", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("ME", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("ZA", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("TR", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("TR", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("UA", RTW89_UKRAINE, RTW89_UKRAINE, RTW89_UKRAINE), COUNTRY_REGD("AE", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("YE", RTW89_ETSI, RTW89_ETSI, RTW89_NA), @@ -104,11 +104,11 @@ static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("BD", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("KH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("CN", RTW89_CN, RTW89_CN, RTW89_CN), - COUNTRY_REGD("HK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("HK", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("IN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("ID", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("KR", RTW89_KCC, RTW89_KCC, RTW89_KCC), - COUNTRY_REGD("MY", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("MY", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("PK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("PH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), @@ -116,55 +116,55 @@ static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("TH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA, RTW89_NA), - COUNTRY_REGD("NZ", RTW89_ACMA, RTW89_ACMA, RTW89_NA), - COUNTRY_REGD("PG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA), + COUNTRY_REGD("NZ", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA), + COUNTRY_REGD("PG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("CA", RTW89_IC, RTW89_IC, RTW89_IC), - COUNTRY_REGD("JP", RTW89_MKK, RTW89_MKK, RTW89_NA), - COUNTRY_REGD("JM", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("AN", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("JP", RTW89_MKK, RTW89_MKK, RTW89_MKK), + COUNTRY_REGD("JM", RTW89_FCC, RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("AN", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("TT", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("TN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("AF", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("DZ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("DZ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("AS", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("AD", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("AO", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("AI", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("AI", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("AQ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("AG", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("AM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("AW", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("BS", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("BB", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("AG", RTW89_FCC, RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("AM", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("AW", RTW89_FCC, RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("BS", RTW89_FCC, RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("BB", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("BY", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("BZ", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("BJ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("BM", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("BM", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("BT", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("BW", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("BW", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("BV", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("IO", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("VG", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("VG", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("BN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("BF", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("MM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("BI", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("BI", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("CM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("CV", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("KY", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("KY", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("CF", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("TD", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("TD", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("CX", RTW89_ACMA, RTW89_ACMA, RTW89_NA), - COUNTRY_REGD("CC", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("KM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("CC", RTW89_ACMA, RTW89_ACMA, RTW89_NA), + COUNTRY_REGD("KM", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("CG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("CD", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("CK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("CI", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("DJ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("DM", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("GQ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("DJ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), + COUNTRY_REGD("DM", RTW89_FCC, RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("GQ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("ER", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("ET", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("FK", RTW89_ETSI, RTW89_ETSI, RTW89_NA), @@ -174,17 +174,17 @@ static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("PF", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("TF", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GA", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("GM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("GM", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("GE", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GI", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GU", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("GG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("GN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("GN", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("GW", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("GY", RTW89_NCC, RTW89_NCC, RTW89_NA), + COUNTRY_REGD("GY", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("HT", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("HM", RTW89_ACMA, RTW89_ACMA, RTW89_NA), COUNTRY_REGD("VA", RTW89_ETSI, RTW89_ETSI, RTW89_NA), @@ -195,17 +195,17 @@ static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("LR", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("LY", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("MO", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("MG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("MG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("MW", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("MV", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("ML", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("MH", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("MQ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("MR", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("MU", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("MU", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("YT", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("FM", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("MD", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("MD", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("MN", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("MS", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("NR", RTW89_ETSI, RTW89_ETSI, RTW89_NA), @@ -219,26 +219,26 @@ static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("RE", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("RW", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("SH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("KN", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("LC", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("KN", RTW89_FCC, RTW89_FCC, RTW89_FCC), + COUNTRY_REGD("LC", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("MF", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("SX", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("PM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("VC", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("WS", RTW89_FCC, RTW89_FCC, RTW89_NA), COUNTRY_REGD("SM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("ST", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("ST", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("SC", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("SL", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("SL", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("SB", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("SO", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("GS", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("SR", RTW89_FCC, RTW89_FCC, RTW89_NA), + COUNTRY_REGD("SR", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("SJ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("SZ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("TJ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("TJ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("TZ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), - COUNTRY_REGD("TG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("TG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("TK", RTW89_ACMA, RTW89_ACMA, RTW89_NA), COUNTRY_REGD("TO", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("TM", RTW89_ETSI, RTW89_ETSI, RTW89_NA), @@ -246,7 +246,7 @@ static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("TV", RTW89_ETSI, RTW89_NA, RTW89_NA), COUNTRY_REGD("UG", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("VI", RTW89_FCC, RTW89_FCC, RTW89_NA), - COUNTRY_REGD("UZ", RTW89_ETSI, RTW89_ETSI, RTW89_NA), + COUNTRY_REGD("UZ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI), COUNTRY_REGD("VU", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("WF", RTW89_ETSI, RTW89_ETSI, RTW89_NA), COUNTRY_REGD("EH", RTW89_ETSI, RTW89_ETSI, RTW89_NA), -- cgit v1.2.3 From f6baa1d3d5703fe65b87b3149265a1c7f564f450 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 2 Jun 2023 23:05:52 +0800 Subject: wifi: rtw89: process regulatory for 6 GHz power type Configure the corresponding power type for 6 GHz regulatory if we can determine one single target. Otherwise, we use the default one. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602150556.36777-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.c | 7 ++- drivers/net/wireless/realtek/rtw89/core.h | 25 +++++++- drivers/net/wireless/realtek/rtw89/mac80211.c | 9 +++ drivers/net/wireless/realtek/rtw89/regd.c | 91 +++++++++++++++++++++++---- 4 files changed, 116 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 33d47933eafc..69b181fa2966 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2869,6 +2869,8 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { /* for station mode, assign the mac_id from itself */ rtwsta->mac_id = rtwvif->mac_id; + /* must do rtw89_reg_6ghz_power_recalc() before rfk channel */ + rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, true); rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, BTC_ROLE_MSTS_STA_CONN_START); rtw89_chip_rfk_channel(rtwdev); @@ -3042,10 +3044,11 @@ int rtw89_core_sta_remove(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; int ret; - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { + rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, false); rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta, BTC_ROLE_MSTS_STA_DIS_CONN); - else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { + } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { rtw89_core_release_bit_map(rtwdev->mac_id_map, rtwsta->mac_id); ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta, diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 6e807fa571c7..3915ab7ab8a1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -488,6 +488,15 @@ enum rtw89_regulation_type { RTW89_REGD_NUM, }; +enum rtw89_reg_6ghz_power { + RTW89_REG_6GHZ_POWER_VLP = 0, + RTW89_REG_6GHZ_POWER_LPI = 1, + RTW89_REG_6GHZ_POWER_STD = 2, + + NUM_OF_RTW89_REG_6GHZ_POWER, + RTW89_REG_6GHZ_POWER_DFLT = RTW89_REG_6GHZ_POWER_VLP, +}; + enum rtw89_fw_pkt_ofld_type { RTW89_PKT_OFLD_TYPE_PROBE_RSP = 0, RTW89_PKT_OFLD_TYPE_PS_POLL = 1, @@ -2682,6 +2691,7 @@ struct rtw89_vif { struct rtw89_dev *rtwdev; struct rtw89_roc roc; enum rtw89_sub_entity_idx sub_entity_idx; + enum rtw89_reg_6ghz_power reg_6ghz_power; u8 mac_id; u8 port; @@ -3807,11 +3817,16 @@ struct rtw89_power_trim_info { u8 pa_bias_trim[RF_PATH_MAX]; }; -struct rtw89_regulatory { +struct rtw89_regd { char alpha2[3]; u8 txpwr_regd[RTW89_BAND_MAX]; }; +struct rtw89_regulatory_info { + const struct rtw89_regd *regd; + enum rtw89_reg_6ghz_power reg_6ghz_power; +}; + enum rtw89_ifs_clm_application { RTW89_IFS_CLM_INIT = 0, RTW89_IFS_CLM_BACKGROUND = 1, @@ -4161,7 +4176,7 @@ struct rtw89_dev { u8 total_sta_assoc; bool scanning; - const struct rtw89_regulatory *regd; + struct rtw89_regulatory_info regulatory; struct rtw89_sar_info sar; struct rtw89_btc btc; @@ -4848,7 +4863,9 @@ static inline void rtw89_load_txpwr_table(struct rtw89_dev *rtwdev, static inline u8 rtw89_regd_get(struct rtw89_dev *rtwdev, u8 band) { - return rtwdev->regd->txpwr_regd[band]; + const struct rtw89_regd *regd = rtwdev->regulatory.regd; + + return regd->txpwr_regd[band]; } static inline void rtw89_ctrl_btg(struct rtw89_dev *rtwdev, bool btg) @@ -5090,5 +5107,7 @@ void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, const u8 *mac_addr, bool hw_scan); void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, bool hw_scan); +void rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool active); #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 0ffd7fb489a5..a66503eb35b8 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -146,6 +146,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw, rtwvif->phy_idx = RTW89_PHY_0; rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; rtwvif->hit_rule = 0; + rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; ether_addr_copy(rtwvif->mac_addr, vif->addr); INIT_LIST_HEAD(&rtwvif->general_pkt_list); @@ -457,8 +458,16 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + const struct rtw89_chan *chan; mutex_lock(&rtwdev->mutex); + + chan = rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx); + if (chan->band_type == RTW89_BAND_6G) { + mutex_unlock(&rtwdev->mutex); + return -EOPNOTSUPP; + } + ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); rtw89_cam_bssid_changed(rtwdev, rtwvif); rtw89_mac_port_update(rtwdev, rtwvif); diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 89e027d846af..34c4d40cfa02 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -5,16 +5,17 @@ #include "acpi.h" #include "debug.h" #include "ps.h" +#include "util.h" #define COUNTRY_REGD(_alpha2, _txpwr_regd...) \ {.alpha2 = (_alpha2), \ .txpwr_regd = {_txpwr_regd}, \ } -static const struct rtw89_regulatory rtw89_ww_regd = +static const struct rtw89_regd rtw89_ww_regd = COUNTRY_REGD("00", RTW89_WW, RTW89_WW); -static const struct rtw89_regulatory rtw89_regd_map[] = { +static const struct rtw89_regd rtw89_regd_map[] = { COUNTRY_REGD("AR", RTW89_MEXICO, RTW89_MEXICO, RTW89_NA), COUNTRY_REGD("BO", RTW89_FCC, RTW89_FCC, RTW89_FCC), COUNTRY_REGD("BR", RTW89_FCC, RTW89_FCC, RTW89_FCC), @@ -255,7 +256,7 @@ static const struct rtw89_regulatory rtw89_regd_map[] = { COUNTRY_REGD("PS", RTW89_ETSI, RTW89_ETSI, RTW89_NA), }; -static const struct rtw89_regulatory *rtw89_regd_find_reg_by_name(char *alpha2) +static const struct rtw89_regd *rtw89_regd_find_reg_by_name(char *alpha2) { u32 i; @@ -267,7 +268,7 @@ static const struct rtw89_regulatory *rtw89_regd_find_reg_by_name(char *alpha2) return &rtw89_ww_regd; } -static bool rtw89_regd_is_ww(const struct rtw89_regulatory *regd) +static bool rtw89_regd_is_ww(const struct rtw89_regd *regd) { return regd == &rtw89_ww_regd; } @@ -397,21 +398,25 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev, void (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)) { - const struct rtw89_regulatory *chip_regd; + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *chip_regd; struct wiphy *wiphy = rtwdev->hw->wiphy; int ret; + regulatory->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + if (!wiphy) return -EINVAL; chip_regd = rtw89_regd_find_reg_by_name(rtwdev->efuse.country_code); if (!rtw89_regd_is_ww(chip_regd)) { - rtwdev->regd = chip_regd; + rtwdev->regulatory.regd = chip_regd; /* Ignore country ie if there is a country domain programmed in chip */ wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; wiphy->regulatory_flags |= REGULATORY_STRICT_REG; - ret = regulatory_hint(rtwdev->hw->wiphy, rtwdev->regd->alpha2); + ret = regulatory_hint(rtwdev->hw->wiphy, + rtwdev->regulatory.regd->alpha2); if (ret) rtw89_warn(rtwdev, "failed to hint regulatory:%d\n", ret); @@ -419,7 +424,7 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev, return 0; } - rtw89_debug_regd(rtwdev, rtwdev->regd, + rtw89_debug_regd(rtwdev, rtwdev->regulatory.regd, "worldwide roaming chip, follow the setting of stack"); return 0; } @@ -428,13 +433,13 @@ static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev, struct wiphy *wiphy, struct regulatory_request *request) { - rtwdev->regd = rtw89_regd_find_reg_by_name(request->alpha2); + rtwdev->regulatory.regd = rtw89_regd_find_reg_by_name(request->alpha2); /* This notification might be set from the system of distros, * and it does not expect the regulatory will be modified by * connecting to an AP (i.e. country ie). */ if (request->initiator == NL80211_REGDOM_SET_BY_USER && - !rtw89_regd_is_ww(rtwdev->regd)) + !rtw89_regd_is_ww(rtwdev->regulatory.regd)) wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; else wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE; @@ -454,7 +459,8 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request goto exit; } rtw89_regd_notifier_apply(rtwdev, wiphy, request); - rtw89_debug_regd(rtwdev, rtwdev->regd, "get from initiator %d, alpha2", + rtw89_debug_regd(rtwdev, rtwdev->regulatory.regd, + "get from initiator %d, alpha2", request->initiator); rtw89_core_set_chip_txpwr(rtwdev); @@ -462,3 +468,66 @@ void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request exit: mutex_unlock(&rtwdev->mutex); } + +static void __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + enum rtw89_reg_6ghz_power sel; + const struct rtw89_chan *chan; + struct rtw89_vif *rtwvif; + int count = 0; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + chan = rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx); + if (chan->band_type != RTW89_BAND_6G) + continue; + + if (count != 0 && rtwvif->reg_6ghz_power == sel) + continue; + + sel = rtwvif->reg_6ghz_power; + count++; + } + + if (count != 1) + sel = RTW89_REG_6GHZ_POWER_DFLT; + + if (regulatory->reg_6ghz_power == sel) + return; + + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "recalc 6 GHz reg power type to %d\n", sel); + + regulatory->reg_6ghz_power = sel; + + rtw89_core_set_chip_txpwr(rtwdev); +} + +void rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool active) +{ + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + + lockdep_assert_held(&rtwdev->mutex); + + if (active) { + switch (vif->bss_conf.power_type) { + case IEEE80211_REG_VLP_AP: + rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_VLP; + break; + case IEEE80211_REG_LPI_AP: + rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_LPI; + break; + case IEEE80211_REG_SP_AP: + rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_STD; + break; + default: + rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + break; + } + } else { + rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + } + + __rtw89_reg_6ghz_power_recalc(rtwdev); +} -- cgit v1.2.3 From b742394cfe80a51572ff74e0a57b4b21db1489b1 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 2 Jun 2023 23:05:53 +0800 Subject: wifi: rtw89: 8852c: update TX power tables to R63 with 6 GHz power type (1 of 3) Update TX power tables to RF version R63. TX power tables' changes: * TX power byrate: tweak a bit * TX power limit, TX power limit RU, TX power shape: configure values for MEXICO, UKRAINE, CHILE, QATAR tweak a bit on other configured values * 6 GHz TX power limit, 6 GHz TX power limit RU: add an extra dimension for 6 GHz regulatory power type, i.e. STD (standard power), LPI (low power indoor), VLP (very low power) Besides, we adjust TX power handling at 6 GHz in phy to consider 6 GHz regulatory power type. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602150556.36777-6-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8852c_table.c | 3382 +++++++++++++++++--- 1 file changed, 2964 insertions(+), 418 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c index 7011e5a6f8fd..52b124fb58c6 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c @@ -28430,11 +28430,11 @@ static const struct rtw89_txpwr_byrate_cfg rtw89_8852c_txpwr_byrate[] = { { 2, 0, 1, 4, 4, 0x383c4040, }, { 2, 0, 2, 0, 4, 0x40404040, }, { 2, 0, 2, 4, 4, 0x34383c40, }, - { 2, 0, 2, 8, 4, 0x24282c30, }, + { 2, 0, 2, 8, 4, 0x20282c30, }, { 2, 0, 3, 0, 4, 0x40404040, }, { 2, 1, 2, 0, 4, 0x40404040, }, { 2, 1, 2, 4, 4, 0x34383c40, }, - { 2, 1, 2, 8, 4, 0x24282c30, }, + { 2, 1, 2, 8, 4, 0x20282c30, }, { 2, 1, 3, 0, 4, 0x40404040, }, { 2, 0, 4, 0, 4, 0x00000000, }, }; @@ -28562,32 +28562,50 @@ static const s8 _txpwr_track_delta_swingidx_2g_cck_a_p[] = { const u8 rtw89_8852c_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] [RTW89_REGD_NUM] = { [0][0][RTW89_ACMA] = 0, + [0][0][RTW89_CHILE] = 0, [0][0][RTW89_CN] = 0, [0][0][RTW89_ETSI] = 0, [0][0][RTW89_FCC] = 1, [0][0][RTW89_IC] = 1, [0][0][RTW89_KCC] = 0, + [0][0][RTW89_MEXICO] = 1, [0][0][RTW89_MKK] = 0, + [0][0][RTW89_QATAR] = 0, [0][0][RTW89_UK] = 0, + [0][0][RTW89_UKRAINE] = 0, [0][1][RTW89_ACMA] = 0, + [0][1][RTW89_CHILE] = 0, [0][1][RTW89_CN] = 0, [0][1][RTW89_ETSI] = 0, [0][1][RTW89_FCC] = 3, [0][1][RTW89_IC] = 3, [0][1][RTW89_KCC] = 0, + [0][1][RTW89_MEXICO] = 3, [0][1][RTW89_MKK] = 0, + [0][1][RTW89_QATAR] = 0, [0][1][RTW89_UK] = 0, + [0][1][RTW89_UKRAINE] = 0, [1][1][RTW89_ACMA] = 0, + [1][1][RTW89_CHILE] = 0, [1][1][RTW89_CN] = 0, [1][1][RTW89_ETSI] = 0, [1][1][RTW89_FCC] = 3, [1][1][RTW89_IC] = 3, [1][1][RTW89_KCC] = 0, + [1][1][RTW89_MEXICO] = 3, [1][1][RTW89_MKK] = 0, + [1][1][RTW89_QATAR] = 0, [1][1][RTW89_UK] = 0, + [1][1][RTW89_UKRAINE] = 0, + [2][1][RTW89_ACMA] = 0, + [2][1][RTW89_CHILE] = 0, [2][1][RTW89_ETSI] = 0, [2][1][RTW89_FCC] = 0, + [2][1][RTW89_IC] = 0, [2][1][RTW89_KCC] = 0, + [2][1][RTW89_MKK] = 0, + [2][1][RTW89_QATAR] = 0, + [2][1][RTW89_UK] = 0, }; static @@ -28770,6 +28788,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][0] = 60, [0][0][0][0][RTW89_CN][0] = 58, [0][0][0][0][RTW89_UK][0] = 60, + [0][0][0][0][RTW89_MEXICO][0] = 76, + [0][0][0][0][RTW89_UKRAINE][0] = 60, + [0][0][0][0][RTW89_CHILE][0] = 76, + [0][0][0][0][RTW89_QATAR][0] = 60, [0][0][0][0][RTW89_FCC][1] = 76, [0][0][0][0][RTW89_ETSI][1] = 60, [0][0][0][0][RTW89_MKK][1] = 68, @@ -28778,6 +28800,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][1] = 60, [0][0][0][0][RTW89_CN][1] = 58, [0][0][0][0][RTW89_UK][1] = 60, + [0][0][0][0][RTW89_MEXICO][1] = 76, + [0][0][0][0][RTW89_UKRAINE][1] = 60, + [0][0][0][0][RTW89_CHILE][1] = 68, + [0][0][0][0][RTW89_QATAR][1] = 60, [0][0][0][0][RTW89_FCC][2] = 76, [0][0][0][0][RTW89_ETSI][2] = 60, [0][0][0][0][RTW89_MKK][2] = 68, @@ -28786,6 +28812,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][2] = 60, [0][0][0][0][RTW89_CN][2] = 58, [0][0][0][0][RTW89_UK][2] = 60, + [0][0][0][0][RTW89_MEXICO][2] = 76, + [0][0][0][0][RTW89_UKRAINE][2] = 60, + [0][0][0][0][RTW89_CHILE][2] = 68, + [0][0][0][0][RTW89_QATAR][2] = 60, [0][0][0][0][RTW89_FCC][3] = 76, [0][0][0][0][RTW89_ETSI][3] = 60, [0][0][0][0][RTW89_MKK][3] = 68, @@ -28794,6 +28824,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][3] = 60, [0][0][0][0][RTW89_CN][3] = 58, [0][0][0][0][RTW89_UK][3] = 60, + [0][0][0][0][RTW89_MEXICO][3] = 76, + [0][0][0][0][RTW89_UKRAINE][3] = 60, + [0][0][0][0][RTW89_CHILE][3] = 68, + [0][0][0][0][RTW89_QATAR][3] = 60, [0][0][0][0][RTW89_FCC][4] = 76, [0][0][0][0][RTW89_ETSI][4] = 60, [0][0][0][0][RTW89_MKK][4] = 68, @@ -28802,6 +28836,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][4] = 60, [0][0][0][0][RTW89_CN][4] = 58, [0][0][0][0][RTW89_UK][4] = 60, + [0][0][0][0][RTW89_MEXICO][4] = 76, + [0][0][0][0][RTW89_UKRAINE][4] = 60, + [0][0][0][0][RTW89_CHILE][4] = 68, + [0][0][0][0][RTW89_QATAR][4] = 60, [0][0][0][0][RTW89_FCC][5] = 76, [0][0][0][0][RTW89_ETSI][5] = 60, [0][0][0][0][RTW89_MKK][5] = 68, @@ -28810,6 +28848,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][5] = 60, [0][0][0][0][RTW89_CN][5] = 58, [0][0][0][0][RTW89_UK][5] = 60, + [0][0][0][0][RTW89_MEXICO][5] = 76, + [0][0][0][0][RTW89_UKRAINE][5] = 60, + [0][0][0][0][RTW89_CHILE][5] = 76, + [0][0][0][0][RTW89_QATAR][5] = 60, [0][0][0][0][RTW89_FCC][6] = 76, [0][0][0][0][RTW89_ETSI][6] = 60, [0][0][0][0][RTW89_MKK][6] = 68, @@ -28818,6 +28860,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][6] = 60, [0][0][0][0][RTW89_CN][6] = 58, [0][0][0][0][RTW89_UK][6] = 60, + [0][0][0][0][RTW89_MEXICO][6] = 76, + [0][0][0][0][RTW89_UKRAINE][6] = 60, + [0][0][0][0][RTW89_CHILE][6] = 76, + [0][0][0][0][RTW89_QATAR][6] = 60, [0][0][0][0][RTW89_FCC][7] = 76, [0][0][0][0][RTW89_ETSI][7] = 60, [0][0][0][0][RTW89_MKK][7] = 68, @@ -28826,6 +28872,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][7] = 60, [0][0][0][0][RTW89_CN][7] = 58, [0][0][0][0][RTW89_UK][7] = 60, + [0][0][0][0][RTW89_MEXICO][7] = 76, + [0][0][0][0][RTW89_UKRAINE][7] = 60, + [0][0][0][0][RTW89_CHILE][7] = 76, + [0][0][0][0][RTW89_QATAR][7] = 60, [0][0][0][0][RTW89_FCC][8] = 76, [0][0][0][0][RTW89_ETSI][8] = 60, [0][0][0][0][RTW89_MKK][8] = 68, @@ -28834,6 +28884,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][8] = 60, [0][0][0][0][RTW89_CN][8] = 58, [0][0][0][0][RTW89_UK][8] = 60, + [0][0][0][0][RTW89_MEXICO][8] = 76, + [0][0][0][0][RTW89_UKRAINE][8] = 60, + [0][0][0][0][RTW89_CHILE][8] = 76, + [0][0][0][0][RTW89_QATAR][8] = 60, [0][0][0][0][RTW89_FCC][9] = 76, [0][0][0][0][RTW89_ETSI][9] = 60, [0][0][0][0][RTW89_MKK][9] = 68, @@ -28842,6 +28896,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][9] = 60, [0][0][0][0][RTW89_CN][9] = 58, [0][0][0][0][RTW89_UK][9] = 60, + [0][0][0][0][RTW89_MEXICO][9] = 76, + [0][0][0][0][RTW89_UKRAINE][9] = 60, + [0][0][0][0][RTW89_CHILE][9] = 76, + [0][0][0][0][RTW89_QATAR][9] = 60, [0][0][0][0][RTW89_FCC][10] = 76, [0][0][0][0][RTW89_ETSI][10] = 60, [0][0][0][0][RTW89_MKK][10] = 68, @@ -28850,6 +28908,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][10] = 60, [0][0][0][0][RTW89_CN][10] = 58, [0][0][0][0][RTW89_UK][10] = 60, + [0][0][0][0][RTW89_MEXICO][10] = 76, + [0][0][0][0][RTW89_UKRAINE][10] = 60, + [0][0][0][0][RTW89_CHILE][10] = 76, + [0][0][0][0][RTW89_QATAR][10] = 60, [0][0][0][0][RTW89_FCC][11] = 58, [0][0][0][0][RTW89_ETSI][11] = 60, [0][0][0][0][RTW89_MKK][11] = 68, @@ -28858,6 +28920,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][11] = 60, [0][0][0][0][RTW89_CN][11] = 58, [0][0][0][0][RTW89_UK][11] = 60, + [0][0][0][0][RTW89_MEXICO][11] = 58, + [0][0][0][0][RTW89_UKRAINE][11] = 60, + [0][0][0][0][RTW89_CHILE][11] = 58, + [0][0][0][0][RTW89_QATAR][11] = 60, [0][0][0][0][RTW89_FCC][12] = 46, [0][0][0][0][RTW89_ETSI][12] = 60, [0][0][0][0][RTW89_MKK][12] = 68, @@ -28866,6 +28932,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][12] = 60, [0][0][0][0][RTW89_CN][12] = 58, [0][0][0][0][RTW89_UK][12] = 60, + [0][0][0][0][RTW89_MEXICO][12] = 46, + [0][0][0][0][RTW89_UKRAINE][12] = 60, + [0][0][0][0][RTW89_CHILE][12] = 46, + [0][0][0][0][RTW89_QATAR][12] = 60, [0][0][0][0][RTW89_FCC][13] = 127, [0][0][0][0][RTW89_ETSI][13] = 127, [0][0][0][0][RTW89_MKK][13] = 72, @@ -28874,6 +28944,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][0][0][RTW89_ACMA][13] = 127, [0][0][0][0][RTW89_CN][13] = 127, [0][0][0][0][RTW89_UK][13] = 127, + [0][0][0][0][RTW89_MEXICO][13] = 127, + [0][0][0][0][RTW89_UKRAINE][13] = 127, + [0][0][0][0][RTW89_CHILE][13] = 127, + [0][0][0][0][RTW89_QATAR][13] = 127, [0][1][0][0][RTW89_FCC][0] = 76, [0][1][0][0][RTW89_ETSI][0] = 48, [0][1][0][0][RTW89_MKK][0] = 58, @@ -28882,6 +28956,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][0] = 48, [0][1][0][0][RTW89_CN][0] = 42, [0][1][0][0][RTW89_UK][0] = 48, + [0][1][0][0][RTW89_MEXICO][0] = 76, + [0][1][0][0][RTW89_UKRAINE][0] = 48, + [0][1][0][0][RTW89_CHILE][0] = 76, + [0][1][0][0][RTW89_QATAR][0] = 48, [0][1][0][0][RTW89_FCC][1] = 76, [0][1][0][0][RTW89_ETSI][1] = 48, [0][1][0][0][RTW89_MKK][1] = 58, @@ -28890,6 +28968,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][1] = 48, [0][1][0][0][RTW89_CN][1] = 42, [0][1][0][0][RTW89_UK][1] = 48, + [0][1][0][0][RTW89_MEXICO][1] = 76, + [0][1][0][0][RTW89_UKRAINE][1] = 48, + [0][1][0][0][RTW89_CHILE][1] = 54, + [0][1][0][0][RTW89_QATAR][1] = 48, [0][1][0][0][RTW89_FCC][2] = 76, [0][1][0][0][RTW89_ETSI][2] = 48, [0][1][0][0][RTW89_MKK][2] = 58, @@ -28898,6 +28980,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][2] = 48, [0][1][0][0][RTW89_CN][2] = 42, [0][1][0][0][RTW89_UK][2] = 48, + [0][1][0][0][RTW89_MEXICO][2] = 76, + [0][1][0][0][RTW89_UKRAINE][2] = 48, + [0][1][0][0][RTW89_CHILE][2] = 54, + [0][1][0][0][RTW89_QATAR][2] = 48, [0][1][0][0][RTW89_FCC][3] = 76, [0][1][0][0][RTW89_ETSI][3] = 48, [0][1][0][0][RTW89_MKK][3] = 58, @@ -28906,6 +28992,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][3] = 48, [0][1][0][0][RTW89_CN][3] = 42, [0][1][0][0][RTW89_UK][3] = 48, + [0][1][0][0][RTW89_MEXICO][3] = 76, + [0][1][0][0][RTW89_UKRAINE][3] = 48, + [0][1][0][0][RTW89_CHILE][3] = 54, + [0][1][0][0][RTW89_QATAR][3] = 48, [0][1][0][0][RTW89_FCC][4] = 76, [0][1][0][0][RTW89_ETSI][4] = 48, [0][1][0][0][RTW89_MKK][4] = 58, @@ -28914,6 +29004,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][4] = 48, [0][1][0][0][RTW89_CN][4] = 42, [0][1][0][0][RTW89_UK][4] = 48, + [0][1][0][0][RTW89_MEXICO][4] = 76, + [0][1][0][0][RTW89_UKRAINE][4] = 48, + [0][1][0][0][RTW89_CHILE][4] = 54, + [0][1][0][0][RTW89_QATAR][4] = 48, [0][1][0][0][RTW89_FCC][5] = 76, [0][1][0][0][RTW89_ETSI][5] = 48, [0][1][0][0][RTW89_MKK][5] = 58, @@ -28922,6 +29016,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][5] = 48, [0][1][0][0][RTW89_CN][5] = 42, [0][1][0][0][RTW89_UK][5] = 48, + [0][1][0][0][RTW89_MEXICO][5] = 76, + [0][1][0][0][RTW89_UKRAINE][5] = 48, + [0][1][0][0][RTW89_CHILE][5] = 76, + [0][1][0][0][RTW89_QATAR][5] = 48, [0][1][0][0][RTW89_FCC][6] = 76, [0][1][0][0][RTW89_ETSI][6] = 48, [0][1][0][0][RTW89_MKK][6] = 58, @@ -28930,6 +29028,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][6] = 48, [0][1][0][0][RTW89_CN][6] = 42, [0][1][0][0][RTW89_UK][6] = 48, + [0][1][0][0][RTW89_MEXICO][6] = 76, + [0][1][0][0][RTW89_UKRAINE][6] = 48, + [0][1][0][0][RTW89_CHILE][6] = 76, + [0][1][0][0][RTW89_QATAR][6] = 48, [0][1][0][0][RTW89_FCC][7] = 76, [0][1][0][0][RTW89_ETSI][7] = 48, [0][1][0][0][RTW89_MKK][7] = 58, @@ -28938,6 +29040,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][7] = 48, [0][1][0][0][RTW89_CN][7] = 42, [0][1][0][0][RTW89_UK][7] = 48, + [0][1][0][0][RTW89_MEXICO][7] = 76, + [0][1][0][0][RTW89_UKRAINE][7] = 48, + [0][1][0][0][RTW89_CHILE][7] = 76, + [0][1][0][0][RTW89_QATAR][7] = 48, [0][1][0][0][RTW89_FCC][8] = 76, [0][1][0][0][RTW89_ETSI][8] = 48, [0][1][0][0][RTW89_MKK][8] = 58, @@ -28946,6 +29052,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][8] = 48, [0][1][0][0][RTW89_CN][8] = 42, [0][1][0][0][RTW89_UK][8] = 48, + [0][1][0][0][RTW89_MEXICO][8] = 76, + [0][1][0][0][RTW89_UKRAINE][8] = 48, + [0][1][0][0][RTW89_CHILE][8] = 76, + [0][1][0][0][RTW89_QATAR][8] = 48, [0][1][0][0][RTW89_FCC][9] = 70, [0][1][0][0][RTW89_ETSI][9] = 48, [0][1][0][0][RTW89_MKK][9] = 58, @@ -28954,6 +29064,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][9] = 48, [0][1][0][0][RTW89_CN][9] = 42, [0][1][0][0][RTW89_UK][9] = 48, + [0][1][0][0][RTW89_MEXICO][9] = 70, + [0][1][0][0][RTW89_UKRAINE][9] = 48, + [0][1][0][0][RTW89_CHILE][9] = 70, + [0][1][0][0][RTW89_QATAR][9] = 48, [0][1][0][0][RTW89_FCC][10] = 72, [0][1][0][0][RTW89_ETSI][10] = 48, [0][1][0][0][RTW89_MKK][10] = 58, @@ -28962,6 +29076,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][10] = 48, [0][1][0][0][RTW89_CN][10] = 42, [0][1][0][0][RTW89_UK][10] = 48, + [0][1][0][0][RTW89_MEXICO][10] = 72, + [0][1][0][0][RTW89_UKRAINE][10] = 48, + [0][1][0][0][RTW89_CHILE][10] = 72, + [0][1][0][0][RTW89_QATAR][10] = 48, [0][1][0][0][RTW89_FCC][11] = 44, [0][1][0][0][RTW89_ETSI][11] = 48, [0][1][0][0][RTW89_MKK][11] = 58, @@ -28970,6 +29088,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][11] = 48, [0][1][0][0][RTW89_CN][11] = 42, [0][1][0][0][RTW89_UK][11] = 48, + [0][1][0][0][RTW89_MEXICO][11] = 44, + [0][1][0][0][RTW89_UKRAINE][11] = 48, + [0][1][0][0][RTW89_CHILE][11] = 44, + [0][1][0][0][RTW89_QATAR][11] = 48, [0][1][0][0][RTW89_FCC][12] = 18, [0][1][0][0][RTW89_ETSI][12] = 48, [0][1][0][0][RTW89_MKK][12] = 58, @@ -28978,6 +29100,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][12] = 48, [0][1][0][0][RTW89_CN][12] = 42, [0][1][0][0][RTW89_UK][12] = 48, + [0][1][0][0][RTW89_MEXICO][12] = 18, + [0][1][0][0][RTW89_UKRAINE][12] = 48, + [0][1][0][0][RTW89_CHILE][12] = 18, + [0][1][0][0][RTW89_QATAR][12] = 48, [0][1][0][0][RTW89_FCC][13] = 127, [0][1][0][0][RTW89_ETSI][13] = 127, [0][1][0][0][RTW89_MKK][13] = 60, @@ -28986,6 +29112,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][0][0][RTW89_ACMA][13] = 127, [0][1][0][0][RTW89_CN][13] = 127, [0][1][0][0][RTW89_UK][13] = 127, + [0][1][0][0][RTW89_MEXICO][13] = 127, + [0][1][0][0][RTW89_UKRAINE][13] = 127, + [0][1][0][0][RTW89_CHILE][13] = 127, + [0][1][0][0][RTW89_QATAR][13] = 127, [1][0][0][0][RTW89_FCC][0] = 127, [1][0][0][0][RTW89_ETSI][0] = 127, [1][0][0][0][RTW89_MKK][0] = 127, @@ -28994,6 +29124,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][0] = 127, [1][0][0][0][RTW89_CN][0] = 127, [1][0][0][0][RTW89_UK][0] = 127, + [1][0][0][0][RTW89_MEXICO][0] = 127, + [1][0][0][0][RTW89_UKRAINE][0] = 127, + [1][0][0][0][RTW89_CHILE][0] = 127, + [1][0][0][0][RTW89_QATAR][0] = 127, [1][0][0][0][RTW89_FCC][1] = 127, [1][0][0][0][RTW89_ETSI][1] = 127, [1][0][0][0][RTW89_MKK][1] = 127, @@ -29002,6 +29136,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][1] = 127, [1][0][0][0][RTW89_CN][1] = 127, [1][0][0][0][RTW89_UK][1] = 127, + [1][0][0][0][RTW89_MEXICO][1] = 127, + [1][0][0][0][RTW89_UKRAINE][1] = 127, + [1][0][0][0][RTW89_CHILE][1] = 127, + [1][0][0][0][RTW89_QATAR][1] = 127, [1][0][0][0][RTW89_FCC][2] = 44, [1][0][0][0][RTW89_ETSI][2] = 60, [1][0][0][0][RTW89_MKK][2] = 66, @@ -29010,6 +29148,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][2] = 60, [1][0][0][0][RTW89_CN][2] = 58, [1][0][0][0][RTW89_UK][2] = 60, + [1][0][0][0][RTW89_MEXICO][2] = 44, + [1][0][0][0][RTW89_UKRAINE][2] = 60, + [1][0][0][0][RTW89_CHILE][2] = 44, + [1][0][0][0][RTW89_QATAR][2] = 60, [1][0][0][0][RTW89_FCC][3] = 60, [1][0][0][0][RTW89_ETSI][3] = 60, [1][0][0][0][RTW89_MKK][3] = 66, @@ -29018,6 +29160,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][3] = 60, [1][0][0][0][RTW89_CN][3] = 58, [1][0][0][0][RTW89_UK][3] = 60, + [1][0][0][0][RTW89_MEXICO][3] = 60, + [1][0][0][0][RTW89_UKRAINE][3] = 60, + [1][0][0][0][RTW89_CHILE][3] = 60, + [1][0][0][0][RTW89_QATAR][3] = 60, [1][0][0][0][RTW89_FCC][4] = 60, [1][0][0][0][RTW89_ETSI][4] = 60, [1][0][0][0][RTW89_MKK][4] = 66, @@ -29026,6 +29172,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][4] = 60, [1][0][0][0][RTW89_CN][4] = 58, [1][0][0][0][RTW89_UK][4] = 60, + [1][0][0][0][RTW89_MEXICO][4] = 60, + [1][0][0][0][RTW89_UKRAINE][4] = 60, + [1][0][0][0][RTW89_CHILE][4] = 60, + [1][0][0][0][RTW89_QATAR][4] = 60, [1][0][0][0][RTW89_FCC][5] = 62, [1][0][0][0][RTW89_ETSI][5] = 60, [1][0][0][0][RTW89_MKK][5] = 66, @@ -29034,6 +29184,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][5] = 60, [1][0][0][0][RTW89_CN][5] = 58, [1][0][0][0][RTW89_UK][5] = 60, + [1][0][0][0][RTW89_MEXICO][5] = 62, + [1][0][0][0][RTW89_UKRAINE][5] = 60, + [1][0][0][0][RTW89_CHILE][5] = 62, + [1][0][0][0][RTW89_QATAR][5] = 60, [1][0][0][0][RTW89_FCC][6] = 46, [1][0][0][0][RTW89_ETSI][6] = 60, [1][0][0][0][RTW89_MKK][6] = 66, @@ -29042,6 +29196,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][6] = 60, [1][0][0][0][RTW89_CN][6] = 58, [1][0][0][0][RTW89_UK][6] = 60, + [1][0][0][0][RTW89_MEXICO][6] = 46, + [1][0][0][0][RTW89_UKRAINE][6] = 60, + [1][0][0][0][RTW89_CHILE][6] = 46, + [1][0][0][0][RTW89_QATAR][6] = 60, [1][0][0][0][RTW89_FCC][7] = 46, [1][0][0][0][RTW89_ETSI][7] = 60, [1][0][0][0][RTW89_MKK][7] = 66, @@ -29050,6 +29208,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][7] = 60, [1][0][0][0][RTW89_CN][7] = 58, [1][0][0][0][RTW89_UK][7] = 60, + [1][0][0][0][RTW89_MEXICO][7] = 46, + [1][0][0][0][RTW89_UKRAINE][7] = 60, + [1][0][0][0][RTW89_CHILE][7] = 46, + [1][0][0][0][RTW89_QATAR][7] = 60, [1][0][0][0][RTW89_FCC][8] = 28, [1][0][0][0][RTW89_ETSI][8] = 60, [1][0][0][0][RTW89_MKK][8] = 66, @@ -29058,6 +29220,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][8] = 60, [1][0][0][0][RTW89_CN][8] = 58, [1][0][0][0][RTW89_UK][8] = 60, + [1][0][0][0][RTW89_MEXICO][8] = 28, + [1][0][0][0][RTW89_UKRAINE][8] = 60, + [1][0][0][0][RTW89_CHILE][8] = 28, + [1][0][0][0][RTW89_QATAR][8] = 60, [1][0][0][0][RTW89_FCC][9] = 26, [1][0][0][0][RTW89_ETSI][9] = 60, [1][0][0][0][RTW89_MKK][9] = 66, @@ -29066,6 +29232,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][9] = 60, [1][0][0][0][RTW89_CN][9] = 58, [1][0][0][0][RTW89_UK][9] = 60, + [1][0][0][0][RTW89_MEXICO][9] = 26, + [1][0][0][0][RTW89_UKRAINE][9] = 60, + [1][0][0][0][RTW89_CHILE][9] = 26, + [1][0][0][0][RTW89_QATAR][9] = 60, [1][0][0][0][RTW89_FCC][10] = 26, [1][0][0][0][RTW89_ETSI][10] = 60, [1][0][0][0][RTW89_MKK][10] = 66, @@ -29074,6 +29244,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][10] = 60, [1][0][0][0][RTW89_CN][10] = 58, [1][0][0][0][RTW89_UK][10] = 60, + [1][0][0][0][RTW89_MEXICO][10] = 26, + [1][0][0][0][RTW89_UKRAINE][10] = 60, + [1][0][0][0][RTW89_CHILE][10] = 26, + [1][0][0][0][RTW89_QATAR][10] = 60, [1][0][0][0][RTW89_FCC][11] = 127, [1][0][0][0][RTW89_ETSI][11] = 127, [1][0][0][0][RTW89_MKK][11] = 127, @@ -29082,6 +29256,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][11] = 127, [1][0][0][0][RTW89_CN][11] = 127, [1][0][0][0][RTW89_UK][11] = 127, + [1][0][0][0][RTW89_MEXICO][11] = 127, + [1][0][0][0][RTW89_UKRAINE][11] = 127, + [1][0][0][0][RTW89_CHILE][11] = 127, + [1][0][0][0][RTW89_QATAR][11] = 127, [1][0][0][0][RTW89_FCC][12] = 127, [1][0][0][0][RTW89_ETSI][12] = 127, [1][0][0][0][RTW89_MKK][12] = 127, @@ -29090,6 +29268,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][12] = 127, [1][0][0][0][RTW89_CN][12] = 127, [1][0][0][0][RTW89_UK][12] = 127, + [1][0][0][0][RTW89_MEXICO][12] = 127, + [1][0][0][0][RTW89_UKRAINE][12] = 127, + [1][0][0][0][RTW89_CHILE][12] = 127, + [1][0][0][0][RTW89_QATAR][12] = 127, [1][0][0][0][RTW89_FCC][13] = 127, [1][0][0][0][RTW89_ETSI][13] = 127, [1][0][0][0][RTW89_MKK][13] = 127, @@ -29098,6 +29280,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][0][0][RTW89_ACMA][13] = 127, [1][0][0][0][RTW89_CN][13] = 127, [1][0][0][0][RTW89_UK][13] = 127, + [1][0][0][0][RTW89_MEXICO][13] = 127, + [1][0][0][0][RTW89_UKRAINE][13] = 127, + [1][0][0][0][RTW89_CHILE][13] = 127, + [1][0][0][0][RTW89_QATAR][13] = 127, [1][1][0][0][RTW89_FCC][0] = 127, [1][1][0][0][RTW89_ETSI][0] = 127, [1][1][0][0][RTW89_MKK][0] = 127, @@ -29106,6 +29292,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][0] = 127, [1][1][0][0][RTW89_CN][0] = 127, [1][1][0][0][RTW89_UK][0] = 127, + [1][1][0][0][RTW89_MEXICO][0] = 127, + [1][1][0][0][RTW89_UKRAINE][0] = 127, + [1][1][0][0][RTW89_CHILE][0] = 127, + [1][1][0][0][RTW89_QATAR][0] = 127, [1][1][0][0][RTW89_FCC][1] = 127, [1][1][0][0][RTW89_ETSI][1] = 127, [1][1][0][0][RTW89_MKK][1] = 127, @@ -29114,6 +29304,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][1] = 127, [1][1][0][0][RTW89_CN][1] = 127, [1][1][0][0][RTW89_UK][1] = 127, + [1][1][0][0][RTW89_MEXICO][1] = 127, + [1][1][0][0][RTW89_UKRAINE][1] = 127, + [1][1][0][0][RTW89_CHILE][1] = 127, + [1][1][0][0][RTW89_QATAR][1] = 127, [1][1][0][0][RTW89_FCC][2] = 46, [1][1][0][0][RTW89_ETSI][2] = 48, [1][1][0][0][RTW89_MKK][2] = 58, @@ -29122,6 +29316,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][2] = 48, [1][1][0][0][RTW89_CN][2] = 46, [1][1][0][0][RTW89_UK][2] = 48, + [1][1][0][0][RTW89_MEXICO][2] = 46, + [1][1][0][0][RTW89_UKRAINE][2] = 48, + [1][1][0][0][RTW89_CHILE][2] = 46, + [1][1][0][0][RTW89_QATAR][2] = 48, [1][1][0][0][RTW89_FCC][3] = 46, [1][1][0][0][RTW89_ETSI][3] = 48, [1][1][0][0][RTW89_MKK][3] = 58, @@ -29130,6 +29328,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][3] = 48, [1][1][0][0][RTW89_CN][3] = 46, [1][1][0][0][RTW89_UK][3] = 48, + [1][1][0][0][RTW89_MEXICO][3] = 46, + [1][1][0][0][RTW89_UKRAINE][3] = 48, + [1][1][0][0][RTW89_CHILE][3] = 46, + [1][1][0][0][RTW89_QATAR][3] = 48, [1][1][0][0][RTW89_FCC][4] = 46, [1][1][0][0][RTW89_ETSI][4] = 48, [1][1][0][0][RTW89_MKK][4] = 58, @@ -29138,6 +29340,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][4] = 48, [1][1][0][0][RTW89_CN][4] = 46, [1][1][0][0][RTW89_UK][4] = 48, + [1][1][0][0][RTW89_MEXICO][4] = 46, + [1][1][0][0][RTW89_UKRAINE][4] = 48, + [1][1][0][0][RTW89_CHILE][4] = 46, + [1][1][0][0][RTW89_QATAR][4] = 48, [1][1][0][0][RTW89_FCC][5] = 48, [1][1][0][0][RTW89_ETSI][5] = 48, [1][1][0][0][RTW89_MKK][5] = 58, @@ -29146,6 +29352,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][5] = 48, [1][1][0][0][RTW89_CN][5] = 46, [1][1][0][0][RTW89_UK][5] = 48, + [1][1][0][0][RTW89_MEXICO][5] = 48, + [1][1][0][0][RTW89_UKRAINE][5] = 48, + [1][1][0][0][RTW89_CHILE][5] = 48, + [1][1][0][0][RTW89_QATAR][5] = 48, [1][1][0][0][RTW89_FCC][6] = 40, [1][1][0][0][RTW89_ETSI][6] = 48, [1][1][0][0][RTW89_MKK][6] = 58, @@ -29154,6 +29364,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][6] = 48, [1][1][0][0][RTW89_CN][6] = 46, [1][1][0][0][RTW89_UK][6] = 48, + [1][1][0][0][RTW89_MEXICO][6] = 40, + [1][1][0][0][RTW89_UKRAINE][6] = 48, + [1][1][0][0][RTW89_CHILE][6] = 40, + [1][1][0][0][RTW89_QATAR][6] = 48, [1][1][0][0][RTW89_FCC][7] = 40, [1][1][0][0][RTW89_ETSI][7] = 48, [1][1][0][0][RTW89_MKK][7] = 58, @@ -29162,6 +29376,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][7] = 48, [1][1][0][0][RTW89_CN][7] = 46, [1][1][0][0][RTW89_UK][7] = 48, + [1][1][0][0][RTW89_MEXICO][7] = 40, + [1][1][0][0][RTW89_UKRAINE][7] = 48, + [1][1][0][0][RTW89_CHILE][7] = 40, + [1][1][0][0][RTW89_QATAR][7] = 48, [1][1][0][0][RTW89_FCC][8] = 14, [1][1][0][0][RTW89_ETSI][8] = 48, [1][1][0][0][RTW89_MKK][8] = 58, @@ -29170,6 +29388,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][8] = 48, [1][1][0][0][RTW89_CN][8] = 46, [1][1][0][0][RTW89_UK][8] = 48, + [1][1][0][0][RTW89_MEXICO][8] = 14, + [1][1][0][0][RTW89_UKRAINE][8] = 48, + [1][1][0][0][RTW89_CHILE][8] = 14, + [1][1][0][0][RTW89_QATAR][8] = 48, [1][1][0][0][RTW89_FCC][9] = 14, [1][1][0][0][RTW89_ETSI][9] = 48, [1][1][0][0][RTW89_MKK][9] = 58, @@ -29178,6 +29400,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][9] = 48, [1][1][0][0][RTW89_CN][9] = 46, [1][1][0][0][RTW89_UK][9] = 48, + [1][1][0][0][RTW89_MEXICO][9] = 14, + [1][1][0][0][RTW89_UKRAINE][9] = 48, + [1][1][0][0][RTW89_CHILE][9] = 14, + [1][1][0][0][RTW89_QATAR][9] = 48, [1][1][0][0][RTW89_FCC][10] = 12, [1][1][0][0][RTW89_ETSI][10] = 48, [1][1][0][0][RTW89_MKK][10] = 56, @@ -29186,6 +29412,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][10] = 48, [1][1][0][0][RTW89_CN][10] = 46, [1][1][0][0][RTW89_UK][10] = 48, + [1][1][0][0][RTW89_MEXICO][10] = 12, + [1][1][0][0][RTW89_UKRAINE][10] = 48, + [1][1][0][0][RTW89_CHILE][10] = 12, + [1][1][0][0][RTW89_QATAR][10] = 48, [1][1][0][0][RTW89_FCC][11] = 127, [1][1][0][0][RTW89_ETSI][11] = 127, [1][1][0][0][RTW89_MKK][11] = 127, @@ -29194,6 +29424,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][11] = 127, [1][1][0][0][RTW89_CN][11] = 127, [1][1][0][0][RTW89_UK][11] = 127, + [1][1][0][0][RTW89_MEXICO][11] = 127, + [1][1][0][0][RTW89_UKRAINE][11] = 127, + [1][1][0][0][RTW89_CHILE][11] = 127, + [1][1][0][0][RTW89_QATAR][11] = 127, [1][1][0][0][RTW89_FCC][12] = 127, [1][1][0][0][RTW89_ETSI][12] = 127, [1][1][0][0][RTW89_MKK][12] = 127, @@ -29202,6 +29436,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][12] = 127, [1][1][0][0][RTW89_CN][12] = 127, [1][1][0][0][RTW89_UK][12] = 127, + [1][1][0][0][RTW89_MEXICO][12] = 127, + [1][1][0][0][RTW89_UKRAINE][12] = 127, + [1][1][0][0][RTW89_CHILE][12] = 127, + [1][1][0][0][RTW89_QATAR][12] = 127, [1][1][0][0][RTW89_FCC][13] = 127, [1][1][0][0][RTW89_ETSI][13] = 127, [1][1][0][0][RTW89_MKK][13] = 127, @@ -29210,6 +29448,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][0][0][RTW89_ACMA][13] = 127, [1][1][0][0][RTW89_CN][13] = 127, [1][1][0][0][RTW89_UK][13] = 127, + [1][1][0][0][RTW89_MEXICO][13] = 127, + [1][1][0][0][RTW89_UKRAINE][13] = 127, + [1][1][0][0][RTW89_CHILE][13] = 127, + [1][1][0][0][RTW89_QATAR][13] = 127, [0][0][1][0][RTW89_FCC][0] = 66, [0][0][1][0][RTW89_ETSI][0] = 60, [0][0][1][0][RTW89_MKK][0] = 76, @@ -29218,6 +29460,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][0] = 60, [0][0][1][0][RTW89_CN][0] = 58, [0][0][1][0][RTW89_UK][0] = 60, + [0][0][1][0][RTW89_MEXICO][0] = 66, + [0][0][1][0][RTW89_UKRAINE][0] = 60, + [0][0][1][0][RTW89_CHILE][0] = 66, + [0][0][1][0][RTW89_QATAR][0] = 60, [0][0][1][0][RTW89_FCC][1] = 68, [0][0][1][0][RTW89_ETSI][1] = 60, [0][0][1][0][RTW89_MKK][1] = 78, @@ -29226,6 +29472,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][1] = 60, [0][0][1][0][RTW89_CN][1] = 58, [0][0][1][0][RTW89_UK][1] = 60, + [0][0][1][0][RTW89_MEXICO][1] = 68, + [0][0][1][0][RTW89_UKRAINE][1] = 60, + [0][0][1][0][RTW89_CHILE][1] = 68, + [0][0][1][0][RTW89_QATAR][1] = 60, [0][0][1][0][RTW89_FCC][2] = 72, [0][0][1][0][RTW89_ETSI][2] = 60, [0][0][1][0][RTW89_MKK][2] = 78, @@ -29234,6 +29484,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][2] = 60, [0][0][1][0][RTW89_CN][2] = 58, [0][0][1][0][RTW89_UK][2] = 60, + [0][0][1][0][RTW89_MEXICO][2] = 72, + [0][0][1][0][RTW89_UKRAINE][2] = 60, + [0][0][1][0][RTW89_CHILE][2] = 62, + [0][0][1][0][RTW89_QATAR][2] = 60, [0][0][1][0][RTW89_FCC][3] = 76, [0][0][1][0][RTW89_ETSI][3] = 60, [0][0][1][0][RTW89_MKK][3] = 78, @@ -29242,6 +29496,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][3] = 60, [0][0][1][0][RTW89_CN][3] = 58, [0][0][1][0][RTW89_UK][3] = 60, + [0][0][1][0][RTW89_MEXICO][3] = 76, + [0][0][1][0][RTW89_UKRAINE][3] = 60, + [0][0][1][0][RTW89_CHILE][3] = 62, + [0][0][1][0][RTW89_QATAR][3] = 60, [0][0][1][0][RTW89_FCC][4] = 80, [0][0][1][0][RTW89_ETSI][4] = 60, [0][0][1][0][RTW89_MKK][4] = 78, @@ -29250,6 +29508,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][4] = 60, [0][0][1][0][RTW89_CN][4] = 58, [0][0][1][0][RTW89_UK][4] = 60, + [0][0][1][0][RTW89_MEXICO][4] = 80, + [0][0][1][0][RTW89_UKRAINE][4] = 60, + [0][0][1][0][RTW89_CHILE][4] = 62, + [0][0][1][0][RTW89_QATAR][4] = 60, [0][0][1][0][RTW89_FCC][5] = 80, [0][0][1][0][RTW89_ETSI][5] = 60, [0][0][1][0][RTW89_MKK][5] = 78, @@ -29258,6 +29520,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][5] = 60, [0][0][1][0][RTW89_CN][5] = 58, [0][0][1][0][RTW89_UK][5] = 60, + [0][0][1][0][RTW89_MEXICO][5] = 80, + [0][0][1][0][RTW89_UKRAINE][5] = 60, + [0][0][1][0][RTW89_CHILE][5] = 80, + [0][0][1][0][RTW89_QATAR][5] = 60, [0][0][1][0][RTW89_FCC][6] = 80, [0][0][1][0][RTW89_ETSI][6] = 60, [0][0][1][0][RTW89_MKK][6] = 76, @@ -29266,6 +29532,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][6] = 60, [0][0][1][0][RTW89_CN][6] = 58, [0][0][1][0][RTW89_UK][6] = 60, + [0][0][1][0][RTW89_MEXICO][6] = 80, + [0][0][1][0][RTW89_UKRAINE][6] = 60, + [0][0][1][0][RTW89_CHILE][6] = 70, + [0][0][1][0][RTW89_QATAR][6] = 60, [0][0][1][0][RTW89_FCC][7] = 80, [0][0][1][0][RTW89_ETSI][7] = 60, [0][0][1][0][RTW89_MKK][7] = 78, @@ -29274,6 +29544,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][7] = 60, [0][0][1][0][RTW89_CN][7] = 58, [0][0][1][0][RTW89_UK][7] = 60, + [0][0][1][0][RTW89_MEXICO][7] = 80, + [0][0][1][0][RTW89_UKRAINE][7] = 60, + [0][0][1][0][RTW89_CHILE][7] = 70, + [0][0][1][0][RTW89_QATAR][7] = 60, [0][0][1][0][RTW89_FCC][8] = 80, [0][0][1][0][RTW89_ETSI][8] = 60, [0][0][1][0][RTW89_MKK][8] = 78, @@ -29282,6 +29556,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][8] = 60, [0][0][1][0][RTW89_CN][8] = 58, [0][0][1][0][RTW89_UK][8] = 60, + [0][0][1][0][RTW89_MEXICO][8] = 80, + [0][0][1][0][RTW89_UKRAINE][8] = 60, + [0][0][1][0][RTW89_CHILE][8] = 70, + [0][0][1][0][RTW89_QATAR][8] = 60, [0][0][1][0][RTW89_FCC][9] = 76, [0][0][1][0][RTW89_ETSI][9] = 60, [0][0][1][0][RTW89_MKK][9] = 78, @@ -29290,6 +29568,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][9] = 60, [0][0][1][0][RTW89_CN][9] = 58, [0][0][1][0][RTW89_UK][9] = 60, + [0][0][1][0][RTW89_MEXICO][9] = 76, + [0][0][1][0][RTW89_UKRAINE][9] = 60, + [0][0][1][0][RTW89_CHILE][9] = 76, + [0][0][1][0][RTW89_QATAR][9] = 60, [0][0][1][0][RTW89_FCC][10] = 66, [0][0][1][0][RTW89_ETSI][10] = 60, [0][0][1][0][RTW89_MKK][10] = 78, @@ -29298,6 +29580,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][10] = 60, [0][0][1][0][RTW89_CN][10] = 58, [0][0][1][0][RTW89_UK][10] = 60, + [0][0][1][0][RTW89_MEXICO][10] = 66, + [0][0][1][0][RTW89_UKRAINE][10] = 60, + [0][0][1][0][RTW89_CHILE][10] = 66, + [0][0][1][0][RTW89_QATAR][10] = 60, [0][0][1][0][RTW89_FCC][11] = 62, [0][0][1][0][RTW89_ETSI][11] = 60, [0][0][1][0][RTW89_MKK][11] = 78, @@ -29306,6 +29592,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][11] = 60, [0][0][1][0][RTW89_CN][11] = 58, [0][0][1][0][RTW89_UK][11] = 60, + [0][0][1][0][RTW89_MEXICO][11] = 62, + [0][0][1][0][RTW89_UKRAINE][11] = 60, + [0][0][1][0][RTW89_CHILE][11] = 62, + [0][0][1][0][RTW89_QATAR][11] = 60, [0][0][1][0][RTW89_FCC][12] = 60, [0][0][1][0][RTW89_ETSI][12] = 60, [0][0][1][0][RTW89_MKK][12] = 78, @@ -29314,6 +29604,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][12] = 60, [0][0][1][0][RTW89_CN][12] = 58, [0][0][1][0][RTW89_UK][12] = 60, + [0][0][1][0][RTW89_MEXICO][12] = 60, + [0][0][1][0][RTW89_UKRAINE][12] = 60, + [0][0][1][0][RTW89_CHILE][12] = 60, + [0][0][1][0][RTW89_QATAR][12] = 60, [0][0][1][0][RTW89_FCC][13] = 127, [0][0][1][0][RTW89_ETSI][13] = 127, [0][0][1][0][RTW89_MKK][13] = 127, @@ -29322,6 +29616,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][13] = 127, [0][0][1][0][RTW89_CN][13] = 127, [0][0][1][0][RTW89_UK][13] = 127, + [0][0][1][0][RTW89_MEXICO][13] = 127, + [0][0][1][0][RTW89_UKRAINE][13] = 127, + [0][0][1][0][RTW89_CHILE][13] = 127, + [0][0][1][0][RTW89_QATAR][13] = 127, [0][1][1][0][RTW89_FCC][0] = 66, [0][1][1][0][RTW89_ETSI][0] = 48, [0][1][1][0][RTW89_MKK][0] = 66, @@ -29330,6 +29628,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][0] = 48, [0][1][1][0][RTW89_CN][0] = 46, [0][1][1][0][RTW89_UK][0] = 48, + [0][1][1][0][RTW89_MEXICO][0] = 66, + [0][1][1][0][RTW89_UKRAINE][0] = 48, + [0][1][1][0][RTW89_CHILE][0] = 66, + [0][1][1][0][RTW89_QATAR][0] = 48, [0][1][1][0][RTW89_FCC][1] = 68, [0][1][1][0][RTW89_ETSI][1] = 48, [0][1][1][0][RTW89_MKK][1] = 66, @@ -29338,6 +29640,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][1] = 48, [0][1][1][0][RTW89_CN][1] = 46, [0][1][1][0][RTW89_UK][1] = 48, + [0][1][1][0][RTW89_MEXICO][1] = 68, + [0][1][1][0][RTW89_UKRAINE][1] = 48, + [0][1][1][0][RTW89_CHILE][1] = 68, + [0][1][1][0][RTW89_QATAR][1] = 48, [0][1][1][0][RTW89_FCC][2] = 72, [0][1][1][0][RTW89_ETSI][2] = 48, [0][1][1][0][RTW89_MKK][2] = 66, @@ -29346,6 +29652,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][2] = 48, [0][1][1][0][RTW89_CN][2] = 46, [0][1][1][0][RTW89_UK][2] = 48, + [0][1][1][0][RTW89_MEXICO][2] = 72, + [0][1][1][0][RTW89_UKRAINE][2] = 48, + [0][1][1][0][RTW89_CHILE][2] = 54, + [0][1][1][0][RTW89_QATAR][2] = 48, [0][1][1][0][RTW89_FCC][3] = 76, [0][1][1][0][RTW89_ETSI][3] = 48, [0][1][1][0][RTW89_MKK][3] = 66, @@ -29354,6 +29664,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][3] = 48, [0][1][1][0][RTW89_CN][3] = 46, [0][1][1][0][RTW89_UK][3] = 48, + [0][1][1][0][RTW89_MEXICO][3] = 76, + [0][1][1][0][RTW89_UKRAINE][3] = 48, + [0][1][1][0][RTW89_CHILE][3] = 54, + [0][1][1][0][RTW89_QATAR][3] = 48, [0][1][1][0][RTW89_FCC][4] = 80, [0][1][1][0][RTW89_ETSI][4] = 48, [0][1][1][0][RTW89_MKK][4] = 66, @@ -29362,6 +29676,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][4] = 48, [0][1][1][0][RTW89_CN][4] = 46, [0][1][1][0][RTW89_UK][4] = 48, + [0][1][1][0][RTW89_MEXICO][4] = 80, + [0][1][1][0][RTW89_UKRAINE][4] = 48, + [0][1][1][0][RTW89_CHILE][4] = 54, + [0][1][1][0][RTW89_QATAR][4] = 48, [0][1][1][0][RTW89_FCC][5] = 80, [0][1][1][0][RTW89_ETSI][5] = 48, [0][1][1][0][RTW89_MKK][5] = 66, @@ -29370,6 +29688,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][5] = 48, [0][1][1][0][RTW89_CN][5] = 46, [0][1][1][0][RTW89_UK][5] = 48, + [0][1][1][0][RTW89_MEXICO][5] = 80, + [0][1][1][0][RTW89_UKRAINE][5] = 48, + [0][1][1][0][RTW89_CHILE][5] = 80, + [0][1][1][0][RTW89_QATAR][5] = 48, [0][1][1][0][RTW89_FCC][6] = 80, [0][1][1][0][RTW89_ETSI][6] = 48, [0][1][1][0][RTW89_MKK][6] = 66, @@ -29378,6 +29700,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][6] = 48, [0][1][1][0][RTW89_CN][6] = 46, [0][1][1][0][RTW89_UK][6] = 48, + [0][1][1][0][RTW89_MEXICO][6] = 80, + [0][1][1][0][RTW89_UKRAINE][6] = 48, + [0][1][1][0][RTW89_CHILE][6] = 56, + [0][1][1][0][RTW89_QATAR][6] = 48, [0][1][1][0][RTW89_FCC][7] = 78, [0][1][1][0][RTW89_ETSI][7] = 48, [0][1][1][0][RTW89_MKK][7] = 66, @@ -29386,6 +29712,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][7] = 48, [0][1][1][0][RTW89_CN][7] = 46, [0][1][1][0][RTW89_UK][7] = 48, + [0][1][1][0][RTW89_MEXICO][7] = 78, + [0][1][1][0][RTW89_UKRAINE][7] = 48, + [0][1][1][0][RTW89_CHILE][7] = 56, + [0][1][1][0][RTW89_QATAR][7] = 48, [0][1][1][0][RTW89_FCC][8] = 74, [0][1][1][0][RTW89_ETSI][8] = 48, [0][1][1][0][RTW89_MKK][8] = 66, @@ -29394,6 +29724,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][8] = 48, [0][1][1][0][RTW89_CN][8] = 46, [0][1][1][0][RTW89_UK][8] = 48, + [0][1][1][0][RTW89_MEXICO][8] = 74, + [0][1][1][0][RTW89_UKRAINE][8] = 48, + [0][1][1][0][RTW89_CHILE][8] = 56, + [0][1][1][0][RTW89_QATAR][8] = 48, [0][1][1][0][RTW89_FCC][9] = 70, [0][1][1][0][RTW89_ETSI][9] = 48, [0][1][1][0][RTW89_MKK][9] = 66, @@ -29402,6 +29736,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][9] = 48, [0][1][1][0][RTW89_CN][9] = 46, [0][1][1][0][RTW89_UK][9] = 48, + [0][1][1][0][RTW89_MEXICO][9] = 70, + [0][1][1][0][RTW89_UKRAINE][9] = 48, + [0][1][1][0][RTW89_CHILE][9] = 70, + [0][1][1][0][RTW89_QATAR][9] = 48, [0][1][1][0][RTW89_FCC][10] = 62, [0][1][1][0][RTW89_ETSI][10] = 48, [0][1][1][0][RTW89_MKK][10] = 66, @@ -29410,6 +29748,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][10] = 48, [0][1][1][0][RTW89_CN][10] = 46, [0][1][1][0][RTW89_UK][10] = 48, + [0][1][1][0][RTW89_MEXICO][10] = 62, + [0][1][1][0][RTW89_UKRAINE][10] = 48, + [0][1][1][0][RTW89_CHILE][10] = 62, + [0][1][1][0][RTW89_QATAR][10] = 48, [0][1][1][0][RTW89_FCC][11] = 60, [0][1][1][0][RTW89_ETSI][11] = 48, [0][1][1][0][RTW89_MKK][11] = 66, @@ -29418,6 +29760,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][11] = 48, [0][1][1][0][RTW89_CN][11] = 46, [0][1][1][0][RTW89_UK][11] = 48, + [0][1][1][0][RTW89_MEXICO][11] = 60, + [0][1][1][0][RTW89_UKRAINE][11] = 48, + [0][1][1][0][RTW89_CHILE][11] = 60, + [0][1][1][0][RTW89_QATAR][11] = 48, [0][1][1][0][RTW89_FCC][12] = 36, [0][1][1][0][RTW89_ETSI][12] = 48, [0][1][1][0][RTW89_MKK][12] = 66, @@ -29426,6 +29772,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][12] = 48, [0][1][1][0][RTW89_CN][12] = 46, [0][1][1][0][RTW89_UK][12] = 48, + [0][1][1][0][RTW89_MEXICO][12] = 36, + [0][1][1][0][RTW89_UKRAINE][12] = 48, + [0][1][1][0][RTW89_CHILE][12] = 36, + [0][1][1][0][RTW89_QATAR][12] = 48, [0][1][1][0][RTW89_FCC][13] = 127, [0][1][1][0][RTW89_ETSI][13] = 127, [0][1][1][0][RTW89_MKK][13] = 127, @@ -29434,6 +29784,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][13] = 127, [0][1][1][0][RTW89_CN][13] = 127, [0][1][1][0][RTW89_UK][13] = 127, + [0][1][1][0][RTW89_MEXICO][13] = 127, + [0][1][1][0][RTW89_UKRAINE][13] = 127, + [0][1][1][0][RTW89_CHILE][13] = 127, + [0][1][1][0][RTW89_QATAR][13] = 127, [0][0][2][0][RTW89_FCC][0] = 66, [0][0][2][0][RTW89_ETSI][0] = 60, [0][0][2][0][RTW89_MKK][0] = 78, @@ -29442,6 +29796,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][0] = 60, [0][0][2][0][RTW89_CN][0] = 58, [0][0][2][0][RTW89_UK][0] = 60, + [0][0][2][0][RTW89_MEXICO][0] = 66, + [0][0][2][0][RTW89_UKRAINE][0] = 60, + [0][0][2][0][RTW89_CHILE][0] = 66, + [0][0][2][0][RTW89_QATAR][0] = 60, [0][0][2][0][RTW89_FCC][1] = 70, [0][0][2][0][RTW89_ETSI][1] = 60, [0][0][2][0][RTW89_MKK][1] = 78, @@ -29450,6 +29808,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][1] = 60, [0][0][2][0][RTW89_CN][1] = 58, [0][0][2][0][RTW89_UK][1] = 60, + [0][0][2][0][RTW89_MEXICO][1] = 70, + [0][0][2][0][RTW89_UKRAINE][1] = 60, + [0][0][2][0][RTW89_CHILE][1] = 70, + [0][0][2][0][RTW89_QATAR][1] = 60, [0][0][2][0][RTW89_FCC][2] = 74, [0][0][2][0][RTW89_ETSI][2] = 60, [0][0][2][0][RTW89_MKK][2] = 78, @@ -29458,6 +29820,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][2] = 60, [0][0][2][0][RTW89_CN][2] = 58, [0][0][2][0][RTW89_UK][2] = 60, + [0][0][2][0][RTW89_MEXICO][2] = 74, + [0][0][2][0][RTW89_UKRAINE][2] = 60, + [0][0][2][0][RTW89_CHILE][2] = 64, + [0][0][2][0][RTW89_QATAR][2] = 60, [0][0][2][0][RTW89_FCC][3] = 78, [0][0][2][0][RTW89_ETSI][3] = 60, [0][0][2][0][RTW89_MKK][3] = 78, @@ -29466,6 +29832,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][3] = 60, [0][0][2][0][RTW89_CN][3] = 58, [0][0][2][0][RTW89_UK][3] = 60, + [0][0][2][0][RTW89_MEXICO][3] = 78, + [0][0][2][0][RTW89_UKRAINE][3] = 60, + [0][0][2][0][RTW89_CHILE][3] = 64, + [0][0][2][0][RTW89_QATAR][3] = 60, [0][0][2][0][RTW89_FCC][4] = 80, [0][0][2][0][RTW89_ETSI][4] = 60, [0][0][2][0][RTW89_MKK][4] = 78, @@ -29474,6 +29844,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][4] = 60, [0][0][2][0][RTW89_CN][4] = 58, [0][0][2][0][RTW89_UK][4] = 60, + [0][0][2][0][RTW89_MEXICO][4] = 80, + [0][0][2][0][RTW89_UKRAINE][4] = 60, + [0][0][2][0][RTW89_CHILE][4] = 64, + [0][0][2][0][RTW89_QATAR][4] = 60, [0][0][2][0][RTW89_FCC][5] = 80, [0][0][2][0][RTW89_ETSI][5] = 60, [0][0][2][0][RTW89_MKK][5] = 78, @@ -29482,6 +29856,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][5] = 60, [0][0][2][0][RTW89_CN][5] = 58, [0][0][2][0][RTW89_UK][5] = 60, + [0][0][2][0][RTW89_MEXICO][5] = 80, + [0][0][2][0][RTW89_UKRAINE][5] = 60, + [0][0][2][0][RTW89_CHILE][5] = 80, + [0][0][2][0][RTW89_QATAR][5] = 60, [0][0][2][0][RTW89_FCC][6] = 80, [0][0][2][0][RTW89_ETSI][6] = 60, [0][0][2][0][RTW89_MKK][6] = 78, @@ -29490,6 +29868,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][6] = 60, [0][0][2][0][RTW89_CN][6] = 58, [0][0][2][0][RTW89_UK][6] = 60, + [0][0][2][0][RTW89_MEXICO][6] = 80, + [0][0][2][0][RTW89_UKRAINE][6] = 60, + [0][0][2][0][RTW89_CHILE][6] = 68, + [0][0][2][0][RTW89_QATAR][6] = 60, [0][0][2][0][RTW89_FCC][7] = 80, [0][0][2][0][RTW89_ETSI][7] = 60, [0][0][2][0][RTW89_MKK][7] = 78, @@ -29498,6 +29880,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][7] = 60, [0][0][2][0][RTW89_CN][7] = 58, [0][0][2][0][RTW89_UK][7] = 60, + [0][0][2][0][RTW89_MEXICO][7] = 80, + [0][0][2][0][RTW89_UKRAINE][7] = 60, + [0][0][2][0][RTW89_CHILE][7] = 68, + [0][0][2][0][RTW89_QATAR][7] = 60, [0][0][2][0][RTW89_FCC][8] = 78, [0][0][2][0][RTW89_ETSI][8] = 60, [0][0][2][0][RTW89_MKK][8] = 78, @@ -29506,6 +29892,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][8] = 60, [0][0][2][0][RTW89_CN][8] = 58, [0][0][2][0][RTW89_UK][8] = 60, + [0][0][2][0][RTW89_MEXICO][8] = 78, + [0][0][2][0][RTW89_UKRAINE][8] = 60, + [0][0][2][0][RTW89_CHILE][8] = 68, + [0][0][2][0][RTW89_QATAR][8] = 60, [0][0][2][0][RTW89_FCC][9] = 74, [0][0][2][0][RTW89_ETSI][9] = 60, [0][0][2][0][RTW89_MKK][9] = 78, @@ -29514,6 +29904,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][9] = 60, [0][0][2][0][RTW89_CN][9] = 58, [0][0][2][0][RTW89_UK][9] = 60, + [0][0][2][0][RTW89_MEXICO][9] = 74, + [0][0][2][0][RTW89_UKRAINE][9] = 60, + [0][0][2][0][RTW89_CHILE][9] = 74, + [0][0][2][0][RTW89_QATAR][9] = 60, [0][0][2][0][RTW89_FCC][10] = 62, [0][0][2][0][RTW89_ETSI][10] = 60, [0][0][2][0][RTW89_MKK][10] = 78, @@ -29522,6 +29916,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][10] = 60, [0][0][2][0][RTW89_CN][10] = 58, [0][0][2][0][RTW89_UK][10] = 60, + [0][0][2][0][RTW89_MEXICO][10] = 62, + [0][0][2][0][RTW89_UKRAINE][10] = 60, + [0][0][2][0][RTW89_CHILE][10] = 62, + [0][0][2][0][RTW89_QATAR][10] = 60, [0][0][2][0][RTW89_FCC][11] = 60, [0][0][2][0][RTW89_ETSI][11] = 60, [0][0][2][0][RTW89_MKK][11] = 78, @@ -29530,6 +29928,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][11] = 60, [0][0][2][0][RTW89_CN][11] = 58, [0][0][2][0][RTW89_UK][11] = 60, + [0][0][2][0][RTW89_MEXICO][11] = 60, + [0][0][2][0][RTW89_UKRAINE][11] = 60, + [0][0][2][0][RTW89_CHILE][11] = 60, + [0][0][2][0][RTW89_QATAR][11] = 60, [0][0][2][0][RTW89_FCC][12] = 38, [0][0][2][0][RTW89_ETSI][12] = 60, [0][0][2][0][RTW89_MKK][12] = 78, @@ -29538,6 +29940,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][12] = 60, [0][0][2][0][RTW89_CN][12] = 58, [0][0][2][0][RTW89_UK][12] = 60, + [0][0][2][0][RTW89_MEXICO][12] = 38, + [0][0][2][0][RTW89_UKRAINE][12] = 60, + [0][0][2][0][RTW89_CHILE][12] = 38, + [0][0][2][0][RTW89_QATAR][12] = 60, [0][0][2][0][RTW89_FCC][13] = 127, [0][0][2][0][RTW89_ETSI][13] = 127, [0][0][2][0][RTW89_MKK][13] = 127, @@ -29546,6 +29952,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][13] = 127, [0][0][2][0][RTW89_CN][13] = 127, [0][0][2][0][RTW89_UK][13] = 127, + [0][0][2][0][RTW89_MEXICO][13] = 127, + [0][0][2][0][RTW89_UKRAINE][13] = 127, + [0][0][2][0][RTW89_CHILE][13] = 127, + [0][0][2][0][RTW89_QATAR][13] = 127, [0][1][2][0][RTW89_FCC][0] = 64, [0][1][2][0][RTW89_ETSI][0] = 48, [0][1][2][0][RTW89_MKK][0] = 68, @@ -29554,6 +29964,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][0] = 48, [0][1][2][0][RTW89_CN][0] = 46, [0][1][2][0][RTW89_UK][0] = 48, + [0][1][2][0][RTW89_MEXICO][0] = 64, + [0][1][2][0][RTW89_UKRAINE][0] = 48, + [0][1][2][0][RTW89_CHILE][0] = 64, + [0][1][2][0][RTW89_QATAR][0] = 48, [0][1][2][0][RTW89_FCC][1] = 70, [0][1][2][0][RTW89_ETSI][1] = 48, [0][1][2][0][RTW89_MKK][1] = 68, @@ -29562,6 +29976,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][1] = 48, [0][1][2][0][RTW89_CN][1] = 46, [0][1][2][0][RTW89_UK][1] = 48, + [0][1][2][0][RTW89_MEXICO][1] = 70, + [0][1][2][0][RTW89_UKRAINE][1] = 48, + [0][1][2][0][RTW89_CHILE][1] = 70, + [0][1][2][0][RTW89_QATAR][1] = 48, [0][1][2][0][RTW89_FCC][2] = 74, [0][1][2][0][RTW89_ETSI][2] = 48, [0][1][2][0][RTW89_MKK][2] = 68, @@ -29570,6 +29988,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][2] = 48, [0][1][2][0][RTW89_CN][2] = 46, [0][1][2][0][RTW89_UK][2] = 48, + [0][1][2][0][RTW89_MEXICO][2] = 74, + [0][1][2][0][RTW89_UKRAINE][2] = 48, + [0][1][2][0][RTW89_CHILE][2] = 56, + [0][1][2][0][RTW89_QATAR][2] = 48, [0][1][2][0][RTW89_FCC][3] = 78, [0][1][2][0][RTW89_ETSI][3] = 48, [0][1][2][0][RTW89_MKK][3] = 68, @@ -29578,6 +30000,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][3] = 48, [0][1][2][0][RTW89_CN][3] = 46, [0][1][2][0][RTW89_UK][3] = 48, + [0][1][2][0][RTW89_MEXICO][3] = 78, + [0][1][2][0][RTW89_UKRAINE][3] = 48, + [0][1][2][0][RTW89_CHILE][3] = 56, + [0][1][2][0][RTW89_QATAR][3] = 48, [0][1][2][0][RTW89_FCC][4] = 80, [0][1][2][0][RTW89_ETSI][4] = 48, [0][1][2][0][RTW89_MKK][4] = 68, @@ -29586,6 +30012,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][4] = 48, [0][1][2][0][RTW89_CN][4] = 46, [0][1][2][0][RTW89_UK][4] = 48, + [0][1][2][0][RTW89_MEXICO][4] = 80, + [0][1][2][0][RTW89_UKRAINE][4] = 48, + [0][1][2][0][RTW89_CHILE][4] = 56, + [0][1][2][0][RTW89_QATAR][4] = 48, [0][1][2][0][RTW89_FCC][5] = 80, [0][1][2][0][RTW89_ETSI][5] = 48, [0][1][2][0][RTW89_MKK][5] = 68, @@ -29594,6 +30024,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][5] = 48, [0][1][2][0][RTW89_CN][5] = 46, [0][1][2][0][RTW89_UK][5] = 48, + [0][1][2][0][RTW89_MEXICO][5] = 80, + [0][1][2][0][RTW89_UKRAINE][5] = 48, + [0][1][2][0][RTW89_CHILE][5] = 78, + [0][1][2][0][RTW89_QATAR][5] = 48, [0][1][2][0][RTW89_FCC][6] = 80, [0][1][2][0][RTW89_ETSI][6] = 48, [0][1][2][0][RTW89_MKK][6] = 68, @@ -29602,6 +30036,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][6] = 48, [0][1][2][0][RTW89_CN][6] = 46, [0][1][2][0][RTW89_UK][6] = 48, + [0][1][2][0][RTW89_MEXICO][6] = 80, + [0][1][2][0][RTW89_UKRAINE][6] = 48, + [0][1][2][0][RTW89_CHILE][6] = 54, + [0][1][2][0][RTW89_QATAR][6] = 48, [0][1][2][0][RTW89_FCC][7] = 74, [0][1][2][0][RTW89_ETSI][7] = 48, [0][1][2][0][RTW89_MKK][7] = 68, @@ -29610,6 +30048,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][7] = 48, [0][1][2][0][RTW89_CN][7] = 46, [0][1][2][0][RTW89_UK][7] = 48, + [0][1][2][0][RTW89_MEXICO][7] = 74, + [0][1][2][0][RTW89_UKRAINE][7] = 48, + [0][1][2][0][RTW89_CHILE][7] = 54, + [0][1][2][0][RTW89_QATAR][7] = 48, [0][1][2][0][RTW89_FCC][8] = 70, [0][1][2][0][RTW89_ETSI][8] = 48, [0][1][2][0][RTW89_MKK][8] = 68, @@ -29618,6 +30060,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][8] = 48, [0][1][2][0][RTW89_CN][8] = 46, [0][1][2][0][RTW89_UK][8] = 48, + [0][1][2][0][RTW89_MEXICO][8] = 70, + [0][1][2][0][RTW89_UKRAINE][8] = 48, + [0][1][2][0][RTW89_CHILE][8] = 54, + [0][1][2][0][RTW89_QATAR][8] = 48, [0][1][2][0][RTW89_FCC][9] = 66, [0][1][2][0][RTW89_ETSI][9] = 48, [0][1][2][0][RTW89_MKK][9] = 68, @@ -29626,6 +30072,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][9] = 48, [0][1][2][0][RTW89_CN][9] = 46, [0][1][2][0][RTW89_UK][9] = 48, + [0][1][2][0][RTW89_MEXICO][9] = 66, + [0][1][2][0][RTW89_UKRAINE][9] = 48, + [0][1][2][0][RTW89_CHILE][9] = 66, + [0][1][2][0][RTW89_QATAR][9] = 48, [0][1][2][0][RTW89_FCC][10] = 58, [0][1][2][0][RTW89_ETSI][10] = 48, [0][1][2][0][RTW89_MKK][10] = 68, @@ -29634,6 +30084,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][10] = 48, [0][1][2][0][RTW89_CN][10] = 46, [0][1][2][0][RTW89_UK][10] = 48, + [0][1][2][0][RTW89_MEXICO][10] = 58, + [0][1][2][0][RTW89_UKRAINE][10] = 48, + [0][1][2][0][RTW89_CHILE][10] = 58, + [0][1][2][0][RTW89_QATAR][10] = 48, [0][1][2][0][RTW89_FCC][11] = 58, [0][1][2][0][RTW89_ETSI][11] = 48, [0][1][2][0][RTW89_MKK][11] = 68, @@ -29642,6 +30096,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][11] = 48, [0][1][2][0][RTW89_CN][11] = 46, [0][1][2][0][RTW89_UK][11] = 48, + [0][1][2][0][RTW89_MEXICO][11] = 58, + [0][1][2][0][RTW89_UKRAINE][11] = 48, + [0][1][2][0][RTW89_CHILE][11] = 58, + [0][1][2][0][RTW89_QATAR][11] = 48, [0][1][2][0][RTW89_FCC][12] = 16, [0][1][2][0][RTW89_ETSI][12] = 48, [0][1][2][0][RTW89_MKK][12] = 68, @@ -29650,6 +30108,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][12] = 48, [0][1][2][0][RTW89_CN][12] = 46, [0][1][2][0][RTW89_UK][12] = 48, + [0][1][2][0][RTW89_MEXICO][12] = 16, + [0][1][2][0][RTW89_UKRAINE][12] = 48, + [0][1][2][0][RTW89_CHILE][12] = 16, + [0][1][2][0][RTW89_QATAR][12] = 48, [0][1][2][0][RTW89_FCC][13] = 127, [0][1][2][0][RTW89_ETSI][13] = 127, [0][1][2][0][RTW89_MKK][13] = 127, @@ -29658,6 +30120,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][13] = 127, [0][1][2][0][RTW89_CN][13] = 127, [0][1][2][0][RTW89_UK][13] = 127, + [0][1][2][0][RTW89_MEXICO][13] = 127, + [0][1][2][0][RTW89_UKRAINE][13] = 127, + [0][1][2][0][RTW89_CHILE][13] = 127, + [0][1][2][0][RTW89_QATAR][13] = 127, [0][1][2][1][RTW89_FCC][0] = 64, [0][1][2][1][RTW89_ETSI][0] = 36, [0][1][2][1][RTW89_MKK][0] = 68, @@ -29666,6 +30132,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][0] = 36, [0][1][2][1][RTW89_CN][0] = 36, [0][1][2][1][RTW89_UK][0] = 36, + [0][1][2][1][RTW89_MEXICO][0] = 64, + [0][1][2][1][RTW89_UKRAINE][0] = 36, + [0][1][2][1][RTW89_CHILE][0] = 64, + [0][1][2][1][RTW89_QATAR][0] = 36, [0][1][2][1][RTW89_FCC][1] = 70, [0][1][2][1][RTW89_ETSI][1] = 36, [0][1][2][1][RTW89_MKK][1] = 68, @@ -29674,6 +30144,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][1] = 36, [0][1][2][1][RTW89_CN][1] = 34, [0][1][2][1][RTW89_UK][1] = 36, + [0][1][2][1][RTW89_MEXICO][1] = 70, + [0][1][2][1][RTW89_UKRAINE][1] = 36, + [0][1][2][1][RTW89_CHILE][1] = 70, + [0][1][2][1][RTW89_QATAR][1] = 36, [0][1][2][1][RTW89_FCC][2] = 74, [0][1][2][1][RTW89_ETSI][2] = 36, [0][1][2][1][RTW89_MKK][2] = 68, @@ -29682,6 +30156,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][2] = 36, [0][1][2][1][RTW89_CN][2] = 34, [0][1][2][1][RTW89_UK][2] = 36, + [0][1][2][1][RTW89_MEXICO][2] = 74, + [0][1][2][1][RTW89_UKRAINE][2] = 36, + [0][1][2][1][RTW89_CHILE][2] = 44, + [0][1][2][1][RTW89_QATAR][2] = 36, [0][1][2][1][RTW89_FCC][3] = 78, [0][1][2][1][RTW89_ETSI][3] = 36, [0][1][2][1][RTW89_MKK][3] = 68, @@ -29690,6 +30168,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][3] = 36, [0][1][2][1][RTW89_CN][3] = 34, [0][1][2][1][RTW89_UK][3] = 36, + [0][1][2][1][RTW89_MEXICO][3] = 78, + [0][1][2][1][RTW89_UKRAINE][3] = 36, + [0][1][2][1][RTW89_CHILE][3] = 44, + [0][1][2][1][RTW89_QATAR][3] = 36, [0][1][2][1][RTW89_FCC][4] = 80, [0][1][2][1][RTW89_ETSI][4] = 36, [0][1][2][1][RTW89_MKK][4] = 68, @@ -29698,6 +30180,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][4] = 36, [0][1][2][1][RTW89_CN][4] = 34, [0][1][2][1][RTW89_UK][4] = 36, + [0][1][2][1][RTW89_MEXICO][4] = 80, + [0][1][2][1][RTW89_UKRAINE][4] = 36, + [0][1][2][1][RTW89_CHILE][4] = 44, + [0][1][2][1][RTW89_QATAR][4] = 36, [0][1][2][1][RTW89_FCC][5] = 80, [0][1][2][1][RTW89_ETSI][5] = 36, [0][1][2][1][RTW89_MKK][5] = 68, @@ -29706,6 +30192,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][5] = 36, [0][1][2][1][RTW89_CN][5] = 34, [0][1][2][1][RTW89_UK][5] = 36, + [0][1][2][1][RTW89_MEXICO][5] = 80, + [0][1][2][1][RTW89_UKRAINE][5] = 36, + [0][1][2][1][RTW89_CHILE][5] = 74, + [0][1][2][1][RTW89_QATAR][5] = 36, [0][1][2][1][RTW89_FCC][6] = 80, [0][1][2][1][RTW89_ETSI][6] = 36, [0][1][2][1][RTW89_MKK][6] = 68, @@ -29714,6 +30204,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][6] = 36, [0][1][2][1][RTW89_CN][6] = 34, [0][1][2][1][RTW89_UK][6] = 36, + [0][1][2][1][RTW89_MEXICO][6] = 80, + [0][1][2][1][RTW89_UKRAINE][6] = 36, + [0][1][2][1][RTW89_CHILE][6] = 42, + [0][1][2][1][RTW89_QATAR][6] = 36, [0][1][2][1][RTW89_FCC][7] = 74, [0][1][2][1][RTW89_ETSI][7] = 36, [0][1][2][1][RTW89_MKK][7] = 68, @@ -29722,6 +30216,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][7] = 36, [0][1][2][1][RTW89_CN][7] = 34, [0][1][2][1][RTW89_UK][7] = 36, + [0][1][2][1][RTW89_MEXICO][7] = 74, + [0][1][2][1][RTW89_UKRAINE][7] = 36, + [0][1][2][1][RTW89_CHILE][7] = 42, + [0][1][2][1][RTW89_QATAR][7] = 36, [0][1][2][1][RTW89_FCC][8] = 70, [0][1][2][1][RTW89_ETSI][8] = 36, [0][1][2][1][RTW89_MKK][8] = 68, @@ -29730,6 +30228,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][8] = 36, [0][1][2][1][RTW89_CN][8] = 34, [0][1][2][1][RTW89_UK][8] = 36, + [0][1][2][1][RTW89_MEXICO][8] = 70, + [0][1][2][1][RTW89_UKRAINE][8] = 36, + [0][1][2][1][RTW89_CHILE][8] = 42, + [0][1][2][1][RTW89_QATAR][8] = 36, [0][1][2][1][RTW89_FCC][9] = 66, [0][1][2][1][RTW89_ETSI][9] = 36, [0][1][2][1][RTW89_MKK][9] = 68, @@ -29738,6 +30240,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][9] = 36, [0][1][2][1][RTW89_CN][9] = 34, [0][1][2][1][RTW89_UK][9] = 36, + [0][1][2][1][RTW89_MEXICO][9] = 66, + [0][1][2][1][RTW89_UKRAINE][9] = 36, + [0][1][2][1][RTW89_CHILE][9] = 66, + [0][1][2][1][RTW89_QATAR][9] = 36, [0][1][2][1][RTW89_FCC][10] = 58, [0][1][2][1][RTW89_ETSI][10] = 36, [0][1][2][1][RTW89_MKK][10] = 68, @@ -29746,6 +30252,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][10] = 36, [0][1][2][1][RTW89_CN][10] = 34, [0][1][2][1][RTW89_UK][10] = 36, + [0][1][2][1][RTW89_MEXICO][10] = 58, + [0][1][2][1][RTW89_UKRAINE][10] = 36, + [0][1][2][1][RTW89_CHILE][10] = 58, + [0][1][2][1][RTW89_QATAR][10] = 36, [0][1][2][1][RTW89_FCC][11] = 58, [0][1][2][1][RTW89_ETSI][11] = 36, [0][1][2][1][RTW89_MKK][11] = 68, @@ -29754,6 +30264,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][11] = 36, [0][1][2][1][RTW89_CN][11] = 34, [0][1][2][1][RTW89_UK][11] = 36, + [0][1][2][1][RTW89_MEXICO][11] = 58, + [0][1][2][1][RTW89_UKRAINE][11] = 36, + [0][1][2][1][RTW89_CHILE][11] = 58, + [0][1][2][1][RTW89_QATAR][11] = 36, [0][1][2][1][RTW89_FCC][12] = 16, [0][1][2][1][RTW89_ETSI][12] = 36, [0][1][2][1][RTW89_MKK][12] = 68, @@ -29762,6 +30276,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][12] = 36, [0][1][2][1][RTW89_CN][12] = 34, [0][1][2][1][RTW89_UK][12] = 36, + [0][1][2][1][RTW89_MEXICO][12] = 16, + [0][1][2][1][RTW89_UKRAINE][12] = 36, + [0][1][2][1][RTW89_CHILE][12] = 16, + [0][1][2][1][RTW89_QATAR][12] = 36, [0][1][2][1][RTW89_FCC][13] = 127, [0][1][2][1][RTW89_ETSI][13] = 127, [0][1][2][1][RTW89_MKK][13] = 127, @@ -29770,6 +30288,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][13] = 127, [0][1][2][1][RTW89_CN][13] = 127, [0][1][2][1][RTW89_UK][13] = 127, + [0][1][2][1][RTW89_MEXICO][13] = 127, + [0][1][2][1][RTW89_UKRAINE][13] = 127, + [0][1][2][1][RTW89_CHILE][13] = 127, + [0][1][2][1][RTW89_QATAR][13] = 127, [1][0][2][0][RTW89_FCC][0] = 127, [1][0][2][0][RTW89_ETSI][0] = 127, [1][0][2][0][RTW89_MKK][0] = 127, @@ -29778,6 +30300,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][0] = 127, [1][0][2][0][RTW89_CN][0] = 127, [1][0][2][0][RTW89_UK][0] = 127, + [1][0][2][0][RTW89_MEXICO][0] = 127, + [1][0][2][0][RTW89_UKRAINE][0] = 127, + [1][0][2][0][RTW89_CHILE][0] = 127, + [1][0][2][0][RTW89_QATAR][0] = 127, [1][0][2][0][RTW89_FCC][1] = 127, [1][0][2][0][RTW89_ETSI][1] = 127, [1][0][2][0][RTW89_MKK][1] = 127, @@ -29786,6 +30312,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][1] = 127, [1][0][2][0][RTW89_CN][1] = 127, [1][0][2][0][RTW89_UK][1] = 127, + [1][0][2][0][RTW89_MEXICO][1] = 127, + [1][0][2][0][RTW89_UKRAINE][1] = 127, + [1][0][2][0][RTW89_CHILE][1] = 127, + [1][0][2][0][RTW89_QATAR][1] = 127, [1][0][2][0][RTW89_FCC][2] = 64, [1][0][2][0][RTW89_ETSI][2] = 60, [1][0][2][0][RTW89_MKK][2] = 74, @@ -29794,6 +30324,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][2] = 60, [1][0][2][0][RTW89_CN][2] = 58, [1][0][2][0][RTW89_UK][2] = 60, + [1][0][2][0][RTW89_MEXICO][2] = 64, + [1][0][2][0][RTW89_UKRAINE][2] = 60, + [1][0][2][0][RTW89_CHILE][2] = 64, + [1][0][2][0][RTW89_QATAR][2] = 60, [1][0][2][0][RTW89_FCC][3] = 64, [1][0][2][0][RTW89_ETSI][3] = 60, [1][0][2][0][RTW89_MKK][3] = 74, @@ -29802,6 +30336,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][3] = 60, [1][0][2][0][RTW89_CN][3] = 58, [1][0][2][0][RTW89_UK][3] = 60, + [1][0][2][0][RTW89_MEXICO][3] = 64, + [1][0][2][0][RTW89_UKRAINE][3] = 60, + [1][0][2][0][RTW89_CHILE][3] = 64, + [1][0][2][0][RTW89_QATAR][3] = 60, [1][0][2][0][RTW89_FCC][4] = 68, [1][0][2][0][RTW89_ETSI][4] = 60, [1][0][2][0][RTW89_MKK][4] = 74, @@ -29810,6 +30348,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][4] = 60, [1][0][2][0][RTW89_CN][4] = 58, [1][0][2][0][RTW89_UK][4] = 60, + [1][0][2][0][RTW89_MEXICO][4] = 68, + [1][0][2][0][RTW89_UKRAINE][4] = 60, + [1][0][2][0][RTW89_CHILE][4] = 68, + [1][0][2][0][RTW89_QATAR][4] = 60, [1][0][2][0][RTW89_FCC][5] = 68, [1][0][2][0][RTW89_ETSI][5] = 60, [1][0][2][0][RTW89_MKK][5] = 74, @@ -29818,6 +30360,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][5] = 60, [1][0][2][0][RTW89_CN][5] = 58, [1][0][2][0][RTW89_UK][5] = 60, + [1][0][2][0][RTW89_MEXICO][5] = 68, + [1][0][2][0][RTW89_UKRAINE][5] = 60, + [1][0][2][0][RTW89_CHILE][5] = 68, + [1][0][2][0][RTW89_QATAR][5] = 60, [1][0][2][0][RTW89_FCC][6] = 66, [1][0][2][0][RTW89_ETSI][6] = 60, [1][0][2][0][RTW89_MKK][6] = 74, @@ -29826,6 +30372,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][6] = 60, [1][0][2][0][RTW89_CN][6] = 58, [1][0][2][0][RTW89_UK][6] = 60, + [1][0][2][0][RTW89_MEXICO][6] = 66, + [1][0][2][0][RTW89_UKRAINE][6] = 60, + [1][0][2][0][RTW89_CHILE][6] = 66, + [1][0][2][0][RTW89_QATAR][6] = 60, [1][0][2][0][RTW89_FCC][7] = 62, [1][0][2][0][RTW89_ETSI][7] = 60, [1][0][2][0][RTW89_MKK][7] = 74, @@ -29834,6 +30384,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][7] = 60, [1][0][2][0][RTW89_CN][7] = 58, [1][0][2][0][RTW89_UK][7] = 60, + [1][0][2][0][RTW89_MEXICO][7] = 62, + [1][0][2][0][RTW89_UKRAINE][7] = 60, + [1][0][2][0][RTW89_CHILE][7] = 62, + [1][0][2][0][RTW89_QATAR][7] = 60, [1][0][2][0][RTW89_FCC][8] = 62, [1][0][2][0][RTW89_ETSI][8] = 60, [1][0][2][0][RTW89_MKK][8] = 74, @@ -29842,6 +30396,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][8] = 60, [1][0][2][0][RTW89_CN][8] = 58, [1][0][2][0][RTW89_UK][8] = 60, + [1][0][2][0][RTW89_MEXICO][8] = 62, + [1][0][2][0][RTW89_UKRAINE][8] = 60, + [1][0][2][0][RTW89_CHILE][8] = 62, + [1][0][2][0][RTW89_QATAR][8] = 60, [1][0][2][0][RTW89_FCC][9] = 60, [1][0][2][0][RTW89_ETSI][9] = 60, [1][0][2][0][RTW89_MKK][9] = 74, @@ -29850,6 +30408,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][9] = 60, [1][0][2][0][RTW89_CN][9] = 58, [1][0][2][0][RTW89_UK][9] = 60, + [1][0][2][0][RTW89_MEXICO][9] = 60, + [1][0][2][0][RTW89_UKRAINE][9] = 60, + [1][0][2][0][RTW89_CHILE][9] = 60, + [1][0][2][0][RTW89_QATAR][9] = 60, [1][0][2][0][RTW89_FCC][10] = 56, [1][0][2][0][RTW89_ETSI][10] = 60, [1][0][2][0][RTW89_MKK][10] = 74, @@ -29858,6 +30420,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][10] = 60, [1][0][2][0][RTW89_CN][10] = 58, [1][0][2][0][RTW89_UK][10] = 60, + [1][0][2][0][RTW89_MEXICO][10] = 56, + [1][0][2][0][RTW89_UKRAINE][10] = 60, + [1][0][2][0][RTW89_CHILE][10] = 56, + [1][0][2][0][RTW89_QATAR][10] = 60, [1][0][2][0][RTW89_FCC][11] = 127, [1][0][2][0][RTW89_ETSI][11] = 127, [1][0][2][0][RTW89_MKK][11] = 127, @@ -29866,6 +30432,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][11] = 127, [1][0][2][0][RTW89_CN][11] = 127, [1][0][2][0][RTW89_UK][11] = 127, + [1][0][2][0][RTW89_MEXICO][11] = 127, + [1][0][2][0][RTW89_UKRAINE][11] = 127, + [1][0][2][0][RTW89_CHILE][11] = 127, + [1][0][2][0][RTW89_QATAR][11] = 127, [1][0][2][0][RTW89_FCC][12] = 127, [1][0][2][0][RTW89_ETSI][12] = 127, [1][0][2][0][RTW89_MKK][12] = 127, @@ -29874,6 +30444,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][12] = 127, [1][0][2][0][RTW89_CN][12] = 127, [1][0][2][0][RTW89_UK][12] = 127, + [1][0][2][0][RTW89_MEXICO][12] = 127, + [1][0][2][0][RTW89_UKRAINE][12] = 127, + [1][0][2][0][RTW89_CHILE][12] = 127, + [1][0][2][0][RTW89_QATAR][12] = 127, [1][0][2][0][RTW89_FCC][13] = 127, [1][0][2][0][RTW89_ETSI][13] = 127, [1][0][2][0][RTW89_MKK][13] = 127, @@ -29882,6 +30456,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][13] = 127, [1][0][2][0][RTW89_CN][13] = 127, [1][0][2][0][RTW89_UK][13] = 127, + [1][0][2][0][RTW89_MEXICO][13] = 127, + [1][0][2][0][RTW89_UKRAINE][13] = 127, + [1][0][2][0][RTW89_CHILE][13] = 127, + [1][0][2][0][RTW89_QATAR][13] = 127, [1][1][2][0][RTW89_FCC][0] = 127, [1][1][2][0][RTW89_ETSI][0] = 127, [1][1][2][0][RTW89_MKK][0] = 127, @@ -29890,6 +30468,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][0] = 127, [1][1][2][0][RTW89_CN][0] = 127, [1][1][2][0][RTW89_UK][0] = 127, + [1][1][2][0][RTW89_MEXICO][0] = 127, + [1][1][2][0][RTW89_UKRAINE][0] = 127, + [1][1][2][0][RTW89_CHILE][0] = 127, + [1][1][2][0][RTW89_QATAR][0] = 127, [1][1][2][0][RTW89_FCC][1] = 127, [1][1][2][0][RTW89_ETSI][1] = 127, [1][1][2][0][RTW89_MKK][1] = 127, @@ -29898,6 +30480,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][1] = 127, [1][1][2][0][RTW89_CN][1] = 127, [1][1][2][0][RTW89_UK][1] = 127, + [1][1][2][0][RTW89_MEXICO][1] = 127, + [1][1][2][0][RTW89_UKRAINE][1] = 127, + [1][1][2][0][RTW89_CHILE][1] = 127, + [1][1][2][0][RTW89_QATAR][1] = 127, [1][1][2][0][RTW89_FCC][2] = 60, [1][1][2][0][RTW89_ETSI][2] = 48, [1][1][2][0][RTW89_MKK][2] = 68, @@ -29906,6 +30492,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][2] = 48, [1][1][2][0][RTW89_CN][2] = 34, [1][1][2][0][RTW89_UK][2] = 48, + [1][1][2][0][RTW89_MEXICO][2] = 60, + [1][1][2][0][RTW89_UKRAINE][2] = 48, + [1][1][2][0][RTW89_CHILE][2] = 60, + [1][1][2][0][RTW89_QATAR][2] = 48, [1][1][2][0][RTW89_FCC][3] = 60, [1][1][2][0][RTW89_ETSI][3] = 48, [1][1][2][0][RTW89_MKK][3] = 68, @@ -29914,6 +30504,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][3] = 48, [1][1][2][0][RTW89_CN][3] = 34, [1][1][2][0][RTW89_UK][3] = 48, + [1][1][2][0][RTW89_MEXICO][3] = 60, + [1][1][2][0][RTW89_UKRAINE][3] = 48, + [1][1][2][0][RTW89_CHILE][3] = 56, + [1][1][2][0][RTW89_QATAR][3] = 48, [1][1][2][0][RTW89_FCC][4] = 60, [1][1][2][0][RTW89_ETSI][4] = 48, [1][1][2][0][RTW89_MKK][4] = 68, @@ -29922,6 +30516,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][4] = 48, [1][1][2][0][RTW89_CN][4] = 34, [1][1][2][0][RTW89_UK][4] = 48, + [1][1][2][0][RTW89_MEXICO][4] = 60, + [1][1][2][0][RTW89_UKRAINE][4] = 48, + [1][1][2][0][RTW89_CHILE][4] = 56, + [1][1][2][0][RTW89_QATAR][4] = 48, [1][1][2][0][RTW89_FCC][5] = 60, [1][1][2][0][RTW89_ETSI][5] = 48, [1][1][2][0][RTW89_MKK][5] = 68, @@ -29930,6 +30528,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][5] = 48, [1][1][2][0][RTW89_CN][5] = 34, [1][1][2][0][RTW89_UK][5] = 48, + [1][1][2][0][RTW89_MEXICO][5] = 60, + [1][1][2][0][RTW89_UKRAINE][5] = 48, + [1][1][2][0][RTW89_CHILE][5] = 60, + [1][1][2][0][RTW89_QATAR][5] = 48, [1][1][2][0][RTW89_FCC][6] = 58, [1][1][2][0][RTW89_ETSI][6] = 48, [1][1][2][0][RTW89_MKK][6] = 68, @@ -29938,6 +30540,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][6] = 48, [1][1][2][0][RTW89_CN][6] = 34, [1][1][2][0][RTW89_UK][6] = 48, + [1][1][2][0][RTW89_MEXICO][6] = 58, + [1][1][2][0][RTW89_UKRAINE][6] = 48, + [1][1][2][0][RTW89_CHILE][6] = 52, + [1][1][2][0][RTW89_QATAR][6] = 48, [1][1][2][0][RTW89_FCC][7] = 54, [1][1][2][0][RTW89_ETSI][7] = 48, [1][1][2][0][RTW89_MKK][7] = 68, @@ -29946,6 +30552,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][7] = 48, [1][1][2][0][RTW89_CN][7] = 34, [1][1][2][0][RTW89_UK][7] = 48, + [1][1][2][0][RTW89_MEXICO][7] = 54, + [1][1][2][0][RTW89_UKRAINE][7] = 48, + [1][1][2][0][RTW89_CHILE][7] = 52, + [1][1][2][0][RTW89_QATAR][7] = 48, [1][1][2][0][RTW89_FCC][8] = 54, [1][1][2][0][RTW89_ETSI][8] = 48, [1][1][2][0][RTW89_MKK][8] = 68, @@ -29954,6 +30564,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][8] = 48, [1][1][2][0][RTW89_CN][8] = 34, [1][1][2][0][RTW89_UK][8] = 48, + [1][1][2][0][RTW89_MEXICO][8] = 54, + [1][1][2][0][RTW89_UKRAINE][8] = 48, + [1][1][2][0][RTW89_CHILE][8] = 54, + [1][1][2][0][RTW89_QATAR][8] = 48, [1][1][2][0][RTW89_FCC][9] = 54, [1][1][2][0][RTW89_ETSI][9] = 48, [1][1][2][0][RTW89_MKK][9] = 68, @@ -29962,6 +30576,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][9] = 48, [1][1][2][0][RTW89_CN][9] = 34, [1][1][2][0][RTW89_UK][9] = 48, + [1][1][2][0][RTW89_MEXICO][9] = 54, + [1][1][2][0][RTW89_UKRAINE][9] = 48, + [1][1][2][0][RTW89_CHILE][9] = 54, + [1][1][2][0][RTW89_QATAR][9] = 48, [1][1][2][0][RTW89_FCC][10] = 46, [1][1][2][0][RTW89_ETSI][10] = 48, [1][1][2][0][RTW89_MKK][10] = 68, @@ -29970,6 +30588,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][10] = 48, [1][1][2][0][RTW89_CN][10] = 34, [1][1][2][0][RTW89_UK][10] = 48, + [1][1][2][0][RTW89_MEXICO][10] = 46, + [1][1][2][0][RTW89_UKRAINE][10] = 48, + [1][1][2][0][RTW89_CHILE][10] = 46, + [1][1][2][0][RTW89_QATAR][10] = 48, [1][1][2][0][RTW89_FCC][11] = 127, [1][1][2][0][RTW89_ETSI][11] = 127, [1][1][2][0][RTW89_MKK][11] = 127, @@ -29978,6 +30600,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][11] = 127, [1][1][2][0][RTW89_CN][11] = 127, [1][1][2][0][RTW89_UK][11] = 127, + [1][1][2][0][RTW89_MEXICO][11] = 127, + [1][1][2][0][RTW89_UKRAINE][11] = 127, + [1][1][2][0][RTW89_CHILE][11] = 127, + [1][1][2][0][RTW89_QATAR][11] = 127, [1][1][2][0][RTW89_FCC][12] = 127, [1][1][2][0][RTW89_ETSI][12] = 127, [1][1][2][0][RTW89_MKK][12] = 127, @@ -29986,6 +30612,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][12] = 127, [1][1][2][0][RTW89_CN][12] = 127, [1][1][2][0][RTW89_UK][12] = 127, + [1][1][2][0][RTW89_MEXICO][12] = 127, + [1][1][2][0][RTW89_UKRAINE][12] = 127, + [1][1][2][0][RTW89_CHILE][12] = 127, + [1][1][2][0][RTW89_QATAR][12] = 127, [1][1][2][0][RTW89_FCC][13] = 127, [1][1][2][0][RTW89_ETSI][13] = 127, [1][1][2][0][RTW89_MKK][13] = 127, @@ -29994,6 +30624,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][13] = 127, [1][1][2][0][RTW89_CN][13] = 127, [1][1][2][0][RTW89_UK][13] = 127, + [1][1][2][0][RTW89_MEXICO][13] = 127, + [1][1][2][0][RTW89_UKRAINE][13] = 127, + [1][1][2][0][RTW89_CHILE][13] = 127, + [1][1][2][0][RTW89_QATAR][13] = 127, [1][1][2][1][RTW89_FCC][0] = 127, [1][1][2][1][RTW89_ETSI][0] = 127, [1][1][2][1][RTW89_MKK][0] = 127, @@ -30002,6 +30636,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][0] = 127, [1][1][2][1][RTW89_CN][0] = 127, [1][1][2][1][RTW89_UK][0] = 127, + [1][1][2][1][RTW89_MEXICO][0] = 127, + [1][1][2][1][RTW89_UKRAINE][0] = 127, + [1][1][2][1][RTW89_CHILE][0] = 127, + [1][1][2][1][RTW89_QATAR][0] = 127, [1][1][2][1][RTW89_FCC][1] = 127, [1][1][2][1][RTW89_ETSI][1] = 127, [1][1][2][1][RTW89_MKK][1] = 127, @@ -30010,6 +30648,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][1] = 127, [1][1][2][1][RTW89_CN][1] = 127, [1][1][2][1][RTW89_UK][1] = 127, + [1][1][2][1][RTW89_MEXICO][1] = 127, + [1][1][2][1][RTW89_UKRAINE][1] = 127, + [1][1][2][1][RTW89_CHILE][1] = 127, + [1][1][2][1][RTW89_QATAR][1] = 127, [1][1][2][1][RTW89_FCC][2] = 60, [1][1][2][1][RTW89_ETSI][2] = 36, [1][1][2][1][RTW89_MKK][2] = 68, @@ -30018,6 +30660,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][2] = 36, [1][1][2][1][RTW89_CN][2] = 34, [1][1][2][1][RTW89_UK][2] = 36, + [1][1][2][1][RTW89_MEXICO][2] = 60, + [1][1][2][1][RTW89_UKRAINE][2] = 36, + [1][1][2][1][RTW89_CHILE][2] = 60, + [1][1][2][1][RTW89_QATAR][2] = 36, [1][1][2][1][RTW89_FCC][3] = 60, [1][1][2][1][RTW89_ETSI][3] = 36, [1][1][2][1][RTW89_MKK][3] = 68, @@ -30026,6 +30672,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][3] = 36, [1][1][2][1][RTW89_CN][3] = 34, [1][1][2][1][RTW89_UK][3] = 36, + [1][1][2][1][RTW89_MEXICO][3] = 60, + [1][1][2][1][RTW89_UKRAINE][3] = 36, + [1][1][2][1][RTW89_CHILE][3] = 44, + [1][1][2][1][RTW89_QATAR][3] = 36, [1][1][2][1][RTW89_FCC][4] = 60, [1][1][2][1][RTW89_ETSI][4] = 36, [1][1][2][1][RTW89_MKK][4] = 68, @@ -30034,6 +30684,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][4] = 36, [1][1][2][1][RTW89_CN][4] = 34, [1][1][2][1][RTW89_UK][4] = 36, + [1][1][2][1][RTW89_MEXICO][4] = 60, + [1][1][2][1][RTW89_UKRAINE][4] = 36, + [1][1][2][1][RTW89_CHILE][4] = 44, + [1][1][2][1][RTW89_QATAR][4] = 36, [1][1][2][1][RTW89_FCC][5] = 60, [1][1][2][1][RTW89_ETSI][5] = 36, [1][1][2][1][RTW89_MKK][5] = 68, @@ -30042,6 +30696,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][5] = 36, [1][1][2][1][RTW89_CN][5] = 34, [1][1][2][1][RTW89_UK][5] = 36, + [1][1][2][1][RTW89_MEXICO][5] = 60, + [1][1][2][1][RTW89_UKRAINE][5] = 36, + [1][1][2][1][RTW89_CHILE][5] = 60, + [1][1][2][1][RTW89_QATAR][5] = 36, [1][1][2][1][RTW89_FCC][6] = 58, [1][1][2][1][RTW89_ETSI][6] = 36, [1][1][2][1][RTW89_MKK][6] = 68, @@ -30050,6 +30708,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][6] = 36, [1][1][2][1][RTW89_CN][6] = 34, [1][1][2][1][RTW89_UK][6] = 36, + [1][1][2][1][RTW89_MEXICO][6] = 58, + [1][1][2][1][RTW89_UKRAINE][6] = 36, + [1][1][2][1][RTW89_CHILE][6] = 40, + [1][1][2][1][RTW89_QATAR][6] = 36, [1][1][2][1][RTW89_FCC][7] = 54, [1][1][2][1][RTW89_ETSI][7] = 36, [1][1][2][1][RTW89_MKK][7] = 68, @@ -30058,6 +30720,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][7] = 36, [1][1][2][1][RTW89_CN][7] = 34, [1][1][2][1][RTW89_UK][7] = 36, + [1][1][2][1][RTW89_MEXICO][7] = 54, + [1][1][2][1][RTW89_UKRAINE][7] = 36, + [1][1][2][1][RTW89_CHILE][7] = 40, + [1][1][2][1][RTW89_QATAR][7] = 36, [1][1][2][1][RTW89_FCC][8] = 54, [1][1][2][1][RTW89_ETSI][8] = 36, [1][1][2][1][RTW89_MKK][8] = 68, @@ -30066,6 +30732,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][8] = 36, [1][1][2][1][RTW89_CN][8] = 34, [1][1][2][1][RTW89_UK][8] = 36, + [1][1][2][1][RTW89_MEXICO][8] = 54, + [1][1][2][1][RTW89_UKRAINE][8] = 36, + [1][1][2][1][RTW89_CHILE][8] = 54, + [1][1][2][1][RTW89_QATAR][8] = 36, [1][1][2][1][RTW89_FCC][9] = 54, [1][1][2][1][RTW89_ETSI][9] = 36, [1][1][2][1][RTW89_MKK][9] = 68, @@ -30074,6 +30744,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][9] = 36, [1][1][2][1][RTW89_CN][9] = 34, [1][1][2][1][RTW89_UK][9] = 36, + [1][1][2][1][RTW89_MEXICO][9] = 54, + [1][1][2][1][RTW89_UKRAINE][9] = 36, + [1][1][2][1][RTW89_CHILE][9] = 54, + [1][1][2][1][RTW89_QATAR][9] = 36, [1][1][2][1][RTW89_FCC][10] = 46, [1][1][2][1][RTW89_ETSI][10] = 36, [1][1][2][1][RTW89_MKK][10] = 68, @@ -30082,6 +30756,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][10] = 36, [1][1][2][1][RTW89_CN][10] = 36, [1][1][2][1][RTW89_UK][10] = 36, + [1][1][2][1][RTW89_MEXICO][10] = 46, + [1][1][2][1][RTW89_UKRAINE][10] = 36, + [1][1][2][1][RTW89_CHILE][10] = 46, + [1][1][2][1][RTW89_QATAR][10] = 36, [1][1][2][1][RTW89_FCC][11] = 127, [1][1][2][1][RTW89_ETSI][11] = 127, [1][1][2][1][RTW89_MKK][11] = 127, @@ -30090,6 +30768,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][11] = 127, [1][1][2][1][RTW89_CN][11] = 127, [1][1][2][1][RTW89_UK][11] = 127, + [1][1][2][1][RTW89_MEXICO][11] = 127, + [1][1][2][1][RTW89_UKRAINE][11] = 127, + [1][1][2][1][RTW89_CHILE][11] = 127, + [1][1][2][1][RTW89_QATAR][11] = 127, [1][1][2][1][RTW89_FCC][12] = 127, [1][1][2][1][RTW89_ETSI][12] = 127, [1][1][2][1][RTW89_MKK][12] = 127, @@ -30098,6 +30780,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][12] = 127, [1][1][2][1][RTW89_CN][12] = 127, [1][1][2][1][RTW89_UK][12] = 127, + [1][1][2][1][RTW89_MEXICO][12] = 127, + [1][1][2][1][RTW89_UKRAINE][12] = 127, + [1][1][2][1][RTW89_CHILE][12] = 127, + [1][1][2][1][RTW89_QATAR][12] = 127, [1][1][2][1][RTW89_FCC][13] = 127, [1][1][2][1][RTW89_ETSI][13] = 127, [1][1][2][1][RTW89_MKK][13] = 127, @@ -30106,6 +30792,10 @@ const s8 rtw89_8852c_txpwr_lmt_2g[RTW89_2G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][13] = 127, [1][1][2][1][RTW89_CN][13] = 127, [1][1][2][1][RTW89_UK][13] = 127, + [1][1][2][1][RTW89_MEXICO][13] = 127, + [1][1][2][1][RTW89_UKRAINE][13] = 127, + [1][1][2][1][RTW89_CHILE][13] = 127, + [1][1][2][1][RTW89_QATAR][13] = 127, }; static @@ -30120,17 +30810,17 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_WW][10] = 50, [0][0][1][0][RTW89_WW][12] = 50, [0][0][1][0][RTW89_WW][14] = 50, - [0][0][1][0][RTW89_WW][15] = 66, - [0][0][1][0][RTW89_WW][17] = 66, - [0][0][1][0][RTW89_WW][19] = 66, - [0][0][1][0][RTW89_WW][21] = 66, - [0][0][1][0][RTW89_WW][23] = 66, - [0][0][1][0][RTW89_WW][25] = 66, - [0][0][1][0][RTW89_WW][27] = 66, - [0][0][1][0][RTW89_WW][29] = 66, - [0][0][1][0][RTW89_WW][31] = 66, - [0][0][1][0][RTW89_WW][33] = 66, - [0][0][1][0][RTW89_WW][35] = 60, + [0][0][1][0][RTW89_WW][15] = 54, + [0][0][1][0][RTW89_WW][17] = 54, + [0][0][1][0][RTW89_WW][19] = 54, + [0][0][1][0][RTW89_WW][21] = 54, + [0][0][1][0][RTW89_WW][23] = 54, + [0][0][1][0][RTW89_WW][25] = 54, + [0][0][1][0][RTW89_WW][27] = 54, + [0][0][1][0][RTW89_WW][29] = 54, + [0][0][1][0][RTW89_WW][31] = 54, + [0][0][1][0][RTW89_WW][33] = 54, + [0][0][1][0][RTW89_WW][35] = 54, [0][0][1][0][RTW89_WW][37] = 64, [0][0][1][0][RTW89_WW][38] = 30, [0][0][1][0][RTW89_WW][40] = 30, @@ -30144,21 +30834,21 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_WW][2] = 34, [0][1][1][0][RTW89_WW][4] = 34, [0][1][1][0][RTW89_WW][6] = 36, - [0][1][1][0][RTW89_WW][8] = 46, - [0][1][1][0][RTW89_WW][10] = 46, - [0][1][1][0][RTW89_WW][12] = 46, - [0][1][1][0][RTW89_WW][14] = 46, - [0][1][1][0][RTW89_WW][15] = 54, - [0][1][1][0][RTW89_WW][17] = 54, - [0][1][1][0][RTW89_WW][19] = 54, - [0][1][1][0][RTW89_WW][21] = 54, - [0][1][1][0][RTW89_WW][23] = 54, - [0][1][1][0][RTW89_WW][25] = 54, - [0][1][1][0][RTW89_WW][27] = 54, - [0][1][1][0][RTW89_WW][29] = 54, - [0][1][1][0][RTW89_WW][31] = 54, - [0][1][1][0][RTW89_WW][33] = 54, - [0][1][1][0][RTW89_WW][35] = 52, + [0][1][1][0][RTW89_WW][8] = 42, + [0][1][1][0][RTW89_WW][10] = 42, + [0][1][1][0][RTW89_WW][12] = 42, + [0][1][1][0][RTW89_WW][14] = 42, + [0][1][1][0][RTW89_WW][15] = 42, + [0][1][1][0][RTW89_WW][17] = 42, + [0][1][1][0][RTW89_WW][19] = 42, + [0][1][1][0][RTW89_WW][21] = 42, + [0][1][1][0][RTW89_WW][23] = 42, + [0][1][1][0][RTW89_WW][25] = 42, + [0][1][1][0][RTW89_WW][27] = 42, + [0][1][1][0][RTW89_WW][29] = 42, + [0][1][1][0][RTW89_WW][31] = 42, + [0][1][1][0][RTW89_WW][33] = 42, + [0][1][1][0][RTW89_WW][35] = 42, [0][1][1][0][RTW89_WW][37] = 52, [0][1][1][0][RTW89_WW][38] = 18, [0][1][1][0][RTW89_WW][40] = 18, @@ -30176,17 +30866,17 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_WW][10] = 52, [0][0][2][0][RTW89_WW][12] = 52, [0][0][2][0][RTW89_WW][14] = 52, - [0][0][2][0][RTW89_WW][15] = 66, - [0][0][2][0][RTW89_WW][17] = 66, - [0][0][2][0][RTW89_WW][19] = 66, - [0][0][2][0][RTW89_WW][21] = 66, - [0][0][2][0][RTW89_WW][23] = 66, - [0][0][2][0][RTW89_WW][25] = 66, - [0][0][2][0][RTW89_WW][27] = 66, - [0][0][2][0][RTW89_WW][29] = 66, - [0][0][2][0][RTW89_WW][31] = 66, - [0][0][2][0][RTW89_WW][33] = 66, - [0][0][2][0][RTW89_WW][35] = 56, + [0][0][2][0][RTW89_WW][15] = 54, + [0][0][2][0][RTW89_WW][17] = 54, + [0][0][2][0][RTW89_WW][19] = 54, + [0][0][2][0][RTW89_WW][21] = 54, + [0][0][2][0][RTW89_WW][23] = 54, + [0][0][2][0][RTW89_WW][25] = 54, + [0][0][2][0][RTW89_WW][27] = 54, + [0][0][2][0][RTW89_WW][29] = 54, + [0][0][2][0][RTW89_WW][31] = 54, + [0][0][2][0][RTW89_WW][33] = 54, + [0][0][2][0][RTW89_WW][35] = 54, [0][0][2][0][RTW89_WW][37] = 64, [0][0][2][0][RTW89_WW][38] = 30, [0][0][2][0][RTW89_WW][40] = 30, @@ -30204,17 +30894,17 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_WW][10] = 40, [0][1][2][0][RTW89_WW][12] = 40, [0][1][2][0][RTW89_WW][14] = 40, - [0][1][2][0][RTW89_WW][15] = 54, - [0][1][2][0][RTW89_WW][17] = 54, - [0][1][2][0][RTW89_WW][19] = 54, - [0][1][2][0][RTW89_WW][21] = 54, - [0][1][2][0][RTW89_WW][23] = 54, - [0][1][2][0][RTW89_WW][25] = 54, - [0][1][2][0][RTW89_WW][27] = 54, - [0][1][2][0][RTW89_WW][29] = 54, - [0][1][2][0][RTW89_WW][31] = 54, - [0][1][2][0][RTW89_WW][33] = 54, - [0][1][2][0][RTW89_WW][35] = 46, + [0][1][2][0][RTW89_WW][15] = 42, + [0][1][2][0][RTW89_WW][17] = 42, + [0][1][2][0][RTW89_WW][19] = 42, + [0][1][2][0][RTW89_WW][21] = 42, + [0][1][2][0][RTW89_WW][23] = 42, + [0][1][2][0][RTW89_WW][25] = 42, + [0][1][2][0][RTW89_WW][27] = 42, + [0][1][2][0][RTW89_WW][29] = 42, + [0][1][2][0][RTW89_WW][31] = 42, + [0][1][2][0][RTW89_WW][33] = 42, + [0][1][2][0][RTW89_WW][35] = 42, [0][1][2][0][RTW89_WW][37] = 52, [0][1][2][0][RTW89_WW][38] = 18, [0][1][2][0][RTW89_WW][40] = 18, @@ -30224,25 +30914,25 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_WW][48] = 48, [0][1][2][0][RTW89_WW][50] = 50, [0][1][2][0][RTW89_WW][52] = 48, - [0][1][2][1][RTW89_WW][0] = 36, - [0][1][2][1][RTW89_WW][2] = 36, - [0][1][2][1][RTW89_WW][4] = 36, - [0][1][2][1][RTW89_WW][6] = 36, - [0][1][2][1][RTW89_WW][8] = 36, - [0][1][2][1][RTW89_WW][10] = 36, - [0][1][2][1][RTW89_WW][12] = 36, - [0][1][2][1][RTW89_WW][14] = 36, - [0][1][2][1][RTW89_WW][15] = 40, - [0][1][2][1][RTW89_WW][17] = 40, - [0][1][2][1][RTW89_WW][19] = 40, - [0][1][2][1][RTW89_WW][21] = 40, - [0][1][2][1][RTW89_WW][23] = 40, - [0][1][2][1][RTW89_WW][25] = 40, - [0][1][2][1][RTW89_WW][27] = 40, - [0][1][2][1][RTW89_WW][29] = 40, - [0][1][2][1][RTW89_WW][31] = 40, - [0][1][2][1][RTW89_WW][33] = 40, - [0][1][2][1][RTW89_WW][35] = 40, + [0][1][2][1][RTW89_WW][0] = 30, + [0][1][2][1][RTW89_WW][2] = 30, + [0][1][2][1][RTW89_WW][4] = 30, + [0][1][2][1][RTW89_WW][6] = 30, + [0][1][2][1][RTW89_WW][8] = 30, + [0][1][2][1][RTW89_WW][10] = 30, + [0][1][2][1][RTW89_WW][12] = 30, + [0][1][2][1][RTW89_WW][14] = 30, + [0][1][2][1][RTW89_WW][15] = 30, + [0][1][2][1][RTW89_WW][17] = 30, + [0][1][2][1][RTW89_WW][19] = 30, + [0][1][2][1][RTW89_WW][21] = 30, + [0][1][2][1][RTW89_WW][23] = 30, + [0][1][2][1][RTW89_WW][25] = 30, + [0][1][2][1][RTW89_WW][27] = 30, + [0][1][2][1][RTW89_WW][29] = 30, + [0][1][2][1][RTW89_WW][31] = 30, + [0][1][2][1][RTW89_WW][33] = 30, + [0][1][2][1][RTW89_WW][35] = 30, [0][1][2][1][RTW89_WW][37] = 40, [0][1][2][1][RTW89_WW][38] = 6, [0][1][2][1][RTW89_WW][40] = 6, @@ -30256,11 +30946,11 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_WW][5] = 54, [1][0][2][0][RTW89_WW][9] = 54, [1][0][2][0][RTW89_WW][13] = 52, - [1][0][2][0][RTW89_WW][16] = 56, - [1][0][2][0][RTW89_WW][20] = 56, - [1][0][2][0][RTW89_WW][24] = 56, - [1][0][2][0][RTW89_WW][28] = 66, - [1][0][2][0][RTW89_WW][32] = 62, + [1][0][2][0][RTW89_WW][16] = 54, + [1][0][2][0][RTW89_WW][20] = 54, + [1][0][2][0][RTW89_WW][24] = 54, + [1][0][2][0][RTW89_WW][28] = 54, + [1][0][2][0][RTW89_WW][32] = 54, [1][0][2][0][RTW89_WW][36] = 64, [1][0][2][0][RTW89_WW][39] = 30, [1][0][2][0][RTW89_WW][43] = 30, @@ -30270,25 +30960,25 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_WW][5] = 42, [1][1][2][0][RTW89_WW][9] = 42, [1][1][2][0][RTW89_WW][13] = 42, - [1][1][2][0][RTW89_WW][16] = 54, - [1][1][2][0][RTW89_WW][20] = 54, - [1][1][2][0][RTW89_WW][24] = 54, - [1][1][2][0][RTW89_WW][28] = 54, - [1][1][2][0][RTW89_WW][32] = 54, + [1][1][2][0][RTW89_WW][16] = 42, + [1][1][2][0][RTW89_WW][20] = 42, + [1][1][2][0][RTW89_WW][24] = 42, + [1][1][2][0][RTW89_WW][28] = 42, + [1][1][2][0][RTW89_WW][32] = 42, [1][1][2][0][RTW89_WW][36] = 52, [1][1][2][0][RTW89_WW][39] = 18, [1][1][2][0][RTW89_WW][43] = 18, [1][1][2][0][RTW89_WW][47] = 62, [1][1][2][0][RTW89_WW][51] = 60, - [1][1][2][1][RTW89_WW][1] = 40, - [1][1][2][1][RTW89_WW][5] = 40, - [1][1][2][1][RTW89_WW][9] = 40, - [1][1][2][1][RTW89_WW][13] = 40, - [1][1][2][1][RTW89_WW][16] = 40, - [1][1][2][1][RTW89_WW][20] = 40, - [1][1][2][1][RTW89_WW][24] = 40, - [1][1][2][1][RTW89_WW][28] = 40, - [1][1][2][1][RTW89_WW][32] = 40, + [1][1][2][1][RTW89_WW][1] = 30, + [1][1][2][1][RTW89_WW][5] = 30, + [1][1][2][1][RTW89_WW][9] = 30, + [1][1][2][1][RTW89_WW][13] = 30, + [1][1][2][1][RTW89_WW][16] = 30, + [1][1][2][1][RTW89_WW][20] = 30, + [1][1][2][1][RTW89_WW][24] = 30, + [1][1][2][1][RTW89_WW][28] = 30, + [1][1][2][1][RTW89_WW][32] = 30, [1][1][2][1][RTW89_WW][36] = 40, [1][1][2][1][RTW89_WW][39] = 6, [1][1][2][1][RTW89_WW][43] = 6, @@ -30296,22 +30986,22 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_WW][51] = 60, [2][0][2][0][RTW89_WW][3] = 54, [2][0][2][0][RTW89_WW][11] = 50, - [2][0][2][0][RTW89_WW][18] = 56, - [2][0][2][0][RTW89_WW][26] = 60, + [2][0][2][0][RTW89_WW][18] = 54, + [2][0][2][0][RTW89_WW][26] = 54, [2][0][2][0][RTW89_WW][34] = 60, [2][0][2][0][RTW89_WW][41] = 30, [2][0][2][0][RTW89_WW][49] = 62, - [2][1][2][0][RTW89_WW][3] = 46, + [2][1][2][0][RTW89_WW][3] = 42, [2][1][2][0][RTW89_WW][11] = 38, - [2][1][2][0][RTW89_WW][18] = 50, - [2][1][2][0][RTW89_WW][26] = 52, + [2][1][2][0][RTW89_WW][18] = 42, + [2][1][2][0][RTW89_WW][26] = 42, [2][1][2][0][RTW89_WW][34] = 52, [2][1][2][0][RTW89_WW][41] = 18, [2][1][2][0][RTW89_WW][49] = 62, - [2][1][2][1][RTW89_WW][3] = 40, - [2][1][2][1][RTW89_WW][11] = 38, - [2][1][2][1][RTW89_WW][18] = 40, - [2][1][2][1][RTW89_WW][26] = 42, + [2][1][2][1][RTW89_WW][3] = 30, + [2][1][2][1][RTW89_WW][11] = 30, + [2][1][2][1][RTW89_WW][18] = 30, + [2][1][2][1][RTW89_WW][26] = 30, [2][1][2][1][RTW89_WW][34] = 40, [2][1][2][1][RTW89_WW][41] = 6, [2][1][2][1][RTW89_WW][49] = 62, @@ -30328,34 +31018,50 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ETSI][0] = 66, [0][0][1][0][RTW89_MKK][0] = 66, [0][0][1][0][RTW89_IC][0] = 60, - [0][0][1][0][RTW89_KCC][0] = 52, + [0][0][1][0][RTW89_KCC][0] = 62, [0][0][1][0][RTW89_ACMA][0] = 66, [0][0][1][0][RTW89_CN][0] = 50, [0][0][1][0][RTW89_UK][0] = 66, + [0][0][1][0][RTW89_MEXICO][0] = 62, + [0][0][1][0][RTW89_UKRAINE][0] = 54, + [0][0][1][0][RTW89_CHILE][0] = 70, + [0][0][1][0][RTW89_QATAR][0] = 66, [0][0][1][0][RTW89_FCC][2] = 72, [0][0][1][0][RTW89_ETSI][2] = 66, [0][0][1][0][RTW89_MKK][2] = 66, [0][0][1][0][RTW89_IC][2] = 60, - [0][0][1][0][RTW89_KCC][2] = 52, + [0][0][1][0][RTW89_KCC][2] = 62, [0][0][1][0][RTW89_ACMA][2] = 66, [0][0][1][0][RTW89_CN][2] = 50, [0][0][1][0][RTW89_UK][2] = 66, + [0][0][1][0][RTW89_MEXICO][2] = 62, + [0][0][1][0][RTW89_UKRAINE][2] = 54, + [0][0][1][0][RTW89_CHILE][2] = 70, + [0][0][1][0][RTW89_QATAR][2] = 66, [0][0][1][0][RTW89_FCC][4] = 72, [0][0][1][0][RTW89_ETSI][4] = 66, [0][0][1][0][RTW89_MKK][4] = 66, [0][0][1][0][RTW89_IC][4] = 60, - [0][0][1][0][RTW89_KCC][4] = 52, + [0][0][1][0][RTW89_KCC][4] = 62, [0][0][1][0][RTW89_ACMA][4] = 66, [0][0][1][0][RTW89_CN][4] = 50, [0][0][1][0][RTW89_UK][4] = 66, + [0][0][1][0][RTW89_MEXICO][4] = 62, + [0][0][1][0][RTW89_UKRAINE][4] = 54, + [0][0][1][0][RTW89_CHILE][4] = 70, + [0][0][1][0][RTW89_QATAR][4] = 66, [0][0][1][0][RTW89_FCC][6] = 72, [0][0][1][0][RTW89_ETSI][6] = 66, [0][0][1][0][RTW89_MKK][6] = 66, [0][0][1][0][RTW89_IC][6] = 58, - [0][0][1][0][RTW89_KCC][6] = 62, + [0][0][1][0][RTW89_KCC][6] = 52, [0][0][1][0][RTW89_ACMA][6] = 66, [0][0][1][0][RTW89_CN][6] = 50, [0][0][1][0][RTW89_UK][6] = 66, + [0][0][1][0][RTW89_MEXICO][6] = 62, + [0][0][1][0][RTW89_UKRAINE][6] = 54, + [0][0][1][0][RTW89_CHILE][6] = 70, + [0][0][1][0][RTW89_QATAR][6] = 66, [0][0][1][0][RTW89_FCC][8] = 72, [0][0][1][0][RTW89_ETSI][8] = 66, [0][0][1][0][RTW89_MKK][8] = 66, @@ -30364,6 +31070,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][8] = 66, [0][0][1][0][RTW89_CN][8] = 50, [0][0][1][0][RTW89_UK][8] = 66, + [0][0][1][0][RTW89_MEXICO][8] = 72, + [0][0][1][0][RTW89_UKRAINE][8] = 54, + [0][0][1][0][RTW89_CHILE][8] = 70, + [0][0][1][0][RTW89_QATAR][8] = 66, [0][0][1][0][RTW89_FCC][10] = 72, [0][0][1][0][RTW89_ETSI][10] = 66, [0][0][1][0][RTW89_MKK][10] = 66, @@ -30372,6 +31082,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][10] = 66, [0][0][1][0][RTW89_CN][10] = 50, [0][0][1][0][RTW89_UK][10] = 66, + [0][0][1][0][RTW89_MEXICO][10] = 72, + [0][0][1][0][RTW89_UKRAINE][10] = 54, + [0][0][1][0][RTW89_CHILE][10] = 70, + [0][0][1][0][RTW89_QATAR][10] = 66, [0][0][1][0][RTW89_FCC][12] = 72, [0][0][1][0][RTW89_ETSI][12] = 66, [0][0][1][0][RTW89_MKK][12] = 66, @@ -30380,6 +31094,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][12] = 66, [0][0][1][0][RTW89_CN][12] = 50, [0][0][1][0][RTW89_UK][12] = 66, + [0][0][1][0][RTW89_MEXICO][12] = 72, + [0][0][1][0][RTW89_UKRAINE][12] = 54, + [0][0][1][0][RTW89_CHILE][12] = 70, + [0][0][1][0][RTW89_QATAR][12] = 66, [0][0][1][0][RTW89_FCC][14] = 70, [0][0][1][0][RTW89_ETSI][14] = 66, [0][0][1][0][RTW89_MKK][14] = 66, @@ -30388,6 +31106,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][14] = 66, [0][0][1][0][RTW89_CN][14] = 50, [0][0][1][0][RTW89_UK][14] = 66, + [0][0][1][0][RTW89_MEXICO][14] = 70, + [0][0][1][0][RTW89_UKRAINE][14] = 54, + [0][0][1][0][RTW89_CHILE][14] = 68, + [0][0][1][0][RTW89_QATAR][14] = 66, [0][0][1][0][RTW89_FCC][15] = 72, [0][0][1][0][RTW89_ETSI][15] = 66, [0][0][1][0][RTW89_MKK][15] = 70, @@ -30396,6 +31118,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][15] = 66, [0][0][1][0][RTW89_CN][15] = 127, [0][0][1][0][RTW89_UK][15] = 66, + [0][0][1][0][RTW89_MEXICO][15] = 72, + [0][0][1][0][RTW89_UKRAINE][15] = 54, + [0][0][1][0][RTW89_CHILE][15] = 70, + [0][0][1][0][RTW89_QATAR][15] = 66, [0][0][1][0][RTW89_FCC][17] = 72, [0][0][1][0][RTW89_ETSI][17] = 66, [0][0][1][0][RTW89_MKK][17] = 70, @@ -30404,6 +31130,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][17] = 66, [0][0][1][0][RTW89_CN][17] = 127, [0][0][1][0][RTW89_UK][17] = 66, + [0][0][1][0][RTW89_MEXICO][17] = 72, + [0][0][1][0][RTW89_UKRAINE][17] = 54, + [0][0][1][0][RTW89_CHILE][17] = 70, + [0][0][1][0][RTW89_QATAR][17] = 66, [0][0][1][0][RTW89_FCC][19] = 72, [0][0][1][0][RTW89_ETSI][19] = 66, [0][0][1][0][RTW89_MKK][19] = 70, @@ -30412,6 +31142,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][19] = 66, [0][0][1][0][RTW89_CN][19] = 127, [0][0][1][0][RTW89_UK][19] = 66, + [0][0][1][0][RTW89_MEXICO][19] = 72, + [0][0][1][0][RTW89_UKRAINE][19] = 54, + [0][0][1][0][RTW89_CHILE][19] = 70, + [0][0][1][0][RTW89_QATAR][19] = 66, [0][0][1][0][RTW89_FCC][21] = 72, [0][0][1][0][RTW89_ETSI][21] = 66, [0][0][1][0][RTW89_MKK][21] = 70, @@ -30420,6 +31154,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][21] = 66, [0][0][1][0][RTW89_CN][21] = 127, [0][0][1][0][RTW89_UK][21] = 66, + [0][0][1][0][RTW89_MEXICO][21] = 72, + [0][0][1][0][RTW89_UKRAINE][21] = 54, + [0][0][1][0][RTW89_CHILE][21] = 70, + [0][0][1][0][RTW89_QATAR][21] = 66, [0][0][1][0][RTW89_FCC][23] = 72, [0][0][1][0][RTW89_ETSI][23] = 66, [0][0][1][0][RTW89_MKK][23] = 70, @@ -30428,6 +31166,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][23] = 66, [0][0][1][0][RTW89_CN][23] = 127, [0][0][1][0][RTW89_UK][23] = 66, + [0][0][1][0][RTW89_MEXICO][23] = 72, + [0][0][1][0][RTW89_UKRAINE][23] = 54, + [0][0][1][0][RTW89_CHILE][23] = 70, + [0][0][1][0][RTW89_QATAR][23] = 66, [0][0][1][0][RTW89_FCC][25] = 72, [0][0][1][0][RTW89_ETSI][25] = 66, [0][0][1][0][RTW89_MKK][25] = 70, @@ -30436,6 +31178,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][25] = 127, [0][0][1][0][RTW89_CN][25] = 127, [0][0][1][0][RTW89_UK][25] = 66, + [0][0][1][0][RTW89_MEXICO][25] = 72, + [0][0][1][0][RTW89_UKRAINE][25] = 54, + [0][0][1][0][RTW89_CHILE][25] = 70, + [0][0][1][0][RTW89_QATAR][25] = 66, [0][0][1][0][RTW89_FCC][27] = 72, [0][0][1][0][RTW89_ETSI][27] = 66, [0][0][1][0][RTW89_MKK][27] = 70, @@ -30444,6 +31190,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][27] = 127, [0][0][1][0][RTW89_CN][27] = 127, [0][0][1][0][RTW89_UK][27] = 66, + [0][0][1][0][RTW89_MEXICO][27] = 72, + [0][0][1][0][RTW89_UKRAINE][27] = 54, + [0][0][1][0][RTW89_CHILE][27] = 58, + [0][0][1][0][RTW89_QATAR][27] = 66, [0][0][1][0][RTW89_FCC][29] = 72, [0][0][1][0][RTW89_ETSI][29] = 66, [0][0][1][0][RTW89_MKK][29] = 70, @@ -30452,6 +31202,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][29] = 127, [0][0][1][0][RTW89_CN][29] = 127, [0][0][1][0][RTW89_UK][29] = 66, + [0][0][1][0][RTW89_MEXICO][29] = 72, + [0][0][1][0][RTW89_UKRAINE][29] = 54, + [0][0][1][0][RTW89_CHILE][29] = 58, + [0][0][1][0][RTW89_QATAR][29] = 66, [0][0][1][0][RTW89_FCC][31] = 72, [0][0][1][0][RTW89_ETSI][31] = 66, [0][0][1][0][RTW89_MKK][31] = 70, @@ -30460,6 +31214,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][31] = 66, [0][0][1][0][RTW89_CN][31] = 127, [0][0][1][0][RTW89_UK][31] = 66, + [0][0][1][0][RTW89_MEXICO][31] = 72, + [0][0][1][0][RTW89_UKRAINE][31] = 54, + [0][0][1][0][RTW89_CHILE][31] = 58, + [0][0][1][0][RTW89_QATAR][31] = 66, [0][0][1][0][RTW89_FCC][33] = 72, [0][0][1][0][RTW89_ETSI][33] = 66, [0][0][1][0][RTW89_MKK][33] = 70, @@ -30468,6 +31226,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][33] = 66, [0][0][1][0][RTW89_CN][33] = 127, [0][0][1][0][RTW89_UK][33] = 66, + [0][0][1][0][RTW89_MEXICO][33] = 72, + [0][0][1][0][RTW89_UKRAINE][33] = 54, + [0][0][1][0][RTW89_CHILE][33] = 58, + [0][0][1][0][RTW89_QATAR][33] = 66, [0][0][1][0][RTW89_FCC][35] = 60, [0][0][1][0][RTW89_ETSI][35] = 66, [0][0][1][0][RTW89_MKK][35] = 70, @@ -30476,6 +31238,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][35] = 66, [0][0][1][0][RTW89_CN][35] = 127, [0][0][1][0][RTW89_UK][35] = 66, + [0][0][1][0][RTW89_MEXICO][35] = 60, + [0][0][1][0][RTW89_UKRAINE][35] = 54, + [0][0][1][0][RTW89_CHILE][35] = 58, + [0][0][1][0][RTW89_QATAR][35] = 66, [0][0][1][0][RTW89_FCC][37] = 72, [0][0][1][0][RTW89_ETSI][37] = 127, [0][0][1][0][RTW89_MKK][37] = 70, @@ -30484,6 +31250,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][37] = 70, [0][0][1][0][RTW89_CN][37] = 127, [0][0][1][0][RTW89_UK][37] = 64, + [0][0][1][0][RTW89_MEXICO][37] = 72, + [0][0][1][0][RTW89_UKRAINE][37] = 127, + [0][0][1][0][RTW89_CHILE][37] = 70, + [0][0][1][0][RTW89_QATAR][37] = 127, [0][0][1][0][RTW89_FCC][38] = 72, [0][0][1][0][RTW89_ETSI][38] = 30, [0][0][1][0][RTW89_MKK][38] = 127, @@ -30492,6 +31262,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][38] = 70, [0][0][1][0][RTW89_CN][38] = 68, [0][0][1][0][RTW89_UK][38] = 64, + [0][0][1][0][RTW89_MEXICO][38] = 72, + [0][0][1][0][RTW89_UKRAINE][38] = 30, + [0][0][1][0][RTW89_CHILE][38] = 70, + [0][0][1][0][RTW89_QATAR][38] = 30, [0][0][1][0][RTW89_FCC][40] = 72, [0][0][1][0][RTW89_ETSI][40] = 30, [0][0][1][0][RTW89_MKK][40] = 127, @@ -30500,6 +31274,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][40] = 70, [0][0][1][0][RTW89_CN][40] = 68, [0][0][1][0][RTW89_UK][40] = 64, + [0][0][1][0][RTW89_MEXICO][40] = 72, + [0][0][1][0][RTW89_UKRAINE][40] = 30, + [0][0][1][0][RTW89_CHILE][40] = 70, + [0][0][1][0][RTW89_QATAR][40] = 30, [0][0][1][0][RTW89_FCC][42] = 72, [0][0][1][0][RTW89_ETSI][42] = 30, [0][0][1][0][RTW89_MKK][42] = 127, @@ -30508,6 +31286,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][42] = 70, [0][0][1][0][RTW89_CN][42] = 68, [0][0][1][0][RTW89_UK][42] = 64, + [0][0][1][0][RTW89_MEXICO][42] = 72, + [0][0][1][0][RTW89_UKRAINE][42] = 30, + [0][0][1][0][RTW89_CHILE][42] = 70, + [0][0][1][0][RTW89_QATAR][42] = 30, [0][0][1][0][RTW89_FCC][44] = 72, [0][0][1][0][RTW89_ETSI][44] = 30, [0][0][1][0][RTW89_MKK][44] = 127, @@ -30516,6 +31298,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][44] = 70, [0][0][1][0][RTW89_CN][44] = 68, [0][0][1][0][RTW89_UK][44] = 64, + [0][0][1][0][RTW89_MEXICO][44] = 72, + [0][0][1][0][RTW89_UKRAINE][44] = 30, + [0][0][1][0][RTW89_CHILE][44] = 70, + [0][0][1][0][RTW89_QATAR][44] = 30, [0][0][1][0][RTW89_FCC][46] = 72, [0][0][1][0][RTW89_ETSI][46] = 30, [0][0][1][0][RTW89_MKK][46] = 127, @@ -30524,6 +31310,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][46] = 70, [0][0][1][0][RTW89_CN][46] = 68, [0][0][1][0][RTW89_UK][46] = 64, + [0][0][1][0][RTW89_MEXICO][46] = 72, + [0][0][1][0][RTW89_UKRAINE][46] = 30, + [0][0][1][0][RTW89_CHILE][46] = 70, + [0][0][1][0][RTW89_QATAR][46] = 30, [0][0][1][0][RTW89_FCC][48] = 72, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, @@ -30532,6 +31322,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CN][48] = 127, [0][0][1][0][RTW89_UK][48] = 127, + [0][0][1][0][RTW89_MEXICO][48] = 127, + [0][0][1][0][RTW89_UKRAINE][48] = 127, + [0][0][1][0][RTW89_CHILE][48] = 127, + [0][0][1][0][RTW89_QATAR][48] = 127, [0][0][1][0][RTW89_FCC][50] = 72, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, @@ -30540,6 +31334,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CN][50] = 127, [0][0][1][0][RTW89_UK][50] = 127, + [0][0][1][0][RTW89_MEXICO][50] = 127, + [0][0][1][0][RTW89_UKRAINE][50] = 127, + [0][0][1][0][RTW89_CHILE][50] = 127, + [0][0][1][0][RTW89_QATAR][50] = 127, [0][0][1][0][RTW89_FCC][52] = 72, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, @@ -30548,38 +31346,58 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][52] = 127, [0][0][1][0][RTW89_CN][52] = 127, [0][0][1][0][RTW89_UK][52] = 127, + [0][0][1][0][RTW89_MEXICO][52] = 127, + [0][0][1][0][RTW89_UKRAINE][52] = 127, + [0][0][1][0][RTW89_CHILE][52] = 127, + [0][0][1][0][RTW89_QATAR][52] = 127, [0][1][1][0][RTW89_FCC][0] = 60, [0][1][1][0][RTW89_ETSI][0] = 54, [0][1][1][0][RTW89_MKK][0] = 54, [0][1][1][0][RTW89_IC][0] = 34, - [0][1][1][0][RTW89_KCC][0] = 40, + [0][1][1][0][RTW89_KCC][0] = 60, [0][1][1][0][RTW89_ACMA][0] = 54, [0][1][1][0][RTW89_CN][0] = 46, [0][1][1][0][RTW89_UK][0] = 54, + [0][1][1][0][RTW89_MEXICO][0] = 50, + [0][1][1][0][RTW89_UKRAINE][0] = 42, + [0][1][1][0][RTW89_CHILE][0] = 60, + [0][1][1][0][RTW89_QATAR][0] = 54, [0][1][1][0][RTW89_FCC][2] = 60, [0][1][1][0][RTW89_ETSI][2] = 54, [0][1][1][0][RTW89_MKK][2] = 54, [0][1][1][0][RTW89_IC][2] = 34, - [0][1][1][0][RTW89_KCC][2] = 40, + [0][1][1][0][RTW89_KCC][2] = 60, [0][1][1][0][RTW89_ACMA][2] = 54, [0][1][1][0][RTW89_CN][2] = 46, [0][1][1][0][RTW89_UK][2] = 54, + [0][1][1][0][RTW89_MEXICO][2] = 50, + [0][1][1][0][RTW89_UKRAINE][2] = 42, + [0][1][1][0][RTW89_CHILE][2] = 60, + [0][1][1][0][RTW89_QATAR][2] = 54, [0][1][1][0][RTW89_FCC][4] = 60, [0][1][1][0][RTW89_ETSI][4] = 54, [0][1][1][0][RTW89_MKK][4] = 54, [0][1][1][0][RTW89_IC][4] = 34, - [0][1][1][0][RTW89_KCC][4] = 40, + [0][1][1][0][RTW89_KCC][4] = 60, [0][1][1][0][RTW89_ACMA][4] = 54, [0][1][1][0][RTW89_CN][4] = 46, [0][1][1][0][RTW89_UK][4] = 54, + [0][1][1][0][RTW89_MEXICO][4] = 50, + [0][1][1][0][RTW89_UKRAINE][4] = 42, + [0][1][1][0][RTW89_CHILE][4] = 60, + [0][1][1][0][RTW89_QATAR][4] = 54, [0][1][1][0][RTW89_FCC][6] = 60, [0][1][1][0][RTW89_ETSI][6] = 54, [0][1][1][0][RTW89_MKK][6] = 54, [0][1][1][0][RTW89_IC][6] = 36, - [0][1][1][0][RTW89_KCC][6] = 60, + [0][1][1][0][RTW89_KCC][6] = 40, [0][1][1][0][RTW89_ACMA][6] = 54, [0][1][1][0][RTW89_CN][6] = 46, [0][1][1][0][RTW89_UK][6] = 54, + [0][1][1][0][RTW89_MEXICO][6] = 50, + [0][1][1][0][RTW89_UKRAINE][6] = 42, + [0][1][1][0][RTW89_CHILE][6] = 60, + [0][1][1][0][RTW89_QATAR][6] = 54, [0][1][1][0][RTW89_FCC][8] = 62, [0][1][1][0][RTW89_ETSI][8] = 54, [0][1][1][0][RTW89_MKK][8] = 52, @@ -30588,6 +31406,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][8] = 54, [0][1][1][0][RTW89_CN][8] = 46, [0][1][1][0][RTW89_UK][8] = 54, + [0][1][1][0][RTW89_MEXICO][8] = 62, + [0][1][1][0][RTW89_UKRAINE][8] = 42, + [0][1][1][0][RTW89_CHILE][8] = 62, + [0][1][1][0][RTW89_QATAR][8] = 54, [0][1][1][0][RTW89_FCC][10] = 62, [0][1][1][0][RTW89_ETSI][10] = 54, [0][1][1][0][RTW89_MKK][10] = 54, @@ -30596,6 +31418,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][10] = 54, [0][1][1][0][RTW89_CN][10] = 46, [0][1][1][0][RTW89_UK][10] = 54, + [0][1][1][0][RTW89_MEXICO][10] = 62, + [0][1][1][0][RTW89_UKRAINE][10] = 42, + [0][1][1][0][RTW89_CHILE][10] = 62, + [0][1][1][0][RTW89_QATAR][10] = 54, [0][1][1][0][RTW89_FCC][12] = 62, [0][1][1][0][RTW89_ETSI][12] = 54, [0][1][1][0][RTW89_MKK][12] = 54, @@ -30604,6 +31430,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][12] = 54, [0][1][1][0][RTW89_CN][12] = 46, [0][1][1][0][RTW89_UK][12] = 54, + [0][1][1][0][RTW89_MEXICO][12] = 62, + [0][1][1][0][RTW89_UKRAINE][12] = 42, + [0][1][1][0][RTW89_CHILE][12] = 62, + [0][1][1][0][RTW89_QATAR][12] = 54, [0][1][1][0][RTW89_FCC][14] = 60, [0][1][1][0][RTW89_ETSI][14] = 54, [0][1][1][0][RTW89_MKK][14] = 54, @@ -30612,6 +31442,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][14] = 54, [0][1][1][0][RTW89_CN][14] = 46, [0][1][1][0][RTW89_UK][14] = 54, + [0][1][1][0][RTW89_MEXICO][14] = 60, + [0][1][1][0][RTW89_UKRAINE][14] = 42, + [0][1][1][0][RTW89_CHILE][14] = 60, + [0][1][1][0][RTW89_QATAR][14] = 54, [0][1][1][0][RTW89_FCC][15] = 60, [0][1][1][0][RTW89_ETSI][15] = 54, [0][1][1][0][RTW89_MKK][15] = 70, @@ -30620,6 +31454,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][15] = 54, [0][1][1][0][RTW89_CN][15] = 127, [0][1][1][0][RTW89_UK][15] = 54, + [0][1][1][0][RTW89_MEXICO][15] = 60, + [0][1][1][0][RTW89_UKRAINE][15] = 42, + [0][1][1][0][RTW89_CHILE][15] = 60, + [0][1][1][0][RTW89_QATAR][15] = 54, [0][1][1][0][RTW89_FCC][17] = 60, [0][1][1][0][RTW89_ETSI][17] = 54, [0][1][1][0][RTW89_MKK][17] = 70, @@ -30628,6 +31466,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][17] = 54, [0][1][1][0][RTW89_CN][17] = 127, [0][1][1][0][RTW89_UK][17] = 54, + [0][1][1][0][RTW89_MEXICO][17] = 60, + [0][1][1][0][RTW89_UKRAINE][17] = 42, + [0][1][1][0][RTW89_CHILE][17] = 60, + [0][1][1][0][RTW89_QATAR][17] = 54, [0][1][1][0][RTW89_FCC][19] = 60, [0][1][1][0][RTW89_ETSI][19] = 54, [0][1][1][0][RTW89_MKK][19] = 70, @@ -30636,6 +31478,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][19] = 54, [0][1][1][0][RTW89_CN][19] = 127, [0][1][1][0][RTW89_UK][19] = 54, + [0][1][1][0][RTW89_MEXICO][19] = 60, + [0][1][1][0][RTW89_UKRAINE][19] = 42, + [0][1][1][0][RTW89_CHILE][19] = 60, + [0][1][1][0][RTW89_QATAR][19] = 54, [0][1][1][0][RTW89_FCC][21] = 60, [0][1][1][0][RTW89_ETSI][21] = 54, [0][1][1][0][RTW89_MKK][21] = 70, @@ -30644,6 +31490,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][21] = 54, [0][1][1][0][RTW89_CN][21] = 127, [0][1][1][0][RTW89_UK][21] = 54, + [0][1][1][0][RTW89_MEXICO][21] = 60, + [0][1][1][0][RTW89_UKRAINE][21] = 42, + [0][1][1][0][RTW89_CHILE][21] = 60, + [0][1][1][0][RTW89_QATAR][21] = 54, [0][1][1][0][RTW89_FCC][23] = 60, [0][1][1][0][RTW89_ETSI][23] = 54, [0][1][1][0][RTW89_MKK][23] = 70, @@ -30652,6 +31502,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][23] = 54, [0][1][1][0][RTW89_CN][23] = 127, [0][1][1][0][RTW89_UK][23] = 54, + [0][1][1][0][RTW89_MEXICO][23] = 60, + [0][1][1][0][RTW89_UKRAINE][23] = 42, + [0][1][1][0][RTW89_CHILE][23] = 60, + [0][1][1][0][RTW89_QATAR][23] = 54, [0][1][1][0][RTW89_FCC][25] = 60, [0][1][1][0][RTW89_ETSI][25] = 54, [0][1][1][0][RTW89_MKK][25] = 70, @@ -30660,6 +31514,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][25] = 127, [0][1][1][0][RTW89_CN][25] = 127, [0][1][1][0][RTW89_UK][25] = 54, + [0][1][1][0][RTW89_MEXICO][25] = 60, + [0][1][1][0][RTW89_UKRAINE][25] = 42, + [0][1][1][0][RTW89_CHILE][25] = 60, + [0][1][1][0][RTW89_QATAR][25] = 54, [0][1][1][0][RTW89_FCC][27] = 60, [0][1][1][0][RTW89_ETSI][27] = 54, [0][1][1][0][RTW89_MKK][27] = 70, @@ -30668,6 +31526,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][27] = 127, [0][1][1][0][RTW89_CN][27] = 127, [0][1][1][0][RTW89_UK][27] = 54, + [0][1][1][0][RTW89_MEXICO][27] = 60, + [0][1][1][0][RTW89_UKRAINE][27] = 42, + [0][1][1][0][RTW89_CHILE][27] = 52, + [0][1][1][0][RTW89_QATAR][27] = 54, [0][1][1][0][RTW89_FCC][29] = 60, [0][1][1][0][RTW89_ETSI][29] = 54, [0][1][1][0][RTW89_MKK][29] = 70, @@ -30676,6 +31538,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][29] = 127, [0][1][1][0][RTW89_CN][29] = 127, [0][1][1][0][RTW89_UK][29] = 54, + [0][1][1][0][RTW89_MEXICO][29] = 60, + [0][1][1][0][RTW89_UKRAINE][29] = 42, + [0][1][1][0][RTW89_CHILE][29] = 52, + [0][1][1][0][RTW89_QATAR][29] = 54, [0][1][1][0][RTW89_FCC][31] = 60, [0][1][1][0][RTW89_ETSI][31] = 54, [0][1][1][0][RTW89_MKK][31] = 70, @@ -30684,6 +31550,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][31] = 54, [0][1][1][0][RTW89_CN][31] = 127, [0][1][1][0][RTW89_UK][31] = 54, + [0][1][1][0][RTW89_MEXICO][31] = 60, + [0][1][1][0][RTW89_UKRAINE][31] = 42, + [0][1][1][0][RTW89_CHILE][31] = 52, + [0][1][1][0][RTW89_QATAR][31] = 54, [0][1][1][0][RTW89_FCC][33] = 60, [0][1][1][0][RTW89_ETSI][33] = 54, [0][1][1][0][RTW89_MKK][33] = 70, @@ -30692,6 +31562,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][33] = 54, [0][1][1][0][RTW89_CN][33] = 127, [0][1][1][0][RTW89_UK][33] = 54, + [0][1][1][0][RTW89_MEXICO][33] = 60, + [0][1][1][0][RTW89_UKRAINE][33] = 42, + [0][1][1][0][RTW89_CHILE][33] = 52, + [0][1][1][0][RTW89_QATAR][33] = 54, [0][1][1][0][RTW89_FCC][35] = 52, [0][1][1][0][RTW89_ETSI][35] = 54, [0][1][1][0][RTW89_MKK][35] = 70, @@ -30700,6 +31574,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][35] = 54, [0][1][1][0][RTW89_CN][35] = 127, [0][1][1][0][RTW89_UK][35] = 54, + [0][1][1][0][RTW89_MEXICO][35] = 52, + [0][1][1][0][RTW89_UKRAINE][35] = 42, + [0][1][1][0][RTW89_CHILE][35] = 52, + [0][1][1][0][RTW89_QATAR][35] = 54, [0][1][1][0][RTW89_FCC][37] = 62, [0][1][1][0][RTW89_ETSI][37] = 127, [0][1][1][0][RTW89_MKK][37] = 70, @@ -30708,6 +31586,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][37] = 64, [0][1][1][0][RTW89_CN][37] = 127, [0][1][1][0][RTW89_UK][37] = 52, + [0][1][1][0][RTW89_MEXICO][37] = 62, + [0][1][1][0][RTW89_UKRAINE][37] = 127, + [0][1][1][0][RTW89_CHILE][37] = 62, + [0][1][1][0][RTW89_QATAR][37] = 127, [0][1][1][0][RTW89_FCC][38] = 72, [0][1][1][0][RTW89_ETSI][38] = 18, [0][1][1][0][RTW89_MKK][38] = 127, @@ -30716,6 +31598,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][38] = 70, [0][1][1][0][RTW89_CN][38] = 64, [0][1][1][0][RTW89_UK][38] = 52, + [0][1][1][0][RTW89_MEXICO][38] = 72, + [0][1][1][0][RTW89_UKRAINE][38] = 18, + [0][1][1][0][RTW89_CHILE][38] = 70, + [0][1][1][0][RTW89_QATAR][38] = 18, [0][1][1][0][RTW89_FCC][40] = 72, [0][1][1][0][RTW89_ETSI][40] = 18, [0][1][1][0][RTW89_MKK][40] = 127, @@ -30724,6 +31610,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][40] = 70, [0][1][1][0][RTW89_CN][40] = 64, [0][1][1][0][RTW89_UK][40] = 52, + [0][1][1][0][RTW89_MEXICO][40] = 72, + [0][1][1][0][RTW89_UKRAINE][40] = 18, + [0][1][1][0][RTW89_CHILE][40] = 70, + [0][1][1][0][RTW89_QATAR][40] = 18, [0][1][1][0][RTW89_FCC][42] = 72, [0][1][1][0][RTW89_ETSI][42] = 18, [0][1][1][0][RTW89_MKK][42] = 127, @@ -30732,6 +31622,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][42] = 70, [0][1][1][0][RTW89_CN][42] = 64, [0][1][1][0][RTW89_UK][42] = 52, + [0][1][1][0][RTW89_MEXICO][42] = 72, + [0][1][1][0][RTW89_UKRAINE][42] = 18, + [0][1][1][0][RTW89_CHILE][42] = 70, + [0][1][1][0][RTW89_QATAR][42] = 18, [0][1][1][0][RTW89_FCC][44] = 72, [0][1][1][0][RTW89_ETSI][44] = 18, [0][1][1][0][RTW89_MKK][44] = 127, @@ -30740,6 +31634,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][44] = 70, [0][1][1][0][RTW89_CN][44] = 60, [0][1][1][0][RTW89_UK][44] = 52, + [0][1][1][0][RTW89_MEXICO][44] = 72, + [0][1][1][0][RTW89_UKRAINE][44] = 18, + [0][1][1][0][RTW89_CHILE][44] = 70, + [0][1][1][0][RTW89_QATAR][44] = 18, [0][1][1][0][RTW89_FCC][46] = 72, [0][1][1][0][RTW89_ETSI][46] = 18, [0][1][1][0][RTW89_MKK][46] = 127, @@ -30748,6 +31646,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][46] = 70, [0][1][1][0][RTW89_CN][46] = 60, [0][1][1][0][RTW89_UK][46] = 52, + [0][1][1][0][RTW89_MEXICO][46] = 72, + [0][1][1][0][RTW89_UKRAINE][46] = 18, + [0][1][1][0][RTW89_CHILE][46] = 70, + [0][1][1][0][RTW89_QATAR][46] = 18, [0][1][1][0][RTW89_FCC][48] = 48, [0][1][1][0][RTW89_ETSI][48] = 127, [0][1][1][0][RTW89_MKK][48] = 127, @@ -30756,6 +31658,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][48] = 127, [0][1][1][0][RTW89_CN][48] = 127, [0][1][1][0][RTW89_UK][48] = 127, + [0][1][1][0][RTW89_MEXICO][48] = 127, + [0][1][1][0][RTW89_UKRAINE][48] = 127, + [0][1][1][0][RTW89_CHILE][48] = 127, + [0][1][1][0][RTW89_QATAR][48] = 127, [0][1][1][0][RTW89_FCC][50] = 48, [0][1][1][0][RTW89_ETSI][50] = 127, [0][1][1][0][RTW89_MKK][50] = 127, @@ -30764,6 +31670,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][50] = 127, [0][1][1][0][RTW89_CN][50] = 127, [0][1][1][0][RTW89_UK][50] = 127, + [0][1][1][0][RTW89_MEXICO][50] = 127, + [0][1][1][0][RTW89_UKRAINE][50] = 127, + [0][1][1][0][RTW89_CHILE][50] = 127, + [0][1][1][0][RTW89_QATAR][50] = 127, [0][1][1][0][RTW89_FCC][52] = 48, [0][1][1][0][RTW89_ETSI][52] = 127, [0][1][1][0][RTW89_MKK][52] = 127, @@ -30772,38 +31682,58 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][52] = 127, [0][1][1][0][RTW89_CN][52] = 127, [0][1][1][0][RTW89_UK][52] = 127, + [0][1][1][0][RTW89_MEXICO][52] = 127, + [0][1][1][0][RTW89_UKRAINE][52] = 127, + [0][1][1][0][RTW89_CHILE][52] = 127, + [0][1][1][0][RTW89_QATAR][52] = 127, [0][0][2][0][RTW89_FCC][0] = 70, [0][0][2][0][RTW89_ETSI][0] = 66, [0][0][2][0][RTW89_MKK][0] = 68, [0][0][2][0][RTW89_IC][0] = 60, - [0][0][2][0][RTW89_KCC][0] = 54, + [0][0][2][0][RTW89_KCC][0] = 68, [0][0][2][0][RTW89_ACMA][0] = 66, [0][0][2][0][RTW89_CN][0] = 52, [0][0][2][0][RTW89_UK][0] = 66, + [0][0][2][0][RTW89_MEXICO][0] = 62, + [0][0][2][0][RTW89_UKRAINE][0] = 54, + [0][0][2][0][RTW89_CHILE][0] = 68, + [0][0][2][0][RTW89_QATAR][0] = 66, [0][0][2][0][RTW89_FCC][2] = 72, [0][0][2][0][RTW89_ETSI][2] = 66, [0][0][2][0][RTW89_MKK][2] = 68, [0][0][2][0][RTW89_IC][2] = 60, - [0][0][2][0][RTW89_KCC][2] = 54, + [0][0][2][0][RTW89_KCC][2] = 68, [0][0][2][0][RTW89_ACMA][2] = 66, [0][0][2][0][RTW89_CN][2] = 52, [0][0][2][0][RTW89_UK][2] = 66, + [0][0][2][0][RTW89_MEXICO][2] = 62, + [0][0][2][0][RTW89_UKRAINE][2] = 54, + [0][0][2][0][RTW89_CHILE][2] = 70, + [0][0][2][0][RTW89_QATAR][2] = 66, [0][0][2][0][RTW89_FCC][4] = 72, [0][0][2][0][RTW89_ETSI][4] = 66, [0][0][2][0][RTW89_MKK][4] = 68, [0][0][2][0][RTW89_IC][4] = 60, - [0][0][2][0][RTW89_KCC][4] = 54, + [0][0][2][0][RTW89_KCC][4] = 68, [0][0][2][0][RTW89_ACMA][4] = 66, [0][0][2][0][RTW89_CN][4] = 52, [0][0][2][0][RTW89_UK][4] = 66, + [0][0][2][0][RTW89_MEXICO][4] = 62, + [0][0][2][0][RTW89_UKRAINE][4] = 54, + [0][0][2][0][RTW89_CHILE][4] = 70, + [0][0][2][0][RTW89_QATAR][4] = 66, [0][0][2][0][RTW89_FCC][6] = 72, [0][0][2][0][RTW89_ETSI][6] = 66, [0][0][2][0][RTW89_MKK][6] = 60, [0][0][2][0][RTW89_IC][6] = 60, - [0][0][2][0][RTW89_KCC][6] = 68, + [0][0][2][0][RTW89_KCC][6] = 54, [0][0][2][0][RTW89_ACMA][6] = 66, [0][0][2][0][RTW89_CN][6] = 52, [0][0][2][0][RTW89_UK][6] = 66, + [0][0][2][0][RTW89_MEXICO][6] = 62, + [0][0][2][0][RTW89_UKRAINE][6] = 54, + [0][0][2][0][RTW89_CHILE][6] = 70, + [0][0][2][0][RTW89_QATAR][6] = 66, [0][0][2][0][RTW89_FCC][8] = 72, [0][0][2][0][RTW89_ETSI][8] = 66, [0][0][2][0][RTW89_MKK][8] = 58, @@ -30812,6 +31742,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][8] = 66, [0][0][2][0][RTW89_CN][8] = 52, [0][0][2][0][RTW89_UK][8] = 66, + [0][0][2][0][RTW89_MEXICO][8] = 72, + [0][0][2][0][RTW89_UKRAINE][8] = 54, + [0][0][2][0][RTW89_CHILE][8] = 70, + [0][0][2][0][RTW89_QATAR][8] = 66, [0][0][2][0][RTW89_FCC][10] = 72, [0][0][2][0][RTW89_ETSI][10] = 66, [0][0][2][0][RTW89_MKK][10] = 70, @@ -30820,6 +31754,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][10] = 66, [0][0][2][0][RTW89_CN][10] = 52, [0][0][2][0][RTW89_UK][10] = 66, + [0][0][2][0][RTW89_MEXICO][10] = 72, + [0][0][2][0][RTW89_UKRAINE][10] = 54, + [0][0][2][0][RTW89_CHILE][10] = 70, + [0][0][2][0][RTW89_QATAR][10] = 66, [0][0][2][0][RTW89_FCC][12] = 72, [0][0][2][0][RTW89_ETSI][12] = 66, [0][0][2][0][RTW89_MKK][12] = 70, @@ -30828,6 +31766,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][12] = 66, [0][0][2][0][RTW89_CN][12] = 52, [0][0][2][0][RTW89_UK][12] = 66, + [0][0][2][0][RTW89_MEXICO][12] = 72, + [0][0][2][0][RTW89_UKRAINE][12] = 54, + [0][0][2][0][RTW89_CHILE][12] = 70, + [0][0][2][0][RTW89_QATAR][12] = 66, [0][0][2][0][RTW89_FCC][14] = 68, [0][0][2][0][RTW89_ETSI][14] = 66, [0][0][2][0][RTW89_MKK][14] = 70, @@ -30836,6 +31778,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][14] = 66, [0][0][2][0][RTW89_CN][14] = 52, [0][0][2][0][RTW89_UK][14] = 66, + [0][0][2][0][RTW89_MEXICO][14] = 68, + [0][0][2][0][RTW89_UKRAINE][14] = 54, + [0][0][2][0][RTW89_CHILE][14] = 66, + [0][0][2][0][RTW89_QATAR][14] = 66, [0][0][2][0][RTW89_FCC][15] = 70, [0][0][2][0][RTW89_ETSI][15] = 66, [0][0][2][0][RTW89_MKK][15] = 70, @@ -30844,6 +31790,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][15] = 66, [0][0][2][0][RTW89_CN][15] = 127, [0][0][2][0][RTW89_UK][15] = 66, + [0][0][2][0][RTW89_MEXICO][15] = 70, + [0][0][2][0][RTW89_UKRAINE][15] = 54, + [0][0][2][0][RTW89_CHILE][15] = 68, + [0][0][2][0][RTW89_QATAR][15] = 66, [0][0][2][0][RTW89_FCC][17] = 72, [0][0][2][0][RTW89_ETSI][17] = 66, [0][0][2][0][RTW89_MKK][17] = 70, @@ -30852,6 +31802,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][17] = 66, [0][0][2][0][RTW89_CN][17] = 127, [0][0][2][0][RTW89_UK][17] = 66, + [0][0][2][0][RTW89_MEXICO][17] = 72, + [0][0][2][0][RTW89_UKRAINE][17] = 54, + [0][0][2][0][RTW89_CHILE][17] = 68, + [0][0][2][0][RTW89_QATAR][17] = 66, [0][0][2][0][RTW89_FCC][19] = 72, [0][0][2][0][RTW89_ETSI][19] = 66, [0][0][2][0][RTW89_MKK][19] = 70, @@ -30860,6 +31814,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][19] = 66, [0][0][2][0][RTW89_CN][19] = 127, [0][0][2][0][RTW89_UK][19] = 66, + [0][0][2][0][RTW89_MEXICO][19] = 72, + [0][0][2][0][RTW89_UKRAINE][19] = 54, + [0][0][2][0][RTW89_CHILE][19] = 68, + [0][0][2][0][RTW89_QATAR][19] = 66, [0][0][2][0][RTW89_FCC][21] = 72, [0][0][2][0][RTW89_ETSI][21] = 66, [0][0][2][0][RTW89_MKK][21] = 70, @@ -30868,6 +31826,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][21] = 66, [0][0][2][0][RTW89_CN][21] = 127, [0][0][2][0][RTW89_UK][21] = 66, + [0][0][2][0][RTW89_MEXICO][21] = 72, + [0][0][2][0][RTW89_UKRAINE][21] = 54, + [0][0][2][0][RTW89_CHILE][21] = 70, + [0][0][2][0][RTW89_QATAR][21] = 66, [0][0][2][0][RTW89_FCC][23] = 72, [0][0][2][0][RTW89_ETSI][23] = 66, [0][0][2][0][RTW89_MKK][23] = 70, @@ -30876,6 +31838,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][23] = 66, [0][0][2][0][RTW89_CN][23] = 127, [0][0][2][0][RTW89_UK][23] = 66, + [0][0][2][0][RTW89_MEXICO][23] = 72, + [0][0][2][0][RTW89_UKRAINE][23] = 54, + [0][0][2][0][RTW89_CHILE][23] = 70, + [0][0][2][0][RTW89_QATAR][23] = 66, [0][0][2][0][RTW89_FCC][25] = 72, [0][0][2][0][RTW89_ETSI][25] = 66, [0][0][2][0][RTW89_MKK][25] = 70, @@ -30884,6 +31850,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][25] = 127, [0][0][2][0][RTW89_CN][25] = 127, [0][0][2][0][RTW89_UK][25] = 66, + [0][0][2][0][RTW89_MEXICO][25] = 72, + [0][0][2][0][RTW89_UKRAINE][25] = 54, + [0][0][2][0][RTW89_CHILE][25] = 70, + [0][0][2][0][RTW89_QATAR][25] = 66, [0][0][2][0][RTW89_FCC][27] = 72, [0][0][2][0][RTW89_ETSI][27] = 66, [0][0][2][0][RTW89_MKK][27] = 70, @@ -30892,6 +31862,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][27] = 127, [0][0][2][0][RTW89_CN][27] = 127, [0][0][2][0][RTW89_UK][27] = 66, + [0][0][2][0][RTW89_MEXICO][27] = 72, + [0][0][2][0][RTW89_UKRAINE][27] = 54, + [0][0][2][0][RTW89_CHILE][27] = 56, + [0][0][2][0][RTW89_QATAR][27] = 66, [0][0][2][0][RTW89_FCC][29] = 72, [0][0][2][0][RTW89_ETSI][29] = 66, [0][0][2][0][RTW89_MKK][29] = 70, @@ -30900,6 +31874,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][29] = 127, [0][0][2][0][RTW89_CN][29] = 127, [0][0][2][0][RTW89_UK][29] = 66, + [0][0][2][0][RTW89_MEXICO][29] = 72, + [0][0][2][0][RTW89_UKRAINE][29] = 54, + [0][0][2][0][RTW89_CHILE][29] = 56, + [0][0][2][0][RTW89_QATAR][29] = 66, [0][0][2][0][RTW89_FCC][31] = 72, [0][0][2][0][RTW89_ETSI][31] = 66, [0][0][2][0][RTW89_MKK][31] = 70, @@ -30908,6 +31886,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][31] = 66, [0][0][2][0][RTW89_CN][31] = 127, [0][0][2][0][RTW89_UK][31] = 66, + [0][0][2][0][RTW89_MEXICO][31] = 72, + [0][0][2][0][RTW89_UKRAINE][31] = 54, + [0][0][2][0][RTW89_CHILE][31] = 56, + [0][0][2][0][RTW89_QATAR][31] = 66, [0][0][2][0][RTW89_FCC][33] = 72, [0][0][2][0][RTW89_ETSI][33] = 66, [0][0][2][0][RTW89_MKK][33] = 70, @@ -30916,6 +31898,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][33] = 66, [0][0][2][0][RTW89_CN][33] = 127, [0][0][2][0][RTW89_UK][33] = 66, + [0][0][2][0][RTW89_MEXICO][33] = 72, + [0][0][2][0][RTW89_UKRAINE][33] = 54, + [0][0][2][0][RTW89_CHILE][33] = 56, + [0][0][2][0][RTW89_QATAR][33] = 66, [0][0][2][0][RTW89_FCC][35] = 56, [0][0][2][0][RTW89_ETSI][35] = 66, [0][0][2][0][RTW89_MKK][35] = 70, @@ -30924,6 +31910,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][35] = 66, [0][0][2][0][RTW89_CN][35] = 127, [0][0][2][0][RTW89_UK][35] = 66, + [0][0][2][0][RTW89_MEXICO][35] = 56, + [0][0][2][0][RTW89_UKRAINE][35] = 54, + [0][0][2][0][RTW89_CHILE][35] = 56, + [0][0][2][0][RTW89_QATAR][35] = 66, [0][0][2][0][RTW89_FCC][37] = 72, [0][0][2][0][RTW89_ETSI][37] = 127, [0][0][2][0][RTW89_MKK][37] = 70, @@ -30932,6 +31922,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][37] = 70, [0][0][2][0][RTW89_CN][37] = 127, [0][0][2][0][RTW89_UK][37] = 64, + [0][0][2][0][RTW89_MEXICO][37] = 72, + [0][0][2][0][RTW89_UKRAINE][37] = 127, + [0][0][2][0][RTW89_CHILE][37] = 70, + [0][0][2][0][RTW89_QATAR][37] = 127, [0][0][2][0][RTW89_FCC][38] = 72, [0][0][2][0][RTW89_ETSI][38] = 30, [0][0][2][0][RTW89_MKK][38] = 127, @@ -30940,6 +31934,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][38] = 70, [0][0][2][0][RTW89_CN][38] = 68, [0][0][2][0][RTW89_UK][38] = 64, + [0][0][2][0][RTW89_MEXICO][38] = 72, + [0][0][2][0][RTW89_UKRAINE][38] = 30, + [0][0][2][0][RTW89_CHILE][38] = 70, + [0][0][2][0][RTW89_QATAR][38] = 30, [0][0][2][0][RTW89_FCC][40] = 72, [0][0][2][0][RTW89_ETSI][40] = 30, [0][0][2][0][RTW89_MKK][40] = 127, @@ -30948,6 +31946,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][40] = 70, [0][0][2][0][RTW89_CN][40] = 68, [0][0][2][0][RTW89_UK][40] = 64, + [0][0][2][0][RTW89_MEXICO][40] = 72, + [0][0][2][0][RTW89_UKRAINE][40] = 30, + [0][0][2][0][RTW89_CHILE][40] = 70, + [0][0][2][0][RTW89_QATAR][40] = 30, [0][0][2][0][RTW89_FCC][42] = 72, [0][0][2][0][RTW89_ETSI][42] = 30, [0][0][2][0][RTW89_MKK][42] = 127, @@ -30956,6 +31958,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][42] = 70, [0][0][2][0][RTW89_CN][42] = 68, [0][0][2][0][RTW89_UK][42] = 64, + [0][0][2][0][RTW89_MEXICO][42] = 72, + [0][0][2][0][RTW89_UKRAINE][42] = 30, + [0][0][2][0][RTW89_CHILE][42] = 70, + [0][0][2][0][RTW89_QATAR][42] = 30, [0][0][2][0][RTW89_FCC][44] = 72, [0][0][2][0][RTW89_ETSI][44] = 30, [0][0][2][0][RTW89_MKK][44] = 127, @@ -30964,6 +31970,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][44] = 70, [0][0][2][0][RTW89_CN][44] = 68, [0][0][2][0][RTW89_UK][44] = 64, + [0][0][2][0][RTW89_MEXICO][44] = 72, + [0][0][2][0][RTW89_UKRAINE][44] = 30, + [0][0][2][0][RTW89_CHILE][44] = 70, + [0][0][2][0][RTW89_QATAR][44] = 30, [0][0][2][0][RTW89_FCC][46] = 72, [0][0][2][0][RTW89_ETSI][46] = 30, [0][0][2][0][RTW89_MKK][46] = 127, @@ -30972,6 +31982,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][46] = 70, [0][0][2][0][RTW89_CN][46] = 68, [0][0][2][0][RTW89_UK][46] = 64, + [0][0][2][0][RTW89_MEXICO][46] = 72, + [0][0][2][0][RTW89_UKRAINE][46] = 30, + [0][0][2][0][RTW89_CHILE][46] = 70, + [0][0][2][0][RTW89_QATAR][46] = 30, [0][0][2][0][RTW89_FCC][48] = 72, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, @@ -30980,6 +31994,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CN][48] = 127, [0][0][2][0][RTW89_UK][48] = 127, + [0][0][2][0][RTW89_MEXICO][48] = 127, + [0][0][2][0][RTW89_UKRAINE][48] = 127, + [0][0][2][0][RTW89_CHILE][48] = 127, + [0][0][2][0][RTW89_QATAR][48] = 127, [0][0][2][0][RTW89_FCC][50] = 72, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, @@ -30988,6 +32006,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CN][50] = 127, [0][0][2][0][RTW89_UK][50] = 127, + [0][0][2][0][RTW89_MEXICO][50] = 127, + [0][0][2][0][RTW89_UKRAINE][50] = 127, + [0][0][2][0][RTW89_CHILE][50] = 127, + [0][0][2][0][RTW89_QATAR][50] = 127, [0][0][2][0][RTW89_FCC][52] = 72, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, @@ -30996,38 +32018,58 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][52] = 127, [0][0][2][0][RTW89_CN][52] = 127, [0][0][2][0][RTW89_UK][52] = 127, + [0][0][2][0][RTW89_MEXICO][52] = 127, + [0][0][2][0][RTW89_UKRAINE][52] = 127, + [0][0][2][0][RTW89_CHILE][52] = 127, + [0][0][2][0][RTW89_QATAR][52] = 127, [0][1][2][0][RTW89_FCC][0] = 60, [0][1][2][0][RTW89_ETSI][0] = 54, [0][1][2][0][RTW89_MKK][0] = 54, [0][1][2][0][RTW89_IC][0] = 36, - [0][1][2][0][RTW89_KCC][0] = 40, + [0][1][2][0][RTW89_KCC][0] = 64, [0][1][2][0][RTW89_ACMA][0] = 54, [0][1][2][0][RTW89_CN][0] = 40, [0][1][2][0][RTW89_UK][0] = 54, + [0][1][2][0][RTW89_MEXICO][0] = 50, + [0][1][2][0][RTW89_UKRAINE][0] = 42, + [0][1][2][0][RTW89_CHILE][0] = 60, + [0][1][2][0][RTW89_QATAR][0] = 54, [0][1][2][0][RTW89_FCC][2] = 62, [0][1][2][0][RTW89_ETSI][2] = 54, [0][1][2][0][RTW89_MKK][2] = 54, [0][1][2][0][RTW89_IC][2] = 36, - [0][1][2][0][RTW89_KCC][2] = 40, + [0][1][2][0][RTW89_KCC][2] = 64, [0][1][2][0][RTW89_ACMA][2] = 54, [0][1][2][0][RTW89_CN][2] = 40, [0][1][2][0][RTW89_UK][2] = 54, + [0][1][2][0][RTW89_MEXICO][2] = 50, + [0][1][2][0][RTW89_UKRAINE][2] = 42, + [0][1][2][0][RTW89_CHILE][2] = 62, + [0][1][2][0][RTW89_QATAR][2] = 54, [0][1][2][0][RTW89_FCC][4] = 62, [0][1][2][0][RTW89_ETSI][4] = 54, [0][1][2][0][RTW89_MKK][4] = 54, [0][1][2][0][RTW89_IC][4] = 36, - [0][1][2][0][RTW89_KCC][4] = 40, + [0][1][2][0][RTW89_KCC][4] = 64, [0][1][2][0][RTW89_ACMA][4] = 54, [0][1][2][0][RTW89_CN][4] = 40, [0][1][2][0][RTW89_UK][4] = 54, + [0][1][2][0][RTW89_MEXICO][4] = 50, + [0][1][2][0][RTW89_UKRAINE][4] = 42, + [0][1][2][0][RTW89_CHILE][4] = 62, + [0][1][2][0][RTW89_QATAR][4] = 54, [0][1][2][0][RTW89_FCC][6] = 62, [0][1][2][0][RTW89_ETSI][6] = 54, [0][1][2][0][RTW89_MKK][6] = 50, [0][1][2][0][RTW89_IC][6] = 38, - [0][1][2][0][RTW89_KCC][6] = 64, + [0][1][2][0][RTW89_KCC][6] = 40, [0][1][2][0][RTW89_ACMA][6] = 54, [0][1][2][0][RTW89_CN][6] = 40, [0][1][2][0][RTW89_UK][6] = 54, + [0][1][2][0][RTW89_MEXICO][6] = 50, + [0][1][2][0][RTW89_UKRAINE][6] = 42, + [0][1][2][0][RTW89_CHILE][6] = 62, + [0][1][2][0][RTW89_QATAR][6] = 54, [0][1][2][0][RTW89_FCC][8] = 62, [0][1][2][0][RTW89_ETSI][8] = 54, [0][1][2][0][RTW89_MKK][8] = 42, @@ -31036,6 +32078,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][8] = 54, [0][1][2][0][RTW89_CN][8] = 40, [0][1][2][0][RTW89_UK][8] = 54, + [0][1][2][0][RTW89_MEXICO][8] = 62, + [0][1][2][0][RTW89_UKRAINE][8] = 42, + [0][1][2][0][RTW89_CHILE][8] = 62, + [0][1][2][0][RTW89_QATAR][8] = 54, [0][1][2][0][RTW89_FCC][10] = 62, [0][1][2][0][RTW89_ETSI][10] = 54, [0][1][2][0][RTW89_MKK][10] = 54, @@ -31044,6 +32090,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][10] = 54, [0][1][2][0][RTW89_CN][10] = 40, [0][1][2][0][RTW89_UK][10] = 54, + [0][1][2][0][RTW89_MEXICO][10] = 62, + [0][1][2][0][RTW89_UKRAINE][10] = 42, + [0][1][2][0][RTW89_CHILE][10] = 62, + [0][1][2][0][RTW89_QATAR][10] = 54, [0][1][2][0][RTW89_FCC][12] = 62, [0][1][2][0][RTW89_ETSI][12] = 54, [0][1][2][0][RTW89_MKK][12] = 54, @@ -31052,6 +32102,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][12] = 54, [0][1][2][0][RTW89_CN][12] = 40, [0][1][2][0][RTW89_UK][12] = 54, + [0][1][2][0][RTW89_MEXICO][12] = 62, + [0][1][2][0][RTW89_UKRAINE][12] = 42, + [0][1][2][0][RTW89_CHILE][12] = 62, + [0][1][2][0][RTW89_QATAR][12] = 54, [0][1][2][0][RTW89_FCC][14] = 62, [0][1][2][0][RTW89_ETSI][14] = 54, [0][1][2][0][RTW89_MKK][14] = 54, @@ -31060,6 +32114,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][14] = 54, [0][1][2][0][RTW89_CN][14] = 40, [0][1][2][0][RTW89_UK][14] = 54, + [0][1][2][0][RTW89_MEXICO][14] = 62, + [0][1][2][0][RTW89_UKRAINE][14] = 42, + [0][1][2][0][RTW89_CHILE][14] = 62, + [0][1][2][0][RTW89_QATAR][14] = 54, [0][1][2][0][RTW89_FCC][15] = 60, [0][1][2][0][RTW89_ETSI][15] = 54, [0][1][2][0][RTW89_MKK][15] = 68, @@ -31068,6 +32126,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][15] = 54, [0][1][2][0][RTW89_CN][15] = 127, [0][1][2][0][RTW89_UK][15] = 54, + [0][1][2][0][RTW89_MEXICO][15] = 60, + [0][1][2][0][RTW89_UKRAINE][15] = 42, + [0][1][2][0][RTW89_CHILE][15] = 60, + [0][1][2][0][RTW89_QATAR][15] = 54, [0][1][2][0][RTW89_FCC][17] = 62, [0][1][2][0][RTW89_ETSI][17] = 54, [0][1][2][0][RTW89_MKK][17] = 68, @@ -31076,6 +32138,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][17] = 54, [0][1][2][0][RTW89_CN][17] = 127, [0][1][2][0][RTW89_UK][17] = 54, + [0][1][2][0][RTW89_MEXICO][17] = 62, + [0][1][2][0][RTW89_UKRAINE][17] = 42, + [0][1][2][0][RTW89_CHILE][17] = 60, + [0][1][2][0][RTW89_QATAR][17] = 54, [0][1][2][0][RTW89_FCC][19] = 62, [0][1][2][0][RTW89_ETSI][19] = 54, [0][1][2][0][RTW89_MKK][19] = 68, @@ -31084,6 +32150,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][19] = 54, [0][1][2][0][RTW89_CN][19] = 127, [0][1][2][0][RTW89_UK][19] = 54, + [0][1][2][0][RTW89_MEXICO][19] = 62, + [0][1][2][0][RTW89_UKRAINE][19] = 42, + [0][1][2][0][RTW89_CHILE][19] = 62, + [0][1][2][0][RTW89_QATAR][19] = 54, [0][1][2][0][RTW89_FCC][21] = 62, [0][1][2][0][RTW89_ETSI][21] = 54, [0][1][2][0][RTW89_MKK][21] = 68, @@ -31092,6 +32162,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][21] = 54, [0][1][2][0][RTW89_CN][21] = 127, [0][1][2][0][RTW89_UK][21] = 54, + [0][1][2][0][RTW89_MEXICO][21] = 62, + [0][1][2][0][RTW89_UKRAINE][21] = 42, + [0][1][2][0][RTW89_CHILE][21] = 62, + [0][1][2][0][RTW89_QATAR][21] = 54, [0][1][2][0][RTW89_FCC][23] = 62, [0][1][2][0][RTW89_ETSI][23] = 54, [0][1][2][0][RTW89_MKK][23] = 68, @@ -31100,6 +32174,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][23] = 54, [0][1][2][0][RTW89_CN][23] = 127, [0][1][2][0][RTW89_UK][23] = 54, + [0][1][2][0][RTW89_MEXICO][23] = 62, + [0][1][2][0][RTW89_UKRAINE][23] = 42, + [0][1][2][0][RTW89_CHILE][23] = 62, + [0][1][2][0][RTW89_QATAR][23] = 54, [0][1][2][0][RTW89_FCC][25] = 62, [0][1][2][0][RTW89_ETSI][25] = 54, [0][1][2][0][RTW89_MKK][25] = 68, @@ -31108,6 +32186,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][25] = 127, [0][1][2][0][RTW89_CN][25] = 127, [0][1][2][0][RTW89_UK][25] = 54, + [0][1][2][0][RTW89_MEXICO][25] = 62, + [0][1][2][0][RTW89_UKRAINE][25] = 42, + [0][1][2][0][RTW89_CHILE][25] = 62, + [0][1][2][0][RTW89_QATAR][25] = 54, [0][1][2][0][RTW89_FCC][27] = 62, [0][1][2][0][RTW89_ETSI][27] = 54, [0][1][2][0][RTW89_MKK][27] = 68, @@ -31116,6 +32198,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][27] = 127, [0][1][2][0][RTW89_CN][27] = 127, [0][1][2][0][RTW89_UK][27] = 54, + [0][1][2][0][RTW89_MEXICO][27] = 62, + [0][1][2][0][RTW89_UKRAINE][27] = 42, + [0][1][2][0][RTW89_CHILE][27] = 46, + [0][1][2][0][RTW89_QATAR][27] = 54, [0][1][2][0][RTW89_FCC][29] = 62, [0][1][2][0][RTW89_ETSI][29] = 54, [0][1][2][0][RTW89_MKK][29] = 68, @@ -31124,6 +32210,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][29] = 127, [0][1][2][0][RTW89_CN][29] = 127, [0][1][2][0][RTW89_UK][29] = 54, + [0][1][2][0][RTW89_MEXICO][29] = 62, + [0][1][2][0][RTW89_UKRAINE][29] = 42, + [0][1][2][0][RTW89_CHILE][29] = 46, + [0][1][2][0][RTW89_QATAR][29] = 54, [0][1][2][0][RTW89_FCC][31] = 62, [0][1][2][0][RTW89_ETSI][31] = 54, [0][1][2][0][RTW89_MKK][31] = 68, @@ -31132,6 +32222,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][31] = 54, [0][1][2][0][RTW89_CN][31] = 127, [0][1][2][0][RTW89_UK][31] = 54, + [0][1][2][0][RTW89_MEXICO][31] = 62, + [0][1][2][0][RTW89_UKRAINE][31] = 42, + [0][1][2][0][RTW89_CHILE][31] = 46, + [0][1][2][0][RTW89_QATAR][31] = 54, [0][1][2][0][RTW89_FCC][33] = 62, [0][1][2][0][RTW89_ETSI][33] = 54, [0][1][2][0][RTW89_MKK][33] = 68, @@ -31140,6 +32234,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][33] = 54, [0][1][2][0][RTW89_CN][33] = 127, [0][1][2][0][RTW89_UK][33] = 54, + [0][1][2][0][RTW89_MEXICO][33] = 62, + [0][1][2][0][RTW89_UKRAINE][33] = 42, + [0][1][2][0][RTW89_CHILE][33] = 46, + [0][1][2][0][RTW89_QATAR][33] = 54, [0][1][2][0][RTW89_FCC][35] = 46, [0][1][2][0][RTW89_ETSI][35] = 54, [0][1][2][0][RTW89_MKK][35] = 68, @@ -31148,6 +32246,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][35] = 54, [0][1][2][0][RTW89_CN][35] = 127, [0][1][2][0][RTW89_UK][35] = 54, + [0][1][2][0][RTW89_MEXICO][35] = 46, + [0][1][2][0][RTW89_UKRAINE][35] = 42, + [0][1][2][0][RTW89_CHILE][35] = 46, + [0][1][2][0][RTW89_QATAR][35] = 54, [0][1][2][0][RTW89_FCC][37] = 64, [0][1][2][0][RTW89_ETSI][37] = 127, [0][1][2][0][RTW89_MKK][37] = 68, @@ -31156,6 +32258,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][37] = 64, [0][1][2][0][RTW89_CN][37] = 127, [0][1][2][0][RTW89_UK][37] = 52, + [0][1][2][0][RTW89_MEXICO][37] = 64, + [0][1][2][0][RTW89_UKRAINE][37] = 127, + [0][1][2][0][RTW89_CHILE][37] = 64, + [0][1][2][0][RTW89_QATAR][37] = 127, [0][1][2][0][RTW89_FCC][38] = 72, [0][1][2][0][RTW89_ETSI][38] = 18, [0][1][2][0][RTW89_MKK][38] = 127, @@ -31164,6 +32270,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][38] = 70, [0][1][2][0][RTW89_CN][38] = 68, [0][1][2][0][RTW89_UK][38] = 52, + [0][1][2][0][RTW89_MEXICO][38] = 72, + [0][1][2][0][RTW89_UKRAINE][38] = 18, + [0][1][2][0][RTW89_CHILE][38] = 70, + [0][1][2][0][RTW89_QATAR][38] = 18, [0][1][2][0][RTW89_FCC][40] = 72, [0][1][2][0][RTW89_ETSI][40] = 18, [0][1][2][0][RTW89_MKK][40] = 127, @@ -31172,6 +32282,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][40] = 70, [0][1][2][0][RTW89_CN][40] = 68, [0][1][2][0][RTW89_UK][40] = 52, + [0][1][2][0][RTW89_MEXICO][40] = 72, + [0][1][2][0][RTW89_UKRAINE][40] = 18, + [0][1][2][0][RTW89_CHILE][40] = 70, + [0][1][2][0][RTW89_QATAR][40] = 18, [0][1][2][0][RTW89_FCC][42] = 72, [0][1][2][0][RTW89_ETSI][42] = 18, [0][1][2][0][RTW89_MKK][42] = 127, @@ -31180,6 +32294,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][42] = 70, [0][1][2][0][RTW89_CN][42] = 68, [0][1][2][0][RTW89_UK][42] = 52, + [0][1][2][0][RTW89_MEXICO][42] = 72, + [0][1][2][0][RTW89_UKRAINE][42] = 18, + [0][1][2][0][RTW89_CHILE][42] = 70, + [0][1][2][0][RTW89_QATAR][42] = 18, [0][1][2][0][RTW89_FCC][44] = 72, [0][1][2][0][RTW89_ETSI][44] = 18, [0][1][2][0][RTW89_MKK][44] = 127, @@ -31188,6 +32306,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][44] = 70, [0][1][2][0][RTW89_CN][44] = 68, [0][1][2][0][RTW89_UK][44] = 52, + [0][1][2][0][RTW89_MEXICO][44] = 72, + [0][1][2][0][RTW89_UKRAINE][44] = 18, + [0][1][2][0][RTW89_CHILE][44] = 70, + [0][1][2][0][RTW89_QATAR][44] = 18, [0][1][2][0][RTW89_FCC][46] = 72, [0][1][2][0][RTW89_ETSI][46] = 18, [0][1][2][0][RTW89_MKK][46] = 127, @@ -31196,6 +32318,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][46] = 70, [0][1][2][0][RTW89_CN][46] = 68, [0][1][2][0][RTW89_UK][46] = 52, + [0][1][2][0][RTW89_MEXICO][46] = 72, + [0][1][2][0][RTW89_UKRAINE][46] = 18, + [0][1][2][0][RTW89_CHILE][46] = 70, + [0][1][2][0][RTW89_QATAR][46] = 18, [0][1][2][0][RTW89_FCC][48] = 48, [0][1][2][0][RTW89_ETSI][48] = 127, [0][1][2][0][RTW89_MKK][48] = 127, @@ -31204,6 +32330,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][48] = 127, [0][1][2][0][RTW89_CN][48] = 127, [0][1][2][0][RTW89_UK][48] = 127, + [0][1][2][0][RTW89_MEXICO][48] = 127, + [0][1][2][0][RTW89_UKRAINE][48] = 127, + [0][1][2][0][RTW89_CHILE][48] = 127, + [0][1][2][0][RTW89_QATAR][48] = 127, [0][1][2][0][RTW89_FCC][50] = 50, [0][1][2][0][RTW89_ETSI][50] = 127, [0][1][2][0][RTW89_MKK][50] = 127, @@ -31212,6 +32342,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][50] = 127, [0][1][2][0][RTW89_CN][50] = 127, [0][1][2][0][RTW89_UK][50] = 127, + [0][1][2][0][RTW89_MEXICO][50] = 127, + [0][1][2][0][RTW89_UKRAINE][50] = 127, + [0][1][2][0][RTW89_CHILE][50] = 127, + [0][1][2][0][RTW89_QATAR][50] = 127, [0][1][2][0][RTW89_FCC][52] = 48, [0][1][2][0][RTW89_ETSI][52] = 127, [0][1][2][0][RTW89_MKK][52] = 127, @@ -31220,38 +32354,58 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_ACMA][52] = 127, [0][1][2][0][RTW89_CN][52] = 127, [0][1][2][0][RTW89_UK][52] = 127, + [0][1][2][0][RTW89_MEXICO][52] = 127, + [0][1][2][0][RTW89_UKRAINE][52] = 127, + [0][1][2][0][RTW89_CHILE][52] = 127, + [0][1][2][0][RTW89_QATAR][52] = 127, [0][1][2][1][RTW89_FCC][0] = 60, [0][1][2][1][RTW89_ETSI][0] = 40, [0][1][2][1][RTW89_MKK][0] = 54, [0][1][2][1][RTW89_IC][0] = 40, - [0][1][2][1][RTW89_KCC][0] = 40, + [0][1][2][1][RTW89_KCC][0] = 64, [0][1][2][1][RTW89_ACMA][0] = 40, [0][1][2][1][RTW89_CN][0] = 36, [0][1][2][1][RTW89_UK][0] = 40, + [0][1][2][1][RTW89_MEXICO][0] = 50, + [0][1][2][1][RTW89_UKRAINE][0] = 30, + [0][1][2][1][RTW89_CHILE][0] = 60, + [0][1][2][1][RTW89_QATAR][0] = 40, [0][1][2][1][RTW89_FCC][2] = 62, [0][1][2][1][RTW89_ETSI][2] = 40, [0][1][2][1][RTW89_MKK][2] = 54, [0][1][2][1][RTW89_IC][2] = 40, - [0][1][2][1][RTW89_KCC][2] = 40, + [0][1][2][1][RTW89_KCC][2] = 64, [0][1][2][1][RTW89_ACMA][2] = 40, [0][1][2][1][RTW89_CN][2] = 36, [0][1][2][1][RTW89_UK][2] = 40, + [0][1][2][1][RTW89_MEXICO][2] = 50, + [0][1][2][1][RTW89_UKRAINE][2] = 30, + [0][1][2][1][RTW89_CHILE][2] = 60, + [0][1][2][1][RTW89_QATAR][2] = 40, [0][1][2][1][RTW89_FCC][4] = 62, [0][1][2][1][RTW89_ETSI][4] = 40, [0][1][2][1][RTW89_MKK][4] = 54, [0][1][2][1][RTW89_IC][4] = 40, - [0][1][2][1][RTW89_KCC][4] = 40, + [0][1][2][1][RTW89_KCC][4] = 64, [0][1][2][1][RTW89_ACMA][4] = 40, [0][1][2][1][RTW89_CN][4] = 36, [0][1][2][1][RTW89_UK][4] = 40, + [0][1][2][1][RTW89_MEXICO][4] = 50, + [0][1][2][1][RTW89_UKRAINE][4] = 30, + [0][1][2][1][RTW89_CHILE][4] = 60, + [0][1][2][1][RTW89_QATAR][4] = 40, [0][1][2][1][RTW89_FCC][6] = 62, [0][1][2][1][RTW89_ETSI][6] = 40, [0][1][2][1][RTW89_MKK][6] = 50, [0][1][2][1][RTW89_IC][6] = 40, - [0][1][2][1][RTW89_KCC][6] = 64, + [0][1][2][1][RTW89_KCC][6] = 40, [0][1][2][1][RTW89_ACMA][6] = 40, [0][1][2][1][RTW89_CN][6] = 36, [0][1][2][1][RTW89_UK][6] = 40, + [0][1][2][1][RTW89_MEXICO][6] = 50, + [0][1][2][1][RTW89_UKRAINE][6] = 30, + [0][1][2][1][RTW89_CHILE][6] = 60, + [0][1][2][1][RTW89_QATAR][6] = 40, [0][1][2][1][RTW89_FCC][8] = 62, [0][1][2][1][RTW89_ETSI][8] = 40, [0][1][2][1][RTW89_MKK][8] = 42, @@ -31260,6 +32414,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][8] = 40, [0][1][2][1][RTW89_CN][8] = 36, [0][1][2][1][RTW89_UK][8] = 40, + [0][1][2][1][RTW89_MEXICO][8] = 62, + [0][1][2][1][RTW89_UKRAINE][8] = 30, + [0][1][2][1][RTW89_CHILE][8] = 60, + [0][1][2][1][RTW89_QATAR][8] = 40, [0][1][2][1][RTW89_FCC][10] = 62, [0][1][2][1][RTW89_ETSI][10] = 40, [0][1][2][1][RTW89_MKK][10] = 54, @@ -31268,6 +32426,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][10] = 40, [0][1][2][1][RTW89_CN][10] = 36, [0][1][2][1][RTW89_UK][10] = 40, + [0][1][2][1][RTW89_MEXICO][10] = 62, + [0][1][2][1][RTW89_UKRAINE][10] = 30, + [0][1][2][1][RTW89_CHILE][10] = 60, + [0][1][2][1][RTW89_QATAR][10] = 40, [0][1][2][1][RTW89_FCC][12] = 62, [0][1][2][1][RTW89_ETSI][12] = 40, [0][1][2][1][RTW89_MKK][12] = 54, @@ -31276,6 +32438,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][12] = 40, [0][1][2][1][RTW89_CN][12] = 36, [0][1][2][1][RTW89_UK][12] = 40, + [0][1][2][1][RTW89_MEXICO][12] = 62, + [0][1][2][1][RTW89_UKRAINE][12] = 30, + [0][1][2][1][RTW89_CHILE][12] = 60, + [0][1][2][1][RTW89_QATAR][12] = 40, [0][1][2][1][RTW89_FCC][14] = 62, [0][1][2][1][RTW89_ETSI][14] = 40, [0][1][2][1][RTW89_MKK][14] = 54, @@ -31284,6 +32450,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][14] = 40, [0][1][2][1][RTW89_CN][14] = 36, [0][1][2][1][RTW89_UK][14] = 40, + [0][1][2][1][RTW89_MEXICO][14] = 62, + [0][1][2][1][RTW89_UKRAINE][14] = 30, + [0][1][2][1][RTW89_CHILE][14] = 60, + [0][1][2][1][RTW89_QATAR][14] = 40, [0][1][2][1][RTW89_FCC][15] = 60, [0][1][2][1][RTW89_ETSI][15] = 40, [0][1][2][1][RTW89_MKK][15] = 68, @@ -31292,6 +32462,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][15] = 40, [0][1][2][1][RTW89_CN][15] = 127, [0][1][2][1][RTW89_UK][15] = 40, + [0][1][2][1][RTW89_MEXICO][15] = 60, + [0][1][2][1][RTW89_UKRAINE][15] = 30, + [0][1][2][1][RTW89_CHILE][15] = 60, + [0][1][2][1][RTW89_QATAR][15] = 40, [0][1][2][1][RTW89_FCC][17] = 62, [0][1][2][1][RTW89_ETSI][17] = 40, [0][1][2][1][RTW89_MKK][17] = 68, @@ -31300,6 +32474,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][17] = 40, [0][1][2][1][RTW89_CN][17] = 127, [0][1][2][1][RTW89_UK][17] = 40, + [0][1][2][1][RTW89_MEXICO][17] = 62, + [0][1][2][1][RTW89_UKRAINE][17] = 30, + [0][1][2][1][RTW89_CHILE][17] = 60, + [0][1][2][1][RTW89_QATAR][17] = 40, [0][1][2][1][RTW89_FCC][19] = 62, [0][1][2][1][RTW89_ETSI][19] = 40, [0][1][2][1][RTW89_MKK][19] = 68, @@ -31308,6 +32486,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][19] = 40, [0][1][2][1][RTW89_CN][19] = 127, [0][1][2][1][RTW89_UK][19] = 40, + [0][1][2][1][RTW89_MEXICO][19] = 62, + [0][1][2][1][RTW89_UKRAINE][19] = 30, + [0][1][2][1][RTW89_CHILE][19] = 60, + [0][1][2][1][RTW89_QATAR][19] = 40, [0][1][2][1][RTW89_FCC][21] = 62, [0][1][2][1][RTW89_ETSI][21] = 40, [0][1][2][1][RTW89_MKK][21] = 68, @@ -31316,6 +32498,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][21] = 40, [0][1][2][1][RTW89_CN][21] = 127, [0][1][2][1][RTW89_UK][21] = 40, + [0][1][2][1][RTW89_MEXICO][21] = 62, + [0][1][2][1][RTW89_UKRAINE][21] = 30, + [0][1][2][1][RTW89_CHILE][21] = 60, + [0][1][2][1][RTW89_QATAR][21] = 40, [0][1][2][1][RTW89_FCC][23] = 62, [0][1][2][1][RTW89_ETSI][23] = 40, [0][1][2][1][RTW89_MKK][23] = 68, @@ -31324,6 +32510,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][23] = 40, [0][1][2][1][RTW89_CN][23] = 127, [0][1][2][1][RTW89_UK][23] = 40, + [0][1][2][1][RTW89_MEXICO][23] = 62, + [0][1][2][1][RTW89_UKRAINE][23] = 30, + [0][1][2][1][RTW89_CHILE][23] = 60, + [0][1][2][1][RTW89_QATAR][23] = 40, [0][1][2][1][RTW89_FCC][25] = 46, [0][1][2][1][RTW89_ETSI][25] = 40, [0][1][2][1][RTW89_MKK][25] = 68, @@ -31332,6 +32522,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][25] = 127, [0][1][2][1][RTW89_CN][25] = 127, [0][1][2][1][RTW89_UK][25] = 40, + [0][1][2][1][RTW89_MEXICO][25] = 46, + [0][1][2][1][RTW89_UKRAINE][25] = 30, + [0][1][2][1][RTW89_CHILE][25] = 60, + [0][1][2][1][RTW89_QATAR][25] = 40, [0][1][2][1][RTW89_FCC][27] = 46, [0][1][2][1][RTW89_ETSI][27] = 40, [0][1][2][1][RTW89_MKK][27] = 68, @@ -31340,6 +32534,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][27] = 127, [0][1][2][1][RTW89_CN][27] = 127, [0][1][2][1][RTW89_UK][27] = 40, + [0][1][2][1][RTW89_MEXICO][27] = 46, + [0][1][2][1][RTW89_UKRAINE][27] = 30, + [0][1][2][1][RTW89_CHILE][27] = 46, + [0][1][2][1][RTW89_QATAR][27] = 40, [0][1][2][1][RTW89_FCC][29] = 46, [0][1][2][1][RTW89_ETSI][29] = 40, [0][1][2][1][RTW89_MKK][29] = 68, @@ -31348,6 +32546,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][29] = 127, [0][1][2][1][RTW89_CN][29] = 127, [0][1][2][1][RTW89_UK][29] = 40, + [0][1][2][1][RTW89_MEXICO][29] = 46, + [0][1][2][1][RTW89_UKRAINE][29] = 30, + [0][1][2][1][RTW89_CHILE][29] = 46, + [0][1][2][1][RTW89_QATAR][29] = 40, [0][1][2][1][RTW89_FCC][31] = 46, [0][1][2][1][RTW89_ETSI][31] = 40, [0][1][2][1][RTW89_MKK][31] = 68, @@ -31356,6 +32558,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][31] = 40, [0][1][2][1][RTW89_CN][31] = 127, [0][1][2][1][RTW89_UK][31] = 40, + [0][1][2][1][RTW89_MEXICO][31] = 46, + [0][1][2][1][RTW89_UKRAINE][31] = 30, + [0][1][2][1][RTW89_CHILE][31] = 46, + [0][1][2][1][RTW89_QATAR][31] = 40, [0][1][2][1][RTW89_FCC][33] = 46, [0][1][2][1][RTW89_ETSI][33] = 40, [0][1][2][1][RTW89_MKK][33] = 68, @@ -31364,6 +32570,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][33] = 40, [0][1][2][1][RTW89_CN][33] = 127, [0][1][2][1][RTW89_UK][33] = 40, + [0][1][2][1][RTW89_MEXICO][33] = 46, + [0][1][2][1][RTW89_UKRAINE][33] = 30, + [0][1][2][1][RTW89_CHILE][33] = 46, + [0][1][2][1][RTW89_QATAR][33] = 40, [0][1][2][1][RTW89_FCC][35] = 46, [0][1][2][1][RTW89_ETSI][35] = 40, [0][1][2][1][RTW89_MKK][35] = 68, @@ -31372,6 +32582,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][35] = 40, [0][1][2][1][RTW89_CN][35] = 127, [0][1][2][1][RTW89_UK][35] = 40, + [0][1][2][1][RTW89_MEXICO][35] = 46, + [0][1][2][1][RTW89_UKRAINE][35] = 30, + [0][1][2][1][RTW89_CHILE][35] = 46, + [0][1][2][1][RTW89_QATAR][35] = 40, [0][1][2][1][RTW89_FCC][37] = 64, [0][1][2][1][RTW89_ETSI][37] = 127, [0][1][2][1][RTW89_MKK][37] = 68, @@ -31380,6 +32594,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][37] = 64, [0][1][2][1][RTW89_CN][37] = 127, [0][1][2][1][RTW89_UK][37] = 40, + [0][1][2][1][RTW89_MEXICO][37] = 64, + [0][1][2][1][RTW89_UKRAINE][37] = 127, + [0][1][2][1][RTW89_CHILE][37] = 64, + [0][1][2][1][RTW89_QATAR][37] = 127, [0][1][2][1][RTW89_FCC][38] = 72, [0][1][2][1][RTW89_ETSI][38] = 6, [0][1][2][1][RTW89_MKK][38] = 127, @@ -31388,6 +32606,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][38] = 70, [0][1][2][1][RTW89_CN][38] = 60, [0][1][2][1][RTW89_UK][38] = 40, + [0][1][2][1][RTW89_MEXICO][38] = 72, + [0][1][2][1][RTW89_UKRAINE][38] = 6, + [0][1][2][1][RTW89_CHILE][38] = 60, + [0][1][2][1][RTW89_QATAR][38] = 6, [0][1][2][1][RTW89_FCC][40] = 72, [0][1][2][1][RTW89_ETSI][40] = 6, [0][1][2][1][RTW89_MKK][40] = 127, @@ -31396,6 +32618,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][40] = 70, [0][1][2][1][RTW89_CN][40] = 60, [0][1][2][1][RTW89_UK][40] = 40, + [0][1][2][1][RTW89_MEXICO][40] = 72, + [0][1][2][1][RTW89_UKRAINE][40] = 6, + [0][1][2][1][RTW89_CHILE][40] = 60, + [0][1][2][1][RTW89_QATAR][40] = 6, [0][1][2][1][RTW89_FCC][42] = 72, [0][1][2][1][RTW89_ETSI][42] = 6, [0][1][2][1][RTW89_MKK][42] = 127, @@ -31404,6 +32630,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][42] = 70, [0][1][2][1][RTW89_CN][42] = 60, [0][1][2][1][RTW89_UK][42] = 40, + [0][1][2][1][RTW89_MEXICO][42] = 72, + [0][1][2][1][RTW89_UKRAINE][42] = 6, + [0][1][2][1][RTW89_CHILE][42] = 60, + [0][1][2][1][RTW89_QATAR][42] = 6, [0][1][2][1][RTW89_FCC][44] = 72, [0][1][2][1][RTW89_ETSI][44] = 6, [0][1][2][1][RTW89_MKK][44] = 127, @@ -31412,6 +32642,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][44] = 70, [0][1][2][1][RTW89_CN][44] = 54, [0][1][2][1][RTW89_UK][44] = 40, + [0][1][2][1][RTW89_MEXICO][44] = 72, + [0][1][2][1][RTW89_UKRAINE][44] = 6, + [0][1][2][1][RTW89_CHILE][44] = 60, + [0][1][2][1][RTW89_QATAR][44] = 6, [0][1][2][1][RTW89_FCC][46] = 72, [0][1][2][1][RTW89_ETSI][46] = 6, [0][1][2][1][RTW89_MKK][46] = 127, @@ -31420,6 +32654,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][46] = 70, [0][1][2][1][RTW89_CN][46] = 54, [0][1][2][1][RTW89_UK][46] = 40, + [0][1][2][1][RTW89_MEXICO][46] = 72, + [0][1][2][1][RTW89_UKRAINE][46] = 6, + [0][1][2][1][RTW89_CHILE][46] = 60, + [0][1][2][1][RTW89_QATAR][46] = 6, [0][1][2][1][RTW89_FCC][48] = 48, [0][1][2][1][RTW89_ETSI][48] = 127, [0][1][2][1][RTW89_MKK][48] = 127, @@ -31428,6 +32666,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][48] = 127, [0][1][2][1][RTW89_CN][48] = 127, [0][1][2][1][RTW89_UK][48] = 127, + [0][1][2][1][RTW89_MEXICO][48] = 127, + [0][1][2][1][RTW89_UKRAINE][48] = 127, + [0][1][2][1][RTW89_CHILE][48] = 127, + [0][1][2][1][RTW89_QATAR][48] = 127, [0][1][2][1][RTW89_FCC][50] = 50, [0][1][2][1][RTW89_ETSI][50] = 127, [0][1][2][1][RTW89_MKK][50] = 127, @@ -31436,6 +32678,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][50] = 127, [0][1][2][1][RTW89_CN][50] = 127, [0][1][2][1][RTW89_UK][50] = 127, + [0][1][2][1][RTW89_MEXICO][50] = 127, + [0][1][2][1][RTW89_UKRAINE][50] = 127, + [0][1][2][1][RTW89_CHILE][50] = 127, + [0][1][2][1][RTW89_QATAR][50] = 127, [0][1][2][1][RTW89_FCC][52] = 48, [0][1][2][1][RTW89_ETSI][52] = 127, [0][1][2][1][RTW89_MKK][52] = 127, @@ -31444,22 +32690,34 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][52] = 127, [0][1][2][1][RTW89_CN][52] = 127, [0][1][2][1][RTW89_UK][52] = 127, + [0][1][2][1][RTW89_MEXICO][52] = 127, + [0][1][2][1][RTW89_UKRAINE][52] = 127, + [0][1][2][1][RTW89_CHILE][52] = 127, + [0][1][2][1][RTW89_QATAR][52] = 127, [1][0][2][0][RTW89_FCC][1] = 64, [1][0][2][0][RTW89_ETSI][1] = 66, [1][0][2][0][RTW89_MKK][1] = 66, [1][0][2][0][RTW89_IC][1] = 62, - [1][0][2][0][RTW89_KCC][1] = 66, + [1][0][2][0][RTW89_KCC][1] = 54, [1][0][2][0][RTW89_ACMA][1] = 66, [1][0][2][0][RTW89_CN][1] = 54, [1][0][2][0][RTW89_UK][1] = 66, + [1][0][2][0][RTW89_MEXICO][1] = 62, + [1][0][2][0][RTW89_UKRAINE][1] = 54, + [1][0][2][0][RTW89_CHILE][1] = 62, + [1][0][2][0][RTW89_QATAR][1] = 66, [1][0][2][0][RTW89_FCC][5] = 68, [1][0][2][0][RTW89_ETSI][5] = 66, [1][0][2][0][RTW89_MKK][5] = 66, [1][0][2][0][RTW89_IC][5] = 64, - [1][0][2][0][RTW89_KCC][5] = 54, + [1][0][2][0][RTW89_KCC][5] = 66, [1][0][2][0][RTW89_ACMA][5] = 66, [1][0][2][0][RTW89_CN][5] = 54, [1][0][2][0][RTW89_UK][5] = 66, + [1][0][2][0][RTW89_MEXICO][5] = 62, + [1][0][2][0][RTW89_UKRAINE][5] = 54, + [1][0][2][0][RTW89_CHILE][5] = 66, + [1][0][2][0][RTW89_QATAR][5] = 66, [1][0][2][0][RTW89_FCC][9] = 68, [1][0][2][0][RTW89_ETSI][9] = 66, [1][0][2][0][RTW89_MKK][9] = 66, @@ -31468,6 +32726,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][9] = 66, [1][0][2][0][RTW89_CN][9] = 54, [1][0][2][0][RTW89_UK][9] = 66, + [1][0][2][0][RTW89_MEXICO][9] = 68, + [1][0][2][0][RTW89_UKRAINE][9] = 54, + [1][0][2][0][RTW89_CHILE][9] = 66, + [1][0][2][0][RTW89_QATAR][9] = 66, [1][0][2][0][RTW89_FCC][13] = 60, [1][0][2][0][RTW89_ETSI][13] = 66, [1][0][2][0][RTW89_MKK][13] = 66, @@ -31476,6 +32738,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][13] = 66, [1][0][2][0][RTW89_CN][13] = 54, [1][0][2][0][RTW89_UK][13] = 66, + [1][0][2][0][RTW89_MEXICO][13] = 60, + [1][0][2][0][RTW89_UKRAINE][13] = 54, + [1][0][2][0][RTW89_CHILE][13] = 60, + [1][0][2][0][RTW89_QATAR][13] = 66, [1][0][2][0][RTW89_FCC][16] = 64, [1][0][2][0][RTW89_ETSI][16] = 66, [1][0][2][0][RTW89_MKK][16] = 66, @@ -31484,6 +32750,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][16] = 66, [1][0][2][0][RTW89_CN][16] = 127, [1][0][2][0][RTW89_UK][16] = 66, + [1][0][2][0][RTW89_MEXICO][16] = 64, + [1][0][2][0][RTW89_UKRAINE][16] = 54, + [1][0][2][0][RTW89_CHILE][16] = 64, + [1][0][2][0][RTW89_QATAR][16] = 66, [1][0][2][0][RTW89_FCC][20] = 68, [1][0][2][0][RTW89_ETSI][20] = 66, [1][0][2][0][RTW89_MKK][20] = 66, @@ -31492,6 +32762,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][20] = 66, [1][0][2][0][RTW89_CN][20] = 127, [1][0][2][0][RTW89_UK][20] = 66, + [1][0][2][0][RTW89_MEXICO][20] = 68, + [1][0][2][0][RTW89_UKRAINE][20] = 54, + [1][0][2][0][RTW89_CHILE][20] = 66, + [1][0][2][0][RTW89_QATAR][20] = 66, [1][0][2][0][RTW89_FCC][24] = 68, [1][0][2][0][RTW89_ETSI][24] = 66, [1][0][2][0][RTW89_MKK][24] = 66, @@ -31500,6 +32774,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][24] = 127, [1][0][2][0][RTW89_CN][24] = 127, [1][0][2][0][RTW89_UK][24] = 66, + [1][0][2][0][RTW89_MEXICO][24] = 68, + [1][0][2][0][RTW89_UKRAINE][24] = 54, + [1][0][2][0][RTW89_CHILE][24] = 66, + [1][0][2][0][RTW89_QATAR][24] = 66, [1][0][2][0][RTW89_FCC][28] = 68, [1][0][2][0][RTW89_ETSI][28] = 66, [1][0][2][0][RTW89_MKK][28] = 66, @@ -31508,6 +32786,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][28] = 127, [1][0][2][0][RTW89_CN][28] = 127, [1][0][2][0][RTW89_UK][28] = 66, + [1][0][2][0][RTW89_MEXICO][28] = 68, + [1][0][2][0][RTW89_UKRAINE][28] = 54, + [1][0][2][0][RTW89_CHILE][28] = 62, + [1][0][2][0][RTW89_QATAR][28] = 66, [1][0][2][0][RTW89_FCC][32] = 62, [1][0][2][0][RTW89_ETSI][32] = 66, [1][0][2][0][RTW89_MKK][32] = 66, @@ -31516,6 +32798,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][32] = 66, [1][0][2][0][RTW89_CN][32] = 127, [1][0][2][0][RTW89_UK][32] = 66, + [1][0][2][0][RTW89_MEXICO][32] = 62, + [1][0][2][0][RTW89_UKRAINE][32] = 54, + [1][0][2][0][RTW89_CHILE][32] = 62, + [1][0][2][0][RTW89_QATAR][32] = 66, [1][0][2][0][RTW89_FCC][36] = 68, [1][0][2][0][RTW89_ETSI][36] = 127, [1][0][2][0][RTW89_MKK][36] = 66, @@ -31524,6 +32810,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][36] = 66, [1][0][2][0][RTW89_CN][36] = 127, [1][0][2][0][RTW89_UK][36] = 64, + [1][0][2][0][RTW89_MEXICO][36] = 68, + [1][0][2][0][RTW89_UKRAINE][36] = 127, + [1][0][2][0][RTW89_CHILE][36] = 66, + [1][0][2][0][RTW89_QATAR][36] = 127, [1][0][2][0][RTW89_FCC][39] = 68, [1][0][2][0][RTW89_ETSI][39] = 30, [1][0][2][0][RTW89_MKK][39] = 127, @@ -31532,6 +32822,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][39] = 66, [1][0][2][0][RTW89_CN][39] = 62, [1][0][2][0][RTW89_UK][39] = 64, + [1][0][2][0][RTW89_MEXICO][39] = 68, + [1][0][2][0][RTW89_UKRAINE][39] = 30, + [1][0][2][0][RTW89_CHILE][39] = 66, + [1][0][2][0][RTW89_QATAR][39] = 30, [1][0][2][0][RTW89_FCC][43] = 68, [1][0][2][0][RTW89_ETSI][43] = 30, [1][0][2][0][RTW89_MKK][43] = 127, @@ -31540,6 +32834,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][43] = 66, [1][0][2][0][RTW89_CN][43] = 66, [1][0][2][0][RTW89_UK][43] = 64, + [1][0][2][0][RTW89_MEXICO][43] = 68, + [1][0][2][0][RTW89_UKRAINE][43] = 30, + [1][0][2][0][RTW89_CHILE][43] = 66, + [1][0][2][0][RTW89_QATAR][43] = 30, [1][0][2][0][RTW89_FCC][47] = 68, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, @@ -31548,6 +32846,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CN][47] = 127, [1][0][2][0][RTW89_UK][47] = 127, + [1][0][2][0][RTW89_MEXICO][47] = 127, + [1][0][2][0][RTW89_UKRAINE][47] = 127, + [1][0][2][0][RTW89_CHILE][47] = 127, + [1][0][2][0][RTW89_QATAR][47] = 127, [1][0][2][0][RTW89_FCC][51] = 68, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, @@ -31556,6 +32858,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][51] = 127, [1][0][2][0][RTW89_CN][51] = 127, [1][0][2][0][RTW89_UK][51] = 127, + [1][0][2][0][RTW89_MEXICO][51] = 127, + [1][0][2][0][RTW89_UKRAINE][51] = 127, + [1][0][2][0][RTW89_CHILE][51] = 127, + [1][0][2][0][RTW89_QATAR][51] = 127, [1][1][2][0][RTW89_FCC][1] = 54, [1][1][2][0][RTW89_ETSI][1] = 54, [1][1][2][0][RTW89_MKK][1] = 48, @@ -31564,6 +32870,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][1] = 54, [1][1][2][0][RTW89_CN][1] = 42, [1][1][2][0][RTW89_UK][1] = 54, + [1][1][2][0][RTW89_MEXICO][1] = 50, + [1][1][2][0][RTW89_UKRAINE][1] = 42, + [1][1][2][0][RTW89_CHILE][1] = 54, + [1][1][2][0][RTW89_QATAR][1] = 54, [1][1][2][0][RTW89_FCC][5] = 68, [1][1][2][0][RTW89_ETSI][5] = 54, [1][1][2][0][RTW89_MKK][5] = 52, @@ -31572,6 +32882,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][5] = 54, [1][1][2][0][RTW89_CN][5] = 42, [1][1][2][0][RTW89_UK][5] = 54, + [1][1][2][0][RTW89_MEXICO][5] = 50, + [1][1][2][0][RTW89_UKRAINE][5] = 42, + [1][1][2][0][RTW89_CHILE][5] = 66, + [1][1][2][0][RTW89_QATAR][5] = 54, [1][1][2][0][RTW89_FCC][9] = 68, [1][1][2][0][RTW89_ETSI][9] = 54, [1][1][2][0][RTW89_MKK][9] = 52, @@ -31580,6 +32894,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][9] = 54, [1][1][2][0][RTW89_CN][9] = 42, [1][1][2][0][RTW89_UK][9] = 54, + [1][1][2][0][RTW89_MEXICO][9] = 68, + [1][1][2][0][RTW89_UKRAINE][9] = 42, + [1][1][2][0][RTW89_CHILE][9] = 66, + [1][1][2][0][RTW89_QATAR][9] = 54, [1][1][2][0][RTW89_FCC][13] = 54, [1][1][2][0][RTW89_ETSI][13] = 54, [1][1][2][0][RTW89_MKK][13] = 52, @@ -31588,6 +32906,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][13] = 54, [1][1][2][0][RTW89_CN][13] = 42, [1][1][2][0][RTW89_UK][13] = 54, + [1][1][2][0][RTW89_MEXICO][13] = 54, + [1][1][2][0][RTW89_UKRAINE][13] = 42, + [1][1][2][0][RTW89_CHILE][13] = 54, + [1][1][2][0][RTW89_QATAR][13] = 54, [1][1][2][0][RTW89_FCC][16] = 56, [1][1][2][0][RTW89_ETSI][16] = 54, [1][1][2][0][RTW89_MKK][16] = 66, @@ -31596,6 +32918,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][16] = 54, [1][1][2][0][RTW89_CN][16] = 127, [1][1][2][0][RTW89_UK][16] = 54, + [1][1][2][0][RTW89_MEXICO][16] = 56, + [1][1][2][0][RTW89_UKRAINE][16] = 42, + [1][1][2][0][RTW89_CHILE][16] = 54, + [1][1][2][0][RTW89_QATAR][16] = 54, [1][1][2][0][RTW89_FCC][20] = 68, [1][1][2][0][RTW89_ETSI][20] = 54, [1][1][2][0][RTW89_MKK][20] = 66, @@ -31604,6 +32930,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][20] = 54, [1][1][2][0][RTW89_CN][20] = 127, [1][1][2][0][RTW89_UK][20] = 54, + [1][1][2][0][RTW89_MEXICO][20] = 68, + [1][1][2][0][RTW89_UKRAINE][20] = 42, + [1][1][2][0][RTW89_CHILE][20] = 66, + [1][1][2][0][RTW89_QATAR][20] = 54, [1][1][2][0][RTW89_FCC][24] = 68, [1][1][2][0][RTW89_ETSI][24] = 54, [1][1][2][0][RTW89_MKK][24] = 66, @@ -31612,6 +32942,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][24] = 127, [1][1][2][0][RTW89_CN][24] = 127, [1][1][2][0][RTW89_UK][24] = 54, + [1][1][2][0][RTW89_MEXICO][24] = 68, + [1][1][2][0][RTW89_UKRAINE][24] = 42, + [1][1][2][0][RTW89_CHILE][24] = 66, + [1][1][2][0][RTW89_QATAR][24] = 54, [1][1][2][0][RTW89_FCC][28] = 68, [1][1][2][0][RTW89_ETSI][28] = 54, [1][1][2][0][RTW89_MKK][28] = 66, @@ -31620,6 +32954,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][28] = 127, [1][1][2][0][RTW89_CN][28] = 127, [1][1][2][0][RTW89_UK][28] = 54, + [1][1][2][0][RTW89_MEXICO][28] = 68, + [1][1][2][0][RTW89_UKRAINE][28] = 42, + [1][1][2][0][RTW89_CHILE][28] = 54, + [1][1][2][0][RTW89_QATAR][28] = 54, [1][1][2][0][RTW89_FCC][32] = 56, [1][1][2][0][RTW89_ETSI][32] = 54, [1][1][2][0][RTW89_MKK][32] = 66, @@ -31628,6 +32966,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][32] = 54, [1][1][2][0][RTW89_CN][32] = 127, [1][1][2][0][RTW89_UK][32] = 54, + [1][1][2][0][RTW89_MEXICO][32] = 56, + [1][1][2][0][RTW89_UKRAINE][32] = 42, + [1][1][2][0][RTW89_CHILE][32] = 54, + [1][1][2][0][RTW89_QATAR][32] = 54, [1][1][2][0][RTW89_FCC][36] = 68, [1][1][2][0][RTW89_ETSI][36] = 127, [1][1][2][0][RTW89_MKK][36] = 66, @@ -31636,6 +32978,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][36] = 66, [1][1][2][0][RTW89_CN][36] = 127, [1][1][2][0][RTW89_UK][36] = 52, + [1][1][2][0][RTW89_MEXICO][36] = 68, + [1][1][2][0][RTW89_UKRAINE][36] = 127, + [1][1][2][0][RTW89_CHILE][36] = 66, + [1][1][2][0][RTW89_QATAR][36] = 127, [1][1][2][0][RTW89_FCC][39] = 68, [1][1][2][0][RTW89_ETSI][39] = 18, [1][1][2][0][RTW89_MKK][39] = 127, @@ -31644,6 +32990,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][39] = 66, [1][1][2][0][RTW89_CN][39] = 62, [1][1][2][0][RTW89_UK][39] = 52, + [1][1][2][0][RTW89_MEXICO][39] = 68, + [1][1][2][0][RTW89_UKRAINE][39] = 18, + [1][1][2][0][RTW89_CHILE][39] = 66, + [1][1][2][0][RTW89_QATAR][39] = 18, [1][1][2][0][RTW89_FCC][43] = 68, [1][1][2][0][RTW89_ETSI][43] = 18, [1][1][2][0][RTW89_MKK][43] = 127, @@ -31652,6 +33002,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][43] = 66, [1][1][2][0][RTW89_CN][43] = 66, [1][1][2][0][RTW89_UK][43] = 52, + [1][1][2][0][RTW89_MEXICO][43] = 68, + [1][1][2][0][RTW89_UKRAINE][43] = 18, + [1][1][2][0][RTW89_CHILE][43] = 66, + [1][1][2][0][RTW89_QATAR][43] = 18, [1][1][2][0][RTW89_FCC][47] = 62, [1][1][2][0][RTW89_ETSI][47] = 127, [1][1][2][0][RTW89_MKK][47] = 127, @@ -31660,6 +33014,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][47] = 127, [1][1][2][0][RTW89_CN][47] = 127, [1][1][2][0][RTW89_UK][47] = 127, + [1][1][2][0][RTW89_MEXICO][47] = 127, + [1][1][2][0][RTW89_UKRAINE][47] = 127, + [1][1][2][0][RTW89_CHILE][47] = 127, + [1][1][2][0][RTW89_QATAR][47] = 127, [1][1][2][0][RTW89_FCC][51] = 60, [1][1][2][0][RTW89_ETSI][51] = 127, [1][1][2][0][RTW89_MKK][51] = 127, @@ -31668,6 +33026,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_ACMA][51] = 127, [1][1][2][0][RTW89_CN][51] = 127, [1][1][2][0][RTW89_UK][51] = 127, + [1][1][2][0][RTW89_MEXICO][51] = 127, + [1][1][2][0][RTW89_UKRAINE][51] = 127, + [1][1][2][0][RTW89_CHILE][51] = 127, + [1][1][2][0][RTW89_QATAR][51] = 127, [1][1][2][1][RTW89_FCC][1] = 54, [1][1][2][1][RTW89_ETSI][1] = 40, [1][1][2][1][RTW89_MKK][1] = 48, @@ -31676,6 +33038,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][1] = 40, [1][1][2][1][RTW89_CN][1] = 42, [1][1][2][1][RTW89_UK][1] = 40, + [1][1][2][1][RTW89_MEXICO][1] = 50, + [1][1][2][1][RTW89_UKRAINE][1] = 30, + [1][1][2][1][RTW89_CHILE][1] = 54, + [1][1][2][1][RTW89_QATAR][1] = 40, [1][1][2][1][RTW89_FCC][5] = 68, [1][1][2][1][RTW89_ETSI][5] = 40, [1][1][2][1][RTW89_MKK][5] = 52, @@ -31684,6 +33050,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][5] = 40, [1][1][2][1][RTW89_CN][5] = 42, [1][1][2][1][RTW89_UK][5] = 40, + [1][1][2][1][RTW89_MEXICO][5] = 50, + [1][1][2][1][RTW89_UKRAINE][5] = 30, + [1][1][2][1][RTW89_CHILE][5] = 60, + [1][1][2][1][RTW89_QATAR][5] = 40, [1][1][2][1][RTW89_FCC][9] = 68, [1][1][2][1][RTW89_ETSI][9] = 40, [1][1][2][1][RTW89_MKK][9] = 52, @@ -31692,6 +33062,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][9] = 40, [1][1][2][1][RTW89_CN][9] = 42, [1][1][2][1][RTW89_UK][9] = 40, + [1][1][2][1][RTW89_MEXICO][9] = 68, + [1][1][2][1][RTW89_UKRAINE][9] = 30, + [1][1][2][1][RTW89_CHILE][9] = 60, + [1][1][2][1][RTW89_QATAR][9] = 40, [1][1][2][1][RTW89_FCC][13] = 54, [1][1][2][1][RTW89_ETSI][13] = 40, [1][1][2][1][RTW89_MKK][13] = 52, @@ -31700,6 +33074,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][13] = 40, [1][1][2][1][RTW89_CN][13] = 42, [1][1][2][1][RTW89_UK][13] = 40, + [1][1][2][1][RTW89_MEXICO][13] = 54, + [1][1][2][1][RTW89_UKRAINE][13] = 30, + [1][1][2][1][RTW89_CHILE][13] = 54, + [1][1][2][1][RTW89_QATAR][13] = 40, [1][1][2][1][RTW89_FCC][16] = 56, [1][1][2][1][RTW89_ETSI][16] = 40, [1][1][2][1][RTW89_MKK][16] = 66, @@ -31708,6 +33086,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][16] = 40, [1][1][2][1][RTW89_CN][16] = 127, [1][1][2][1][RTW89_UK][16] = 40, + [1][1][2][1][RTW89_MEXICO][16] = 56, + [1][1][2][1][RTW89_UKRAINE][16] = 30, + [1][1][2][1][RTW89_CHILE][16] = 54, + [1][1][2][1][RTW89_QATAR][16] = 40, [1][1][2][1][RTW89_FCC][20] = 68, [1][1][2][1][RTW89_ETSI][20] = 40, [1][1][2][1][RTW89_MKK][20] = 66, @@ -31716,6 +33098,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][20] = 40, [1][1][2][1][RTW89_CN][20] = 127, [1][1][2][1][RTW89_UK][20] = 40, + [1][1][2][1][RTW89_MEXICO][20] = 68, + [1][1][2][1][RTW89_UKRAINE][20] = 30, + [1][1][2][1][RTW89_CHILE][20] = 60, + [1][1][2][1][RTW89_QATAR][20] = 40, [1][1][2][1][RTW89_FCC][24] = 68, [1][1][2][1][RTW89_ETSI][24] = 40, [1][1][2][1][RTW89_MKK][24] = 66, @@ -31724,6 +33110,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][24] = 127, [1][1][2][1][RTW89_CN][24] = 127, [1][1][2][1][RTW89_UK][24] = 40, + [1][1][2][1][RTW89_MEXICO][24] = 68, + [1][1][2][1][RTW89_UKRAINE][24] = 30, + [1][1][2][1][RTW89_CHILE][24] = 60, + [1][1][2][1][RTW89_QATAR][24] = 40, [1][1][2][1][RTW89_FCC][28] = 68, [1][1][2][1][RTW89_ETSI][28] = 40, [1][1][2][1][RTW89_MKK][28] = 66, @@ -31732,6 +33122,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][28] = 127, [1][1][2][1][RTW89_CN][28] = 127, [1][1][2][1][RTW89_UK][28] = 40, + [1][1][2][1][RTW89_MEXICO][28] = 68, + [1][1][2][1][RTW89_UKRAINE][28] = 30, + [1][1][2][1][RTW89_CHILE][28] = 54, + [1][1][2][1][RTW89_QATAR][28] = 40, [1][1][2][1][RTW89_FCC][32] = 56, [1][1][2][1][RTW89_ETSI][32] = 40, [1][1][2][1][RTW89_MKK][32] = 66, @@ -31740,6 +33134,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][32] = 40, [1][1][2][1][RTW89_CN][32] = 127, [1][1][2][1][RTW89_UK][32] = 40, + [1][1][2][1][RTW89_MEXICO][32] = 56, + [1][1][2][1][RTW89_UKRAINE][32] = 30, + [1][1][2][1][RTW89_CHILE][32] = 54, + [1][1][2][1][RTW89_QATAR][32] = 40, [1][1][2][1][RTW89_FCC][36] = 68, [1][1][2][1][RTW89_ETSI][36] = 127, [1][1][2][1][RTW89_MKK][36] = 66, @@ -31748,6 +33146,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][36] = 66, [1][1][2][1][RTW89_CN][36] = 127, [1][1][2][1][RTW89_UK][36] = 40, + [1][1][2][1][RTW89_MEXICO][36] = 68, + [1][1][2][1][RTW89_UKRAINE][36] = 127, + [1][1][2][1][RTW89_CHILE][36] = 66, + [1][1][2][1][RTW89_QATAR][36] = 127, [1][1][2][1][RTW89_FCC][39] = 68, [1][1][2][1][RTW89_ETSI][39] = 6, [1][1][2][1][RTW89_MKK][39] = 127, @@ -31756,6 +33158,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][39] = 66, [1][1][2][1][RTW89_CN][39] = 60, [1][1][2][1][RTW89_UK][39] = 40, + [1][1][2][1][RTW89_MEXICO][39] = 68, + [1][1][2][1][RTW89_UKRAINE][39] = 6, + [1][1][2][1][RTW89_CHILE][39] = 60, + [1][1][2][1][RTW89_QATAR][39] = 6, [1][1][2][1][RTW89_FCC][43] = 68, [1][1][2][1][RTW89_ETSI][43] = 6, [1][1][2][1][RTW89_MKK][43] = 127, @@ -31764,6 +33170,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][43] = 66, [1][1][2][1][RTW89_CN][43] = 52, [1][1][2][1][RTW89_UK][43] = 40, + [1][1][2][1][RTW89_MEXICO][43] = 68, + [1][1][2][1][RTW89_UKRAINE][43] = 6, + [1][1][2][1][RTW89_CHILE][43] = 60, + [1][1][2][1][RTW89_QATAR][43] = 6, [1][1][2][1][RTW89_FCC][47] = 62, [1][1][2][1][RTW89_ETSI][47] = 127, [1][1][2][1][RTW89_MKK][47] = 127, @@ -31772,6 +33182,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][47] = 127, [1][1][2][1][RTW89_CN][47] = 127, [1][1][2][1][RTW89_UK][47] = 127, + [1][1][2][1][RTW89_MEXICO][47] = 127, + [1][1][2][1][RTW89_UKRAINE][47] = 127, + [1][1][2][1][RTW89_CHILE][47] = 127, + [1][1][2][1][RTW89_QATAR][47] = 127, [1][1][2][1][RTW89_FCC][51] = 60, [1][1][2][1][RTW89_ETSI][51] = 127, [1][1][2][1][RTW89_MKK][51] = 127, @@ -31780,6 +33194,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][51] = 127, [1][1][2][1][RTW89_CN][51] = 127, [1][1][2][1][RTW89_UK][51] = 127, + [1][1][2][1][RTW89_MEXICO][51] = 127, + [1][1][2][1][RTW89_UKRAINE][51] = 127, + [1][1][2][1][RTW89_CHILE][51] = 127, + [1][1][2][1][RTW89_QATAR][51] = 127, [2][0][2][0][RTW89_FCC][3] = 58, [2][0][2][0][RTW89_ETSI][3] = 60, [2][0][2][0][RTW89_MKK][3] = 60, @@ -31788,6 +33206,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_ACMA][3] = 60, [2][0][2][0][RTW89_CN][3] = 54, [2][0][2][0][RTW89_UK][3] = 60, + [2][0][2][0][RTW89_MEXICO][3] = 58, + [2][0][2][0][RTW89_UKRAINE][3] = 54, + [2][0][2][0][RTW89_CHILE][3] = 58, + [2][0][2][0][RTW89_QATAR][3] = 60, [2][0][2][0][RTW89_FCC][11] = 50, [2][0][2][0][RTW89_ETSI][11] = 60, [2][0][2][0][RTW89_MKK][11] = 60, @@ -31796,6 +33218,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_ACMA][11] = 60, [2][0][2][0][RTW89_CN][11] = 54, [2][0][2][0][RTW89_UK][11] = 60, + [2][0][2][0][RTW89_MEXICO][11] = 50, + [2][0][2][0][RTW89_UKRAINE][11] = 54, + [2][0][2][0][RTW89_CHILE][11] = 50, + [2][0][2][0][RTW89_QATAR][11] = 60, [2][0][2][0][RTW89_FCC][18] = 60, [2][0][2][0][RTW89_ETSI][18] = 60, [2][0][2][0][RTW89_MKK][18] = 60, @@ -31804,6 +33230,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_ACMA][18] = 60, [2][0][2][0][RTW89_CN][18] = 127, [2][0][2][0][RTW89_UK][18] = 60, + [2][0][2][0][RTW89_MEXICO][18] = 60, + [2][0][2][0][RTW89_UKRAINE][18] = 54, + [2][0][2][0][RTW89_CHILE][18] = 60, + [2][0][2][0][RTW89_QATAR][18] = 60, [2][0][2][0][RTW89_FCC][26] = 62, [2][0][2][0][RTW89_ETSI][26] = 60, [2][0][2][0][RTW89_MKK][26] = 60, @@ -31812,6 +33242,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_ACMA][26] = 127, [2][0][2][0][RTW89_CN][26] = 127, [2][0][2][0][RTW89_UK][26] = 60, + [2][0][2][0][RTW89_MEXICO][26] = 62, + [2][0][2][0][RTW89_UKRAINE][26] = 54, + [2][0][2][0][RTW89_CHILE][26] = 60, + [2][0][2][0][RTW89_QATAR][26] = 60, [2][0][2][0][RTW89_FCC][34] = 62, [2][0][2][0][RTW89_ETSI][34] = 127, [2][0][2][0][RTW89_MKK][34] = 60, @@ -31820,6 +33254,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_ACMA][34] = 60, [2][0][2][0][RTW89_CN][34] = 127, [2][0][2][0][RTW89_UK][34] = 60, + [2][0][2][0][RTW89_MEXICO][34] = 62, + [2][0][2][0][RTW89_UKRAINE][34] = 127, + [2][0][2][0][RTW89_CHILE][34] = 60, + [2][0][2][0][RTW89_QATAR][34] = 127, [2][0][2][0][RTW89_FCC][41] = 62, [2][0][2][0][RTW89_ETSI][41] = 30, [2][0][2][0][RTW89_MKK][41] = 127, @@ -31828,6 +33266,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_ACMA][41] = 60, [2][0][2][0][RTW89_CN][41] = 62, [2][0][2][0][RTW89_UK][41] = 60, + [2][0][2][0][RTW89_MEXICO][41] = 62, + [2][0][2][0][RTW89_UKRAINE][41] = 30, + [2][0][2][0][RTW89_CHILE][41] = 60, + [2][0][2][0][RTW89_QATAR][41] = 30, [2][0][2][0][RTW89_FCC][49] = 62, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, @@ -31836,6 +33278,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_ACMA][49] = 127, [2][0][2][0][RTW89_CN][49] = 127, [2][0][2][0][RTW89_UK][49] = 127, + [2][0][2][0][RTW89_MEXICO][49] = 127, + [2][0][2][0][RTW89_UKRAINE][49] = 127, + [2][0][2][0][RTW89_CHILE][49] = 127, + [2][0][2][0][RTW89_QATAR][49] = 127, [2][1][2][0][RTW89_FCC][3] = 48, [2][1][2][0][RTW89_ETSI][3] = 54, [2][1][2][0][RTW89_MKK][3] = 56, @@ -31844,6 +33290,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_ACMA][3] = 54, [2][1][2][0][RTW89_CN][3] = 52, [2][1][2][0][RTW89_UK][3] = 54, + [2][1][2][0][RTW89_MEXICO][3] = 48, + [2][1][2][0][RTW89_UKRAINE][3] = 42, + [2][1][2][0][RTW89_CHILE][3] = 46, + [2][1][2][0][RTW89_QATAR][3] = 54, [2][1][2][0][RTW89_FCC][11] = 38, [2][1][2][0][RTW89_ETSI][11] = 54, [2][1][2][0][RTW89_MKK][11] = 54, @@ -31852,6 +33302,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_ACMA][11] = 54, [2][1][2][0][RTW89_CN][11] = 52, [2][1][2][0][RTW89_UK][11] = 54, + [2][1][2][0][RTW89_MEXICO][11] = 38, + [2][1][2][0][RTW89_UKRAINE][11] = 42, + [2][1][2][0][RTW89_CHILE][11] = 38, + [2][1][2][0][RTW89_QATAR][11] = 54, [2][1][2][0][RTW89_FCC][18] = 50, [2][1][2][0][RTW89_ETSI][18] = 54, [2][1][2][0][RTW89_MKK][18] = 60, @@ -31860,6 +33314,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_ACMA][18] = 54, [2][1][2][0][RTW89_CN][18] = 127, [2][1][2][0][RTW89_UK][18] = 54, + [2][1][2][0][RTW89_MEXICO][18] = 50, + [2][1][2][0][RTW89_UKRAINE][18] = 42, + [2][1][2][0][RTW89_CHILE][18] = 50, + [2][1][2][0][RTW89_QATAR][18] = 54, [2][1][2][0][RTW89_FCC][26] = 52, [2][1][2][0][RTW89_ETSI][26] = 54, [2][1][2][0][RTW89_MKK][26] = 56, @@ -31868,6 +33326,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_ACMA][26] = 127, [2][1][2][0][RTW89_CN][26] = 127, [2][1][2][0][RTW89_UK][26] = 54, + [2][1][2][0][RTW89_MEXICO][26] = 52, + [2][1][2][0][RTW89_UKRAINE][26] = 42, + [2][1][2][0][RTW89_CHILE][26] = 52, + [2][1][2][0][RTW89_QATAR][26] = 54, [2][1][2][0][RTW89_FCC][34] = 62, [2][1][2][0][RTW89_ETSI][34] = 127, [2][1][2][0][RTW89_MKK][34] = 60, @@ -31876,6 +33338,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_ACMA][34] = 60, [2][1][2][0][RTW89_CN][34] = 127, [2][1][2][0][RTW89_UK][34] = 52, + [2][1][2][0][RTW89_MEXICO][34] = 62, + [2][1][2][0][RTW89_UKRAINE][34] = 127, + [2][1][2][0][RTW89_CHILE][34] = 60, + [2][1][2][0][RTW89_QATAR][34] = 127, [2][1][2][0][RTW89_FCC][41] = 60, [2][1][2][0][RTW89_ETSI][41] = 18, [2][1][2][0][RTW89_MKK][41] = 127, @@ -31884,6 +33350,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_ACMA][41] = 58, [2][1][2][0][RTW89_CN][41] = 62, [2][1][2][0][RTW89_UK][41] = 52, + [2][1][2][0][RTW89_MEXICO][41] = 60, + [2][1][2][0][RTW89_UKRAINE][41] = 18, + [2][1][2][0][RTW89_CHILE][41] = 58, + [2][1][2][0][RTW89_QATAR][41] = 18, [2][1][2][0][RTW89_FCC][49] = 62, [2][1][2][0][RTW89_ETSI][49] = 127, [2][1][2][0][RTW89_MKK][49] = 127, @@ -31892,6 +33362,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_ACMA][49] = 127, [2][1][2][0][RTW89_CN][49] = 127, [2][1][2][0][RTW89_UK][49] = 127, + [2][1][2][0][RTW89_MEXICO][49] = 127, + [2][1][2][0][RTW89_UKRAINE][49] = 127, + [2][1][2][0][RTW89_CHILE][49] = 127, + [2][1][2][0][RTW89_QATAR][49] = 127, [2][1][2][1][RTW89_FCC][3] = 48, [2][1][2][1][RTW89_ETSI][3] = 40, [2][1][2][1][RTW89_MKK][3] = 56, @@ -31900,6 +33374,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_ACMA][3] = 40, [2][1][2][1][RTW89_CN][3] = 42, [2][1][2][1][RTW89_UK][3] = 40, + [2][1][2][1][RTW89_MEXICO][3] = 48, + [2][1][2][1][RTW89_UKRAINE][3] = 30, + [2][1][2][1][RTW89_CHILE][3] = 46, + [2][1][2][1][RTW89_QATAR][3] = 40, [2][1][2][1][RTW89_FCC][11] = 38, [2][1][2][1][RTW89_ETSI][11] = 40, [2][1][2][1][RTW89_MKK][11] = 54, @@ -31908,6 +33386,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_ACMA][11] = 40, [2][1][2][1][RTW89_CN][11] = 42, [2][1][2][1][RTW89_UK][11] = 40, + [2][1][2][1][RTW89_MEXICO][11] = 38, + [2][1][2][1][RTW89_UKRAINE][11] = 30, + [2][1][2][1][RTW89_CHILE][11] = 38, + [2][1][2][1][RTW89_QATAR][11] = 40, [2][1][2][1][RTW89_FCC][18] = 50, [2][1][2][1][RTW89_ETSI][18] = 40, [2][1][2][1][RTW89_MKK][18] = 60, @@ -31916,6 +33398,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_ACMA][18] = 40, [2][1][2][1][RTW89_CN][18] = 127, [2][1][2][1][RTW89_UK][18] = 40, + [2][1][2][1][RTW89_MEXICO][18] = 50, + [2][1][2][1][RTW89_UKRAINE][18] = 30, + [2][1][2][1][RTW89_CHILE][18] = 50, + [2][1][2][1][RTW89_QATAR][18] = 40, [2][1][2][1][RTW89_FCC][26] = 52, [2][1][2][1][RTW89_ETSI][26] = 42, [2][1][2][1][RTW89_MKK][26] = 56, @@ -31924,6 +33410,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_ACMA][26] = 127, [2][1][2][1][RTW89_CN][26] = 127, [2][1][2][1][RTW89_UK][26] = 42, + [2][1][2][1][RTW89_MEXICO][26] = 52, + [2][1][2][1][RTW89_UKRAINE][26] = 30, + [2][1][2][1][RTW89_CHILE][26] = 52, + [2][1][2][1][RTW89_QATAR][26] = 42, [2][1][2][1][RTW89_FCC][34] = 62, [2][1][2][1][RTW89_ETSI][34] = 127, [2][1][2][1][RTW89_MKK][34] = 60, @@ -31932,6 +33422,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_ACMA][34] = 60, [2][1][2][1][RTW89_CN][34] = 127, [2][1][2][1][RTW89_UK][34] = 40, + [2][1][2][1][RTW89_MEXICO][34] = 62, + [2][1][2][1][RTW89_UKRAINE][34] = 127, + [2][1][2][1][RTW89_CHILE][34] = 60, + [2][1][2][1][RTW89_QATAR][34] = 127, [2][1][2][1][RTW89_FCC][41] = 60, [2][1][2][1][RTW89_ETSI][41] = 6, [2][1][2][1][RTW89_MKK][41] = 127, @@ -31940,6 +33434,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_ACMA][41] = 58, [2][1][2][1][RTW89_CN][41] = 40, [2][1][2][1][RTW89_UK][41] = 40, + [2][1][2][1][RTW89_MEXICO][41] = 60, + [2][1][2][1][RTW89_UKRAINE][41] = 6, + [2][1][2][1][RTW89_CHILE][41] = 58, + [2][1][2][1][RTW89_QATAR][41] = 6, [2][1][2][1][RTW89_FCC][49] = 62, [2][1][2][1][RTW89_ETSI][49] = 127, [2][1][2][1][RTW89_MKK][49] = 127, @@ -31948,6 +33446,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_ACMA][49] = 127, [2][1][2][1][RTW89_CN][49] = 127, [2][1][2][1][RTW89_UK][49] = 127, + [2][1][2][1][RTW89_MEXICO][49] = 127, + [2][1][2][1][RTW89_UKRAINE][49] = 127, + [2][1][2][1][RTW89_CHILE][49] = 127, + [2][1][2][1][RTW89_QATAR][49] = 127, [3][0][2][0][RTW89_FCC][7] = 40, [3][0][2][0][RTW89_ETSI][7] = 50, [3][0][2][0][RTW89_MKK][7] = 50, @@ -31956,6 +33458,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][0][2][0][RTW89_ACMA][7] = 127, [3][0][2][0][RTW89_CN][7] = 66, [3][0][2][0][RTW89_UK][7] = 127, + [3][0][2][0][RTW89_MEXICO][7] = 127, + [3][0][2][0][RTW89_UKRAINE][7] = 50, + [3][0][2][0][RTW89_CHILE][7] = 40, + [3][0][2][0][RTW89_QATAR][7] = 50, [3][0][2][0][RTW89_FCC][22] = 42, [3][0][2][0][RTW89_ETSI][22] = 50, [3][0][2][0][RTW89_MKK][22] = 50, @@ -31964,6 +33470,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][0][2][0][RTW89_ACMA][22] = 127, [3][0][2][0][RTW89_CN][22] = 66, [3][0][2][0][RTW89_UK][22] = 127, + [3][0][2][0][RTW89_MEXICO][22] = 127, + [3][0][2][0][RTW89_UKRAINE][22] = 50, + [3][0][2][0][RTW89_CHILE][22] = 42, + [3][0][2][0][RTW89_QATAR][22] = 50, [3][0][2][0][RTW89_FCC][45] = 52, [3][0][2][0][RTW89_ETSI][45] = 127, [3][0][2][0][RTW89_MKK][45] = 127, @@ -31972,6 +33482,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][0][2][0][RTW89_ACMA][45] = 127, [3][0][2][0][RTW89_CN][45] = 127, [3][0][2][0][RTW89_UK][45] = 127, + [3][0][2][0][RTW89_MEXICO][45] = 127, + [3][0][2][0][RTW89_UKRAINE][45] = 127, + [3][0][2][0][RTW89_CHILE][45] = 127, + [3][0][2][0][RTW89_QATAR][45] = 127, [3][1][2][0][RTW89_FCC][7] = 32, [3][1][2][0][RTW89_ETSI][7] = 50, [3][1][2][0][RTW89_MKK][7] = 36, @@ -31980,6 +33494,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][1][2][0][RTW89_ACMA][7] = 127, [3][1][2][0][RTW89_CN][7] = 54, [3][1][2][0][RTW89_UK][7] = 127, + [3][1][2][0][RTW89_MEXICO][7] = 127, + [3][1][2][0][RTW89_UKRAINE][7] = 50, + [3][1][2][0][RTW89_CHILE][7] = 32, + [3][1][2][0][RTW89_QATAR][7] = 50, [3][1][2][0][RTW89_FCC][22] = 36, [3][1][2][0][RTW89_ETSI][22] = 50, [3][1][2][0][RTW89_MKK][22] = 48, @@ -31988,6 +33506,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][1][2][0][RTW89_ACMA][22] = 127, [3][1][2][0][RTW89_CN][22] = 54, [3][1][2][0][RTW89_UK][22] = 127, + [3][1][2][0][RTW89_MEXICO][22] = 127, + [3][1][2][0][RTW89_UKRAINE][22] = 50, + [3][1][2][0][RTW89_CHILE][22] = 36, + [3][1][2][0][RTW89_QATAR][22] = 50, [3][1][2][0][RTW89_FCC][45] = 46, [3][1][2][0][RTW89_ETSI][45] = 127, [3][1][2][0][RTW89_MKK][45] = 127, @@ -31996,6 +33518,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][1][2][0][RTW89_ACMA][45] = 127, [3][1][2][0][RTW89_CN][45] = 127, [3][1][2][0][RTW89_UK][45] = 127, + [3][1][2][0][RTW89_MEXICO][45] = 127, + [3][1][2][0][RTW89_UKRAINE][45] = 127, + [3][1][2][0][RTW89_CHILE][45] = 127, + [3][1][2][0][RTW89_QATAR][45] = 127, [3][1][2][1][RTW89_FCC][7] = 32, [3][1][2][1][RTW89_ETSI][7] = 42, [3][1][2][1][RTW89_MKK][7] = 36, @@ -32004,6 +33530,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][1][2][1][RTW89_ACMA][7] = 127, [3][1][2][1][RTW89_CN][7] = 42, [3][1][2][1][RTW89_UK][7] = 127, + [3][1][2][1][RTW89_MEXICO][7] = 127, + [3][1][2][1][RTW89_UKRAINE][7] = 42, + [3][1][2][1][RTW89_CHILE][7] = 32, + [3][1][2][1][RTW89_QATAR][7] = 42, [3][1][2][1][RTW89_FCC][22] = 36, [3][1][2][1][RTW89_ETSI][22] = 42, [3][1][2][1][RTW89_MKK][22] = 48, @@ -32012,6 +33542,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][1][2][1][RTW89_ACMA][22] = 127, [3][1][2][1][RTW89_CN][22] = 42, [3][1][2][1][RTW89_UK][22] = 127, + [3][1][2][1][RTW89_MEXICO][22] = 127, + [3][1][2][1][RTW89_UKRAINE][22] = 42, + [3][1][2][1][RTW89_CHILE][22] = 36, + [3][1][2][1][RTW89_QATAR][22] = 42, [3][1][2][1][RTW89_FCC][45] = 46, [3][1][2][1][RTW89_ETSI][45] = 127, [3][1][2][1][RTW89_MKK][45] = 127, @@ -32020,6 +33554,10 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][1][2][1][RTW89_ACMA][45] = 127, [3][1][2][1][RTW89_CN][45] = 127, [3][1][2][1][RTW89_UK][45] = 127, + [3][1][2][1][RTW89_MEXICO][45] = 127, + [3][1][2][1][RTW89_UKRAINE][45] = 127, + [3][1][2][1][RTW89_CHILE][45] = 127, + [3][1][2][1][RTW89_QATAR][45] = 127, }; static @@ -34017,10 +35555,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_WW][3] = 44, [1][0][RTW89_WW][4] = 44, [1][0][RTW89_WW][5] = 44, - [1][0][RTW89_WW][6] = 44, - [1][0][RTW89_WW][7] = 44, - [1][0][RTW89_WW][8] = 44, - [1][0][RTW89_WW][9] = 44, + [1][0][RTW89_WW][6] = 40, + [1][0][RTW89_WW][7] = 40, + [1][0][RTW89_WW][8] = 40, + [1][0][RTW89_WW][9] = 40, [1][0][RTW89_WW][10] = 44, [1][0][RTW89_WW][11] = 36, [1][0][RTW89_WW][12] = 4, @@ -34031,24 +35569,24 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_WW][3] = 32, [1][1][RTW89_WW][4] = 32, [1][1][RTW89_WW][5] = 32, - [1][1][RTW89_WW][6] = 32, - [1][1][RTW89_WW][7] = 32, - [1][1][RTW89_WW][8] = 32, - [1][1][RTW89_WW][9] = 32, + [1][1][RTW89_WW][6] = 30, + [1][1][RTW89_WW][7] = 30, + [1][1][RTW89_WW][8] = 30, + [1][1][RTW89_WW][9] = 30, [1][1][RTW89_WW][10] = 32, [1][1][RTW89_WW][11] = 30, [1][1][RTW89_WW][12] = -6, [1][1][RTW89_WW][13] = 0, [2][0][RTW89_WW][0] = 56, - [2][0][RTW89_WW][1] = 56, - [2][0][RTW89_WW][2] = 56, - [2][0][RTW89_WW][3] = 56, - [2][0][RTW89_WW][4] = 56, + [2][0][RTW89_WW][1] = 54, + [2][0][RTW89_WW][2] = 54, + [2][0][RTW89_WW][3] = 54, + [2][0][RTW89_WW][4] = 54, [2][0][RTW89_WW][5] = 56, - [2][0][RTW89_WW][6] = 56, - [2][0][RTW89_WW][7] = 56, - [2][0][RTW89_WW][8] = 56, - [2][0][RTW89_WW][9] = 56, + [2][0][RTW89_WW][6] = 48, + [2][0][RTW89_WW][7] = 48, + [2][0][RTW89_WW][8] = 48, + [2][0][RTW89_WW][9] = 48, [2][0][RTW89_WW][10] = 56, [2][0][RTW89_WW][11] = 48, [2][0][RTW89_WW][12] = 16, @@ -34059,10 +35597,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_WW][3] = 44, [2][1][RTW89_WW][4] = 44, [2][1][RTW89_WW][5] = 44, - [2][1][RTW89_WW][6] = 44, - [2][1][RTW89_WW][7] = 44, - [2][1][RTW89_WW][8] = 44, - [2][1][RTW89_WW][9] = 44, + [2][1][RTW89_WW][6] = 42, + [2][1][RTW89_WW][7] = 42, + [2][1][RTW89_WW][8] = 42, + [2][1][RTW89_WW][9] = 42, [2][1][RTW89_WW][10] = 44, [2][1][RTW89_WW][11] = 44, [2][1][RTW89_WW][12] = 6, @@ -34075,6 +35613,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][0] = 34, [0][0][RTW89_CN][0] = 32, [0][0][RTW89_UK][0] = 34, + [0][0][RTW89_MEXICO][0] = 60, + [0][0][RTW89_UKRAINE][0] = 34, + [0][0][RTW89_CHILE][0] = 60, + [0][0][RTW89_QATAR][0] = 34, [0][0][RTW89_FCC][1] = 60, [0][0][RTW89_ETSI][1] = 38, [0][0][RTW89_MKK][1] = 40, @@ -34083,6 +35625,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][1] = 38, [0][0][RTW89_CN][1] = 32, [0][0][RTW89_UK][1] = 38, + [0][0][RTW89_MEXICO][1] = 60, + [0][0][RTW89_UKRAINE][1] = 38, + [0][0][RTW89_CHILE][1] = 50, + [0][0][RTW89_QATAR][1] = 38, [0][0][RTW89_FCC][2] = 64, [0][0][RTW89_ETSI][2] = 38, [0][0][RTW89_MKK][2] = 40, @@ -34091,6 +35637,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][2] = 38, [0][0][RTW89_CN][2] = 32, [0][0][RTW89_UK][2] = 38, + [0][0][RTW89_MEXICO][2] = 64, + [0][0][RTW89_UKRAINE][2] = 38, + [0][0][RTW89_CHILE][2] = 50, + [0][0][RTW89_QATAR][2] = 38, [0][0][RTW89_FCC][3] = 68, [0][0][RTW89_ETSI][3] = 38, [0][0][RTW89_MKK][3] = 40, @@ -34099,78 +35649,118 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][3] = 38, [0][0][RTW89_CN][3] = 32, [0][0][RTW89_UK][3] = 38, + [0][0][RTW89_MEXICO][3] = 68, + [0][0][RTW89_UKRAINE][3] = 38, + [0][0][RTW89_CHILE][3] = 50, + [0][0][RTW89_QATAR][3] = 38, [0][0][RTW89_FCC][4] = 68, [0][0][RTW89_ETSI][4] = 38, [0][0][RTW89_MKK][4] = 40, [0][0][RTW89_IC][4] = 68, - [0][0][RTW89_KCC][4] = 42, + [0][0][RTW89_KCC][4] = 44, [0][0][RTW89_ACMA][4] = 38, [0][0][RTW89_CN][4] = 32, [0][0][RTW89_UK][4] = 38, + [0][0][RTW89_MEXICO][4] = 68, + [0][0][RTW89_UKRAINE][4] = 38, + [0][0][RTW89_CHILE][4] = 50, + [0][0][RTW89_QATAR][4] = 38, [0][0][RTW89_FCC][5] = 78, [0][0][RTW89_ETSI][5] = 38, [0][0][RTW89_MKK][5] = 40, [0][0][RTW89_IC][5] = 78, - [0][0][RTW89_KCC][5] = 42, + [0][0][RTW89_KCC][5] = 44, [0][0][RTW89_ACMA][5] = 38, [0][0][RTW89_CN][5] = 32, [0][0][RTW89_UK][5] = 38, + [0][0][RTW89_MEXICO][5] = 78, + [0][0][RTW89_UKRAINE][5] = 38, + [0][0][RTW89_CHILE][5] = 78, + [0][0][RTW89_QATAR][5] = 38, [0][0][RTW89_FCC][6] = 54, [0][0][RTW89_ETSI][6] = 38, [0][0][RTW89_MKK][6] = 40, [0][0][RTW89_IC][6] = 54, - [0][0][RTW89_KCC][6] = 42, + [0][0][RTW89_KCC][6] = 44, [0][0][RTW89_ACMA][6] = 38, [0][0][RTW89_CN][6] = 32, [0][0][RTW89_UK][6] = 38, + [0][0][RTW89_MEXICO][6] = 54, + [0][0][RTW89_UKRAINE][6] = 38, + [0][0][RTW89_CHILE][6] = 36, + [0][0][RTW89_QATAR][6] = 38, [0][0][RTW89_FCC][7] = 54, [0][0][RTW89_ETSI][7] = 38, [0][0][RTW89_MKK][7] = 40, [0][0][RTW89_IC][7] = 54, - [0][0][RTW89_KCC][7] = 42, + [0][0][RTW89_KCC][7] = 44, [0][0][RTW89_ACMA][7] = 38, [0][0][RTW89_CN][7] = 32, [0][0][RTW89_UK][7] = 38, + [0][0][RTW89_MEXICO][7] = 54, + [0][0][RTW89_UKRAINE][7] = 38, + [0][0][RTW89_CHILE][7] = 36, + [0][0][RTW89_QATAR][7] = 38, [0][0][RTW89_FCC][8] = 50, [0][0][RTW89_ETSI][8] = 38, [0][0][RTW89_MKK][8] = 40, [0][0][RTW89_IC][8] = 50, - [0][0][RTW89_KCC][8] = 42, + [0][0][RTW89_KCC][8] = 44, [0][0][RTW89_ACMA][8] = 38, [0][0][RTW89_CN][8] = 32, [0][0][RTW89_UK][8] = 38, + [0][0][RTW89_MEXICO][8] = 50, + [0][0][RTW89_UKRAINE][8] = 38, + [0][0][RTW89_CHILE][8] = 36, + [0][0][RTW89_QATAR][8] = 38, [0][0][RTW89_FCC][9] = 46, [0][0][RTW89_ETSI][9] = 38, [0][0][RTW89_MKK][9] = 40, [0][0][RTW89_IC][9] = 46, - [0][0][RTW89_KCC][9] = 40, + [0][0][RTW89_KCC][9] = 42, [0][0][RTW89_ACMA][9] = 38, [0][0][RTW89_CN][9] = 32, [0][0][RTW89_UK][9] = 38, + [0][0][RTW89_MEXICO][9] = 46, + [0][0][RTW89_UKRAINE][9] = 38, + [0][0][RTW89_CHILE][9] = 36, + [0][0][RTW89_QATAR][9] = 38, [0][0][RTW89_FCC][10] = 46, [0][0][RTW89_ETSI][10] = 38, [0][0][RTW89_MKK][10] = 40, [0][0][RTW89_IC][10] = 46, - [0][0][RTW89_KCC][10] = 40, + [0][0][RTW89_KCC][10] = 42, [0][0][RTW89_ACMA][10] = 38, [0][0][RTW89_CN][10] = 32, [0][0][RTW89_UK][10] = 38, + [0][0][RTW89_MEXICO][10] = 46, + [0][0][RTW89_UKRAINE][10] = 38, + [0][0][RTW89_CHILE][10] = 46, + [0][0][RTW89_QATAR][10] = 38, [0][0][RTW89_FCC][11] = 26, [0][0][RTW89_ETSI][11] = 38, [0][0][RTW89_MKK][11] = 40, [0][0][RTW89_IC][11] = 26, - [0][0][RTW89_KCC][11] = 40, + [0][0][RTW89_KCC][11] = 42, [0][0][RTW89_ACMA][11] = 38, [0][0][RTW89_CN][11] = 32, [0][0][RTW89_UK][11] = 38, + [0][0][RTW89_MEXICO][11] = 26, + [0][0][RTW89_UKRAINE][11] = 38, + [0][0][RTW89_CHILE][11] = 26, + [0][0][RTW89_QATAR][11] = 38, [0][0][RTW89_FCC][12] = -20, [0][0][RTW89_ETSI][12] = 34, [0][0][RTW89_MKK][12] = 36, [0][0][RTW89_IC][12] = -20, - [0][0][RTW89_KCC][12] = 40, + [0][0][RTW89_KCC][12] = 42, [0][0][RTW89_ACMA][12] = 34, [0][0][RTW89_CN][12] = 32, [0][0][RTW89_UK][12] = 34, + [0][0][RTW89_MEXICO][12] = -20, + [0][0][RTW89_UKRAINE][12] = 34, + [0][0][RTW89_CHILE][12] = -20, + [0][0][RTW89_QATAR][12] = 34, [0][0][RTW89_FCC][13] = 127, [0][0][RTW89_ETSI][13] = 127, [0][0][RTW89_MKK][13] = 127, @@ -34179,6 +35769,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][13] = 127, [0][0][RTW89_CN][13] = 127, [0][0][RTW89_UK][13] = 127, + [0][0][RTW89_MEXICO][13] = 127, + [0][0][RTW89_UKRAINE][13] = 127, + [0][0][RTW89_CHILE][13] = 127, + [0][0][RTW89_QATAR][13] = 127, [0][1][RTW89_FCC][0] = 56, [0][1][RTW89_ETSI][0] = 22, [0][1][RTW89_MKK][0] = 24, @@ -34187,6 +35781,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][0] = 22, [0][1][RTW89_CN][0] = 20, [0][1][RTW89_UK][0] = 22, + [0][1][RTW89_MEXICO][0] = 56, + [0][1][RTW89_UKRAINE][0] = 22, + [0][1][RTW89_CHILE][0] = 56, + [0][1][RTW89_QATAR][0] = 22, [0][1][RTW89_FCC][1] = 56, [0][1][RTW89_ETSI][1] = 24, [0][1][RTW89_MKK][1] = 30, @@ -34195,6 +35793,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][1] = 24, [0][1][RTW89_CN][1] = 22, [0][1][RTW89_UK][1] = 24, + [0][1][RTW89_MEXICO][1] = 56, + [0][1][RTW89_UKRAINE][1] = 24, + [0][1][RTW89_CHILE][1] = 40, + [0][1][RTW89_QATAR][1] = 24, [0][1][RTW89_FCC][2] = 60, [0][1][RTW89_ETSI][2] = 24, [0][1][RTW89_MKK][2] = 30, @@ -34203,6 +35805,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][2] = 24, [0][1][RTW89_CN][2] = 22, [0][1][RTW89_UK][2] = 24, + [0][1][RTW89_MEXICO][2] = 60, + [0][1][RTW89_UKRAINE][2] = 24, + [0][1][RTW89_CHILE][2] = 40, + [0][1][RTW89_QATAR][2] = 24, [0][1][RTW89_FCC][3] = 64, [0][1][RTW89_ETSI][3] = 24, [0][1][RTW89_MKK][3] = 30, @@ -34211,78 +35817,118 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][3] = 24, [0][1][RTW89_CN][3] = 22, [0][1][RTW89_UK][3] = 24, + [0][1][RTW89_MEXICO][3] = 64, + [0][1][RTW89_UKRAINE][3] = 24, + [0][1][RTW89_CHILE][3] = 40, + [0][1][RTW89_QATAR][3] = 24, [0][1][RTW89_FCC][4] = 68, [0][1][RTW89_ETSI][4] = 24, [0][1][RTW89_MKK][4] = 30, [0][1][RTW89_IC][4] = 68, - [0][1][RTW89_KCC][4] = 28, + [0][1][RTW89_KCC][4] = 34, [0][1][RTW89_ACMA][4] = 24, [0][1][RTW89_CN][4] = 22, [0][1][RTW89_UK][4] = 24, + [0][1][RTW89_MEXICO][4] = 68, + [0][1][RTW89_UKRAINE][4] = 24, + [0][1][RTW89_CHILE][4] = 40, + [0][1][RTW89_QATAR][4] = 24, [0][1][RTW89_FCC][5] = 76, [0][1][RTW89_ETSI][5] = 24, [0][1][RTW89_MKK][5] = 30, [0][1][RTW89_IC][5] = 76, - [0][1][RTW89_KCC][5] = 28, + [0][1][RTW89_KCC][5] = 34, [0][1][RTW89_ACMA][5] = 24, [0][1][RTW89_CN][5] = 22, [0][1][RTW89_UK][5] = 24, + [0][1][RTW89_MEXICO][5] = 76, + [0][1][RTW89_UKRAINE][5] = 24, + [0][1][RTW89_CHILE][5] = 76, + [0][1][RTW89_QATAR][5] = 24, [0][1][RTW89_FCC][6] = 54, [0][1][RTW89_ETSI][6] = 24, [0][1][RTW89_MKK][6] = 30, [0][1][RTW89_IC][6] = 54, - [0][1][RTW89_KCC][6] = 28, + [0][1][RTW89_KCC][6] = 34, [0][1][RTW89_ACMA][6] = 24, [0][1][RTW89_CN][6] = 22, [0][1][RTW89_UK][6] = 24, + [0][1][RTW89_MEXICO][6] = 54, + [0][1][RTW89_UKRAINE][6] = 24, + [0][1][RTW89_CHILE][6] = 26, + [0][1][RTW89_QATAR][6] = 24, [0][1][RTW89_FCC][7] = 50, [0][1][RTW89_ETSI][7] = 24, [0][1][RTW89_MKK][7] = 30, [0][1][RTW89_IC][7] = 50, - [0][1][RTW89_KCC][7] = 28, + [0][1][RTW89_KCC][7] = 34, [0][1][RTW89_ACMA][7] = 24, [0][1][RTW89_CN][7] = 22, [0][1][RTW89_UK][7] = 24, + [0][1][RTW89_MEXICO][7] = 50, + [0][1][RTW89_UKRAINE][7] = 24, + [0][1][RTW89_CHILE][7] = 26, + [0][1][RTW89_QATAR][7] = 24, [0][1][RTW89_FCC][8] = 46, [0][1][RTW89_ETSI][8] = 24, [0][1][RTW89_MKK][8] = 30, [0][1][RTW89_IC][8] = 46, - [0][1][RTW89_KCC][8] = 28, + [0][1][RTW89_KCC][8] = 34, [0][1][RTW89_ACMA][8] = 24, [0][1][RTW89_CN][8] = 22, [0][1][RTW89_UK][8] = 24, + [0][1][RTW89_MEXICO][8] = 46, + [0][1][RTW89_UKRAINE][8] = 24, + [0][1][RTW89_CHILE][8] = 26, + [0][1][RTW89_QATAR][8] = 24, [0][1][RTW89_FCC][9] = 42, [0][1][RTW89_ETSI][9] = 24, [0][1][RTW89_MKK][9] = 30, [0][1][RTW89_IC][9] = 42, - [0][1][RTW89_KCC][9] = 28, + [0][1][RTW89_KCC][9] = 32, [0][1][RTW89_ACMA][9] = 24, [0][1][RTW89_CN][9] = 22, [0][1][RTW89_UK][9] = 24, + [0][1][RTW89_MEXICO][9] = 42, + [0][1][RTW89_UKRAINE][9] = 24, + [0][1][RTW89_CHILE][9] = 26, + [0][1][RTW89_QATAR][9] = 24, [0][1][RTW89_FCC][10] = 42, [0][1][RTW89_ETSI][10] = 24, [0][1][RTW89_MKK][10] = 30, [0][1][RTW89_IC][10] = 42, - [0][1][RTW89_KCC][10] = 28, + [0][1][RTW89_KCC][10] = 32, [0][1][RTW89_ACMA][10] = 24, [0][1][RTW89_CN][10] = 22, [0][1][RTW89_UK][10] = 24, + [0][1][RTW89_MEXICO][10] = 42, + [0][1][RTW89_UKRAINE][10] = 24, + [0][1][RTW89_CHILE][10] = 42, + [0][1][RTW89_QATAR][10] = 24, [0][1][RTW89_FCC][11] = 22, [0][1][RTW89_ETSI][11] = 24, [0][1][RTW89_MKK][11] = 30, [0][1][RTW89_IC][11] = 22, - [0][1][RTW89_KCC][11] = 28, + [0][1][RTW89_KCC][11] = 32, [0][1][RTW89_ACMA][11] = 24, [0][1][RTW89_CN][11] = 22, [0][1][RTW89_UK][11] = 24, + [0][1][RTW89_MEXICO][11] = 22, + [0][1][RTW89_UKRAINE][11] = 24, + [0][1][RTW89_CHILE][11] = 22, + [0][1][RTW89_QATAR][11] = 24, [0][1][RTW89_FCC][12] = -30, [0][1][RTW89_ETSI][12] = 20, [0][1][RTW89_MKK][12] = 24, [0][1][RTW89_IC][12] = -30, - [0][1][RTW89_KCC][12] = 28, + [0][1][RTW89_KCC][12] = 32, [0][1][RTW89_ACMA][12] = 20, [0][1][RTW89_CN][12] = 20, [0][1][RTW89_UK][12] = 20, + [0][1][RTW89_MEXICO][12] = -30, + [0][1][RTW89_UKRAINE][12] = 20, + [0][1][RTW89_CHILE][12] = -30, + [0][1][RTW89_QATAR][12] = 20, [0][1][RTW89_FCC][13] = 127, [0][1][RTW89_ETSI][13] = 127, [0][1][RTW89_MKK][13] = 127, @@ -34291,110 +35937,166 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][13] = 127, [0][1][RTW89_CN][13] = 127, [0][1][RTW89_UK][13] = 127, + [0][1][RTW89_MEXICO][13] = 127, + [0][1][RTW89_UKRAINE][13] = 127, + [0][1][RTW89_CHILE][13] = 127, + [0][1][RTW89_QATAR][13] = 127, [1][0][RTW89_FCC][0] = 66, [1][0][RTW89_ETSI][0] = 46, [1][0][RTW89_MKK][0] = 48, [1][0][RTW89_IC][0] = 66, - [1][0][RTW89_KCC][0] = 50, + [1][0][RTW89_KCC][0] = 54, [1][0][RTW89_ACMA][0] = 46, [1][0][RTW89_CN][0] = 42, [1][0][RTW89_UK][0] = 46, + [1][0][RTW89_MEXICO][0] = 66, + [1][0][RTW89_UKRAINE][0] = 46, + [1][0][RTW89_CHILE][0] = 66, + [1][0][RTW89_QATAR][0] = 46, [1][0][RTW89_FCC][1] = 66, [1][0][RTW89_ETSI][1] = 46, [1][0][RTW89_MKK][1] = 48, [1][0][RTW89_IC][1] = 66, - [1][0][RTW89_KCC][1] = 50, + [1][0][RTW89_KCC][1] = 54, [1][0][RTW89_ACMA][1] = 46, [1][0][RTW89_CN][1] = 44, [1][0][RTW89_UK][1] = 46, + [1][0][RTW89_MEXICO][1] = 66, + [1][0][RTW89_UKRAINE][1] = 46, + [1][0][RTW89_CHILE][1] = 54, + [1][0][RTW89_QATAR][1] = 46, [1][0][RTW89_FCC][2] = 70, [1][0][RTW89_ETSI][2] = 46, [1][0][RTW89_MKK][2] = 48, [1][0][RTW89_IC][2] = 70, - [1][0][RTW89_KCC][2] = 50, + [1][0][RTW89_KCC][2] = 54, [1][0][RTW89_ACMA][2] = 46, [1][0][RTW89_CN][2] = 44, [1][0][RTW89_UK][2] = 46, + [1][0][RTW89_MEXICO][2] = 70, + [1][0][RTW89_UKRAINE][2] = 46, + [1][0][RTW89_CHILE][2] = 54, + [1][0][RTW89_QATAR][2] = 46, [1][0][RTW89_FCC][3] = 72, [1][0][RTW89_ETSI][3] = 46, [1][0][RTW89_MKK][3] = 48, [1][0][RTW89_IC][3] = 72, - [1][0][RTW89_KCC][3] = 50, + [1][0][RTW89_KCC][3] = 54, [1][0][RTW89_ACMA][3] = 46, [1][0][RTW89_CN][3] = 44, [1][0][RTW89_UK][3] = 46, + [1][0][RTW89_MEXICO][3] = 72, + [1][0][RTW89_UKRAINE][3] = 46, + [1][0][RTW89_CHILE][3] = 54, + [1][0][RTW89_QATAR][3] = 46, [1][0][RTW89_FCC][4] = 72, [1][0][RTW89_ETSI][4] = 46, [1][0][RTW89_MKK][4] = 48, [1][0][RTW89_IC][4] = 72, - [1][0][RTW89_KCC][4] = 50, + [1][0][RTW89_KCC][4] = 56, [1][0][RTW89_ACMA][4] = 46, [1][0][RTW89_CN][4] = 44, [1][0][RTW89_UK][4] = 46, + [1][0][RTW89_MEXICO][4] = 72, + [1][0][RTW89_UKRAINE][4] = 46, + [1][0][RTW89_CHILE][4] = 54, + [1][0][RTW89_QATAR][4] = 46, [1][0][RTW89_FCC][5] = 82, [1][0][RTW89_ETSI][5] = 46, [1][0][RTW89_MKK][5] = 48, [1][0][RTW89_IC][5] = 82, - [1][0][RTW89_KCC][5] = 50, + [1][0][RTW89_KCC][5] = 56, [1][0][RTW89_ACMA][5] = 46, [1][0][RTW89_CN][5] = 44, [1][0][RTW89_UK][5] = 46, + [1][0][RTW89_MEXICO][5] = 82, + [1][0][RTW89_UKRAINE][5] = 46, + [1][0][RTW89_CHILE][5] = 82, + [1][0][RTW89_QATAR][5] = 46, [1][0][RTW89_FCC][6] = 58, [1][0][RTW89_ETSI][6] = 44, [1][0][RTW89_MKK][6] = 48, [1][0][RTW89_IC][6] = 58, - [1][0][RTW89_KCC][6] = 50, + [1][0][RTW89_KCC][6] = 56, [1][0][RTW89_ACMA][6] = 44, [1][0][RTW89_CN][6] = 44, [1][0][RTW89_UK][6] = 44, + [1][0][RTW89_MEXICO][6] = 58, + [1][0][RTW89_UKRAINE][6] = 44, + [1][0][RTW89_CHILE][6] = 40, + [1][0][RTW89_QATAR][6] = 44, [1][0][RTW89_FCC][7] = 58, [1][0][RTW89_ETSI][7] = 46, [1][0][RTW89_MKK][7] = 48, [1][0][RTW89_IC][7] = 58, - [1][0][RTW89_KCC][7] = 50, + [1][0][RTW89_KCC][7] = 56, [1][0][RTW89_ACMA][7] = 46, [1][0][RTW89_CN][7] = 44, [1][0][RTW89_UK][7] = 46, + [1][0][RTW89_MEXICO][7] = 58, + [1][0][RTW89_UKRAINE][7] = 46, + [1][0][RTW89_CHILE][7] = 40, + [1][0][RTW89_QATAR][7] = 46, [1][0][RTW89_FCC][8] = 58, [1][0][RTW89_ETSI][8] = 46, [1][0][RTW89_MKK][8] = 48, [1][0][RTW89_IC][8] = 58, - [1][0][RTW89_KCC][8] = 50, + [1][0][RTW89_KCC][8] = 56, [1][0][RTW89_ACMA][8] = 46, [1][0][RTW89_CN][8] = 44, [1][0][RTW89_UK][8] = 46, + [1][0][RTW89_MEXICO][8] = 58, + [1][0][RTW89_UKRAINE][8] = 46, + [1][0][RTW89_CHILE][8] = 40, + [1][0][RTW89_QATAR][8] = 46, [1][0][RTW89_FCC][9] = 54, [1][0][RTW89_ETSI][9] = 46, [1][0][RTW89_MKK][9] = 48, [1][0][RTW89_IC][9] = 54, - [1][0][RTW89_KCC][9] = 50, + [1][0][RTW89_KCC][9] = 56, [1][0][RTW89_ACMA][9] = 46, [1][0][RTW89_CN][9] = 44, [1][0][RTW89_UK][9] = 46, + [1][0][RTW89_MEXICO][9] = 54, + [1][0][RTW89_UKRAINE][9] = 46, + [1][0][RTW89_CHILE][9] = 40, + [1][0][RTW89_QATAR][9] = 46, [1][0][RTW89_FCC][10] = 54, [1][0][RTW89_ETSI][10] = 46, [1][0][RTW89_MKK][10] = 48, [1][0][RTW89_IC][10] = 54, - [1][0][RTW89_KCC][10] = 50, + [1][0][RTW89_KCC][10] = 56, [1][0][RTW89_ACMA][10] = 46, [1][0][RTW89_CN][10] = 44, [1][0][RTW89_UK][10] = 46, + [1][0][RTW89_MEXICO][10] = 54, + [1][0][RTW89_UKRAINE][10] = 46, + [1][0][RTW89_CHILE][10] = 54, + [1][0][RTW89_QATAR][10] = 46, [1][0][RTW89_FCC][11] = 36, [1][0][RTW89_ETSI][11] = 46, [1][0][RTW89_MKK][11] = 48, [1][0][RTW89_IC][11] = 36, - [1][0][RTW89_KCC][11] = 50, + [1][0][RTW89_KCC][11] = 56, [1][0][RTW89_ACMA][11] = 46, [1][0][RTW89_CN][11] = 44, [1][0][RTW89_UK][11] = 46, + [1][0][RTW89_MEXICO][11] = 36, + [1][0][RTW89_UKRAINE][11] = 46, + [1][0][RTW89_CHILE][11] = 36, + [1][0][RTW89_QATAR][11] = 46, [1][0][RTW89_FCC][12] = 4, [1][0][RTW89_ETSI][12] = 46, [1][0][RTW89_MKK][12] = 46, [1][0][RTW89_IC][12] = 4, - [1][0][RTW89_KCC][12] = 50, + [1][0][RTW89_KCC][12] = 56, [1][0][RTW89_ACMA][12] = 46, [1][0][RTW89_CN][12] = 42, [1][0][RTW89_UK][12] = 46, + [1][0][RTW89_MEXICO][12] = 4, + [1][0][RTW89_UKRAINE][12] = 46, + [1][0][RTW89_CHILE][12] = 4, + [1][0][RTW89_QATAR][12] = 46, [1][0][RTW89_FCC][13] = 127, [1][0][RTW89_ETSI][13] = 127, [1][0][RTW89_MKK][13] = 127, @@ -34403,110 +36105,166 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][13] = 127, [1][0][RTW89_CN][13] = 127, [1][0][RTW89_UK][13] = 127, + [1][0][RTW89_MEXICO][13] = 127, + [1][0][RTW89_UKRAINE][13] = 127, + [1][0][RTW89_CHILE][13] = 127, + [1][0][RTW89_QATAR][13] = 127, [1][1][RTW89_FCC][0] = 58, [1][1][RTW89_ETSI][0] = 32, [1][1][RTW89_MKK][0] = 34, [1][1][RTW89_IC][0] = 58, - [1][1][RTW89_KCC][0] = 38, + [1][1][RTW89_KCC][0] = 42, [1][1][RTW89_ACMA][0] = 32, [1][1][RTW89_CN][0] = 32, [1][1][RTW89_UK][0] = 32, + [1][1][RTW89_MEXICO][0] = 58, + [1][1][RTW89_UKRAINE][0] = 32, + [1][1][RTW89_CHILE][0] = 58, + [1][1][RTW89_QATAR][0] = 32, [1][1][RTW89_FCC][1] = 58, [1][1][RTW89_ETSI][1] = 34, [1][1][RTW89_MKK][1] = 34, [1][1][RTW89_IC][1] = 58, - [1][1][RTW89_KCC][1] = 38, + [1][1][RTW89_KCC][1] = 42, [1][1][RTW89_ACMA][1] = 34, [1][1][RTW89_CN][1] = 32, [1][1][RTW89_UK][1] = 34, + [1][1][RTW89_MEXICO][1] = 58, + [1][1][RTW89_UKRAINE][1] = 34, + [1][1][RTW89_CHILE][1] = 40, + [1][1][RTW89_QATAR][1] = 34, [1][1][RTW89_FCC][2] = 62, [1][1][RTW89_ETSI][2] = 34, [1][1][RTW89_MKK][2] = 34, [1][1][RTW89_IC][2] = 62, - [1][1][RTW89_KCC][2] = 38, + [1][1][RTW89_KCC][2] = 42, [1][1][RTW89_ACMA][2] = 34, [1][1][RTW89_CN][2] = 32, [1][1][RTW89_UK][2] = 34, + [1][1][RTW89_MEXICO][2] = 62, + [1][1][RTW89_UKRAINE][2] = 34, + [1][1][RTW89_CHILE][2] = 40, + [1][1][RTW89_QATAR][2] = 34, [1][1][RTW89_FCC][3] = 66, [1][1][RTW89_ETSI][3] = 34, [1][1][RTW89_MKK][3] = 34, [1][1][RTW89_IC][3] = 66, - [1][1][RTW89_KCC][3] = 38, + [1][1][RTW89_KCC][3] = 42, [1][1][RTW89_ACMA][3] = 34, [1][1][RTW89_CN][3] = 32, [1][1][RTW89_UK][3] = 34, + [1][1][RTW89_MEXICO][3] = 66, + [1][1][RTW89_UKRAINE][3] = 34, + [1][1][RTW89_CHILE][3] = 40, + [1][1][RTW89_QATAR][3] = 34, [1][1][RTW89_FCC][4] = 70, [1][1][RTW89_ETSI][4] = 34, [1][1][RTW89_MKK][4] = 34, [1][1][RTW89_IC][4] = 70, - [1][1][RTW89_KCC][4] = 38, + [1][1][RTW89_KCC][4] = 44, [1][1][RTW89_ACMA][4] = 34, [1][1][RTW89_CN][4] = 32, [1][1][RTW89_UK][4] = 34, + [1][1][RTW89_MEXICO][4] = 70, + [1][1][RTW89_UKRAINE][4] = 34, + [1][1][RTW89_CHILE][4] = 40, + [1][1][RTW89_QATAR][4] = 34, [1][1][RTW89_FCC][5] = 82, [1][1][RTW89_ETSI][5] = 34, [1][1][RTW89_MKK][5] = 34, [1][1][RTW89_IC][5] = 82, - [1][1][RTW89_KCC][5] = 38, + [1][1][RTW89_KCC][5] = 44, [1][1][RTW89_ACMA][5] = 34, [1][1][RTW89_CN][5] = 32, [1][1][RTW89_UK][5] = 34, + [1][1][RTW89_MEXICO][5] = 82, + [1][1][RTW89_UKRAINE][5] = 34, + [1][1][RTW89_CHILE][5] = 78, + [1][1][RTW89_QATAR][5] = 34, [1][1][RTW89_FCC][6] = 60, [1][1][RTW89_ETSI][6] = 34, [1][1][RTW89_MKK][6] = 34, [1][1][RTW89_IC][6] = 60, - [1][1][RTW89_KCC][6] = 38, + [1][1][RTW89_KCC][6] = 44, [1][1][RTW89_ACMA][6] = 34, [1][1][RTW89_CN][6] = 32, [1][1][RTW89_UK][6] = 34, + [1][1][RTW89_MEXICO][6] = 60, + [1][1][RTW89_UKRAINE][6] = 34, + [1][1][RTW89_CHILE][6] = 30, + [1][1][RTW89_QATAR][6] = 34, [1][1][RTW89_FCC][7] = 56, [1][1][RTW89_ETSI][7] = 34, [1][1][RTW89_MKK][7] = 34, [1][1][RTW89_IC][7] = 56, - [1][1][RTW89_KCC][7] = 38, + [1][1][RTW89_KCC][7] = 44, [1][1][RTW89_ACMA][7] = 34, [1][1][RTW89_CN][7] = 32, [1][1][RTW89_UK][7] = 34, + [1][1][RTW89_MEXICO][7] = 56, + [1][1][RTW89_UKRAINE][7] = 34, + [1][1][RTW89_CHILE][7] = 30, + [1][1][RTW89_QATAR][7] = 34, [1][1][RTW89_FCC][8] = 52, [1][1][RTW89_ETSI][8] = 34, [1][1][RTW89_MKK][8] = 34, [1][1][RTW89_IC][8] = 52, - [1][1][RTW89_KCC][8] = 38, + [1][1][RTW89_KCC][8] = 44, [1][1][RTW89_ACMA][8] = 34, [1][1][RTW89_CN][8] = 32, [1][1][RTW89_UK][8] = 34, + [1][1][RTW89_MEXICO][8] = 52, + [1][1][RTW89_UKRAINE][8] = 34, + [1][1][RTW89_CHILE][8] = 30, + [1][1][RTW89_QATAR][8] = 34, [1][1][RTW89_FCC][9] = 48, [1][1][RTW89_ETSI][9] = 34, [1][1][RTW89_MKK][9] = 34, [1][1][RTW89_IC][9] = 48, - [1][1][RTW89_KCC][9] = 38, + [1][1][RTW89_KCC][9] = 44, [1][1][RTW89_ACMA][9] = 34, [1][1][RTW89_CN][9] = 32, [1][1][RTW89_UK][9] = 34, + [1][1][RTW89_MEXICO][9] = 48, + [1][1][RTW89_UKRAINE][9] = 34, + [1][1][RTW89_CHILE][9] = 30, + [1][1][RTW89_QATAR][9] = 34, [1][1][RTW89_FCC][10] = 48, [1][1][RTW89_ETSI][10] = 34, [1][1][RTW89_MKK][10] = 34, [1][1][RTW89_IC][10] = 48, - [1][1][RTW89_KCC][10] = 38, + [1][1][RTW89_KCC][10] = 44, [1][1][RTW89_ACMA][10] = 34, [1][1][RTW89_CN][10] = 32, [1][1][RTW89_UK][10] = 34, + [1][1][RTW89_MEXICO][10] = 48, + [1][1][RTW89_UKRAINE][10] = 34, + [1][1][RTW89_CHILE][10] = 48, + [1][1][RTW89_QATAR][10] = 34, [1][1][RTW89_FCC][11] = 30, [1][1][RTW89_ETSI][11] = 34, [1][1][RTW89_MKK][11] = 34, [1][1][RTW89_IC][11] = 30, - [1][1][RTW89_KCC][11] = 38, + [1][1][RTW89_KCC][11] = 44, [1][1][RTW89_ACMA][11] = 34, [1][1][RTW89_CN][11] = 32, [1][1][RTW89_UK][11] = 34, + [1][1][RTW89_MEXICO][11] = 30, + [1][1][RTW89_UKRAINE][11] = 34, + [1][1][RTW89_CHILE][11] = 30, + [1][1][RTW89_QATAR][11] = 34, [1][1][RTW89_FCC][12] = -6, [1][1][RTW89_ETSI][12] = 34, [1][1][RTW89_MKK][12] = 34, [1][1][RTW89_IC][12] = -6, - [1][1][RTW89_KCC][12] = 38, + [1][1][RTW89_KCC][12] = 44, [1][1][RTW89_ACMA][12] = 34, [1][1][RTW89_CN][12] = 32, [1][1][RTW89_UK][12] = 34, + [1][1][RTW89_MEXICO][12] = -6, + [1][1][RTW89_UKRAINE][12] = 34, + [1][1][RTW89_CHILE][12] = -6, + [1][1][RTW89_QATAR][12] = 34, [1][1][RTW89_FCC][13] = 127, [1][1][RTW89_ETSI][13] = 127, [1][1][RTW89_MKK][13] = 127, @@ -34515,110 +36273,166 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_ACMA][13] = 127, [1][1][RTW89_CN][13] = 127, [1][1][RTW89_UK][13] = 127, + [1][1][RTW89_MEXICO][13] = 127, + [1][1][RTW89_UKRAINE][13] = 127, + [1][1][RTW89_CHILE][13] = 127, + [1][1][RTW89_QATAR][13] = 127, [2][0][RTW89_FCC][0] = 70, [2][0][RTW89_ETSI][0] = 58, [2][0][RTW89_MKK][0] = 58, [2][0][RTW89_IC][0] = 70, - [2][0][RTW89_KCC][0] = 64, + [2][0][RTW89_KCC][0] = 60, [2][0][RTW89_ACMA][0] = 58, [2][0][RTW89_CN][0] = 56, [2][0][RTW89_UK][0] = 58, + [2][0][RTW89_MEXICO][0] = 70, + [2][0][RTW89_UKRAINE][0] = 58, + [2][0][RTW89_CHILE][0] = 70, + [2][0][RTW89_QATAR][0] = 58, [2][0][RTW89_FCC][1] = 70, [2][0][RTW89_ETSI][1] = 58, [2][0][RTW89_MKK][1] = 58, [2][0][RTW89_IC][1] = 70, - [2][0][RTW89_KCC][1] = 64, + [2][0][RTW89_KCC][1] = 60, [2][0][RTW89_ACMA][1] = 58, [2][0][RTW89_CN][1] = 56, [2][0][RTW89_UK][1] = 58, + [2][0][RTW89_MEXICO][1] = 70, + [2][0][RTW89_UKRAINE][1] = 58, + [2][0][RTW89_CHILE][1] = 54, + [2][0][RTW89_QATAR][1] = 58, [2][0][RTW89_FCC][2] = 72, [2][0][RTW89_ETSI][2] = 58, [2][0][RTW89_MKK][2] = 58, [2][0][RTW89_IC][2] = 72, - [2][0][RTW89_KCC][2] = 64, + [2][0][RTW89_KCC][2] = 60, [2][0][RTW89_ACMA][2] = 58, [2][0][RTW89_CN][2] = 56, [2][0][RTW89_UK][2] = 58, + [2][0][RTW89_MEXICO][2] = 72, + [2][0][RTW89_UKRAINE][2] = 58, + [2][0][RTW89_CHILE][2] = 54, + [2][0][RTW89_QATAR][2] = 58, [2][0][RTW89_FCC][3] = 72, [2][0][RTW89_ETSI][3] = 58, [2][0][RTW89_MKK][3] = 58, [2][0][RTW89_IC][3] = 72, - [2][0][RTW89_KCC][3] = 64, + [2][0][RTW89_KCC][3] = 60, [2][0][RTW89_ACMA][3] = 58, [2][0][RTW89_CN][3] = 56, [2][0][RTW89_UK][3] = 58, + [2][0][RTW89_MEXICO][3] = 72, + [2][0][RTW89_UKRAINE][3] = 58, + [2][0][RTW89_CHILE][3] = 54, + [2][0][RTW89_QATAR][3] = 58, [2][0][RTW89_FCC][4] = 72, [2][0][RTW89_ETSI][4] = 58, [2][0][RTW89_MKK][4] = 58, [2][0][RTW89_IC][4] = 72, - [2][0][RTW89_KCC][4] = 64, + [2][0][RTW89_KCC][4] = 60, [2][0][RTW89_ACMA][4] = 58, [2][0][RTW89_CN][4] = 56, [2][0][RTW89_UK][4] = 58, + [2][0][RTW89_MEXICO][4] = 72, + [2][0][RTW89_UKRAINE][4] = 58, + [2][0][RTW89_CHILE][4] = 54, + [2][0][RTW89_QATAR][4] = 58, [2][0][RTW89_FCC][5] = 82, [2][0][RTW89_ETSI][5] = 58, [2][0][RTW89_MKK][5] = 58, [2][0][RTW89_IC][5] = 82, - [2][0][RTW89_KCC][5] = 64, + [2][0][RTW89_KCC][5] = 60, [2][0][RTW89_ACMA][5] = 58, [2][0][RTW89_CN][5] = 56, [2][0][RTW89_UK][5] = 58, + [2][0][RTW89_MEXICO][5] = 82, + [2][0][RTW89_UKRAINE][5] = 58, + [2][0][RTW89_CHILE][5] = 82, + [2][0][RTW89_QATAR][5] = 58, [2][0][RTW89_FCC][6] = 66, [2][0][RTW89_ETSI][6] = 56, [2][0][RTW89_MKK][6] = 58, [2][0][RTW89_IC][6] = 66, - [2][0][RTW89_KCC][6] = 64, + [2][0][RTW89_KCC][6] = 60, [2][0][RTW89_ACMA][6] = 56, [2][0][RTW89_CN][6] = 56, [2][0][RTW89_UK][6] = 56, + [2][0][RTW89_MEXICO][6] = 66, + [2][0][RTW89_UKRAINE][6] = 56, + [2][0][RTW89_CHILE][6] = 48, + [2][0][RTW89_QATAR][6] = 56, [2][0][RTW89_FCC][7] = 66, [2][0][RTW89_ETSI][7] = 58, [2][0][RTW89_MKK][7] = 58, [2][0][RTW89_IC][7] = 66, - [2][0][RTW89_KCC][7] = 64, + [2][0][RTW89_KCC][7] = 60, [2][0][RTW89_ACMA][7] = 58, [2][0][RTW89_CN][7] = 56, [2][0][RTW89_UK][7] = 58, + [2][0][RTW89_MEXICO][7] = 66, + [2][0][RTW89_UKRAINE][7] = 58, + [2][0][RTW89_CHILE][7] = 48, + [2][0][RTW89_QATAR][7] = 58, [2][0][RTW89_FCC][8] = 66, [2][0][RTW89_ETSI][8] = 58, [2][0][RTW89_MKK][8] = 58, [2][0][RTW89_IC][8] = 66, - [2][0][RTW89_KCC][8] = 64, + [2][0][RTW89_KCC][8] = 60, [2][0][RTW89_ACMA][8] = 58, [2][0][RTW89_CN][8] = 56, [2][0][RTW89_UK][8] = 58, + [2][0][RTW89_MEXICO][8] = 66, + [2][0][RTW89_UKRAINE][8] = 58, + [2][0][RTW89_CHILE][8] = 48, + [2][0][RTW89_QATAR][8] = 58, [2][0][RTW89_FCC][9] = 64, [2][0][RTW89_ETSI][9] = 58, [2][0][RTW89_MKK][9] = 58, [2][0][RTW89_IC][9] = 64, - [2][0][RTW89_KCC][9] = 64, + [2][0][RTW89_KCC][9] = 60, [2][0][RTW89_ACMA][9] = 58, [2][0][RTW89_CN][9] = 56, [2][0][RTW89_UK][9] = 58, + [2][0][RTW89_MEXICO][9] = 64, + [2][0][RTW89_UKRAINE][9] = 58, + [2][0][RTW89_CHILE][9] = 48, + [2][0][RTW89_QATAR][9] = 58, [2][0][RTW89_FCC][10] = 64, [2][0][RTW89_ETSI][10] = 58, [2][0][RTW89_MKK][10] = 58, [2][0][RTW89_IC][10] = 64, - [2][0][RTW89_KCC][10] = 64, + [2][0][RTW89_KCC][10] = 60, [2][0][RTW89_ACMA][10] = 58, [2][0][RTW89_CN][10] = 56, [2][0][RTW89_UK][10] = 58, + [2][0][RTW89_MEXICO][10] = 64, + [2][0][RTW89_UKRAINE][10] = 58, + [2][0][RTW89_CHILE][10] = 64, + [2][0][RTW89_QATAR][10] = 58, [2][0][RTW89_FCC][11] = 48, [2][0][RTW89_ETSI][11] = 58, [2][0][RTW89_MKK][11] = 58, [2][0][RTW89_IC][11] = 48, - [2][0][RTW89_KCC][11] = 64, + [2][0][RTW89_KCC][11] = 60, [2][0][RTW89_ACMA][11] = 58, [2][0][RTW89_CN][11] = 56, [2][0][RTW89_UK][11] = 58, + [2][0][RTW89_MEXICO][11] = 48, + [2][0][RTW89_UKRAINE][11] = 58, + [2][0][RTW89_CHILE][11] = 48, + [2][0][RTW89_QATAR][11] = 58, [2][0][RTW89_FCC][12] = 16, [2][0][RTW89_ETSI][12] = 58, [2][0][RTW89_MKK][12] = 58, [2][0][RTW89_IC][12] = 16, - [2][0][RTW89_KCC][12] = 64, + [2][0][RTW89_KCC][12] = 60, [2][0][RTW89_ACMA][12] = 58, [2][0][RTW89_CN][12] = 56, [2][0][RTW89_UK][12] = 58, + [2][0][RTW89_MEXICO][12] = 16, + [2][0][RTW89_UKRAINE][12] = 58, + [2][0][RTW89_CHILE][12] = 16, + [2][0][RTW89_QATAR][12] = 58, [2][0][RTW89_FCC][13] = 127, [2][0][RTW89_ETSI][13] = 127, [2][0][RTW89_MKK][13] = 127, @@ -34627,110 +36441,166 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ACMA][13] = 127, [2][0][RTW89_CN][13] = 127, [2][0][RTW89_UK][13] = 127, + [2][0][RTW89_MEXICO][13] = 127, + [2][0][RTW89_UKRAINE][13] = 127, + [2][0][RTW89_CHILE][13] = 127, + [2][0][RTW89_QATAR][13] = 127, [2][1][RTW89_FCC][0] = 64, [2][1][RTW89_ETSI][0] = 46, [2][1][RTW89_MKK][0] = 46, [2][1][RTW89_IC][0] = 64, - [2][1][RTW89_KCC][0] = 52, + [2][1][RTW89_KCC][0] = 48, [2][1][RTW89_ACMA][0] = 46, [2][1][RTW89_CN][0] = 44, [2][1][RTW89_UK][0] = 46, + [2][1][RTW89_MEXICO][0] = 64, + [2][1][RTW89_UKRAINE][0] = 46, + [2][1][RTW89_CHILE][0] = 64, + [2][1][RTW89_QATAR][0] = 46, [2][1][RTW89_FCC][1] = 64, [2][1][RTW89_ETSI][1] = 46, [2][1][RTW89_MKK][1] = 46, [2][1][RTW89_IC][1] = 64, - [2][1][RTW89_KCC][1] = 52, + [2][1][RTW89_KCC][1] = 48, [2][1][RTW89_ACMA][1] = 46, [2][1][RTW89_CN][1] = 44, [2][1][RTW89_UK][1] = 46, + [2][1][RTW89_MEXICO][1] = 64, + [2][1][RTW89_UKRAINE][1] = 46, + [2][1][RTW89_CHILE][1] = 44, + [2][1][RTW89_QATAR][1] = 46, [2][1][RTW89_FCC][2] = 68, [2][1][RTW89_ETSI][2] = 46, [2][1][RTW89_MKK][2] = 46, [2][1][RTW89_IC][2] = 68, - [2][1][RTW89_KCC][2] = 52, + [2][1][RTW89_KCC][2] = 48, [2][1][RTW89_ACMA][2] = 46, [2][1][RTW89_CN][2] = 44, [2][1][RTW89_UK][2] = 46, + [2][1][RTW89_MEXICO][2] = 68, + [2][1][RTW89_UKRAINE][2] = 46, + [2][1][RTW89_CHILE][2] = 44, + [2][1][RTW89_QATAR][2] = 46, [2][1][RTW89_FCC][3] = 72, [2][1][RTW89_ETSI][3] = 46, [2][1][RTW89_MKK][3] = 46, [2][1][RTW89_IC][3] = 72, - [2][1][RTW89_KCC][3] = 52, + [2][1][RTW89_KCC][3] = 48, [2][1][RTW89_ACMA][3] = 46, [2][1][RTW89_CN][3] = 44, [2][1][RTW89_UK][3] = 46, + [2][1][RTW89_MEXICO][3] = 72, + [2][1][RTW89_UKRAINE][3] = 46, + [2][1][RTW89_CHILE][3] = 44, + [2][1][RTW89_QATAR][3] = 46, [2][1][RTW89_FCC][4] = 74, [2][1][RTW89_ETSI][4] = 46, [2][1][RTW89_MKK][4] = 46, [2][1][RTW89_IC][4] = 74, - [2][1][RTW89_KCC][4] = 50, + [2][1][RTW89_KCC][4] = 48, [2][1][RTW89_ACMA][4] = 46, [2][1][RTW89_CN][4] = 44, [2][1][RTW89_UK][4] = 46, + [2][1][RTW89_MEXICO][4] = 74, + [2][1][RTW89_UKRAINE][4] = 46, + [2][1][RTW89_CHILE][4] = 44, + [2][1][RTW89_QATAR][4] = 46, [2][1][RTW89_FCC][5] = 82, [2][1][RTW89_ETSI][5] = 46, [2][1][RTW89_MKK][5] = 46, [2][1][RTW89_IC][5] = 82, - [2][1][RTW89_KCC][5] = 50, + [2][1][RTW89_KCC][5] = 48, [2][1][RTW89_ACMA][5] = 46, [2][1][RTW89_CN][5] = 44, [2][1][RTW89_UK][5] = 46, + [2][1][RTW89_MEXICO][5] = 82, + [2][1][RTW89_UKRAINE][5] = 46, + [2][1][RTW89_CHILE][5] = 78, + [2][1][RTW89_QATAR][5] = 46, [2][1][RTW89_FCC][6] = 72, [2][1][RTW89_ETSI][6] = 44, [2][1][RTW89_MKK][6] = 46, [2][1][RTW89_IC][6] = 72, - [2][1][RTW89_KCC][6] = 50, + [2][1][RTW89_KCC][6] = 48, [2][1][RTW89_ACMA][6] = 44, [2][1][RTW89_CN][6] = 44, [2][1][RTW89_UK][6] = 44, + [2][1][RTW89_MEXICO][6] = 72, + [2][1][RTW89_UKRAINE][6] = 44, + [2][1][RTW89_CHILE][6] = 42, + [2][1][RTW89_QATAR][6] = 44, [2][1][RTW89_FCC][7] = 72, [2][1][RTW89_ETSI][7] = 46, [2][1][RTW89_MKK][7] = 46, [2][1][RTW89_IC][7] = 72, - [2][1][RTW89_KCC][7] = 50, + [2][1][RTW89_KCC][7] = 48, [2][1][RTW89_ACMA][7] = 46, [2][1][RTW89_CN][7] = 44, [2][1][RTW89_UK][7] = 46, + [2][1][RTW89_MEXICO][7] = 72, + [2][1][RTW89_UKRAINE][7] = 46, + [2][1][RTW89_CHILE][7] = 42, + [2][1][RTW89_QATAR][7] = 46, [2][1][RTW89_FCC][8] = 68, [2][1][RTW89_ETSI][8] = 46, [2][1][RTW89_MKK][8] = 46, [2][1][RTW89_IC][8] = 68, - [2][1][RTW89_KCC][8] = 50, + [2][1][RTW89_KCC][8] = 48, [2][1][RTW89_ACMA][8] = 46, [2][1][RTW89_CN][8] = 44, [2][1][RTW89_UK][8] = 46, + [2][1][RTW89_MEXICO][8] = 68, + [2][1][RTW89_UKRAINE][8] = 46, + [2][1][RTW89_CHILE][8] = 42, + [2][1][RTW89_QATAR][8] = 46, [2][1][RTW89_FCC][9] = 64, [2][1][RTW89_ETSI][9] = 46, [2][1][RTW89_MKK][9] = 46, [2][1][RTW89_IC][9] = 64, - [2][1][RTW89_KCC][9] = 52, + [2][1][RTW89_KCC][9] = 48, [2][1][RTW89_ACMA][9] = 46, [2][1][RTW89_CN][9] = 44, [2][1][RTW89_UK][9] = 46, + [2][1][RTW89_MEXICO][9] = 64, + [2][1][RTW89_UKRAINE][9] = 46, + [2][1][RTW89_CHILE][9] = 42, + [2][1][RTW89_QATAR][9] = 46, [2][1][RTW89_FCC][10] = 64, [2][1][RTW89_ETSI][10] = 46, [2][1][RTW89_MKK][10] = 46, [2][1][RTW89_IC][10] = 64, - [2][1][RTW89_KCC][10] = 52, + [2][1][RTW89_KCC][10] = 48, [2][1][RTW89_ACMA][10] = 46, [2][1][RTW89_CN][10] = 44, [2][1][RTW89_UK][10] = 46, + [2][1][RTW89_MEXICO][10] = 64, + [2][1][RTW89_UKRAINE][10] = 46, + [2][1][RTW89_CHILE][10] = 64, + [2][1][RTW89_QATAR][10] = 46, [2][1][RTW89_FCC][11] = 46, [2][1][RTW89_ETSI][11] = 46, [2][1][RTW89_MKK][11] = 46, [2][1][RTW89_IC][11] = 46, - [2][1][RTW89_KCC][11] = 52, + [2][1][RTW89_KCC][11] = 48, [2][1][RTW89_ACMA][11] = 46, [2][1][RTW89_CN][11] = 44, [2][1][RTW89_UK][11] = 46, + [2][1][RTW89_MEXICO][11] = 46, + [2][1][RTW89_UKRAINE][11] = 46, + [2][1][RTW89_CHILE][11] = 46, + [2][1][RTW89_QATAR][11] = 46, [2][1][RTW89_FCC][12] = 6, [2][1][RTW89_ETSI][12] = 44, [2][1][RTW89_MKK][12] = 46, [2][1][RTW89_IC][12] = 6, - [2][1][RTW89_KCC][12] = 52, + [2][1][RTW89_KCC][12] = 48, [2][1][RTW89_ACMA][12] = 44, [2][1][RTW89_CN][12] = 42, [2][1][RTW89_UK][12] = 44, + [2][1][RTW89_MEXICO][12] = 6, + [2][1][RTW89_UKRAINE][12] = 44, + [2][1][RTW89_CHILE][12] = 6, + [2][1][RTW89_QATAR][12] = 44, [2][1][RTW89_FCC][13] = 127, [2][1][RTW89_ETSI][13] = 127, [2][1][RTW89_MKK][13] = 127, @@ -34739,6 +36609,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_2g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_ACMA][13] = 127, [2][1][RTW89_CN][13] = 127, [2][1][RTW89_UK][13] = 127, + [2][1][RTW89_MEXICO][13] = 127, + [2][1][RTW89_UKRAINE][13] = 127, + [2][1][RTW89_CHILE][13] = 127, + [2][1][RTW89_QATAR][13] = 127, }; static @@ -34747,168 +36621,168 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_WW][0] = 16, [0][0][RTW89_WW][2] = 16, [0][0][RTW89_WW][4] = 16, - [0][0][RTW89_WW][6] = 10, + [0][0][RTW89_WW][6] = 16, [0][0][RTW89_WW][8] = 16, [0][0][RTW89_WW][10] = 16, [0][0][RTW89_WW][12] = 16, [0][0][RTW89_WW][14] = 16, - [0][0][RTW89_WW][15] = 30, - [0][0][RTW89_WW][17] = 30, - [0][0][RTW89_WW][19] = 30, - [0][0][RTW89_WW][21] = 30, - [0][0][RTW89_WW][23] = 30, - [0][0][RTW89_WW][25] = 30, - [0][0][RTW89_WW][27] = 30, - [0][0][RTW89_WW][29] = 30, - [0][0][RTW89_WW][31] = 30, - [0][0][RTW89_WW][33] = 30, - [0][0][RTW89_WW][35] = 30, + [0][0][RTW89_WW][15] = 22, + [0][0][RTW89_WW][17] = 22, + [0][0][RTW89_WW][19] = 22, + [0][0][RTW89_WW][21] = 22, + [0][0][RTW89_WW][23] = 22, + [0][0][RTW89_WW][25] = 22, + [0][0][RTW89_WW][27] = 22, + [0][0][RTW89_WW][29] = 22, + [0][0][RTW89_WW][31] = 22, + [0][0][RTW89_WW][33] = 22, + [0][0][RTW89_WW][35] = 22, [0][0][RTW89_WW][37] = 30, - [0][0][RTW89_WW][38] = 28, - [0][0][RTW89_WW][40] = 28, - [0][0][RTW89_WW][42] = 28, - [0][0][RTW89_WW][44] = 28, - [0][0][RTW89_WW][46] = 28, + [0][0][RTW89_WW][38] = 26, + [0][0][RTW89_WW][40] = 26, + [0][0][RTW89_WW][42] = 26, + [0][0][RTW89_WW][44] = 26, + [0][0][RTW89_WW][46] = 26, [0][0][RTW89_WW][48] = 46, [0][0][RTW89_WW][50] = 44, [0][0][RTW89_WW][52] = 34, [0][1][RTW89_WW][0] = 4, [0][1][RTW89_WW][2] = 4, [0][1][RTW89_WW][4] = 4, - [0][1][RTW89_WW][6] = 1, + [0][1][RTW89_WW][6] = 4, [0][1][RTW89_WW][8] = 4, [0][1][RTW89_WW][10] = 4, [0][1][RTW89_WW][12] = 4, [0][1][RTW89_WW][14] = 4, - [0][1][RTW89_WW][15] = 18, - [0][1][RTW89_WW][17] = 18, - [0][1][RTW89_WW][19] = 18, - [0][1][RTW89_WW][21] = 18, - [0][1][RTW89_WW][23] = 18, - [0][1][RTW89_WW][25] = 18, - [0][1][RTW89_WW][27] = 16, - [0][1][RTW89_WW][29] = 16, - [0][1][RTW89_WW][31] = 16, - [0][1][RTW89_WW][33] = 16, - [0][1][RTW89_WW][35] = 16, + [0][1][RTW89_WW][15] = 10, + [0][1][RTW89_WW][17] = 10, + [0][1][RTW89_WW][19] = 10, + [0][1][RTW89_WW][21] = 10, + [0][1][RTW89_WW][23] = 10, + [0][1][RTW89_WW][25] = 10, + [0][1][RTW89_WW][27] = 10, + [0][1][RTW89_WW][29] = 10, + [0][1][RTW89_WW][31] = 10, + [0][1][RTW89_WW][33] = 10, + [0][1][RTW89_WW][35] = 10, [0][1][RTW89_WW][37] = 18, - [0][1][RTW89_WW][38] = 16, - [0][1][RTW89_WW][40] = 16, - [0][1][RTW89_WW][42] = 16, - [0][1][RTW89_WW][44] = 16, - [0][1][RTW89_WW][46] = 16, + [0][1][RTW89_WW][38] = 14, + [0][1][RTW89_WW][40] = 14, + [0][1][RTW89_WW][42] = 14, + [0][1][RTW89_WW][44] = 14, + [0][1][RTW89_WW][46] = 14, [0][1][RTW89_WW][48] = 20, [0][1][RTW89_WW][50] = 20, [0][1][RTW89_WW][52] = 8, [1][0][RTW89_WW][0] = 26, [1][0][RTW89_WW][2] = 26, [1][0][RTW89_WW][4] = 26, - [1][0][RTW89_WW][6] = 24, + [1][0][RTW89_WW][6] = 26, [1][0][RTW89_WW][8] = 26, [1][0][RTW89_WW][10] = 26, [1][0][RTW89_WW][12] = 26, [1][0][RTW89_WW][14] = 26, - [1][0][RTW89_WW][15] = 40, - [1][0][RTW89_WW][17] = 40, - [1][0][RTW89_WW][19] = 40, - [1][0][RTW89_WW][21] = 40, - [1][0][RTW89_WW][23] = 40, - [1][0][RTW89_WW][25] = 40, - [1][0][RTW89_WW][27] = 42, - [1][0][RTW89_WW][29] = 42, - [1][0][RTW89_WW][31] = 42, - [1][0][RTW89_WW][33] = 42, - [1][0][RTW89_WW][35] = 42, + [1][0][RTW89_WW][15] = 32, + [1][0][RTW89_WW][17] = 32, + [1][0][RTW89_WW][19] = 32, + [1][0][RTW89_WW][21] = 32, + [1][0][RTW89_WW][23] = 32, + [1][0][RTW89_WW][25] = 32, + [1][0][RTW89_WW][27] = 32, + [1][0][RTW89_WW][29] = 32, + [1][0][RTW89_WW][31] = 32, + [1][0][RTW89_WW][33] = 32, + [1][0][RTW89_WW][35] = 32, [1][0][RTW89_WW][37] = 42, - [1][0][RTW89_WW][38] = 28, - [1][0][RTW89_WW][40] = 28, - [1][0][RTW89_WW][42] = 28, - [1][0][RTW89_WW][44] = 28, - [1][0][RTW89_WW][46] = 28, + [1][0][RTW89_WW][38] = 26, + [1][0][RTW89_WW][40] = 26, + [1][0][RTW89_WW][42] = 26, + [1][0][RTW89_WW][44] = 26, + [1][0][RTW89_WW][46] = 26, [1][0][RTW89_WW][48] = 56, [1][0][RTW89_WW][50] = 58, [1][0][RTW89_WW][52] = 56, [1][1][RTW89_WW][0] = 14, [1][1][RTW89_WW][2] = 14, [1][1][RTW89_WW][4] = 14, - [1][1][RTW89_WW][6] = 8, + [1][1][RTW89_WW][6] = 14, [1][1][RTW89_WW][8] = 14, [1][1][RTW89_WW][10] = 14, [1][1][RTW89_WW][12] = 14, [1][1][RTW89_WW][14] = 14, - [1][1][RTW89_WW][15] = 28, - [1][1][RTW89_WW][17] = 28, - [1][1][RTW89_WW][19] = 28, - [1][1][RTW89_WW][21] = 28, - [1][1][RTW89_WW][23] = 28, - [1][1][RTW89_WW][25] = 28, - [1][1][RTW89_WW][27] = 30, - [1][1][RTW89_WW][29] = 30, - [1][1][RTW89_WW][31] = 30, - [1][1][RTW89_WW][33] = 30, - [1][1][RTW89_WW][35] = 30, + [1][1][RTW89_WW][15] = 20, + [1][1][RTW89_WW][17] = 20, + [1][1][RTW89_WW][19] = 20, + [1][1][RTW89_WW][21] = 20, + [1][1][RTW89_WW][23] = 20, + [1][1][RTW89_WW][25] = 20, + [1][1][RTW89_WW][27] = 20, + [1][1][RTW89_WW][29] = 20, + [1][1][RTW89_WW][31] = 20, + [1][1][RTW89_WW][33] = 20, + [1][1][RTW89_WW][35] = 20, [1][1][RTW89_WW][37] = 32, - [1][1][RTW89_WW][38] = 16, - [1][1][RTW89_WW][40] = 16, - [1][1][RTW89_WW][42] = 16, - [1][1][RTW89_WW][44] = 16, - [1][1][RTW89_WW][46] = 16, + [1][1][RTW89_WW][38] = 14, + [1][1][RTW89_WW][40] = 14, + [1][1][RTW89_WW][42] = 14, + [1][1][RTW89_WW][44] = 14, + [1][1][RTW89_WW][46] = 14, [1][1][RTW89_WW][48] = 34, [1][1][RTW89_WW][50] = 34, [1][1][RTW89_WW][52] = 30, [2][0][RTW89_WW][0] = 40, [2][0][RTW89_WW][2] = 40, [2][0][RTW89_WW][4] = 40, - [2][0][RTW89_WW][6] = 36, + [2][0][RTW89_WW][6] = 38, [2][0][RTW89_WW][8] = 40, [2][0][RTW89_WW][10] = 40, [2][0][RTW89_WW][12] = 40, [2][0][RTW89_WW][14] = 40, - [2][0][RTW89_WW][15] = 52, - [2][0][RTW89_WW][17] = 52, - [2][0][RTW89_WW][19] = 52, - [2][0][RTW89_WW][21] = 52, - [2][0][RTW89_WW][23] = 52, - [2][0][RTW89_WW][25] = 52, - [2][0][RTW89_WW][27] = 52, - [2][0][RTW89_WW][29] = 52, - [2][0][RTW89_WW][31] = 52, - [2][0][RTW89_WW][33] = 52, - [2][0][RTW89_WW][35] = 52, + [2][0][RTW89_WW][15] = 46, + [2][0][RTW89_WW][17] = 46, + [2][0][RTW89_WW][19] = 46, + [2][0][RTW89_WW][21] = 46, + [2][0][RTW89_WW][23] = 46, + [2][0][RTW89_WW][25] = 46, + [2][0][RTW89_WW][27] = 46, + [2][0][RTW89_WW][29] = 46, + [2][0][RTW89_WW][31] = 46, + [2][0][RTW89_WW][33] = 46, + [2][0][RTW89_WW][35] = 46, [2][0][RTW89_WW][37] = 52, - [2][0][RTW89_WW][38] = 28, - [2][0][RTW89_WW][40] = 28, - [2][0][RTW89_WW][42] = 28, - [2][0][RTW89_WW][44] = 28, - [2][0][RTW89_WW][46] = 28, + [2][0][RTW89_WW][38] = 26, + [2][0][RTW89_WW][40] = 26, + [2][0][RTW89_WW][42] = 26, + [2][0][RTW89_WW][44] = 26, + [2][0][RTW89_WW][46] = 26, [2][0][RTW89_WW][48] = 64, [2][0][RTW89_WW][50] = 64, [2][0][RTW89_WW][52] = 64, [2][1][RTW89_WW][0] = 26, [2][1][RTW89_WW][2] = 26, [2][1][RTW89_WW][4] = 26, - [2][1][RTW89_WW][6] = 20, + [2][1][RTW89_WW][6] = 26, [2][1][RTW89_WW][8] = 28, [2][1][RTW89_WW][10] = 28, [2][1][RTW89_WW][12] = 28, [2][1][RTW89_WW][14] = 28, - [2][1][RTW89_WW][15] = 40, - [2][1][RTW89_WW][17] = 40, - [2][1][RTW89_WW][19] = 40, - [2][1][RTW89_WW][21] = 40, - [2][1][RTW89_WW][23] = 40, - [2][1][RTW89_WW][25] = 40, - [2][1][RTW89_WW][27] = 40, - [2][1][RTW89_WW][29] = 40, - [2][1][RTW89_WW][31] = 40, - [2][1][RTW89_WW][33] = 40, - [2][1][RTW89_WW][35] = 40, + [2][1][RTW89_WW][15] = 34, + [2][1][RTW89_WW][17] = 34, + [2][1][RTW89_WW][19] = 34, + [2][1][RTW89_WW][21] = 34, + [2][1][RTW89_WW][23] = 34, + [2][1][RTW89_WW][25] = 34, + [2][1][RTW89_WW][27] = 34, + [2][1][RTW89_WW][29] = 34, + [2][1][RTW89_WW][31] = 34, + [2][1][RTW89_WW][33] = 34, + [2][1][RTW89_WW][35] = 34, [2][1][RTW89_WW][37] = 42, - [2][1][RTW89_WW][38] = 16, - [2][1][RTW89_WW][40] = 16, - [2][1][RTW89_WW][42] = 16, - [2][1][RTW89_WW][44] = 16, - [2][1][RTW89_WW][46] = 16, + [2][1][RTW89_WW][38] = 14, + [2][1][RTW89_WW][40] = 14, + [2][1][RTW89_WW][42] = 14, + [2][1][RTW89_WW][44] = 14, + [2][1][RTW89_WW][46] = 14, [2][1][RTW89_WW][48] = 40, [2][1][RTW89_WW][50] = 40, [2][1][RTW89_WW][52] = 40, @@ -34920,6 +36794,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][0] = 30, [0][0][RTW89_CN][0] = 16, [0][0][RTW89_UK][0] = 30, + [0][0][RTW89_MEXICO][0] = 50, + [0][0][RTW89_UKRAINE][0] = 22, + [0][0][RTW89_CHILE][0] = 50, + [0][0][RTW89_QATAR][0] = 30, [0][0][RTW89_FCC][2] = 50, [0][0][RTW89_ETSI][2] = 30, [0][0][RTW89_MKK][2] = 36, @@ -34928,6 +36806,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][2] = 30, [0][0][RTW89_CN][2] = 16, [0][0][RTW89_UK][2] = 30, + [0][0][RTW89_MEXICO][2] = 50, + [0][0][RTW89_UKRAINE][2] = 22, + [0][0][RTW89_CHILE][2] = 50, + [0][0][RTW89_QATAR][2] = 30, [0][0][RTW89_FCC][4] = 50, [0][0][RTW89_ETSI][4] = 30, [0][0][RTW89_MKK][4] = 22, @@ -34936,30 +36818,46 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][4] = 30, [0][0][RTW89_CN][4] = 16, [0][0][RTW89_UK][4] = 30, + [0][0][RTW89_MEXICO][4] = 50, + [0][0][RTW89_UKRAINE][4] = 22, + [0][0][RTW89_CHILE][4] = 50, + [0][0][RTW89_QATAR][4] = 30, [0][0][RTW89_FCC][6] = 50, [0][0][RTW89_ETSI][6] = 30, [0][0][RTW89_MKK][6] = 22, [0][0][RTW89_IC][6] = 32, - [0][0][RTW89_KCC][6] = 10, + [0][0][RTW89_KCC][6] = 18, [0][0][RTW89_ACMA][6] = 30, [0][0][RTW89_CN][6] = 16, [0][0][RTW89_UK][6] = 30, + [0][0][RTW89_MEXICO][6] = 50, + [0][0][RTW89_UKRAINE][6] = 22, + [0][0][RTW89_CHILE][6] = 50, + [0][0][RTW89_QATAR][6] = 30, [0][0][RTW89_FCC][8] = 52, [0][0][RTW89_ETSI][8] = 28, [0][0][RTW89_MKK][8] = 18, [0][0][RTW89_IC][8] = 52, - [0][0][RTW89_KCC][8] = 44, + [0][0][RTW89_KCC][8] = 40, [0][0][RTW89_ACMA][8] = 28, [0][0][RTW89_CN][8] = 16, [0][0][RTW89_UK][8] = 28, + [0][0][RTW89_MEXICO][8] = 52, + [0][0][RTW89_UKRAINE][8] = 22, + [0][0][RTW89_CHILE][8] = 52, + [0][0][RTW89_QATAR][8] = 28, [0][0][RTW89_FCC][10] = 52, [0][0][RTW89_ETSI][10] = 28, [0][0][RTW89_MKK][10] = 18, [0][0][RTW89_IC][10] = 52, - [0][0][RTW89_KCC][10] = 44, + [0][0][RTW89_KCC][10] = 40, [0][0][RTW89_ACMA][10] = 28, [0][0][RTW89_CN][10] = 16, [0][0][RTW89_UK][10] = 28, + [0][0][RTW89_MEXICO][10] = 52, + [0][0][RTW89_UKRAINE][10] = 22, + [0][0][RTW89_CHILE][10] = 52, + [0][0][RTW89_QATAR][10] = 28, [0][0][RTW89_FCC][12] = 52, [0][0][RTW89_ETSI][12] = 28, [0][0][RTW89_MKK][12] = 34, @@ -34968,6 +36866,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][12] = 28, [0][0][RTW89_CN][12] = 16, [0][0][RTW89_UK][12] = 28, + [0][0][RTW89_MEXICO][12] = 52, + [0][0][RTW89_UKRAINE][12] = 22, + [0][0][RTW89_CHILE][12] = 52, + [0][0][RTW89_QATAR][12] = 28, [0][0][RTW89_FCC][14] = 52, [0][0][RTW89_ETSI][14] = 28, [0][0][RTW89_MKK][14] = 34, @@ -34976,70 +36878,106 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][14] = 28, [0][0][RTW89_CN][14] = 16, [0][0][RTW89_UK][14] = 28, + [0][0][RTW89_MEXICO][14] = 52, + [0][0][RTW89_UKRAINE][14] = 22, + [0][0][RTW89_CHILE][14] = 52, + [0][0][RTW89_QATAR][14] = 28, [0][0][RTW89_FCC][15] = 52, [0][0][RTW89_ETSI][15] = 30, [0][0][RTW89_MKK][15] = 56, [0][0][RTW89_IC][15] = 52, - [0][0][RTW89_KCC][15] = 42, + [0][0][RTW89_KCC][15] = 40, [0][0][RTW89_ACMA][15] = 30, [0][0][RTW89_CN][15] = 127, [0][0][RTW89_UK][15] = 30, + [0][0][RTW89_MEXICO][15] = 52, + [0][0][RTW89_UKRAINE][15] = 22, + [0][0][RTW89_CHILE][15] = 52, + [0][0][RTW89_QATAR][15] = 30, [0][0][RTW89_FCC][17] = 52, [0][0][RTW89_ETSI][17] = 30, [0][0][RTW89_MKK][17] = 58, [0][0][RTW89_IC][17] = 52, - [0][0][RTW89_KCC][17] = 42, + [0][0][RTW89_KCC][17] = 40, [0][0][RTW89_ACMA][17] = 30, [0][0][RTW89_CN][17] = 127, [0][0][RTW89_UK][17] = 30, + [0][0][RTW89_MEXICO][17] = 52, + [0][0][RTW89_UKRAINE][17] = 22, + [0][0][RTW89_CHILE][17] = 52, + [0][0][RTW89_QATAR][17] = 30, [0][0][RTW89_FCC][19] = 52, [0][0][RTW89_ETSI][19] = 30, [0][0][RTW89_MKK][19] = 58, [0][0][RTW89_IC][19] = 52, - [0][0][RTW89_KCC][19] = 42, + [0][0][RTW89_KCC][19] = 40, [0][0][RTW89_ACMA][19] = 30, [0][0][RTW89_CN][19] = 127, [0][0][RTW89_UK][19] = 30, + [0][0][RTW89_MEXICO][19] = 52, + [0][0][RTW89_UKRAINE][19] = 22, + [0][0][RTW89_CHILE][19] = 52, + [0][0][RTW89_QATAR][19] = 30, [0][0][RTW89_FCC][21] = 52, [0][0][RTW89_ETSI][21] = 30, [0][0][RTW89_MKK][21] = 58, [0][0][RTW89_IC][21] = 52, - [0][0][RTW89_KCC][21] = 42, + [0][0][RTW89_KCC][21] = 40, [0][0][RTW89_ACMA][21] = 30, [0][0][RTW89_CN][21] = 127, [0][0][RTW89_UK][21] = 30, + [0][0][RTW89_MEXICO][21] = 52, + [0][0][RTW89_UKRAINE][21] = 22, + [0][0][RTW89_CHILE][21] = 52, + [0][0][RTW89_QATAR][21] = 30, [0][0][RTW89_FCC][23] = 52, [0][0][RTW89_ETSI][23] = 30, [0][0][RTW89_MKK][23] = 58, [0][0][RTW89_IC][23] = 52, - [0][0][RTW89_KCC][23] = 42, + [0][0][RTW89_KCC][23] = 40, [0][0][RTW89_ACMA][23] = 30, [0][0][RTW89_CN][23] = 127, [0][0][RTW89_UK][23] = 30, + [0][0][RTW89_MEXICO][23] = 52, + [0][0][RTW89_UKRAINE][23] = 22, + [0][0][RTW89_CHILE][23] = 52, + [0][0][RTW89_QATAR][23] = 30, [0][0][RTW89_FCC][25] = 52, [0][0][RTW89_ETSI][25] = 30, [0][0][RTW89_MKK][25] = 58, [0][0][RTW89_IC][25] = 127, - [0][0][RTW89_KCC][25] = 42, + [0][0][RTW89_KCC][25] = 40, [0][0][RTW89_ACMA][25] = 127, [0][0][RTW89_CN][25] = 127, [0][0][RTW89_UK][25] = 30, + [0][0][RTW89_MEXICO][25] = 52, + [0][0][RTW89_UKRAINE][25] = 22, + [0][0][RTW89_CHILE][25] = 52, + [0][0][RTW89_QATAR][25] = 30, [0][0][RTW89_FCC][27] = 52, [0][0][RTW89_ETSI][27] = 30, [0][0][RTW89_MKK][27] = 58, [0][0][RTW89_IC][27] = 127, - [0][0][RTW89_KCC][27] = 42, + [0][0][RTW89_KCC][27] = 40, [0][0][RTW89_ACMA][27] = 127, [0][0][RTW89_CN][27] = 127, [0][0][RTW89_UK][27] = 30, + [0][0][RTW89_MEXICO][27] = 52, + [0][0][RTW89_UKRAINE][27] = 22, + [0][0][RTW89_CHILE][27] = 52, + [0][0][RTW89_QATAR][27] = 30, [0][0][RTW89_FCC][29] = 52, [0][0][RTW89_ETSI][29] = 30, [0][0][RTW89_MKK][29] = 58, [0][0][RTW89_IC][29] = 127, - [0][0][RTW89_KCC][29] = 42, + [0][0][RTW89_KCC][29] = 40, [0][0][RTW89_ACMA][29] = 127, [0][0][RTW89_CN][29] = 127, [0][0][RTW89_UK][29] = 30, + [0][0][RTW89_MEXICO][29] = 52, + [0][0][RTW89_UKRAINE][29] = 22, + [0][0][RTW89_CHILE][29] = 52, + [0][0][RTW89_QATAR][29] = 30, [0][0][RTW89_FCC][31] = 52, [0][0][RTW89_ETSI][31] = 30, [0][0][RTW89_MKK][31] = 58, @@ -35048,6 +36986,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][31] = 30, [0][0][RTW89_CN][31] = 127, [0][0][RTW89_UK][31] = 30, + [0][0][RTW89_MEXICO][31] = 52, + [0][0][RTW89_UKRAINE][31] = 22, + [0][0][RTW89_CHILE][31] = 52, + [0][0][RTW89_QATAR][31] = 30, [0][0][RTW89_FCC][33] = 44, [0][0][RTW89_ETSI][33] = 30, [0][0][RTW89_MKK][33] = 58, @@ -35056,6 +36998,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][33] = 30, [0][0][RTW89_CN][33] = 127, [0][0][RTW89_UK][33] = 30, + [0][0][RTW89_MEXICO][33] = 44, + [0][0][RTW89_UKRAINE][33] = 22, + [0][0][RTW89_CHILE][33] = 44, + [0][0][RTW89_QATAR][33] = 30, [0][0][RTW89_FCC][35] = 44, [0][0][RTW89_ETSI][35] = 30, [0][0][RTW89_MKK][35] = 58, @@ -35064,6 +37010,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][35] = 30, [0][0][RTW89_CN][35] = 127, [0][0][RTW89_UK][35] = 30, + [0][0][RTW89_MEXICO][35] = 44, + [0][0][RTW89_UKRAINE][35] = 22, + [0][0][RTW89_CHILE][35] = 44, + [0][0][RTW89_QATAR][35] = 30, [0][0][RTW89_FCC][37] = 52, [0][0][RTW89_ETSI][37] = 127, [0][0][RTW89_MKK][37] = 58, @@ -35072,6 +37022,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][37] = 52, [0][0][RTW89_CN][37] = 127, [0][0][RTW89_UK][37] = 30, + [0][0][RTW89_MEXICO][37] = 52, + [0][0][RTW89_UKRAINE][37] = 127, + [0][0][RTW89_CHILE][37] = 52, + [0][0][RTW89_QATAR][37] = 127, [0][0][RTW89_FCC][38] = 64, [0][0][RTW89_ETSI][38] = 28, [0][0][RTW89_MKK][38] = 127, @@ -35080,6 +37034,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][38] = 64, [0][0][RTW89_CN][38] = 54, [0][0][RTW89_UK][38] = 30, + [0][0][RTW89_MEXICO][38] = 64, + [0][0][RTW89_UKRAINE][38] = 26, + [0][0][RTW89_CHILE][38] = 64, + [0][0][RTW89_QATAR][38] = 26, [0][0][RTW89_FCC][40] = 64, [0][0][RTW89_ETSI][40] = 28, [0][0][RTW89_MKK][40] = 127, @@ -35088,6 +37046,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][40] = 64, [0][0][RTW89_CN][40] = 54, [0][0][RTW89_UK][40] = 30, + [0][0][RTW89_MEXICO][40] = 64, + [0][0][RTW89_UKRAINE][40] = 26, + [0][0][RTW89_CHILE][40] = 64, + [0][0][RTW89_QATAR][40] = 26, [0][0][RTW89_FCC][42] = 60, [0][0][RTW89_ETSI][42] = 28, [0][0][RTW89_MKK][42] = 127, @@ -35096,6 +37058,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][42] = 60, [0][0][RTW89_CN][42] = 54, [0][0][RTW89_UK][42] = 30, + [0][0][RTW89_MEXICO][42] = 60, + [0][0][RTW89_UKRAINE][42] = 26, + [0][0][RTW89_CHILE][42] = 60, + [0][0][RTW89_QATAR][42] = 26, [0][0][RTW89_FCC][44] = 60, [0][0][RTW89_ETSI][44] = 28, [0][0][RTW89_MKK][44] = 127, @@ -35104,6 +37070,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][44] = 60, [0][0][RTW89_CN][44] = 54, [0][0][RTW89_UK][44] = 30, + [0][0][RTW89_MEXICO][44] = 60, + [0][0][RTW89_UKRAINE][44] = 26, + [0][0][RTW89_CHILE][44] = 60, + [0][0][RTW89_QATAR][44] = 26, [0][0][RTW89_FCC][46] = 60, [0][0][RTW89_ETSI][46] = 28, [0][0][RTW89_MKK][46] = 127, @@ -35112,6 +37082,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][46] = 60, [0][0][RTW89_CN][46] = 54, [0][0][RTW89_UK][46] = 30, + [0][0][RTW89_MEXICO][46] = 60, + [0][0][RTW89_UKRAINE][46] = 26, + [0][0][RTW89_CHILE][46] = 60, + [0][0][RTW89_QATAR][46] = 26, [0][0][RTW89_FCC][48] = 46, [0][0][RTW89_ETSI][48] = 127, [0][0][RTW89_MKK][48] = 127, @@ -35120,6 +37094,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][48] = 127, [0][0][RTW89_CN][48] = 127, [0][0][RTW89_UK][48] = 127, + [0][0][RTW89_MEXICO][48] = 127, + [0][0][RTW89_UKRAINE][48] = 127, + [0][0][RTW89_CHILE][48] = 127, + [0][0][RTW89_QATAR][48] = 127, [0][0][RTW89_FCC][50] = 44, [0][0][RTW89_ETSI][50] = 127, [0][0][RTW89_MKK][50] = 127, @@ -35128,6 +37106,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][50] = 127, [0][0][RTW89_CN][50] = 127, [0][0][RTW89_UK][50] = 127, + [0][0][RTW89_MEXICO][50] = 127, + [0][0][RTW89_UKRAINE][50] = 127, + [0][0][RTW89_CHILE][50] = 127, + [0][0][RTW89_QATAR][50] = 127, [0][0][RTW89_FCC][52] = 34, [0][0][RTW89_ETSI][52] = 127, [0][0][RTW89_MKK][52] = 127, @@ -35136,38 +37118,58 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_ACMA][52] = 127, [0][0][RTW89_CN][52] = 127, [0][0][RTW89_UK][52] = 127, + [0][0][RTW89_MEXICO][52] = 127, + [0][0][RTW89_UKRAINE][52] = 127, + [0][0][RTW89_CHILE][52] = 127, + [0][0][RTW89_QATAR][52] = 127, [0][1][RTW89_FCC][0] = 30, [0][1][RTW89_ETSI][0] = 18, [0][1][RTW89_MKK][0] = 20, [0][1][RTW89_IC][0] = 8, - [0][1][RTW89_KCC][0] = 26, + [0][1][RTW89_KCC][0] = 32, [0][1][RTW89_ACMA][0] = 18, [0][1][RTW89_CN][0] = 4, [0][1][RTW89_UK][0] = 18, + [0][1][RTW89_MEXICO][0] = 30, + [0][1][RTW89_UKRAINE][0] = 10, + [0][1][RTW89_CHILE][0] = 30, + [0][1][RTW89_QATAR][0] = 18, [0][1][RTW89_FCC][2] = 32, [0][1][RTW89_ETSI][2] = 18, [0][1][RTW89_MKK][2] = 20, [0][1][RTW89_IC][2] = 8, - [0][1][RTW89_KCC][2] = 26, + [0][1][RTW89_KCC][2] = 32, [0][1][RTW89_ACMA][2] = 18, [0][1][RTW89_CN][2] = 4, [0][1][RTW89_UK][2] = 18, + [0][1][RTW89_MEXICO][2] = 32, + [0][1][RTW89_UKRAINE][2] = 10, + [0][1][RTW89_CHILE][2] = 32, + [0][1][RTW89_QATAR][2] = 18, [0][1][RTW89_FCC][4] = 30, [0][1][RTW89_ETSI][4] = 18, [0][1][RTW89_MKK][4] = 8, [0][1][RTW89_IC][4] = 8, - [0][1][RTW89_KCC][4] = 26, + [0][1][RTW89_KCC][4] = 32, [0][1][RTW89_ACMA][4] = 18, [0][1][RTW89_CN][4] = 4, [0][1][RTW89_UK][4] = 18, + [0][1][RTW89_MEXICO][4] = 30, + [0][1][RTW89_UKRAINE][4] = 10, + [0][1][RTW89_CHILE][4] = 30, + [0][1][RTW89_QATAR][4] = 18, [0][1][RTW89_FCC][6] = 30, [0][1][RTW89_ETSI][6] = 18, [0][1][RTW89_MKK][6] = 8, [0][1][RTW89_IC][6] = 8, - [0][1][RTW89_KCC][6] = 0, + [0][1][RTW89_KCC][6] = 6, [0][1][RTW89_ACMA][6] = 18, [0][1][RTW89_CN][6] = 4, [0][1][RTW89_UK][6] = 18, + [0][1][RTW89_MEXICO][6] = 30, + [0][1][RTW89_UKRAINE][6] = 10, + [0][1][RTW89_CHILE][6] = 30, + [0][1][RTW89_QATAR][6] = 18, [0][1][RTW89_FCC][8] = 30, [0][1][RTW89_ETSI][8] = 16, [0][1][RTW89_MKK][8] = 20, @@ -35176,6 +37178,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][8] = 16, [0][1][RTW89_CN][8] = 4, [0][1][RTW89_UK][8] = 16, + [0][1][RTW89_MEXICO][8] = 30, + [0][1][RTW89_UKRAINE][8] = 10, + [0][1][RTW89_CHILE][8] = 30, + [0][1][RTW89_QATAR][8] = 16, [0][1][RTW89_FCC][10] = 30, [0][1][RTW89_ETSI][10] = 16, [0][1][RTW89_MKK][10] = 20, @@ -35184,22 +37190,34 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][10] = 16, [0][1][RTW89_CN][10] = 4, [0][1][RTW89_UK][10] = 16, + [0][1][RTW89_MEXICO][10] = 30, + [0][1][RTW89_UKRAINE][10] = 10, + [0][1][RTW89_CHILE][10] = 30, + [0][1][RTW89_QATAR][10] = 16, [0][1][RTW89_FCC][12] = 30, [0][1][RTW89_ETSI][12] = 16, [0][1][RTW89_MKK][12] = 34, [0][1][RTW89_IC][12] = 30, - [0][1][RTW89_KCC][12] = 28, + [0][1][RTW89_KCC][12] = 26, [0][1][RTW89_ACMA][12] = 16, [0][1][RTW89_CN][12] = 4, [0][1][RTW89_UK][12] = 16, + [0][1][RTW89_MEXICO][12] = 30, + [0][1][RTW89_UKRAINE][12] = 10, + [0][1][RTW89_CHILE][12] = 30, + [0][1][RTW89_QATAR][12] = 16, [0][1][RTW89_FCC][14] = 30, [0][1][RTW89_ETSI][14] = 16, [0][1][RTW89_MKK][14] = 34, [0][1][RTW89_IC][14] = 30, - [0][1][RTW89_KCC][14] = 28, + [0][1][RTW89_KCC][14] = 26, [0][1][RTW89_ACMA][14] = 16, [0][1][RTW89_CN][14] = 4, [0][1][RTW89_UK][14] = 16, + [0][1][RTW89_MEXICO][14] = 30, + [0][1][RTW89_UKRAINE][14] = 10, + [0][1][RTW89_CHILE][14] = 30, + [0][1][RTW89_QATAR][14] = 16, [0][1][RTW89_FCC][15] = 32, [0][1][RTW89_ETSI][15] = 18, [0][1][RTW89_MKK][15] = 44, @@ -35208,6 +37226,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][15] = 18, [0][1][RTW89_CN][15] = 127, [0][1][RTW89_UK][15] = 18, + [0][1][RTW89_MEXICO][15] = 32, + [0][1][RTW89_UKRAINE][15] = 10, + [0][1][RTW89_CHILE][15] = 32, + [0][1][RTW89_QATAR][15] = 18, [0][1][RTW89_FCC][17] = 32, [0][1][RTW89_ETSI][17] = 18, [0][1][RTW89_MKK][17] = 44, @@ -35216,6 +37238,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][17] = 18, [0][1][RTW89_CN][17] = 127, [0][1][RTW89_UK][17] = 18, + [0][1][RTW89_MEXICO][17] = 32, + [0][1][RTW89_UKRAINE][17] = 10, + [0][1][RTW89_CHILE][17] = 32, + [0][1][RTW89_QATAR][17] = 18, [0][1][RTW89_FCC][19] = 32, [0][1][RTW89_ETSI][19] = 18, [0][1][RTW89_MKK][19] = 44, @@ -35224,6 +37250,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][19] = 18, [0][1][RTW89_CN][19] = 127, [0][1][RTW89_UK][19] = 18, + [0][1][RTW89_MEXICO][19] = 32, + [0][1][RTW89_UKRAINE][19] = 10, + [0][1][RTW89_CHILE][19] = 32, + [0][1][RTW89_QATAR][19] = 18, [0][1][RTW89_FCC][21] = 32, [0][1][RTW89_ETSI][21] = 18, [0][1][RTW89_MKK][21] = 44, @@ -35232,6 +37262,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][21] = 18, [0][1][RTW89_CN][21] = 127, [0][1][RTW89_UK][21] = 18, + [0][1][RTW89_MEXICO][21] = 32, + [0][1][RTW89_UKRAINE][21] = 10, + [0][1][RTW89_CHILE][21] = 32, + [0][1][RTW89_QATAR][21] = 18, [0][1][RTW89_FCC][23] = 32, [0][1][RTW89_ETSI][23] = 18, [0][1][RTW89_MKK][23] = 44, @@ -35240,6 +37274,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][23] = 18, [0][1][RTW89_CN][23] = 127, [0][1][RTW89_UK][23] = 18, + [0][1][RTW89_MEXICO][23] = 32, + [0][1][RTW89_UKRAINE][23] = 10, + [0][1][RTW89_CHILE][23] = 32, + [0][1][RTW89_QATAR][23] = 18, [0][1][RTW89_FCC][25] = 32, [0][1][RTW89_ETSI][25] = 18, [0][1][RTW89_MKK][25] = 44, @@ -35248,6 +37286,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][25] = 127, [0][1][RTW89_CN][25] = 127, [0][1][RTW89_UK][25] = 18, + [0][1][RTW89_MEXICO][25] = 32, + [0][1][RTW89_UKRAINE][25] = 10, + [0][1][RTW89_CHILE][25] = 32, + [0][1][RTW89_QATAR][25] = 18, [0][1][RTW89_FCC][27] = 32, [0][1][RTW89_ETSI][27] = 16, [0][1][RTW89_MKK][27] = 44, @@ -35256,6 +37298,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][27] = 127, [0][1][RTW89_CN][27] = 127, [0][1][RTW89_UK][27] = 16, + [0][1][RTW89_MEXICO][27] = 32, + [0][1][RTW89_UKRAINE][27] = 10, + [0][1][RTW89_CHILE][27] = 32, + [0][1][RTW89_QATAR][27] = 16, [0][1][RTW89_FCC][29] = 32, [0][1][RTW89_ETSI][29] = 16, [0][1][RTW89_MKK][29] = 44, @@ -35264,6 +37310,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][29] = 127, [0][1][RTW89_CN][29] = 127, [0][1][RTW89_UK][29] = 16, + [0][1][RTW89_MEXICO][29] = 32, + [0][1][RTW89_UKRAINE][29] = 10, + [0][1][RTW89_CHILE][29] = 32, + [0][1][RTW89_QATAR][29] = 16, [0][1][RTW89_FCC][31] = 32, [0][1][RTW89_ETSI][31] = 16, [0][1][RTW89_MKK][31] = 44, @@ -35272,6 +37322,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][31] = 16, [0][1][RTW89_CN][31] = 127, [0][1][RTW89_UK][31] = 16, + [0][1][RTW89_MEXICO][31] = 32, + [0][1][RTW89_UKRAINE][31] = 10, + [0][1][RTW89_CHILE][31] = 32, + [0][1][RTW89_QATAR][31] = 16, [0][1][RTW89_FCC][33] = 30, [0][1][RTW89_ETSI][33] = 16, [0][1][RTW89_MKK][33] = 44, @@ -35280,6 +37334,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][33] = 16, [0][1][RTW89_CN][33] = 127, [0][1][RTW89_UK][33] = 16, + [0][1][RTW89_MEXICO][33] = 30, + [0][1][RTW89_UKRAINE][33] = 10, + [0][1][RTW89_CHILE][33] = 30, + [0][1][RTW89_QATAR][33] = 16, [0][1][RTW89_FCC][35] = 30, [0][1][RTW89_ETSI][35] = 16, [0][1][RTW89_MKK][35] = 44, @@ -35288,6 +37346,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][35] = 16, [0][1][RTW89_CN][35] = 127, [0][1][RTW89_UK][35] = 16, + [0][1][RTW89_MEXICO][35] = 30, + [0][1][RTW89_UKRAINE][35] = 10, + [0][1][RTW89_CHILE][35] = 30, + [0][1][RTW89_QATAR][35] = 16, [0][1][RTW89_FCC][37] = 34, [0][1][RTW89_ETSI][37] = 127, [0][1][RTW89_MKK][37] = 44, @@ -35296,46 +37358,70 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][37] = 34, [0][1][RTW89_CN][37] = 127, [0][1][RTW89_UK][37] = 18, + [0][1][RTW89_MEXICO][37] = 34, + [0][1][RTW89_UKRAINE][37] = 127, + [0][1][RTW89_CHILE][37] = 34, + [0][1][RTW89_QATAR][37] = 127, [0][1][RTW89_FCC][38] = 62, [0][1][RTW89_ETSI][38] = 16, [0][1][RTW89_MKK][38] = 127, [0][1][RTW89_IC][38] = 62, - [0][1][RTW89_KCC][38] = 28, + [0][1][RTW89_KCC][38] = 30, [0][1][RTW89_ACMA][38] = 62, [0][1][RTW89_CN][38] = 42, [0][1][RTW89_UK][38] = 18, + [0][1][RTW89_MEXICO][38] = 62, + [0][1][RTW89_UKRAINE][38] = 14, + [0][1][RTW89_CHILE][38] = 62, + [0][1][RTW89_QATAR][38] = 14, [0][1][RTW89_FCC][40] = 62, [0][1][RTW89_ETSI][40] = 16, [0][1][RTW89_MKK][40] = 127, [0][1][RTW89_IC][40] = 62, - [0][1][RTW89_KCC][40] = 28, + [0][1][RTW89_KCC][40] = 30, [0][1][RTW89_ACMA][40] = 62, [0][1][RTW89_CN][40] = 42, [0][1][RTW89_UK][40] = 18, + [0][1][RTW89_MEXICO][40] = 62, + [0][1][RTW89_UKRAINE][40] = 14, + [0][1][RTW89_CHILE][40] = 62, + [0][1][RTW89_QATAR][40] = 14, [0][1][RTW89_FCC][42] = 58, [0][1][RTW89_ETSI][42] = 16, [0][1][RTW89_MKK][42] = 127, [0][1][RTW89_IC][42] = 58, - [0][1][RTW89_KCC][42] = 28, + [0][1][RTW89_KCC][42] = 30, [0][1][RTW89_ACMA][42] = 58, [0][1][RTW89_CN][42] = 42, [0][1][RTW89_UK][42] = 18, + [0][1][RTW89_MEXICO][42] = 58, + [0][1][RTW89_UKRAINE][42] = 14, + [0][1][RTW89_CHILE][42] = 58, + [0][1][RTW89_QATAR][42] = 14, [0][1][RTW89_FCC][44] = 56, [0][1][RTW89_ETSI][44] = 16, [0][1][RTW89_MKK][44] = 127, [0][1][RTW89_IC][44] = 56, - [0][1][RTW89_KCC][44] = 28, + [0][1][RTW89_KCC][44] = 30, [0][1][RTW89_ACMA][44] = 56, [0][1][RTW89_CN][44] = 42, [0][1][RTW89_UK][44] = 18, + [0][1][RTW89_MEXICO][44] = 56, + [0][1][RTW89_UKRAINE][44] = 14, + [0][1][RTW89_CHILE][44] = 56, + [0][1][RTW89_QATAR][44] = 14, [0][1][RTW89_FCC][46] = 56, [0][1][RTW89_ETSI][46] = 16, [0][1][RTW89_MKK][46] = 127, [0][1][RTW89_IC][46] = 56, - [0][1][RTW89_KCC][46] = 28, + [0][1][RTW89_KCC][46] = 30, [0][1][RTW89_ACMA][46] = 56, [0][1][RTW89_CN][46] = 42, [0][1][RTW89_UK][46] = 18, + [0][1][RTW89_MEXICO][46] = 56, + [0][1][RTW89_UKRAINE][46] = 14, + [0][1][RTW89_CHILE][46] = 56, + [0][1][RTW89_QATAR][46] = 14, [0][1][RTW89_FCC][48] = 20, [0][1][RTW89_ETSI][48] = 127, [0][1][RTW89_MKK][48] = 127, @@ -35344,6 +37430,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][48] = 127, [0][1][RTW89_CN][48] = 127, [0][1][RTW89_UK][48] = 127, + [0][1][RTW89_MEXICO][48] = 127, + [0][1][RTW89_UKRAINE][48] = 127, + [0][1][RTW89_CHILE][48] = 127, + [0][1][RTW89_QATAR][48] = 127, [0][1][RTW89_FCC][50] = 20, [0][1][RTW89_ETSI][50] = 127, [0][1][RTW89_MKK][50] = 127, @@ -35352,6 +37442,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][50] = 127, [0][1][RTW89_CN][50] = 127, [0][1][RTW89_UK][50] = 127, + [0][1][RTW89_MEXICO][50] = 127, + [0][1][RTW89_UKRAINE][50] = 127, + [0][1][RTW89_CHILE][50] = 127, + [0][1][RTW89_QATAR][50] = 127, [0][1][RTW89_FCC][52] = 8, [0][1][RTW89_ETSI][52] = 127, [0][1][RTW89_MKK][52] = 127, @@ -35360,70 +37454,106 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_ACMA][52] = 127, [0][1][RTW89_CN][52] = 127, [0][1][RTW89_UK][52] = 127, + [0][1][RTW89_MEXICO][52] = 127, + [0][1][RTW89_UKRAINE][52] = 127, + [0][1][RTW89_CHILE][52] = 127, + [0][1][RTW89_QATAR][52] = 127, [1][0][RTW89_FCC][0] = 62, [1][0][RTW89_ETSI][0] = 40, [1][0][RTW89_MKK][0] = 48, [1][0][RTW89_IC][0] = 42, - [1][0][RTW89_KCC][0] = 50, + [1][0][RTW89_KCC][0] = 54, [1][0][RTW89_ACMA][0] = 40, [1][0][RTW89_CN][0] = 26, [1][0][RTW89_UK][0] = 40, + [1][0][RTW89_MEXICO][0] = 62, + [1][0][RTW89_UKRAINE][0] = 32, + [1][0][RTW89_CHILE][0] = 62, + [1][0][RTW89_QATAR][0] = 40, [1][0][RTW89_FCC][2] = 62, [1][0][RTW89_ETSI][2] = 40, [1][0][RTW89_MKK][2] = 48, [1][0][RTW89_IC][2] = 42, - [1][0][RTW89_KCC][2] = 50, + [1][0][RTW89_KCC][2] = 54, [1][0][RTW89_ACMA][2] = 40, [1][0][RTW89_CN][2] = 26, [1][0][RTW89_UK][2] = 40, + [1][0][RTW89_MEXICO][2] = 62, + [1][0][RTW89_UKRAINE][2] = 32, + [1][0][RTW89_CHILE][2] = 62, + [1][0][RTW89_QATAR][2] = 40, [1][0][RTW89_FCC][4] = 64, [1][0][RTW89_ETSI][4] = 40, [1][0][RTW89_MKK][4] = 40, [1][0][RTW89_IC][4] = 42, - [1][0][RTW89_KCC][4] = 50, + [1][0][RTW89_KCC][4] = 54, [1][0][RTW89_ACMA][4] = 40, [1][0][RTW89_CN][4] = 26, [1][0][RTW89_UK][4] = 40, + [1][0][RTW89_MEXICO][4] = 64, + [1][0][RTW89_UKRAINE][4] = 32, + [1][0][RTW89_CHILE][4] = 64, + [1][0][RTW89_QATAR][4] = 40, [1][0][RTW89_FCC][6] = 64, [1][0][RTW89_ETSI][6] = 40, [1][0][RTW89_MKK][6] = 40, [1][0][RTW89_IC][6] = 42, - [1][0][RTW89_KCC][6] = 24, + [1][0][RTW89_KCC][6] = 32, [1][0][RTW89_ACMA][6] = 40, [1][0][RTW89_CN][6] = 26, [1][0][RTW89_UK][6] = 40, + [1][0][RTW89_MEXICO][6] = 64, + [1][0][RTW89_UKRAINE][6] = 32, + [1][0][RTW89_CHILE][6] = 64, + [1][0][RTW89_QATAR][6] = 40, [1][0][RTW89_FCC][8] = 62, [1][0][RTW89_ETSI][8] = 40, [1][0][RTW89_MKK][8] = 34, [1][0][RTW89_IC][8] = 62, - [1][0][RTW89_KCC][8] = 52, + [1][0][RTW89_KCC][8] = 50, [1][0][RTW89_ACMA][8] = 40, [1][0][RTW89_CN][8] = 26, [1][0][RTW89_UK][8] = 40, + [1][0][RTW89_MEXICO][8] = 62, + [1][0][RTW89_UKRAINE][8] = 32, + [1][0][RTW89_CHILE][8] = 62, + [1][0][RTW89_QATAR][8] = 40, [1][0][RTW89_FCC][10] = 62, [1][0][RTW89_ETSI][10] = 40, [1][0][RTW89_MKK][10] = 34, [1][0][RTW89_IC][10] = 62, - [1][0][RTW89_KCC][10] = 52, + [1][0][RTW89_KCC][10] = 50, [1][0][RTW89_ACMA][10] = 40, [1][0][RTW89_CN][10] = 26, [1][0][RTW89_UK][10] = 40, + [1][0][RTW89_MEXICO][10] = 62, + [1][0][RTW89_UKRAINE][10] = 32, + [1][0][RTW89_CHILE][10] = 62, + [1][0][RTW89_QATAR][10] = 40, [1][0][RTW89_FCC][12] = 62, [1][0][RTW89_ETSI][12] = 40, [1][0][RTW89_MKK][12] = 46, [1][0][RTW89_IC][12] = 62, - [1][0][RTW89_KCC][12] = 52, + [1][0][RTW89_KCC][12] = 50, [1][0][RTW89_ACMA][12] = 40, [1][0][RTW89_CN][12] = 26, [1][0][RTW89_UK][12] = 40, + [1][0][RTW89_MEXICO][12] = 62, + [1][0][RTW89_UKRAINE][12] = 32, + [1][0][RTW89_CHILE][12] = 62, + [1][0][RTW89_QATAR][12] = 40, [1][0][RTW89_FCC][14] = 62, [1][0][RTW89_ETSI][14] = 40, [1][0][RTW89_MKK][14] = 46, [1][0][RTW89_IC][14] = 62, - [1][0][RTW89_KCC][14] = 52, + [1][0][RTW89_KCC][14] = 50, [1][0][RTW89_ACMA][14] = 40, [1][0][RTW89_CN][14] = 26, [1][0][RTW89_UK][14] = 40, + [1][0][RTW89_MEXICO][14] = 62, + [1][0][RTW89_UKRAINE][14] = 32, + [1][0][RTW89_CHILE][14] = 62, + [1][0][RTW89_QATAR][14] = 40, [1][0][RTW89_FCC][15] = 62, [1][0][RTW89_ETSI][15] = 40, [1][0][RTW89_MKK][15] = 62, @@ -35432,6 +37562,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][15] = 40, [1][0][RTW89_CN][15] = 127, [1][0][RTW89_UK][15] = 40, + [1][0][RTW89_MEXICO][15] = 62, + [1][0][RTW89_UKRAINE][15] = 32, + [1][0][RTW89_CHILE][15] = 62, + [1][0][RTW89_QATAR][15] = 40, [1][0][RTW89_FCC][17] = 62, [1][0][RTW89_ETSI][17] = 40, [1][0][RTW89_MKK][17] = 68, @@ -35440,6 +37574,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][17] = 40, [1][0][RTW89_CN][17] = 127, [1][0][RTW89_UK][17] = 40, + [1][0][RTW89_MEXICO][17] = 62, + [1][0][RTW89_UKRAINE][17] = 32, + [1][0][RTW89_CHILE][17] = 62, + [1][0][RTW89_QATAR][17] = 40, [1][0][RTW89_FCC][19] = 64, [1][0][RTW89_ETSI][19] = 40, [1][0][RTW89_MKK][19] = 68, @@ -35448,6 +37586,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][19] = 40, [1][0][RTW89_CN][19] = 127, [1][0][RTW89_UK][19] = 40, + [1][0][RTW89_MEXICO][19] = 64, + [1][0][RTW89_UKRAINE][19] = 32, + [1][0][RTW89_CHILE][19] = 64, + [1][0][RTW89_QATAR][19] = 40, [1][0][RTW89_FCC][21] = 64, [1][0][RTW89_ETSI][21] = 40, [1][0][RTW89_MKK][21] = 68, @@ -35456,6 +37598,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][21] = 40, [1][0][RTW89_CN][21] = 127, [1][0][RTW89_UK][21] = 40, + [1][0][RTW89_MEXICO][21] = 64, + [1][0][RTW89_UKRAINE][21] = 32, + [1][0][RTW89_CHILE][21] = 64, + [1][0][RTW89_QATAR][21] = 40, [1][0][RTW89_FCC][23] = 64, [1][0][RTW89_ETSI][23] = 40, [1][0][RTW89_MKK][23] = 68, @@ -35464,6 +37610,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][23] = 40, [1][0][RTW89_CN][23] = 127, [1][0][RTW89_UK][23] = 40, + [1][0][RTW89_MEXICO][23] = 64, + [1][0][RTW89_UKRAINE][23] = 32, + [1][0][RTW89_CHILE][23] = 64, + [1][0][RTW89_QATAR][23] = 40, [1][0][RTW89_FCC][25] = 64, [1][0][RTW89_ETSI][25] = 40, [1][0][RTW89_MKK][25] = 68, @@ -35472,6 +37622,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][25] = 127, [1][0][RTW89_CN][25] = 127, [1][0][RTW89_UK][25] = 40, + [1][0][RTW89_MEXICO][25] = 64, + [1][0][RTW89_UKRAINE][25] = 32, + [1][0][RTW89_CHILE][25] = 64, + [1][0][RTW89_QATAR][25] = 40, [1][0][RTW89_FCC][27] = 64, [1][0][RTW89_ETSI][27] = 42, [1][0][RTW89_MKK][27] = 68, @@ -35480,6 +37634,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][27] = 127, [1][0][RTW89_CN][27] = 127, [1][0][RTW89_UK][27] = 42, + [1][0][RTW89_MEXICO][27] = 64, + [1][0][RTW89_UKRAINE][27] = 32, + [1][0][RTW89_CHILE][27] = 64, + [1][0][RTW89_QATAR][27] = 42, [1][0][RTW89_FCC][29] = 64, [1][0][RTW89_ETSI][29] = 42, [1][0][RTW89_MKK][29] = 68, @@ -35488,38 +37646,58 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][29] = 127, [1][0][RTW89_CN][29] = 127, [1][0][RTW89_UK][29] = 42, + [1][0][RTW89_MEXICO][29] = 64, + [1][0][RTW89_UKRAINE][29] = 32, + [1][0][RTW89_CHILE][29] = 64, + [1][0][RTW89_QATAR][29] = 42, [1][0][RTW89_FCC][31] = 64, [1][0][RTW89_ETSI][31] = 42, [1][0][RTW89_MKK][31] = 68, [1][0][RTW89_IC][31] = 56, - [1][0][RTW89_KCC][31] = 52, + [1][0][RTW89_KCC][31] = 50, [1][0][RTW89_ACMA][31] = 42, [1][0][RTW89_CN][31] = 127, [1][0][RTW89_UK][31] = 42, + [1][0][RTW89_MEXICO][31] = 64, + [1][0][RTW89_UKRAINE][31] = 32, + [1][0][RTW89_CHILE][31] = 64, + [1][0][RTW89_QATAR][31] = 42, [1][0][RTW89_FCC][33] = 56, [1][0][RTW89_ETSI][33] = 42, [1][0][RTW89_MKK][33] = 68, [1][0][RTW89_IC][33] = 56, - [1][0][RTW89_KCC][33] = 52, + [1][0][RTW89_KCC][33] = 50, [1][0][RTW89_ACMA][33] = 42, [1][0][RTW89_CN][33] = 127, [1][0][RTW89_UK][33] = 42, + [1][0][RTW89_MEXICO][33] = 56, + [1][0][RTW89_UKRAINE][33] = 32, + [1][0][RTW89_CHILE][33] = 56, + [1][0][RTW89_QATAR][33] = 42, [1][0][RTW89_FCC][35] = 56, [1][0][RTW89_ETSI][35] = 42, [1][0][RTW89_MKK][35] = 68, [1][0][RTW89_IC][35] = 56, - [1][0][RTW89_KCC][35] = 52, + [1][0][RTW89_KCC][35] = 50, [1][0][RTW89_ACMA][35] = 42, [1][0][RTW89_CN][35] = 127, [1][0][RTW89_UK][35] = 42, + [1][0][RTW89_MEXICO][35] = 56, + [1][0][RTW89_UKRAINE][35] = 32, + [1][0][RTW89_CHILE][35] = 56, + [1][0][RTW89_QATAR][35] = 42, [1][0][RTW89_FCC][37] = 66, [1][0][RTW89_ETSI][37] = 127, [1][0][RTW89_MKK][37] = 68, [1][0][RTW89_IC][37] = 66, - [1][0][RTW89_KCC][37] = 52, + [1][0][RTW89_KCC][37] = 50, [1][0][RTW89_ACMA][37] = 66, [1][0][RTW89_CN][37] = 127, [1][0][RTW89_UK][37] = 42, + [1][0][RTW89_MEXICO][37] = 66, + [1][0][RTW89_UKRAINE][37] = 127, + [1][0][RTW89_CHILE][37] = 66, + [1][0][RTW89_QATAR][37] = 127, [1][0][RTW89_FCC][38] = 76, [1][0][RTW89_ETSI][38] = 28, [1][0][RTW89_MKK][38] = 127, @@ -35528,6 +37706,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][38] = 76, [1][0][RTW89_CN][38] = 66, [1][0][RTW89_UK][38] = 44, + [1][0][RTW89_MEXICO][38] = 76, + [1][0][RTW89_UKRAINE][38] = 26, + [1][0][RTW89_CHILE][38] = 76, + [1][0][RTW89_QATAR][38] = 26, [1][0][RTW89_FCC][40] = 76, [1][0][RTW89_ETSI][40] = 28, [1][0][RTW89_MKK][40] = 127, @@ -35536,6 +37718,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][40] = 76, [1][0][RTW89_CN][40] = 66, [1][0][RTW89_UK][40] = 44, + [1][0][RTW89_MEXICO][40] = 76, + [1][0][RTW89_UKRAINE][40] = 26, + [1][0][RTW89_CHILE][40] = 76, + [1][0][RTW89_QATAR][40] = 26, [1][0][RTW89_FCC][42] = 68, [1][0][RTW89_ETSI][42] = 28, [1][0][RTW89_MKK][42] = 127, @@ -35544,6 +37730,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][42] = 68, [1][0][RTW89_CN][42] = 66, [1][0][RTW89_UK][42] = 44, + [1][0][RTW89_MEXICO][42] = 68, + [1][0][RTW89_UKRAINE][42] = 26, + [1][0][RTW89_CHILE][42] = 68, + [1][0][RTW89_QATAR][42] = 26, [1][0][RTW89_FCC][44] = 70, [1][0][RTW89_ETSI][44] = 28, [1][0][RTW89_MKK][44] = 127, @@ -35552,6 +37742,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][44] = 70, [1][0][RTW89_CN][44] = 66, [1][0][RTW89_UK][44] = 42, + [1][0][RTW89_MEXICO][44] = 70, + [1][0][RTW89_UKRAINE][44] = 26, + [1][0][RTW89_CHILE][44] = 70, + [1][0][RTW89_QATAR][44] = 26, [1][0][RTW89_FCC][46] = 70, [1][0][RTW89_ETSI][46] = 28, [1][0][RTW89_MKK][46] = 127, @@ -35560,6 +37754,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][46] = 70, [1][0][RTW89_CN][46] = 66, [1][0][RTW89_UK][46] = 42, + [1][0][RTW89_MEXICO][46] = 70, + [1][0][RTW89_UKRAINE][46] = 26, + [1][0][RTW89_CHILE][46] = 70, + [1][0][RTW89_QATAR][46] = 26, [1][0][RTW89_FCC][48] = 56, [1][0][RTW89_ETSI][48] = 127, [1][0][RTW89_MKK][48] = 127, @@ -35568,6 +37766,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][48] = 127, [1][0][RTW89_CN][48] = 127, [1][0][RTW89_UK][48] = 127, + [1][0][RTW89_MEXICO][48] = 127, + [1][0][RTW89_UKRAINE][48] = 127, + [1][0][RTW89_CHILE][48] = 127, + [1][0][RTW89_QATAR][48] = 127, [1][0][RTW89_FCC][50] = 58, [1][0][RTW89_ETSI][50] = 127, [1][0][RTW89_MKK][50] = 127, @@ -35576,6 +37778,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][50] = 127, [1][0][RTW89_CN][50] = 127, [1][0][RTW89_UK][50] = 127, + [1][0][RTW89_MEXICO][50] = 127, + [1][0][RTW89_UKRAINE][50] = 127, + [1][0][RTW89_CHILE][50] = 127, + [1][0][RTW89_QATAR][50] = 127, [1][0][RTW89_FCC][52] = 56, [1][0][RTW89_ETSI][52] = 127, [1][0][RTW89_MKK][52] = 127, @@ -35584,54 +37790,82 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_ACMA][52] = 127, [1][0][RTW89_CN][52] = 127, [1][0][RTW89_UK][52] = 127, + [1][0][RTW89_MEXICO][52] = 127, + [1][0][RTW89_UKRAINE][52] = 127, + [1][0][RTW89_CHILE][52] = 127, + [1][0][RTW89_QATAR][52] = 127, [1][1][RTW89_FCC][0] = 44, [1][1][RTW89_ETSI][0] = 30, [1][1][RTW89_MKK][0] = 34, [1][1][RTW89_IC][0] = 20, - [1][1][RTW89_KCC][0] = 34, + [1][1][RTW89_KCC][0] = 40, [1][1][RTW89_ACMA][0] = 30, [1][1][RTW89_CN][0] = 14, [1][1][RTW89_UK][0] = 30, + [1][1][RTW89_MEXICO][0] = 44, + [1][1][RTW89_UKRAINE][0] = 20, + [1][1][RTW89_CHILE][0] = 44, + [1][1][RTW89_QATAR][0] = 30, [1][1][RTW89_FCC][2] = 44, [1][1][RTW89_ETSI][2] = 30, [1][1][RTW89_MKK][2] = 34, [1][1][RTW89_IC][2] = 18, - [1][1][RTW89_KCC][2] = 34, + [1][1][RTW89_KCC][2] = 40, [1][1][RTW89_ACMA][2] = 30, [1][1][RTW89_CN][2] = 14, [1][1][RTW89_UK][2] = 30, + [1][1][RTW89_MEXICO][2] = 44, + [1][1][RTW89_UKRAINE][2] = 20, + [1][1][RTW89_CHILE][2] = 44, + [1][1][RTW89_QATAR][2] = 30, [1][1][RTW89_FCC][4] = 46, [1][1][RTW89_ETSI][4] = 30, [1][1][RTW89_MKK][4] = 26, [1][1][RTW89_IC][4] = 20, - [1][1][RTW89_KCC][4] = 34, + [1][1][RTW89_KCC][4] = 40, [1][1][RTW89_ACMA][4] = 30, [1][1][RTW89_CN][4] = 14, [1][1][RTW89_UK][4] = 30, + [1][1][RTW89_MEXICO][4] = 46, + [1][1][RTW89_UKRAINE][4] = 20, + [1][1][RTW89_CHILE][4] = 46, + [1][1][RTW89_QATAR][4] = 30, [1][1][RTW89_FCC][6] = 46, [1][1][RTW89_ETSI][6] = 30, [1][1][RTW89_MKK][6] = 26, [1][1][RTW89_IC][6] = 20, - [1][1][RTW89_KCC][6] = 8, + [1][1][RTW89_KCC][6] = 18, [1][1][RTW89_ACMA][6] = 30, [1][1][RTW89_CN][6] = 14, [1][1][RTW89_UK][6] = 30, + [1][1][RTW89_MEXICO][6] = 46, + [1][1][RTW89_UKRAINE][6] = 20, + [1][1][RTW89_CHILE][6] = 46, + [1][1][RTW89_QATAR][6] = 30, [1][1][RTW89_FCC][8] = 44, [1][1][RTW89_ETSI][8] = 30, [1][1][RTW89_MKK][8] = 20, [1][1][RTW89_IC][8] = 44, - [1][1][RTW89_KCC][8] = 34, + [1][1][RTW89_KCC][8] = 38, [1][1][RTW89_ACMA][8] = 30, [1][1][RTW89_CN][8] = 14, [1][1][RTW89_UK][8] = 30, + [1][1][RTW89_MEXICO][8] = 44, + [1][1][RTW89_UKRAINE][8] = 20, + [1][1][RTW89_CHILE][8] = 44, + [1][1][RTW89_QATAR][8] = 30, [1][1][RTW89_FCC][10] = 44, [1][1][RTW89_ETSI][10] = 30, [1][1][RTW89_MKK][10] = 20, [1][1][RTW89_IC][10] = 44, - [1][1][RTW89_KCC][10] = 34, + [1][1][RTW89_KCC][10] = 38, [1][1][RTW89_ACMA][10] = 30, [1][1][RTW89_CN][10] = 14, [1][1][RTW89_UK][10] = 30, + [1][1][RTW89_MEXICO][10] = 44, + [1][1][RTW89_UKRAINE][10] = 20, + [1][1][RTW89_CHILE][10] = 44, + [1][1][RTW89_QATAR][10] = 30, [1][1][RTW89_FCC][12] = 44, [1][1][RTW89_ETSI][12] = 30, [1][1][RTW89_MKK][12] = 34, @@ -35640,6 +37874,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_ACMA][12] = 30, [1][1][RTW89_CN][12] = 14, [1][1][RTW89_UK][12] = 30, + [1][1][RTW89_MEXICO][12] = 44, + [1][1][RTW89_UKRAINE][12] = 20, + [1][1][RTW89_CHILE][12] = 44, + [1][1][RTW89_QATAR][12] = 30, [1][1][RTW89_FCC][14] = 44, [1][1][RTW89_ETSI][14] = 30, [1][1][RTW89_MKK][14] = 34, @@ -35648,142 +37886,214 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_ACMA][14] = 30, [1][1][RTW89_CN][14] = 14, [1][1][RTW89_UK][14] = 30, + [1][1][RTW89_MEXICO][14] = 44, + [1][1][RTW89_UKRAINE][14] = 20, + [1][1][RTW89_CHILE][14] = 44, + [1][1][RTW89_QATAR][14] = 30, [1][1][RTW89_FCC][15] = 44, [1][1][RTW89_ETSI][15] = 28, [1][1][RTW89_MKK][15] = 56, [1][1][RTW89_IC][15] = 44, - [1][1][RTW89_KCC][15] = 36, + [1][1][RTW89_KCC][15] = 38, [1][1][RTW89_ACMA][15] = 28, [1][1][RTW89_CN][15] = 127, [1][1][RTW89_UK][15] = 28, + [1][1][RTW89_MEXICO][15] = 44, + [1][1][RTW89_UKRAINE][15] = 20, + [1][1][RTW89_CHILE][15] = 44, + [1][1][RTW89_QATAR][15] = 28, [1][1][RTW89_FCC][17] = 44, [1][1][RTW89_ETSI][17] = 28, [1][1][RTW89_MKK][17] = 58, [1][1][RTW89_IC][17] = 44, - [1][1][RTW89_KCC][17] = 36, + [1][1][RTW89_KCC][17] = 38, [1][1][RTW89_ACMA][17] = 28, [1][1][RTW89_CN][17] = 127, [1][1][RTW89_UK][17] = 28, + [1][1][RTW89_MEXICO][17] = 44, + [1][1][RTW89_UKRAINE][17] = 20, + [1][1][RTW89_CHILE][17] = 44, + [1][1][RTW89_QATAR][17] = 28, [1][1][RTW89_FCC][19] = 44, [1][1][RTW89_ETSI][19] = 28, [1][1][RTW89_MKK][19] = 58, [1][1][RTW89_IC][19] = 44, - [1][1][RTW89_KCC][19] = 36, + [1][1][RTW89_KCC][19] = 38, [1][1][RTW89_ACMA][19] = 28, [1][1][RTW89_CN][19] = 127, [1][1][RTW89_UK][19] = 28, + [1][1][RTW89_MEXICO][19] = 44, + [1][1][RTW89_UKRAINE][19] = 20, + [1][1][RTW89_CHILE][19] = 44, + [1][1][RTW89_QATAR][19] = 28, [1][1][RTW89_FCC][21] = 44, [1][1][RTW89_ETSI][21] = 28, [1][1][RTW89_MKK][21] = 58, [1][1][RTW89_IC][21] = 44, - [1][1][RTW89_KCC][21] = 36, + [1][1][RTW89_KCC][21] = 38, [1][1][RTW89_ACMA][21] = 28, [1][1][RTW89_CN][21] = 127, [1][1][RTW89_UK][21] = 28, + [1][1][RTW89_MEXICO][21] = 44, + [1][1][RTW89_UKRAINE][21] = 20, + [1][1][RTW89_CHILE][21] = 44, + [1][1][RTW89_QATAR][21] = 28, [1][1][RTW89_FCC][23] = 44, [1][1][RTW89_ETSI][23] = 28, [1][1][RTW89_MKK][23] = 58, [1][1][RTW89_IC][23] = 44, - [1][1][RTW89_KCC][23] = 36, + [1][1][RTW89_KCC][23] = 38, [1][1][RTW89_ACMA][23] = 28, [1][1][RTW89_CN][23] = 127, [1][1][RTW89_UK][23] = 28, + [1][1][RTW89_MEXICO][23] = 44, + [1][1][RTW89_UKRAINE][23] = 20, + [1][1][RTW89_CHILE][23] = 44, + [1][1][RTW89_QATAR][23] = 28, [1][1][RTW89_FCC][25] = 44, [1][1][RTW89_ETSI][25] = 28, [1][1][RTW89_MKK][25] = 58, [1][1][RTW89_IC][25] = 127, - [1][1][RTW89_KCC][25] = 36, + [1][1][RTW89_KCC][25] = 38, [1][1][RTW89_ACMA][25] = 127, [1][1][RTW89_CN][25] = 127, [1][1][RTW89_UK][25] = 28, + [1][1][RTW89_MEXICO][25] = 44, + [1][1][RTW89_UKRAINE][25] = 20, + [1][1][RTW89_CHILE][25] = 44, + [1][1][RTW89_QATAR][25] = 28, [1][1][RTW89_FCC][27] = 44, [1][1][RTW89_ETSI][27] = 30, [1][1][RTW89_MKK][27] = 58, [1][1][RTW89_IC][27] = 127, - [1][1][RTW89_KCC][27] = 36, + [1][1][RTW89_KCC][27] = 38, [1][1][RTW89_ACMA][27] = 127, [1][1][RTW89_CN][27] = 127, [1][1][RTW89_UK][27] = 30, + [1][1][RTW89_MEXICO][27] = 44, + [1][1][RTW89_UKRAINE][27] = 20, + [1][1][RTW89_CHILE][27] = 44, + [1][1][RTW89_QATAR][27] = 30, [1][1][RTW89_FCC][29] = 44, [1][1][RTW89_ETSI][29] = 30, [1][1][RTW89_MKK][29] = 58, [1][1][RTW89_IC][29] = 127, - [1][1][RTW89_KCC][29] = 36, + [1][1][RTW89_KCC][29] = 38, [1][1][RTW89_ACMA][29] = 127, [1][1][RTW89_CN][29] = 127, [1][1][RTW89_UK][29] = 30, + [1][1][RTW89_MEXICO][29] = 44, + [1][1][RTW89_UKRAINE][29] = 20, + [1][1][RTW89_CHILE][29] = 44, + [1][1][RTW89_QATAR][29] = 30, [1][1][RTW89_FCC][31] = 44, [1][1][RTW89_ETSI][31] = 30, [1][1][RTW89_MKK][31] = 58, [1][1][RTW89_IC][31] = 38, - [1][1][RTW89_KCC][31] = 36, + [1][1][RTW89_KCC][31] = 40, [1][1][RTW89_ACMA][31] = 30, [1][1][RTW89_CN][31] = 127, [1][1][RTW89_UK][31] = 30, + [1][1][RTW89_MEXICO][31] = 44, + [1][1][RTW89_UKRAINE][31] = 20, + [1][1][RTW89_CHILE][31] = 44, + [1][1][RTW89_QATAR][31] = 30, [1][1][RTW89_FCC][33] = 38, [1][1][RTW89_ETSI][33] = 30, [1][1][RTW89_MKK][33] = 58, [1][1][RTW89_IC][33] = 38, - [1][1][RTW89_KCC][33] = 36, + [1][1][RTW89_KCC][33] = 40, [1][1][RTW89_ACMA][33] = 30, [1][1][RTW89_CN][33] = 127, [1][1][RTW89_UK][33] = 30, + [1][1][RTW89_MEXICO][33] = 38, + [1][1][RTW89_UKRAINE][33] = 20, + [1][1][RTW89_CHILE][33] = 38, + [1][1][RTW89_QATAR][33] = 30, [1][1][RTW89_FCC][35] = 38, [1][1][RTW89_ETSI][35] = 30, [1][1][RTW89_MKK][35] = 58, [1][1][RTW89_IC][35] = 38, - [1][1][RTW89_KCC][35] = 36, + [1][1][RTW89_KCC][35] = 40, [1][1][RTW89_ACMA][35] = 30, [1][1][RTW89_CN][35] = 127, [1][1][RTW89_UK][35] = 30, + [1][1][RTW89_MEXICO][35] = 38, + [1][1][RTW89_UKRAINE][35] = 20, + [1][1][RTW89_CHILE][35] = 38, + [1][1][RTW89_QATAR][35] = 30, [1][1][RTW89_FCC][37] = 46, [1][1][RTW89_ETSI][37] = 127, [1][1][RTW89_MKK][37] = 58, [1][1][RTW89_IC][37] = 46, - [1][1][RTW89_KCC][37] = 36, + [1][1][RTW89_KCC][37] = 40, [1][1][RTW89_ACMA][37] = 46, [1][1][RTW89_CN][37] = 127, [1][1][RTW89_UK][37] = 32, + [1][1][RTW89_MEXICO][37] = 46, + [1][1][RTW89_UKRAINE][37] = 127, + [1][1][RTW89_CHILE][37] = 46, + [1][1][RTW89_QATAR][37] = 127, [1][1][RTW89_FCC][38] = 74, [1][1][RTW89_ETSI][38] = 16, [1][1][RTW89_MKK][38] = 127, [1][1][RTW89_IC][38] = 74, - [1][1][RTW89_KCC][38] = 36, + [1][1][RTW89_KCC][38] = 38, [1][1][RTW89_ACMA][38] = 74, [1][1][RTW89_CN][38] = 54, [1][1][RTW89_UK][38] = 30, + [1][1][RTW89_MEXICO][38] = 74, + [1][1][RTW89_UKRAINE][38] = 14, + [1][1][RTW89_CHILE][38] = 72, + [1][1][RTW89_QATAR][38] = 14, [1][1][RTW89_FCC][40] = 74, [1][1][RTW89_ETSI][40] = 16, [1][1][RTW89_MKK][40] = 127, [1][1][RTW89_IC][40] = 74, - [1][1][RTW89_KCC][40] = 36, + [1][1][RTW89_KCC][40] = 38, [1][1][RTW89_ACMA][40] = 74, [1][1][RTW89_CN][40] = 54, [1][1][RTW89_UK][40] = 30, + [1][1][RTW89_MEXICO][40] = 74, + [1][1][RTW89_UKRAINE][40] = 14, + [1][1][RTW89_CHILE][40] = 72, + [1][1][RTW89_QATAR][40] = 14, [1][1][RTW89_FCC][42] = 74, [1][1][RTW89_ETSI][42] = 16, [1][1][RTW89_MKK][42] = 127, [1][1][RTW89_IC][42] = 74, - [1][1][RTW89_KCC][42] = 36, + [1][1][RTW89_KCC][42] = 38, [1][1][RTW89_ACMA][42] = 74, [1][1][RTW89_CN][42] = 54, [1][1][RTW89_UK][42] = 30, + [1][1][RTW89_MEXICO][42] = 74, + [1][1][RTW89_UKRAINE][42] = 14, + [1][1][RTW89_CHILE][42] = 72, + [1][1][RTW89_QATAR][42] = 14, [1][1][RTW89_FCC][44] = 74, [1][1][RTW89_ETSI][44] = 16, [1][1][RTW89_MKK][44] = 127, [1][1][RTW89_IC][44] = 74, - [1][1][RTW89_KCC][44] = 36, + [1][1][RTW89_KCC][44] = 38, [1][1][RTW89_ACMA][44] = 74, [1][1][RTW89_CN][44] = 54, [1][1][RTW89_UK][44] = 30, + [1][1][RTW89_MEXICO][44] = 74, + [1][1][RTW89_UKRAINE][44] = 14, + [1][1][RTW89_CHILE][44] = 72, + [1][1][RTW89_QATAR][44] = 14, [1][1][RTW89_FCC][46] = 74, [1][1][RTW89_ETSI][46] = 16, [1][1][RTW89_MKK][46] = 127, [1][1][RTW89_IC][46] = 74, - [1][1][RTW89_KCC][46] = 36, + [1][1][RTW89_KCC][46] = 38, [1][1][RTW89_ACMA][46] = 74, [1][1][RTW89_CN][46] = 54, [1][1][RTW89_UK][46] = 30, + [1][1][RTW89_MEXICO][46] = 74, + [1][1][RTW89_UKRAINE][46] = 14, + [1][1][RTW89_CHILE][46] = 72, + [1][1][RTW89_QATAR][46] = 14, [1][1][RTW89_FCC][48] = 34, [1][1][RTW89_ETSI][48] = 127, [1][1][RTW89_MKK][48] = 127, @@ -35792,6 +38102,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_ACMA][48] = 127, [1][1][RTW89_CN][48] = 127, [1][1][RTW89_UK][48] = 127, + [1][1][RTW89_MEXICO][48] = 127, + [1][1][RTW89_UKRAINE][48] = 127, + [1][1][RTW89_CHILE][48] = 127, + [1][1][RTW89_QATAR][48] = 127, [1][1][RTW89_FCC][50] = 34, [1][1][RTW89_ETSI][50] = 127, [1][1][RTW89_MKK][50] = 127, @@ -35800,6 +38114,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_ACMA][50] = 127, [1][1][RTW89_CN][50] = 127, [1][1][RTW89_UK][50] = 127, + [1][1][RTW89_MEXICO][50] = 127, + [1][1][RTW89_UKRAINE][50] = 127, + [1][1][RTW89_CHILE][50] = 127, + [1][1][RTW89_QATAR][50] = 127, [1][1][RTW89_FCC][52] = 30, [1][1][RTW89_ETSI][52] = 127, [1][1][RTW89_MKK][52] = 127, @@ -35808,206 +38126,310 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_ACMA][52] = 127, [1][1][RTW89_CN][52] = 127, [1][1][RTW89_UK][52] = 127, + [1][1][RTW89_MEXICO][52] = 127, + [1][1][RTW89_UKRAINE][52] = 127, + [1][1][RTW89_CHILE][52] = 127, + [1][1][RTW89_QATAR][52] = 127, [2][0][RTW89_FCC][0] = 68, [2][0][RTW89_ETSI][0] = 52, [2][0][RTW89_MKK][0] = 60, [2][0][RTW89_IC][0] = 52, - [2][0][RTW89_KCC][0] = 64, + [2][0][RTW89_KCC][0] = 60, [2][0][RTW89_ACMA][0] = 52, [2][0][RTW89_CN][0] = 40, [2][0][RTW89_UK][0] = 52, + [2][0][RTW89_MEXICO][0] = 62, + [2][0][RTW89_UKRAINE][0] = 46, + [2][0][RTW89_CHILE][0] = 68, + [2][0][RTW89_QATAR][0] = 52, [2][0][RTW89_FCC][2] = 64, [2][0][RTW89_ETSI][2] = 52, [2][0][RTW89_MKK][2] = 60, [2][0][RTW89_IC][2] = 50, - [2][0][RTW89_KCC][2] = 64, + [2][0][RTW89_KCC][2] = 60, [2][0][RTW89_ACMA][2] = 52, [2][0][RTW89_CN][2] = 40, [2][0][RTW89_UK][2] = 52, + [2][0][RTW89_MEXICO][2] = 62, + [2][0][RTW89_UKRAINE][2] = 46, + [2][0][RTW89_CHILE][2] = 64, + [2][0][RTW89_QATAR][2] = 52, [2][0][RTW89_FCC][4] = 68, [2][0][RTW89_ETSI][4] = 52, [2][0][RTW89_MKK][4] = 50, [2][0][RTW89_IC][4] = 50, - [2][0][RTW89_KCC][4] = 64, + [2][0][RTW89_KCC][4] = 60, [2][0][RTW89_ACMA][4] = 52, [2][0][RTW89_CN][4] = 40, [2][0][RTW89_UK][4] = 52, + [2][0][RTW89_MEXICO][4] = 62, + [2][0][RTW89_UKRAINE][4] = 46, + [2][0][RTW89_CHILE][4] = 68, + [2][0][RTW89_QATAR][4] = 52, [2][0][RTW89_FCC][6] = 68, [2][0][RTW89_ETSI][6] = 52, [2][0][RTW89_MKK][6] = 50, [2][0][RTW89_IC][6] = 50, - [2][0][RTW89_KCC][6] = 36, + [2][0][RTW89_KCC][6] = 38, [2][0][RTW89_ACMA][6] = 52, [2][0][RTW89_CN][6] = 40, [2][0][RTW89_UK][6] = 52, + [2][0][RTW89_MEXICO][6] = 62, + [2][0][RTW89_UKRAINE][6] = 46, + [2][0][RTW89_CHILE][6] = 68, + [2][0][RTW89_QATAR][6] = 52, [2][0][RTW89_FCC][8] = 68, [2][0][RTW89_ETSI][8] = 52, [2][0][RTW89_MKK][8] = 44, [2][0][RTW89_IC][8] = 64, - [2][0][RTW89_KCC][8] = 62, + [2][0][RTW89_KCC][8] = 56, [2][0][RTW89_ACMA][8] = 52, [2][0][RTW89_CN][8] = 40, [2][0][RTW89_UK][8] = 52, + [2][0][RTW89_MEXICO][8] = 68, + [2][0][RTW89_UKRAINE][8] = 46, + [2][0][RTW89_CHILE][8] = 68, + [2][0][RTW89_QATAR][8] = 52, [2][0][RTW89_FCC][10] = 68, [2][0][RTW89_ETSI][10] = 52, [2][0][RTW89_MKK][10] = 44, [2][0][RTW89_IC][10] = 64, - [2][0][RTW89_KCC][10] = 62, + [2][0][RTW89_KCC][10] = 56, [2][0][RTW89_ACMA][10] = 52, [2][0][RTW89_CN][10] = 40, [2][0][RTW89_UK][10] = 52, + [2][0][RTW89_MEXICO][10] = 68, + [2][0][RTW89_UKRAINE][10] = 46, + [2][0][RTW89_CHILE][10] = 68, + [2][0][RTW89_QATAR][10] = 52, [2][0][RTW89_FCC][12] = 68, [2][0][RTW89_ETSI][12] = 52, [2][0][RTW89_MKK][12] = 58, [2][0][RTW89_IC][12] = 64, - [2][0][RTW89_KCC][12] = 62, + [2][0][RTW89_KCC][12] = 58, [2][0][RTW89_ACMA][12] = 52, [2][0][RTW89_CN][12] = 40, [2][0][RTW89_UK][12] = 52, + [2][0][RTW89_MEXICO][12] = 68, + [2][0][RTW89_UKRAINE][12] = 46, + [2][0][RTW89_CHILE][12] = 68, + [2][0][RTW89_QATAR][12] = 52, [2][0][RTW89_FCC][14] = 68, [2][0][RTW89_ETSI][14] = 52, [2][0][RTW89_MKK][14] = 58, [2][0][RTW89_IC][14] = 64, - [2][0][RTW89_KCC][14] = 62, + [2][0][RTW89_KCC][14] = 58, [2][0][RTW89_ACMA][14] = 52, [2][0][RTW89_CN][14] = 40, [2][0][RTW89_UK][14] = 52, + [2][0][RTW89_MEXICO][14] = 68, + [2][0][RTW89_UKRAINE][14] = 46, + [2][0][RTW89_CHILE][14] = 68, + [2][0][RTW89_QATAR][14] = 52, [2][0][RTW89_FCC][15] = 68, [2][0][RTW89_ETSI][15] = 52, [2][0][RTW89_MKK][15] = 68, [2][0][RTW89_IC][15] = 68, - [2][0][RTW89_KCC][15] = 62, + [2][0][RTW89_KCC][15] = 58, [2][0][RTW89_ACMA][15] = 52, [2][0][RTW89_CN][15] = 127, [2][0][RTW89_UK][15] = 52, + [2][0][RTW89_MEXICO][15] = 68, + [2][0][RTW89_UKRAINE][15] = 46, + [2][0][RTW89_CHILE][15] = 68, + [2][0][RTW89_QATAR][15] = 52, [2][0][RTW89_FCC][17] = 68, [2][0][RTW89_ETSI][17] = 52, [2][0][RTW89_MKK][17] = 74, [2][0][RTW89_IC][17] = 68, - [2][0][RTW89_KCC][17] = 62, + [2][0][RTW89_KCC][17] = 58, [2][0][RTW89_ACMA][17] = 52, [2][0][RTW89_CN][17] = 127, [2][0][RTW89_UK][17] = 52, + [2][0][RTW89_MEXICO][17] = 68, + [2][0][RTW89_UKRAINE][17] = 46, + [2][0][RTW89_CHILE][17] = 68, + [2][0][RTW89_QATAR][17] = 52, [2][0][RTW89_FCC][19] = 70, [2][0][RTW89_ETSI][19] = 52, [2][0][RTW89_MKK][19] = 74, [2][0][RTW89_IC][19] = 70, - [2][0][RTW89_KCC][19] = 62, + [2][0][RTW89_KCC][19] = 58, [2][0][RTW89_ACMA][19] = 52, [2][0][RTW89_CN][19] = 127, [2][0][RTW89_UK][19] = 52, + [2][0][RTW89_MEXICO][19] = 70, + [2][0][RTW89_UKRAINE][19] = 46, + [2][0][RTW89_CHILE][19] = 70, + [2][0][RTW89_QATAR][19] = 52, [2][0][RTW89_FCC][21] = 70, [2][0][RTW89_ETSI][21] = 52, [2][0][RTW89_MKK][21] = 74, [2][0][RTW89_IC][21] = 70, - [2][0][RTW89_KCC][21] = 62, + [2][0][RTW89_KCC][21] = 58, [2][0][RTW89_ACMA][21] = 52, [2][0][RTW89_CN][21] = 127, [2][0][RTW89_UK][21] = 52, + [2][0][RTW89_MEXICO][21] = 70, + [2][0][RTW89_UKRAINE][21] = 46, + [2][0][RTW89_CHILE][21] = 70, + [2][0][RTW89_QATAR][21] = 52, [2][0][RTW89_FCC][23] = 70, [2][0][RTW89_ETSI][23] = 52, [2][0][RTW89_MKK][23] = 74, [2][0][RTW89_IC][23] = 70, - [2][0][RTW89_KCC][23] = 62, + [2][0][RTW89_KCC][23] = 58, [2][0][RTW89_ACMA][23] = 52, [2][0][RTW89_CN][23] = 127, [2][0][RTW89_UK][23] = 52, + [2][0][RTW89_MEXICO][23] = 70, + [2][0][RTW89_UKRAINE][23] = 46, + [2][0][RTW89_CHILE][23] = 70, + [2][0][RTW89_QATAR][23] = 52, [2][0][RTW89_FCC][25] = 70, [2][0][RTW89_ETSI][25] = 52, [2][0][RTW89_MKK][25] = 74, [2][0][RTW89_IC][25] = 127, - [2][0][RTW89_KCC][25] = 62, + [2][0][RTW89_KCC][25] = 58, [2][0][RTW89_ACMA][25] = 127, [2][0][RTW89_CN][25] = 127, [2][0][RTW89_UK][25] = 52, + [2][0][RTW89_MEXICO][25] = 70, + [2][0][RTW89_UKRAINE][25] = 46, + [2][0][RTW89_CHILE][25] = 70, + [2][0][RTW89_QATAR][25] = 52, [2][0][RTW89_FCC][27] = 70, [2][0][RTW89_ETSI][27] = 52, [2][0][RTW89_MKK][27] = 74, [2][0][RTW89_IC][27] = 127, - [2][0][RTW89_KCC][27] = 62, + [2][0][RTW89_KCC][27] = 58, [2][0][RTW89_ACMA][27] = 127, [2][0][RTW89_CN][27] = 127, [2][0][RTW89_UK][27] = 52, + [2][0][RTW89_MEXICO][27] = 70, + [2][0][RTW89_UKRAINE][27] = 46, + [2][0][RTW89_CHILE][27] = 70, + [2][0][RTW89_QATAR][27] = 52, [2][0][RTW89_FCC][29] = 70, [2][0][RTW89_ETSI][29] = 52, [2][0][RTW89_MKK][29] = 74, [2][0][RTW89_IC][29] = 127, - [2][0][RTW89_KCC][29] = 62, + [2][0][RTW89_KCC][29] = 58, [2][0][RTW89_ACMA][29] = 127, [2][0][RTW89_CN][29] = 127, [2][0][RTW89_UK][29] = 52, + [2][0][RTW89_MEXICO][29] = 70, + [2][0][RTW89_UKRAINE][29] = 46, + [2][0][RTW89_CHILE][29] = 70, + [2][0][RTW89_QATAR][29] = 52, [2][0][RTW89_FCC][31] = 70, [2][0][RTW89_ETSI][31] = 52, [2][0][RTW89_MKK][31] = 74, [2][0][RTW89_IC][31] = 62, - [2][0][RTW89_KCC][31] = 62, + [2][0][RTW89_KCC][31] = 56, [2][0][RTW89_ACMA][31] = 52, [2][0][RTW89_CN][31] = 127, [2][0][RTW89_UK][31] = 52, + [2][0][RTW89_MEXICO][31] = 70, + [2][0][RTW89_UKRAINE][31] = 46, + [2][0][RTW89_CHILE][31] = 70, + [2][0][RTW89_QATAR][31] = 52, [2][0][RTW89_FCC][33] = 62, [2][0][RTW89_ETSI][33] = 52, [2][0][RTW89_MKK][33] = 74, [2][0][RTW89_IC][33] = 62, - [2][0][RTW89_KCC][33] = 62, + [2][0][RTW89_KCC][33] = 56, [2][0][RTW89_ACMA][33] = 52, [2][0][RTW89_CN][33] = 127, [2][0][RTW89_UK][33] = 52, + [2][0][RTW89_MEXICO][33] = 62, + [2][0][RTW89_UKRAINE][33] = 46, + [2][0][RTW89_CHILE][33] = 62, + [2][0][RTW89_QATAR][33] = 52, [2][0][RTW89_FCC][35] = 62, [2][0][RTW89_ETSI][35] = 52, [2][0][RTW89_MKK][35] = 74, [2][0][RTW89_IC][35] = 62, - [2][0][RTW89_KCC][35] = 62, + [2][0][RTW89_KCC][35] = 56, [2][0][RTW89_ACMA][35] = 52, [2][0][RTW89_CN][35] = 127, [2][0][RTW89_UK][35] = 52, + [2][0][RTW89_MEXICO][35] = 62, + [2][0][RTW89_UKRAINE][35] = 46, + [2][0][RTW89_CHILE][35] = 62, + [2][0][RTW89_QATAR][35] = 52, [2][0][RTW89_FCC][37] = 70, [2][0][RTW89_ETSI][37] = 127, [2][0][RTW89_MKK][37] = 74, [2][0][RTW89_IC][37] = 70, - [2][0][RTW89_KCC][37] = 62, + [2][0][RTW89_KCC][37] = 56, [2][0][RTW89_ACMA][37] = 70, [2][0][RTW89_CN][37] = 127, [2][0][RTW89_UK][37] = 52, + [2][0][RTW89_MEXICO][37] = 70, + [2][0][RTW89_UKRAINE][37] = 127, + [2][0][RTW89_CHILE][37] = 70, + [2][0][RTW89_QATAR][37] = 127, [2][0][RTW89_FCC][38] = 82, [2][0][RTW89_ETSI][38] = 28, [2][0][RTW89_MKK][38] = 127, [2][0][RTW89_IC][38] = 82, - [2][0][RTW89_KCC][38] = 64, + [2][0][RTW89_KCC][38] = 60, [2][0][RTW89_ACMA][38] = 82, [2][0][RTW89_CN][38] = 68, [2][0][RTW89_UK][38] = 54, + [2][0][RTW89_MEXICO][38] = 82, + [2][0][RTW89_UKRAINE][38] = 26, + [2][0][RTW89_CHILE][38] = 82, + [2][0][RTW89_QATAR][38] = 26, [2][0][RTW89_FCC][40] = 82, [2][0][RTW89_ETSI][40] = 28, [2][0][RTW89_MKK][40] = 127, [2][0][RTW89_IC][40] = 82, - [2][0][RTW89_KCC][40] = 64, + [2][0][RTW89_KCC][40] = 60, [2][0][RTW89_ACMA][40] = 82, [2][0][RTW89_CN][40] = 68, [2][0][RTW89_UK][40] = 54, + [2][0][RTW89_MEXICO][40] = 82, + [2][0][RTW89_UKRAINE][40] = 26, + [2][0][RTW89_CHILE][40] = 82, + [2][0][RTW89_QATAR][40] = 26, [2][0][RTW89_FCC][42] = 76, [2][0][RTW89_ETSI][42] = 28, [2][0][RTW89_MKK][42] = 127, [2][0][RTW89_IC][42] = 76, - [2][0][RTW89_KCC][42] = 64, + [2][0][RTW89_KCC][42] = 60, [2][0][RTW89_ACMA][42] = 76, [2][0][RTW89_CN][42] = 68, [2][0][RTW89_UK][42] = 54, + [2][0][RTW89_MEXICO][42] = 76, + [2][0][RTW89_UKRAINE][42] = 26, + [2][0][RTW89_CHILE][42] = 76, + [2][0][RTW89_QATAR][42] = 26, [2][0][RTW89_FCC][44] = 80, [2][0][RTW89_ETSI][44] = 28, [2][0][RTW89_MKK][44] = 127, [2][0][RTW89_IC][44] = 80, - [2][0][RTW89_KCC][44] = 64, + [2][0][RTW89_KCC][44] = 60, [2][0][RTW89_ACMA][44] = 80, [2][0][RTW89_CN][44] = 68, [2][0][RTW89_UK][44] = 54, + [2][0][RTW89_MEXICO][44] = 80, + [2][0][RTW89_UKRAINE][44] = 26, + [2][0][RTW89_CHILE][44] = 80, + [2][0][RTW89_QATAR][44] = 26, [2][0][RTW89_FCC][46] = 80, [2][0][RTW89_ETSI][46] = 28, [2][0][RTW89_MKK][46] = 127, [2][0][RTW89_IC][46] = 80, - [2][0][RTW89_KCC][46] = 64, + [2][0][RTW89_KCC][46] = 60, [2][0][RTW89_ACMA][46] = 80, [2][0][RTW89_CN][46] = 68, [2][0][RTW89_UK][46] = 54, + [2][0][RTW89_MEXICO][46] = 80, + [2][0][RTW89_UKRAINE][46] = 26, + [2][0][RTW89_CHILE][46] = 80, + [2][0][RTW89_QATAR][46] = 26, [2][0][RTW89_FCC][48] = 64, [2][0][RTW89_ETSI][48] = 127, [2][0][RTW89_MKK][48] = 127, @@ -36016,6 +38438,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ACMA][48] = 127, [2][0][RTW89_CN][48] = 127, [2][0][RTW89_UK][48] = 127, + [2][0][RTW89_MEXICO][48] = 127, + [2][0][RTW89_UKRAINE][48] = 127, + [2][0][RTW89_CHILE][48] = 127, + [2][0][RTW89_QATAR][48] = 127, [2][0][RTW89_FCC][50] = 64, [2][0][RTW89_ETSI][50] = 127, [2][0][RTW89_MKK][50] = 127, @@ -36024,6 +38450,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ACMA][50] = 127, [2][0][RTW89_CN][50] = 127, [2][0][RTW89_UK][50] = 127, + [2][0][RTW89_MEXICO][50] = 127, + [2][0][RTW89_UKRAINE][50] = 127, + [2][0][RTW89_CHILE][50] = 127, + [2][0][RTW89_QATAR][50] = 127, [2][0][RTW89_FCC][52] = 64, [2][0][RTW89_ETSI][52] = 127, [2][0][RTW89_MKK][52] = 127, @@ -36032,206 +38462,310 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ACMA][52] = 127, [2][0][RTW89_CN][52] = 127, [2][0][RTW89_UK][52] = 127, + [2][0][RTW89_MEXICO][52] = 127, + [2][0][RTW89_UKRAINE][52] = 127, + [2][0][RTW89_CHILE][52] = 127, + [2][0][RTW89_QATAR][52] = 127, [2][1][RTW89_FCC][0] = 50, [2][1][RTW89_ETSI][0] = 40, [2][1][RTW89_MKK][0] = 44, [2][1][RTW89_IC][0] = 26, - [2][1][RTW89_KCC][0] = 44, + [2][1][RTW89_KCC][0] = 52, [2][1][RTW89_ACMA][0] = 40, [2][1][RTW89_CN][0] = 28, [2][1][RTW89_UK][0] = 40, + [2][1][RTW89_MEXICO][0] = 50, + [2][1][RTW89_UKRAINE][0] = 34, + [2][1][RTW89_CHILE][0] = 50, + [2][1][RTW89_QATAR][0] = 40, [2][1][RTW89_FCC][2] = 50, [2][1][RTW89_ETSI][2] = 40, [2][1][RTW89_MKK][2] = 44, [2][1][RTW89_IC][2] = 26, - [2][1][RTW89_KCC][2] = 44, + [2][1][RTW89_KCC][2] = 52, [2][1][RTW89_ACMA][2] = 40, [2][1][RTW89_CN][2] = 28, [2][1][RTW89_UK][2] = 40, + [2][1][RTW89_MEXICO][2] = 50, + [2][1][RTW89_UKRAINE][2] = 34, + [2][1][RTW89_CHILE][2] = 50, + [2][1][RTW89_QATAR][2] = 40, [2][1][RTW89_FCC][4] = 50, [2][1][RTW89_ETSI][4] = 40, [2][1][RTW89_MKK][4] = 36, [2][1][RTW89_IC][4] = 26, - [2][1][RTW89_KCC][4] = 44, + [2][1][RTW89_KCC][4] = 52, [2][1][RTW89_ACMA][4] = 40, [2][1][RTW89_CN][4] = 28, [2][1][RTW89_UK][4] = 40, + [2][1][RTW89_MEXICO][4] = 50, + [2][1][RTW89_UKRAINE][4] = 34, + [2][1][RTW89_CHILE][4] = 50, + [2][1][RTW89_QATAR][4] = 40, [2][1][RTW89_FCC][6] = 50, [2][1][RTW89_ETSI][6] = 40, [2][1][RTW89_MKK][6] = 36, [2][1][RTW89_IC][6] = 26, - [2][1][RTW89_KCC][6] = 20, + [2][1][RTW89_KCC][6] = 30, [2][1][RTW89_ACMA][6] = 40, [2][1][RTW89_CN][6] = 28, [2][1][RTW89_UK][6] = 40, + [2][1][RTW89_MEXICO][6] = 50, + [2][1][RTW89_UKRAINE][6] = 34, + [2][1][RTW89_CHILE][6] = 50, + [2][1][RTW89_QATAR][6] = 40, [2][1][RTW89_FCC][8] = 50, [2][1][RTW89_ETSI][8] = 40, [2][1][RTW89_MKK][8] = 32, [2][1][RTW89_IC][8] = 50, - [2][1][RTW89_KCC][8] = 46, + [2][1][RTW89_KCC][8] = 50, [2][1][RTW89_ACMA][8] = 40, [2][1][RTW89_CN][8] = 28, [2][1][RTW89_UK][8] = 40, + [2][1][RTW89_MEXICO][8] = 50, + [2][1][RTW89_UKRAINE][8] = 34, + [2][1][RTW89_CHILE][8] = 50, + [2][1][RTW89_QATAR][8] = 40, [2][1][RTW89_FCC][10] = 50, [2][1][RTW89_ETSI][10] = 40, [2][1][RTW89_MKK][10] = 32, [2][1][RTW89_IC][10] = 50, - [2][1][RTW89_KCC][10] = 46, + [2][1][RTW89_KCC][10] = 50, [2][1][RTW89_ACMA][10] = 40, [2][1][RTW89_CN][10] = 28, [2][1][RTW89_UK][10] = 40, + [2][1][RTW89_MEXICO][10] = 50, + [2][1][RTW89_UKRAINE][10] = 34, + [2][1][RTW89_CHILE][10] = 50, + [2][1][RTW89_QATAR][10] = 40, [2][1][RTW89_FCC][12] = 48, [2][1][RTW89_ETSI][12] = 40, [2][1][RTW89_MKK][12] = 44, [2][1][RTW89_IC][12] = 48, - [2][1][RTW89_KCC][12] = 46, + [2][1][RTW89_KCC][12] = 48, [2][1][RTW89_ACMA][12] = 40, [2][1][RTW89_CN][12] = 28, [2][1][RTW89_UK][12] = 40, + [2][1][RTW89_MEXICO][12] = 48, + [2][1][RTW89_UKRAINE][12] = 34, + [2][1][RTW89_CHILE][12] = 48, + [2][1][RTW89_QATAR][12] = 40, [2][1][RTW89_FCC][14] = 48, [2][1][RTW89_ETSI][14] = 40, [2][1][RTW89_MKK][14] = 44, [2][1][RTW89_IC][14] = 48, - [2][1][RTW89_KCC][14] = 46, + [2][1][RTW89_KCC][14] = 48, [2][1][RTW89_ACMA][14] = 40, [2][1][RTW89_CN][14] = 28, [2][1][RTW89_UK][14] = 40, + [2][1][RTW89_MEXICO][14] = 48, + [2][1][RTW89_UKRAINE][14] = 34, + [2][1][RTW89_CHILE][14] = 48, + [2][1][RTW89_QATAR][14] = 40, [2][1][RTW89_FCC][15] = 50, [2][1][RTW89_ETSI][15] = 40, [2][1][RTW89_MKK][15] = 66, [2][1][RTW89_IC][15] = 50, - [2][1][RTW89_KCC][15] = 46, + [2][1][RTW89_KCC][15] = 48, [2][1][RTW89_ACMA][15] = 40, [2][1][RTW89_CN][15] = 127, [2][1][RTW89_UK][15] = 40, + [2][1][RTW89_MEXICO][15] = 50, + [2][1][RTW89_UKRAINE][15] = 34, + [2][1][RTW89_CHILE][15] = 50, + [2][1][RTW89_QATAR][15] = 40, [2][1][RTW89_FCC][17] = 50, [2][1][RTW89_ETSI][17] = 40, [2][1][RTW89_MKK][17] = 66, [2][1][RTW89_IC][17] = 50, - [2][1][RTW89_KCC][17] = 46, + [2][1][RTW89_KCC][17] = 48, [2][1][RTW89_ACMA][17] = 40, [2][1][RTW89_CN][17] = 127, [2][1][RTW89_UK][17] = 40, + [2][1][RTW89_MEXICO][17] = 50, + [2][1][RTW89_UKRAINE][17] = 34, + [2][1][RTW89_CHILE][17] = 50, + [2][1][RTW89_QATAR][17] = 40, [2][1][RTW89_FCC][19] = 50, [2][1][RTW89_ETSI][19] = 40, [2][1][RTW89_MKK][19] = 66, [2][1][RTW89_IC][19] = 50, - [2][1][RTW89_KCC][19] = 46, + [2][1][RTW89_KCC][19] = 48, [2][1][RTW89_ACMA][19] = 40, [2][1][RTW89_CN][19] = 127, [2][1][RTW89_UK][19] = 40, + [2][1][RTW89_MEXICO][19] = 50, + [2][1][RTW89_UKRAINE][19] = 34, + [2][1][RTW89_CHILE][19] = 50, + [2][1][RTW89_QATAR][19] = 40, [2][1][RTW89_FCC][21] = 50, [2][1][RTW89_ETSI][21] = 40, [2][1][RTW89_MKK][21] = 66, [2][1][RTW89_IC][21] = 50, - [2][1][RTW89_KCC][21] = 46, + [2][1][RTW89_KCC][21] = 48, [2][1][RTW89_ACMA][21] = 40, [2][1][RTW89_CN][21] = 127, [2][1][RTW89_UK][21] = 40, + [2][1][RTW89_MEXICO][21] = 50, + [2][1][RTW89_UKRAINE][21] = 34, + [2][1][RTW89_CHILE][21] = 50, + [2][1][RTW89_QATAR][21] = 40, [2][1][RTW89_FCC][23] = 50, [2][1][RTW89_ETSI][23] = 40, [2][1][RTW89_MKK][23] = 66, [2][1][RTW89_IC][23] = 50, - [2][1][RTW89_KCC][23] = 46, + [2][1][RTW89_KCC][23] = 48, [2][1][RTW89_ACMA][23] = 40, [2][1][RTW89_CN][23] = 127, [2][1][RTW89_UK][23] = 40, + [2][1][RTW89_MEXICO][23] = 50, + [2][1][RTW89_UKRAINE][23] = 34, + [2][1][RTW89_CHILE][23] = 50, + [2][1][RTW89_QATAR][23] = 40, [2][1][RTW89_FCC][25] = 50, [2][1][RTW89_ETSI][25] = 40, [2][1][RTW89_MKK][25] = 66, [2][1][RTW89_IC][25] = 127, - [2][1][RTW89_KCC][25] = 46, + [2][1][RTW89_KCC][25] = 48, [2][1][RTW89_ACMA][25] = 127, [2][1][RTW89_CN][25] = 127, [2][1][RTW89_UK][25] = 40, + [2][1][RTW89_MEXICO][25] = 50, + [2][1][RTW89_UKRAINE][25] = 34, + [2][1][RTW89_CHILE][25] = 50, + [2][1][RTW89_QATAR][25] = 40, [2][1][RTW89_FCC][27] = 50, [2][1][RTW89_ETSI][27] = 40, [2][1][RTW89_MKK][27] = 66, [2][1][RTW89_IC][27] = 127, - [2][1][RTW89_KCC][27] = 46, + [2][1][RTW89_KCC][27] = 48, [2][1][RTW89_ACMA][27] = 127, [2][1][RTW89_CN][27] = 127, [2][1][RTW89_UK][27] = 40, + [2][1][RTW89_MEXICO][27] = 50, + [2][1][RTW89_UKRAINE][27] = 34, + [2][1][RTW89_CHILE][27] = 50, + [2][1][RTW89_QATAR][27] = 40, [2][1][RTW89_FCC][29] = 50, [2][1][RTW89_ETSI][29] = 40, [2][1][RTW89_MKK][29] = 66, [2][1][RTW89_IC][29] = 127, - [2][1][RTW89_KCC][29] = 46, + [2][1][RTW89_KCC][29] = 48, [2][1][RTW89_ACMA][29] = 127, [2][1][RTW89_CN][29] = 127, [2][1][RTW89_UK][29] = 40, + [2][1][RTW89_MEXICO][29] = 50, + [2][1][RTW89_UKRAINE][29] = 34, + [2][1][RTW89_CHILE][29] = 50, + [2][1][RTW89_QATAR][29] = 40, [2][1][RTW89_FCC][31] = 50, [2][1][RTW89_ETSI][31] = 40, [2][1][RTW89_MKK][31] = 66, [2][1][RTW89_IC][31] = 48, - [2][1][RTW89_KCC][31] = 46, + [2][1][RTW89_KCC][31] = 48, [2][1][RTW89_ACMA][31] = 40, [2][1][RTW89_CN][31] = 127, [2][1][RTW89_UK][31] = 40, + [2][1][RTW89_MEXICO][31] = 50, + [2][1][RTW89_UKRAINE][31] = 34, + [2][1][RTW89_CHILE][31] = 50, + [2][1][RTW89_QATAR][31] = 40, [2][1][RTW89_FCC][33] = 48, [2][1][RTW89_ETSI][33] = 40, [2][1][RTW89_MKK][33] = 66, [2][1][RTW89_IC][33] = 48, - [2][1][RTW89_KCC][33] = 46, + [2][1][RTW89_KCC][33] = 48, [2][1][RTW89_ACMA][33] = 40, [2][1][RTW89_CN][33] = 127, [2][1][RTW89_UK][33] = 40, + [2][1][RTW89_MEXICO][33] = 48, + [2][1][RTW89_UKRAINE][33] = 34, + [2][1][RTW89_CHILE][33] = 48, + [2][1][RTW89_QATAR][33] = 40, [2][1][RTW89_FCC][35] = 48, [2][1][RTW89_ETSI][35] = 40, [2][1][RTW89_MKK][35] = 66, [2][1][RTW89_IC][35] = 48, - [2][1][RTW89_KCC][35] = 46, + [2][1][RTW89_KCC][35] = 48, [2][1][RTW89_ACMA][35] = 40, [2][1][RTW89_CN][35] = 127, [2][1][RTW89_UK][35] = 40, + [2][1][RTW89_MEXICO][35] = 48, + [2][1][RTW89_UKRAINE][35] = 34, + [2][1][RTW89_CHILE][35] = 48, + [2][1][RTW89_QATAR][35] = 40, [2][1][RTW89_FCC][37] = 52, [2][1][RTW89_ETSI][37] = 127, [2][1][RTW89_MKK][37] = 66, [2][1][RTW89_IC][37] = 52, - [2][1][RTW89_KCC][37] = 46, + [2][1][RTW89_KCC][37] = 48, [2][1][RTW89_ACMA][37] = 52, [2][1][RTW89_CN][37] = 127, [2][1][RTW89_UK][37] = 42, + [2][1][RTW89_MEXICO][37] = 52, + [2][1][RTW89_UKRAINE][37] = 127, + [2][1][RTW89_CHILE][37] = 52, + [2][1][RTW89_QATAR][37] = 127, [2][1][RTW89_FCC][38] = 78, [2][1][RTW89_ETSI][38] = 16, [2][1][RTW89_MKK][38] = 127, [2][1][RTW89_IC][38] = 78, - [2][1][RTW89_KCC][38] = 46, + [2][1][RTW89_KCC][38] = 50, [2][1][RTW89_ACMA][38] = 78, [2][1][RTW89_CN][38] = 56, [2][1][RTW89_UK][38] = 42, + [2][1][RTW89_MEXICO][38] = 78, + [2][1][RTW89_UKRAINE][38] = 14, + [2][1][RTW89_CHILE][38] = 72, + [2][1][RTW89_QATAR][38] = 14, [2][1][RTW89_FCC][40] = 78, [2][1][RTW89_ETSI][40] = 16, [2][1][RTW89_MKK][40] = 127, [2][1][RTW89_IC][40] = 78, - [2][1][RTW89_KCC][40] = 46, + [2][1][RTW89_KCC][40] = 50, [2][1][RTW89_ACMA][40] = 78, [2][1][RTW89_CN][40] = 56, [2][1][RTW89_UK][40] = 42, + [2][1][RTW89_MEXICO][40] = 78, + [2][1][RTW89_UKRAINE][40] = 14, + [2][1][RTW89_CHILE][40] = 72, + [2][1][RTW89_QATAR][40] = 14, [2][1][RTW89_FCC][42] = 78, [2][1][RTW89_ETSI][42] = 16, [2][1][RTW89_MKK][42] = 127, [2][1][RTW89_IC][42] = 78, - [2][1][RTW89_KCC][42] = 46, + [2][1][RTW89_KCC][42] = 50, [2][1][RTW89_ACMA][42] = 78, [2][1][RTW89_CN][42] = 56, [2][1][RTW89_UK][42] = 42, + [2][1][RTW89_MEXICO][42] = 78, + [2][1][RTW89_UKRAINE][42] = 14, + [2][1][RTW89_CHILE][42] = 72, + [2][1][RTW89_QATAR][42] = 14, [2][1][RTW89_FCC][44] = 74, [2][1][RTW89_ETSI][44] = 16, [2][1][RTW89_MKK][44] = 127, [2][1][RTW89_IC][44] = 74, - [2][1][RTW89_KCC][44] = 46, + [2][1][RTW89_KCC][44] = 50, [2][1][RTW89_ACMA][44] = 74, [2][1][RTW89_CN][44] = 56, [2][1][RTW89_UK][44] = 42, + [2][1][RTW89_MEXICO][44] = 74, + [2][1][RTW89_UKRAINE][44] = 14, + [2][1][RTW89_CHILE][44] = 72, + [2][1][RTW89_QATAR][44] = 14, [2][1][RTW89_FCC][46] = 74, [2][1][RTW89_ETSI][46] = 16, [2][1][RTW89_MKK][46] = 127, [2][1][RTW89_IC][46] = 74, - [2][1][RTW89_KCC][46] = 46, + [2][1][RTW89_KCC][46] = 50, [2][1][RTW89_ACMA][46] = 74, [2][1][RTW89_CN][46] = 56, [2][1][RTW89_UK][46] = 42, + [2][1][RTW89_MEXICO][46] = 74, + [2][1][RTW89_UKRAINE][46] = 14, + [2][1][RTW89_CHILE][46] = 72, + [2][1][RTW89_QATAR][46] = 14, [2][1][RTW89_FCC][48] = 40, [2][1][RTW89_ETSI][48] = 127, [2][1][RTW89_MKK][48] = 127, @@ -36240,6 +38774,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_ACMA][48] = 127, [2][1][RTW89_CN][48] = 127, [2][1][RTW89_UK][48] = 127, + [2][1][RTW89_MEXICO][48] = 127, + [2][1][RTW89_UKRAINE][48] = 127, + [2][1][RTW89_CHILE][48] = 127, + [2][1][RTW89_QATAR][48] = 127, [2][1][RTW89_FCC][50] = 40, [2][1][RTW89_ETSI][50] = 127, [2][1][RTW89_MKK][50] = 127, @@ -36248,6 +38786,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_ACMA][50] = 127, [2][1][RTW89_CN][50] = 127, [2][1][RTW89_UK][50] = 127, + [2][1][RTW89_MEXICO][50] = 127, + [2][1][RTW89_UKRAINE][50] = 127, + [2][1][RTW89_CHILE][50] = 127, + [2][1][RTW89_QATAR][50] = 127, [2][1][RTW89_FCC][52] = 40, [2][1][RTW89_ETSI][52] = 127, [2][1][RTW89_MKK][52] = 127, @@ -36256,6 +38798,10 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_ACMA][52] = 127, [2][1][RTW89_CN][52] = 127, [2][1][RTW89_UK][52] = 127, + [2][1][RTW89_MEXICO][52] = 127, + [2][1][RTW89_UKRAINE][52] = 127, + [2][1][RTW89_CHILE][52] = 127, + [2][1][RTW89_QATAR][52] = 127, }; static -- cgit v1.2.3 From 2a8ec45f4d0eff76cf0cef78b3040ccfd923a72e Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 2 Jun 2023 23:05:54 +0800 Subject: wifi: rtw89: 8852c: update TX power tables to R63 with 6 GHz power type (2 of 3) Update TX power tables to RF version R63. TX power tables' changes: * TX power byrate: tweak a bit * TX power limit, TX power limit RU, TX power shape: configure values for MEXICO, UKRAINE, CHILE, QATAR tweak a bit on other configured values * 6 GHz TX power limit, 6 GHz TX power limit RU: add an extra dimension for 6 GHz regulatory power type, i.e. STD (standard power), LPI (low power indoor), VLP (very low power) Besides, we adjust TX power handling at 6 GHz in phy to consider 6 GHz regulatory power type. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602150556.36777-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 3 +- drivers/net/wireless/realtek/rtw89/phy.c | 8 +- .../net/wireless/realtek/rtw89/rtw8852c_table.c | 11227 +++++++++++++++---- 3 files changed, 9282 insertions(+), 1956 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 3915ab7ab8a1..84dff8188dd2 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3046,7 +3046,8 @@ struct rtw89_txpwr_rule_5ghz { struct rtw89_txpwr_rule_6ghz { const s8 (*lmt)[RTW89_6G_BW_NUM][RTW89_NTX_NUM] [RTW89_RS_LMT_NUM][RTW89_BF_NUM] - [RTW89_REGD_NUM][RTW89_6G_CH_NUM]; + [RTW89_REGD_NUM][NUM_OF_RTW89_REG_6GHZ_POWER] + [RTW89_6G_CH_NUM]; const s8 (*lmt_ru)[RTW89_RU_NUM][RTW89_NTX_NUM] [RTW89_REGD_NUM][RTW89_6G_CH_NUM]; }; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index de0776dfddf7..7152f093b8e6 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1626,8 +1626,10 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz; const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz; const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz; + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch); u8 regd = rtw89_regd_get(rtwdev, band); + u8 reg6 = regulatory->reg_6ghz_power; s8 lmt = 0, sar; switch (band) { @@ -1646,11 +1648,13 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, lmt = (*rule_5ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx]; break; case RTW89_BAND_6G: - lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][regd][ch_idx]; + lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][regd][reg6][ch_idx]; if (lmt) break; - lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][RTW89_WW][ch_idx]; + lmt = (*rule_6ghz->lmt)[bw][ntx][rs][bf][RTW89_WW] + [RTW89_REG_6GHZ_POWER_DFLT] + [ch_idx]; break; default: rtw89_warn(rtwdev, "unknown band type: %d\n", band); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c index 52b124fb58c6..5c59ff182c6e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c @@ -33563,1959 +33563,9280 @@ const s8 rtw89_8852c_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] static const s8 rtw89_8852c_txpwr_lmt_6g[RTW89_6G_BW_NUM][RTW89_NTX_NUM] [RTW89_RS_LMT_NUM][RTW89_BF_NUM] - [RTW89_REGD_NUM][RTW89_6G_CH_NUM] = { - [0][0][1][0][RTW89_WW][0] = 24, - [0][0][1][0][RTW89_WW][2] = 22, - [0][0][1][0][RTW89_WW][4] = 22, - [0][0][1][0][RTW89_WW][6] = 22, - [0][0][1][0][RTW89_WW][8] = 22, - [0][0][1][0][RTW89_WW][10] = 22, - [0][0][1][0][RTW89_WW][12] = 22, - [0][0][1][0][RTW89_WW][14] = 22, - [0][0][1][0][RTW89_WW][15] = 22, - [0][0][1][0][RTW89_WW][17] = 22, - [0][0][1][0][RTW89_WW][19] = 22, - [0][0][1][0][RTW89_WW][21] = 22, - [0][0][1][0][RTW89_WW][23] = 22, - [0][0][1][0][RTW89_WW][25] = 22, - [0][0][1][0][RTW89_WW][27] = 22, - [0][0][1][0][RTW89_WW][29] = 22, - [0][0][1][0][RTW89_WW][30] = 22, - [0][0][1][0][RTW89_WW][32] = 22, - [0][0][1][0][RTW89_WW][34] = 22, - [0][0][1][0][RTW89_WW][36] = 22, - [0][0][1][0][RTW89_WW][38] = 22, - [0][0][1][0][RTW89_WW][40] = 22, - [0][0][1][0][RTW89_WW][42] = 22, - [0][0][1][0][RTW89_WW][44] = 22, - [0][0][1][0][RTW89_WW][45] = 22, - [0][0][1][0][RTW89_WW][47] = 22, - [0][0][1][0][RTW89_WW][49] = 24, - [0][0][1][0][RTW89_WW][51] = 22, - [0][0][1][0][RTW89_WW][53] = 22, - [0][0][1][0][RTW89_WW][55] = 22, - [0][0][1][0][RTW89_WW][57] = 22, - [0][0][1][0][RTW89_WW][59] = 22, - [0][0][1][0][RTW89_WW][60] = 22, - [0][0][1][0][RTW89_WW][62] = 22, - [0][0][1][0][RTW89_WW][64] = 22, - [0][0][1][0][RTW89_WW][66] = 22, - [0][0][1][0][RTW89_WW][68] = 22, - [0][0][1][0][RTW89_WW][70] = 24, - [0][0][1][0][RTW89_WW][72] = 22, - [0][0][1][0][RTW89_WW][74] = 22, - [0][0][1][0][RTW89_WW][75] = 22, - [0][0][1][0][RTW89_WW][77] = 22, - [0][0][1][0][RTW89_WW][79] = 22, - [0][0][1][0][RTW89_WW][81] = 22, - [0][0][1][0][RTW89_WW][83] = 22, - [0][0][1][0][RTW89_WW][85] = 22, - [0][0][1][0][RTW89_WW][87] = 22, - [0][0][1][0][RTW89_WW][89] = 22, - [0][0][1][0][RTW89_WW][90] = 22, - [0][0][1][0][RTW89_WW][92] = 22, - [0][0][1][0][RTW89_WW][94] = 22, - [0][0][1][0][RTW89_WW][96] = 22, - [0][0][1][0][RTW89_WW][98] = 22, - [0][0][1][0][RTW89_WW][100] = 22, - [0][0][1][0][RTW89_WW][102] = 22, - [0][0][1][0][RTW89_WW][104] = 22, - [0][0][1][0][RTW89_WW][105] = 22, - [0][0][1][0][RTW89_WW][107] = 24, - [0][0][1][0][RTW89_WW][109] = 24, - [0][0][1][0][RTW89_WW][111] = 0, - [0][0][1][0][RTW89_WW][113] = 0, - [0][0][1][0][RTW89_WW][115] = 0, - [0][0][1][0][RTW89_WW][117] = 0, - [0][0][1][0][RTW89_WW][119] = 0, - [0][1][1][0][RTW89_WW][0] = -2, - [0][1][1][0][RTW89_WW][2] = -4, - [0][1][1][0][RTW89_WW][4] = -4, - [0][1][1][0][RTW89_WW][6] = -4, - [0][1][1][0][RTW89_WW][8] = -4, - [0][1][1][0][RTW89_WW][10] = -4, - [0][1][1][0][RTW89_WW][12] = -4, - [0][1][1][0][RTW89_WW][14] = -4, - [0][1][1][0][RTW89_WW][15] = -4, - [0][1][1][0][RTW89_WW][17] = -4, - [0][1][1][0][RTW89_WW][19] = -4, - [0][1][1][0][RTW89_WW][21] = -4, - [0][1][1][0][RTW89_WW][23] = -4, - [0][1][1][0][RTW89_WW][25] = -4, - [0][1][1][0][RTW89_WW][27] = -4, - [0][1][1][0][RTW89_WW][29] = -4, - [0][1][1][0][RTW89_WW][30] = -4, - [0][1][1][0][RTW89_WW][32] = -4, - [0][1][1][0][RTW89_WW][34] = -4, - [0][1][1][0][RTW89_WW][36] = -4, - [0][1][1][0][RTW89_WW][38] = -4, - [0][1][1][0][RTW89_WW][40] = -4, - [0][1][1][0][RTW89_WW][42] = -4, - [0][1][1][0][RTW89_WW][44] = -2, - [0][1][1][0][RTW89_WW][45] = -2, - [0][1][1][0][RTW89_WW][47] = -2, - [0][1][1][0][RTW89_WW][49] = -2, - [0][1][1][0][RTW89_WW][51] = -2, - [0][1][1][0][RTW89_WW][53] = -2, - [0][1][1][0][RTW89_WW][55] = -2, - [0][1][1][0][RTW89_WW][57] = -2, - [0][1][1][0][RTW89_WW][59] = -2, - [0][1][1][0][RTW89_WW][60] = -2, - [0][1][1][0][RTW89_WW][62] = -2, - [0][1][1][0][RTW89_WW][64] = -2, - [0][1][1][0][RTW89_WW][66] = -2, - [0][1][1][0][RTW89_WW][68] = -2, - [0][1][1][0][RTW89_WW][70] = -2, - [0][1][1][0][RTW89_WW][72] = -2, - [0][1][1][0][RTW89_WW][74] = -2, - [0][1][1][0][RTW89_WW][75] = -2, - [0][1][1][0][RTW89_WW][77] = -2, - [0][1][1][0][RTW89_WW][79] = -2, - [0][1][1][0][RTW89_WW][81] = -2, - [0][1][1][0][RTW89_WW][83] = -2, - [0][1][1][0][RTW89_WW][85] = -2, - [0][1][1][0][RTW89_WW][87] = -2, - [0][1][1][0][RTW89_WW][89] = -2, - [0][1][1][0][RTW89_WW][90] = -2, - [0][1][1][0][RTW89_WW][92] = -2, - [0][1][1][0][RTW89_WW][94] = -2, - [0][1][1][0][RTW89_WW][96] = -2, - [0][1][1][0][RTW89_WW][98] = -2, - [0][1][1][0][RTW89_WW][100] = -2, - [0][1][1][0][RTW89_WW][102] = -2, - [0][1][1][0][RTW89_WW][104] = -2, - [0][1][1][0][RTW89_WW][105] = -2, - [0][1][1][0][RTW89_WW][107] = 1, - [0][1][1][0][RTW89_WW][109] = 1, - [0][1][1][0][RTW89_WW][111] = 0, - [0][1][1][0][RTW89_WW][113] = 0, - [0][1][1][0][RTW89_WW][115] = 0, - [0][1][1][0][RTW89_WW][117] = 0, - [0][1][1][0][RTW89_WW][119] = 0, - [0][0][2][0][RTW89_WW][0] = 24, - [0][0][2][0][RTW89_WW][2] = 22, - [0][0][2][0][RTW89_WW][4] = 22, - [0][0][2][0][RTW89_WW][6] = 22, - [0][0][2][0][RTW89_WW][8] = 22, - [0][0][2][0][RTW89_WW][10] = 22, - [0][0][2][0][RTW89_WW][12] = 22, - [0][0][2][0][RTW89_WW][14] = 22, - [0][0][2][0][RTW89_WW][15] = 22, - [0][0][2][0][RTW89_WW][17] = 22, - [0][0][2][0][RTW89_WW][19] = 22, - [0][0][2][0][RTW89_WW][21] = 22, - [0][0][2][0][RTW89_WW][23] = 22, - [0][0][2][0][RTW89_WW][25] = 22, - [0][0][2][0][RTW89_WW][27] = 22, - [0][0][2][0][RTW89_WW][29] = 22, - [0][0][2][0][RTW89_WW][30] = 22, - [0][0][2][0][RTW89_WW][32] = 22, - [0][0][2][0][RTW89_WW][34] = 22, - [0][0][2][0][RTW89_WW][36] = 22, - [0][0][2][0][RTW89_WW][38] = 22, - [0][0][2][0][RTW89_WW][40] = 22, - [0][0][2][0][RTW89_WW][42] = 22, - [0][0][2][0][RTW89_WW][44] = 22, - [0][0][2][0][RTW89_WW][45] = 22, - [0][0][2][0][RTW89_WW][47] = 22, - [0][0][2][0][RTW89_WW][49] = 24, - [0][0][2][0][RTW89_WW][51] = 22, - [0][0][2][0][RTW89_WW][53] = 22, - [0][0][2][0][RTW89_WW][55] = 22, - [0][0][2][0][RTW89_WW][57] = 22, - [0][0][2][0][RTW89_WW][59] = 22, - [0][0][2][0][RTW89_WW][60] = 22, - [0][0][2][0][RTW89_WW][62] = 22, - [0][0][2][0][RTW89_WW][64] = 22, - [0][0][2][0][RTW89_WW][66] = 22, - [0][0][2][0][RTW89_WW][68] = 22, - [0][0][2][0][RTW89_WW][70] = 24, - [0][0][2][0][RTW89_WW][72] = 22, - [0][0][2][0][RTW89_WW][74] = 22, - [0][0][2][0][RTW89_WW][75] = 22, - [0][0][2][0][RTW89_WW][77] = 22, - [0][0][2][0][RTW89_WW][79] = 22, - [0][0][2][0][RTW89_WW][81] = 22, - [0][0][2][0][RTW89_WW][83] = 22, - [0][0][2][0][RTW89_WW][85] = 22, - [0][0][2][0][RTW89_WW][87] = 22, - [0][0][2][0][RTW89_WW][89] = 22, - [0][0][2][0][RTW89_WW][90] = 22, - [0][0][2][0][RTW89_WW][92] = 22, - [0][0][2][0][RTW89_WW][94] = 22, - [0][0][2][0][RTW89_WW][96] = 22, - [0][0][2][0][RTW89_WW][98] = 22, - [0][0][2][0][RTW89_WW][100] = 22, - [0][0][2][0][RTW89_WW][102] = 22, - [0][0][2][0][RTW89_WW][104] = 22, - [0][0][2][0][RTW89_WW][105] = 22, - [0][0][2][0][RTW89_WW][107] = 24, - [0][0][2][0][RTW89_WW][109] = 24, - [0][0][2][0][RTW89_WW][111] = 0, - [0][0][2][0][RTW89_WW][113] = 0, - [0][0][2][0][RTW89_WW][115] = 0, - [0][0][2][0][RTW89_WW][117] = 0, - [0][0][2][0][RTW89_WW][119] = 0, - [0][1][2][0][RTW89_WW][0] = -2, - [0][1][2][0][RTW89_WW][2] = -4, - [0][1][2][0][RTW89_WW][4] = -4, - [0][1][2][0][RTW89_WW][6] = -4, - [0][1][2][0][RTW89_WW][8] = -4, - [0][1][2][0][RTW89_WW][10] = -4, - [0][1][2][0][RTW89_WW][12] = -4, - [0][1][2][0][RTW89_WW][14] = -4, - [0][1][2][0][RTW89_WW][15] = -4, - [0][1][2][0][RTW89_WW][17] = -4, - [0][1][2][0][RTW89_WW][19] = -4, - [0][1][2][0][RTW89_WW][21] = -4, - [0][1][2][0][RTW89_WW][23] = -4, - [0][1][2][0][RTW89_WW][25] = -4, - [0][1][2][0][RTW89_WW][27] = -4, - [0][1][2][0][RTW89_WW][29] = -4, - [0][1][2][0][RTW89_WW][30] = -4, - [0][1][2][0][RTW89_WW][32] = -4, - [0][1][2][0][RTW89_WW][34] = -4, - [0][1][2][0][RTW89_WW][36] = -4, - [0][1][2][0][RTW89_WW][38] = -4, - [0][1][2][0][RTW89_WW][40] = -4, - [0][1][2][0][RTW89_WW][42] = -4, - [0][1][2][0][RTW89_WW][44] = -2, - [0][1][2][0][RTW89_WW][45] = -2, - [0][1][2][0][RTW89_WW][47] = -2, - [0][1][2][0][RTW89_WW][49] = -2, - [0][1][2][0][RTW89_WW][51] = -2, - [0][1][2][0][RTW89_WW][53] = -2, - [0][1][2][0][RTW89_WW][55] = -2, - [0][1][2][0][RTW89_WW][57] = -2, - [0][1][2][0][RTW89_WW][59] = -2, - [0][1][2][0][RTW89_WW][60] = -2, - [0][1][2][0][RTW89_WW][62] = -2, - [0][1][2][0][RTW89_WW][64] = -2, - [0][1][2][0][RTW89_WW][66] = -2, - [0][1][2][0][RTW89_WW][68] = -2, - [0][1][2][0][RTW89_WW][70] = -2, - [0][1][2][0][RTW89_WW][72] = -2, - [0][1][2][0][RTW89_WW][74] = -2, - [0][1][2][0][RTW89_WW][75] = -2, - [0][1][2][0][RTW89_WW][77] = -2, - [0][1][2][0][RTW89_WW][79] = -2, - [0][1][2][0][RTW89_WW][81] = -2, - [0][1][2][0][RTW89_WW][83] = -2, - [0][1][2][0][RTW89_WW][85] = -2, - [0][1][2][0][RTW89_WW][87] = -2, - [0][1][2][0][RTW89_WW][89] = -2, - [0][1][2][0][RTW89_WW][90] = -2, - [0][1][2][0][RTW89_WW][92] = -2, - [0][1][2][0][RTW89_WW][94] = -2, - [0][1][2][0][RTW89_WW][96] = -2, - [0][1][2][0][RTW89_WW][98] = -2, - [0][1][2][0][RTW89_WW][100] = -2, - [0][1][2][0][RTW89_WW][102] = -2, - [0][1][2][0][RTW89_WW][104] = -2, - [0][1][2][0][RTW89_WW][105] = -2, - [0][1][2][0][RTW89_WW][107] = 1, - [0][1][2][0][RTW89_WW][109] = 1, - [0][1][2][0][RTW89_WW][111] = 0, - [0][1][2][0][RTW89_WW][113] = 0, - [0][1][2][0][RTW89_WW][115] = 0, - [0][1][2][0][RTW89_WW][117] = 0, - [0][1][2][0][RTW89_WW][119] = 0, - [0][1][2][1][RTW89_WW][0] = -2, - [0][1][2][1][RTW89_WW][2] = -4, - [0][1][2][1][RTW89_WW][4] = -4, - [0][1][2][1][RTW89_WW][6] = -4, - [0][1][2][1][RTW89_WW][8] = -4, - [0][1][2][1][RTW89_WW][10] = -4, - [0][1][2][1][RTW89_WW][12] = -4, - [0][1][2][1][RTW89_WW][14] = -4, - [0][1][2][1][RTW89_WW][15] = -4, - [0][1][2][1][RTW89_WW][17] = -4, - [0][1][2][1][RTW89_WW][19] = -4, - [0][1][2][1][RTW89_WW][21] = -4, - [0][1][2][1][RTW89_WW][23] = -4, - [0][1][2][1][RTW89_WW][25] = -4, - [0][1][2][1][RTW89_WW][27] = -4, - [0][1][2][1][RTW89_WW][29] = -4, - [0][1][2][1][RTW89_WW][30] = -4, - [0][1][2][1][RTW89_WW][32] = -4, - [0][1][2][1][RTW89_WW][34] = -4, - [0][1][2][1][RTW89_WW][36] = -4, - [0][1][2][1][RTW89_WW][38] = -4, - [0][1][2][1][RTW89_WW][40] = -4, - [0][1][2][1][RTW89_WW][42] = -4, - [0][1][2][1][RTW89_WW][44] = -2, - [0][1][2][1][RTW89_WW][45] = -2, - [0][1][2][1][RTW89_WW][47] = -2, - [0][1][2][1][RTW89_WW][49] = -2, - [0][1][2][1][RTW89_WW][51] = -2, - [0][1][2][1][RTW89_WW][53] = -2, - [0][1][2][1][RTW89_WW][55] = -2, - [0][1][2][1][RTW89_WW][57] = -2, - [0][1][2][1][RTW89_WW][59] = -2, - [0][1][2][1][RTW89_WW][60] = -2, - [0][1][2][1][RTW89_WW][62] = -2, - [0][1][2][1][RTW89_WW][64] = -2, - [0][1][2][1][RTW89_WW][66] = -2, - [0][1][2][1][RTW89_WW][68] = -2, - [0][1][2][1][RTW89_WW][70] = -2, - [0][1][2][1][RTW89_WW][72] = -2, - [0][1][2][1][RTW89_WW][74] = -2, - [0][1][2][1][RTW89_WW][75] = -2, - [0][1][2][1][RTW89_WW][77] = -2, - [0][1][2][1][RTW89_WW][79] = -2, - [0][1][2][1][RTW89_WW][81] = -2, - [0][1][2][1][RTW89_WW][83] = -2, - [0][1][2][1][RTW89_WW][85] = -2, - [0][1][2][1][RTW89_WW][87] = -2, - [0][1][2][1][RTW89_WW][89] = -2, - [0][1][2][1][RTW89_WW][90] = -2, - [0][1][2][1][RTW89_WW][92] = -2, - [0][1][2][1][RTW89_WW][94] = -2, - [0][1][2][1][RTW89_WW][96] = -2, - [0][1][2][1][RTW89_WW][98] = -2, - [0][1][2][1][RTW89_WW][100] = -2, - [0][1][2][1][RTW89_WW][102] = -2, - [0][1][2][1][RTW89_WW][104] = -2, - [0][1][2][1][RTW89_WW][105] = -2, - [0][1][2][1][RTW89_WW][107] = 1, - [0][1][2][1][RTW89_WW][109] = 1, - [0][1][2][1][RTW89_WW][111] = 0, - [0][1][2][1][RTW89_WW][113] = 0, - [0][1][2][1][RTW89_WW][115] = 0, - [0][1][2][1][RTW89_WW][117] = 0, - [0][1][2][1][RTW89_WW][119] = 0, - [1][0][2][0][RTW89_WW][1] = 34, - [1][0][2][0][RTW89_WW][5] = 34, - [1][0][2][0][RTW89_WW][9] = 34, - [1][0][2][0][RTW89_WW][13] = 34, - [1][0][2][0][RTW89_WW][16] = 34, - [1][0][2][0][RTW89_WW][20] = 34, - [1][0][2][0][RTW89_WW][24] = 36, - [1][0][2][0][RTW89_WW][28] = 34, - [1][0][2][0][RTW89_WW][31] = 34, - [1][0][2][0][RTW89_WW][35] = 34, - [1][0][2][0][RTW89_WW][39] = 34, - [1][0][2][0][RTW89_WW][43] = 34, - [1][0][2][0][RTW89_WW][46] = 34, - [1][0][2][0][RTW89_WW][50] = 34, - [1][0][2][0][RTW89_WW][54] = 36, - [1][0][2][0][RTW89_WW][58] = 36, - [1][0][2][0][RTW89_WW][61] = 34, - [1][0][2][0][RTW89_WW][65] = 34, - [1][0][2][0][RTW89_WW][69] = 34, - [1][0][2][0][RTW89_WW][73] = 34, - [1][0][2][0][RTW89_WW][76] = 34, - [1][0][2][0][RTW89_WW][80] = 34, - [1][0][2][0][RTW89_WW][84] = 34, - [1][0][2][0][RTW89_WW][88] = 34, - [1][0][2][0][RTW89_WW][91] = 36, - [1][0][2][0][RTW89_WW][95] = 34, - [1][0][2][0][RTW89_WW][99] = 34, - [1][0][2][0][RTW89_WW][103] = 34, - [1][0][2][0][RTW89_WW][106] = 36, - [1][0][2][0][RTW89_WW][110] = 0, - [1][0][2][0][RTW89_WW][114] = 0, - [1][0][2][0][RTW89_WW][118] = 0, - [1][1][2][0][RTW89_WW][1] = 10, - [1][1][2][0][RTW89_WW][5] = 10, - [1][1][2][0][RTW89_WW][9] = 10, - [1][1][2][0][RTW89_WW][13] = 10, - [1][1][2][0][RTW89_WW][16] = 10, - [1][1][2][0][RTW89_WW][20] = 10, - [1][1][2][0][RTW89_WW][24] = 10, - [1][1][2][0][RTW89_WW][28] = 10, - [1][1][2][0][RTW89_WW][31] = 10, - [1][1][2][0][RTW89_WW][35] = 10, - [1][1][2][0][RTW89_WW][39] = 10, - [1][1][2][0][RTW89_WW][43] = 10, - [1][1][2][0][RTW89_WW][46] = 12, - [1][1][2][0][RTW89_WW][50] = 12, - [1][1][2][0][RTW89_WW][54] = 10, - [1][1][2][0][RTW89_WW][58] = 10, - [1][1][2][0][RTW89_WW][61] = 10, - [1][1][2][0][RTW89_WW][65] = 10, - [1][1][2][0][RTW89_WW][69] = 10, - [1][1][2][0][RTW89_WW][73] = 10, - [1][1][2][0][RTW89_WW][76] = 10, - [1][1][2][0][RTW89_WW][80] = 10, - [1][1][2][0][RTW89_WW][84] = 10, - [1][1][2][0][RTW89_WW][88] = 10, - [1][1][2][0][RTW89_WW][91] = 12, - [1][1][2][0][RTW89_WW][95] = 10, - [1][1][2][0][RTW89_WW][99] = 10, - [1][1][2][0][RTW89_WW][103] = 10, - [1][1][2][0][RTW89_WW][106] = 12, - [1][1][2][0][RTW89_WW][110] = 0, - [1][1][2][0][RTW89_WW][114] = 0, - [1][1][2][0][RTW89_WW][118] = 0, - [1][1][2][1][RTW89_WW][1] = 10, - [1][1][2][1][RTW89_WW][5] = 10, - [1][1][2][1][RTW89_WW][9] = 10, - [1][1][2][1][RTW89_WW][13] = 10, - [1][1][2][1][RTW89_WW][16] = 10, - [1][1][2][1][RTW89_WW][20] = 10, - [1][1][2][1][RTW89_WW][24] = 10, - [1][1][2][1][RTW89_WW][28] = 10, - [1][1][2][1][RTW89_WW][31] = 10, - [1][1][2][1][RTW89_WW][35] = 10, - [1][1][2][1][RTW89_WW][39] = 10, - [1][1][2][1][RTW89_WW][43] = 10, - [1][1][2][1][RTW89_WW][46] = 12, - [1][1][2][1][RTW89_WW][50] = 12, - [1][1][2][1][RTW89_WW][54] = 10, - [1][1][2][1][RTW89_WW][58] = 10, - [1][1][2][1][RTW89_WW][61] = 10, - [1][1][2][1][RTW89_WW][65] = 10, - [1][1][2][1][RTW89_WW][69] = 10, - [1][1][2][1][RTW89_WW][73] = 10, - [1][1][2][1][RTW89_WW][76] = 10, - [1][1][2][1][RTW89_WW][80] = 10, - [1][1][2][1][RTW89_WW][84] = 10, - [1][1][2][1][RTW89_WW][88] = 10, - [1][1][2][1][RTW89_WW][91] = 12, - [1][1][2][1][RTW89_WW][95] = 10, - [1][1][2][1][RTW89_WW][99] = 10, - [1][1][2][1][RTW89_WW][103] = 10, - [1][1][2][1][RTW89_WW][106] = 12, - [1][1][2][1][RTW89_WW][110] = 0, - [1][1][2][1][RTW89_WW][114] = 0, - [1][1][2][1][RTW89_WW][118] = 0, - [2][0][2][0][RTW89_WW][3] = 46, - [2][0][2][0][RTW89_WW][11] = 46, - [2][0][2][0][RTW89_WW][18] = 46, - [2][0][2][0][RTW89_WW][26] = 46, - [2][0][2][0][RTW89_WW][33] = 46, - [2][0][2][0][RTW89_WW][41] = 46, - [2][0][2][0][RTW89_WW][48] = 46, - [2][0][2][0][RTW89_WW][56] = 46, - [2][0][2][0][RTW89_WW][63] = 46, - [2][0][2][0][RTW89_WW][71] = 46, - [2][0][2][0][RTW89_WW][78] = 46, - [2][0][2][0][RTW89_WW][86] = 46, - [2][0][2][0][RTW89_WW][93] = 46, - [2][0][2][0][RTW89_WW][101] = 44, - [2][0][2][0][RTW89_WW][108] = 0, - [2][0][2][0][RTW89_WW][116] = 0, - [2][1][2][0][RTW89_WW][3] = 22, - [2][1][2][0][RTW89_WW][11] = 20, - [2][1][2][0][RTW89_WW][18] = 20, - [2][1][2][0][RTW89_WW][26] = 20, - [2][1][2][0][RTW89_WW][33] = 20, - [2][1][2][0][RTW89_WW][41] = 22, - [2][1][2][0][RTW89_WW][48] = 22, - [2][1][2][0][RTW89_WW][56] = 20, - [2][1][2][0][RTW89_WW][63] = 22, - [2][1][2][0][RTW89_WW][71] = 20, - [2][1][2][0][RTW89_WW][78] = 20, - [2][1][2][0][RTW89_WW][86] = 20, - [2][1][2][0][RTW89_WW][93] = 22, - [2][1][2][0][RTW89_WW][101] = 22, - [2][1][2][0][RTW89_WW][108] = 0, - [2][1][2][0][RTW89_WW][116] = 0, - [2][1][2][1][RTW89_WW][3] = 22, - [2][1][2][1][RTW89_WW][11] = 20, - [2][1][2][1][RTW89_WW][18] = 20, - [2][1][2][1][RTW89_WW][26] = 20, - [2][1][2][1][RTW89_WW][33] = 20, - [2][1][2][1][RTW89_WW][41] = 22, - [2][1][2][1][RTW89_WW][48] = 22, - [2][1][2][1][RTW89_WW][56] = 20, - [2][1][2][1][RTW89_WW][63] = 22, - [2][1][2][1][RTW89_WW][71] = 20, - [2][1][2][1][RTW89_WW][78] = 20, - [2][1][2][1][RTW89_WW][86] = 20, - [2][1][2][1][RTW89_WW][93] = 22, - [2][1][2][1][RTW89_WW][101] = 22, - [2][1][2][1][RTW89_WW][108] = 0, - [2][1][2][1][RTW89_WW][116] = 0, - [3][0][2][0][RTW89_WW][7] = 38, - [3][0][2][0][RTW89_WW][22] = 38, - [3][0][2][0][RTW89_WW][37] = 38, - [3][0][2][0][RTW89_WW][52] = 54, - [3][0][2][0][RTW89_WW][67] = 54, - [3][0][2][0][RTW89_WW][82] = 26, - [3][0][2][0][RTW89_WW][97] = 26, - [3][0][2][0][RTW89_WW][112] = 0, - [3][1][2][0][RTW89_WW][7] = 32, - [3][1][2][0][RTW89_WW][22] = 30, - [3][1][2][0][RTW89_WW][37] = 30, - [3][1][2][0][RTW89_WW][52] = 30, - [3][1][2][0][RTW89_WW][67] = 32, - [3][1][2][0][RTW89_WW][82] = 24, - [3][1][2][0][RTW89_WW][97] = 14, - [3][1][2][0][RTW89_WW][112] = 0, - [3][1][2][1][RTW89_WW][7] = 32, - [3][1][2][1][RTW89_WW][22] = 30, - [3][1][2][1][RTW89_WW][37] = 30, - [3][1][2][1][RTW89_WW][52] = 30, - [3][1][2][1][RTW89_WW][67] = 32, - [3][1][2][1][RTW89_WW][82] = 24, - [3][1][2][1][RTW89_WW][97] = 14, - [3][1][2][1][RTW89_WW][112] = 0, - [0][0][1][0][RTW89_FCC][0] = 24, - [0][0][1][0][RTW89_ETSI][0] = 66, - [0][0][1][0][RTW89_KCC][0] = 24, - [0][0][1][0][RTW89_FCC][2] = 22, - [0][0][1][0][RTW89_ETSI][2] = 66, - [0][0][1][0][RTW89_KCC][2] = 24, - [0][0][1][0][RTW89_FCC][4] = 22, - [0][0][1][0][RTW89_ETSI][4] = 66, - [0][0][1][0][RTW89_KCC][4] = 24, - [0][0][1][0][RTW89_FCC][6] = 22, - [0][0][1][0][RTW89_ETSI][6] = 66, - [0][0][1][0][RTW89_KCC][6] = 24, - [0][0][1][0][RTW89_FCC][8] = 22, - [0][0][1][0][RTW89_ETSI][8] = 66, - [0][0][1][0][RTW89_KCC][8] = 24, - [0][0][1][0][RTW89_FCC][10] = 22, - [0][0][1][0][RTW89_ETSI][10] = 66, - [0][0][1][0][RTW89_KCC][10] = 24, - [0][0][1][0][RTW89_FCC][12] = 22, - [0][0][1][0][RTW89_ETSI][12] = 66, - [0][0][1][0][RTW89_KCC][12] = 24, - [0][0][1][0][RTW89_FCC][14] = 22, - [0][0][1][0][RTW89_ETSI][14] = 66, - [0][0][1][0][RTW89_KCC][14] = 24, - [0][0][1][0][RTW89_FCC][15] = 22, - [0][0][1][0][RTW89_ETSI][15] = 66, - [0][0][1][0][RTW89_KCC][15] = 24, - [0][0][1][0][RTW89_FCC][17] = 22, - [0][0][1][0][RTW89_ETSI][17] = 66, - [0][0][1][0][RTW89_KCC][17] = 24, - [0][0][1][0][RTW89_FCC][19] = 22, - [0][0][1][0][RTW89_ETSI][19] = 66, - [0][0][1][0][RTW89_KCC][19] = 24, - [0][0][1][0][RTW89_FCC][21] = 22, - [0][0][1][0][RTW89_ETSI][21] = 66, - [0][0][1][0][RTW89_KCC][21] = 24, - [0][0][1][0][RTW89_FCC][23] = 22, - [0][0][1][0][RTW89_ETSI][23] = 66, - [0][0][1][0][RTW89_KCC][23] = 24, - [0][0][1][0][RTW89_FCC][25] = 22, - [0][0][1][0][RTW89_ETSI][25] = 66, - [0][0][1][0][RTW89_KCC][25] = 24, - [0][0][1][0][RTW89_FCC][27] = 22, - [0][0][1][0][RTW89_ETSI][27] = 66, - [0][0][1][0][RTW89_KCC][27] = 24, - [0][0][1][0][RTW89_FCC][29] = 22, - [0][0][1][0][RTW89_ETSI][29] = 66, - [0][0][1][0][RTW89_KCC][29] = 24, - [0][0][1][0][RTW89_FCC][30] = 22, - [0][0][1][0][RTW89_ETSI][30] = 66, - [0][0][1][0][RTW89_KCC][30] = 24, - [0][0][1][0][RTW89_FCC][32] = 22, - [0][0][1][0][RTW89_ETSI][32] = 66, - [0][0][1][0][RTW89_KCC][32] = 24, - [0][0][1][0][RTW89_FCC][34] = 22, - [0][0][1][0][RTW89_ETSI][34] = 66, - [0][0][1][0][RTW89_KCC][34] = 24, - [0][0][1][0][RTW89_FCC][36] = 22, - [0][0][1][0][RTW89_ETSI][36] = 66, - [0][0][1][0][RTW89_KCC][36] = 24, - [0][0][1][0][RTW89_FCC][38] = 22, - [0][0][1][0][RTW89_ETSI][38] = 66, - [0][0][1][0][RTW89_KCC][38] = 24, - [0][0][1][0][RTW89_FCC][40] = 22, - [0][0][1][0][RTW89_ETSI][40] = 66, - [0][0][1][0][RTW89_KCC][40] = 24, - [0][0][1][0][RTW89_FCC][42] = 22, - [0][0][1][0][RTW89_ETSI][42] = 66, - [0][0][1][0][RTW89_KCC][42] = 24, - [0][0][1][0][RTW89_FCC][44] = 22, - [0][0][1][0][RTW89_ETSI][44] = 66, - [0][0][1][0][RTW89_KCC][44] = 24, - [0][0][1][0][RTW89_FCC][45] = 22, - [0][0][1][0][RTW89_ETSI][45] = 127, - [0][0][1][0][RTW89_KCC][45] = 24, - [0][0][1][0][RTW89_FCC][47] = 22, - [0][0][1][0][RTW89_ETSI][47] = 127, - [0][0][1][0][RTW89_KCC][47] = 24, - [0][0][1][0][RTW89_FCC][49] = 24, - [0][0][1][0][RTW89_ETSI][49] = 127, - [0][0][1][0][RTW89_KCC][49] = 24, - [0][0][1][0][RTW89_FCC][51] = 22, - [0][0][1][0][RTW89_ETSI][51] = 127, - [0][0][1][0][RTW89_KCC][51] = 24, - [0][0][1][0][RTW89_FCC][53] = 22, - [0][0][1][0][RTW89_ETSI][53] = 127, - [0][0][1][0][RTW89_KCC][53] = 24, - [0][0][1][0][RTW89_FCC][55] = 22, - [0][0][1][0][RTW89_ETSI][55] = 127, - [0][0][1][0][RTW89_KCC][55] = 26, - [0][0][1][0][RTW89_FCC][57] = 22, - [0][0][1][0][RTW89_ETSI][57] = 127, - [0][0][1][0][RTW89_KCC][57] = 26, - [0][0][1][0][RTW89_FCC][59] = 22, - [0][0][1][0][RTW89_ETSI][59] = 127, - [0][0][1][0][RTW89_KCC][59] = 26, - [0][0][1][0][RTW89_FCC][60] = 22, - [0][0][1][0][RTW89_ETSI][60] = 127, - [0][0][1][0][RTW89_KCC][60] = 26, - [0][0][1][0][RTW89_FCC][62] = 22, - [0][0][1][0][RTW89_ETSI][62] = 127, - [0][0][1][0][RTW89_KCC][62] = 26, - [0][0][1][0][RTW89_FCC][64] = 22, - [0][0][1][0][RTW89_ETSI][64] = 127, - [0][0][1][0][RTW89_KCC][64] = 26, - [0][0][1][0][RTW89_FCC][66] = 22, - [0][0][1][0][RTW89_ETSI][66] = 127, - [0][0][1][0][RTW89_KCC][66] = 26, - [0][0][1][0][RTW89_FCC][68] = 22, - [0][0][1][0][RTW89_ETSI][68] = 127, - [0][0][1][0][RTW89_KCC][68] = 26, - [0][0][1][0][RTW89_FCC][70] = 24, - [0][0][1][0][RTW89_ETSI][70] = 127, - [0][0][1][0][RTW89_KCC][70] = 26, - [0][0][1][0][RTW89_FCC][72] = 22, - [0][0][1][0][RTW89_ETSI][72] = 127, - [0][0][1][0][RTW89_KCC][72] = 26, - [0][0][1][0][RTW89_FCC][74] = 22, - [0][0][1][0][RTW89_ETSI][74] = 127, - [0][0][1][0][RTW89_KCC][74] = 26, - [0][0][1][0][RTW89_FCC][75] = 22, - [0][0][1][0][RTW89_ETSI][75] = 127, - [0][0][1][0][RTW89_KCC][75] = 26, - [0][0][1][0][RTW89_FCC][77] = 22, - [0][0][1][0][RTW89_ETSI][77] = 127, - [0][0][1][0][RTW89_KCC][77] = 26, - [0][0][1][0][RTW89_FCC][79] = 22, - [0][0][1][0][RTW89_ETSI][79] = 127, - [0][0][1][0][RTW89_KCC][79] = 26, - [0][0][1][0][RTW89_FCC][81] = 22, - [0][0][1][0][RTW89_ETSI][81] = 127, - [0][0][1][0][RTW89_KCC][81] = 26, - [0][0][1][0][RTW89_FCC][83] = 22, - [0][0][1][0][RTW89_ETSI][83] = 127, - [0][0][1][0][RTW89_KCC][83] = 32, - [0][0][1][0][RTW89_FCC][85] = 22, - [0][0][1][0][RTW89_ETSI][85] = 127, - [0][0][1][0][RTW89_KCC][85] = 32, - [0][0][1][0][RTW89_FCC][87] = 22, - [0][0][1][0][RTW89_ETSI][87] = 127, - [0][0][1][0][RTW89_KCC][87] = 32, - [0][0][1][0][RTW89_FCC][89] = 22, - [0][0][1][0][RTW89_ETSI][89] = 127, - [0][0][1][0][RTW89_KCC][89] = 32, - [0][0][1][0][RTW89_FCC][90] = 22, - [0][0][1][0][RTW89_ETSI][90] = 127, - [0][0][1][0][RTW89_KCC][90] = 32, - [0][0][1][0][RTW89_FCC][92] = 22, - [0][0][1][0][RTW89_ETSI][92] = 127, - [0][0][1][0][RTW89_KCC][92] = 32, - [0][0][1][0][RTW89_FCC][94] = 22, - [0][0][1][0][RTW89_ETSI][94] = 127, - [0][0][1][0][RTW89_KCC][94] = 32, - [0][0][1][0][RTW89_FCC][96] = 22, - [0][0][1][0][RTW89_ETSI][96] = 127, - [0][0][1][0][RTW89_KCC][96] = 32, - [0][0][1][0][RTW89_FCC][98] = 22, - [0][0][1][0][RTW89_ETSI][98] = 127, - [0][0][1][0][RTW89_KCC][98] = 32, - [0][0][1][0][RTW89_FCC][100] = 22, - [0][0][1][0][RTW89_ETSI][100] = 127, - [0][0][1][0][RTW89_KCC][100] = 32, - [0][0][1][0][RTW89_FCC][102] = 22, - [0][0][1][0][RTW89_ETSI][102] = 127, - [0][0][1][0][RTW89_KCC][102] = 32, - [0][0][1][0][RTW89_FCC][104] = 22, - [0][0][1][0][RTW89_ETSI][104] = 127, - [0][0][1][0][RTW89_KCC][104] = 32, - [0][0][1][0][RTW89_FCC][105] = 22, - [0][0][1][0][RTW89_ETSI][105] = 127, - [0][0][1][0][RTW89_KCC][105] = 32, - [0][0][1][0][RTW89_FCC][107] = 24, - [0][0][1][0][RTW89_ETSI][107] = 127, - [0][0][1][0][RTW89_KCC][107] = 32, - [0][0][1][0][RTW89_FCC][109] = 24, - [0][0][1][0][RTW89_ETSI][109] = 127, - [0][0][1][0][RTW89_KCC][109] = 32, - [0][0][1][0][RTW89_FCC][111] = 127, - [0][0][1][0][RTW89_ETSI][111] = 127, - [0][0][1][0][RTW89_KCC][111] = 127, - [0][0][1][0][RTW89_FCC][113] = 127, - [0][0][1][0][RTW89_ETSI][113] = 127, - [0][0][1][0][RTW89_KCC][113] = 127, - [0][0][1][0][RTW89_FCC][115] = 127, - [0][0][1][0][RTW89_ETSI][115] = 127, - [0][0][1][0][RTW89_KCC][115] = 127, - [0][0][1][0][RTW89_FCC][117] = 127, - [0][0][1][0][RTW89_ETSI][117] = 127, - [0][0][1][0][RTW89_KCC][117] = 127, - [0][0][1][0][RTW89_FCC][119] = 127, - [0][0][1][0][RTW89_ETSI][119] = 127, - [0][0][1][0][RTW89_KCC][119] = 127, - [0][1][1][0][RTW89_FCC][0] = -2, - [0][1][1][0][RTW89_ETSI][0] = 54, - [0][1][1][0][RTW89_KCC][0] = 12, - [0][1][1][0][RTW89_FCC][2] = -4, - [0][1][1][0][RTW89_ETSI][2] = 54, - [0][1][1][0][RTW89_KCC][2] = 12, - [0][1][1][0][RTW89_FCC][4] = -4, - [0][1][1][0][RTW89_ETSI][4] = 54, - [0][1][1][0][RTW89_KCC][4] = 12, - [0][1][1][0][RTW89_FCC][6] = -4, - [0][1][1][0][RTW89_ETSI][6] = 54, - [0][1][1][0][RTW89_KCC][6] = 12, - [0][1][1][0][RTW89_FCC][8] = -4, - [0][1][1][0][RTW89_ETSI][8] = 54, - [0][1][1][0][RTW89_KCC][8] = 12, - [0][1][1][0][RTW89_FCC][10] = -4, - [0][1][1][0][RTW89_ETSI][10] = 54, - [0][1][1][0][RTW89_KCC][10] = 12, - [0][1][1][0][RTW89_FCC][12] = -4, - [0][1][1][0][RTW89_ETSI][12] = 54, - [0][1][1][0][RTW89_KCC][12] = 12, - [0][1][1][0][RTW89_FCC][14] = -4, - [0][1][1][0][RTW89_ETSI][14] = 54, - [0][1][1][0][RTW89_KCC][14] = 12, - [0][1][1][0][RTW89_FCC][15] = -4, - [0][1][1][0][RTW89_ETSI][15] = 54, - [0][1][1][0][RTW89_KCC][15] = 12, - [0][1][1][0][RTW89_FCC][17] = -4, - [0][1][1][0][RTW89_ETSI][17] = 54, - [0][1][1][0][RTW89_KCC][17] = 12, - [0][1][1][0][RTW89_FCC][19] = -4, - [0][1][1][0][RTW89_ETSI][19] = 54, - [0][1][1][0][RTW89_KCC][19] = 12, - [0][1][1][0][RTW89_FCC][21] = -4, - [0][1][1][0][RTW89_ETSI][21] = 54, - [0][1][1][0][RTW89_KCC][21] = 12, - [0][1][1][0][RTW89_FCC][23] = -4, - [0][1][1][0][RTW89_ETSI][23] = 54, - [0][1][1][0][RTW89_KCC][23] = 12, - [0][1][1][0][RTW89_FCC][25] = -4, - [0][1][1][0][RTW89_ETSI][25] = 54, - [0][1][1][0][RTW89_KCC][25] = 12, - [0][1][1][0][RTW89_FCC][27] = -4, - [0][1][1][0][RTW89_ETSI][27] = 54, - [0][1][1][0][RTW89_KCC][27] = 12, - [0][1][1][0][RTW89_FCC][29] = -4, - [0][1][1][0][RTW89_ETSI][29] = 54, - [0][1][1][0][RTW89_KCC][29] = 12, - [0][1][1][0][RTW89_FCC][30] = -4, - [0][1][1][0][RTW89_ETSI][30] = 54, - [0][1][1][0][RTW89_KCC][30] = 12, - [0][1][1][0][RTW89_FCC][32] = -4, - [0][1][1][0][RTW89_ETSI][32] = 54, - [0][1][1][0][RTW89_KCC][32] = 12, - [0][1][1][0][RTW89_FCC][34] = -4, - [0][1][1][0][RTW89_ETSI][34] = 54, - [0][1][1][0][RTW89_KCC][34] = 12, - [0][1][1][0][RTW89_FCC][36] = -4, - [0][1][1][0][RTW89_ETSI][36] = 54, - [0][1][1][0][RTW89_KCC][36] = 12, - [0][1][1][0][RTW89_FCC][38] = -4, - [0][1][1][0][RTW89_ETSI][38] = 54, - [0][1][1][0][RTW89_KCC][38] = 12, - [0][1][1][0][RTW89_FCC][40] = -4, - [0][1][1][0][RTW89_ETSI][40] = 54, - [0][1][1][0][RTW89_KCC][40] = 12, - [0][1][1][0][RTW89_FCC][42] = -4, - [0][1][1][0][RTW89_ETSI][42] = 54, - [0][1][1][0][RTW89_KCC][42] = 12, - [0][1][1][0][RTW89_FCC][44] = -2, - [0][1][1][0][RTW89_ETSI][44] = 54, - [0][1][1][0][RTW89_KCC][44] = 12, - [0][1][1][0][RTW89_FCC][45] = -2, - [0][1][1][0][RTW89_ETSI][45] = 127, - [0][1][1][0][RTW89_KCC][45] = 12, - [0][1][1][0][RTW89_FCC][47] = -2, - [0][1][1][0][RTW89_ETSI][47] = 127, - [0][1][1][0][RTW89_KCC][47] = 12, - [0][1][1][0][RTW89_FCC][49] = -2, - [0][1][1][0][RTW89_ETSI][49] = 127, - [0][1][1][0][RTW89_KCC][49] = 12, - [0][1][1][0][RTW89_FCC][51] = -2, - [0][1][1][0][RTW89_ETSI][51] = 127, - [0][1][1][0][RTW89_KCC][51] = 12, - [0][1][1][0][RTW89_FCC][53] = -2, - [0][1][1][0][RTW89_ETSI][53] = 127, - [0][1][1][0][RTW89_KCC][53] = 12, - [0][1][1][0][RTW89_FCC][55] = -2, - [0][1][1][0][RTW89_ETSI][55] = 127, - [0][1][1][0][RTW89_KCC][55] = 12, - [0][1][1][0][RTW89_FCC][57] = -2, - [0][1][1][0][RTW89_ETSI][57] = 127, - [0][1][1][0][RTW89_KCC][57] = 12, - [0][1][1][0][RTW89_FCC][59] = -2, - [0][1][1][0][RTW89_ETSI][59] = 127, - [0][1][1][0][RTW89_KCC][59] = 12, - [0][1][1][0][RTW89_FCC][60] = -2, - [0][1][1][0][RTW89_ETSI][60] = 127, - [0][1][1][0][RTW89_KCC][60] = 12, - [0][1][1][0][RTW89_FCC][62] = -2, - [0][1][1][0][RTW89_ETSI][62] = 127, - [0][1][1][0][RTW89_KCC][62] = 12, - [0][1][1][0][RTW89_FCC][64] = -2, - [0][1][1][0][RTW89_ETSI][64] = 127, - [0][1][1][0][RTW89_KCC][64] = 12, - [0][1][1][0][RTW89_FCC][66] = -2, - [0][1][1][0][RTW89_ETSI][66] = 127, - [0][1][1][0][RTW89_KCC][66] = 12, - [0][1][1][0][RTW89_FCC][68] = -2, - [0][1][1][0][RTW89_ETSI][68] = 127, - [0][1][1][0][RTW89_KCC][68] = 12, - [0][1][1][0][RTW89_FCC][70] = -2, - [0][1][1][0][RTW89_ETSI][70] = 127, - [0][1][1][0][RTW89_KCC][70] = 12, - [0][1][1][0][RTW89_FCC][72] = -2, - [0][1][1][0][RTW89_ETSI][72] = 127, - [0][1][1][0][RTW89_KCC][72] = 12, - [0][1][1][0][RTW89_FCC][74] = -2, - [0][1][1][0][RTW89_ETSI][74] = 127, - [0][1][1][0][RTW89_KCC][74] = 12, - [0][1][1][0][RTW89_FCC][75] = -2, - [0][1][1][0][RTW89_ETSI][75] = 127, - [0][1][1][0][RTW89_KCC][75] = 12, - [0][1][1][0][RTW89_FCC][77] = -2, - [0][1][1][0][RTW89_ETSI][77] = 127, - [0][1][1][0][RTW89_KCC][77] = 12, - [0][1][1][0][RTW89_FCC][79] = -2, - [0][1][1][0][RTW89_ETSI][79] = 127, - [0][1][1][0][RTW89_KCC][79] = 12, - [0][1][1][0][RTW89_FCC][81] = -2, - [0][1][1][0][RTW89_ETSI][81] = 127, - [0][1][1][0][RTW89_KCC][81] = 12, - [0][1][1][0][RTW89_FCC][83] = -2, - [0][1][1][0][RTW89_ETSI][83] = 127, - [0][1][1][0][RTW89_KCC][83] = 20, - [0][1][1][0][RTW89_FCC][85] = -2, - [0][1][1][0][RTW89_ETSI][85] = 127, - [0][1][1][0][RTW89_KCC][85] = 20, - [0][1][1][0][RTW89_FCC][87] = -2, - [0][1][1][0][RTW89_ETSI][87] = 127, - [0][1][1][0][RTW89_KCC][87] = 20, - [0][1][1][0][RTW89_FCC][89] = -2, - [0][1][1][0][RTW89_ETSI][89] = 127, - [0][1][1][0][RTW89_KCC][89] = 20, - [0][1][1][0][RTW89_FCC][90] = -2, - [0][1][1][0][RTW89_ETSI][90] = 127, - [0][1][1][0][RTW89_KCC][90] = 20, - [0][1][1][0][RTW89_FCC][92] = -2, - [0][1][1][0][RTW89_ETSI][92] = 127, - [0][1][1][0][RTW89_KCC][92] = 20, - [0][1][1][0][RTW89_FCC][94] = -2, - [0][1][1][0][RTW89_ETSI][94] = 127, - [0][1][1][0][RTW89_KCC][94] = 20, - [0][1][1][0][RTW89_FCC][96] = -2, - [0][1][1][0][RTW89_ETSI][96] = 127, - [0][1][1][0][RTW89_KCC][96] = 20, - [0][1][1][0][RTW89_FCC][98] = -2, - [0][1][1][0][RTW89_ETSI][98] = 127, - [0][1][1][0][RTW89_KCC][98] = 20, - [0][1][1][0][RTW89_FCC][100] = -2, - [0][1][1][0][RTW89_ETSI][100] = 127, - [0][1][1][0][RTW89_KCC][100] = 20, - [0][1][1][0][RTW89_FCC][102] = -2, - [0][1][1][0][RTW89_ETSI][102] = 127, - [0][1][1][0][RTW89_KCC][102] = 20, - [0][1][1][0][RTW89_FCC][104] = -2, - [0][1][1][0][RTW89_ETSI][104] = 127, - [0][1][1][0][RTW89_KCC][104] = 20, - [0][1][1][0][RTW89_FCC][105] = -2, - [0][1][1][0][RTW89_ETSI][105] = 127, - [0][1][1][0][RTW89_KCC][105] = 20, - [0][1][1][0][RTW89_FCC][107] = 0, - [0][1][1][0][RTW89_ETSI][107] = 127, - [0][1][1][0][RTW89_KCC][107] = 20, - [0][1][1][0][RTW89_FCC][109] = 0, - [0][1][1][0][RTW89_ETSI][109] = 127, - [0][1][1][0][RTW89_KCC][109] = 20, - [0][1][1][0][RTW89_FCC][111] = 127, - [0][1][1][0][RTW89_ETSI][111] = 127, - [0][1][1][0][RTW89_KCC][111] = 127, - [0][1][1][0][RTW89_FCC][113] = 127, - [0][1][1][0][RTW89_ETSI][113] = 127, - [0][1][1][0][RTW89_KCC][113] = 127, - [0][1][1][0][RTW89_FCC][115] = 127, - [0][1][1][0][RTW89_ETSI][115] = 127, - [0][1][1][0][RTW89_KCC][115] = 127, - [0][1][1][0][RTW89_FCC][117] = 127, - [0][1][1][0][RTW89_ETSI][117] = 127, - [0][1][1][0][RTW89_KCC][117] = 127, - [0][1][1][0][RTW89_FCC][119] = 127, - [0][1][1][0][RTW89_ETSI][119] = 127, - [0][1][1][0][RTW89_KCC][119] = 127, - [0][0][2][0][RTW89_FCC][0] = 24, - [0][0][2][0][RTW89_ETSI][0] = 66, - [0][0][2][0][RTW89_KCC][0] = 24, - [0][0][2][0][RTW89_FCC][2] = 22, - [0][0][2][0][RTW89_ETSI][2] = 66, - [0][0][2][0][RTW89_KCC][2] = 24, - [0][0][2][0][RTW89_FCC][4] = 22, - [0][0][2][0][RTW89_ETSI][4] = 66, - [0][0][2][0][RTW89_KCC][4] = 24, - [0][0][2][0][RTW89_FCC][6] = 22, - [0][0][2][0][RTW89_ETSI][6] = 66, - [0][0][2][0][RTW89_KCC][6] = 24, - [0][0][2][0][RTW89_FCC][8] = 22, - [0][0][2][0][RTW89_ETSI][8] = 66, - [0][0][2][0][RTW89_KCC][8] = 24, - [0][0][2][0][RTW89_FCC][10] = 22, - [0][0][2][0][RTW89_ETSI][10] = 66, - [0][0][2][0][RTW89_KCC][10] = 24, - [0][0][2][0][RTW89_FCC][12] = 22, - [0][0][2][0][RTW89_ETSI][12] = 66, - [0][0][2][0][RTW89_KCC][12] = 24, - [0][0][2][0][RTW89_FCC][14] = 22, - [0][0][2][0][RTW89_ETSI][14] = 66, - [0][0][2][0][RTW89_KCC][14] = 24, - [0][0][2][0][RTW89_FCC][15] = 22, - [0][0][2][0][RTW89_ETSI][15] = 66, - [0][0][2][0][RTW89_KCC][15] = 24, - [0][0][2][0][RTW89_FCC][17] = 22, - [0][0][2][0][RTW89_ETSI][17] = 66, - [0][0][2][0][RTW89_KCC][17] = 24, - [0][0][2][0][RTW89_FCC][19] = 22, - [0][0][2][0][RTW89_ETSI][19] = 66, - [0][0][2][0][RTW89_KCC][19] = 24, - [0][0][2][0][RTW89_FCC][21] = 22, - [0][0][2][0][RTW89_ETSI][21] = 66, - [0][0][2][0][RTW89_KCC][21] = 24, - [0][0][2][0][RTW89_FCC][23] = 22, - [0][0][2][0][RTW89_ETSI][23] = 66, - [0][0][2][0][RTW89_KCC][23] = 24, - [0][0][2][0][RTW89_FCC][25] = 22, - [0][0][2][0][RTW89_ETSI][25] = 66, - [0][0][2][0][RTW89_KCC][25] = 24, - [0][0][2][0][RTW89_FCC][27] = 22, - [0][0][2][0][RTW89_ETSI][27] = 66, - [0][0][2][0][RTW89_KCC][27] = 24, - [0][0][2][0][RTW89_FCC][29] = 22, - [0][0][2][0][RTW89_ETSI][29] = 66, - [0][0][2][0][RTW89_KCC][29] = 24, - [0][0][2][0][RTW89_FCC][30] = 22, - [0][0][2][0][RTW89_ETSI][30] = 66, - [0][0][2][0][RTW89_KCC][30] = 24, - [0][0][2][0][RTW89_FCC][32] = 22, - [0][0][2][0][RTW89_ETSI][32] = 66, - [0][0][2][0][RTW89_KCC][32] = 24, - [0][0][2][0][RTW89_FCC][34] = 22, - [0][0][2][0][RTW89_ETSI][34] = 66, - [0][0][2][0][RTW89_KCC][34] = 24, - [0][0][2][0][RTW89_FCC][36] = 22, - [0][0][2][0][RTW89_ETSI][36] = 66, - [0][0][2][0][RTW89_KCC][36] = 24, - [0][0][2][0][RTW89_FCC][38] = 22, - [0][0][2][0][RTW89_ETSI][38] = 66, - [0][0][2][0][RTW89_KCC][38] = 24, - [0][0][2][0][RTW89_FCC][40] = 22, - [0][0][2][0][RTW89_ETSI][40] = 66, - [0][0][2][0][RTW89_KCC][40] = 24, - [0][0][2][0][RTW89_FCC][42] = 22, - [0][0][2][0][RTW89_ETSI][42] = 66, - [0][0][2][0][RTW89_KCC][42] = 24, - [0][0][2][0][RTW89_FCC][44] = 22, - [0][0][2][0][RTW89_ETSI][44] = 66, - [0][0][2][0][RTW89_KCC][44] = 24, - [0][0][2][0][RTW89_FCC][45] = 22, - [0][0][2][0][RTW89_ETSI][45] = 127, - [0][0][2][0][RTW89_KCC][45] = 24, - [0][0][2][0][RTW89_FCC][47] = 22, - [0][0][2][0][RTW89_ETSI][47] = 127, - [0][0][2][0][RTW89_KCC][47] = 24, - [0][0][2][0][RTW89_FCC][49] = 24, - [0][0][2][0][RTW89_ETSI][49] = 127, - [0][0][2][0][RTW89_KCC][49] = 24, - [0][0][2][0][RTW89_FCC][51] = 22, - [0][0][2][0][RTW89_ETSI][51] = 127, - [0][0][2][0][RTW89_KCC][51] = 24, - [0][0][2][0][RTW89_FCC][53] = 22, - [0][0][2][0][RTW89_ETSI][53] = 127, - [0][0][2][0][RTW89_KCC][53] = 24, - [0][0][2][0][RTW89_FCC][55] = 22, - [0][0][2][0][RTW89_ETSI][55] = 127, - [0][0][2][0][RTW89_KCC][55] = 26, - [0][0][2][0][RTW89_FCC][57] = 22, - [0][0][2][0][RTW89_ETSI][57] = 127, - [0][0][2][0][RTW89_KCC][57] = 26, - [0][0][2][0][RTW89_FCC][59] = 22, - [0][0][2][0][RTW89_ETSI][59] = 127, - [0][0][2][0][RTW89_KCC][59] = 26, - [0][0][2][0][RTW89_FCC][60] = 22, - [0][0][2][0][RTW89_ETSI][60] = 127, - [0][0][2][0][RTW89_KCC][60] = 26, - [0][0][2][0][RTW89_FCC][62] = 22, - [0][0][2][0][RTW89_ETSI][62] = 127, - [0][0][2][0][RTW89_KCC][62] = 26, - [0][0][2][0][RTW89_FCC][64] = 22, - [0][0][2][0][RTW89_ETSI][64] = 127, - [0][0][2][0][RTW89_KCC][64] = 26, - [0][0][2][0][RTW89_FCC][66] = 22, - [0][0][2][0][RTW89_ETSI][66] = 127, - [0][0][2][0][RTW89_KCC][66] = 26, - [0][0][2][0][RTW89_FCC][68] = 22, - [0][0][2][0][RTW89_ETSI][68] = 127, - [0][0][2][0][RTW89_KCC][68] = 26, - [0][0][2][0][RTW89_FCC][70] = 24, - [0][0][2][0][RTW89_ETSI][70] = 127, - [0][0][2][0][RTW89_KCC][70] = 26, - [0][0][2][0][RTW89_FCC][72] = 22, - [0][0][2][0][RTW89_ETSI][72] = 127, - [0][0][2][0][RTW89_KCC][72] = 26, - [0][0][2][0][RTW89_FCC][74] = 22, - [0][0][2][0][RTW89_ETSI][74] = 127, - [0][0][2][0][RTW89_KCC][74] = 26, - [0][0][2][0][RTW89_FCC][75] = 22, - [0][0][2][0][RTW89_ETSI][75] = 127, - [0][0][2][0][RTW89_KCC][75] = 26, - [0][0][2][0][RTW89_FCC][77] = 22, - [0][0][2][0][RTW89_ETSI][77] = 127, - [0][0][2][0][RTW89_KCC][77] = 26, - [0][0][2][0][RTW89_FCC][79] = 22, - [0][0][2][0][RTW89_ETSI][79] = 127, - [0][0][2][0][RTW89_KCC][79] = 26, - [0][0][2][0][RTW89_FCC][81] = 22, - [0][0][2][0][RTW89_ETSI][81] = 127, - [0][0][2][0][RTW89_KCC][81] = 26, - [0][0][2][0][RTW89_FCC][83] = 22, - [0][0][2][0][RTW89_ETSI][83] = 127, - [0][0][2][0][RTW89_KCC][83] = 32, - [0][0][2][0][RTW89_FCC][85] = 22, - [0][0][2][0][RTW89_ETSI][85] = 127, - [0][0][2][0][RTW89_KCC][85] = 32, - [0][0][2][0][RTW89_FCC][87] = 22, - [0][0][2][0][RTW89_ETSI][87] = 127, - [0][0][2][0][RTW89_KCC][87] = 32, - [0][0][2][0][RTW89_FCC][89] = 22, - [0][0][2][0][RTW89_ETSI][89] = 127, - [0][0][2][0][RTW89_KCC][89] = 32, - [0][0][2][0][RTW89_FCC][90] = 22, - [0][0][2][0][RTW89_ETSI][90] = 127, - [0][0][2][0][RTW89_KCC][90] = 32, - [0][0][2][0][RTW89_FCC][92] = 22, - [0][0][2][0][RTW89_ETSI][92] = 127, - [0][0][2][0][RTW89_KCC][92] = 32, - [0][0][2][0][RTW89_FCC][94] = 22, - [0][0][2][0][RTW89_ETSI][94] = 127, - [0][0][2][0][RTW89_KCC][94] = 32, - [0][0][2][0][RTW89_FCC][96] = 22, - [0][0][2][0][RTW89_ETSI][96] = 127, - [0][0][2][0][RTW89_KCC][96] = 32, - [0][0][2][0][RTW89_FCC][98] = 22, - [0][0][2][0][RTW89_ETSI][98] = 127, - [0][0][2][0][RTW89_KCC][98] = 32, - [0][0][2][0][RTW89_FCC][100] = 22, - [0][0][2][0][RTW89_ETSI][100] = 127, - [0][0][2][0][RTW89_KCC][100] = 32, - [0][0][2][0][RTW89_FCC][102] = 22, - [0][0][2][0][RTW89_ETSI][102] = 127, - [0][0][2][0][RTW89_KCC][102] = 32, - [0][0][2][0][RTW89_FCC][104] = 22, - [0][0][2][0][RTW89_ETSI][104] = 127, - [0][0][2][0][RTW89_KCC][104] = 32, - [0][0][2][0][RTW89_FCC][105] = 22, - [0][0][2][0][RTW89_ETSI][105] = 127, - [0][0][2][0][RTW89_KCC][105] = 32, - [0][0][2][0][RTW89_FCC][107] = 24, - [0][0][2][0][RTW89_ETSI][107] = 127, - [0][0][2][0][RTW89_KCC][107] = 32, - [0][0][2][0][RTW89_FCC][109] = 24, - [0][0][2][0][RTW89_ETSI][109] = 127, - [0][0][2][0][RTW89_KCC][109] = 32, - [0][0][2][0][RTW89_FCC][111] = 127, - [0][0][2][0][RTW89_ETSI][111] = 127, - [0][0][2][0][RTW89_KCC][111] = 127, - [0][0][2][0][RTW89_FCC][113] = 127, - [0][0][2][0][RTW89_ETSI][113] = 127, - [0][0][2][0][RTW89_KCC][113] = 127, - [0][0][2][0][RTW89_FCC][115] = 127, - [0][0][2][0][RTW89_ETSI][115] = 127, - [0][0][2][0][RTW89_KCC][115] = 127, - [0][0][2][0][RTW89_FCC][117] = 127, - [0][0][2][0][RTW89_ETSI][117] = 127, - [0][0][2][0][RTW89_KCC][117] = 127, - [0][0][2][0][RTW89_FCC][119] = 127, - [0][0][2][0][RTW89_ETSI][119] = 127, - [0][0][2][0][RTW89_KCC][119] = 127, - [0][1][2][0][RTW89_FCC][0] = -2, - [0][1][2][0][RTW89_ETSI][0] = 54, - [0][1][2][0][RTW89_KCC][0] = 12, - [0][1][2][0][RTW89_FCC][2] = -4, - [0][1][2][0][RTW89_ETSI][2] = 54, - [0][1][2][0][RTW89_KCC][2] = 12, - [0][1][2][0][RTW89_FCC][4] = -4, - [0][1][2][0][RTW89_ETSI][4] = 54, - [0][1][2][0][RTW89_KCC][4] = 12, - [0][1][2][0][RTW89_FCC][6] = -4, - [0][1][2][0][RTW89_ETSI][6] = 54, - [0][1][2][0][RTW89_KCC][6] = 12, - [0][1][2][0][RTW89_FCC][8] = -4, - [0][1][2][0][RTW89_ETSI][8] = 54, - [0][1][2][0][RTW89_KCC][8] = 12, - [0][1][2][0][RTW89_FCC][10] = -4, - [0][1][2][0][RTW89_ETSI][10] = 54, - [0][1][2][0][RTW89_KCC][10] = 12, - [0][1][2][0][RTW89_FCC][12] = -4, - [0][1][2][0][RTW89_ETSI][12] = 54, - [0][1][2][0][RTW89_KCC][12] = 12, - [0][1][2][0][RTW89_FCC][14] = -4, - [0][1][2][0][RTW89_ETSI][14] = 54, - [0][1][2][0][RTW89_KCC][14] = 12, - [0][1][2][0][RTW89_FCC][15] = -4, - [0][1][2][0][RTW89_ETSI][15] = 54, - [0][1][2][0][RTW89_KCC][15] = 12, - [0][1][2][0][RTW89_FCC][17] = -4, - [0][1][2][0][RTW89_ETSI][17] = 54, - [0][1][2][0][RTW89_KCC][17] = 12, - [0][1][2][0][RTW89_FCC][19] = -4, - [0][1][2][0][RTW89_ETSI][19] = 54, - [0][1][2][0][RTW89_KCC][19] = 12, - [0][1][2][0][RTW89_FCC][21] = -4, - [0][1][2][0][RTW89_ETSI][21] = 54, - [0][1][2][0][RTW89_KCC][21] = 12, - [0][1][2][0][RTW89_FCC][23] = -4, - [0][1][2][0][RTW89_ETSI][23] = 54, - [0][1][2][0][RTW89_KCC][23] = 12, - [0][1][2][0][RTW89_FCC][25] = -4, - [0][1][2][0][RTW89_ETSI][25] = 54, - [0][1][2][0][RTW89_KCC][25] = 12, - [0][1][2][0][RTW89_FCC][27] = -4, - [0][1][2][0][RTW89_ETSI][27] = 54, - [0][1][2][0][RTW89_KCC][27] = 12, - [0][1][2][0][RTW89_FCC][29] = -4, - [0][1][2][0][RTW89_ETSI][29] = 54, - [0][1][2][0][RTW89_KCC][29] = 12, - [0][1][2][0][RTW89_FCC][30] = -4, - [0][1][2][0][RTW89_ETSI][30] = 54, - [0][1][2][0][RTW89_KCC][30] = 12, - [0][1][2][0][RTW89_FCC][32] = -4, - [0][1][2][0][RTW89_ETSI][32] = 54, - [0][1][2][0][RTW89_KCC][32] = 12, - [0][1][2][0][RTW89_FCC][34] = -4, - [0][1][2][0][RTW89_ETSI][34] = 54, - [0][1][2][0][RTW89_KCC][34] = 12, - [0][1][2][0][RTW89_FCC][36] = -4, - [0][1][2][0][RTW89_ETSI][36] = 54, - [0][1][2][0][RTW89_KCC][36] = 12, - [0][1][2][0][RTW89_FCC][38] = -4, - [0][1][2][0][RTW89_ETSI][38] = 54, - [0][1][2][0][RTW89_KCC][38] = 12, - [0][1][2][0][RTW89_FCC][40] = -4, - [0][1][2][0][RTW89_ETSI][40] = 54, - [0][1][2][0][RTW89_KCC][40] = 12, - [0][1][2][0][RTW89_FCC][42] = -4, - [0][1][2][0][RTW89_ETSI][42] = 54, - [0][1][2][0][RTW89_KCC][42] = 12, - [0][1][2][0][RTW89_FCC][44] = -2, - [0][1][2][0][RTW89_ETSI][44] = 54, - [0][1][2][0][RTW89_KCC][44] = 12, - [0][1][2][0][RTW89_FCC][45] = -2, - [0][1][2][0][RTW89_ETSI][45] = 127, - [0][1][2][0][RTW89_KCC][45] = 12, - [0][1][2][0][RTW89_FCC][47] = -2, - [0][1][2][0][RTW89_ETSI][47] = 127, - [0][1][2][0][RTW89_KCC][47] = 12, - [0][1][2][0][RTW89_FCC][49] = -2, - [0][1][2][0][RTW89_ETSI][49] = 127, - [0][1][2][0][RTW89_KCC][49] = 12, - [0][1][2][0][RTW89_FCC][51] = -2, - [0][1][2][0][RTW89_ETSI][51] = 127, - [0][1][2][0][RTW89_KCC][51] = 12, - [0][1][2][0][RTW89_FCC][53] = -2, - [0][1][2][0][RTW89_ETSI][53] = 127, - [0][1][2][0][RTW89_KCC][53] = 12, - [0][1][2][0][RTW89_FCC][55] = -2, - [0][1][2][0][RTW89_ETSI][55] = 127, - [0][1][2][0][RTW89_KCC][55] = 12, - [0][1][2][0][RTW89_FCC][57] = -2, - [0][1][2][0][RTW89_ETSI][57] = 127, - [0][1][2][0][RTW89_KCC][57] = 12, - [0][1][2][0][RTW89_FCC][59] = -2, - [0][1][2][0][RTW89_ETSI][59] = 127, - [0][1][2][0][RTW89_KCC][59] = 12, - [0][1][2][0][RTW89_FCC][60] = -2, - [0][1][2][0][RTW89_ETSI][60] = 127, - [0][1][2][0][RTW89_KCC][60] = 12, - [0][1][2][0][RTW89_FCC][62] = -2, - [0][1][2][0][RTW89_ETSI][62] = 127, - [0][1][2][0][RTW89_KCC][62] = 12, - [0][1][2][0][RTW89_FCC][64] = -2, - [0][1][2][0][RTW89_ETSI][64] = 127, - [0][1][2][0][RTW89_KCC][64] = 12, - [0][1][2][0][RTW89_FCC][66] = -2, - [0][1][2][0][RTW89_ETSI][66] = 127, - [0][1][2][0][RTW89_KCC][66] = 12, - [0][1][2][0][RTW89_FCC][68] = -2, - [0][1][2][0][RTW89_ETSI][68] = 127, - [0][1][2][0][RTW89_KCC][68] = 12, - [0][1][2][0][RTW89_FCC][70] = -2, - [0][1][2][0][RTW89_ETSI][70] = 127, - [0][1][2][0][RTW89_KCC][70] = 12, - [0][1][2][0][RTW89_FCC][72] = -2, - [0][1][2][0][RTW89_ETSI][72] = 127, - [0][1][2][0][RTW89_KCC][72] = 12, - [0][1][2][0][RTW89_FCC][74] = -2, - [0][1][2][0][RTW89_ETSI][74] = 127, - [0][1][2][0][RTW89_KCC][74] = 12, - [0][1][2][0][RTW89_FCC][75] = -2, - [0][1][2][0][RTW89_ETSI][75] = 127, - [0][1][2][0][RTW89_KCC][75] = 12, - [0][1][2][0][RTW89_FCC][77] = -2, - [0][1][2][0][RTW89_ETSI][77] = 127, - [0][1][2][0][RTW89_KCC][77] = 12, - [0][1][2][0][RTW89_FCC][79] = -2, - [0][1][2][0][RTW89_ETSI][79] = 127, - [0][1][2][0][RTW89_KCC][79] = 12, - [0][1][2][0][RTW89_FCC][81] = -2, - [0][1][2][0][RTW89_ETSI][81] = 127, - [0][1][2][0][RTW89_KCC][81] = 12, - [0][1][2][0][RTW89_FCC][83] = -2, - [0][1][2][0][RTW89_ETSI][83] = 127, - [0][1][2][0][RTW89_KCC][83] = 20, - [0][1][2][0][RTW89_FCC][85] = -2, - [0][1][2][0][RTW89_ETSI][85] = 127, - [0][1][2][0][RTW89_KCC][85] = 20, - [0][1][2][0][RTW89_FCC][87] = -2, - [0][1][2][0][RTW89_ETSI][87] = 127, - [0][1][2][0][RTW89_KCC][87] = 20, - [0][1][2][0][RTW89_FCC][89] = -2, - [0][1][2][0][RTW89_ETSI][89] = 127, - [0][1][2][0][RTW89_KCC][89] = 20, - [0][1][2][0][RTW89_FCC][90] = -2, - [0][1][2][0][RTW89_ETSI][90] = 127, - [0][1][2][0][RTW89_KCC][90] = 20, - [0][1][2][0][RTW89_FCC][92] = -2, - [0][1][2][0][RTW89_ETSI][92] = 127, - [0][1][2][0][RTW89_KCC][92] = 20, - [0][1][2][0][RTW89_FCC][94] = -2, - [0][1][2][0][RTW89_ETSI][94] = 127, - [0][1][2][0][RTW89_KCC][94] = 20, - [0][1][2][0][RTW89_FCC][96] = -2, - [0][1][2][0][RTW89_ETSI][96] = 127, - [0][1][2][0][RTW89_KCC][96] = 20, - [0][1][2][0][RTW89_FCC][98] = -2, - [0][1][2][0][RTW89_ETSI][98] = 127, - [0][1][2][0][RTW89_KCC][98] = 20, - [0][1][2][0][RTW89_FCC][100] = -2, - [0][1][2][0][RTW89_ETSI][100] = 127, - [0][1][2][0][RTW89_KCC][100] = 20, - [0][1][2][0][RTW89_FCC][102] = -2, - [0][1][2][0][RTW89_ETSI][102] = 127, - [0][1][2][0][RTW89_KCC][102] = 20, - [0][1][2][0][RTW89_FCC][104] = -2, - [0][1][2][0][RTW89_ETSI][104] = 127, - [0][1][2][0][RTW89_KCC][104] = 20, - [0][1][2][0][RTW89_FCC][105] = -2, - [0][1][2][0][RTW89_ETSI][105] = 127, - [0][1][2][0][RTW89_KCC][105] = 20, - [0][1][2][0][RTW89_FCC][107] = 0, - [0][1][2][0][RTW89_ETSI][107] = 127, - [0][1][2][0][RTW89_KCC][107] = 20, - [0][1][2][0][RTW89_FCC][109] = 0, - [0][1][2][0][RTW89_ETSI][109] = 127, - [0][1][2][0][RTW89_KCC][109] = 20, - [0][1][2][0][RTW89_FCC][111] = 127, - [0][1][2][0][RTW89_ETSI][111] = 127, - [0][1][2][0][RTW89_KCC][111] = 127, - [0][1][2][0][RTW89_FCC][113] = 127, - [0][1][2][0][RTW89_ETSI][113] = 127, - [0][1][2][0][RTW89_KCC][113] = 127, - [0][1][2][0][RTW89_FCC][115] = 127, - [0][1][2][0][RTW89_ETSI][115] = 127, - [0][1][2][0][RTW89_KCC][115] = 127, - [0][1][2][0][RTW89_FCC][117] = 127, - [0][1][2][0][RTW89_ETSI][117] = 127, - [0][1][2][0][RTW89_KCC][117] = 127, - [0][1][2][0][RTW89_FCC][119] = 127, - [0][1][2][0][RTW89_ETSI][119] = 127, - [0][1][2][0][RTW89_KCC][119] = 127, - [0][1][2][1][RTW89_FCC][0] = -2, - [0][1][2][1][RTW89_ETSI][0] = 42, - [0][1][2][1][RTW89_KCC][0] = 12, - [0][1][2][1][RTW89_FCC][2] = -4, - [0][1][2][1][RTW89_ETSI][2] = 42, - [0][1][2][1][RTW89_KCC][2] = 12, - [0][1][2][1][RTW89_FCC][4] = -4, - [0][1][2][1][RTW89_ETSI][4] = 42, - [0][1][2][1][RTW89_KCC][4] = 12, - [0][1][2][1][RTW89_FCC][6] = -4, - [0][1][2][1][RTW89_ETSI][6] = 42, - [0][1][2][1][RTW89_KCC][6] = 12, - [0][1][2][1][RTW89_FCC][8] = -4, - [0][1][2][1][RTW89_ETSI][8] = 42, - [0][1][2][1][RTW89_KCC][8] = 12, - [0][1][2][1][RTW89_FCC][10] = -4, - [0][1][2][1][RTW89_ETSI][10] = 42, - [0][1][2][1][RTW89_KCC][10] = 12, - [0][1][2][1][RTW89_FCC][12] = -4, - [0][1][2][1][RTW89_ETSI][12] = 42, - [0][1][2][1][RTW89_KCC][12] = 12, - [0][1][2][1][RTW89_FCC][14] = -4, - [0][1][2][1][RTW89_ETSI][14] = 42, - [0][1][2][1][RTW89_KCC][14] = 12, - [0][1][2][1][RTW89_FCC][15] = -4, - [0][1][2][1][RTW89_ETSI][15] = 42, - [0][1][2][1][RTW89_KCC][15] = 12, - [0][1][2][1][RTW89_FCC][17] = -4, - [0][1][2][1][RTW89_ETSI][17] = 42, - [0][1][2][1][RTW89_KCC][17] = 12, - [0][1][2][1][RTW89_FCC][19] = -4, - [0][1][2][1][RTW89_ETSI][19] = 42, - [0][1][2][1][RTW89_KCC][19] = 12, - [0][1][2][1][RTW89_FCC][21] = -4, - [0][1][2][1][RTW89_ETSI][21] = 42, - [0][1][2][1][RTW89_KCC][21] = 12, - [0][1][2][1][RTW89_FCC][23] = -4, - [0][1][2][1][RTW89_ETSI][23] = 42, - [0][1][2][1][RTW89_KCC][23] = 12, - [0][1][2][1][RTW89_FCC][25] = -4, - [0][1][2][1][RTW89_ETSI][25] = 42, - [0][1][2][1][RTW89_KCC][25] = 12, - [0][1][2][1][RTW89_FCC][27] = -4, - [0][1][2][1][RTW89_ETSI][27] = 42, - [0][1][2][1][RTW89_KCC][27] = 12, - [0][1][2][1][RTW89_FCC][29] = -4, - [0][1][2][1][RTW89_ETSI][29] = 42, - [0][1][2][1][RTW89_KCC][29] = 12, - [0][1][2][1][RTW89_FCC][30] = -4, - [0][1][2][1][RTW89_ETSI][30] = 42, - [0][1][2][1][RTW89_KCC][30] = 12, - [0][1][2][1][RTW89_FCC][32] = -4, - [0][1][2][1][RTW89_ETSI][32] = 42, - [0][1][2][1][RTW89_KCC][32] = 12, - [0][1][2][1][RTW89_FCC][34] = -4, - [0][1][2][1][RTW89_ETSI][34] = 42, - [0][1][2][1][RTW89_KCC][34] = 12, - [0][1][2][1][RTW89_FCC][36] = -4, - [0][1][2][1][RTW89_ETSI][36] = 42, - [0][1][2][1][RTW89_KCC][36] = 12, - [0][1][2][1][RTW89_FCC][38] = -4, - [0][1][2][1][RTW89_ETSI][38] = 42, - [0][1][2][1][RTW89_KCC][38] = 12, - [0][1][2][1][RTW89_FCC][40] = -4, - [0][1][2][1][RTW89_ETSI][40] = 42, - [0][1][2][1][RTW89_KCC][40] = 12, - [0][1][2][1][RTW89_FCC][42] = -4, - [0][1][2][1][RTW89_ETSI][42] = 42, - [0][1][2][1][RTW89_KCC][42] = 12, - [0][1][2][1][RTW89_FCC][44] = -2, - [0][1][2][1][RTW89_ETSI][44] = 42, - [0][1][2][1][RTW89_KCC][44] = 12, - [0][1][2][1][RTW89_FCC][45] = -2, - [0][1][2][1][RTW89_ETSI][45] = 127, - [0][1][2][1][RTW89_KCC][45] = 12, - [0][1][2][1][RTW89_FCC][47] = -2, - [0][1][2][1][RTW89_ETSI][47] = 127, - [0][1][2][1][RTW89_KCC][47] = 12, - [0][1][2][1][RTW89_FCC][49] = -2, - [0][1][2][1][RTW89_ETSI][49] = 127, - [0][1][2][1][RTW89_KCC][49] = 12, - [0][1][2][1][RTW89_FCC][51] = -2, - [0][1][2][1][RTW89_ETSI][51] = 127, - [0][1][2][1][RTW89_KCC][51] = 12, - [0][1][2][1][RTW89_FCC][53] = -2, - [0][1][2][1][RTW89_ETSI][53] = 127, - [0][1][2][1][RTW89_KCC][53] = 12, - [0][1][2][1][RTW89_FCC][55] = -2, - [0][1][2][1][RTW89_ETSI][55] = 127, - [0][1][2][1][RTW89_KCC][55] = 12, - [0][1][2][1][RTW89_FCC][57] = -2, - [0][1][2][1][RTW89_ETSI][57] = 127, - [0][1][2][1][RTW89_KCC][57] = 12, - [0][1][2][1][RTW89_FCC][59] = -2, - [0][1][2][1][RTW89_ETSI][59] = 127, - [0][1][2][1][RTW89_KCC][59] = 12, - [0][1][2][1][RTW89_FCC][60] = -2, - [0][1][2][1][RTW89_ETSI][60] = 127, - [0][1][2][1][RTW89_KCC][60] = 12, - [0][1][2][1][RTW89_FCC][62] = -2, - [0][1][2][1][RTW89_ETSI][62] = 127, - [0][1][2][1][RTW89_KCC][62] = 12, - [0][1][2][1][RTW89_FCC][64] = -2, - [0][1][2][1][RTW89_ETSI][64] = 127, - [0][1][2][1][RTW89_KCC][64] = 12, - [0][1][2][1][RTW89_FCC][66] = -2, - [0][1][2][1][RTW89_ETSI][66] = 127, - [0][1][2][1][RTW89_KCC][66] = 12, - [0][1][2][1][RTW89_FCC][68] = -2, - [0][1][2][1][RTW89_ETSI][68] = 127, - [0][1][2][1][RTW89_KCC][68] = 12, - [0][1][2][1][RTW89_FCC][70] = -2, - [0][1][2][1][RTW89_ETSI][70] = 127, - [0][1][2][1][RTW89_KCC][70] = 12, - [0][1][2][1][RTW89_FCC][72] = -2, - [0][1][2][1][RTW89_ETSI][72] = 127, - [0][1][2][1][RTW89_KCC][72] = 12, - [0][1][2][1][RTW89_FCC][74] = -2, - [0][1][2][1][RTW89_ETSI][74] = 127, - [0][1][2][1][RTW89_KCC][74] = 12, - [0][1][2][1][RTW89_FCC][75] = -2, - [0][1][2][1][RTW89_ETSI][75] = 127, - [0][1][2][1][RTW89_KCC][75] = 12, - [0][1][2][1][RTW89_FCC][77] = -2, - [0][1][2][1][RTW89_ETSI][77] = 127, - [0][1][2][1][RTW89_KCC][77] = 12, - [0][1][2][1][RTW89_FCC][79] = -2, - [0][1][2][1][RTW89_ETSI][79] = 127, - [0][1][2][1][RTW89_KCC][79] = 12, - [0][1][2][1][RTW89_FCC][81] = -2, - [0][1][2][1][RTW89_ETSI][81] = 127, - [0][1][2][1][RTW89_KCC][81] = 12, - [0][1][2][1][RTW89_FCC][83] = -2, - [0][1][2][1][RTW89_ETSI][83] = 127, - [0][1][2][1][RTW89_KCC][83] = 20, - [0][1][2][1][RTW89_FCC][85] = -2, - [0][1][2][1][RTW89_ETSI][85] = 127, - [0][1][2][1][RTW89_KCC][85] = 20, - [0][1][2][1][RTW89_FCC][87] = -2, - [0][1][2][1][RTW89_ETSI][87] = 127, - [0][1][2][1][RTW89_KCC][87] = 20, - [0][1][2][1][RTW89_FCC][89] = -2, - [0][1][2][1][RTW89_ETSI][89] = 127, - [0][1][2][1][RTW89_KCC][89] = 20, - [0][1][2][1][RTW89_FCC][90] = -2, - [0][1][2][1][RTW89_ETSI][90] = 127, - [0][1][2][1][RTW89_KCC][90] = 20, - [0][1][2][1][RTW89_FCC][92] = -2, - [0][1][2][1][RTW89_ETSI][92] = 127, - [0][1][2][1][RTW89_KCC][92] = 20, - [0][1][2][1][RTW89_FCC][94] = -2, - [0][1][2][1][RTW89_ETSI][94] = 127, - [0][1][2][1][RTW89_KCC][94] = 20, - [0][1][2][1][RTW89_FCC][96] = -2, - [0][1][2][1][RTW89_ETSI][96] = 127, - [0][1][2][1][RTW89_KCC][96] = 20, - [0][1][2][1][RTW89_FCC][98] = -2, - [0][1][2][1][RTW89_ETSI][98] = 127, - [0][1][2][1][RTW89_KCC][98] = 20, - [0][1][2][1][RTW89_FCC][100] = -2, - [0][1][2][1][RTW89_ETSI][100] = 127, - [0][1][2][1][RTW89_KCC][100] = 20, - [0][1][2][1][RTW89_FCC][102] = -2, - [0][1][2][1][RTW89_ETSI][102] = 127, - [0][1][2][1][RTW89_KCC][102] = 20, - [0][1][2][1][RTW89_FCC][104] = -2, - [0][1][2][1][RTW89_ETSI][104] = 127, - [0][1][2][1][RTW89_KCC][104] = 20, - [0][1][2][1][RTW89_FCC][105] = -2, - [0][1][2][1][RTW89_ETSI][105] = 127, - [0][1][2][1][RTW89_KCC][105] = 20, - [0][1][2][1][RTW89_FCC][107] = 0, - [0][1][2][1][RTW89_ETSI][107] = 127, - [0][1][2][1][RTW89_KCC][107] = 20, - [0][1][2][1][RTW89_FCC][109] = 0, - [0][1][2][1][RTW89_ETSI][109] = 127, - [0][1][2][1][RTW89_KCC][109] = 20, - [0][1][2][1][RTW89_FCC][111] = 127, - [0][1][2][1][RTW89_ETSI][111] = 127, - [0][1][2][1][RTW89_KCC][111] = 127, - [0][1][2][1][RTW89_FCC][113] = 127, - [0][1][2][1][RTW89_ETSI][113] = 127, - [0][1][2][1][RTW89_KCC][113] = 127, - [0][1][2][1][RTW89_FCC][115] = 127, - [0][1][2][1][RTW89_ETSI][115] = 127, - [0][1][2][1][RTW89_KCC][115] = 127, - [0][1][2][1][RTW89_FCC][117] = 127, - [0][1][2][1][RTW89_ETSI][117] = 127, - [0][1][2][1][RTW89_KCC][117] = 127, - [0][1][2][1][RTW89_FCC][119] = 127, - [0][1][2][1][RTW89_ETSI][119] = 127, - [0][1][2][1][RTW89_KCC][119] = 127, - [1][0][2][0][RTW89_FCC][1] = 34, - [1][0][2][0][RTW89_ETSI][1] = 66, - [1][0][2][0][RTW89_KCC][1] = 40, - [1][0][2][0][RTW89_FCC][5] = 34, - [1][0][2][0][RTW89_ETSI][5] = 66, - [1][0][2][0][RTW89_KCC][5] = 40, - [1][0][2][0][RTW89_FCC][9] = 34, - [1][0][2][0][RTW89_ETSI][9] = 66, - [1][0][2][0][RTW89_KCC][9] = 40, - [1][0][2][0][RTW89_FCC][13] = 34, - [1][0][2][0][RTW89_ETSI][13] = 66, - [1][0][2][0][RTW89_KCC][13] = 40, - [1][0][2][0][RTW89_FCC][16] = 34, - [1][0][2][0][RTW89_ETSI][16] = 66, - [1][0][2][0][RTW89_KCC][16] = 40, - [1][0][2][0][RTW89_FCC][20] = 34, - [1][0][2][0][RTW89_ETSI][20] = 66, - [1][0][2][0][RTW89_KCC][20] = 40, - [1][0][2][0][RTW89_FCC][24] = 36, - [1][0][2][0][RTW89_ETSI][24] = 66, - [1][0][2][0][RTW89_KCC][24] = 40, - [1][0][2][0][RTW89_FCC][28] = 34, - [1][0][2][0][RTW89_ETSI][28] = 66, - [1][0][2][0][RTW89_KCC][28] = 40, - [1][0][2][0][RTW89_FCC][31] = 34, - [1][0][2][0][RTW89_ETSI][31] = 66, - [1][0][2][0][RTW89_KCC][31] = 40, - [1][0][2][0][RTW89_FCC][35] = 34, - [1][0][2][0][RTW89_ETSI][35] = 66, - [1][0][2][0][RTW89_KCC][35] = 40, - [1][0][2][0][RTW89_FCC][39] = 34, - [1][0][2][0][RTW89_ETSI][39] = 66, - [1][0][2][0][RTW89_KCC][39] = 40, - [1][0][2][0][RTW89_FCC][43] = 34, - [1][0][2][0][RTW89_ETSI][43] = 66, - [1][0][2][0][RTW89_KCC][43] = 40, - [1][0][2][0][RTW89_FCC][46] = 34, - [1][0][2][0][RTW89_ETSI][46] = 127, - [1][0][2][0][RTW89_KCC][46] = 40, - [1][0][2][0][RTW89_FCC][50] = 34, - [1][0][2][0][RTW89_ETSI][50] = 127, - [1][0][2][0][RTW89_KCC][50] = 40, - [1][0][2][0][RTW89_FCC][54] = 36, - [1][0][2][0][RTW89_ETSI][54] = 127, - [1][0][2][0][RTW89_KCC][54] = 40, - [1][0][2][0][RTW89_FCC][58] = 36, - [1][0][2][0][RTW89_ETSI][58] = 127, - [1][0][2][0][RTW89_KCC][58] = 40, - [1][0][2][0][RTW89_FCC][61] = 34, - [1][0][2][0][RTW89_ETSI][61] = 127, - [1][0][2][0][RTW89_KCC][61] = 40, - [1][0][2][0][RTW89_FCC][65] = 34, - [1][0][2][0][RTW89_ETSI][65] = 127, - [1][0][2][0][RTW89_KCC][65] = 40, - [1][0][2][0][RTW89_FCC][69] = 34, - [1][0][2][0][RTW89_ETSI][69] = 127, - [1][0][2][0][RTW89_KCC][69] = 40, - [1][0][2][0][RTW89_FCC][73] = 34, - [1][0][2][0][RTW89_ETSI][73] = 127, - [1][0][2][0][RTW89_KCC][73] = 40, - [1][0][2][0][RTW89_FCC][76] = 34, - [1][0][2][0][RTW89_ETSI][76] = 127, - [1][0][2][0][RTW89_KCC][76] = 40, - [1][0][2][0][RTW89_FCC][80] = 34, - [1][0][2][0][RTW89_ETSI][80] = 127, - [1][0][2][0][RTW89_KCC][80] = 42, - [1][0][2][0][RTW89_FCC][84] = 34, - [1][0][2][0][RTW89_ETSI][84] = 127, - [1][0][2][0][RTW89_KCC][84] = 42, - [1][0][2][0][RTW89_FCC][88] = 34, - [1][0][2][0][RTW89_ETSI][88] = 127, - [1][0][2][0][RTW89_KCC][88] = 42, - [1][0][2][0][RTW89_FCC][91] = 36, - [1][0][2][0][RTW89_ETSI][91] = 127, - [1][0][2][0][RTW89_KCC][91] = 42, - [1][0][2][0][RTW89_FCC][95] = 34, - [1][0][2][0][RTW89_ETSI][95] = 127, - [1][0][2][0][RTW89_KCC][95] = 42, - [1][0][2][0][RTW89_FCC][99] = 34, - [1][0][2][0][RTW89_ETSI][99] = 127, - [1][0][2][0][RTW89_KCC][99] = 42, - [1][0][2][0][RTW89_FCC][103] = 34, - [1][0][2][0][RTW89_ETSI][103] = 127, - [1][0][2][0][RTW89_KCC][103] = 42, - [1][0][2][0][RTW89_FCC][106] = 36, - [1][0][2][0][RTW89_ETSI][106] = 127, - [1][0][2][0][RTW89_KCC][106] = 42, - [1][0][2][0][RTW89_FCC][110] = 127, - [1][0][2][0][RTW89_ETSI][110] = 127, - [1][0][2][0][RTW89_KCC][110] = 127, - [1][0][2][0][RTW89_FCC][114] = 127, - [1][0][2][0][RTW89_ETSI][114] = 127, - [1][0][2][0][RTW89_KCC][114] = 127, - [1][0][2][0][RTW89_FCC][118] = 127, - [1][0][2][0][RTW89_ETSI][118] = 127, - [1][0][2][0][RTW89_KCC][118] = 127, - [1][1][2][0][RTW89_FCC][1] = 10, - [1][1][2][0][RTW89_ETSI][1] = 54, - [1][1][2][0][RTW89_KCC][1] = 28, - [1][1][2][0][RTW89_FCC][5] = 10, - [1][1][2][0][RTW89_ETSI][5] = 54, - [1][1][2][0][RTW89_KCC][5] = 28, - [1][1][2][0][RTW89_FCC][9] = 10, - [1][1][2][0][RTW89_ETSI][9] = 54, - [1][1][2][0][RTW89_KCC][9] = 28, - [1][1][2][0][RTW89_FCC][13] = 10, - [1][1][2][0][RTW89_ETSI][13] = 54, - [1][1][2][0][RTW89_KCC][13] = 28, - [1][1][2][0][RTW89_FCC][16] = 10, - [1][1][2][0][RTW89_ETSI][16] = 54, - [1][1][2][0][RTW89_KCC][16] = 28, - [1][1][2][0][RTW89_FCC][20] = 10, - [1][1][2][0][RTW89_ETSI][20] = 54, - [1][1][2][0][RTW89_KCC][20] = 28, - [1][1][2][0][RTW89_FCC][24] = 10, - [1][1][2][0][RTW89_ETSI][24] = 54, - [1][1][2][0][RTW89_KCC][24] = 28, - [1][1][2][0][RTW89_FCC][28] = 10, - [1][1][2][0][RTW89_ETSI][28] = 54, - [1][1][2][0][RTW89_KCC][28] = 28, - [1][1][2][0][RTW89_FCC][31] = 10, - [1][1][2][0][RTW89_ETSI][31] = 54, - [1][1][2][0][RTW89_KCC][31] = 28, - [1][1][2][0][RTW89_FCC][35] = 10, - [1][1][2][0][RTW89_ETSI][35] = 54, - [1][1][2][0][RTW89_KCC][35] = 28, - [1][1][2][0][RTW89_FCC][39] = 10, - [1][1][2][0][RTW89_ETSI][39] = 54, - [1][1][2][0][RTW89_KCC][39] = 28, - [1][1][2][0][RTW89_FCC][43] = 10, - [1][1][2][0][RTW89_ETSI][43] = 54, - [1][1][2][0][RTW89_KCC][43] = 28, - [1][1][2][0][RTW89_FCC][46] = 12, - [1][1][2][0][RTW89_ETSI][46] = 127, - [1][1][2][0][RTW89_KCC][46] = 28, - [1][1][2][0][RTW89_FCC][50] = 12, - [1][1][2][0][RTW89_ETSI][50] = 127, - [1][1][2][0][RTW89_KCC][50] = 28, - [1][1][2][0][RTW89_FCC][54] = 10, - [1][1][2][0][RTW89_ETSI][54] = 127, - [1][1][2][0][RTW89_KCC][54] = 28, - [1][1][2][0][RTW89_FCC][58] = 10, - [1][1][2][0][RTW89_ETSI][58] = 127, - [1][1][2][0][RTW89_KCC][58] = 28, - [1][1][2][0][RTW89_FCC][61] = 10, - [1][1][2][0][RTW89_ETSI][61] = 127, - [1][1][2][0][RTW89_KCC][61] = 28, - [1][1][2][0][RTW89_FCC][65] = 10, - [1][1][2][0][RTW89_ETSI][65] = 127, - [1][1][2][0][RTW89_KCC][65] = 28, - [1][1][2][0][RTW89_FCC][69] = 10, - [1][1][2][0][RTW89_ETSI][69] = 127, - [1][1][2][0][RTW89_KCC][69] = 28, - [1][1][2][0][RTW89_FCC][73] = 10, - [1][1][2][0][RTW89_ETSI][73] = 127, - [1][1][2][0][RTW89_KCC][73] = 28, - [1][1][2][0][RTW89_FCC][76] = 10, - [1][1][2][0][RTW89_ETSI][76] = 127, - [1][1][2][0][RTW89_KCC][76] = 28, - [1][1][2][0][RTW89_FCC][80] = 10, - [1][1][2][0][RTW89_ETSI][80] = 127, - [1][1][2][0][RTW89_KCC][80] = 32, - [1][1][2][0][RTW89_FCC][84] = 10, - [1][1][2][0][RTW89_ETSI][84] = 127, - [1][1][2][0][RTW89_KCC][84] = 32, - [1][1][2][0][RTW89_FCC][88] = 10, - [1][1][2][0][RTW89_ETSI][88] = 127, - [1][1][2][0][RTW89_KCC][88] = 32, - [1][1][2][0][RTW89_FCC][91] = 12, - [1][1][2][0][RTW89_ETSI][91] = 127, - [1][1][2][0][RTW89_KCC][91] = 32, - [1][1][2][0][RTW89_FCC][95] = 10, - [1][1][2][0][RTW89_ETSI][95] = 127, - [1][1][2][0][RTW89_KCC][95] = 32, - [1][1][2][0][RTW89_FCC][99] = 10, - [1][1][2][0][RTW89_ETSI][99] = 127, - [1][1][2][0][RTW89_KCC][99] = 32, - [1][1][2][0][RTW89_FCC][103] = 10, - [1][1][2][0][RTW89_ETSI][103] = 127, - [1][1][2][0][RTW89_KCC][103] = 32, - [1][1][2][0][RTW89_FCC][106] = 12, - [1][1][2][0][RTW89_ETSI][106] = 127, - [1][1][2][0][RTW89_KCC][106] = 32, - [1][1][2][0][RTW89_FCC][110] = 127, - [1][1][2][0][RTW89_ETSI][110] = 127, - [1][1][2][0][RTW89_KCC][110] = 127, - [1][1][2][0][RTW89_FCC][114] = 127, - [1][1][2][0][RTW89_ETSI][114] = 127, - [1][1][2][0][RTW89_KCC][114] = 127, - [1][1][2][0][RTW89_FCC][118] = 127, - [1][1][2][0][RTW89_ETSI][118] = 127, - [1][1][2][0][RTW89_KCC][118] = 127, - [1][1][2][1][RTW89_FCC][1] = 10, - [1][1][2][1][RTW89_ETSI][1] = 42, - [1][1][2][1][RTW89_KCC][1] = 28, - [1][1][2][1][RTW89_FCC][5] = 10, - [1][1][2][1][RTW89_ETSI][5] = 42, - [1][1][2][1][RTW89_KCC][5] = 28, - [1][1][2][1][RTW89_FCC][9] = 10, - [1][1][2][1][RTW89_ETSI][9] = 42, - [1][1][2][1][RTW89_KCC][9] = 28, - [1][1][2][1][RTW89_FCC][13] = 10, - [1][1][2][1][RTW89_ETSI][13] = 42, - [1][1][2][1][RTW89_KCC][13] = 28, - [1][1][2][1][RTW89_FCC][16] = 10, - [1][1][2][1][RTW89_ETSI][16] = 42, - [1][1][2][1][RTW89_KCC][16] = 28, - [1][1][2][1][RTW89_FCC][20] = 10, - [1][1][2][1][RTW89_ETSI][20] = 42, - [1][1][2][1][RTW89_KCC][20] = 28, - [1][1][2][1][RTW89_FCC][24] = 10, - [1][1][2][1][RTW89_ETSI][24] = 42, - [1][1][2][1][RTW89_KCC][24] = 28, - [1][1][2][1][RTW89_FCC][28] = 10, - [1][1][2][1][RTW89_ETSI][28] = 42, - [1][1][2][1][RTW89_KCC][28] = 28, - [1][1][2][1][RTW89_FCC][31] = 10, - [1][1][2][1][RTW89_ETSI][31] = 42, - [1][1][2][1][RTW89_KCC][31] = 28, - [1][1][2][1][RTW89_FCC][35] = 10, - [1][1][2][1][RTW89_ETSI][35] = 42, - [1][1][2][1][RTW89_KCC][35] = 28, - [1][1][2][1][RTW89_FCC][39] = 10, - [1][1][2][1][RTW89_ETSI][39] = 42, - [1][1][2][1][RTW89_KCC][39] = 28, - [1][1][2][1][RTW89_FCC][43] = 10, - [1][1][2][1][RTW89_ETSI][43] = 42, - [1][1][2][1][RTW89_KCC][43] = 28, - [1][1][2][1][RTW89_FCC][46] = 12, - [1][1][2][1][RTW89_ETSI][46] = 127, - [1][1][2][1][RTW89_KCC][46] = 28, - [1][1][2][1][RTW89_FCC][50] = 12, - [1][1][2][1][RTW89_ETSI][50] = 127, - [1][1][2][1][RTW89_KCC][50] = 28, - [1][1][2][1][RTW89_FCC][54] = 10, - [1][1][2][1][RTW89_ETSI][54] = 127, - [1][1][2][1][RTW89_KCC][54] = 28, - [1][1][2][1][RTW89_FCC][58] = 10, - [1][1][2][1][RTW89_ETSI][58] = 127, - [1][1][2][1][RTW89_KCC][58] = 28, - [1][1][2][1][RTW89_FCC][61] = 10, - [1][1][2][1][RTW89_ETSI][61] = 127, - [1][1][2][1][RTW89_KCC][61] = 28, - [1][1][2][1][RTW89_FCC][65] = 10, - [1][1][2][1][RTW89_ETSI][65] = 127, - [1][1][2][1][RTW89_KCC][65] = 28, - [1][1][2][1][RTW89_FCC][69] = 10, - [1][1][2][1][RTW89_ETSI][69] = 127, - [1][1][2][1][RTW89_KCC][69] = 28, - [1][1][2][1][RTW89_FCC][73] = 10, - [1][1][2][1][RTW89_ETSI][73] = 127, - [1][1][2][1][RTW89_KCC][73] = 28, - [1][1][2][1][RTW89_FCC][76] = 10, - [1][1][2][1][RTW89_ETSI][76] = 127, - [1][1][2][1][RTW89_KCC][76] = 28, - [1][1][2][1][RTW89_FCC][80] = 10, - [1][1][2][1][RTW89_ETSI][80] = 127, - [1][1][2][1][RTW89_KCC][80] = 32, - [1][1][2][1][RTW89_FCC][84] = 10, - [1][1][2][1][RTW89_ETSI][84] = 127, - [1][1][2][1][RTW89_KCC][84] = 32, - [1][1][2][1][RTW89_FCC][88] = 10, - [1][1][2][1][RTW89_ETSI][88] = 127, - [1][1][2][1][RTW89_KCC][88] = 32, - [1][1][2][1][RTW89_FCC][91] = 12, - [1][1][2][1][RTW89_ETSI][91] = 127, - [1][1][2][1][RTW89_KCC][91] = 32, - [1][1][2][1][RTW89_FCC][95] = 10, - [1][1][2][1][RTW89_ETSI][95] = 127, - [1][1][2][1][RTW89_KCC][95] = 32, - [1][1][2][1][RTW89_FCC][99] = 10, - [1][1][2][1][RTW89_ETSI][99] = 127, - [1][1][2][1][RTW89_KCC][99] = 32, - [1][1][2][1][RTW89_FCC][103] = 10, - [1][1][2][1][RTW89_ETSI][103] = 127, - [1][1][2][1][RTW89_KCC][103] = 32, - [1][1][2][1][RTW89_FCC][106] = 12, - [1][1][2][1][RTW89_ETSI][106] = 127, - [1][1][2][1][RTW89_KCC][106] = 32, - [1][1][2][1][RTW89_FCC][110] = 127, - [1][1][2][1][RTW89_ETSI][110] = 127, - [1][1][2][1][RTW89_KCC][110] = 127, - [1][1][2][1][RTW89_FCC][114] = 127, - [1][1][2][1][RTW89_ETSI][114] = 127, - [1][1][2][1][RTW89_KCC][114] = 127, - [1][1][2][1][RTW89_FCC][118] = 127, - [1][1][2][1][RTW89_ETSI][118] = 127, - [1][1][2][1][RTW89_KCC][118] = 127, - [2][0][2][0][RTW89_FCC][3] = 46, - [2][0][2][0][RTW89_ETSI][3] = 48, - [2][0][2][0][RTW89_KCC][3] = 50, - [2][0][2][0][RTW89_FCC][11] = 46, - [2][0][2][0][RTW89_ETSI][11] = 48, - [2][0][2][0][RTW89_KCC][11] = 50, - [2][0][2][0][RTW89_FCC][18] = 46, - [2][0][2][0][RTW89_ETSI][18] = 48, - [2][0][2][0][RTW89_KCC][18] = 50, - [2][0][2][0][RTW89_FCC][26] = 46, - [2][0][2][0][RTW89_ETSI][26] = 48, - [2][0][2][0][RTW89_KCC][26] = 50, - [2][0][2][0][RTW89_FCC][33] = 46, - [2][0][2][0][RTW89_ETSI][33] = 48, - [2][0][2][0][RTW89_KCC][33] = 50, - [2][0][2][0][RTW89_FCC][41] = 46, - [2][0][2][0][RTW89_ETSI][41] = 48, - [2][0][2][0][RTW89_KCC][41] = 50, - [2][0][2][0][RTW89_FCC][48] = 46, - [2][0][2][0][RTW89_ETSI][48] = 127, - [2][0][2][0][RTW89_KCC][48] = 48, - [2][0][2][0][RTW89_FCC][56] = 46, - [2][0][2][0][RTW89_ETSI][56] = 127, - [2][0][2][0][RTW89_KCC][56] = 48, - [2][0][2][0][RTW89_FCC][63] = 46, - [2][0][2][0][RTW89_ETSI][63] = 127, - [2][0][2][0][RTW89_KCC][63] = 48, - [2][0][2][0][RTW89_FCC][71] = 46, - [2][0][2][0][RTW89_ETSI][71] = 127, - [2][0][2][0][RTW89_KCC][71] = 48, - [2][0][2][0][RTW89_FCC][78] = 46, - [2][0][2][0][RTW89_ETSI][78] = 127, - [2][0][2][0][RTW89_KCC][78] = 52, - [2][0][2][0][RTW89_FCC][86] = 46, - [2][0][2][0][RTW89_ETSI][86] = 127, - [2][0][2][0][RTW89_KCC][86] = 52, - [2][0][2][0][RTW89_FCC][93] = 46, - [2][0][2][0][RTW89_ETSI][93] = 127, - [2][0][2][0][RTW89_KCC][93] = 50, - [2][0][2][0][RTW89_FCC][101] = 44, - [2][0][2][0][RTW89_ETSI][101] = 127, - [2][0][2][0][RTW89_KCC][101] = 50, - [2][0][2][0][RTW89_FCC][108] = 127, - [2][0][2][0][RTW89_ETSI][108] = 127, - [2][0][2][0][RTW89_KCC][108] = 127, - [2][0][2][0][RTW89_FCC][116] = 127, - [2][0][2][0][RTW89_ETSI][116] = 127, - [2][0][2][0][RTW89_KCC][116] = 127, - [2][1][2][0][RTW89_FCC][3] = 22, - [2][1][2][0][RTW89_ETSI][3] = 48, - [2][1][2][0][RTW89_KCC][3] = 38, - [2][1][2][0][RTW89_FCC][11] = 20, - [2][1][2][0][RTW89_ETSI][11] = 48, - [2][1][2][0][RTW89_KCC][11] = 38, - [2][1][2][0][RTW89_FCC][18] = 20, - [2][1][2][0][RTW89_ETSI][18] = 48, - [2][1][2][0][RTW89_KCC][18] = 38, - [2][1][2][0][RTW89_FCC][26] = 20, - [2][1][2][0][RTW89_ETSI][26] = 48, - [2][1][2][0][RTW89_KCC][26] = 38, - [2][1][2][0][RTW89_FCC][33] = 20, - [2][1][2][0][RTW89_ETSI][33] = 48, - [2][1][2][0][RTW89_KCC][33] = 38, - [2][1][2][0][RTW89_FCC][41] = 22, - [2][1][2][0][RTW89_ETSI][41] = 48, - [2][1][2][0][RTW89_KCC][41] = 38, - [2][1][2][0][RTW89_FCC][48] = 22, - [2][1][2][0][RTW89_ETSI][48] = 127, - [2][1][2][0][RTW89_KCC][48] = 38, - [2][1][2][0][RTW89_FCC][56] = 20, - [2][1][2][0][RTW89_ETSI][56] = 127, - [2][1][2][0][RTW89_KCC][56] = 38, - [2][1][2][0][RTW89_FCC][63] = 22, - [2][1][2][0][RTW89_ETSI][63] = 127, - [2][1][2][0][RTW89_KCC][63] = 38, - [2][1][2][0][RTW89_FCC][71] = 20, - [2][1][2][0][RTW89_ETSI][71] = 127, - [2][1][2][0][RTW89_KCC][71] = 38, - [2][1][2][0][RTW89_FCC][78] = 20, - [2][1][2][0][RTW89_ETSI][78] = 127, - [2][1][2][0][RTW89_KCC][78] = 38, - [2][1][2][0][RTW89_FCC][86] = 20, - [2][1][2][0][RTW89_ETSI][86] = 127, - [2][1][2][0][RTW89_KCC][86] = 38, - [2][1][2][0][RTW89_FCC][93] = 22, - [2][1][2][0][RTW89_ETSI][93] = 127, - [2][1][2][0][RTW89_KCC][93] = 38, - [2][1][2][0][RTW89_FCC][101] = 22, - [2][1][2][0][RTW89_ETSI][101] = 127, - [2][1][2][0][RTW89_KCC][101] = 38, - [2][1][2][0][RTW89_FCC][108] = 127, - [2][1][2][0][RTW89_ETSI][108] = 127, - [2][1][2][0][RTW89_KCC][108] = 127, - [2][1][2][0][RTW89_FCC][116] = 127, - [2][1][2][0][RTW89_ETSI][116] = 127, - [2][1][2][0][RTW89_KCC][116] = 127, - [2][1][2][1][RTW89_FCC][3] = 22, - [2][1][2][1][RTW89_ETSI][3] = 42, - [2][1][2][1][RTW89_KCC][3] = 38, - [2][1][2][1][RTW89_FCC][11] = 20, - [2][1][2][1][RTW89_ETSI][11] = 42, - [2][1][2][1][RTW89_KCC][11] = 38, - [2][1][2][1][RTW89_FCC][18] = 20, - [2][1][2][1][RTW89_ETSI][18] = 42, - [2][1][2][1][RTW89_KCC][18] = 38, - [2][1][2][1][RTW89_FCC][26] = 20, - [2][1][2][1][RTW89_ETSI][26] = 42, - [2][1][2][1][RTW89_KCC][26] = 38, - [2][1][2][1][RTW89_FCC][33] = 20, - [2][1][2][1][RTW89_ETSI][33] = 42, - [2][1][2][1][RTW89_KCC][33] = 38, - [2][1][2][1][RTW89_FCC][41] = 22, - [2][1][2][1][RTW89_ETSI][41] = 42, - [2][1][2][1][RTW89_KCC][41] = 38, - [2][1][2][1][RTW89_FCC][48] = 22, - [2][1][2][1][RTW89_ETSI][48] = 127, - [2][1][2][1][RTW89_KCC][48] = 38, - [2][1][2][1][RTW89_FCC][56] = 20, - [2][1][2][1][RTW89_ETSI][56] = 127, - [2][1][2][1][RTW89_KCC][56] = 38, - [2][1][2][1][RTW89_FCC][63] = 22, - [2][1][2][1][RTW89_ETSI][63] = 127, - [2][1][2][1][RTW89_KCC][63] = 38, - [2][1][2][1][RTW89_FCC][71] = 20, - [2][1][2][1][RTW89_ETSI][71] = 127, - [2][1][2][1][RTW89_KCC][71] = 38, - [2][1][2][1][RTW89_FCC][78] = 20, - [2][1][2][1][RTW89_ETSI][78] = 127, - [2][1][2][1][RTW89_KCC][78] = 38, - [2][1][2][1][RTW89_FCC][86] = 20, - [2][1][2][1][RTW89_ETSI][86] = 127, - [2][1][2][1][RTW89_KCC][86] = 38, - [2][1][2][1][RTW89_FCC][93] = 22, - [2][1][2][1][RTW89_ETSI][93] = 127, - [2][1][2][1][RTW89_KCC][93] = 38, - [2][1][2][1][RTW89_FCC][101] = 22, - [2][1][2][1][RTW89_ETSI][101] = 127, - [2][1][2][1][RTW89_KCC][101] = 38, - [2][1][2][1][RTW89_FCC][108] = 127, - [2][1][2][1][RTW89_ETSI][108] = 127, - [2][1][2][1][RTW89_KCC][108] = 127, - [2][1][2][1][RTW89_FCC][116] = 127, - [2][1][2][1][RTW89_ETSI][116] = 127, - [2][1][2][1][RTW89_KCC][116] = 127, - [3][0][2][0][RTW89_FCC][7] = 52, - [3][0][2][0][RTW89_ETSI][7] = 38, - [3][0][2][0][RTW89_KCC][7] = 42, - [3][0][2][0][RTW89_FCC][22] = 52, - [3][0][2][0][RTW89_ETSI][22] = 38, - [3][0][2][0][RTW89_KCC][22] = 42, - [3][0][2][0][RTW89_FCC][37] = 52, - [3][0][2][0][RTW89_ETSI][37] = 38, - [3][0][2][0][RTW89_KCC][37] = 42, - [3][0][2][0][RTW89_FCC][52] = 54, - [3][0][2][0][RTW89_ETSI][52] = 127, - [3][0][2][0][RTW89_KCC][52] = 56, - [3][0][2][0][RTW89_FCC][67] = 54, - [3][0][2][0][RTW89_ETSI][67] = 127, - [3][0][2][0][RTW89_KCC][67] = 54, - [3][0][2][0][RTW89_FCC][82] = 54, - [3][0][2][0][RTW89_ETSI][82] = 127, - [3][0][2][0][RTW89_KCC][82] = 26, - [3][0][2][0][RTW89_FCC][97] = 40, - [3][0][2][0][RTW89_ETSI][97] = 127, - [3][0][2][0][RTW89_KCC][97] = 26, - [3][0][2][0][RTW89_FCC][112] = 127, - [3][0][2][0][RTW89_ETSI][112] = 127, - [3][0][2][0][RTW89_KCC][112] = 127, - [3][1][2][0][RTW89_FCC][7] = 32, - [3][1][2][0][RTW89_ETSI][7] = 38, - [3][1][2][0][RTW89_KCC][7] = 40, - [3][1][2][0][RTW89_FCC][22] = 30, - [3][1][2][0][RTW89_ETSI][22] = 38, - [3][1][2][0][RTW89_KCC][22] = 40, - [3][1][2][0][RTW89_FCC][37] = 30, - [3][1][2][0][RTW89_ETSI][37] = 38, - [3][1][2][0][RTW89_KCC][37] = 40, - [3][1][2][0][RTW89_FCC][52] = 30, - [3][1][2][0][RTW89_ETSI][52] = 127, - [3][1][2][0][RTW89_KCC][52] = 48, - [3][1][2][0][RTW89_FCC][67] = 32, - [3][1][2][0][RTW89_ETSI][67] = 127, - [3][1][2][0][RTW89_KCC][67] = 48, - [3][1][2][0][RTW89_FCC][82] = 32, - [3][1][2][0][RTW89_ETSI][82] = 127, - [3][1][2][0][RTW89_KCC][82] = 24, - [3][1][2][0][RTW89_FCC][97] = 14, - [3][1][2][0][RTW89_ETSI][97] = 127, - [3][1][2][0][RTW89_KCC][97] = 24, - [3][1][2][0][RTW89_FCC][112] = 127, - [3][1][2][0][RTW89_ETSI][112] = 127, - [3][1][2][0][RTW89_KCC][112] = 127, - [3][1][2][1][RTW89_FCC][7] = 32, - [3][1][2][1][RTW89_ETSI][7] = 38, - [3][1][2][1][RTW89_KCC][7] = 40, - [3][1][2][1][RTW89_FCC][22] = 30, - [3][1][2][1][RTW89_ETSI][22] = 38, - [3][1][2][1][RTW89_KCC][22] = 40, - [3][1][2][1][RTW89_FCC][37] = 30, - [3][1][2][1][RTW89_ETSI][37] = 38, - [3][1][2][1][RTW89_KCC][37] = 40, - [3][1][2][1][RTW89_FCC][52] = 30, - [3][1][2][1][RTW89_ETSI][52] = 127, - [3][1][2][1][RTW89_KCC][52] = 48, - [3][1][2][1][RTW89_FCC][67] = 32, - [3][1][2][1][RTW89_ETSI][67] = 127, - [3][1][2][1][RTW89_KCC][67] = 48, - [3][1][2][1][RTW89_FCC][82] = 32, - [3][1][2][1][RTW89_ETSI][82] = 127, - [3][1][2][1][RTW89_KCC][82] = 24, - [3][1][2][1][RTW89_FCC][97] = 14, - [3][1][2][1][RTW89_ETSI][97] = 127, - [3][1][2][1][RTW89_KCC][97] = 24, - [3][1][2][1][RTW89_FCC][112] = 127, - [3][1][2][1][RTW89_ETSI][112] = 127, - [3][1][2][1][RTW89_KCC][112] = 127, + [RTW89_REGD_NUM][NUM_OF_RTW89_REG_6GHZ_POWER] + [RTW89_6G_CH_NUM] = { + [0][0][1][0][RTW89_WW][0][0] = 24, + [0][0][1][0][RTW89_WW][1][0] = 24, + [0][0][1][0][RTW89_WW][2][0] = 56, + [0][0][1][0][RTW89_WW][0][2] = 22, + [0][0][1][0][RTW89_WW][1][2] = 22, + [0][0][1][0][RTW89_WW][2][2] = 56, + [0][0][1][0][RTW89_WW][0][4] = 22, + [0][0][1][0][RTW89_WW][1][4] = 22, + [0][0][1][0][RTW89_WW][2][4] = 56, + [0][0][1][0][RTW89_WW][0][6] = 22, + [0][0][1][0][RTW89_WW][1][6] = 22, + [0][0][1][0][RTW89_WW][2][6] = 56, + [0][0][1][0][RTW89_WW][0][8] = 22, + [0][0][1][0][RTW89_WW][1][8] = 22, + [0][0][1][0][RTW89_WW][2][8] = 56, + [0][0][1][0][RTW89_WW][0][10] = 22, + [0][0][1][0][RTW89_WW][1][10] = 22, + [0][0][1][0][RTW89_WW][2][10] = 56, + [0][0][1][0][RTW89_WW][0][12] = 22, + [0][0][1][0][RTW89_WW][1][12] = 22, + [0][0][1][0][RTW89_WW][2][12] = 56, + [0][0][1][0][RTW89_WW][0][14] = 22, + [0][0][1][0][RTW89_WW][1][14] = 22, + [0][0][1][0][RTW89_WW][2][14] = 56, + [0][0][1][0][RTW89_WW][0][15] = 22, + [0][0][1][0][RTW89_WW][1][15] = 22, + [0][0][1][0][RTW89_WW][2][15] = 56, + [0][0][1][0][RTW89_WW][0][17] = 22, + [0][0][1][0][RTW89_WW][1][17] = 22, + [0][0][1][0][RTW89_WW][2][17] = 56, + [0][0][1][0][RTW89_WW][0][19] = 22, + [0][0][1][0][RTW89_WW][1][19] = 22, + [0][0][1][0][RTW89_WW][2][19] = 56, + [0][0][1][0][RTW89_WW][0][21] = 22, + [0][0][1][0][RTW89_WW][1][21] = 22, + [0][0][1][0][RTW89_WW][2][21] = 56, + [0][0][1][0][RTW89_WW][0][23] = 22, + [0][0][1][0][RTW89_WW][1][23] = 22, + [0][0][1][0][RTW89_WW][2][23] = 70, + [0][0][1][0][RTW89_WW][0][25] = 22, + [0][0][1][0][RTW89_WW][1][25] = 22, + [0][0][1][0][RTW89_WW][2][25] = 70, + [0][0][1][0][RTW89_WW][0][27] = 22, + [0][0][1][0][RTW89_WW][1][27] = 22, + [0][0][1][0][RTW89_WW][2][27] = 70, + [0][0][1][0][RTW89_WW][0][29] = 22, + [0][0][1][0][RTW89_WW][1][29] = 22, + [0][0][1][0][RTW89_WW][2][29] = 70, + [0][0][1][0][RTW89_WW][0][30] = 22, + [0][0][1][0][RTW89_WW][1][30] = 22, + [0][0][1][0][RTW89_WW][2][30] = 70, + [0][0][1][0][RTW89_WW][0][32] = 22, + [0][0][1][0][RTW89_WW][1][32] = 22, + [0][0][1][0][RTW89_WW][2][32] = 70, + [0][0][1][0][RTW89_WW][0][34] = 22, + [0][0][1][0][RTW89_WW][1][34] = 22, + [0][0][1][0][RTW89_WW][2][34] = 70, + [0][0][1][0][RTW89_WW][0][36] = 22, + [0][0][1][0][RTW89_WW][1][36] = 22, + [0][0][1][0][RTW89_WW][2][36] = 70, + [0][0][1][0][RTW89_WW][0][38] = 22, + [0][0][1][0][RTW89_WW][1][38] = 22, + [0][0][1][0][RTW89_WW][2][38] = 70, + [0][0][1][0][RTW89_WW][0][40] = 22, + [0][0][1][0][RTW89_WW][1][40] = 22, + [0][0][1][0][RTW89_WW][2][40] = 70, + [0][0][1][0][RTW89_WW][0][42] = 22, + [0][0][1][0][RTW89_WW][1][42] = 22, + [0][0][1][0][RTW89_WW][2][42] = 70, + [0][0][1][0][RTW89_WW][0][44] = 22, + [0][0][1][0][RTW89_WW][1][44] = 22, + [0][0][1][0][RTW89_WW][2][44] = 70, + [0][0][1][0][RTW89_WW][0][45] = 22, + [0][0][1][0][RTW89_WW][1][45] = 22, + [0][0][1][0][RTW89_WW][2][45] = 0, + [0][0][1][0][RTW89_WW][0][47] = 22, + [0][0][1][0][RTW89_WW][1][47] = 22, + [0][0][1][0][RTW89_WW][2][47] = 0, + [0][0][1][0][RTW89_WW][0][49] = 24, + [0][0][1][0][RTW89_WW][1][49] = 24, + [0][0][1][0][RTW89_WW][2][49] = 0, + [0][0][1][0][RTW89_WW][0][51] = 22, + [0][0][1][0][RTW89_WW][1][51] = 22, + [0][0][1][0][RTW89_WW][2][51] = 0, + [0][0][1][0][RTW89_WW][0][53] = 22, + [0][0][1][0][RTW89_WW][1][53] = 22, + [0][0][1][0][RTW89_WW][2][53] = 0, + [0][0][1][0][RTW89_WW][0][55] = 22, + [0][0][1][0][RTW89_WW][1][55] = 22, + [0][0][1][0][RTW89_WW][2][55] = 68, + [0][0][1][0][RTW89_WW][0][57] = 22, + [0][0][1][0][RTW89_WW][1][57] = 22, + [0][0][1][0][RTW89_WW][2][57] = 68, + [0][0][1][0][RTW89_WW][0][59] = 22, + [0][0][1][0][RTW89_WW][1][59] = 22, + [0][0][1][0][RTW89_WW][2][59] = 68, + [0][0][1][0][RTW89_WW][0][60] = 22, + [0][0][1][0][RTW89_WW][1][60] = 22, + [0][0][1][0][RTW89_WW][2][60] = 68, + [0][0][1][0][RTW89_WW][0][62] = 22, + [0][0][1][0][RTW89_WW][1][62] = 22, + [0][0][1][0][RTW89_WW][2][62] = 68, + [0][0][1][0][RTW89_WW][0][64] = 22, + [0][0][1][0][RTW89_WW][1][64] = 22, + [0][0][1][0][RTW89_WW][2][64] = 68, + [0][0][1][0][RTW89_WW][0][66] = 22, + [0][0][1][0][RTW89_WW][1][66] = 22, + [0][0][1][0][RTW89_WW][2][66] = 68, + [0][0][1][0][RTW89_WW][0][68] = 22, + [0][0][1][0][RTW89_WW][1][68] = 22, + [0][0][1][0][RTW89_WW][2][68] = 68, + [0][0][1][0][RTW89_WW][0][70] = 24, + [0][0][1][0][RTW89_WW][1][70] = 24, + [0][0][1][0][RTW89_WW][2][70] = 68, + [0][0][1][0][RTW89_WW][0][72] = 22, + [0][0][1][0][RTW89_WW][1][72] = 22, + [0][0][1][0][RTW89_WW][2][72] = 68, + [0][0][1][0][RTW89_WW][0][74] = 22, + [0][0][1][0][RTW89_WW][1][74] = 22, + [0][0][1][0][RTW89_WW][2][74] = 68, + [0][0][1][0][RTW89_WW][0][75] = 22, + [0][0][1][0][RTW89_WW][1][75] = 22, + [0][0][1][0][RTW89_WW][2][75] = 68, + [0][0][1][0][RTW89_WW][0][77] = 22, + [0][0][1][0][RTW89_WW][1][77] = 22, + [0][0][1][0][RTW89_WW][2][77] = 68, + [0][0][1][0][RTW89_WW][0][79] = 22, + [0][0][1][0][RTW89_WW][1][79] = 22, + [0][0][1][0][RTW89_WW][2][79] = 68, + [0][0][1][0][RTW89_WW][0][81] = 22, + [0][0][1][0][RTW89_WW][1][81] = 22, + [0][0][1][0][RTW89_WW][2][81] = 68, + [0][0][1][0][RTW89_WW][0][83] = 22, + [0][0][1][0][RTW89_WW][1][83] = 22, + [0][0][1][0][RTW89_WW][2][83] = 68, + [0][0][1][0][RTW89_WW][0][85] = 22, + [0][0][1][0][RTW89_WW][1][85] = 22, + [0][0][1][0][RTW89_WW][2][85] = 68, + [0][0][1][0][RTW89_WW][0][87] = 22, + [0][0][1][0][RTW89_WW][1][87] = 22, + [0][0][1][0][RTW89_WW][2][87] = 0, + [0][0][1][0][RTW89_WW][0][89] = 22, + [0][0][1][0][RTW89_WW][1][89] = 22, + [0][0][1][0][RTW89_WW][2][89] = 0, + [0][0][1][0][RTW89_WW][0][90] = 22, + [0][0][1][0][RTW89_WW][1][90] = 22, + [0][0][1][0][RTW89_WW][2][90] = 0, + [0][0][1][0][RTW89_WW][0][92] = 22, + [0][0][1][0][RTW89_WW][1][92] = 22, + [0][0][1][0][RTW89_WW][2][92] = 0, + [0][0][1][0][RTW89_WW][0][94] = 22, + [0][0][1][0][RTW89_WW][1][94] = 22, + [0][0][1][0][RTW89_WW][2][94] = 0, + [0][0][1][0][RTW89_WW][0][96] = 22, + [0][0][1][0][RTW89_WW][1][96] = 22, + [0][0][1][0][RTW89_WW][2][96] = 0, + [0][0][1][0][RTW89_WW][0][98] = 22, + [0][0][1][0][RTW89_WW][1][98] = 22, + [0][0][1][0][RTW89_WW][2][98] = 0, + [0][0][1][0][RTW89_WW][0][100] = 22, + [0][0][1][0][RTW89_WW][1][100] = 22, + [0][0][1][0][RTW89_WW][2][100] = 0, + [0][0][1][0][RTW89_WW][0][102] = 22, + [0][0][1][0][RTW89_WW][1][102] = 22, + [0][0][1][0][RTW89_WW][2][102] = 0, + [0][0][1][0][RTW89_WW][0][104] = 22, + [0][0][1][0][RTW89_WW][1][104] = 22, + [0][0][1][0][RTW89_WW][2][104] = 0, + [0][0][1][0][RTW89_WW][0][105] = 22, + [0][0][1][0][RTW89_WW][1][105] = 22, + [0][0][1][0][RTW89_WW][2][105] = 0, + [0][0][1][0][RTW89_WW][0][107] = 24, + [0][0][1][0][RTW89_WW][1][107] = 24, + [0][0][1][0][RTW89_WW][2][107] = 0, + [0][0][1][0][RTW89_WW][0][109] = 24, + [0][0][1][0][RTW89_WW][1][109] = 24, + [0][0][1][0][RTW89_WW][2][109] = 0, + [0][0][1][0][RTW89_WW][0][111] = 0, + [0][0][1][0][RTW89_WW][1][111] = 0, + [0][0][1][0][RTW89_WW][2][111] = 0, + [0][0][1][0][RTW89_WW][0][113] = 0, + [0][0][1][0][RTW89_WW][1][113] = 0, + [0][0][1][0][RTW89_WW][2][113] = 0, + [0][0][1][0][RTW89_WW][0][115] = 0, + [0][0][1][0][RTW89_WW][1][115] = 0, + [0][0][1][0][RTW89_WW][2][115] = 0, + [0][0][1][0][RTW89_WW][0][117] = 0, + [0][0][1][0][RTW89_WW][1][117] = 0, + [0][0][1][0][RTW89_WW][2][117] = 0, + [0][0][1][0][RTW89_WW][0][119] = 0, + [0][0][1][0][RTW89_WW][1][119] = 0, + [0][0][1][0][RTW89_WW][2][119] = 0, + [0][1][1][0][RTW89_WW][0][0] = -2, + [0][1][1][0][RTW89_WW][1][0] = -2, + [0][1][1][0][RTW89_WW][2][0] = 54, + [0][1][1][0][RTW89_WW][0][2] = -4, + [0][1][1][0][RTW89_WW][1][2] = -4, + [0][1][1][0][RTW89_WW][2][2] = 54, + [0][1][1][0][RTW89_WW][0][4] = -4, + [0][1][1][0][RTW89_WW][1][4] = -4, + [0][1][1][0][RTW89_WW][2][4] = 54, + [0][1][1][0][RTW89_WW][0][6] = -4, + [0][1][1][0][RTW89_WW][1][6] = -4, + [0][1][1][0][RTW89_WW][2][6] = 54, + [0][1][1][0][RTW89_WW][0][8] = -4, + [0][1][1][0][RTW89_WW][1][8] = -4, + [0][1][1][0][RTW89_WW][2][8] = 54, + [0][1][1][0][RTW89_WW][0][10] = -4, + [0][1][1][0][RTW89_WW][1][10] = -4, + [0][1][1][0][RTW89_WW][2][10] = 54, + [0][1][1][0][RTW89_WW][0][12] = -4, + [0][1][1][0][RTW89_WW][1][12] = -4, + [0][1][1][0][RTW89_WW][2][12] = 54, + [0][1][1][0][RTW89_WW][0][14] = -4, + [0][1][1][0][RTW89_WW][1][14] = -4, + [0][1][1][0][RTW89_WW][2][14] = 54, + [0][1][1][0][RTW89_WW][0][15] = -4, + [0][1][1][0][RTW89_WW][1][15] = -4, + [0][1][1][0][RTW89_WW][2][15] = 54, + [0][1][1][0][RTW89_WW][0][17] = -4, + [0][1][1][0][RTW89_WW][1][17] = -4, + [0][1][1][0][RTW89_WW][2][17] = 54, + [0][1][1][0][RTW89_WW][0][19] = -4, + [0][1][1][0][RTW89_WW][1][19] = -4, + [0][1][1][0][RTW89_WW][2][19] = 54, + [0][1][1][0][RTW89_WW][0][21] = -4, + [0][1][1][0][RTW89_WW][1][21] = -4, + [0][1][1][0][RTW89_WW][2][21] = 54, + [0][1][1][0][RTW89_WW][0][23] = -4, + [0][1][1][0][RTW89_WW][1][23] = -4, + [0][1][1][0][RTW89_WW][2][23] = 68, + [0][1][1][0][RTW89_WW][0][25] = -4, + [0][1][1][0][RTW89_WW][1][25] = -4, + [0][1][1][0][RTW89_WW][2][25] = 68, + [0][1][1][0][RTW89_WW][0][27] = -4, + [0][1][1][0][RTW89_WW][1][27] = -4, + [0][1][1][0][RTW89_WW][2][27] = 68, + [0][1][1][0][RTW89_WW][0][29] = -4, + [0][1][1][0][RTW89_WW][1][29] = -4, + [0][1][1][0][RTW89_WW][2][29] = 68, + [0][1][1][0][RTW89_WW][0][30] = -4, + [0][1][1][0][RTW89_WW][1][30] = -4, + [0][1][1][0][RTW89_WW][2][30] = 68, + [0][1][1][0][RTW89_WW][0][32] = -4, + [0][1][1][0][RTW89_WW][1][32] = -4, + [0][1][1][0][RTW89_WW][2][32] = 68, + [0][1][1][0][RTW89_WW][0][34] = -4, + [0][1][1][0][RTW89_WW][1][34] = -4, + [0][1][1][0][RTW89_WW][2][34] = 68, + [0][1][1][0][RTW89_WW][0][36] = -4, + [0][1][1][0][RTW89_WW][1][36] = -4, + [0][1][1][0][RTW89_WW][2][36] = 68, + [0][1][1][0][RTW89_WW][0][38] = -4, + [0][1][1][0][RTW89_WW][1][38] = -4, + [0][1][1][0][RTW89_WW][2][38] = 68, + [0][1][1][0][RTW89_WW][0][40] = -4, + [0][1][1][0][RTW89_WW][1][40] = -4, + [0][1][1][0][RTW89_WW][2][40] = 68, + [0][1][1][0][RTW89_WW][0][42] = -4, + [0][1][1][0][RTW89_WW][1][42] = -4, + [0][1][1][0][RTW89_WW][2][42] = 68, + [0][1][1][0][RTW89_WW][0][44] = -2, + [0][1][1][0][RTW89_WW][1][44] = -2, + [0][1][1][0][RTW89_WW][2][44] = 68, + [0][1][1][0][RTW89_WW][0][45] = -2, + [0][1][1][0][RTW89_WW][1][45] = -2, + [0][1][1][0][RTW89_WW][2][45] = 0, + [0][1][1][0][RTW89_WW][0][47] = -2, + [0][1][1][0][RTW89_WW][1][47] = -2, + [0][1][1][0][RTW89_WW][2][47] = 0, + [0][1][1][0][RTW89_WW][0][49] = -2, + [0][1][1][0][RTW89_WW][1][49] = -2, + [0][1][1][0][RTW89_WW][2][49] = 0, + [0][1][1][0][RTW89_WW][0][51] = -2, + [0][1][1][0][RTW89_WW][1][51] = -2, + [0][1][1][0][RTW89_WW][2][51] = 0, + [0][1][1][0][RTW89_WW][0][53] = -2, + [0][1][1][0][RTW89_WW][1][53] = -2, + [0][1][1][0][RTW89_WW][2][53] = 0, + [0][1][1][0][RTW89_WW][0][55] = -2, + [0][1][1][0][RTW89_WW][1][55] = -2, + [0][1][1][0][RTW89_WW][2][55] = 68, + [0][1][1][0][RTW89_WW][0][57] = -2, + [0][1][1][0][RTW89_WW][1][57] = -2, + [0][1][1][0][RTW89_WW][2][57] = 68, + [0][1][1][0][RTW89_WW][0][59] = -2, + [0][1][1][0][RTW89_WW][1][59] = -2, + [0][1][1][0][RTW89_WW][2][59] = 68, + [0][1][1][0][RTW89_WW][0][60] = -2, + [0][1][1][0][RTW89_WW][1][60] = -2, + [0][1][1][0][RTW89_WW][2][60] = 68, + [0][1][1][0][RTW89_WW][0][62] = -2, + [0][1][1][0][RTW89_WW][1][62] = -2, + [0][1][1][0][RTW89_WW][2][62] = 68, + [0][1][1][0][RTW89_WW][0][64] = -2, + [0][1][1][0][RTW89_WW][1][64] = -2, + [0][1][1][0][RTW89_WW][2][64] = 68, + [0][1][1][0][RTW89_WW][0][66] = -2, + [0][1][1][0][RTW89_WW][1][66] = -2, + [0][1][1][0][RTW89_WW][2][66] = 68, + [0][1][1][0][RTW89_WW][0][68] = -2, + [0][1][1][0][RTW89_WW][1][68] = -2, + [0][1][1][0][RTW89_WW][2][68] = 68, + [0][1][1][0][RTW89_WW][0][70] = -2, + [0][1][1][0][RTW89_WW][1][70] = -2, + [0][1][1][0][RTW89_WW][2][70] = 68, + [0][1][1][0][RTW89_WW][0][72] = -2, + [0][1][1][0][RTW89_WW][1][72] = -2, + [0][1][1][0][RTW89_WW][2][72] = 68, + [0][1][1][0][RTW89_WW][0][74] = -2, + [0][1][1][0][RTW89_WW][1][74] = -2, + [0][1][1][0][RTW89_WW][2][74] = 68, + [0][1][1][0][RTW89_WW][0][75] = -2, + [0][1][1][0][RTW89_WW][1][75] = -2, + [0][1][1][0][RTW89_WW][2][75] = 68, + [0][1][1][0][RTW89_WW][0][77] = -2, + [0][1][1][0][RTW89_WW][1][77] = -2, + [0][1][1][0][RTW89_WW][2][77] = 68, + [0][1][1][0][RTW89_WW][0][79] = -2, + [0][1][1][0][RTW89_WW][1][79] = -2, + [0][1][1][0][RTW89_WW][2][79] = 68, + [0][1][1][0][RTW89_WW][0][81] = -2, + [0][1][1][0][RTW89_WW][1][81] = -2, + [0][1][1][0][RTW89_WW][2][81] = 68, + [0][1][1][0][RTW89_WW][0][83] = -2, + [0][1][1][0][RTW89_WW][1][83] = -2, + [0][1][1][0][RTW89_WW][2][83] = 68, + [0][1][1][0][RTW89_WW][0][85] = -2, + [0][1][1][0][RTW89_WW][1][85] = -2, + [0][1][1][0][RTW89_WW][2][85] = 68, + [0][1][1][0][RTW89_WW][0][87] = -2, + [0][1][1][0][RTW89_WW][1][87] = -2, + [0][1][1][0][RTW89_WW][2][87] = 0, + [0][1][1][0][RTW89_WW][0][89] = -2, + [0][1][1][0][RTW89_WW][1][89] = -2, + [0][1][1][0][RTW89_WW][2][89] = 0, + [0][1][1][0][RTW89_WW][0][90] = -2, + [0][1][1][0][RTW89_WW][1][90] = -2, + [0][1][1][0][RTW89_WW][2][90] = 0, + [0][1][1][0][RTW89_WW][0][92] = -2, + [0][1][1][0][RTW89_WW][1][92] = -2, + [0][1][1][0][RTW89_WW][2][92] = 0, + [0][1][1][0][RTW89_WW][0][94] = -2, + [0][1][1][0][RTW89_WW][1][94] = -2, + [0][1][1][0][RTW89_WW][2][94] = 0, + [0][1][1][0][RTW89_WW][0][96] = -2, + [0][1][1][0][RTW89_WW][1][96] = -2, + [0][1][1][0][RTW89_WW][2][96] = 0, + [0][1][1][0][RTW89_WW][0][98] = -2, + [0][1][1][0][RTW89_WW][1][98] = -2, + [0][1][1][0][RTW89_WW][2][98] = 0, + [0][1][1][0][RTW89_WW][0][100] = -2, + [0][1][1][0][RTW89_WW][1][100] = -2, + [0][1][1][0][RTW89_WW][2][100] = 0, + [0][1][1][0][RTW89_WW][0][102] = -2, + [0][1][1][0][RTW89_WW][1][102] = -2, + [0][1][1][0][RTW89_WW][2][102] = 0, + [0][1][1][0][RTW89_WW][0][104] = -2, + [0][1][1][0][RTW89_WW][1][104] = -2, + [0][1][1][0][RTW89_WW][2][104] = 0, + [0][1][1][0][RTW89_WW][0][105] = -2, + [0][1][1][0][RTW89_WW][1][105] = -2, + [0][1][1][0][RTW89_WW][2][105] = 0, + [0][1][1][0][RTW89_WW][0][107] = 1, + [0][1][1][0][RTW89_WW][1][107] = 1, + [0][1][1][0][RTW89_WW][2][107] = 0, + [0][1][1][0][RTW89_WW][0][109] = 1, + [0][1][1][0][RTW89_WW][1][109] = 1, + [0][1][1][0][RTW89_WW][2][109] = 0, + [0][1][1][0][RTW89_WW][0][111] = 0, + [0][1][1][0][RTW89_WW][1][111] = 0, + [0][1][1][0][RTW89_WW][2][111] = 0, + [0][1][1][0][RTW89_WW][0][113] = 0, + [0][1][1][0][RTW89_WW][1][113] = 0, + [0][1][1][0][RTW89_WW][2][113] = 0, + [0][1][1][0][RTW89_WW][0][115] = 0, + [0][1][1][0][RTW89_WW][1][115] = 0, + [0][1][1][0][RTW89_WW][2][115] = 0, + [0][1][1][0][RTW89_WW][0][117] = 0, + [0][1][1][0][RTW89_WW][1][117] = 0, + [0][1][1][0][RTW89_WW][2][117] = 0, + [0][1][1][0][RTW89_WW][0][119] = 0, + [0][1][1][0][RTW89_WW][1][119] = 0, + [0][1][1][0][RTW89_WW][2][119] = 0, + [0][0][2][0][RTW89_WW][0][0] = 24, + [0][0][2][0][RTW89_WW][1][0] = 24, + [0][0][2][0][RTW89_WW][2][0] = 56, + [0][0][2][0][RTW89_WW][0][2] = 22, + [0][0][2][0][RTW89_WW][1][2] = 22, + [0][0][2][0][RTW89_WW][2][2] = 56, + [0][0][2][0][RTW89_WW][0][4] = 22, + [0][0][2][0][RTW89_WW][1][4] = 22, + [0][0][2][0][RTW89_WW][2][4] = 56, + [0][0][2][0][RTW89_WW][0][6] = 22, + [0][0][2][0][RTW89_WW][1][6] = 22, + [0][0][2][0][RTW89_WW][2][6] = 56, + [0][0][2][0][RTW89_WW][0][8] = 22, + [0][0][2][0][RTW89_WW][1][8] = 22, + [0][0][2][0][RTW89_WW][2][8] = 56, + [0][0][2][0][RTW89_WW][0][10] = 22, + [0][0][2][0][RTW89_WW][1][10] = 22, + [0][0][2][0][RTW89_WW][2][10] = 56, + [0][0][2][0][RTW89_WW][0][12] = 22, + [0][0][2][0][RTW89_WW][1][12] = 22, + [0][0][2][0][RTW89_WW][2][12] = 56, + [0][0][2][0][RTW89_WW][0][14] = 22, + [0][0][2][0][RTW89_WW][1][14] = 22, + [0][0][2][0][RTW89_WW][2][14] = 56, + [0][0][2][0][RTW89_WW][0][15] = 22, + [0][0][2][0][RTW89_WW][1][15] = 22, + [0][0][2][0][RTW89_WW][2][15] = 56, + [0][0][2][0][RTW89_WW][0][17] = 22, + [0][0][2][0][RTW89_WW][1][17] = 22, + [0][0][2][0][RTW89_WW][2][17] = 56, + [0][0][2][0][RTW89_WW][0][19] = 22, + [0][0][2][0][RTW89_WW][1][19] = 22, + [0][0][2][0][RTW89_WW][2][19] = 56, + [0][0][2][0][RTW89_WW][0][21] = 22, + [0][0][2][0][RTW89_WW][1][21] = 22, + [0][0][2][0][RTW89_WW][2][21] = 56, + [0][0][2][0][RTW89_WW][0][23] = 22, + [0][0][2][0][RTW89_WW][1][23] = 22, + [0][0][2][0][RTW89_WW][2][23] = 70, + [0][0][2][0][RTW89_WW][0][25] = 22, + [0][0][2][0][RTW89_WW][1][25] = 22, + [0][0][2][0][RTW89_WW][2][25] = 70, + [0][0][2][0][RTW89_WW][0][27] = 22, + [0][0][2][0][RTW89_WW][1][27] = 22, + [0][0][2][0][RTW89_WW][2][27] = 70, + [0][0][2][0][RTW89_WW][0][29] = 22, + [0][0][2][0][RTW89_WW][1][29] = 22, + [0][0][2][0][RTW89_WW][2][29] = 70, + [0][0][2][0][RTW89_WW][0][30] = 22, + [0][0][2][0][RTW89_WW][1][30] = 22, + [0][0][2][0][RTW89_WW][2][30] = 70, + [0][0][2][0][RTW89_WW][0][32] = 22, + [0][0][2][0][RTW89_WW][1][32] = 22, + [0][0][2][0][RTW89_WW][2][32] = 70, + [0][0][2][0][RTW89_WW][0][34] = 22, + [0][0][2][0][RTW89_WW][1][34] = 22, + [0][0][2][0][RTW89_WW][2][34] = 70, + [0][0][2][0][RTW89_WW][0][36] = 22, + [0][0][2][0][RTW89_WW][1][36] = 22, + [0][0][2][0][RTW89_WW][2][36] = 70, + [0][0][2][0][RTW89_WW][0][38] = 22, + [0][0][2][0][RTW89_WW][1][38] = 22, + [0][0][2][0][RTW89_WW][2][38] = 70, + [0][0][2][0][RTW89_WW][0][40] = 22, + [0][0][2][0][RTW89_WW][1][40] = 22, + [0][0][2][0][RTW89_WW][2][40] = 70, + [0][0][2][0][RTW89_WW][0][42] = 22, + [0][0][2][0][RTW89_WW][1][42] = 22, + [0][0][2][0][RTW89_WW][2][42] = 70, + [0][0][2][0][RTW89_WW][0][44] = 22, + [0][0][2][0][RTW89_WW][1][44] = 22, + [0][0][2][0][RTW89_WW][2][44] = 70, + [0][0][2][0][RTW89_WW][0][45] = 22, + [0][0][2][0][RTW89_WW][1][45] = 22, + [0][0][2][0][RTW89_WW][2][45] = 0, + [0][0][2][0][RTW89_WW][0][47] = 22, + [0][0][2][0][RTW89_WW][1][47] = 22, + [0][0][2][0][RTW89_WW][2][47] = 0, + [0][0][2][0][RTW89_WW][0][49] = 24, + [0][0][2][0][RTW89_WW][1][49] = 24, + [0][0][2][0][RTW89_WW][2][49] = 0, + [0][0][2][0][RTW89_WW][0][51] = 22, + [0][0][2][0][RTW89_WW][1][51] = 22, + [0][0][2][0][RTW89_WW][2][51] = 0, + [0][0][2][0][RTW89_WW][0][53] = 22, + [0][0][2][0][RTW89_WW][1][53] = 22, + [0][0][2][0][RTW89_WW][2][53] = 0, + [0][0][2][0][RTW89_WW][0][55] = 22, + [0][0][2][0][RTW89_WW][1][55] = 22, + [0][0][2][0][RTW89_WW][2][55] = 68, + [0][0][2][0][RTW89_WW][0][57] = 22, + [0][0][2][0][RTW89_WW][1][57] = 22, + [0][0][2][0][RTW89_WW][2][57] = 68, + [0][0][2][0][RTW89_WW][0][59] = 22, + [0][0][2][0][RTW89_WW][1][59] = 22, + [0][0][2][0][RTW89_WW][2][59] = 68, + [0][0][2][0][RTW89_WW][0][60] = 22, + [0][0][2][0][RTW89_WW][1][60] = 22, + [0][0][2][0][RTW89_WW][2][60] = 68, + [0][0][2][0][RTW89_WW][0][62] = 22, + [0][0][2][0][RTW89_WW][1][62] = 22, + [0][0][2][0][RTW89_WW][2][62] = 68, + [0][0][2][0][RTW89_WW][0][64] = 22, + [0][0][2][0][RTW89_WW][1][64] = 22, + [0][0][2][0][RTW89_WW][2][64] = 68, + [0][0][2][0][RTW89_WW][0][66] = 22, + [0][0][2][0][RTW89_WW][1][66] = 22, + [0][0][2][0][RTW89_WW][2][66] = 68, + [0][0][2][0][RTW89_WW][0][68] = 22, + [0][0][2][0][RTW89_WW][1][68] = 22, + [0][0][2][0][RTW89_WW][2][68] = 68, + [0][0][2][0][RTW89_WW][0][70] = 24, + [0][0][2][0][RTW89_WW][1][70] = 24, + [0][0][2][0][RTW89_WW][2][70] = 68, + [0][0][2][0][RTW89_WW][0][72] = 22, + [0][0][2][0][RTW89_WW][1][72] = 22, + [0][0][2][0][RTW89_WW][2][72] = 68, + [0][0][2][0][RTW89_WW][0][74] = 22, + [0][0][2][0][RTW89_WW][1][74] = 22, + [0][0][2][0][RTW89_WW][2][74] = 68, + [0][0][2][0][RTW89_WW][0][75] = 22, + [0][0][2][0][RTW89_WW][1][75] = 22, + [0][0][2][0][RTW89_WW][2][75] = 68, + [0][0][2][0][RTW89_WW][0][77] = 22, + [0][0][2][0][RTW89_WW][1][77] = 22, + [0][0][2][0][RTW89_WW][2][77] = 68, + [0][0][2][0][RTW89_WW][0][79] = 22, + [0][0][2][0][RTW89_WW][1][79] = 22, + [0][0][2][0][RTW89_WW][2][79] = 68, + [0][0][2][0][RTW89_WW][0][81] = 22, + [0][0][2][0][RTW89_WW][1][81] = 22, + [0][0][2][0][RTW89_WW][2][81] = 68, + [0][0][2][0][RTW89_WW][0][83] = 22, + [0][0][2][0][RTW89_WW][1][83] = 22, + [0][0][2][0][RTW89_WW][2][83] = 68, + [0][0][2][0][RTW89_WW][0][85] = 22, + [0][0][2][0][RTW89_WW][1][85] = 22, + [0][0][2][0][RTW89_WW][2][85] = 68, + [0][0][2][0][RTW89_WW][0][87] = 22, + [0][0][2][0][RTW89_WW][1][87] = 22, + [0][0][2][0][RTW89_WW][2][87] = 0, + [0][0][2][0][RTW89_WW][0][89] = 22, + [0][0][2][0][RTW89_WW][1][89] = 22, + [0][0][2][0][RTW89_WW][2][89] = 0, + [0][0][2][0][RTW89_WW][0][90] = 22, + [0][0][2][0][RTW89_WW][1][90] = 22, + [0][0][2][0][RTW89_WW][2][90] = 0, + [0][0][2][0][RTW89_WW][0][92] = 22, + [0][0][2][0][RTW89_WW][1][92] = 22, + [0][0][2][0][RTW89_WW][2][92] = 0, + [0][0][2][0][RTW89_WW][0][94] = 22, + [0][0][2][0][RTW89_WW][1][94] = 22, + [0][0][2][0][RTW89_WW][2][94] = 0, + [0][0][2][0][RTW89_WW][0][96] = 22, + [0][0][2][0][RTW89_WW][1][96] = 22, + [0][0][2][0][RTW89_WW][2][96] = 0, + [0][0][2][0][RTW89_WW][0][98] = 22, + [0][0][2][0][RTW89_WW][1][98] = 22, + [0][0][2][0][RTW89_WW][2][98] = 0, + [0][0][2][0][RTW89_WW][0][100] = 22, + [0][0][2][0][RTW89_WW][1][100] = 22, + [0][0][2][0][RTW89_WW][2][100] = 0, + [0][0][2][0][RTW89_WW][0][102] = 22, + [0][0][2][0][RTW89_WW][1][102] = 22, + [0][0][2][0][RTW89_WW][2][102] = 0, + [0][0][2][0][RTW89_WW][0][104] = 22, + [0][0][2][0][RTW89_WW][1][104] = 22, + [0][0][2][0][RTW89_WW][2][104] = 0, + [0][0][2][0][RTW89_WW][0][105] = 22, + [0][0][2][0][RTW89_WW][1][105] = 22, + [0][0][2][0][RTW89_WW][2][105] = 0, + [0][0][2][0][RTW89_WW][0][107] = 24, + [0][0][2][0][RTW89_WW][1][107] = 24, + [0][0][2][0][RTW89_WW][2][107] = 0, + [0][0][2][0][RTW89_WW][0][109] = 24, + [0][0][2][0][RTW89_WW][1][109] = 24, + [0][0][2][0][RTW89_WW][2][109] = 0, + [0][0][2][0][RTW89_WW][0][111] = 0, + [0][0][2][0][RTW89_WW][1][111] = 0, + [0][0][2][0][RTW89_WW][2][111] = 0, + [0][0][2][0][RTW89_WW][0][113] = 0, + [0][0][2][0][RTW89_WW][1][113] = 0, + [0][0][2][0][RTW89_WW][2][113] = 0, + [0][0][2][0][RTW89_WW][0][115] = 0, + [0][0][2][0][RTW89_WW][1][115] = 0, + [0][0][2][0][RTW89_WW][2][115] = 0, + [0][0][2][0][RTW89_WW][0][117] = 0, + [0][0][2][0][RTW89_WW][1][117] = 0, + [0][0][2][0][RTW89_WW][2][117] = 0, + [0][0][2][0][RTW89_WW][0][119] = 0, + [0][0][2][0][RTW89_WW][1][119] = 0, + [0][0][2][0][RTW89_WW][2][119] = 0, + [0][1][2][0][RTW89_WW][0][0] = -2, + [0][1][2][0][RTW89_WW][1][0] = -2, + [0][1][2][0][RTW89_WW][2][0] = 54, + [0][1][2][0][RTW89_WW][0][2] = -4, + [0][1][2][0][RTW89_WW][1][2] = -4, + [0][1][2][0][RTW89_WW][2][2] = 54, + [0][1][2][0][RTW89_WW][0][4] = -4, + [0][1][2][0][RTW89_WW][1][4] = -4, + [0][1][2][0][RTW89_WW][2][4] = 54, + [0][1][2][0][RTW89_WW][0][6] = -4, + [0][1][2][0][RTW89_WW][1][6] = -4, + [0][1][2][0][RTW89_WW][2][6] = 54, + [0][1][2][0][RTW89_WW][0][8] = -4, + [0][1][2][0][RTW89_WW][1][8] = -4, + [0][1][2][0][RTW89_WW][2][8] = 54, + [0][1][2][0][RTW89_WW][0][10] = -4, + [0][1][2][0][RTW89_WW][1][10] = -4, + [0][1][2][0][RTW89_WW][2][10] = 54, + [0][1][2][0][RTW89_WW][0][12] = -4, + [0][1][2][0][RTW89_WW][1][12] = -4, + [0][1][2][0][RTW89_WW][2][12] = 54, + [0][1][2][0][RTW89_WW][0][14] = -4, + [0][1][2][0][RTW89_WW][1][14] = -4, + [0][1][2][0][RTW89_WW][2][14] = 54, + [0][1][2][0][RTW89_WW][0][15] = -4, + [0][1][2][0][RTW89_WW][1][15] = -4, + [0][1][2][0][RTW89_WW][2][15] = 54, + [0][1][2][0][RTW89_WW][0][17] = -4, + [0][1][2][0][RTW89_WW][1][17] = -4, + [0][1][2][0][RTW89_WW][2][17] = 54, + [0][1][2][0][RTW89_WW][0][19] = -4, + [0][1][2][0][RTW89_WW][1][19] = -4, + [0][1][2][0][RTW89_WW][2][19] = 54, + [0][1][2][0][RTW89_WW][0][21] = -4, + [0][1][2][0][RTW89_WW][1][21] = -4, + [0][1][2][0][RTW89_WW][2][21] = 54, + [0][1][2][0][RTW89_WW][0][23] = -4, + [0][1][2][0][RTW89_WW][1][23] = -4, + [0][1][2][0][RTW89_WW][2][23] = 68, + [0][1][2][0][RTW89_WW][0][25] = -4, + [0][1][2][0][RTW89_WW][1][25] = -4, + [0][1][2][0][RTW89_WW][2][25] = 68, + [0][1][2][0][RTW89_WW][0][27] = -4, + [0][1][2][0][RTW89_WW][1][27] = -4, + [0][1][2][0][RTW89_WW][2][27] = 68, + [0][1][2][0][RTW89_WW][0][29] = -4, + [0][1][2][0][RTW89_WW][1][29] = -4, + [0][1][2][0][RTW89_WW][2][29] = 68, + [0][1][2][0][RTW89_WW][0][30] = -4, + [0][1][2][0][RTW89_WW][1][30] = -4, + [0][1][2][0][RTW89_WW][2][30] = 68, + [0][1][2][0][RTW89_WW][0][32] = -4, + [0][1][2][0][RTW89_WW][1][32] = -4, + [0][1][2][0][RTW89_WW][2][32] = 68, + [0][1][2][0][RTW89_WW][0][34] = -4, + [0][1][2][0][RTW89_WW][1][34] = -4, + [0][1][2][0][RTW89_WW][2][34] = 68, + [0][1][2][0][RTW89_WW][0][36] = -4, + [0][1][2][0][RTW89_WW][1][36] = -4, + [0][1][2][0][RTW89_WW][2][36] = 68, + [0][1][2][0][RTW89_WW][0][38] = -4, + [0][1][2][0][RTW89_WW][1][38] = -4, + [0][1][2][0][RTW89_WW][2][38] = 68, + [0][1][2][0][RTW89_WW][0][40] = -4, + [0][1][2][0][RTW89_WW][1][40] = -4, + [0][1][2][0][RTW89_WW][2][40] = 68, + [0][1][2][0][RTW89_WW][0][42] = -4, + [0][1][2][0][RTW89_WW][1][42] = -4, + [0][1][2][0][RTW89_WW][2][42] = 68, + [0][1][2][0][RTW89_WW][0][44] = -2, + [0][1][2][0][RTW89_WW][1][44] = -2, + [0][1][2][0][RTW89_WW][2][44] = 68, + [0][1][2][0][RTW89_WW][0][45] = -2, + [0][1][2][0][RTW89_WW][1][45] = -2, + [0][1][2][0][RTW89_WW][2][45] = 0, + [0][1][2][0][RTW89_WW][0][47] = -2, + [0][1][2][0][RTW89_WW][1][47] = -2, + [0][1][2][0][RTW89_WW][2][47] = 0, + [0][1][2][0][RTW89_WW][0][49] = -2, + [0][1][2][0][RTW89_WW][1][49] = -2, + [0][1][2][0][RTW89_WW][2][49] = 0, + [0][1][2][0][RTW89_WW][0][51] = -2, + [0][1][2][0][RTW89_WW][1][51] = -2, + [0][1][2][0][RTW89_WW][2][51] = 0, + [0][1][2][0][RTW89_WW][0][53] = -2, + [0][1][2][0][RTW89_WW][1][53] = -2, + [0][1][2][0][RTW89_WW][2][53] = 0, + [0][1][2][0][RTW89_WW][0][55] = -2, + [0][1][2][0][RTW89_WW][1][55] = -2, + [0][1][2][0][RTW89_WW][2][55] = 68, + [0][1][2][0][RTW89_WW][0][57] = -2, + [0][1][2][0][RTW89_WW][1][57] = -2, + [0][1][2][0][RTW89_WW][2][57] = 68, + [0][1][2][0][RTW89_WW][0][59] = -2, + [0][1][2][0][RTW89_WW][1][59] = -2, + [0][1][2][0][RTW89_WW][2][59] = 68, + [0][1][2][0][RTW89_WW][0][60] = -2, + [0][1][2][0][RTW89_WW][1][60] = -2, + [0][1][2][0][RTW89_WW][2][60] = 68, + [0][1][2][0][RTW89_WW][0][62] = -2, + [0][1][2][0][RTW89_WW][1][62] = -2, + [0][1][2][0][RTW89_WW][2][62] = 68, + [0][1][2][0][RTW89_WW][0][64] = -2, + [0][1][2][0][RTW89_WW][1][64] = -2, + [0][1][2][0][RTW89_WW][2][64] = 68, + [0][1][2][0][RTW89_WW][0][66] = -2, + [0][1][2][0][RTW89_WW][1][66] = -2, + [0][1][2][0][RTW89_WW][2][66] = 68, + [0][1][2][0][RTW89_WW][0][68] = -2, + [0][1][2][0][RTW89_WW][1][68] = -2, + [0][1][2][0][RTW89_WW][2][68] = 68, + [0][1][2][0][RTW89_WW][0][70] = -2, + [0][1][2][0][RTW89_WW][1][70] = -2, + [0][1][2][0][RTW89_WW][2][70] = 68, + [0][1][2][0][RTW89_WW][0][72] = -2, + [0][1][2][0][RTW89_WW][1][72] = -2, + [0][1][2][0][RTW89_WW][2][72] = 68, + [0][1][2][0][RTW89_WW][0][74] = -2, + [0][1][2][0][RTW89_WW][1][74] = -2, + [0][1][2][0][RTW89_WW][2][74] = 68, + [0][1][2][0][RTW89_WW][0][75] = -2, + [0][1][2][0][RTW89_WW][1][75] = -2, + [0][1][2][0][RTW89_WW][2][75] = 68, + [0][1][2][0][RTW89_WW][0][77] = -2, + [0][1][2][0][RTW89_WW][1][77] = -2, + [0][1][2][0][RTW89_WW][2][77] = 68, + [0][1][2][0][RTW89_WW][0][79] = -2, + [0][1][2][0][RTW89_WW][1][79] = -2, + [0][1][2][0][RTW89_WW][2][79] = 68, + [0][1][2][0][RTW89_WW][0][81] = -2, + [0][1][2][0][RTW89_WW][1][81] = -2, + [0][1][2][0][RTW89_WW][2][81] = 68, + [0][1][2][0][RTW89_WW][0][83] = -2, + [0][1][2][0][RTW89_WW][1][83] = -2, + [0][1][2][0][RTW89_WW][2][83] = 68, + [0][1][2][0][RTW89_WW][0][85] = -2, + [0][1][2][0][RTW89_WW][1][85] = -2, + [0][1][2][0][RTW89_WW][2][85] = 68, + [0][1][2][0][RTW89_WW][0][87] = -2, + [0][1][2][0][RTW89_WW][1][87] = -2, + [0][1][2][0][RTW89_WW][2][87] = 0, + [0][1][2][0][RTW89_WW][0][89] = -2, + [0][1][2][0][RTW89_WW][1][89] = -2, + [0][1][2][0][RTW89_WW][2][89] = 0, + [0][1][2][0][RTW89_WW][0][90] = -2, + [0][1][2][0][RTW89_WW][1][90] = -2, + [0][1][2][0][RTW89_WW][2][90] = 0, + [0][1][2][0][RTW89_WW][0][92] = -2, + [0][1][2][0][RTW89_WW][1][92] = -2, + [0][1][2][0][RTW89_WW][2][92] = 0, + [0][1][2][0][RTW89_WW][0][94] = -2, + [0][1][2][0][RTW89_WW][1][94] = -2, + [0][1][2][0][RTW89_WW][2][94] = 0, + [0][1][2][0][RTW89_WW][0][96] = -2, + [0][1][2][0][RTW89_WW][1][96] = -2, + [0][1][2][0][RTW89_WW][2][96] = 0, + [0][1][2][0][RTW89_WW][0][98] = -2, + [0][1][2][0][RTW89_WW][1][98] = -2, + [0][1][2][0][RTW89_WW][2][98] = 0, + [0][1][2][0][RTW89_WW][0][100] = -2, + [0][1][2][0][RTW89_WW][1][100] = -2, + [0][1][2][0][RTW89_WW][2][100] = 0, + [0][1][2][0][RTW89_WW][0][102] = -2, + [0][1][2][0][RTW89_WW][1][102] = -2, + [0][1][2][0][RTW89_WW][2][102] = 0, + [0][1][2][0][RTW89_WW][0][104] = -2, + [0][1][2][0][RTW89_WW][1][104] = -2, + [0][1][2][0][RTW89_WW][2][104] = 0, + [0][1][2][0][RTW89_WW][0][105] = -2, + [0][1][2][0][RTW89_WW][1][105] = -2, + [0][1][2][0][RTW89_WW][2][105] = 0, + [0][1][2][0][RTW89_WW][0][107] = 1, + [0][1][2][0][RTW89_WW][1][107] = 1, + [0][1][2][0][RTW89_WW][2][107] = 0, + [0][1][2][0][RTW89_WW][0][109] = 1, + [0][1][2][0][RTW89_WW][1][109] = 1, + [0][1][2][0][RTW89_WW][2][109] = 0, + [0][1][2][0][RTW89_WW][0][111] = 0, + [0][1][2][0][RTW89_WW][1][111] = 0, + [0][1][2][0][RTW89_WW][2][111] = 0, + [0][1][2][0][RTW89_WW][0][113] = 0, + [0][1][2][0][RTW89_WW][1][113] = 0, + [0][1][2][0][RTW89_WW][2][113] = 0, + [0][1][2][0][RTW89_WW][0][115] = 0, + [0][1][2][0][RTW89_WW][1][115] = 0, + [0][1][2][0][RTW89_WW][2][115] = 0, + [0][1][2][0][RTW89_WW][0][117] = 0, + [0][1][2][0][RTW89_WW][1][117] = 0, + [0][1][2][0][RTW89_WW][2][117] = 0, + [0][1][2][0][RTW89_WW][0][119] = 0, + [0][1][2][0][RTW89_WW][1][119] = 0, + [0][1][2][0][RTW89_WW][2][119] = 0, + [0][1][2][1][RTW89_WW][0][0] = -2, + [0][1][2][1][RTW89_WW][1][0] = -2, + [0][1][2][1][RTW89_WW][2][0] = 54, + [0][1][2][1][RTW89_WW][0][2] = -4, + [0][1][2][1][RTW89_WW][1][2] = -4, + [0][1][2][1][RTW89_WW][2][2] = 54, + [0][1][2][1][RTW89_WW][0][4] = -4, + [0][1][2][1][RTW89_WW][1][4] = -4, + [0][1][2][1][RTW89_WW][2][4] = 54, + [0][1][2][1][RTW89_WW][0][6] = -4, + [0][1][2][1][RTW89_WW][1][6] = -4, + [0][1][2][1][RTW89_WW][2][6] = 54, + [0][1][2][1][RTW89_WW][0][8] = -4, + [0][1][2][1][RTW89_WW][1][8] = -4, + [0][1][2][1][RTW89_WW][2][8] = 54, + [0][1][2][1][RTW89_WW][0][10] = -4, + [0][1][2][1][RTW89_WW][1][10] = -4, + [0][1][2][1][RTW89_WW][2][10] = 54, + [0][1][2][1][RTW89_WW][0][12] = -4, + [0][1][2][1][RTW89_WW][1][12] = -4, + [0][1][2][1][RTW89_WW][2][12] = 54, + [0][1][2][1][RTW89_WW][0][14] = -4, + [0][1][2][1][RTW89_WW][1][14] = -4, + [0][1][2][1][RTW89_WW][2][14] = 54, + [0][1][2][1][RTW89_WW][0][15] = -4, + [0][1][2][1][RTW89_WW][1][15] = -4, + [0][1][2][1][RTW89_WW][2][15] = 54, + [0][1][2][1][RTW89_WW][0][17] = -4, + [0][1][2][1][RTW89_WW][1][17] = -4, + [0][1][2][1][RTW89_WW][2][17] = 54, + [0][1][2][1][RTW89_WW][0][19] = -4, + [0][1][2][1][RTW89_WW][1][19] = -4, + [0][1][2][1][RTW89_WW][2][19] = 54, + [0][1][2][1][RTW89_WW][0][21] = -4, + [0][1][2][1][RTW89_WW][1][21] = -4, + [0][1][2][1][RTW89_WW][2][21] = 54, + [0][1][2][1][RTW89_WW][0][23] = -4, + [0][1][2][1][RTW89_WW][1][23] = -4, + [0][1][2][1][RTW89_WW][2][23] = 68, + [0][1][2][1][RTW89_WW][0][25] = -4, + [0][1][2][1][RTW89_WW][1][25] = -4, + [0][1][2][1][RTW89_WW][2][25] = 68, + [0][1][2][1][RTW89_WW][0][27] = -4, + [0][1][2][1][RTW89_WW][1][27] = -4, + [0][1][2][1][RTW89_WW][2][27] = 68, + [0][1][2][1][RTW89_WW][0][29] = -4, + [0][1][2][1][RTW89_WW][1][29] = -4, + [0][1][2][1][RTW89_WW][2][29] = 68, + [0][1][2][1][RTW89_WW][0][30] = -4, + [0][1][2][1][RTW89_WW][1][30] = -4, + [0][1][2][1][RTW89_WW][2][30] = 68, + [0][1][2][1][RTW89_WW][0][32] = -4, + [0][1][2][1][RTW89_WW][1][32] = -4, + [0][1][2][1][RTW89_WW][2][32] = 68, + [0][1][2][1][RTW89_WW][0][34] = -4, + [0][1][2][1][RTW89_WW][1][34] = -4, + [0][1][2][1][RTW89_WW][2][34] = 68, + [0][1][2][1][RTW89_WW][0][36] = -4, + [0][1][2][1][RTW89_WW][1][36] = -4, + [0][1][2][1][RTW89_WW][2][36] = 68, + [0][1][2][1][RTW89_WW][0][38] = -4, + [0][1][2][1][RTW89_WW][1][38] = -4, + [0][1][2][1][RTW89_WW][2][38] = 68, + [0][1][2][1][RTW89_WW][0][40] = -4, + [0][1][2][1][RTW89_WW][1][40] = -4, + [0][1][2][1][RTW89_WW][2][40] = 68, + [0][1][2][1][RTW89_WW][0][42] = -4, + [0][1][2][1][RTW89_WW][1][42] = -4, + [0][1][2][1][RTW89_WW][2][42] = 68, + [0][1][2][1][RTW89_WW][0][44] = -2, + [0][1][2][1][RTW89_WW][1][44] = -2, + [0][1][2][1][RTW89_WW][2][44] = 68, + [0][1][2][1][RTW89_WW][0][45] = -2, + [0][1][2][1][RTW89_WW][1][45] = -2, + [0][1][2][1][RTW89_WW][2][45] = 0, + [0][1][2][1][RTW89_WW][0][47] = -2, + [0][1][2][1][RTW89_WW][1][47] = -2, + [0][1][2][1][RTW89_WW][2][47] = 0, + [0][1][2][1][RTW89_WW][0][49] = -2, + [0][1][2][1][RTW89_WW][1][49] = -2, + [0][1][2][1][RTW89_WW][2][49] = 0, + [0][1][2][1][RTW89_WW][0][51] = -2, + [0][1][2][1][RTW89_WW][1][51] = -2, + [0][1][2][1][RTW89_WW][2][51] = 0, + [0][1][2][1][RTW89_WW][0][53] = -2, + [0][1][2][1][RTW89_WW][1][53] = -2, + [0][1][2][1][RTW89_WW][2][53] = 0, + [0][1][2][1][RTW89_WW][0][55] = -2, + [0][1][2][1][RTW89_WW][1][55] = -2, + [0][1][2][1][RTW89_WW][2][55] = 68, + [0][1][2][1][RTW89_WW][0][57] = -2, + [0][1][2][1][RTW89_WW][1][57] = -2, + [0][1][2][1][RTW89_WW][2][57] = 68, + [0][1][2][1][RTW89_WW][0][59] = -2, + [0][1][2][1][RTW89_WW][1][59] = -2, + [0][1][2][1][RTW89_WW][2][59] = 68, + [0][1][2][1][RTW89_WW][0][60] = -2, + [0][1][2][1][RTW89_WW][1][60] = -2, + [0][1][2][1][RTW89_WW][2][60] = 68, + [0][1][2][1][RTW89_WW][0][62] = -2, + [0][1][2][1][RTW89_WW][1][62] = -2, + [0][1][2][1][RTW89_WW][2][62] = 68, + [0][1][2][1][RTW89_WW][0][64] = -2, + [0][1][2][1][RTW89_WW][1][64] = -2, + [0][1][2][1][RTW89_WW][2][64] = 68, + [0][1][2][1][RTW89_WW][0][66] = -2, + [0][1][2][1][RTW89_WW][1][66] = -2, + [0][1][2][1][RTW89_WW][2][66] = 68, + [0][1][2][1][RTW89_WW][0][68] = -2, + [0][1][2][1][RTW89_WW][1][68] = -2, + [0][1][2][1][RTW89_WW][2][68] = 68, + [0][1][2][1][RTW89_WW][0][70] = -2, + [0][1][2][1][RTW89_WW][1][70] = -2, + [0][1][2][1][RTW89_WW][2][70] = 68, + [0][1][2][1][RTW89_WW][0][72] = -2, + [0][1][2][1][RTW89_WW][1][72] = -2, + [0][1][2][1][RTW89_WW][2][72] = 68, + [0][1][2][1][RTW89_WW][0][74] = -2, + [0][1][2][1][RTW89_WW][1][74] = -2, + [0][1][2][1][RTW89_WW][2][74] = 68, + [0][1][2][1][RTW89_WW][0][75] = -2, + [0][1][2][1][RTW89_WW][1][75] = -2, + [0][1][2][1][RTW89_WW][2][75] = 68, + [0][1][2][1][RTW89_WW][0][77] = -2, + [0][1][2][1][RTW89_WW][1][77] = -2, + [0][1][2][1][RTW89_WW][2][77] = 68, + [0][1][2][1][RTW89_WW][0][79] = -2, + [0][1][2][1][RTW89_WW][1][79] = -2, + [0][1][2][1][RTW89_WW][2][79] = 68, + [0][1][2][1][RTW89_WW][0][81] = -2, + [0][1][2][1][RTW89_WW][1][81] = -2, + [0][1][2][1][RTW89_WW][2][81] = 68, + [0][1][2][1][RTW89_WW][0][83] = -2, + [0][1][2][1][RTW89_WW][1][83] = -2, + [0][1][2][1][RTW89_WW][2][83] = 68, + [0][1][2][1][RTW89_WW][0][85] = -2, + [0][1][2][1][RTW89_WW][1][85] = -2, + [0][1][2][1][RTW89_WW][2][85] = 68, + [0][1][2][1][RTW89_WW][0][87] = -2, + [0][1][2][1][RTW89_WW][1][87] = -2, + [0][1][2][1][RTW89_WW][2][87] = 0, + [0][1][2][1][RTW89_WW][0][89] = -2, + [0][1][2][1][RTW89_WW][1][89] = -2, + [0][1][2][1][RTW89_WW][2][89] = 0, + [0][1][2][1][RTW89_WW][0][90] = -2, + [0][1][2][1][RTW89_WW][1][90] = -2, + [0][1][2][1][RTW89_WW][2][90] = 0, + [0][1][2][1][RTW89_WW][0][92] = -2, + [0][1][2][1][RTW89_WW][1][92] = -2, + [0][1][2][1][RTW89_WW][2][92] = 0, + [0][1][2][1][RTW89_WW][0][94] = -2, + [0][1][2][1][RTW89_WW][1][94] = -2, + [0][1][2][1][RTW89_WW][2][94] = 0, + [0][1][2][1][RTW89_WW][0][96] = -2, + [0][1][2][1][RTW89_WW][1][96] = -2, + [0][1][2][1][RTW89_WW][2][96] = 0, + [0][1][2][1][RTW89_WW][0][98] = -2, + [0][1][2][1][RTW89_WW][1][98] = -2, + [0][1][2][1][RTW89_WW][2][98] = 0, + [0][1][2][1][RTW89_WW][0][100] = -2, + [0][1][2][1][RTW89_WW][1][100] = -2, + [0][1][2][1][RTW89_WW][2][100] = 0, + [0][1][2][1][RTW89_WW][0][102] = -2, + [0][1][2][1][RTW89_WW][1][102] = -2, + [0][1][2][1][RTW89_WW][2][102] = 0, + [0][1][2][1][RTW89_WW][0][104] = -2, + [0][1][2][1][RTW89_WW][1][104] = -2, + [0][1][2][1][RTW89_WW][2][104] = 0, + [0][1][2][1][RTW89_WW][0][105] = -2, + [0][1][2][1][RTW89_WW][1][105] = -2, + [0][1][2][1][RTW89_WW][2][105] = 0, + [0][1][2][1][RTW89_WW][0][107] = 1, + [0][1][2][1][RTW89_WW][1][107] = 1, + [0][1][2][1][RTW89_WW][2][107] = 0, + [0][1][2][1][RTW89_WW][0][109] = 1, + [0][1][2][1][RTW89_WW][1][109] = 1, + [0][1][2][1][RTW89_WW][2][109] = 0, + [0][1][2][1][RTW89_WW][0][111] = 0, + [0][1][2][1][RTW89_WW][1][111] = 0, + [0][1][2][1][RTW89_WW][2][111] = 0, + [0][1][2][1][RTW89_WW][0][113] = 0, + [0][1][2][1][RTW89_WW][1][113] = 0, + [0][1][2][1][RTW89_WW][2][113] = 0, + [0][1][2][1][RTW89_WW][0][115] = 0, + [0][1][2][1][RTW89_WW][1][115] = 0, + [0][1][2][1][RTW89_WW][2][115] = 0, + [0][1][2][1][RTW89_WW][0][117] = 0, + [0][1][2][1][RTW89_WW][1][117] = 0, + [0][1][2][1][RTW89_WW][2][117] = 0, + [0][1][2][1][RTW89_WW][0][119] = 0, + [0][1][2][1][RTW89_WW][1][119] = 0, + [0][1][2][1][RTW89_WW][2][119] = 0, + [1][0][2][0][RTW89_WW][0][1] = 24, + [1][0][2][0][RTW89_WW][1][1] = 34, + [1][0][2][0][RTW89_WW][2][1] = 70, + [1][0][2][0][RTW89_WW][0][5] = 24, + [1][0][2][0][RTW89_WW][1][5] = 34, + [1][0][2][0][RTW89_WW][2][5] = 70, + [1][0][2][0][RTW89_WW][0][9] = 24, + [1][0][2][0][RTW89_WW][1][9] = 34, + [1][0][2][0][RTW89_WW][2][9] = 70, + [1][0][2][0][RTW89_WW][0][13] = 24, + [1][0][2][0][RTW89_WW][1][13] = 34, + [1][0][2][0][RTW89_WW][2][13] = 70, + [1][0][2][0][RTW89_WW][0][16] = 24, + [1][0][2][0][RTW89_WW][1][16] = 34, + [1][0][2][0][RTW89_WW][2][16] = 70, + [1][0][2][0][RTW89_WW][0][20] = 24, + [1][0][2][0][RTW89_WW][1][20] = 34, + [1][0][2][0][RTW89_WW][2][20] = 70, + [1][0][2][0][RTW89_WW][0][24] = 26, + [1][0][2][0][RTW89_WW][1][24] = 36, + [1][0][2][0][RTW89_WW][2][24] = 70, + [1][0][2][0][RTW89_WW][0][28] = 26, + [1][0][2][0][RTW89_WW][1][28] = 34, + [1][0][2][0][RTW89_WW][2][28] = 70, + [1][0][2][0][RTW89_WW][0][31] = 26, + [1][0][2][0][RTW89_WW][1][31] = 34, + [1][0][2][0][RTW89_WW][2][31] = 70, + [1][0][2][0][RTW89_WW][0][35] = 26, + [1][0][2][0][RTW89_WW][1][35] = 34, + [1][0][2][0][RTW89_WW][2][35] = 70, + [1][0][2][0][RTW89_WW][0][39] = 26, + [1][0][2][0][RTW89_WW][1][39] = 34, + [1][0][2][0][RTW89_WW][2][39] = 70, + [1][0][2][0][RTW89_WW][0][43] = 26, + [1][0][2][0][RTW89_WW][1][43] = 34, + [1][0][2][0][RTW89_WW][2][43] = 70, + [1][0][2][0][RTW89_WW][0][46] = 34, + [1][0][2][0][RTW89_WW][1][46] = 34, + [1][0][2][0][RTW89_WW][2][46] = 0, + [1][0][2][0][RTW89_WW][0][50] = 34, + [1][0][2][0][RTW89_WW][1][50] = 34, + [1][0][2][0][RTW89_WW][2][50] = 0, + [1][0][2][0][RTW89_WW][0][54] = 36, + [1][0][2][0][RTW89_WW][1][54] = 36, + [1][0][2][0][RTW89_WW][2][54] = 0, + [1][0][2][0][RTW89_WW][0][58] = 36, + [1][0][2][0][RTW89_WW][1][58] = 36, + [1][0][2][0][RTW89_WW][2][58] = 66, + [1][0][2][0][RTW89_WW][0][61] = 34, + [1][0][2][0][RTW89_WW][1][61] = 34, + [1][0][2][0][RTW89_WW][2][61] = 66, + [1][0][2][0][RTW89_WW][0][65] = 34, + [1][0][2][0][RTW89_WW][1][65] = 34, + [1][0][2][0][RTW89_WW][2][65] = 66, + [1][0][2][0][RTW89_WW][0][69] = 34, + [1][0][2][0][RTW89_WW][1][69] = 34, + [1][0][2][0][RTW89_WW][2][69] = 66, + [1][0][2][0][RTW89_WW][0][73] = 34, + [1][0][2][0][RTW89_WW][1][73] = 34, + [1][0][2][0][RTW89_WW][2][73] = 66, + [1][0][2][0][RTW89_WW][0][76] = 34, + [1][0][2][0][RTW89_WW][1][76] = 34, + [1][0][2][0][RTW89_WW][2][76] = 66, + [1][0][2][0][RTW89_WW][0][80] = 34, + [1][0][2][0][RTW89_WW][1][80] = 34, + [1][0][2][0][RTW89_WW][2][80] = 66, + [1][0][2][0][RTW89_WW][0][84] = 34, + [1][0][2][0][RTW89_WW][1][84] = 34, + [1][0][2][0][RTW89_WW][2][84] = 66, + [1][0][2][0][RTW89_WW][0][88] = 34, + [1][0][2][0][RTW89_WW][1][88] = 34, + [1][0][2][0][RTW89_WW][2][88] = 0, + [1][0][2][0][RTW89_WW][0][91] = 36, + [1][0][2][0][RTW89_WW][1][91] = 36, + [1][0][2][0][RTW89_WW][2][91] = 0, + [1][0][2][0][RTW89_WW][0][95] = 34, + [1][0][2][0][RTW89_WW][1][95] = 34, + [1][0][2][0][RTW89_WW][2][95] = 0, + [1][0][2][0][RTW89_WW][0][99] = 34, + [1][0][2][0][RTW89_WW][1][99] = 34, + [1][0][2][0][RTW89_WW][2][99] = 0, + [1][0][2][0][RTW89_WW][0][103] = 34, + [1][0][2][0][RTW89_WW][1][103] = 34, + [1][0][2][0][RTW89_WW][2][103] = 0, + [1][0][2][0][RTW89_WW][0][106] = 36, + [1][0][2][0][RTW89_WW][1][106] = 36, + [1][0][2][0][RTW89_WW][2][106] = 0, + [1][0][2][0][RTW89_WW][0][110] = 0, + [1][0][2][0][RTW89_WW][1][110] = 0, + [1][0][2][0][RTW89_WW][2][110] = 0, + [1][0][2][0][RTW89_WW][0][114] = 0, + [1][0][2][0][RTW89_WW][1][114] = 0, + [1][0][2][0][RTW89_WW][2][114] = 0, + [1][0][2][0][RTW89_WW][0][118] = 0, + [1][0][2][0][RTW89_WW][1][118] = 0, + [1][0][2][0][RTW89_WW][2][118] = 0, + [1][1][2][0][RTW89_WW][0][1] = 10, + [1][1][2][0][RTW89_WW][1][1] = 10, + [1][1][2][0][RTW89_WW][2][1] = 58, + [1][1][2][0][RTW89_WW][0][5] = 10, + [1][1][2][0][RTW89_WW][1][5] = 10, + [1][1][2][0][RTW89_WW][2][5] = 58, + [1][1][2][0][RTW89_WW][0][9] = 10, + [1][1][2][0][RTW89_WW][1][9] = 10, + [1][1][2][0][RTW89_WW][2][9] = 58, + [1][1][2][0][RTW89_WW][0][13] = 10, + [1][1][2][0][RTW89_WW][1][13] = 10, + [1][1][2][0][RTW89_WW][2][13] = 58, + [1][1][2][0][RTW89_WW][0][16] = 10, + [1][1][2][0][RTW89_WW][1][16] = 10, + [1][1][2][0][RTW89_WW][2][16] = 58, + [1][1][2][0][RTW89_WW][0][20] = 10, + [1][1][2][0][RTW89_WW][1][20] = 10, + [1][1][2][0][RTW89_WW][2][20] = 58, + [1][1][2][0][RTW89_WW][0][24] = 10, + [1][1][2][0][RTW89_WW][1][24] = 10, + [1][1][2][0][RTW89_WW][2][24] = 70, + [1][1][2][0][RTW89_WW][0][28] = 10, + [1][1][2][0][RTW89_WW][1][28] = 10, + [1][1][2][0][RTW89_WW][2][28] = 70, + [1][1][2][0][RTW89_WW][0][31] = 10, + [1][1][2][0][RTW89_WW][1][31] = 10, + [1][1][2][0][RTW89_WW][2][31] = 70, + [1][1][2][0][RTW89_WW][0][35] = 10, + [1][1][2][0][RTW89_WW][1][35] = 10, + [1][1][2][0][RTW89_WW][2][35] = 70, + [1][1][2][0][RTW89_WW][0][39] = 10, + [1][1][2][0][RTW89_WW][1][39] = 10, + [1][1][2][0][RTW89_WW][2][39] = 70, + [1][1][2][0][RTW89_WW][0][43] = 10, + [1][1][2][0][RTW89_WW][1][43] = 10, + [1][1][2][0][RTW89_WW][2][43] = 70, + [1][1][2][0][RTW89_WW][0][46] = 12, + [1][1][2][0][RTW89_WW][1][46] = 12, + [1][1][2][0][RTW89_WW][2][46] = 0, + [1][1][2][0][RTW89_WW][0][50] = 12, + [1][1][2][0][RTW89_WW][1][50] = 12, + [1][1][2][0][RTW89_WW][2][50] = 0, + [1][1][2][0][RTW89_WW][0][54] = 10, + [1][1][2][0][RTW89_WW][1][54] = 10, + [1][1][2][0][RTW89_WW][2][54] = 0, + [1][1][2][0][RTW89_WW][0][58] = 10, + [1][1][2][0][RTW89_WW][1][58] = 10, + [1][1][2][0][RTW89_WW][2][58] = 66, + [1][1][2][0][RTW89_WW][0][61] = 10, + [1][1][2][0][RTW89_WW][1][61] = 10, + [1][1][2][0][RTW89_WW][2][61] = 66, + [1][1][2][0][RTW89_WW][0][65] = 10, + [1][1][2][0][RTW89_WW][1][65] = 10, + [1][1][2][0][RTW89_WW][2][65] = 66, + [1][1][2][0][RTW89_WW][0][69] = 10, + [1][1][2][0][RTW89_WW][1][69] = 10, + [1][1][2][0][RTW89_WW][2][69] = 66, + [1][1][2][0][RTW89_WW][0][73] = 10, + [1][1][2][0][RTW89_WW][1][73] = 10, + [1][1][2][0][RTW89_WW][2][73] = 66, + [1][1][2][0][RTW89_WW][0][76] = 10, + [1][1][2][0][RTW89_WW][1][76] = 10, + [1][1][2][0][RTW89_WW][2][76] = 66, + [1][1][2][0][RTW89_WW][0][80] = 10, + [1][1][2][0][RTW89_WW][1][80] = 10, + [1][1][2][0][RTW89_WW][2][80] = 66, + [1][1][2][0][RTW89_WW][0][84] = 10, + [1][1][2][0][RTW89_WW][1][84] = 10, + [1][1][2][0][RTW89_WW][2][84] = 66, + [1][1][2][0][RTW89_WW][0][88] = 10, + [1][1][2][0][RTW89_WW][1][88] = 10, + [1][1][2][0][RTW89_WW][2][88] = 0, + [1][1][2][0][RTW89_WW][0][91] = 12, + [1][1][2][0][RTW89_WW][1][91] = 12, + [1][1][2][0][RTW89_WW][2][91] = 0, + [1][1][2][0][RTW89_WW][0][95] = 10, + [1][1][2][0][RTW89_WW][1][95] = 10, + [1][1][2][0][RTW89_WW][2][95] = 0, + [1][1][2][0][RTW89_WW][0][99] = 10, + [1][1][2][0][RTW89_WW][1][99] = 10, + [1][1][2][0][RTW89_WW][2][99] = 0, + [1][1][2][0][RTW89_WW][0][103] = 10, + [1][1][2][0][RTW89_WW][1][103] = 10, + [1][1][2][0][RTW89_WW][2][103] = 0, + [1][1][2][0][RTW89_WW][0][106] = 12, + [1][1][2][0][RTW89_WW][1][106] = 12, + [1][1][2][0][RTW89_WW][2][106] = 0, + [1][1][2][0][RTW89_WW][0][110] = 0, + [1][1][2][0][RTW89_WW][1][110] = 0, + [1][1][2][0][RTW89_WW][2][110] = 0, + [1][1][2][0][RTW89_WW][0][114] = 0, + [1][1][2][0][RTW89_WW][1][114] = 0, + [1][1][2][0][RTW89_WW][2][114] = 0, + [1][1][2][0][RTW89_WW][0][118] = 0, + [1][1][2][0][RTW89_WW][1][118] = 0, + [1][1][2][0][RTW89_WW][2][118] = 0, + [1][1][2][1][RTW89_WW][0][1] = 6, + [1][1][2][1][RTW89_WW][1][1] = 10, + [1][1][2][1][RTW89_WW][2][1] = 58, + [1][1][2][1][RTW89_WW][0][5] = 6, + [1][1][2][1][RTW89_WW][1][5] = 10, + [1][1][2][1][RTW89_WW][2][5] = 58, + [1][1][2][1][RTW89_WW][0][9] = 6, + [1][1][2][1][RTW89_WW][1][9] = 10, + [1][1][2][1][RTW89_WW][2][9] = 58, + [1][1][2][1][RTW89_WW][0][13] = 6, + [1][1][2][1][RTW89_WW][1][13] = 10, + [1][1][2][1][RTW89_WW][2][13] = 58, + [1][1][2][1][RTW89_WW][0][16] = 6, + [1][1][2][1][RTW89_WW][1][16] = 10, + [1][1][2][1][RTW89_WW][2][16] = 58, + [1][1][2][1][RTW89_WW][0][20] = 6, + [1][1][2][1][RTW89_WW][1][20] = 10, + [1][1][2][1][RTW89_WW][2][20] = 58, + [1][1][2][1][RTW89_WW][0][24] = 6, + [1][1][2][1][RTW89_WW][1][24] = 10, + [1][1][2][1][RTW89_WW][2][24] = 70, + [1][1][2][1][RTW89_WW][0][28] = 6, + [1][1][2][1][RTW89_WW][1][28] = 10, + [1][1][2][1][RTW89_WW][2][28] = 70, + [1][1][2][1][RTW89_WW][0][31] = 6, + [1][1][2][1][RTW89_WW][1][31] = 10, + [1][1][2][1][RTW89_WW][2][31] = 70, + [1][1][2][1][RTW89_WW][0][35] = 6, + [1][1][2][1][RTW89_WW][1][35] = 10, + [1][1][2][1][RTW89_WW][2][35] = 70, + [1][1][2][1][RTW89_WW][0][39] = 6, + [1][1][2][1][RTW89_WW][1][39] = 10, + [1][1][2][1][RTW89_WW][2][39] = 70, + [1][1][2][1][RTW89_WW][0][43] = 6, + [1][1][2][1][RTW89_WW][1][43] = 10, + [1][1][2][1][RTW89_WW][2][43] = 70, + [1][1][2][1][RTW89_WW][0][46] = 12, + [1][1][2][1][RTW89_WW][1][46] = 12, + [1][1][2][1][RTW89_WW][2][46] = 0, + [1][1][2][1][RTW89_WW][0][50] = 12, + [1][1][2][1][RTW89_WW][1][50] = 12, + [1][1][2][1][RTW89_WW][2][50] = 0, + [1][1][2][1][RTW89_WW][0][54] = 10, + [1][1][2][1][RTW89_WW][1][54] = 10, + [1][1][2][1][RTW89_WW][2][54] = 0, + [1][1][2][1][RTW89_WW][0][58] = 10, + [1][1][2][1][RTW89_WW][1][58] = 10, + [1][1][2][1][RTW89_WW][2][58] = 66, + [1][1][2][1][RTW89_WW][0][61] = 10, + [1][1][2][1][RTW89_WW][1][61] = 10, + [1][1][2][1][RTW89_WW][2][61] = 66, + [1][1][2][1][RTW89_WW][0][65] = 10, + [1][1][2][1][RTW89_WW][1][65] = 10, + [1][1][2][1][RTW89_WW][2][65] = 66, + [1][1][2][1][RTW89_WW][0][69] = 10, + [1][1][2][1][RTW89_WW][1][69] = 10, + [1][1][2][1][RTW89_WW][2][69] = 66, + [1][1][2][1][RTW89_WW][0][73] = 10, + [1][1][2][1][RTW89_WW][1][73] = 10, + [1][1][2][1][RTW89_WW][2][73] = 66, + [1][1][2][1][RTW89_WW][0][76] = 10, + [1][1][2][1][RTW89_WW][1][76] = 10, + [1][1][2][1][RTW89_WW][2][76] = 66, + [1][1][2][1][RTW89_WW][0][80] = 10, + [1][1][2][1][RTW89_WW][1][80] = 10, + [1][1][2][1][RTW89_WW][2][80] = 66, + [1][1][2][1][RTW89_WW][0][84] = 10, + [1][1][2][1][RTW89_WW][1][84] = 10, + [1][1][2][1][RTW89_WW][2][84] = 66, + [1][1][2][1][RTW89_WW][0][88] = 10, + [1][1][2][1][RTW89_WW][1][88] = 10, + [1][1][2][1][RTW89_WW][2][88] = 0, + [1][1][2][1][RTW89_WW][0][91] = 12, + [1][1][2][1][RTW89_WW][1][91] = 12, + [1][1][2][1][RTW89_WW][2][91] = 0, + [1][1][2][1][RTW89_WW][0][95] = 10, + [1][1][2][1][RTW89_WW][1][95] = 10, + [1][1][2][1][RTW89_WW][2][95] = 0, + [1][1][2][1][RTW89_WW][0][99] = 10, + [1][1][2][1][RTW89_WW][1][99] = 10, + [1][1][2][1][RTW89_WW][2][99] = 0, + [1][1][2][1][RTW89_WW][0][103] = 10, + [1][1][2][1][RTW89_WW][1][103] = 10, + [1][1][2][1][RTW89_WW][2][103] = 0, + [1][1][2][1][RTW89_WW][0][106] = 12, + [1][1][2][1][RTW89_WW][1][106] = 12, + [1][1][2][1][RTW89_WW][2][106] = 0, + [1][1][2][1][RTW89_WW][0][110] = 0, + [1][1][2][1][RTW89_WW][1][110] = 0, + [1][1][2][1][RTW89_WW][2][110] = 0, + [1][1][2][1][RTW89_WW][0][114] = 0, + [1][1][2][1][RTW89_WW][1][114] = 0, + [1][1][2][1][RTW89_WW][2][114] = 0, + [1][1][2][1][RTW89_WW][0][118] = 0, + [1][1][2][1][RTW89_WW][1][118] = 0, + [1][1][2][1][RTW89_WW][2][118] = 0, + [2][0][2][0][RTW89_WW][0][3] = 24, + [2][0][2][0][RTW89_WW][1][3] = 46, + [2][0][2][0][RTW89_WW][2][3] = 60, + [2][0][2][0][RTW89_WW][0][11] = 24, + [2][0][2][0][RTW89_WW][1][11] = 46, + [2][0][2][0][RTW89_WW][2][11] = 60, + [2][0][2][0][RTW89_WW][0][18] = 24, + [2][0][2][0][RTW89_WW][1][18] = 46, + [2][0][2][0][RTW89_WW][2][18] = 60, + [2][0][2][0][RTW89_WW][0][26] = 24, + [2][0][2][0][RTW89_WW][1][26] = 46, + [2][0][2][0][RTW89_WW][2][26] = 60, + [2][0][2][0][RTW89_WW][0][33] = 24, + [2][0][2][0][RTW89_WW][1][33] = 46, + [2][0][2][0][RTW89_WW][2][33] = 60, + [2][0][2][0][RTW89_WW][0][41] = 24, + [2][0][2][0][RTW89_WW][1][41] = 46, + [2][0][2][0][RTW89_WW][2][41] = 60, + [2][0][2][0][RTW89_WW][0][48] = 46, + [2][0][2][0][RTW89_WW][1][48] = 46, + [2][0][2][0][RTW89_WW][2][48] = 0, + [2][0][2][0][RTW89_WW][0][56] = 46, + [2][0][2][0][RTW89_WW][1][56] = 46, + [2][0][2][0][RTW89_WW][2][56] = 0, + [2][0][2][0][RTW89_WW][0][63] = 46, + [2][0][2][0][RTW89_WW][1][63] = 46, + [2][0][2][0][RTW89_WW][2][63] = 58, + [2][0][2][0][RTW89_WW][0][71] = 46, + [2][0][2][0][RTW89_WW][1][71] = 46, + [2][0][2][0][RTW89_WW][2][71] = 58, + [2][0][2][0][RTW89_WW][0][78] = 46, + [2][0][2][0][RTW89_WW][1][78] = 46, + [2][0][2][0][RTW89_WW][2][78] = 58, + [2][0][2][0][RTW89_WW][0][86] = 46, + [2][0][2][0][RTW89_WW][1][86] = 46, + [2][0][2][0][RTW89_WW][2][86] = 0, + [2][0][2][0][RTW89_WW][0][93] = 46, + [2][0][2][0][RTW89_WW][1][93] = 46, + [2][0][2][0][RTW89_WW][2][93] = 0, + [2][0][2][0][RTW89_WW][0][101] = 44, + [2][0][2][0][RTW89_WW][1][101] = 44, + [2][0][2][0][RTW89_WW][2][101] = 0, + [2][0][2][0][RTW89_WW][0][108] = 0, + [2][0][2][0][RTW89_WW][1][108] = 0, + [2][0][2][0][RTW89_WW][2][108] = 0, + [2][0][2][0][RTW89_WW][0][116] = 0, + [2][0][2][0][RTW89_WW][1][116] = 0, + [2][0][2][0][RTW89_WW][2][116] = 0, + [2][1][2][0][RTW89_WW][0][3] = 12, + [2][1][2][0][RTW89_WW][1][3] = 22, + [2][1][2][0][RTW89_WW][2][3] = 50, + [2][1][2][0][RTW89_WW][0][11] = 12, + [2][1][2][0][RTW89_WW][1][11] = 20, + [2][1][2][0][RTW89_WW][2][11] = 50, + [2][1][2][0][RTW89_WW][0][18] = 12, + [2][1][2][0][RTW89_WW][1][18] = 20, + [2][1][2][0][RTW89_WW][2][18] = 50, + [2][1][2][0][RTW89_WW][0][26] = 12, + [2][1][2][0][RTW89_WW][1][26] = 20, + [2][1][2][0][RTW89_WW][2][26] = 60, + [2][1][2][0][RTW89_WW][0][33] = 12, + [2][1][2][0][RTW89_WW][1][33] = 20, + [2][1][2][0][RTW89_WW][2][33] = 60, + [2][1][2][0][RTW89_WW][0][41] = 12, + [2][1][2][0][RTW89_WW][1][41] = 22, + [2][1][2][0][RTW89_WW][2][41] = 60, + [2][1][2][0][RTW89_WW][0][48] = 22, + [2][1][2][0][RTW89_WW][1][48] = 22, + [2][1][2][0][RTW89_WW][2][48] = 0, + [2][1][2][0][RTW89_WW][0][56] = 20, + [2][1][2][0][RTW89_WW][1][56] = 20, + [2][1][2][0][RTW89_WW][2][56] = 0, + [2][1][2][0][RTW89_WW][0][63] = 22, + [2][1][2][0][RTW89_WW][1][63] = 22, + [2][1][2][0][RTW89_WW][2][63] = 58, + [2][1][2][0][RTW89_WW][0][71] = 20, + [2][1][2][0][RTW89_WW][1][71] = 20, + [2][1][2][0][RTW89_WW][2][71] = 58, + [2][1][2][0][RTW89_WW][0][78] = 20, + [2][1][2][0][RTW89_WW][1][78] = 20, + [2][1][2][0][RTW89_WW][2][78] = 58, + [2][1][2][0][RTW89_WW][0][86] = 20, + [2][1][2][0][RTW89_WW][1][86] = 20, + [2][1][2][0][RTW89_WW][2][86] = 0, + [2][1][2][0][RTW89_WW][0][93] = 22, + [2][1][2][0][RTW89_WW][1][93] = 22, + [2][1][2][0][RTW89_WW][2][93] = 0, + [2][1][2][0][RTW89_WW][0][101] = 22, + [2][1][2][0][RTW89_WW][1][101] = 22, + [2][1][2][0][RTW89_WW][2][101] = 0, + [2][1][2][0][RTW89_WW][0][108] = 0, + [2][1][2][0][RTW89_WW][1][108] = 0, + [2][1][2][0][RTW89_WW][2][108] = 0, + [2][1][2][0][RTW89_WW][0][116] = 0, + [2][1][2][0][RTW89_WW][1][116] = 0, + [2][1][2][0][RTW89_WW][2][116] = 0, + [2][1][2][1][RTW89_WW][0][3] = 6, + [2][1][2][1][RTW89_WW][1][3] = 22, + [2][1][2][1][RTW89_WW][2][3] = 50, + [2][1][2][1][RTW89_WW][0][11] = 6, + [2][1][2][1][RTW89_WW][1][11] = 20, + [2][1][2][1][RTW89_WW][2][11] = 50, + [2][1][2][1][RTW89_WW][0][18] = 6, + [2][1][2][1][RTW89_WW][1][18] = 20, + [2][1][2][1][RTW89_WW][2][18] = 50, + [2][1][2][1][RTW89_WW][0][26] = 6, + [2][1][2][1][RTW89_WW][1][26] = 20, + [2][1][2][1][RTW89_WW][2][26] = 60, + [2][1][2][1][RTW89_WW][0][33] = 6, + [2][1][2][1][RTW89_WW][1][33] = 20, + [2][1][2][1][RTW89_WW][2][33] = 60, + [2][1][2][1][RTW89_WW][0][41] = 6, + [2][1][2][1][RTW89_WW][1][41] = 22, + [2][1][2][1][RTW89_WW][2][41] = 60, + [2][1][2][1][RTW89_WW][0][48] = 22, + [2][1][2][1][RTW89_WW][1][48] = 22, + [2][1][2][1][RTW89_WW][2][48] = 0, + [2][1][2][1][RTW89_WW][0][56] = 20, + [2][1][2][1][RTW89_WW][1][56] = 20, + [2][1][2][1][RTW89_WW][2][56] = 0, + [2][1][2][1][RTW89_WW][0][63] = 22, + [2][1][2][1][RTW89_WW][1][63] = 22, + [2][1][2][1][RTW89_WW][2][63] = 58, + [2][1][2][1][RTW89_WW][0][71] = 20, + [2][1][2][1][RTW89_WW][1][71] = 20, + [2][1][2][1][RTW89_WW][2][71] = 58, + [2][1][2][1][RTW89_WW][0][78] = 20, + [2][1][2][1][RTW89_WW][1][78] = 20, + [2][1][2][1][RTW89_WW][2][78] = 58, + [2][1][2][1][RTW89_WW][0][86] = 20, + [2][1][2][1][RTW89_WW][1][86] = 20, + [2][1][2][1][RTW89_WW][2][86] = 0, + [2][1][2][1][RTW89_WW][0][93] = 22, + [2][1][2][1][RTW89_WW][1][93] = 22, + [2][1][2][1][RTW89_WW][2][93] = 0, + [2][1][2][1][RTW89_WW][0][101] = 22, + [2][1][2][1][RTW89_WW][1][101] = 22, + [2][1][2][1][RTW89_WW][2][101] = 0, + [2][1][2][1][RTW89_WW][0][108] = 0, + [2][1][2][1][RTW89_WW][1][108] = 0, + [2][1][2][1][RTW89_WW][2][108] = 0, + [2][1][2][1][RTW89_WW][0][116] = 0, + [2][1][2][1][RTW89_WW][1][116] = 0, + [2][1][2][1][RTW89_WW][2][116] = 0, + [3][0][2][0][RTW89_WW][0][7] = 22, + [3][0][2][0][RTW89_WW][1][7] = 42, + [3][0][2][0][RTW89_WW][2][7] = 52, + [3][0][2][0][RTW89_WW][0][22] = 20, + [3][0][2][0][RTW89_WW][1][22] = 42, + [3][0][2][0][RTW89_WW][2][22] = 52, + [3][0][2][0][RTW89_WW][0][37] = 20, + [3][0][2][0][RTW89_WW][1][37] = 42, + [3][0][2][0][RTW89_WW][2][37] = 52, + [3][0][2][0][RTW89_WW][0][52] = 54, + [3][0][2][0][RTW89_WW][1][52] = 54, + [3][0][2][0][RTW89_WW][2][52] = 0, + [3][0][2][0][RTW89_WW][0][67] = 54, + [3][0][2][0][RTW89_WW][1][67] = 54, + [3][0][2][0][RTW89_WW][2][67] = 54, + [3][0][2][0][RTW89_WW][0][82] = 26, + [3][0][2][0][RTW89_WW][1][82] = 26, + [3][0][2][0][RTW89_WW][2][82] = 0, + [3][0][2][0][RTW89_WW][0][97] = 26, + [3][0][2][0][RTW89_WW][1][97] = 26, + [3][0][2][0][RTW89_WW][2][97] = 0, + [3][0][2][0][RTW89_WW][0][112] = 0, + [3][0][2][0][RTW89_WW][1][112] = 0, + [3][0][2][0][RTW89_WW][2][112] = 0, + [3][1][2][0][RTW89_WW][0][7] = 10, + [3][1][2][0][RTW89_WW][1][7] = 32, + [3][1][2][0][RTW89_WW][2][7] = 46, + [3][1][2][0][RTW89_WW][0][22] = 8, + [3][1][2][0][RTW89_WW][1][22] = 30, + [3][1][2][0][RTW89_WW][2][22] = 52, + [3][1][2][0][RTW89_WW][0][37] = 8, + [3][1][2][0][RTW89_WW][1][37] = 30, + [3][1][2][0][RTW89_WW][2][37] = 52, + [3][1][2][0][RTW89_WW][0][52] = 30, + [3][1][2][0][RTW89_WW][1][52] = 30, + [3][1][2][0][RTW89_WW][2][52] = 0, + [3][1][2][0][RTW89_WW][0][67] = 32, + [3][1][2][0][RTW89_WW][1][67] = 32, + [3][1][2][0][RTW89_WW][2][67] = 54, + [3][1][2][0][RTW89_WW][0][82] = 24, + [3][1][2][0][RTW89_WW][1][82] = 24, + [3][1][2][0][RTW89_WW][2][82] = 0, + [3][1][2][0][RTW89_WW][0][97] = 24, + [3][1][2][0][RTW89_WW][1][97] = 24, + [3][1][2][0][RTW89_WW][2][97] = 0, + [3][1][2][0][RTW89_WW][0][112] = 0, + [3][1][2][0][RTW89_WW][1][112] = 0, + [3][1][2][0][RTW89_WW][2][112] = 0, + [3][1][2][1][RTW89_WW][0][7] = 6, + [3][1][2][1][RTW89_WW][1][7] = 32, + [3][1][2][1][RTW89_WW][2][7] = 46, + [3][1][2][1][RTW89_WW][0][22] = 6, + [3][1][2][1][RTW89_WW][1][22] = 30, + [3][1][2][1][RTW89_WW][2][22] = 52, + [3][1][2][1][RTW89_WW][0][37] = 6, + [3][1][2][1][RTW89_WW][1][37] = 30, + [3][1][2][1][RTW89_WW][2][37] = 52, + [3][1][2][1][RTW89_WW][0][52] = 30, + [3][1][2][1][RTW89_WW][1][52] = 30, + [3][1][2][1][RTW89_WW][2][52] = 0, + [3][1][2][1][RTW89_WW][0][67] = 32, + [3][1][2][1][RTW89_WW][1][67] = 32, + [3][1][2][1][RTW89_WW][2][67] = 54, + [3][1][2][1][RTW89_WW][0][82] = 24, + [3][1][2][1][RTW89_WW][1][82] = 24, + [3][1][2][1][RTW89_WW][2][82] = 0, + [3][1][2][1][RTW89_WW][0][97] = 24, + [3][1][2][1][RTW89_WW][1][97] = 24, + [3][1][2][1][RTW89_WW][2][97] = 0, + [3][1][2][1][RTW89_WW][0][112] = 0, + [3][1][2][1][RTW89_WW][1][112] = 0, + [3][1][2][1][RTW89_WW][2][112] = 0, + [0][0][1][0][RTW89_FCC][1][0] = 24, + [0][0][1][0][RTW89_FCC][2][0] = 56, + [0][0][1][0][RTW89_ETSI][1][0] = 66, + [0][0][1][0][RTW89_ETSI][0][0] = 28, + [0][0][1][0][RTW89_MKK][1][0] = 66, + [0][0][1][0][RTW89_MKK][0][0] = 26, + [0][0][1][0][RTW89_IC][1][0] = 24, + [0][0][1][0][RTW89_KCC][1][0] = 24, + [0][0][1][0][RTW89_KCC][0][0] = 24, + [0][0][1][0][RTW89_ACMA][1][0] = 66, + [0][0][1][0][RTW89_ACMA][0][0] = 28, + [0][0][1][0][RTW89_CHILE][1][0] = 24, + [0][0][1][0][RTW89_QATAR][1][0] = 66, + [0][0][1][0][RTW89_QATAR][0][0] = 28, + [0][0][1][0][RTW89_UK][1][0] = 66, + [0][0][1][0][RTW89_UK][0][0] = 28, + [0][0][1][0][RTW89_FCC][1][2] = 22, + [0][0][1][0][RTW89_FCC][2][2] = 56, + [0][0][1][0][RTW89_ETSI][1][2] = 66, + [0][0][1][0][RTW89_ETSI][0][2] = 28, + [0][0][1][0][RTW89_MKK][1][2] = 66, + [0][0][1][0][RTW89_MKK][0][2] = 26, + [0][0][1][0][RTW89_IC][1][2] = 22, + [0][0][1][0][RTW89_KCC][1][2] = 24, + [0][0][1][0][RTW89_KCC][0][2] = 24, + [0][0][1][0][RTW89_ACMA][1][2] = 66, + [0][0][1][0][RTW89_ACMA][0][2] = 28, + [0][0][1][0][RTW89_CHILE][1][2] = 22, + [0][0][1][0][RTW89_QATAR][1][2] = 66, + [0][0][1][0][RTW89_QATAR][0][2] = 28, + [0][0][1][0][RTW89_UK][1][2] = 66, + [0][0][1][0][RTW89_UK][0][2] = 28, + [0][0][1][0][RTW89_FCC][1][4] = 22, + [0][0][1][0][RTW89_FCC][2][4] = 56, + [0][0][1][0][RTW89_ETSI][1][4] = 66, + [0][0][1][0][RTW89_ETSI][0][4] = 28, + [0][0][1][0][RTW89_MKK][1][4] = 66, + [0][0][1][0][RTW89_MKK][0][4] = 26, + [0][0][1][0][RTW89_IC][1][4] = 22, + [0][0][1][0][RTW89_KCC][1][4] = 24, + [0][0][1][0][RTW89_KCC][0][4] = 24, + [0][0][1][0][RTW89_ACMA][1][4] = 66, + [0][0][1][0][RTW89_ACMA][0][4] = 28, + [0][0][1][0][RTW89_CHILE][1][4] = 22, + [0][0][1][0][RTW89_QATAR][1][4] = 66, + [0][0][1][0][RTW89_QATAR][0][4] = 28, + [0][0][1][0][RTW89_UK][1][4] = 66, + [0][0][1][0][RTW89_UK][0][4] = 28, + [0][0][1][0][RTW89_FCC][1][6] = 22, + [0][0][1][0][RTW89_FCC][2][6] = 56, + [0][0][1][0][RTW89_ETSI][1][6] = 66, + [0][0][1][0][RTW89_ETSI][0][6] = 28, + [0][0][1][0][RTW89_MKK][1][6] = 66, + [0][0][1][0][RTW89_MKK][0][6] = 26, + [0][0][1][0][RTW89_IC][1][6] = 22, + [0][0][1][0][RTW89_KCC][1][6] = 24, + [0][0][1][0][RTW89_KCC][0][6] = 24, + [0][0][1][0][RTW89_ACMA][1][6] = 66, + [0][0][1][0][RTW89_ACMA][0][6] = 28, + [0][0][1][0][RTW89_CHILE][1][6] = 22, + [0][0][1][0][RTW89_QATAR][1][6] = 66, + [0][0][1][0][RTW89_QATAR][0][6] = 28, + [0][0][1][0][RTW89_UK][1][6] = 66, + [0][0][1][0][RTW89_UK][0][6] = 28, + [0][0][1][0][RTW89_FCC][1][8] = 22, + [0][0][1][0][RTW89_FCC][2][8] = 56, + [0][0][1][0][RTW89_ETSI][1][8] = 66, + [0][0][1][0][RTW89_ETSI][0][8] = 28, + [0][0][1][0][RTW89_MKK][1][8] = 66, + [0][0][1][0][RTW89_MKK][0][8] = 26, + [0][0][1][0][RTW89_IC][1][8] = 22, + [0][0][1][0][RTW89_KCC][1][8] = 24, + [0][0][1][0][RTW89_KCC][0][8] = 24, + [0][0][1][0][RTW89_ACMA][1][8] = 66, + [0][0][1][0][RTW89_ACMA][0][8] = 28, + [0][0][1][0][RTW89_CHILE][1][8] = 22, + [0][0][1][0][RTW89_QATAR][1][8] = 66, + [0][0][1][0][RTW89_QATAR][0][8] = 28, + [0][0][1][0][RTW89_UK][1][8] = 66, + [0][0][1][0][RTW89_UK][0][8] = 28, + [0][0][1][0][RTW89_FCC][1][10] = 22, + [0][0][1][0][RTW89_FCC][2][10] = 56, + [0][0][1][0][RTW89_ETSI][1][10] = 66, + [0][0][1][0][RTW89_ETSI][0][10] = 28, + [0][0][1][0][RTW89_MKK][1][10] = 66, + [0][0][1][0][RTW89_MKK][0][10] = 26, + [0][0][1][0][RTW89_IC][1][10] = 22, + [0][0][1][0][RTW89_KCC][1][10] = 24, + [0][0][1][0][RTW89_KCC][0][10] = 24, + [0][0][1][0][RTW89_ACMA][1][10] = 66, + [0][0][1][0][RTW89_ACMA][0][10] = 28, + [0][0][1][0][RTW89_CHILE][1][10] = 22, + [0][0][1][0][RTW89_QATAR][1][10] = 66, + [0][0][1][0][RTW89_QATAR][0][10] = 28, + [0][0][1][0][RTW89_UK][1][10] = 66, + [0][0][1][0][RTW89_UK][0][10] = 28, + [0][0][1][0][RTW89_FCC][1][12] = 22, + [0][0][1][0][RTW89_FCC][2][12] = 56, + [0][0][1][0][RTW89_ETSI][1][12] = 66, + [0][0][1][0][RTW89_ETSI][0][12] = 28, + [0][0][1][0][RTW89_MKK][1][12] = 66, + [0][0][1][0][RTW89_MKK][0][12] = 26, + [0][0][1][0][RTW89_IC][1][12] = 22, + [0][0][1][0][RTW89_KCC][1][12] = 24, + [0][0][1][0][RTW89_KCC][0][12] = 24, + [0][0][1][0][RTW89_ACMA][1][12] = 66, + [0][0][1][0][RTW89_ACMA][0][12] = 28, + [0][0][1][0][RTW89_CHILE][1][12] = 22, + [0][0][1][0][RTW89_QATAR][1][12] = 66, + [0][0][1][0][RTW89_QATAR][0][12] = 28, + [0][0][1][0][RTW89_UK][1][12] = 66, + [0][0][1][0][RTW89_UK][0][12] = 28, + [0][0][1][0][RTW89_FCC][1][14] = 22, + [0][0][1][0][RTW89_FCC][2][14] = 56, + [0][0][1][0][RTW89_ETSI][1][14] = 66, + [0][0][1][0][RTW89_ETSI][0][14] = 28, + [0][0][1][0][RTW89_MKK][1][14] = 66, + [0][0][1][0][RTW89_MKK][0][14] = 26, + [0][0][1][0][RTW89_IC][1][14] = 22, + [0][0][1][0][RTW89_KCC][1][14] = 24, + [0][0][1][0][RTW89_KCC][0][14] = 24, + [0][0][1][0][RTW89_ACMA][1][14] = 66, + [0][0][1][0][RTW89_ACMA][0][14] = 28, + [0][0][1][0][RTW89_CHILE][1][14] = 22, + [0][0][1][0][RTW89_QATAR][1][14] = 66, + [0][0][1][0][RTW89_QATAR][0][14] = 28, + [0][0][1][0][RTW89_UK][1][14] = 66, + [0][0][1][0][RTW89_UK][0][14] = 28, + [0][0][1][0][RTW89_FCC][1][15] = 22, + [0][0][1][0][RTW89_FCC][2][15] = 56, + [0][0][1][0][RTW89_ETSI][1][15] = 66, + [0][0][1][0][RTW89_ETSI][0][15] = 28, + [0][0][1][0][RTW89_MKK][1][15] = 66, + [0][0][1][0][RTW89_MKK][0][15] = 26, + [0][0][1][0][RTW89_IC][1][15] = 22, + [0][0][1][0][RTW89_KCC][1][15] = 24, + [0][0][1][0][RTW89_KCC][0][15] = 24, + [0][0][1][0][RTW89_ACMA][1][15] = 66, + [0][0][1][0][RTW89_ACMA][0][15] = 28, + [0][0][1][0][RTW89_CHILE][1][15] = 22, + [0][0][1][0][RTW89_QATAR][1][15] = 66, + [0][0][1][0][RTW89_QATAR][0][15] = 28, + [0][0][1][0][RTW89_UK][1][15] = 66, + [0][0][1][0][RTW89_UK][0][15] = 28, + [0][0][1][0][RTW89_FCC][1][17] = 22, + [0][0][1][0][RTW89_FCC][2][17] = 56, + [0][0][1][0][RTW89_ETSI][1][17] = 66, + [0][0][1][0][RTW89_ETSI][0][17] = 28, + [0][0][1][0][RTW89_MKK][1][17] = 66, + [0][0][1][0][RTW89_MKK][0][17] = 26, + [0][0][1][0][RTW89_IC][1][17] = 22, + [0][0][1][0][RTW89_KCC][1][17] = 24, + [0][0][1][0][RTW89_KCC][0][17] = 24, + [0][0][1][0][RTW89_ACMA][1][17] = 66, + [0][0][1][0][RTW89_ACMA][0][17] = 28, + [0][0][1][0][RTW89_CHILE][1][17] = 22, + [0][0][1][0][RTW89_QATAR][1][17] = 66, + [0][0][1][0][RTW89_QATAR][0][17] = 28, + [0][0][1][0][RTW89_UK][1][17] = 66, + [0][0][1][0][RTW89_UK][0][17] = 28, + [0][0][1][0][RTW89_FCC][1][19] = 22, + [0][0][1][0][RTW89_FCC][2][19] = 56, + [0][0][1][0][RTW89_ETSI][1][19] = 66, + [0][0][1][0][RTW89_ETSI][0][19] = 28, + [0][0][1][0][RTW89_MKK][1][19] = 66, + [0][0][1][0][RTW89_MKK][0][19] = 26, + [0][0][1][0][RTW89_IC][1][19] = 22, + [0][0][1][0][RTW89_KCC][1][19] = 24, + [0][0][1][0][RTW89_KCC][0][19] = 24, + [0][0][1][0][RTW89_ACMA][1][19] = 66, + [0][0][1][0][RTW89_ACMA][0][19] = 28, + [0][0][1][0][RTW89_CHILE][1][19] = 22, + [0][0][1][0][RTW89_QATAR][1][19] = 66, + [0][0][1][0][RTW89_QATAR][0][19] = 28, + [0][0][1][0][RTW89_UK][1][19] = 66, + [0][0][1][0][RTW89_UK][0][19] = 28, + [0][0][1][0][RTW89_FCC][1][21] = 22, + [0][0][1][0][RTW89_FCC][2][21] = 56, + [0][0][1][0][RTW89_ETSI][1][21] = 66, + [0][0][1][0][RTW89_ETSI][0][21] = 28, + [0][0][1][0][RTW89_MKK][1][21] = 66, + [0][0][1][0][RTW89_MKK][0][21] = 26, + [0][0][1][0][RTW89_IC][1][21] = 22, + [0][0][1][0][RTW89_KCC][1][21] = 24, + [0][0][1][0][RTW89_KCC][0][21] = 24, + [0][0][1][0][RTW89_ACMA][1][21] = 66, + [0][0][1][0][RTW89_ACMA][0][21] = 28, + [0][0][1][0][RTW89_CHILE][1][21] = 22, + [0][0][1][0][RTW89_QATAR][1][21] = 66, + [0][0][1][0][RTW89_QATAR][0][21] = 28, + [0][0][1][0][RTW89_UK][1][21] = 66, + [0][0][1][0][RTW89_UK][0][21] = 28, + [0][0][1][0][RTW89_FCC][1][23] = 22, + [0][0][1][0][RTW89_FCC][2][23] = 70, + [0][0][1][0][RTW89_ETSI][1][23] = 66, + [0][0][1][0][RTW89_ETSI][0][23] = 28, + [0][0][1][0][RTW89_MKK][1][23] = 66, + [0][0][1][0][RTW89_MKK][0][23] = 26, + [0][0][1][0][RTW89_IC][1][23] = 22, + [0][0][1][0][RTW89_KCC][1][23] = 24, + [0][0][1][0][RTW89_KCC][0][23] = 26, + [0][0][1][0][RTW89_ACMA][1][23] = 66, + [0][0][1][0][RTW89_ACMA][0][23] = 28, + [0][0][1][0][RTW89_CHILE][1][23] = 22, + [0][0][1][0][RTW89_QATAR][1][23] = 66, + [0][0][1][0][RTW89_QATAR][0][23] = 28, + [0][0][1][0][RTW89_UK][1][23] = 66, + [0][0][1][0][RTW89_UK][0][23] = 28, + [0][0][1][0][RTW89_FCC][1][25] = 22, + [0][0][1][0][RTW89_FCC][2][25] = 70, + [0][0][1][0][RTW89_ETSI][1][25] = 66, + [0][0][1][0][RTW89_ETSI][0][25] = 28, + [0][0][1][0][RTW89_MKK][1][25] = 66, + [0][0][1][0][RTW89_MKK][0][25] = 26, + [0][0][1][0][RTW89_IC][1][25] = 22, + [0][0][1][0][RTW89_KCC][1][25] = 24, + [0][0][1][0][RTW89_KCC][0][25] = 26, + [0][0][1][0][RTW89_ACMA][1][25] = 66, + [0][0][1][0][RTW89_ACMA][0][25] = 28, + [0][0][1][0][RTW89_CHILE][1][25] = 22, + [0][0][1][0][RTW89_QATAR][1][25] = 66, + [0][0][1][0][RTW89_QATAR][0][25] = 28, + [0][0][1][0][RTW89_UK][1][25] = 66, + [0][0][1][0][RTW89_UK][0][25] = 28, + [0][0][1][0][RTW89_FCC][1][27] = 22, + [0][0][1][0][RTW89_FCC][2][27] = 70, + [0][0][1][0][RTW89_ETSI][1][27] = 66, + [0][0][1][0][RTW89_ETSI][0][27] = 28, + [0][0][1][0][RTW89_MKK][1][27] = 66, + [0][0][1][0][RTW89_MKK][0][27] = 26, + [0][0][1][0][RTW89_IC][1][27] = 22, + [0][0][1][0][RTW89_KCC][1][27] = 24, + [0][0][1][0][RTW89_KCC][0][27] = 26, + [0][0][1][0][RTW89_ACMA][1][27] = 66, + [0][0][1][0][RTW89_ACMA][0][27] = 28, + [0][0][1][0][RTW89_CHILE][1][27] = 22, + [0][0][1][0][RTW89_QATAR][1][27] = 66, + [0][0][1][0][RTW89_QATAR][0][27] = 28, + [0][0][1][0][RTW89_UK][1][27] = 66, + [0][0][1][0][RTW89_UK][0][27] = 28, + [0][0][1][0][RTW89_FCC][1][29] = 22, + [0][0][1][0][RTW89_FCC][2][29] = 70, + [0][0][1][0][RTW89_ETSI][1][29] = 66, + [0][0][1][0][RTW89_ETSI][0][29] = 28, + [0][0][1][0][RTW89_MKK][1][29] = 66, + [0][0][1][0][RTW89_MKK][0][29] = 26, + [0][0][1][0][RTW89_IC][1][29] = 22, + [0][0][1][0][RTW89_KCC][1][29] = 24, + [0][0][1][0][RTW89_KCC][0][29] = 26, + [0][0][1][0][RTW89_ACMA][1][29] = 66, + [0][0][1][0][RTW89_ACMA][0][29] = 28, + [0][0][1][0][RTW89_CHILE][1][29] = 22, + [0][0][1][0][RTW89_QATAR][1][29] = 66, + [0][0][1][0][RTW89_QATAR][0][29] = 28, + [0][0][1][0][RTW89_UK][1][29] = 66, + [0][0][1][0][RTW89_UK][0][29] = 28, + [0][0][1][0][RTW89_FCC][1][30] = 22, + [0][0][1][0][RTW89_FCC][2][30] = 70, + [0][0][1][0][RTW89_ETSI][1][30] = 66, + [0][0][1][0][RTW89_ETSI][0][30] = 28, + [0][0][1][0][RTW89_MKK][1][30] = 66, + [0][0][1][0][RTW89_MKK][0][30] = 26, + [0][0][1][0][RTW89_IC][1][30] = 22, + [0][0][1][0][RTW89_KCC][1][30] = 24, + [0][0][1][0][RTW89_KCC][0][30] = 26, + [0][0][1][0][RTW89_ACMA][1][30] = 66, + [0][0][1][0][RTW89_ACMA][0][30] = 28, + [0][0][1][0][RTW89_CHILE][1][30] = 22, + [0][0][1][0][RTW89_QATAR][1][30] = 66, + [0][0][1][0][RTW89_QATAR][0][30] = 28, + [0][0][1][0][RTW89_UK][1][30] = 66, + [0][0][1][0][RTW89_UK][0][30] = 28, + [0][0][1][0][RTW89_FCC][1][32] = 22, + [0][0][1][0][RTW89_FCC][2][32] = 70, + [0][0][1][0][RTW89_ETSI][1][32] = 66, + [0][0][1][0][RTW89_ETSI][0][32] = 28, + [0][0][1][0][RTW89_MKK][1][32] = 66, + [0][0][1][0][RTW89_MKK][0][32] = 26, + [0][0][1][0][RTW89_IC][1][32] = 22, + [0][0][1][0][RTW89_KCC][1][32] = 24, + [0][0][1][0][RTW89_KCC][0][32] = 26, + [0][0][1][0][RTW89_ACMA][1][32] = 66, + [0][0][1][0][RTW89_ACMA][0][32] = 28, + [0][0][1][0][RTW89_CHILE][1][32] = 22, + [0][0][1][0][RTW89_QATAR][1][32] = 66, + [0][0][1][0][RTW89_QATAR][0][32] = 28, + [0][0][1][0][RTW89_UK][1][32] = 66, + [0][0][1][0][RTW89_UK][0][32] = 28, + [0][0][1][0][RTW89_FCC][1][34] = 22, + [0][0][1][0][RTW89_FCC][2][34] = 70, + [0][0][1][0][RTW89_ETSI][1][34] = 66, + [0][0][1][0][RTW89_ETSI][0][34] = 28, + [0][0][1][0][RTW89_MKK][1][34] = 66, + [0][0][1][0][RTW89_MKK][0][34] = 26, + [0][0][1][0][RTW89_IC][1][34] = 22, + [0][0][1][0][RTW89_KCC][1][34] = 24, + [0][0][1][0][RTW89_KCC][0][34] = 26, + [0][0][1][0][RTW89_ACMA][1][34] = 66, + [0][0][1][0][RTW89_ACMA][0][34] = 28, + [0][0][1][0][RTW89_CHILE][1][34] = 22, + [0][0][1][0][RTW89_QATAR][1][34] = 66, + [0][0][1][0][RTW89_QATAR][0][34] = 28, + [0][0][1][0][RTW89_UK][1][34] = 66, + [0][0][1][0][RTW89_UK][0][34] = 28, + [0][0][1][0][RTW89_FCC][1][36] = 22, + [0][0][1][0][RTW89_FCC][2][36] = 70, + [0][0][1][0][RTW89_ETSI][1][36] = 66, + [0][0][1][0][RTW89_ETSI][0][36] = 28, + [0][0][1][0][RTW89_MKK][1][36] = 66, + [0][0][1][0][RTW89_MKK][0][36] = 26, + [0][0][1][0][RTW89_IC][1][36] = 22, + [0][0][1][0][RTW89_KCC][1][36] = 24, + [0][0][1][0][RTW89_KCC][0][36] = 26, + [0][0][1][0][RTW89_ACMA][1][36] = 66, + [0][0][1][0][RTW89_ACMA][0][36] = 28, + [0][0][1][0][RTW89_CHILE][1][36] = 22, + [0][0][1][0][RTW89_QATAR][1][36] = 66, + [0][0][1][0][RTW89_QATAR][0][36] = 28, + [0][0][1][0][RTW89_UK][1][36] = 66, + [0][0][1][0][RTW89_UK][0][36] = 28, + [0][0][1][0][RTW89_FCC][1][38] = 22, + [0][0][1][0][RTW89_FCC][2][38] = 70, + [0][0][1][0][RTW89_ETSI][1][38] = 66, + [0][0][1][0][RTW89_ETSI][0][38] = 28, + [0][0][1][0][RTW89_MKK][1][38] = 66, + [0][0][1][0][RTW89_MKK][0][38] = 26, + [0][0][1][0][RTW89_IC][1][38] = 22, + [0][0][1][0][RTW89_KCC][1][38] = 24, + [0][0][1][0][RTW89_KCC][0][38] = 26, + [0][0][1][0][RTW89_ACMA][1][38] = 66, + [0][0][1][0][RTW89_ACMA][0][38] = 28, + [0][0][1][0][RTW89_CHILE][1][38] = 22, + [0][0][1][0][RTW89_QATAR][1][38] = 66, + [0][0][1][0][RTW89_QATAR][0][38] = 28, + [0][0][1][0][RTW89_UK][1][38] = 66, + [0][0][1][0][RTW89_UK][0][38] = 28, + [0][0][1][0][RTW89_FCC][1][40] = 22, + [0][0][1][0][RTW89_FCC][2][40] = 70, + [0][0][1][0][RTW89_ETSI][1][40] = 66, + [0][0][1][0][RTW89_ETSI][0][40] = 28, + [0][0][1][0][RTW89_MKK][1][40] = 66, + [0][0][1][0][RTW89_MKK][0][40] = 26, + [0][0][1][0][RTW89_IC][1][40] = 22, + [0][0][1][0][RTW89_KCC][1][40] = 24, + [0][0][1][0][RTW89_KCC][0][40] = 26, + [0][0][1][0][RTW89_ACMA][1][40] = 66, + [0][0][1][0][RTW89_ACMA][0][40] = 28, + [0][0][1][0][RTW89_CHILE][1][40] = 22, + [0][0][1][0][RTW89_QATAR][1][40] = 66, + [0][0][1][0][RTW89_QATAR][0][40] = 28, + [0][0][1][0][RTW89_UK][1][40] = 66, + [0][0][1][0][RTW89_UK][0][40] = 28, + [0][0][1][0][RTW89_FCC][1][42] = 22, + [0][0][1][0][RTW89_FCC][2][42] = 70, + [0][0][1][0][RTW89_ETSI][1][42] = 66, + [0][0][1][0][RTW89_ETSI][0][42] = 28, + [0][0][1][0][RTW89_MKK][1][42] = 66, + [0][0][1][0][RTW89_MKK][0][42] = 26, + [0][0][1][0][RTW89_IC][1][42] = 22, + [0][0][1][0][RTW89_KCC][1][42] = 24, + [0][0][1][0][RTW89_KCC][0][42] = 26, + [0][0][1][0][RTW89_ACMA][1][42] = 66, + [0][0][1][0][RTW89_ACMA][0][42] = 28, + [0][0][1][0][RTW89_CHILE][1][42] = 22, + [0][0][1][0][RTW89_QATAR][1][42] = 66, + [0][0][1][0][RTW89_QATAR][0][42] = 28, + [0][0][1][0][RTW89_UK][1][42] = 66, + [0][0][1][0][RTW89_UK][0][42] = 28, + [0][0][1][0][RTW89_FCC][1][44] = 22, + [0][0][1][0][RTW89_FCC][2][44] = 70, + [0][0][1][0][RTW89_ETSI][1][44] = 66, + [0][0][1][0][RTW89_ETSI][0][44] = 30, + [0][0][1][0][RTW89_MKK][1][44] = 44, + [0][0][1][0][RTW89_MKK][0][44] = 28, + [0][0][1][0][RTW89_IC][1][44] = 22, + [0][0][1][0][RTW89_KCC][1][44] = 24, + [0][0][1][0][RTW89_KCC][0][44] = 26, + [0][0][1][0][RTW89_ACMA][1][44] = 66, + [0][0][1][0][RTW89_ACMA][0][44] = 30, + [0][0][1][0][RTW89_CHILE][1][44] = 22, + [0][0][1][0][RTW89_QATAR][1][44] = 66, + [0][0][1][0][RTW89_QATAR][0][44] = 30, + [0][0][1][0][RTW89_UK][1][44] = 66, + [0][0][1][0][RTW89_UK][0][44] = 30, + [0][0][1][0][RTW89_FCC][1][45] = 22, + [0][0][1][0][RTW89_FCC][2][45] = 127, + [0][0][1][0][RTW89_ETSI][1][45] = 127, + [0][0][1][0][RTW89_ETSI][0][45] = 127, + [0][0][1][0][RTW89_MKK][1][45] = 127, + [0][0][1][0][RTW89_MKK][0][45] = 127, + [0][0][1][0][RTW89_IC][1][45] = 22, + [0][0][1][0][RTW89_KCC][1][45] = 24, + [0][0][1][0][RTW89_KCC][0][45] = 127, + [0][0][1][0][RTW89_ACMA][1][45] = 127, + [0][0][1][0][RTW89_ACMA][0][45] = 127, + [0][0][1][0][RTW89_CHILE][1][45] = 22, + [0][0][1][0][RTW89_QATAR][1][45] = 127, + [0][0][1][0][RTW89_QATAR][0][45] = 127, + [0][0][1][0][RTW89_UK][1][45] = 127, + [0][0][1][0][RTW89_UK][0][45] = 127, + [0][0][1][0][RTW89_FCC][1][47] = 22, + [0][0][1][0][RTW89_FCC][2][47] = 127, + [0][0][1][0][RTW89_ETSI][1][47] = 127, + [0][0][1][0][RTW89_ETSI][0][47] = 127, + [0][0][1][0][RTW89_MKK][1][47] = 127, + [0][0][1][0][RTW89_MKK][0][47] = 127, + [0][0][1][0][RTW89_IC][1][47] = 22, + [0][0][1][0][RTW89_KCC][1][47] = 24, + [0][0][1][0][RTW89_KCC][0][47] = 127, + [0][0][1][0][RTW89_ACMA][1][47] = 127, + [0][0][1][0][RTW89_ACMA][0][47] = 127, + [0][0][1][0][RTW89_CHILE][1][47] = 22, + [0][0][1][0][RTW89_QATAR][1][47] = 127, + [0][0][1][0][RTW89_QATAR][0][47] = 127, + [0][0][1][0][RTW89_UK][1][47] = 127, + [0][0][1][0][RTW89_UK][0][47] = 127, + [0][0][1][0][RTW89_FCC][1][49] = 24, + [0][0][1][0][RTW89_FCC][2][49] = 127, + [0][0][1][0][RTW89_ETSI][1][49] = 127, + [0][0][1][0][RTW89_ETSI][0][49] = 127, + [0][0][1][0][RTW89_MKK][1][49] = 127, + [0][0][1][0][RTW89_MKK][0][49] = 127, + [0][0][1][0][RTW89_IC][1][49] = 24, + [0][0][1][0][RTW89_KCC][1][49] = 24, + [0][0][1][0][RTW89_KCC][0][49] = 127, + [0][0][1][0][RTW89_ACMA][1][49] = 127, + [0][0][1][0][RTW89_ACMA][0][49] = 127, + [0][0][1][0][RTW89_CHILE][1][49] = 24, + [0][0][1][0][RTW89_QATAR][1][49] = 127, + [0][0][1][0][RTW89_QATAR][0][49] = 127, + [0][0][1][0][RTW89_UK][1][49] = 127, + [0][0][1][0][RTW89_UK][0][49] = 127, + [0][0][1][0][RTW89_FCC][1][51] = 22, + [0][0][1][0][RTW89_FCC][2][51] = 127, + [0][0][1][0][RTW89_ETSI][1][51] = 127, + [0][0][1][0][RTW89_ETSI][0][51] = 127, + [0][0][1][0][RTW89_MKK][1][51] = 127, + [0][0][1][0][RTW89_MKK][0][51] = 127, + [0][0][1][0][RTW89_IC][1][51] = 22, + [0][0][1][0][RTW89_KCC][1][51] = 24, + [0][0][1][0][RTW89_KCC][0][51] = 127, + [0][0][1][0][RTW89_ACMA][1][51] = 127, + [0][0][1][0][RTW89_ACMA][0][51] = 127, + [0][0][1][0][RTW89_CHILE][1][51] = 22, + [0][0][1][0][RTW89_QATAR][1][51] = 127, + [0][0][1][0][RTW89_QATAR][0][51] = 127, + [0][0][1][0][RTW89_UK][1][51] = 127, + [0][0][1][0][RTW89_UK][0][51] = 127, + [0][0][1][0][RTW89_FCC][1][53] = 22, + [0][0][1][0][RTW89_FCC][2][53] = 127, + [0][0][1][0][RTW89_ETSI][1][53] = 127, + [0][0][1][0][RTW89_ETSI][0][53] = 127, + [0][0][1][0][RTW89_MKK][1][53] = 127, + [0][0][1][0][RTW89_MKK][0][53] = 127, + [0][0][1][0][RTW89_IC][1][53] = 22, + [0][0][1][0][RTW89_KCC][1][53] = 24, + [0][0][1][0][RTW89_KCC][0][53] = 127, + [0][0][1][0][RTW89_ACMA][1][53] = 127, + [0][0][1][0][RTW89_ACMA][0][53] = 127, + [0][0][1][0][RTW89_CHILE][1][53] = 22, + [0][0][1][0][RTW89_QATAR][1][53] = 127, + [0][0][1][0][RTW89_QATAR][0][53] = 127, + [0][0][1][0][RTW89_UK][1][53] = 127, + [0][0][1][0][RTW89_UK][0][53] = 127, + [0][0][1][0][RTW89_FCC][1][55] = 22, + [0][0][1][0][RTW89_FCC][2][55] = 68, + [0][0][1][0][RTW89_ETSI][1][55] = 127, + [0][0][1][0][RTW89_ETSI][0][55] = 127, + [0][0][1][0][RTW89_MKK][1][55] = 127, + [0][0][1][0][RTW89_MKK][0][55] = 127, + [0][0][1][0][RTW89_IC][1][55] = 22, + [0][0][1][0][RTW89_KCC][1][55] = 26, + [0][0][1][0][RTW89_KCC][0][55] = 127, + [0][0][1][0][RTW89_ACMA][1][55] = 127, + [0][0][1][0][RTW89_ACMA][0][55] = 127, + [0][0][1][0][RTW89_CHILE][1][55] = 22, + [0][0][1][0][RTW89_QATAR][1][55] = 127, + [0][0][1][0][RTW89_QATAR][0][55] = 127, + [0][0][1][0][RTW89_UK][1][55] = 127, + [0][0][1][0][RTW89_UK][0][55] = 127, + [0][0][1][0][RTW89_FCC][1][57] = 22, + [0][0][1][0][RTW89_FCC][2][57] = 68, + [0][0][1][0][RTW89_ETSI][1][57] = 127, + [0][0][1][0][RTW89_ETSI][0][57] = 127, + [0][0][1][0][RTW89_MKK][1][57] = 127, + [0][0][1][0][RTW89_MKK][0][57] = 127, + [0][0][1][0][RTW89_IC][1][57] = 22, + [0][0][1][0][RTW89_KCC][1][57] = 26, + [0][0][1][0][RTW89_KCC][0][57] = 127, + [0][0][1][0][RTW89_ACMA][1][57] = 127, + [0][0][1][0][RTW89_ACMA][0][57] = 127, + [0][0][1][0][RTW89_CHILE][1][57] = 22, + [0][0][1][0][RTW89_QATAR][1][57] = 127, + [0][0][1][0][RTW89_QATAR][0][57] = 127, + [0][0][1][0][RTW89_UK][1][57] = 127, + [0][0][1][0][RTW89_UK][0][57] = 127, + [0][0][1][0][RTW89_FCC][1][59] = 22, + [0][0][1][0][RTW89_FCC][2][59] = 68, + [0][0][1][0][RTW89_ETSI][1][59] = 127, + [0][0][1][0][RTW89_ETSI][0][59] = 127, + [0][0][1][0][RTW89_MKK][1][59] = 127, + [0][0][1][0][RTW89_MKK][0][59] = 127, + [0][0][1][0][RTW89_IC][1][59] = 22, + [0][0][1][0][RTW89_KCC][1][59] = 26, + [0][0][1][0][RTW89_KCC][0][59] = 127, + [0][0][1][0][RTW89_ACMA][1][59] = 127, + [0][0][1][0][RTW89_ACMA][0][59] = 127, + [0][0][1][0][RTW89_CHILE][1][59] = 22, + [0][0][1][0][RTW89_QATAR][1][59] = 127, + [0][0][1][0][RTW89_QATAR][0][59] = 127, + [0][0][1][0][RTW89_UK][1][59] = 127, + [0][0][1][0][RTW89_UK][0][59] = 127, + [0][0][1][0][RTW89_FCC][1][60] = 22, + [0][0][1][0][RTW89_FCC][2][60] = 68, + [0][0][1][0][RTW89_ETSI][1][60] = 127, + [0][0][1][0][RTW89_ETSI][0][60] = 127, + [0][0][1][0][RTW89_MKK][1][60] = 127, + [0][0][1][0][RTW89_MKK][0][60] = 127, + [0][0][1][0][RTW89_IC][1][60] = 22, + [0][0][1][0][RTW89_KCC][1][60] = 26, + [0][0][1][0][RTW89_KCC][0][60] = 127, + [0][0][1][0][RTW89_ACMA][1][60] = 127, + [0][0][1][0][RTW89_ACMA][0][60] = 127, + [0][0][1][0][RTW89_CHILE][1][60] = 22, + [0][0][1][0][RTW89_QATAR][1][60] = 127, + [0][0][1][0][RTW89_QATAR][0][60] = 127, + [0][0][1][0][RTW89_UK][1][60] = 127, + [0][0][1][0][RTW89_UK][0][60] = 127, + [0][0][1][0][RTW89_FCC][1][62] = 22, + [0][0][1][0][RTW89_FCC][2][62] = 68, + [0][0][1][0][RTW89_ETSI][1][62] = 127, + [0][0][1][0][RTW89_ETSI][0][62] = 127, + [0][0][1][0][RTW89_MKK][1][62] = 127, + [0][0][1][0][RTW89_MKK][0][62] = 127, + [0][0][1][0][RTW89_IC][1][62] = 22, + [0][0][1][0][RTW89_KCC][1][62] = 26, + [0][0][1][0][RTW89_KCC][0][62] = 127, + [0][0][1][0][RTW89_ACMA][1][62] = 127, + [0][0][1][0][RTW89_ACMA][0][62] = 127, + [0][0][1][0][RTW89_CHILE][1][62] = 22, + [0][0][1][0][RTW89_QATAR][1][62] = 127, + [0][0][1][0][RTW89_QATAR][0][62] = 127, + [0][0][1][0][RTW89_UK][1][62] = 127, + [0][0][1][0][RTW89_UK][0][62] = 127, + [0][0][1][0][RTW89_FCC][1][64] = 22, + [0][0][1][0][RTW89_FCC][2][64] = 68, + [0][0][1][0][RTW89_ETSI][1][64] = 127, + [0][0][1][0][RTW89_ETSI][0][64] = 127, + [0][0][1][0][RTW89_MKK][1][64] = 127, + [0][0][1][0][RTW89_MKK][0][64] = 127, + [0][0][1][0][RTW89_IC][1][64] = 22, + [0][0][1][0][RTW89_KCC][1][64] = 26, + [0][0][1][0][RTW89_KCC][0][64] = 127, + [0][0][1][0][RTW89_ACMA][1][64] = 127, + [0][0][1][0][RTW89_ACMA][0][64] = 127, + [0][0][1][0][RTW89_CHILE][1][64] = 22, + [0][0][1][0][RTW89_QATAR][1][64] = 127, + [0][0][1][0][RTW89_QATAR][0][64] = 127, + [0][0][1][0][RTW89_UK][1][64] = 127, + [0][0][1][0][RTW89_UK][0][64] = 127, + [0][0][1][0][RTW89_FCC][1][66] = 22, + [0][0][1][0][RTW89_FCC][2][66] = 68, + [0][0][1][0][RTW89_ETSI][1][66] = 127, + [0][0][1][0][RTW89_ETSI][0][66] = 127, + [0][0][1][0][RTW89_MKK][1][66] = 127, + [0][0][1][0][RTW89_MKK][0][66] = 127, + [0][0][1][0][RTW89_IC][1][66] = 22, + [0][0][1][0][RTW89_KCC][1][66] = 26, + [0][0][1][0][RTW89_KCC][0][66] = 127, + [0][0][1][0][RTW89_ACMA][1][66] = 127, + [0][0][1][0][RTW89_ACMA][0][66] = 127, + [0][0][1][0][RTW89_CHILE][1][66] = 22, + [0][0][1][0][RTW89_QATAR][1][66] = 127, + [0][0][1][0][RTW89_QATAR][0][66] = 127, + [0][0][1][0][RTW89_UK][1][66] = 127, + [0][0][1][0][RTW89_UK][0][66] = 127, + [0][0][1][0][RTW89_FCC][1][68] = 22, + [0][0][1][0][RTW89_FCC][2][68] = 68, + [0][0][1][0][RTW89_ETSI][1][68] = 127, + [0][0][1][0][RTW89_ETSI][0][68] = 127, + [0][0][1][0][RTW89_MKK][1][68] = 127, + [0][0][1][0][RTW89_MKK][0][68] = 127, + [0][0][1][0][RTW89_IC][1][68] = 22, + [0][0][1][0][RTW89_KCC][1][68] = 26, + [0][0][1][0][RTW89_KCC][0][68] = 127, + [0][0][1][0][RTW89_ACMA][1][68] = 127, + [0][0][1][0][RTW89_ACMA][0][68] = 127, + [0][0][1][0][RTW89_CHILE][1][68] = 22, + [0][0][1][0][RTW89_QATAR][1][68] = 127, + [0][0][1][0][RTW89_QATAR][0][68] = 127, + [0][0][1][0][RTW89_UK][1][68] = 127, + [0][0][1][0][RTW89_UK][0][68] = 127, + [0][0][1][0][RTW89_FCC][1][70] = 24, + [0][0][1][0][RTW89_FCC][2][70] = 68, + [0][0][1][0][RTW89_ETSI][1][70] = 127, + [0][0][1][0][RTW89_ETSI][0][70] = 127, + [0][0][1][0][RTW89_MKK][1][70] = 127, + [0][0][1][0][RTW89_MKK][0][70] = 127, + [0][0][1][0][RTW89_IC][1][70] = 24, + [0][0][1][0][RTW89_KCC][1][70] = 26, + [0][0][1][0][RTW89_KCC][0][70] = 127, + [0][0][1][0][RTW89_ACMA][1][70] = 127, + [0][0][1][0][RTW89_ACMA][0][70] = 127, + [0][0][1][0][RTW89_CHILE][1][70] = 24, + [0][0][1][0][RTW89_QATAR][1][70] = 127, + [0][0][1][0][RTW89_QATAR][0][70] = 127, + [0][0][1][0][RTW89_UK][1][70] = 127, + [0][0][1][0][RTW89_UK][0][70] = 127, + [0][0][1][0][RTW89_FCC][1][72] = 22, + [0][0][1][0][RTW89_FCC][2][72] = 68, + [0][0][1][0][RTW89_ETSI][1][72] = 127, + [0][0][1][0][RTW89_ETSI][0][72] = 127, + [0][0][1][0][RTW89_MKK][1][72] = 127, + [0][0][1][0][RTW89_MKK][0][72] = 127, + [0][0][1][0][RTW89_IC][1][72] = 22, + [0][0][1][0][RTW89_KCC][1][72] = 26, + [0][0][1][0][RTW89_KCC][0][72] = 127, + [0][0][1][0][RTW89_ACMA][1][72] = 127, + [0][0][1][0][RTW89_ACMA][0][72] = 127, + [0][0][1][0][RTW89_CHILE][1][72] = 22, + [0][0][1][0][RTW89_QATAR][1][72] = 127, + [0][0][1][0][RTW89_QATAR][0][72] = 127, + [0][0][1][0][RTW89_UK][1][72] = 127, + [0][0][1][0][RTW89_UK][0][72] = 127, + [0][0][1][0][RTW89_FCC][1][74] = 22, + [0][0][1][0][RTW89_FCC][2][74] = 68, + [0][0][1][0][RTW89_ETSI][1][74] = 127, + [0][0][1][0][RTW89_ETSI][0][74] = 127, + [0][0][1][0][RTW89_MKK][1][74] = 127, + [0][0][1][0][RTW89_MKK][0][74] = 127, + [0][0][1][0][RTW89_IC][1][74] = 22, + [0][0][1][0][RTW89_KCC][1][74] = 26, + [0][0][1][0][RTW89_KCC][0][74] = 127, + [0][0][1][0][RTW89_ACMA][1][74] = 127, + [0][0][1][0][RTW89_ACMA][0][74] = 127, + [0][0][1][0][RTW89_CHILE][1][74] = 22, + [0][0][1][0][RTW89_QATAR][1][74] = 127, + [0][0][1][0][RTW89_QATAR][0][74] = 127, + [0][0][1][0][RTW89_UK][1][74] = 127, + [0][0][1][0][RTW89_UK][0][74] = 127, + [0][0][1][0][RTW89_FCC][1][75] = 22, + [0][0][1][0][RTW89_FCC][2][75] = 68, + [0][0][1][0][RTW89_ETSI][1][75] = 127, + [0][0][1][0][RTW89_ETSI][0][75] = 127, + [0][0][1][0][RTW89_MKK][1][75] = 127, + [0][0][1][0][RTW89_MKK][0][75] = 127, + [0][0][1][0][RTW89_IC][1][75] = 22, + [0][0][1][0][RTW89_KCC][1][75] = 26, + [0][0][1][0][RTW89_KCC][0][75] = 127, + [0][0][1][0][RTW89_ACMA][1][75] = 127, + [0][0][1][0][RTW89_ACMA][0][75] = 127, + [0][0][1][0][RTW89_CHILE][1][75] = 22, + [0][0][1][0][RTW89_QATAR][1][75] = 127, + [0][0][1][0][RTW89_QATAR][0][75] = 127, + [0][0][1][0][RTW89_UK][1][75] = 127, + [0][0][1][0][RTW89_UK][0][75] = 127, + [0][0][1][0][RTW89_FCC][1][77] = 22, + [0][0][1][0][RTW89_FCC][2][77] = 68, + [0][0][1][0][RTW89_ETSI][1][77] = 127, + [0][0][1][0][RTW89_ETSI][0][77] = 127, + [0][0][1][0][RTW89_MKK][1][77] = 127, + [0][0][1][0][RTW89_MKK][0][77] = 127, + [0][0][1][0][RTW89_IC][1][77] = 22, + [0][0][1][0][RTW89_KCC][1][77] = 26, + [0][0][1][0][RTW89_KCC][0][77] = 127, + [0][0][1][0][RTW89_ACMA][1][77] = 127, + [0][0][1][0][RTW89_ACMA][0][77] = 127, + [0][0][1][0][RTW89_CHILE][1][77] = 22, + [0][0][1][0][RTW89_QATAR][1][77] = 127, + [0][0][1][0][RTW89_QATAR][0][77] = 127, + [0][0][1][0][RTW89_UK][1][77] = 127, + [0][0][1][0][RTW89_UK][0][77] = 127, + [0][0][1][0][RTW89_FCC][1][79] = 22, + [0][0][1][0][RTW89_FCC][2][79] = 68, + [0][0][1][0][RTW89_ETSI][1][79] = 127, + [0][0][1][0][RTW89_ETSI][0][79] = 127, + [0][0][1][0][RTW89_MKK][1][79] = 127, + [0][0][1][0][RTW89_MKK][0][79] = 127, + [0][0][1][0][RTW89_IC][1][79] = 22, + [0][0][1][0][RTW89_KCC][1][79] = 26, + [0][0][1][0][RTW89_KCC][0][79] = 127, + [0][0][1][0][RTW89_ACMA][1][79] = 127, + [0][0][1][0][RTW89_ACMA][0][79] = 127, + [0][0][1][0][RTW89_CHILE][1][79] = 22, + [0][0][1][0][RTW89_QATAR][1][79] = 127, + [0][0][1][0][RTW89_QATAR][0][79] = 127, + [0][0][1][0][RTW89_UK][1][79] = 127, + [0][0][1][0][RTW89_UK][0][79] = 127, + [0][0][1][0][RTW89_FCC][1][81] = 22, + [0][0][1][0][RTW89_FCC][2][81] = 68, + [0][0][1][0][RTW89_ETSI][1][81] = 127, + [0][0][1][0][RTW89_ETSI][0][81] = 127, + [0][0][1][0][RTW89_MKK][1][81] = 127, + [0][0][1][0][RTW89_MKK][0][81] = 127, + [0][0][1][0][RTW89_IC][1][81] = 22, + [0][0][1][0][RTW89_KCC][1][81] = 26, + [0][0][1][0][RTW89_KCC][0][81] = 127, + [0][0][1][0][RTW89_ACMA][1][81] = 127, + [0][0][1][0][RTW89_ACMA][0][81] = 127, + [0][0][1][0][RTW89_CHILE][1][81] = 22, + [0][0][1][0][RTW89_QATAR][1][81] = 127, + [0][0][1][0][RTW89_QATAR][0][81] = 127, + [0][0][1][0][RTW89_UK][1][81] = 127, + [0][0][1][0][RTW89_UK][0][81] = 127, + [0][0][1][0][RTW89_FCC][1][83] = 22, + [0][0][1][0][RTW89_FCC][2][83] = 68, + [0][0][1][0][RTW89_ETSI][1][83] = 127, + [0][0][1][0][RTW89_ETSI][0][83] = 127, + [0][0][1][0][RTW89_MKK][1][83] = 127, + [0][0][1][0][RTW89_MKK][0][83] = 127, + [0][0][1][0][RTW89_IC][1][83] = 22, + [0][0][1][0][RTW89_KCC][1][83] = 32, + [0][0][1][0][RTW89_KCC][0][83] = 127, + [0][0][1][0][RTW89_ACMA][1][83] = 127, + [0][0][1][0][RTW89_ACMA][0][83] = 127, + [0][0][1][0][RTW89_CHILE][1][83] = 22, + [0][0][1][0][RTW89_QATAR][1][83] = 127, + [0][0][1][0][RTW89_QATAR][0][83] = 127, + [0][0][1][0][RTW89_UK][1][83] = 127, + [0][0][1][0][RTW89_UK][0][83] = 127, + [0][0][1][0][RTW89_FCC][1][85] = 22, + [0][0][1][0][RTW89_FCC][2][85] = 68, + [0][0][1][0][RTW89_ETSI][1][85] = 127, + [0][0][1][0][RTW89_ETSI][0][85] = 127, + [0][0][1][0][RTW89_MKK][1][85] = 127, + [0][0][1][0][RTW89_MKK][0][85] = 127, + [0][0][1][0][RTW89_IC][1][85] = 22, + [0][0][1][0][RTW89_KCC][1][85] = 32, + [0][0][1][0][RTW89_KCC][0][85] = 127, + [0][0][1][0][RTW89_ACMA][1][85] = 127, + [0][0][1][0][RTW89_ACMA][0][85] = 127, + [0][0][1][0][RTW89_CHILE][1][85] = 22, + [0][0][1][0][RTW89_QATAR][1][85] = 127, + [0][0][1][0][RTW89_QATAR][0][85] = 127, + [0][0][1][0][RTW89_UK][1][85] = 127, + [0][0][1][0][RTW89_UK][0][85] = 127, + [0][0][1][0][RTW89_FCC][1][87] = 22, + [0][0][1][0][RTW89_FCC][2][87] = 127, + [0][0][1][0][RTW89_ETSI][1][87] = 127, + [0][0][1][0][RTW89_ETSI][0][87] = 127, + [0][0][1][0][RTW89_MKK][1][87] = 127, + [0][0][1][0][RTW89_MKK][0][87] = 127, + [0][0][1][0][RTW89_IC][1][87] = 22, + [0][0][1][0][RTW89_KCC][1][87] = 32, + [0][0][1][0][RTW89_KCC][0][87] = 127, + [0][0][1][0][RTW89_ACMA][1][87] = 127, + [0][0][1][0][RTW89_ACMA][0][87] = 127, + [0][0][1][0][RTW89_CHILE][1][87] = 22, + [0][0][1][0][RTW89_QATAR][1][87] = 127, + [0][0][1][0][RTW89_QATAR][0][87] = 127, + [0][0][1][0][RTW89_UK][1][87] = 127, + [0][0][1][0][RTW89_UK][0][87] = 127, + [0][0][1][0][RTW89_FCC][1][89] = 22, + [0][0][1][0][RTW89_FCC][2][89] = 127, + [0][0][1][0][RTW89_ETSI][1][89] = 127, + [0][0][1][0][RTW89_ETSI][0][89] = 127, + [0][0][1][0][RTW89_MKK][1][89] = 127, + [0][0][1][0][RTW89_MKK][0][89] = 127, + [0][0][1][0][RTW89_IC][1][89] = 22, + [0][0][1][0][RTW89_KCC][1][89] = 32, + [0][0][1][0][RTW89_KCC][0][89] = 127, + [0][0][1][0][RTW89_ACMA][1][89] = 127, + [0][0][1][0][RTW89_ACMA][0][89] = 127, + [0][0][1][0][RTW89_CHILE][1][89] = 22, + [0][0][1][0][RTW89_QATAR][1][89] = 127, + [0][0][1][0][RTW89_QATAR][0][89] = 127, + [0][0][1][0][RTW89_UK][1][89] = 127, + [0][0][1][0][RTW89_UK][0][89] = 127, + [0][0][1][0][RTW89_FCC][1][90] = 22, + [0][0][1][0][RTW89_FCC][2][90] = 127, + [0][0][1][0][RTW89_ETSI][1][90] = 127, + [0][0][1][0][RTW89_ETSI][0][90] = 127, + [0][0][1][0][RTW89_MKK][1][90] = 127, + [0][0][1][0][RTW89_MKK][0][90] = 127, + [0][0][1][0][RTW89_IC][1][90] = 22, + [0][0][1][0][RTW89_KCC][1][90] = 32, + [0][0][1][0][RTW89_KCC][0][90] = 127, + [0][0][1][0][RTW89_ACMA][1][90] = 127, + [0][0][1][0][RTW89_ACMA][0][90] = 127, + [0][0][1][0][RTW89_CHILE][1][90] = 22, + [0][0][1][0][RTW89_QATAR][1][90] = 127, + [0][0][1][0][RTW89_QATAR][0][90] = 127, + [0][0][1][0][RTW89_UK][1][90] = 127, + [0][0][1][0][RTW89_UK][0][90] = 127, + [0][0][1][0][RTW89_FCC][1][92] = 22, + [0][0][1][0][RTW89_FCC][2][92] = 127, + [0][0][1][0][RTW89_ETSI][1][92] = 127, + [0][0][1][0][RTW89_ETSI][0][92] = 127, + [0][0][1][0][RTW89_MKK][1][92] = 127, + [0][0][1][0][RTW89_MKK][0][92] = 127, + [0][0][1][0][RTW89_IC][1][92] = 22, + [0][0][1][0][RTW89_KCC][1][92] = 32, + [0][0][1][0][RTW89_KCC][0][92] = 127, + [0][0][1][0][RTW89_ACMA][1][92] = 127, + [0][0][1][0][RTW89_ACMA][0][92] = 127, + [0][0][1][0][RTW89_CHILE][1][92] = 22, + [0][0][1][0][RTW89_QATAR][1][92] = 127, + [0][0][1][0][RTW89_QATAR][0][92] = 127, + [0][0][1][0][RTW89_UK][1][92] = 127, + [0][0][1][0][RTW89_UK][0][92] = 127, + [0][0][1][0][RTW89_FCC][1][94] = 22, + [0][0][1][0][RTW89_FCC][2][94] = 127, + [0][0][1][0][RTW89_ETSI][1][94] = 127, + [0][0][1][0][RTW89_ETSI][0][94] = 127, + [0][0][1][0][RTW89_MKK][1][94] = 127, + [0][0][1][0][RTW89_MKK][0][94] = 127, + [0][0][1][0][RTW89_IC][1][94] = 22, + [0][0][1][0][RTW89_KCC][1][94] = 32, + [0][0][1][0][RTW89_KCC][0][94] = 127, + [0][0][1][0][RTW89_ACMA][1][94] = 127, + [0][0][1][0][RTW89_ACMA][0][94] = 127, + [0][0][1][0][RTW89_CHILE][1][94] = 22, + [0][0][1][0][RTW89_QATAR][1][94] = 127, + [0][0][1][0][RTW89_QATAR][0][94] = 127, + [0][0][1][0][RTW89_UK][1][94] = 127, + [0][0][1][0][RTW89_UK][0][94] = 127, + [0][0][1][0][RTW89_FCC][1][96] = 22, + [0][0][1][0][RTW89_FCC][2][96] = 127, + [0][0][1][0][RTW89_ETSI][1][96] = 127, + [0][0][1][0][RTW89_ETSI][0][96] = 127, + [0][0][1][0][RTW89_MKK][1][96] = 127, + [0][0][1][0][RTW89_MKK][0][96] = 127, + [0][0][1][0][RTW89_IC][1][96] = 22, + [0][0][1][0][RTW89_KCC][1][96] = 32, + [0][0][1][0][RTW89_KCC][0][96] = 127, + [0][0][1][0][RTW89_ACMA][1][96] = 127, + [0][0][1][0][RTW89_ACMA][0][96] = 127, + [0][0][1][0][RTW89_CHILE][1][96] = 22, + [0][0][1][0][RTW89_QATAR][1][96] = 127, + [0][0][1][0][RTW89_QATAR][0][96] = 127, + [0][0][1][0][RTW89_UK][1][96] = 127, + [0][0][1][0][RTW89_UK][0][96] = 127, + [0][0][1][0][RTW89_FCC][1][98] = 22, + [0][0][1][0][RTW89_FCC][2][98] = 127, + [0][0][1][0][RTW89_ETSI][1][98] = 127, + [0][0][1][0][RTW89_ETSI][0][98] = 127, + [0][0][1][0][RTW89_MKK][1][98] = 127, + [0][0][1][0][RTW89_MKK][0][98] = 127, + [0][0][1][0][RTW89_IC][1][98] = 22, + [0][0][1][0][RTW89_KCC][1][98] = 32, + [0][0][1][0][RTW89_KCC][0][98] = 127, + [0][0][1][0][RTW89_ACMA][1][98] = 127, + [0][0][1][0][RTW89_ACMA][0][98] = 127, + [0][0][1][0][RTW89_CHILE][1][98] = 22, + [0][0][1][0][RTW89_QATAR][1][98] = 127, + [0][0][1][0][RTW89_QATAR][0][98] = 127, + [0][0][1][0][RTW89_UK][1][98] = 127, + [0][0][1][0][RTW89_UK][0][98] = 127, + [0][0][1][0][RTW89_FCC][1][100] = 22, + [0][0][1][0][RTW89_FCC][2][100] = 127, + [0][0][1][0][RTW89_ETSI][1][100] = 127, + [0][0][1][0][RTW89_ETSI][0][100] = 127, + [0][0][1][0][RTW89_MKK][1][100] = 127, + [0][0][1][0][RTW89_MKK][0][100] = 127, + [0][0][1][0][RTW89_IC][1][100] = 22, + [0][0][1][0][RTW89_KCC][1][100] = 32, + [0][0][1][0][RTW89_KCC][0][100] = 127, + [0][0][1][0][RTW89_ACMA][1][100] = 127, + [0][0][1][0][RTW89_ACMA][0][100] = 127, + [0][0][1][0][RTW89_CHILE][1][100] = 22, + [0][0][1][0][RTW89_QATAR][1][100] = 127, + [0][0][1][0][RTW89_QATAR][0][100] = 127, + [0][0][1][0][RTW89_UK][1][100] = 127, + [0][0][1][0][RTW89_UK][0][100] = 127, + [0][0][1][0][RTW89_FCC][1][102] = 22, + [0][0][1][0][RTW89_FCC][2][102] = 127, + [0][0][1][0][RTW89_ETSI][1][102] = 127, + [0][0][1][0][RTW89_ETSI][0][102] = 127, + [0][0][1][0][RTW89_MKK][1][102] = 127, + [0][0][1][0][RTW89_MKK][0][102] = 127, + [0][0][1][0][RTW89_IC][1][102] = 22, + [0][0][1][0][RTW89_KCC][1][102] = 32, + [0][0][1][0][RTW89_KCC][0][102] = 127, + [0][0][1][0][RTW89_ACMA][1][102] = 127, + [0][0][1][0][RTW89_ACMA][0][102] = 127, + [0][0][1][0][RTW89_CHILE][1][102] = 22, + [0][0][1][0][RTW89_QATAR][1][102] = 127, + [0][0][1][0][RTW89_QATAR][0][102] = 127, + [0][0][1][0][RTW89_UK][1][102] = 127, + [0][0][1][0][RTW89_UK][0][102] = 127, + [0][0][1][0][RTW89_FCC][1][104] = 22, + [0][0][1][0][RTW89_FCC][2][104] = 127, + [0][0][1][0][RTW89_ETSI][1][104] = 127, + [0][0][1][0][RTW89_ETSI][0][104] = 127, + [0][0][1][0][RTW89_MKK][1][104] = 127, + [0][0][1][0][RTW89_MKK][0][104] = 127, + [0][0][1][0][RTW89_IC][1][104] = 22, + [0][0][1][0][RTW89_KCC][1][104] = 32, + [0][0][1][0][RTW89_KCC][0][104] = 127, + [0][0][1][0][RTW89_ACMA][1][104] = 127, + [0][0][1][0][RTW89_ACMA][0][104] = 127, + [0][0][1][0][RTW89_CHILE][1][104] = 22, + [0][0][1][0][RTW89_QATAR][1][104] = 127, + [0][0][1][0][RTW89_QATAR][0][104] = 127, + [0][0][1][0][RTW89_UK][1][104] = 127, + [0][0][1][0][RTW89_UK][0][104] = 127, + [0][0][1][0][RTW89_FCC][1][105] = 22, + [0][0][1][0][RTW89_FCC][2][105] = 127, + [0][0][1][0][RTW89_ETSI][1][105] = 127, + [0][0][1][0][RTW89_ETSI][0][105] = 127, + [0][0][1][0][RTW89_MKK][1][105] = 127, + [0][0][1][0][RTW89_MKK][0][105] = 127, + [0][0][1][0][RTW89_IC][1][105] = 22, + [0][0][1][0][RTW89_KCC][1][105] = 32, + [0][0][1][0][RTW89_KCC][0][105] = 127, + [0][0][1][0][RTW89_ACMA][1][105] = 127, + [0][0][1][0][RTW89_ACMA][0][105] = 127, + [0][0][1][0][RTW89_CHILE][1][105] = 22, + [0][0][1][0][RTW89_QATAR][1][105] = 127, + [0][0][1][0][RTW89_QATAR][0][105] = 127, + [0][0][1][0][RTW89_UK][1][105] = 127, + [0][0][1][0][RTW89_UK][0][105] = 127, + [0][0][1][0][RTW89_FCC][1][107] = 24, + [0][0][1][0][RTW89_FCC][2][107] = 127, + [0][0][1][0][RTW89_ETSI][1][107] = 127, + [0][0][1][0][RTW89_ETSI][0][107] = 127, + [0][0][1][0][RTW89_MKK][1][107] = 127, + [0][0][1][0][RTW89_MKK][0][107] = 127, + [0][0][1][0][RTW89_IC][1][107] = 24, + [0][0][1][0][RTW89_KCC][1][107] = 32, + [0][0][1][0][RTW89_KCC][0][107] = 127, + [0][0][1][0][RTW89_ACMA][1][107] = 127, + [0][0][1][0][RTW89_ACMA][0][107] = 127, + [0][0][1][0][RTW89_CHILE][1][107] = 24, + [0][0][1][0][RTW89_QATAR][1][107] = 127, + [0][0][1][0][RTW89_QATAR][0][107] = 127, + [0][0][1][0][RTW89_UK][1][107] = 127, + [0][0][1][0][RTW89_UK][0][107] = 127, + [0][0][1][0][RTW89_FCC][1][109] = 24, + [0][0][1][0][RTW89_FCC][2][109] = 127, + [0][0][1][0][RTW89_ETSI][1][109] = 127, + [0][0][1][0][RTW89_ETSI][0][109] = 127, + [0][0][1][0][RTW89_MKK][1][109] = 127, + [0][0][1][0][RTW89_MKK][0][109] = 127, + [0][0][1][0][RTW89_IC][1][109] = 24, + [0][0][1][0][RTW89_KCC][1][109] = 32, + [0][0][1][0][RTW89_KCC][0][109] = 127, + [0][0][1][0][RTW89_ACMA][1][109] = 127, + [0][0][1][0][RTW89_ACMA][0][109] = 127, + [0][0][1][0][RTW89_CHILE][1][109] = 24, + [0][0][1][0][RTW89_QATAR][1][109] = 127, + [0][0][1][0][RTW89_QATAR][0][109] = 127, + [0][0][1][0][RTW89_UK][1][109] = 127, + [0][0][1][0][RTW89_UK][0][109] = 127, + [0][0][1][0][RTW89_FCC][1][111] = 127, + [0][0][1][0][RTW89_FCC][2][111] = 127, + [0][0][1][0][RTW89_ETSI][1][111] = 127, + [0][0][1][0][RTW89_ETSI][0][111] = 127, + [0][0][1][0][RTW89_MKK][1][111] = 127, + [0][0][1][0][RTW89_MKK][0][111] = 127, + [0][0][1][0][RTW89_IC][1][111] = 127, + [0][0][1][0][RTW89_KCC][1][111] = 127, + [0][0][1][0][RTW89_KCC][0][111] = 127, + [0][0][1][0][RTW89_ACMA][1][111] = 127, + [0][0][1][0][RTW89_ACMA][0][111] = 127, + [0][0][1][0][RTW89_CHILE][1][111] = 127, + [0][0][1][0][RTW89_QATAR][1][111] = 127, + [0][0][1][0][RTW89_QATAR][0][111] = 127, + [0][0][1][0][RTW89_UK][1][111] = 127, + [0][0][1][0][RTW89_UK][0][111] = 127, + [0][0][1][0][RTW89_FCC][1][113] = 127, + [0][0][1][0][RTW89_FCC][2][113] = 127, + [0][0][1][0][RTW89_ETSI][1][113] = 127, + [0][0][1][0][RTW89_ETSI][0][113] = 127, + [0][0][1][0][RTW89_MKK][1][113] = 127, + [0][0][1][0][RTW89_MKK][0][113] = 127, + [0][0][1][0][RTW89_IC][1][113] = 127, + [0][0][1][0][RTW89_KCC][1][113] = 127, + [0][0][1][0][RTW89_KCC][0][113] = 127, + [0][0][1][0][RTW89_ACMA][1][113] = 127, + [0][0][1][0][RTW89_ACMA][0][113] = 127, + [0][0][1][0][RTW89_CHILE][1][113] = 127, + [0][0][1][0][RTW89_QATAR][1][113] = 127, + [0][0][1][0][RTW89_QATAR][0][113] = 127, + [0][0][1][0][RTW89_UK][1][113] = 127, + [0][0][1][0][RTW89_UK][0][113] = 127, + [0][0][1][0][RTW89_FCC][1][115] = 127, + [0][0][1][0][RTW89_FCC][2][115] = 127, + [0][0][1][0][RTW89_ETSI][1][115] = 127, + [0][0][1][0][RTW89_ETSI][0][115] = 127, + [0][0][1][0][RTW89_MKK][1][115] = 127, + [0][0][1][0][RTW89_MKK][0][115] = 127, + [0][0][1][0][RTW89_IC][1][115] = 127, + [0][0][1][0][RTW89_KCC][1][115] = 127, + [0][0][1][0][RTW89_KCC][0][115] = 127, + [0][0][1][0][RTW89_ACMA][1][115] = 127, + [0][0][1][0][RTW89_ACMA][0][115] = 127, + [0][0][1][0][RTW89_CHILE][1][115] = 127, + [0][0][1][0][RTW89_QATAR][1][115] = 127, + [0][0][1][0][RTW89_QATAR][0][115] = 127, + [0][0][1][0][RTW89_UK][1][115] = 127, + [0][0][1][0][RTW89_UK][0][115] = 127, + [0][0][1][0][RTW89_FCC][1][117] = 127, + [0][0][1][0][RTW89_FCC][2][117] = 127, + [0][0][1][0][RTW89_ETSI][1][117] = 127, + [0][0][1][0][RTW89_ETSI][0][117] = 127, + [0][0][1][0][RTW89_MKK][1][117] = 127, + [0][0][1][0][RTW89_MKK][0][117] = 127, + [0][0][1][0][RTW89_IC][1][117] = 127, + [0][0][1][0][RTW89_KCC][1][117] = 127, + [0][0][1][0][RTW89_KCC][0][117] = 127, + [0][0][1][0][RTW89_ACMA][1][117] = 127, + [0][0][1][0][RTW89_ACMA][0][117] = 127, + [0][0][1][0][RTW89_CHILE][1][117] = 127, + [0][0][1][0][RTW89_QATAR][1][117] = 127, + [0][0][1][0][RTW89_QATAR][0][117] = 127, + [0][0][1][0][RTW89_UK][1][117] = 127, + [0][0][1][0][RTW89_UK][0][117] = 127, + [0][0][1][0][RTW89_FCC][1][119] = 127, + [0][0][1][0][RTW89_FCC][2][119] = 127, + [0][0][1][0][RTW89_ETSI][1][119] = 127, + [0][0][1][0][RTW89_ETSI][0][119] = 127, + [0][0][1][0][RTW89_MKK][1][119] = 127, + [0][0][1][0][RTW89_MKK][0][119] = 127, + [0][0][1][0][RTW89_IC][1][119] = 127, + [0][0][1][0][RTW89_KCC][1][119] = 127, + [0][0][1][0][RTW89_KCC][0][119] = 127, + [0][0][1][0][RTW89_ACMA][1][119] = 127, + [0][0][1][0][RTW89_ACMA][0][119] = 127, + [0][0][1][0][RTW89_CHILE][1][119] = 127, + [0][0][1][0][RTW89_QATAR][1][119] = 127, + [0][0][1][0][RTW89_QATAR][0][119] = 127, + [0][0][1][0][RTW89_UK][1][119] = 127, + [0][0][1][0][RTW89_UK][0][119] = 127, + [0][1][1][0][RTW89_FCC][1][0] = -2, + [0][1][1][0][RTW89_FCC][2][0] = 54, + [0][1][1][0][RTW89_ETSI][1][0] = 54, + [0][1][1][0][RTW89_ETSI][0][0] = 18, + [0][1][1][0][RTW89_MKK][1][0] = 56, + [0][1][1][0][RTW89_MKK][0][0] = 16, + [0][1][1][0][RTW89_IC][1][0] = -2, + [0][1][1][0][RTW89_KCC][1][0] = 12, + [0][1][1][0][RTW89_KCC][0][0] = 10, + [0][1][1][0][RTW89_ACMA][1][0] = 54, + [0][1][1][0][RTW89_ACMA][0][0] = 18, + [0][1][1][0][RTW89_CHILE][1][0] = -2, + [0][1][1][0][RTW89_QATAR][1][0] = 54, + [0][1][1][0][RTW89_QATAR][0][0] = 18, + [0][1][1][0][RTW89_UK][1][0] = 54, + [0][1][1][0][RTW89_UK][0][0] = 18, + [0][1][1][0][RTW89_FCC][1][2] = -4, + [0][1][1][0][RTW89_FCC][2][2] = 54, + [0][1][1][0][RTW89_ETSI][1][2] = 54, + [0][1][1][0][RTW89_ETSI][0][2] = 18, + [0][1][1][0][RTW89_MKK][1][2] = 54, + [0][1][1][0][RTW89_MKK][0][2] = 16, + [0][1][1][0][RTW89_IC][1][2] = -4, + [0][1][1][0][RTW89_KCC][1][2] = 12, + [0][1][1][0][RTW89_KCC][0][2] = 12, + [0][1][1][0][RTW89_ACMA][1][2] = 54, + [0][1][1][0][RTW89_ACMA][0][2] = 18, + [0][1][1][0][RTW89_CHILE][1][2] = -4, + [0][1][1][0][RTW89_QATAR][1][2] = 54, + [0][1][1][0][RTW89_QATAR][0][2] = 18, + [0][1][1][0][RTW89_UK][1][2] = 54, + [0][1][1][0][RTW89_UK][0][2] = 18, + [0][1][1][0][RTW89_FCC][1][4] = -4, + [0][1][1][0][RTW89_FCC][2][4] = 54, + [0][1][1][0][RTW89_ETSI][1][4] = 54, + [0][1][1][0][RTW89_ETSI][0][4] = 18, + [0][1][1][0][RTW89_MKK][1][4] = 54, + [0][1][1][0][RTW89_MKK][0][4] = 16, + [0][1][1][0][RTW89_IC][1][4] = -4, + [0][1][1][0][RTW89_KCC][1][4] = 12, + [0][1][1][0][RTW89_KCC][0][4] = 12, + [0][1][1][0][RTW89_ACMA][1][4] = 54, + [0][1][1][0][RTW89_ACMA][0][4] = 18, + [0][1][1][0][RTW89_CHILE][1][4] = -4, + [0][1][1][0][RTW89_QATAR][1][4] = 54, + [0][1][1][0][RTW89_QATAR][0][4] = 18, + [0][1][1][0][RTW89_UK][1][4] = 54, + [0][1][1][0][RTW89_UK][0][4] = 18, + [0][1][1][0][RTW89_FCC][1][6] = -4, + [0][1][1][0][RTW89_FCC][2][6] = 54, + [0][1][1][0][RTW89_ETSI][1][6] = 54, + [0][1][1][0][RTW89_ETSI][0][6] = 18, + [0][1][1][0][RTW89_MKK][1][6] = 54, + [0][1][1][0][RTW89_MKK][0][6] = 16, + [0][1][1][0][RTW89_IC][1][6] = -4, + [0][1][1][0][RTW89_KCC][1][6] = 12, + [0][1][1][0][RTW89_KCC][0][6] = 12, + [0][1][1][0][RTW89_ACMA][1][6] = 54, + [0][1][1][0][RTW89_ACMA][0][6] = 18, + [0][1][1][0][RTW89_CHILE][1][6] = -4, + [0][1][1][0][RTW89_QATAR][1][6] = 54, + [0][1][1][0][RTW89_QATAR][0][6] = 18, + [0][1][1][0][RTW89_UK][1][6] = 54, + [0][1][1][0][RTW89_UK][0][6] = 18, + [0][1][1][0][RTW89_FCC][1][8] = -4, + [0][1][1][0][RTW89_FCC][2][8] = 54, + [0][1][1][0][RTW89_ETSI][1][8] = 54, + [0][1][1][0][RTW89_ETSI][0][8] = 18, + [0][1][1][0][RTW89_MKK][1][8] = 54, + [0][1][1][0][RTW89_MKK][0][8] = 16, + [0][1][1][0][RTW89_IC][1][8] = -4, + [0][1][1][0][RTW89_KCC][1][8] = 12, + [0][1][1][0][RTW89_KCC][0][8] = 12, + [0][1][1][0][RTW89_ACMA][1][8] = 54, + [0][1][1][0][RTW89_ACMA][0][8] = 18, + [0][1][1][0][RTW89_CHILE][1][8] = -4, + [0][1][1][0][RTW89_QATAR][1][8] = 54, + [0][1][1][0][RTW89_QATAR][0][8] = 18, + [0][1][1][0][RTW89_UK][1][8] = 54, + [0][1][1][0][RTW89_UK][0][8] = 18, + [0][1][1][0][RTW89_FCC][1][10] = -4, + [0][1][1][0][RTW89_FCC][2][10] = 54, + [0][1][1][0][RTW89_ETSI][1][10] = 54, + [0][1][1][0][RTW89_ETSI][0][10] = 18, + [0][1][1][0][RTW89_MKK][1][10] = 54, + [0][1][1][0][RTW89_MKK][0][10] = 16, + [0][1][1][0][RTW89_IC][1][10] = -4, + [0][1][1][0][RTW89_KCC][1][10] = 12, + [0][1][1][0][RTW89_KCC][0][10] = 12, + [0][1][1][0][RTW89_ACMA][1][10] = 54, + [0][1][1][0][RTW89_ACMA][0][10] = 18, + [0][1][1][0][RTW89_CHILE][1][10] = -4, + [0][1][1][0][RTW89_QATAR][1][10] = 54, + [0][1][1][0][RTW89_QATAR][0][10] = 18, + [0][1][1][0][RTW89_UK][1][10] = 54, + [0][1][1][0][RTW89_UK][0][10] = 18, + [0][1][1][0][RTW89_FCC][1][12] = -4, + [0][1][1][0][RTW89_FCC][2][12] = 54, + [0][1][1][0][RTW89_ETSI][1][12] = 54, + [0][1][1][0][RTW89_ETSI][0][12] = 18, + [0][1][1][0][RTW89_MKK][1][12] = 54, + [0][1][1][0][RTW89_MKK][0][12] = 16, + [0][1][1][0][RTW89_IC][1][12] = -4, + [0][1][1][0][RTW89_KCC][1][12] = 12, + [0][1][1][0][RTW89_KCC][0][12] = 12, + [0][1][1][0][RTW89_ACMA][1][12] = 54, + [0][1][1][0][RTW89_ACMA][0][12] = 18, + [0][1][1][0][RTW89_CHILE][1][12] = -4, + [0][1][1][0][RTW89_QATAR][1][12] = 54, + [0][1][1][0][RTW89_QATAR][0][12] = 18, + [0][1][1][0][RTW89_UK][1][12] = 54, + [0][1][1][0][RTW89_UK][0][12] = 18, + [0][1][1][0][RTW89_FCC][1][14] = -4, + [0][1][1][0][RTW89_FCC][2][14] = 54, + [0][1][1][0][RTW89_ETSI][1][14] = 54, + [0][1][1][0][RTW89_ETSI][0][14] = 18, + [0][1][1][0][RTW89_MKK][1][14] = 54, + [0][1][1][0][RTW89_MKK][0][14] = 16, + [0][1][1][0][RTW89_IC][1][14] = -4, + [0][1][1][0][RTW89_KCC][1][14] = 12, + [0][1][1][0][RTW89_KCC][0][14] = 12, + [0][1][1][0][RTW89_ACMA][1][14] = 54, + [0][1][1][0][RTW89_ACMA][0][14] = 18, + [0][1][1][0][RTW89_CHILE][1][14] = -4, + [0][1][1][0][RTW89_QATAR][1][14] = 54, + [0][1][1][0][RTW89_QATAR][0][14] = 18, + [0][1][1][0][RTW89_UK][1][14] = 54, + [0][1][1][0][RTW89_UK][0][14] = 18, + [0][1][1][0][RTW89_FCC][1][15] = -4, + [0][1][1][0][RTW89_FCC][2][15] = 54, + [0][1][1][0][RTW89_ETSI][1][15] = 54, + [0][1][1][0][RTW89_ETSI][0][15] = 18, + [0][1][1][0][RTW89_MKK][1][15] = 54, + [0][1][1][0][RTW89_MKK][0][15] = 16, + [0][1][1][0][RTW89_IC][1][15] = -4, + [0][1][1][0][RTW89_KCC][1][15] = 12, + [0][1][1][0][RTW89_KCC][0][15] = 12, + [0][1][1][0][RTW89_ACMA][1][15] = 54, + [0][1][1][0][RTW89_ACMA][0][15] = 18, + [0][1][1][0][RTW89_CHILE][1][15] = -4, + [0][1][1][0][RTW89_QATAR][1][15] = 54, + [0][1][1][0][RTW89_QATAR][0][15] = 18, + [0][1][1][0][RTW89_UK][1][15] = 54, + [0][1][1][0][RTW89_UK][0][15] = 18, + [0][1][1][0][RTW89_FCC][1][17] = -4, + [0][1][1][0][RTW89_FCC][2][17] = 54, + [0][1][1][0][RTW89_ETSI][1][17] = 54, + [0][1][1][0][RTW89_ETSI][0][17] = 18, + [0][1][1][0][RTW89_MKK][1][17] = 54, + [0][1][1][0][RTW89_MKK][0][17] = 16, + [0][1][1][0][RTW89_IC][1][17] = -4, + [0][1][1][0][RTW89_KCC][1][17] = 12, + [0][1][1][0][RTW89_KCC][0][17] = 12, + [0][1][1][0][RTW89_ACMA][1][17] = 54, + [0][1][1][0][RTW89_ACMA][0][17] = 18, + [0][1][1][0][RTW89_CHILE][1][17] = -4, + [0][1][1][0][RTW89_QATAR][1][17] = 54, + [0][1][1][0][RTW89_QATAR][0][17] = 18, + [0][1][1][0][RTW89_UK][1][17] = 54, + [0][1][1][0][RTW89_UK][0][17] = 18, + [0][1][1][0][RTW89_FCC][1][19] = -4, + [0][1][1][0][RTW89_FCC][2][19] = 54, + [0][1][1][0][RTW89_ETSI][1][19] = 54, + [0][1][1][0][RTW89_ETSI][0][19] = 18, + [0][1][1][0][RTW89_MKK][1][19] = 54, + [0][1][1][0][RTW89_MKK][0][19] = 16, + [0][1][1][0][RTW89_IC][1][19] = -4, + [0][1][1][0][RTW89_KCC][1][19] = 12, + [0][1][1][0][RTW89_KCC][0][19] = 12, + [0][1][1][0][RTW89_ACMA][1][19] = 54, + [0][1][1][0][RTW89_ACMA][0][19] = 18, + [0][1][1][0][RTW89_CHILE][1][19] = -4, + [0][1][1][0][RTW89_QATAR][1][19] = 54, + [0][1][1][0][RTW89_QATAR][0][19] = 18, + [0][1][1][0][RTW89_UK][1][19] = 54, + [0][1][1][0][RTW89_UK][0][19] = 18, + [0][1][1][0][RTW89_FCC][1][21] = -4, + [0][1][1][0][RTW89_FCC][2][21] = 54, + [0][1][1][0][RTW89_ETSI][1][21] = 54, + [0][1][1][0][RTW89_ETSI][0][21] = 18, + [0][1][1][0][RTW89_MKK][1][21] = 54, + [0][1][1][0][RTW89_MKK][0][21] = 16, + [0][1][1][0][RTW89_IC][1][21] = -4, + [0][1][1][0][RTW89_KCC][1][21] = 12, + [0][1][1][0][RTW89_KCC][0][21] = 12, + [0][1][1][0][RTW89_ACMA][1][21] = 54, + [0][1][1][0][RTW89_ACMA][0][21] = 18, + [0][1][1][0][RTW89_CHILE][1][21] = -4, + [0][1][1][0][RTW89_QATAR][1][21] = 54, + [0][1][1][0][RTW89_QATAR][0][21] = 18, + [0][1][1][0][RTW89_UK][1][21] = 54, + [0][1][1][0][RTW89_UK][0][21] = 18, + [0][1][1][0][RTW89_FCC][1][23] = -4, + [0][1][1][0][RTW89_FCC][2][23] = 68, + [0][1][1][0][RTW89_ETSI][1][23] = 54, + [0][1][1][0][RTW89_ETSI][0][23] = 18, + [0][1][1][0][RTW89_MKK][1][23] = 54, + [0][1][1][0][RTW89_MKK][0][23] = 16, + [0][1][1][0][RTW89_IC][1][23] = -4, + [0][1][1][0][RTW89_KCC][1][23] = 12, + [0][1][1][0][RTW89_KCC][0][23] = 10, + [0][1][1][0][RTW89_ACMA][1][23] = 54, + [0][1][1][0][RTW89_ACMA][0][23] = 18, + [0][1][1][0][RTW89_CHILE][1][23] = -4, + [0][1][1][0][RTW89_QATAR][1][23] = 54, + [0][1][1][0][RTW89_QATAR][0][23] = 18, + [0][1][1][0][RTW89_UK][1][23] = 54, + [0][1][1][0][RTW89_UK][0][23] = 18, + [0][1][1][0][RTW89_FCC][1][25] = -4, + [0][1][1][0][RTW89_FCC][2][25] = 68, + [0][1][1][0][RTW89_ETSI][1][25] = 54, + [0][1][1][0][RTW89_ETSI][0][25] = 18, + [0][1][1][0][RTW89_MKK][1][25] = 54, + [0][1][1][0][RTW89_MKK][0][25] = 16, + [0][1][1][0][RTW89_IC][1][25] = -4, + [0][1][1][0][RTW89_KCC][1][25] = 12, + [0][1][1][0][RTW89_KCC][0][25] = 14, + [0][1][1][0][RTW89_ACMA][1][25] = 54, + [0][1][1][0][RTW89_ACMA][0][25] = 18, + [0][1][1][0][RTW89_CHILE][1][25] = -4, + [0][1][1][0][RTW89_QATAR][1][25] = 54, + [0][1][1][0][RTW89_QATAR][0][25] = 18, + [0][1][1][0][RTW89_UK][1][25] = 54, + [0][1][1][0][RTW89_UK][0][25] = 18, + [0][1][1][0][RTW89_FCC][1][27] = -4, + [0][1][1][0][RTW89_FCC][2][27] = 68, + [0][1][1][0][RTW89_ETSI][1][27] = 54, + [0][1][1][0][RTW89_ETSI][0][27] = 18, + [0][1][1][0][RTW89_MKK][1][27] = 54, + [0][1][1][0][RTW89_MKK][0][27] = 16, + [0][1][1][0][RTW89_IC][1][27] = -4, + [0][1][1][0][RTW89_KCC][1][27] = 12, + [0][1][1][0][RTW89_KCC][0][27] = 14, + [0][1][1][0][RTW89_ACMA][1][27] = 54, + [0][1][1][0][RTW89_ACMA][0][27] = 18, + [0][1][1][0][RTW89_CHILE][1][27] = -4, + [0][1][1][0][RTW89_QATAR][1][27] = 54, + [0][1][1][0][RTW89_QATAR][0][27] = 18, + [0][1][1][0][RTW89_UK][1][27] = 54, + [0][1][1][0][RTW89_UK][0][27] = 18, + [0][1][1][0][RTW89_FCC][1][29] = -4, + [0][1][1][0][RTW89_FCC][2][29] = 68, + [0][1][1][0][RTW89_ETSI][1][29] = 54, + [0][1][1][0][RTW89_ETSI][0][29] = 18, + [0][1][1][0][RTW89_MKK][1][29] = 54, + [0][1][1][0][RTW89_MKK][0][29] = 16, + [0][1][1][0][RTW89_IC][1][29] = -4, + [0][1][1][0][RTW89_KCC][1][29] = 12, + [0][1][1][0][RTW89_KCC][0][29] = 14, + [0][1][1][0][RTW89_ACMA][1][29] = 54, + [0][1][1][0][RTW89_ACMA][0][29] = 18, + [0][1][1][0][RTW89_CHILE][1][29] = -4, + [0][1][1][0][RTW89_QATAR][1][29] = 54, + [0][1][1][0][RTW89_QATAR][0][29] = 18, + [0][1][1][0][RTW89_UK][1][29] = 54, + [0][1][1][0][RTW89_UK][0][29] = 18, + [0][1][1][0][RTW89_FCC][1][30] = -4, + [0][1][1][0][RTW89_FCC][2][30] = 68, + [0][1][1][0][RTW89_ETSI][1][30] = 54, + [0][1][1][0][RTW89_ETSI][0][30] = 18, + [0][1][1][0][RTW89_MKK][1][30] = 54, + [0][1][1][0][RTW89_MKK][0][30] = 16, + [0][1][1][0][RTW89_IC][1][30] = -4, + [0][1][1][0][RTW89_KCC][1][30] = 12, + [0][1][1][0][RTW89_KCC][0][30] = 14, + [0][1][1][0][RTW89_ACMA][1][30] = 54, + [0][1][1][0][RTW89_ACMA][0][30] = 18, + [0][1][1][0][RTW89_CHILE][1][30] = -4, + [0][1][1][0][RTW89_QATAR][1][30] = 54, + [0][1][1][0][RTW89_QATAR][0][30] = 18, + [0][1][1][0][RTW89_UK][1][30] = 54, + [0][1][1][0][RTW89_UK][0][30] = 18, + [0][1][1][0][RTW89_FCC][1][32] = -4, + [0][1][1][0][RTW89_FCC][2][32] = 68, + [0][1][1][0][RTW89_ETSI][1][32] = 54, + [0][1][1][0][RTW89_ETSI][0][32] = 18, + [0][1][1][0][RTW89_MKK][1][32] = 54, + [0][1][1][0][RTW89_MKK][0][32] = 16, + [0][1][1][0][RTW89_IC][1][32] = -4, + [0][1][1][0][RTW89_KCC][1][32] = 12, + [0][1][1][0][RTW89_KCC][0][32] = 14, + [0][1][1][0][RTW89_ACMA][1][32] = 54, + [0][1][1][0][RTW89_ACMA][0][32] = 18, + [0][1][1][0][RTW89_CHILE][1][32] = -4, + [0][1][1][0][RTW89_QATAR][1][32] = 54, + [0][1][1][0][RTW89_QATAR][0][32] = 18, + [0][1][1][0][RTW89_UK][1][32] = 54, + [0][1][1][0][RTW89_UK][0][32] = 18, + [0][1][1][0][RTW89_FCC][1][34] = -4, + [0][1][1][0][RTW89_FCC][2][34] = 68, + [0][1][1][0][RTW89_ETSI][1][34] = 54, + [0][1][1][0][RTW89_ETSI][0][34] = 18, + [0][1][1][0][RTW89_MKK][1][34] = 54, + [0][1][1][0][RTW89_MKK][0][34] = 16, + [0][1][1][0][RTW89_IC][1][34] = -4, + [0][1][1][0][RTW89_KCC][1][34] = 12, + [0][1][1][0][RTW89_KCC][0][34] = 14, + [0][1][1][0][RTW89_ACMA][1][34] = 54, + [0][1][1][0][RTW89_ACMA][0][34] = 18, + [0][1][1][0][RTW89_CHILE][1][34] = -4, + [0][1][1][0][RTW89_QATAR][1][34] = 54, + [0][1][1][0][RTW89_QATAR][0][34] = 18, + [0][1][1][0][RTW89_UK][1][34] = 54, + [0][1][1][0][RTW89_UK][0][34] = 18, + [0][1][1][0][RTW89_FCC][1][36] = -4, + [0][1][1][0][RTW89_FCC][2][36] = 68, + [0][1][1][0][RTW89_ETSI][1][36] = 54, + [0][1][1][0][RTW89_ETSI][0][36] = 18, + [0][1][1][0][RTW89_MKK][1][36] = 54, + [0][1][1][0][RTW89_MKK][0][36] = 16, + [0][1][1][0][RTW89_IC][1][36] = -4, + [0][1][1][0][RTW89_KCC][1][36] = 12, + [0][1][1][0][RTW89_KCC][0][36] = 14, + [0][1][1][0][RTW89_ACMA][1][36] = 54, + [0][1][1][0][RTW89_ACMA][0][36] = 18, + [0][1][1][0][RTW89_CHILE][1][36] = -4, + [0][1][1][0][RTW89_QATAR][1][36] = 54, + [0][1][1][0][RTW89_QATAR][0][36] = 18, + [0][1][1][0][RTW89_UK][1][36] = 54, + [0][1][1][0][RTW89_UK][0][36] = 18, + [0][1][1][0][RTW89_FCC][1][38] = -4, + [0][1][1][0][RTW89_FCC][2][38] = 68, + [0][1][1][0][RTW89_ETSI][1][38] = 54, + [0][1][1][0][RTW89_ETSI][0][38] = 18, + [0][1][1][0][RTW89_MKK][1][38] = 54, + [0][1][1][0][RTW89_MKK][0][38] = 16, + [0][1][1][0][RTW89_IC][1][38] = -4, + [0][1][1][0][RTW89_KCC][1][38] = 12, + [0][1][1][0][RTW89_KCC][0][38] = 14, + [0][1][1][0][RTW89_ACMA][1][38] = 54, + [0][1][1][0][RTW89_ACMA][0][38] = 18, + [0][1][1][0][RTW89_CHILE][1][38] = -4, + [0][1][1][0][RTW89_QATAR][1][38] = 54, + [0][1][1][0][RTW89_QATAR][0][38] = 18, + [0][1][1][0][RTW89_UK][1][38] = 54, + [0][1][1][0][RTW89_UK][0][38] = 18, + [0][1][1][0][RTW89_FCC][1][40] = -4, + [0][1][1][0][RTW89_FCC][2][40] = 68, + [0][1][1][0][RTW89_ETSI][1][40] = 54, + [0][1][1][0][RTW89_ETSI][0][40] = 18, + [0][1][1][0][RTW89_MKK][1][40] = 54, + [0][1][1][0][RTW89_MKK][0][40] = 16, + [0][1][1][0][RTW89_IC][1][40] = -4, + [0][1][1][0][RTW89_KCC][1][40] = 12, + [0][1][1][0][RTW89_KCC][0][40] = 14, + [0][1][1][0][RTW89_ACMA][1][40] = 54, + [0][1][1][0][RTW89_ACMA][0][40] = 18, + [0][1][1][0][RTW89_CHILE][1][40] = -4, + [0][1][1][0][RTW89_QATAR][1][40] = 54, + [0][1][1][0][RTW89_QATAR][0][40] = 18, + [0][1][1][0][RTW89_UK][1][40] = 54, + [0][1][1][0][RTW89_UK][0][40] = 18, + [0][1][1][0][RTW89_FCC][1][42] = -4, + [0][1][1][0][RTW89_FCC][2][42] = 68, + [0][1][1][0][RTW89_ETSI][1][42] = 54, + [0][1][1][0][RTW89_ETSI][0][42] = 18, + [0][1][1][0][RTW89_MKK][1][42] = 54, + [0][1][1][0][RTW89_MKK][0][42] = 16, + [0][1][1][0][RTW89_IC][1][42] = -4, + [0][1][1][0][RTW89_KCC][1][42] = 12, + [0][1][1][0][RTW89_KCC][0][42] = 14, + [0][1][1][0][RTW89_ACMA][1][42] = 54, + [0][1][1][0][RTW89_ACMA][0][42] = 18, + [0][1][1][0][RTW89_CHILE][1][42] = -4, + [0][1][1][0][RTW89_QATAR][1][42] = 54, + [0][1][1][0][RTW89_QATAR][0][42] = 18, + [0][1][1][0][RTW89_UK][1][42] = 54, + [0][1][1][0][RTW89_UK][0][42] = 18, + [0][1][1][0][RTW89_FCC][1][44] = -2, + [0][1][1][0][RTW89_FCC][2][44] = 68, + [0][1][1][0][RTW89_ETSI][1][44] = 54, + [0][1][1][0][RTW89_ETSI][0][44] = 18, + [0][1][1][0][RTW89_MKK][1][44] = 34, + [0][1][1][0][RTW89_MKK][0][44] = 16, + [0][1][1][0][RTW89_IC][1][44] = -2, + [0][1][1][0][RTW89_KCC][1][44] = 12, + [0][1][1][0][RTW89_KCC][0][44] = 12, + [0][1][1][0][RTW89_ACMA][1][44] = 54, + [0][1][1][0][RTW89_ACMA][0][44] = 18, + [0][1][1][0][RTW89_CHILE][1][44] = -2, + [0][1][1][0][RTW89_QATAR][1][44] = 54, + [0][1][1][0][RTW89_QATAR][0][44] = 18, + [0][1][1][0][RTW89_UK][1][44] = 54, + [0][1][1][0][RTW89_UK][0][44] = 18, + [0][1][1][0][RTW89_FCC][1][45] = -2, + [0][1][1][0][RTW89_FCC][2][45] = 127, + [0][1][1][0][RTW89_ETSI][1][45] = 127, + [0][1][1][0][RTW89_ETSI][0][45] = 127, + [0][1][1][0][RTW89_MKK][1][45] = 127, + [0][1][1][0][RTW89_MKK][0][45] = 127, + [0][1][1][0][RTW89_IC][1][45] = -2, + [0][1][1][0][RTW89_KCC][1][45] = 12, + [0][1][1][0][RTW89_KCC][0][45] = 127, + [0][1][1][0][RTW89_ACMA][1][45] = 127, + [0][1][1][0][RTW89_ACMA][0][45] = 127, + [0][1][1][0][RTW89_CHILE][1][45] = -2, + [0][1][1][0][RTW89_QATAR][1][45] = 127, + [0][1][1][0][RTW89_QATAR][0][45] = 127, + [0][1][1][0][RTW89_UK][1][45] = 127, + [0][1][1][0][RTW89_UK][0][45] = 127, + [0][1][1][0][RTW89_FCC][1][47] = -2, + [0][1][1][0][RTW89_FCC][2][47] = 127, + [0][1][1][0][RTW89_ETSI][1][47] = 127, + [0][1][1][0][RTW89_ETSI][0][47] = 127, + [0][1][1][0][RTW89_MKK][1][47] = 127, + [0][1][1][0][RTW89_MKK][0][47] = 127, + [0][1][1][0][RTW89_IC][1][47] = -2, + [0][1][1][0][RTW89_KCC][1][47] = 12, + [0][1][1][0][RTW89_KCC][0][47] = 127, + [0][1][1][0][RTW89_ACMA][1][47] = 127, + [0][1][1][0][RTW89_ACMA][0][47] = 127, + [0][1][1][0][RTW89_CHILE][1][47] = -2, + [0][1][1][0][RTW89_QATAR][1][47] = 127, + [0][1][1][0][RTW89_QATAR][0][47] = 127, + [0][1][1][0][RTW89_UK][1][47] = 127, + [0][1][1][0][RTW89_UK][0][47] = 127, + [0][1][1][0][RTW89_FCC][1][49] = -2, + [0][1][1][0][RTW89_FCC][2][49] = 127, + [0][1][1][0][RTW89_ETSI][1][49] = 127, + [0][1][1][0][RTW89_ETSI][0][49] = 127, + [0][1][1][0][RTW89_MKK][1][49] = 127, + [0][1][1][0][RTW89_MKK][0][49] = 127, + [0][1][1][0][RTW89_IC][1][49] = -2, + [0][1][1][0][RTW89_KCC][1][49] = 12, + [0][1][1][0][RTW89_KCC][0][49] = 127, + [0][1][1][0][RTW89_ACMA][1][49] = 127, + [0][1][1][0][RTW89_ACMA][0][49] = 127, + [0][1][1][0][RTW89_CHILE][1][49] = -2, + [0][1][1][0][RTW89_QATAR][1][49] = 127, + [0][1][1][0][RTW89_QATAR][0][49] = 127, + [0][1][1][0][RTW89_UK][1][49] = 127, + [0][1][1][0][RTW89_UK][0][49] = 127, + [0][1][1][0][RTW89_FCC][1][51] = -2, + [0][1][1][0][RTW89_FCC][2][51] = 127, + [0][1][1][0][RTW89_ETSI][1][51] = 127, + [0][1][1][0][RTW89_ETSI][0][51] = 127, + [0][1][1][0][RTW89_MKK][1][51] = 127, + [0][1][1][0][RTW89_MKK][0][51] = 127, + [0][1][1][0][RTW89_IC][1][51] = -2, + [0][1][1][0][RTW89_KCC][1][51] = 12, + [0][1][1][0][RTW89_KCC][0][51] = 127, + [0][1][1][0][RTW89_ACMA][1][51] = 127, + [0][1][1][0][RTW89_ACMA][0][51] = 127, + [0][1][1][0][RTW89_CHILE][1][51] = -2, + [0][1][1][0][RTW89_QATAR][1][51] = 127, + [0][1][1][0][RTW89_QATAR][0][51] = 127, + [0][1][1][0][RTW89_UK][1][51] = 127, + [0][1][1][0][RTW89_UK][0][51] = 127, + [0][1][1][0][RTW89_FCC][1][53] = -2, + [0][1][1][0][RTW89_FCC][2][53] = 127, + [0][1][1][0][RTW89_ETSI][1][53] = 127, + [0][1][1][0][RTW89_ETSI][0][53] = 127, + [0][1][1][0][RTW89_MKK][1][53] = 127, + [0][1][1][0][RTW89_MKK][0][53] = 127, + [0][1][1][0][RTW89_IC][1][53] = -2, + [0][1][1][0][RTW89_KCC][1][53] = 12, + [0][1][1][0][RTW89_KCC][0][53] = 127, + [0][1][1][0][RTW89_ACMA][1][53] = 127, + [0][1][1][0][RTW89_ACMA][0][53] = 127, + [0][1][1][0][RTW89_CHILE][1][53] = -2, + [0][1][1][0][RTW89_QATAR][1][53] = 127, + [0][1][1][0][RTW89_QATAR][0][53] = 127, + [0][1][1][0][RTW89_UK][1][53] = 127, + [0][1][1][0][RTW89_UK][0][53] = 127, + [0][1][1][0][RTW89_FCC][1][55] = -2, + [0][1][1][0][RTW89_FCC][2][55] = 68, + [0][1][1][0][RTW89_ETSI][1][55] = 127, + [0][1][1][0][RTW89_ETSI][0][55] = 127, + [0][1][1][0][RTW89_MKK][1][55] = 127, + [0][1][1][0][RTW89_MKK][0][55] = 127, + [0][1][1][0][RTW89_IC][1][55] = -2, + [0][1][1][0][RTW89_KCC][1][55] = 12, + [0][1][1][0][RTW89_KCC][0][55] = 127, + [0][1][1][0][RTW89_ACMA][1][55] = 127, + [0][1][1][0][RTW89_ACMA][0][55] = 127, + [0][1][1][0][RTW89_CHILE][1][55] = -2, + [0][1][1][0][RTW89_QATAR][1][55] = 127, + [0][1][1][0][RTW89_QATAR][0][55] = 127, + [0][1][1][0][RTW89_UK][1][55] = 127, + [0][1][1][0][RTW89_UK][0][55] = 127, + [0][1][1][0][RTW89_FCC][1][57] = -2, + [0][1][1][0][RTW89_FCC][2][57] = 68, + [0][1][1][0][RTW89_ETSI][1][57] = 127, + [0][1][1][0][RTW89_ETSI][0][57] = 127, + [0][1][1][0][RTW89_MKK][1][57] = 127, + [0][1][1][0][RTW89_MKK][0][57] = 127, + [0][1][1][0][RTW89_IC][1][57] = -2, + [0][1][1][0][RTW89_KCC][1][57] = 12, + [0][1][1][0][RTW89_KCC][0][57] = 127, + [0][1][1][0][RTW89_ACMA][1][57] = 127, + [0][1][1][0][RTW89_ACMA][0][57] = 127, + [0][1][1][0][RTW89_CHILE][1][57] = -2, + [0][1][1][0][RTW89_QATAR][1][57] = 127, + [0][1][1][0][RTW89_QATAR][0][57] = 127, + [0][1][1][0][RTW89_UK][1][57] = 127, + [0][1][1][0][RTW89_UK][0][57] = 127, + [0][1][1][0][RTW89_FCC][1][59] = -2, + [0][1][1][0][RTW89_FCC][2][59] = 68, + [0][1][1][0][RTW89_ETSI][1][59] = 127, + [0][1][1][0][RTW89_ETSI][0][59] = 127, + [0][1][1][0][RTW89_MKK][1][59] = 127, + [0][1][1][0][RTW89_MKK][0][59] = 127, + [0][1][1][0][RTW89_IC][1][59] = -2, + [0][1][1][0][RTW89_KCC][1][59] = 12, + [0][1][1][0][RTW89_KCC][0][59] = 127, + [0][1][1][0][RTW89_ACMA][1][59] = 127, + [0][1][1][0][RTW89_ACMA][0][59] = 127, + [0][1][1][0][RTW89_CHILE][1][59] = -2, + [0][1][1][0][RTW89_QATAR][1][59] = 127, + [0][1][1][0][RTW89_QATAR][0][59] = 127, + [0][1][1][0][RTW89_UK][1][59] = 127, + [0][1][1][0][RTW89_UK][0][59] = 127, + [0][1][1][0][RTW89_FCC][1][60] = -2, + [0][1][1][0][RTW89_FCC][2][60] = 68, + [0][1][1][0][RTW89_ETSI][1][60] = 127, + [0][1][1][0][RTW89_ETSI][0][60] = 127, + [0][1][1][0][RTW89_MKK][1][60] = 127, + [0][1][1][0][RTW89_MKK][0][60] = 127, + [0][1][1][0][RTW89_IC][1][60] = -2, + [0][1][1][0][RTW89_KCC][1][60] = 12, + [0][1][1][0][RTW89_KCC][0][60] = 127, + [0][1][1][0][RTW89_ACMA][1][60] = 127, + [0][1][1][0][RTW89_ACMA][0][60] = 127, + [0][1][1][0][RTW89_CHILE][1][60] = -2, + [0][1][1][0][RTW89_QATAR][1][60] = 127, + [0][1][1][0][RTW89_QATAR][0][60] = 127, + [0][1][1][0][RTW89_UK][1][60] = 127, + [0][1][1][0][RTW89_UK][0][60] = 127, + [0][1][1][0][RTW89_FCC][1][62] = -2, + [0][1][1][0][RTW89_FCC][2][62] = 68, + [0][1][1][0][RTW89_ETSI][1][62] = 127, + [0][1][1][0][RTW89_ETSI][0][62] = 127, + [0][1][1][0][RTW89_MKK][1][62] = 127, + [0][1][1][0][RTW89_MKK][0][62] = 127, + [0][1][1][0][RTW89_IC][1][62] = -2, + [0][1][1][0][RTW89_KCC][1][62] = 12, + [0][1][1][0][RTW89_KCC][0][62] = 127, + [0][1][1][0][RTW89_ACMA][1][62] = 127, + [0][1][1][0][RTW89_ACMA][0][62] = 127, + [0][1][1][0][RTW89_CHILE][1][62] = -2, + [0][1][1][0][RTW89_QATAR][1][62] = 127, + [0][1][1][0][RTW89_QATAR][0][62] = 127, + [0][1][1][0][RTW89_UK][1][62] = 127, + [0][1][1][0][RTW89_UK][0][62] = 127, + [0][1][1][0][RTW89_FCC][1][64] = -2, + [0][1][1][0][RTW89_FCC][2][64] = 68, + [0][1][1][0][RTW89_ETSI][1][64] = 127, + [0][1][1][0][RTW89_ETSI][0][64] = 127, + [0][1][1][0][RTW89_MKK][1][64] = 127, + [0][1][1][0][RTW89_MKK][0][64] = 127, + [0][1][1][0][RTW89_IC][1][64] = -2, + [0][1][1][0][RTW89_KCC][1][64] = 12, + [0][1][1][0][RTW89_KCC][0][64] = 127, + [0][1][1][0][RTW89_ACMA][1][64] = 127, + [0][1][1][0][RTW89_ACMA][0][64] = 127, + [0][1][1][0][RTW89_CHILE][1][64] = -2, + [0][1][1][0][RTW89_QATAR][1][64] = 127, + [0][1][1][0][RTW89_QATAR][0][64] = 127, + [0][1][1][0][RTW89_UK][1][64] = 127, + [0][1][1][0][RTW89_UK][0][64] = 127, + [0][1][1][0][RTW89_FCC][1][66] = -2, + [0][1][1][0][RTW89_FCC][2][66] = 68, + [0][1][1][0][RTW89_ETSI][1][66] = 127, + [0][1][1][0][RTW89_ETSI][0][66] = 127, + [0][1][1][0][RTW89_MKK][1][66] = 127, + [0][1][1][0][RTW89_MKK][0][66] = 127, + [0][1][1][0][RTW89_IC][1][66] = -2, + [0][1][1][0][RTW89_KCC][1][66] = 12, + [0][1][1][0][RTW89_KCC][0][66] = 127, + [0][1][1][0][RTW89_ACMA][1][66] = 127, + [0][1][1][0][RTW89_ACMA][0][66] = 127, + [0][1][1][0][RTW89_CHILE][1][66] = -2, + [0][1][1][0][RTW89_QATAR][1][66] = 127, + [0][1][1][0][RTW89_QATAR][0][66] = 127, + [0][1][1][0][RTW89_UK][1][66] = 127, + [0][1][1][0][RTW89_UK][0][66] = 127, + [0][1][1][0][RTW89_FCC][1][68] = -2, + [0][1][1][0][RTW89_FCC][2][68] = 68, + [0][1][1][0][RTW89_ETSI][1][68] = 127, + [0][1][1][0][RTW89_ETSI][0][68] = 127, + [0][1][1][0][RTW89_MKK][1][68] = 127, + [0][1][1][0][RTW89_MKK][0][68] = 127, + [0][1][1][0][RTW89_IC][1][68] = -2, + [0][1][1][0][RTW89_KCC][1][68] = 12, + [0][1][1][0][RTW89_KCC][0][68] = 127, + [0][1][1][0][RTW89_ACMA][1][68] = 127, + [0][1][1][0][RTW89_ACMA][0][68] = 127, + [0][1][1][0][RTW89_CHILE][1][68] = -2, + [0][1][1][0][RTW89_QATAR][1][68] = 127, + [0][1][1][0][RTW89_QATAR][0][68] = 127, + [0][1][1][0][RTW89_UK][1][68] = 127, + [0][1][1][0][RTW89_UK][0][68] = 127, + [0][1][1][0][RTW89_FCC][1][70] = -2, + [0][1][1][0][RTW89_FCC][2][70] = 68, + [0][1][1][0][RTW89_ETSI][1][70] = 127, + [0][1][1][0][RTW89_ETSI][0][70] = 127, + [0][1][1][0][RTW89_MKK][1][70] = 127, + [0][1][1][0][RTW89_MKK][0][70] = 127, + [0][1][1][0][RTW89_IC][1][70] = -2, + [0][1][1][0][RTW89_KCC][1][70] = 12, + [0][1][1][0][RTW89_KCC][0][70] = 127, + [0][1][1][0][RTW89_ACMA][1][70] = 127, + [0][1][1][0][RTW89_ACMA][0][70] = 127, + [0][1][1][0][RTW89_CHILE][1][70] = -2, + [0][1][1][0][RTW89_QATAR][1][70] = 127, + [0][1][1][0][RTW89_QATAR][0][70] = 127, + [0][1][1][0][RTW89_UK][1][70] = 127, + [0][1][1][0][RTW89_UK][0][70] = 127, + [0][1][1][0][RTW89_FCC][1][72] = -2, + [0][1][1][0][RTW89_FCC][2][72] = 68, + [0][1][1][0][RTW89_ETSI][1][72] = 127, + [0][1][1][0][RTW89_ETSI][0][72] = 127, + [0][1][1][0][RTW89_MKK][1][72] = 127, + [0][1][1][0][RTW89_MKK][0][72] = 127, + [0][1][1][0][RTW89_IC][1][72] = -2, + [0][1][1][0][RTW89_KCC][1][72] = 12, + [0][1][1][0][RTW89_KCC][0][72] = 127, + [0][1][1][0][RTW89_ACMA][1][72] = 127, + [0][1][1][0][RTW89_ACMA][0][72] = 127, + [0][1][1][0][RTW89_CHILE][1][72] = -2, + [0][1][1][0][RTW89_QATAR][1][72] = 127, + [0][1][1][0][RTW89_QATAR][0][72] = 127, + [0][1][1][0][RTW89_UK][1][72] = 127, + [0][1][1][0][RTW89_UK][0][72] = 127, + [0][1][1][0][RTW89_FCC][1][74] = -2, + [0][1][1][0][RTW89_FCC][2][74] = 68, + [0][1][1][0][RTW89_ETSI][1][74] = 127, + [0][1][1][0][RTW89_ETSI][0][74] = 127, + [0][1][1][0][RTW89_MKK][1][74] = 127, + [0][1][1][0][RTW89_MKK][0][74] = 127, + [0][1][1][0][RTW89_IC][1][74] = -2, + [0][1][1][0][RTW89_KCC][1][74] = 12, + [0][1][1][0][RTW89_KCC][0][74] = 127, + [0][1][1][0][RTW89_ACMA][1][74] = 127, + [0][1][1][0][RTW89_ACMA][0][74] = 127, + [0][1][1][0][RTW89_CHILE][1][74] = -2, + [0][1][1][0][RTW89_QATAR][1][74] = 127, + [0][1][1][0][RTW89_QATAR][0][74] = 127, + [0][1][1][0][RTW89_UK][1][74] = 127, + [0][1][1][0][RTW89_UK][0][74] = 127, + [0][1][1][0][RTW89_FCC][1][75] = -2, + [0][1][1][0][RTW89_FCC][2][75] = 68, + [0][1][1][0][RTW89_ETSI][1][75] = 127, + [0][1][1][0][RTW89_ETSI][0][75] = 127, + [0][1][1][0][RTW89_MKK][1][75] = 127, + [0][1][1][0][RTW89_MKK][0][75] = 127, + [0][1][1][0][RTW89_IC][1][75] = -2, + [0][1][1][0][RTW89_KCC][1][75] = 12, + [0][1][1][0][RTW89_KCC][0][75] = 127, + [0][1][1][0][RTW89_ACMA][1][75] = 127, + [0][1][1][0][RTW89_ACMA][0][75] = 127, + [0][1][1][0][RTW89_CHILE][1][75] = -2, + [0][1][1][0][RTW89_QATAR][1][75] = 127, + [0][1][1][0][RTW89_QATAR][0][75] = 127, + [0][1][1][0][RTW89_UK][1][75] = 127, + [0][1][1][0][RTW89_UK][0][75] = 127, + [0][1][1][0][RTW89_FCC][1][77] = -2, + [0][1][1][0][RTW89_FCC][2][77] = 68, + [0][1][1][0][RTW89_ETSI][1][77] = 127, + [0][1][1][0][RTW89_ETSI][0][77] = 127, + [0][1][1][0][RTW89_MKK][1][77] = 127, + [0][1][1][0][RTW89_MKK][0][77] = 127, + [0][1][1][0][RTW89_IC][1][77] = -2, + [0][1][1][0][RTW89_KCC][1][77] = 12, + [0][1][1][0][RTW89_KCC][0][77] = 127, + [0][1][1][0][RTW89_ACMA][1][77] = 127, + [0][1][1][0][RTW89_ACMA][0][77] = 127, + [0][1][1][0][RTW89_CHILE][1][77] = -2, + [0][1][1][0][RTW89_QATAR][1][77] = 127, + [0][1][1][0][RTW89_QATAR][0][77] = 127, + [0][1][1][0][RTW89_UK][1][77] = 127, + [0][1][1][0][RTW89_UK][0][77] = 127, + [0][1][1][0][RTW89_FCC][1][79] = -2, + [0][1][1][0][RTW89_FCC][2][79] = 68, + [0][1][1][0][RTW89_ETSI][1][79] = 127, + [0][1][1][0][RTW89_ETSI][0][79] = 127, + [0][1][1][0][RTW89_MKK][1][79] = 127, + [0][1][1][0][RTW89_MKK][0][79] = 127, + [0][1][1][0][RTW89_IC][1][79] = -2, + [0][1][1][0][RTW89_KCC][1][79] = 12, + [0][1][1][0][RTW89_KCC][0][79] = 127, + [0][1][1][0][RTW89_ACMA][1][79] = 127, + [0][1][1][0][RTW89_ACMA][0][79] = 127, + [0][1][1][0][RTW89_CHILE][1][79] = -2, + [0][1][1][0][RTW89_QATAR][1][79] = 127, + [0][1][1][0][RTW89_QATAR][0][79] = 127, + [0][1][1][0][RTW89_UK][1][79] = 127, + [0][1][1][0][RTW89_UK][0][79] = 127, + [0][1][1][0][RTW89_FCC][1][81] = -2, + [0][1][1][0][RTW89_FCC][2][81] = 68, + [0][1][1][0][RTW89_ETSI][1][81] = 127, + [0][1][1][0][RTW89_ETSI][0][81] = 127, + [0][1][1][0][RTW89_MKK][1][81] = 127, + [0][1][1][0][RTW89_MKK][0][81] = 127, + [0][1][1][0][RTW89_IC][1][81] = -2, + [0][1][1][0][RTW89_KCC][1][81] = 12, + [0][1][1][0][RTW89_KCC][0][81] = 127, + [0][1][1][0][RTW89_ACMA][1][81] = 127, + [0][1][1][0][RTW89_ACMA][0][81] = 127, + [0][1][1][0][RTW89_CHILE][1][81] = -2, + [0][1][1][0][RTW89_QATAR][1][81] = 127, + [0][1][1][0][RTW89_QATAR][0][81] = 127, + [0][1][1][0][RTW89_UK][1][81] = 127, + [0][1][1][0][RTW89_UK][0][81] = 127, + [0][1][1][0][RTW89_FCC][1][83] = -2, + [0][1][1][0][RTW89_FCC][2][83] = 68, + [0][1][1][0][RTW89_ETSI][1][83] = 127, + [0][1][1][0][RTW89_ETSI][0][83] = 127, + [0][1][1][0][RTW89_MKK][1][83] = 127, + [0][1][1][0][RTW89_MKK][0][83] = 127, + [0][1][1][0][RTW89_IC][1][83] = -2, + [0][1][1][0][RTW89_KCC][1][83] = 20, + [0][1][1][0][RTW89_KCC][0][83] = 127, + [0][1][1][0][RTW89_ACMA][1][83] = 127, + [0][1][1][0][RTW89_ACMA][0][83] = 127, + [0][1][1][0][RTW89_CHILE][1][83] = -2, + [0][1][1][0][RTW89_QATAR][1][83] = 127, + [0][1][1][0][RTW89_QATAR][0][83] = 127, + [0][1][1][0][RTW89_UK][1][83] = 127, + [0][1][1][0][RTW89_UK][0][83] = 127, + [0][1][1][0][RTW89_FCC][1][85] = -2, + [0][1][1][0][RTW89_FCC][2][85] = 68, + [0][1][1][0][RTW89_ETSI][1][85] = 127, + [0][1][1][0][RTW89_ETSI][0][85] = 127, + [0][1][1][0][RTW89_MKK][1][85] = 127, + [0][1][1][0][RTW89_MKK][0][85] = 127, + [0][1][1][0][RTW89_IC][1][85] = -2, + [0][1][1][0][RTW89_KCC][1][85] = 20, + [0][1][1][0][RTW89_KCC][0][85] = 127, + [0][1][1][0][RTW89_ACMA][1][85] = 127, + [0][1][1][0][RTW89_ACMA][0][85] = 127, + [0][1][1][0][RTW89_CHILE][1][85] = -2, + [0][1][1][0][RTW89_QATAR][1][85] = 127, + [0][1][1][0][RTW89_QATAR][0][85] = 127, + [0][1][1][0][RTW89_UK][1][85] = 127, + [0][1][1][0][RTW89_UK][0][85] = 127, + [0][1][1][0][RTW89_FCC][1][87] = -2, + [0][1][1][0][RTW89_FCC][2][87] = 127, + [0][1][1][0][RTW89_ETSI][1][87] = 127, + [0][1][1][0][RTW89_ETSI][0][87] = 127, + [0][1][1][0][RTW89_MKK][1][87] = 127, + [0][1][1][0][RTW89_MKK][0][87] = 127, + [0][1][1][0][RTW89_IC][1][87] = -2, + [0][1][1][0][RTW89_KCC][1][87] = 20, + [0][1][1][0][RTW89_KCC][0][87] = 127, + [0][1][1][0][RTW89_ACMA][1][87] = 127, + [0][1][1][0][RTW89_ACMA][0][87] = 127, + [0][1][1][0][RTW89_CHILE][1][87] = -2, + [0][1][1][0][RTW89_QATAR][1][87] = 127, + [0][1][1][0][RTW89_QATAR][0][87] = 127, + [0][1][1][0][RTW89_UK][1][87] = 127, + [0][1][1][0][RTW89_UK][0][87] = 127, + [0][1][1][0][RTW89_FCC][1][89] = -2, + [0][1][1][0][RTW89_FCC][2][89] = 127, + [0][1][1][0][RTW89_ETSI][1][89] = 127, + [0][1][1][0][RTW89_ETSI][0][89] = 127, + [0][1][1][0][RTW89_MKK][1][89] = 127, + [0][1][1][0][RTW89_MKK][0][89] = 127, + [0][1][1][0][RTW89_IC][1][89] = -2, + [0][1][1][0][RTW89_KCC][1][89] = 20, + [0][1][1][0][RTW89_KCC][0][89] = 127, + [0][1][1][0][RTW89_ACMA][1][89] = 127, + [0][1][1][0][RTW89_ACMA][0][89] = 127, + [0][1][1][0][RTW89_CHILE][1][89] = -2, + [0][1][1][0][RTW89_QATAR][1][89] = 127, + [0][1][1][0][RTW89_QATAR][0][89] = 127, + [0][1][1][0][RTW89_UK][1][89] = 127, + [0][1][1][0][RTW89_UK][0][89] = 127, + [0][1][1][0][RTW89_FCC][1][90] = -2, + [0][1][1][0][RTW89_FCC][2][90] = 127, + [0][1][1][0][RTW89_ETSI][1][90] = 127, + [0][1][1][0][RTW89_ETSI][0][90] = 127, + [0][1][1][0][RTW89_MKK][1][90] = 127, + [0][1][1][0][RTW89_MKK][0][90] = 127, + [0][1][1][0][RTW89_IC][1][90] = -2, + [0][1][1][0][RTW89_KCC][1][90] = 20, + [0][1][1][0][RTW89_KCC][0][90] = 127, + [0][1][1][0][RTW89_ACMA][1][90] = 127, + [0][1][1][0][RTW89_ACMA][0][90] = 127, + [0][1][1][0][RTW89_CHILE][1][90] = -2, + [0][1][1][0][RTW89_QATAR][1][90] = 127, + [0][1][1][0][RTW89_QATAR][0][90] = 127, + [0][1][1][0][RTW89_UK][1][90] = 127, + [0][1][1][0][RTW89_UK][0][90] = 127, + [0][1][1][0][RTW89_FCC][1][92] = -2, + [0][1][1][0][RTW89_FCC][2][92] = 127, + [0][1][1][0][RTW89_ETSI][1][92] = 127, + [0][1][1][0][RTW89_ETSI][0][92] = 127, + [0][1][1][0][RTW89_MKK][1][92] = 127, + [0][1][1][0][RTW89_MKK][0][92] = 127, + [0][1][1][0][RTW89_IC][1][92] = -2, + [0][1][1][0][RTW89_KCC][1][92] = 20, + [0][1][1][0][RTW89_KCC][0][92] = 127, + [0][1][1][0][RTW89_ACMA][1][92] = 127, + [0][1][1][0][RTW89_ACMA][0][92] = 127, + [0][1][1][0][RTW89_CHILE][1][92] = -2, + [0][1][1][0][RTW89_QATAR][1][92] = 127, + [0][1][1][0][RTW89_QATAR][0][92] = 127, + [0][1][1][0][RTW89_UK][1][92] = 127, + [0][1][1][0][RTW89_UK][0][92] = 127, + [0][1][1][0][RTW89_FCC][1][94] = -2, + [0][1][1][0][RTW89_FCC][2][94] = 127, + [0][1][1][0][RTW89_ETSI][1][94] = 127, + [0][1][1][0][RTW89_ETSI][0][94] = 127, + [0][1][1][0][RTW89_MKK][1][94] = 127, + [0][1][1][0][RTW89_MKK][0][94] = 127, + [0][1][1][0][RTW89_IC][1][94] = -2, + [0][1][1][0][RTW89_KCC][1][94] = 20, + [0][1][1][0][RTW89_KCC][0][94] = 127, + [0][1][1][0][RTW89_ACMA][1][94] = 127, + [0][1][1][0][RTW89_ACMA][0][94] = 127, + [0][1][1][0][RTW89_CHILE][1][94] = -2, + [0][1][1][0][RTW89_QATAR][1][94] = 127, + [0][1][1][0][RTW89_QATAR][0][94] = 127, + [0][1][1][0][RTW89_UK][1][94] = 127, + [0][1][1][0][RTW89_UK][0][94] = 127, + [0][1][1][0][RTW89_FCC][1][96] = -2, + [0][1][1][0][RTW89_FCC][2][96] = 127, + [0][1][1][0][RTW89_ETSI][1][96] = 127, + [0][1][1][0][RTW89_ETSI][0][96] = 127, + [0][1][1][0][RTW89_MKK][1][96] = 127, + [0][1][1][0][RTW89_MKK][0][96] = 127, + [0][1][1][0][RTW89_IC][1][96] = -2, + [0][1][1][0][RTW89_KCC][1][96] = 20, + [0][1][1][0][RTW89_KCC][0][96] = 127, + [0][1][1][0][RTW89_ACMA][1][96] = 127, + [0][1][1][0][RTW89_ACMA][0][96] = 127, + [0][1][1][0][RTW89_CHILE][1][96] = -2, + [0][1][1][0][RTW89_QATAR][1][96] = 127, + [0][1][1][0][RTW89_QATAR][0][96] = 127, + [0][1][1][0][RTW89_UK][1][96] = 127, + [0][1][1][0][RTW89_UK][0][96] = 127, + [0][1][1][0][RTW89_FCC][1][98] = -2, + [0][1][1][0][RTW89_FCC][2][98] = 127, + [0][1][1][0][RTW89_ETSI][1][98] = 127, + [0][1][1][0][RTW89_ETSI][0][98] = 127, + [0][1][1][0][RTW89_MKK][1][98] = 127, + [0][1][1][0][RTW89_MKK][0][98] = 127, + [0][1][1][0][RTW89_IC][1][98] = -2, + [0][1][1][0][RTW89_KCC][1][98] = 20, + [0][1][1][0][RTW89_KCC][0][98] = 127, + [0][1][1][0][RTW89_ACMA][1][98] = 127, + [0][1][1][0][RTW89_ACMA][0][98] = 127, + [0][1][1][0][RTW89_CHILE][1][98] = -2, + [0][1][1][0][RTW89_QATAR][1][98] = 127, + [0][1][1][0][RTW89_QATAR][0][98] = 127, + [0][1][1][0][RTW89_UK][1][98] = 127, + [0][1][1][0][RTW89_UK][0][98] = 127, + [0][1][1][0][RTW89_FCC][1][100] = -2, + [0][1][1][0][RTW89_FCC][2][100] = 127, + [0][1][1][0][RTW89_ETSI][1][100] = 127, + [0][1][1][0][RTW89_ETSI][0][100] = 127, + [0][1][1][0][RTW89_MKK][1][100] = 127, + [0][1][1][0][RTW89_MKK][0][100] = 127, + [0][1][1][0][RTW89_IC][1][100] = -2, + [0][1][1][0][RTW89_KCC][1][100] = 20, + [0][1][1][0][RTW89_KCC][0][100] = 127, + [0][1][1][0][RTW89_ACMA][1][100] = 127, + [0][1][1][0][RTW89_ACMA][0][100] = 127, + [0][1][1][0][RTW89_CHILE][1][100] = -2, + [0][1][1][0][RTW89_QATAR][1][100] = 127, + [0][1][1][0][RTW89_QATAR][0][100] = 127, + [0][1][1][0][RTW89_UK][1][100] = 127, + [0][1][1][0][RTW89_UK][0][100] = 127, + [0][1][1][0][RTW89_FCC][1][102] = -2, + [0][1][1][0][RTW89_FCC][2][102] = 127, + [0][1][1][0][RTW89_ETSI][1][102] = 127, + [0][1][1][0][RTW89_ETSI][0][102] = 127, + [0][1][1][0][RTW89_MKK][1][102] = 127, + [0][1][1][0][RTW89_MKK][0][102] = 127, + [0][1][1][0][RTW89_IC][1][102] = -2, + [0][1][1][0][RTW89_KCC][1][102] = 20, + [0][1][1][0][RTW89_KCC][0][102] = 127, + [0][1][1][0][RTW89_ACMA][1][102] = 127, + [0][1][1][0][RTW89_ACMA][0][102] = 127, + [0][1][1][0][RTW89_CHILE][1][102] = -2, + [0][1][1][0][RTW89_QATAR][1][102] = 127, + [0][1][1][0][RTW89_QATAR][0][102] = 127, + [0][1][1][0][RTW89_UK][1][102] = 127, + [0][1][1][0][RTW89_UK][0][102] = 127, + [0][1][1][0][RTW89_FCC][1][104] = -2, + [0][1][1][0][RTW89_FCC][2][104] = 127, + [0][1][1][0][RTW89_ETSI][1][104] = 127, + [0][1][1][0][RTW89_ETSI][0][104] = 127, + [0][1][1][0][RTW89_MKK][1][104] = 127, + [0][1][1][0][RTW89_MKK][0][104] = 127, + [0][1][1][0][RTW89_IC][1][104] = -2, + [0][1][1][0][RTW89_KCC][1][104] = 20, + [0][1][1][0][RTW89_KCC][0][104] = 127, + [0][1][1][0][RTW89_ACMA][1][104] = 127, + [0][1][1][0][RTW89_ACMA][0][104] = 127, + [0][1][1][0][RTW89_CHILE][1][104] = -2, + [0][1][1][0][RTW89_QATAR][1][104] = 127, + [0][1][1][0][RTW89_QATAR][0][104] = 127, + [0][1][1][0][RTW89_UK][1][104] = 127, + [0][1][1][0][RTW89_UK][0][104] = 127, + [0][1][1][0][RTW89_FCC][1][105] = -2, + [0][1][1][0][RTW89_FCC][2][105] = 127, + [0][1][1][0][RTW89_ETSI][1][105] = 127, + [0][1][1][0][RTW89_ETSI][0][105] = 127, + [0][1][1][0][RTW89_MKK][1][105] = 127, + [0][1][1][0][RTW89_MKK][0][105] = 127, + [0][1][1][0][RTW89_IC][1][105] = -2, + [0][1][1][0][RTW89_KCC][1][105] = 20, + [0][1][1][0][RTW89_KCC][0][105] = 127, + [0][1][1][0][RTW89_ACMA][1][105] = 127, + [0][1][1][0][RTW89_ACMA][0][105] = 127, + [0][1][1][0][RTW89_CHILE][1][105] = -2, + [0][1][1][0][RTW89_QATAR][1][105] = 127, + [0][1][1][0][RTW89_QATAR][0][105] = 127, + [0][1][1][0][RTW89_UK][1][105] = 127, + [0][1][1][0][RTW89_UK][0][105] = 127, + [0][1][1][0][RTW89_FCC][1][107] = 1, + [0][1][1][0][RTW89_FCC][2][107] = 127, + [0][1][1][0][RTW89_ETSI][1][107] = 127, + [0][1][1][0][RTW89_ETSI][0][107] = 127, + [0][1][1][0][RTW89_MKK][1][107] = 127, + [0][1][1][0][RTW89_MKK][0][107] = 127, + [0][1][1][0][RTW89_IC][1][107] = 1, + [0][1][1][0][RTW89_KCC][1][107] = 20, + [0][1][1][0][RTW89_KCC][0][107] = 127, + [0][1][1][0][RTW89_ACMA][1][107] = 127, + [0][1][1][0][RTW89_ACMA][0][107] = 127, + [0][1][1][0][RTW89_CHILE][1][107] = 1, + [0][1][1][0][RTW89_QATAR][1][107] = 127, + [0][1][1][0][RTW89_QATAR][0][107] = 127, + [0][1][1][0][RTW89_UK][1][107] = 127, + [0][1][1][0][RTW89_UK][0][107] = 127, + [0][1][1][0][RTW89_FCC][1][109] = 1, + [0][1][1][0][RTW89_FCC][2][109] = 127, + [0][1][1][0][RTW89_ETSI][1][109] = 127, + [0][1][1][0][RTW89_ETSI][0][109] = 127, + [0][1][1][0][RTW89_MKK][1][109] = 127, + [0][1][1][0][RTW89_MKK][0][109] = 127, + [0][1][1][0][RTW89_IC][1][109] = 1, + [0][1][1][0][RTW89_KCC][1][109] = 20, + [0][1][1][0][RTW89_KCC][0][109] = 127, + [0][1][1][0][RTW89_ACMA][1][109] = 127, + [0][1][1][0][RTW89_ACMA][0][109] = 127, + [0][1][1][0][RTW89_CHILE][1][109] = 1, + [0][1][1][0][RTW89_QATAR][1][109] = 127, + [0][1][1][0][RTW89_QATAR][0][109] = 127, + [0][1][1][0][RTW89_UK][1][109] = 127, + [0][1][1][0][RTW89_UK][0][109] = 127, + [0][1][1][0][RTW89_FCC][1][111] = 127, + [0][1][1][0][RTW89_FCC][2][111] = 127, + [0][1][1][0][RTW89_ETSI][1][111] = 127, + [0][1][1][0][RTW89_ETSI][0][111] = 127, + [0][1][1][0][RTW89_MKK][1][111] = 127, + [0][1][1][0][RTW89_MKK][0][111] = 127, + [0][1][1][0][RTW89_IC][1][111] = 127, + [0][1][1][0][RTW89_KCC][1][111] = 127, + [0][1][1][0][RTW89_KCC][0][111] = 127, + [0][1][1][0][RTW89_ACMA][1][111] = 127, + [0][1][1][0][RTW89_ACMA][0][111] = 127, + [0][1][1][0][RTW89_CHILE][1][111] = 127, + [0][1][1][0][RTW89_QATAR][1][111] = 127, + [0][1][1][0][RTW89_QATAR][0][111] = 127, + [0][1][1][0][RTW89_UK][1][111] = 127, + [0][1][1][0][RTW89_UK][0][111] = 127, + [0][1][1][0][RTW89_FCC][1][113] = 127, + [0][1][1][0][RTW89_FCC][2][113] = 127, + [0][1][1][0][RTW89_ETSI][1][113] = 127, + [0][1][1][0][RTW89_ETSI][0][113] = 127, + [0][1][1][0][RTW89_MKK][1][113] = 127, + [0][1][1][0][RTW89_MKK][0][113] = 127, + [0][1][1][0][RTW89_IC][1][113] = 127, + [0][1][1][0][RTW89_KCC][1][113] = 127, + [0][1][1][0][RTW89_KCC][0][113] = 127, + [0][1][1][0][RTW89_ACMA][1][113] = 127, + [0][1][1][0][RTW89_ACMA][0][113] = 127, + [0][1][1][0][RTW89_CHILE][1][113] = 127, + [0][1][1][0][RTW89_QATAR][1][113] = 127, + [0][1][1][0][RTW89_QATAR][0][113] = 127, + [0][1][1][0][RTW89_UK][1][113] = 127, + [0][1][1][0][RTW89_UK][0][113] = 127, + [0][1][1][0][RTW89_FCC][1][115] = 127, + [0][1][1][0][RTW89_FCC][2][115] = 127, + [0][1][1][0][RTW89_ETSI][1][115] = 127, + [0][1][1][0][RTW89_ETSI][0][115] = 127, + [0][1][1][0][RTW89_MKK][1][115] = 127, + [0][1][1][0][RTW89_MKK][0][115] = 127, + [0][1][1][0][RTW89_IC][1][115] = 127, + [0][1][1][0][RTW89_KCC][1][115] = 127, + [0][1][1][0][RTW89_KCC][0][115] = 127, + [0][1][1][0][RTW89_ACMA][1][115] = 127, + [0][1][1][0][RTW89_ACMA][0][115] = 127, + [0][1][1][0][RTW89_CHILE][1][115] = 127, + [0][1][1][0][RTW89_QATAR][1][115] = 127, + [0][1][1][0][RTW89_QATAR][0][115] = 127, + [0][1][1][0][RTW89_UK][1][115] = 127, + [0][1][1][0][RTW89_UK][0][115] = 127, + [0][1][1][0][RTW89_FCC][1][117] = 127, + [0][1][1][0][RTW89_FCC][2][117] = 127, + [0][1][1][0][RTW89_ETSI][1][117] = 127, + [0][1][1][0][RTW89_ETSI][0][117] = 127, + [0][1][1][0][RTW89_MKK][1][117] = 127, + [0][1][1][0][RTW89_MKK][0][117] = 127, + [0][1][1][0][RTW89_IC][1][117] = 127, + [0][1][1][0][RTW89_KCC][1][117] = 127, + [0][1][1][0][RTW89_KCC][0][117] = 127, + [0][1][1][0][RTW89_ACMA][1][117] = 127, + [0][1][1][0][RTW89_ACMA][0][117] = 127, + [0][1][1][0][RTW89_CHILE][1][117] = 127, + [0][1][1][0][RTW89_QATAR][1][117] = 127, + [0][1][1][0][RTW89_QATAR][0][117] = 127, + [0][1][1][0][RTW89_UK][1][117] = 127, + [0][1][1][0][RTW89_UK][0][117] = 127, + [0][1][1][0][RTW89_FCC][1][119] = 127, + [0][1][1][0][RTW89_FCC][2][119] = 127, + [0][1][1][0][RTW89_ETSI][1][119] = 127, + [0][1][1][0][RTW89_ETSI][0][119] = 127, + [0][1][1][0][RTW89_MKK][1][119] = 127, + [0][1][1][0][RTW89_MKK][0][119] = 127, + [0][1][1][0][RTW89_IC][1][119] = 127, + [0][1][1][0][RTW89_KCC][1][119] = 127, + [0][1][1][0][RTW89_KCC][0][119] = 127, + [0][1][1][0][RTW89_ACMA][1][119] = 127, + [0][1][1][0][RTW89_ACMA][0][119] = 127, + [0][1][1][0][RTW89_CHILE][1][119] = 127, + [0][1][1][0][RTW89_QATAR][1][119] = 127, + [0][1][1][0][RTW89_QATAR][0][119] = 127, + [0][1][1][0][RTW89_UK][1][119] = 127, + [0][1][1][0][RTW89_UK][0][119] = 127, + [0][0][2][0][RTW89_FCC][1][0] = 24, + [0][0][2][0][RTW89_FCC][2][0] = 56, + [0][0][2][0][RTW89_ETSI][1][0] = 66, + [0][0][2][0][RTW89_ETSI][0][0] = 28, + [0][0][2][0][RTW89_MKK][1][0] = 66, + [0][0][2][0][RTW89_MKK][0][0] = 26, + [0][0][2][0][RTW89_IC][1][0] = 24, + [0][0][2][0][RTW89_KCC][1][0] = 24, + [0][0][2][0][RTW89_KCC][0][0] = 24, + [0][0][2][0][RTW89_ACMA][1][0] = 66, + [0][0][2][0][RTW89_ACMA][0][0] = 28, + [0][0][2][0][RTW89_CHILE][1][0] = 24, + [0][0][2][0][RTW89_QATAR][1][0] = 66, + [0][0][2][0][RTW89_QATAR][0][0] = 28, + [0][0][2][0][RTW89_UK][1][0] = 66, + [0][0][2][0][RTW89_UK][0][0] = 28, + [0][0][2][0][RTW89_FCC][1][2] = 22, + [0][0][2][0][RTW89_FCC][2][2] = 56, + [0][0][2][0][RTW89_ETSI][1][2] = 66, + [0][0][2][0][RTW89_ETSI][0][2] = 28, + [0][0][2][0][RTW89_MKK][1][2] = 66, + [0][0][2][0][RTW89_MKK][0][2] = 26, + [0][0][2][0][RTW89_IC][1][2] = 22, + [0][0][2][0][RTW89_KCC][1][2] = 24, + [0][0][2][0][RTW89_KCC][0][2] = 24, + [0][0][2][0][RTW89_ACMA][1][2] = 66, + [0][0][2][0][RTW89_ACMA][0][2] = 28, + [0][0][2][0][RTW89_CHILE][1][2] = 22, + [0][0][2][0][RTW89_QATAR][1][2] = 66, + [0][0][2][0][RTW89_QATAR][0][2] = 28, + [0][0][2][0][RTW89_UK][1][2] = 66, + [0][0][2][0][RTW89_UK][0][2] = 28, + [0][0][2][0][RTW89_FCC][1][4] = 22, + [0][0][2][0][RTW89_FCC][2][4] = 56, + [0][0][2][0][RTW89_ETSI][1][4] = 66, + [0][0][2][0][RTW89_ETSI][0][4] = 28, + [0][0][2][0][RTW89_MKK][1][4] = 66, + [0][0][2][0][RTW89_MKK][0][4] = 26, + [0][0][2][0][RTW89_IC][1][4] = 22, + [0][0][2][0][RTW89_KCC][1][4] = 24, + [0][0][2][0][RTW89_KCC][0][4] = 24, + [0][0][2][0][RTW89_ACMA][1][4] = 66, + [0][0][2][0][RTW89_ACMA][0][4] = 28, + [0][0][2][0][RTW89_CHILE][1][4] = 22, + [0][0][2][0][RTW89_QATAR][1][4] = 66, + [0][0][2][0][RTW89_QATAR][0][4] = 28, + [0][0][2][0][RTW89_UK][1][4] = 66, + [0][0][2][0][RTW89_UK][0][4] = 28, + [0][0][2][0][RTW89_FCC][1][6] = 22, + [0][0][2][0][RTW89_FCC][2][6] = 56, + [0][0][2][0][RTW89_ETSI][1][6] = 66, + [0][0][2][0][RTW89_ETSI][0][6] = 28, + [0][0][2][0][RTW89_MKK][1][6] = 66, + [0][0][2][0][RTW89_MKK][0][6] = 26, + [0][0][2][0][RTW89_IC][1][6] = 22, + [0][0][2][0][RTW89_KCC][1][6] = 24, + [0][0][2][0][RTW89_KCC][0][6] = 24, + [0][0][2][0][RTW89_ACMA][1][6] = 66, + [0][0][2][0][RTW89_ACMA][0][6] = 28, + [0][0][2][0][RTW89_CHILE][1][6] = 22, + [0][0][2][0][RTW89_QATAR][1][6] = 66, + [0][0][2][0][RTW89_QATAR][0][6] = 28, + [0][0][2][0][RTW89_UK][1][6] = 66, + [0][0][2][0][RTW89_UK][0][6] = 28, + [0][0][2][0][RTW89_FCC][1][8] = 22, + [0][0][2][0][RTW89_FCC][2][8] = 56, + [0][0][2][0][RTW89_ETSI][1][8] = 66, + [0][0][2][0][RTW89_ETSI][0][8] = 28, + [0][0][2][0][RTW89_MKK][1][8] = 66, + [0][0][2][0][RTW89_MKK][0][8] = 26, + [0][0][2][0][RTW89_IC][1][8] = 22, + [0][0][2][0][RTW89_KCC][1][8] = 24, + [0][0][2][0][RTW89_KCC][0][8] = 24, + [0][0][2][0][RTW89_ACMA][1][8] = 66, + [0][0][2][0][RTW89_ACMA][0][8] = 28, + [0][0][2][0][RTW89_CHILE][1][8] = 22, + [0][0][2][0][RTW89_QATAR][1][8] = 66, + [0][0][2][0][RTW89_QATAR][0][8] = 28, + [0][0][2][0][RTW89_UK][1][8] = 66, + [0][0][2][0][RTW89_UK][0][8] = 28, + [0][0][2][0][RTW89_FCC][1][10] = 22, + [0][0][2][0][RTW89_FCC][2][10] = 56, + [0][0][2][0][RTW89_ETSI][1][10] = 66, + [0][0][2][0][RTW89_ETSI][0][10] = 28, + [0][0][2][0][RTW89_MKK][1][10] = 66, + [0][0][2][0][RTW89_MKK][0][10] = 26, + [0][0][2][0][RTW89_IC][1][10] = 22, + [0][0][2][0][RTW89_KCC][1][10] = 24, + [0][0][2][0][RTW89_KCC][0][10] = 24, + [0][0][2][0][RTW89_ACMA][1][10] = 66, + [0][0][2][0][RTW89_ACMA][0][10] = 28, + [0][0][2][0][RTW89_CHILE][1][10] = 22, + [0][0][2][0][RTW89_QATAR][1][10] = 66, + [0][0][2][0][RTW89_QATAR][0][10] = 28, + [0][0][2][0][RTW89_UK][1][10] = 66, + [0][0][2][0][RTW89_UK][0][10] = 28, + [0][0][2][0][RTW89_FCC][1][12] = 22, + [0][0][2][0][RTW89_FCC][2][12] = 56, + [0][0][2][0][RTW89_ETSI][1][12] = 66, + [0][0][2][0][RTW89_ETSI][0][12] = 28, + [0][0][2][0][RTW89_MKK][1][12] = 66, + [0][0][2][0][RTW89_MKK][0][12] = 26, + [0][0][2][0][RTW89_IC][1][12] = 22, + [0][0][2][0][RTW89_KCC][1][12] = 24, + [0][0][2][0][RTW89_KCC][0][12] = 24, + [0][0][2][0][RTW89_ACMA][1][12] = 66, + [0][0][2][0][RTW89_ACMA][0][12] = 28, + [0][0][2][0][RTW89_CHILE][1][12] = 22, + [0][0][2][0][RTW89_QATAR][1][12] = 66, + [0][0][2][0][RTW89_QATAR][0][12] = 28, + [0][0][2][0][RTW89_UK][1][12] = 66, + [0][0][2][0][RTW89_UK][0][12] = 28, + [0][0][2][0][RTW89_FCC][1][14] = 22, + [0][0][2][0][RTW89_FCC][2][14] = 56, + [0][0][2][0][RTW89_ETSI][1][14] = 66, + [0][0][2][0][RTW89_ETSI][0][14] = 28, + [0][0][2][0][RTW89_MKK][1][14] = 66, + [0][0][2][0][RTW89_MKK][0][14] = 26, + [0][0][2][0][RTW89_IC][1][14] = 22, + [0][0][2][0][RTW89_KCC][1][14] = 24, + [0][0][2][0][RTW89_KCC][0][14] = 24, + [0][0][2][0][RTW89_ACMA][1][14] = 66, + [0][0][2][0][RTW89_ACMA][0][14] = 28, + [0][0][2][0][RTW89_CHILE][1][14] = 22, + [0][0][2][0][RTW89_QATAR][1][14] = 66, + [0][0][2][0][RTW89_QATAR][0][14] = 28, + [0][0][2][0][RTW89_UK][1][14] = 66, + [0][0][2][0][RTW89_UK][0][14] = 28, + [0][0][2][0][RTW89_FCC][1][15] = 22, + [0][0][2][0][RTW89_FCC][2][15] = 56, + [0][0][2][0][RTW89_ETSI][1][15] = 66, + [0][0][2][0][RTW89_ETSI][0][15] = 28, + [0][0][2][0][RTW89_MKK][1][15] = 66, + [0][0][2][0][RTW89_MKK][0][15] = 26, + [0][0][2][0][RTW89_IC][1][15] = 22, + [0][0][2][0][RTW89_KCC][1][15] = 24, + [0][0][2][0][RTW89_KCC][0][15] = 24, + [0][0][2][0][RTW89_ACMA][1][15] = 66, + [0][0][2][0][RTW89_ACMA][0][15] = 28, + [0][0][2][0][RTW89_CHILE][1][15] = 22, + [0][0][2][0][RTW89_QATAR][1][15] = 66, + [0][0][2][0][RTW89_QATAR][0][15] = 28, + [0][0][2][0][RTW89_UK][1][15] = 66, + [0][0][2][0][RTW89_UK][0][15] = 28, + [0][0][2][0][RTW89_FCC][1][17] = 22, + [0][0][2][0][RTW89_FCC][2][17] = 56, + [0][0][2][0][RTW89_ETSI][1][17] = 66, + [0][0][2][0][RTW89_ETSI][0][17] = 28, + [0][0][2][0][RTW89_MKK][1][17] = 66, + [0][0][2][0][RTW89_MKK][0][17] = 26, + [0][0][2][0][RTW89_IC][1][17] = 22, + [0][0][2][0][RTW89_KCC][1][17] = 24, + [0][0][2][0][RTW89_KCC][0][17] = 24, + [0][0][2][0][RTW89_ACMA][1][17] = 66, + [0][0][2][0][RTW89_ACMA][0][17] = 28, + [0][0][2][0][RTW89_CHILE][1][17] = 22, + [0][0][2][0][RTW89_QATAR][1][17] = 66, + [0][0][2][0][RTW89_QATAR][0][17] = 28, + [0][0][2][0][RTW89_UK][1][17] = 66, + [0][0][2][0][RTW89_UK][0][17] = 28, + [0][0][2][0][RTW89_FCC][1][19] = 22, + [0][0][2][0][RTW89_FCC][2][19] = 56, + [0][0][2][0][RTW89_ETSI][1][19] = 66, + [0][0][2][0][RTW89_ETSI][0][19] = 28, + [0][0][2][0][RTW89_MKK][1][19] = 66, + [0][0][2][0][RTW89_MKK][0][19] = 26, + [0][0][2][0][RTW89_IC][1][19] = 22, + [0][0][2][0][RTW89_KCC][1][19] = 24, + [0][0][2][0][RTW89_KCC][0][19] = 24, + [0][0][2][0][RTW89_ACMA][1][19] = 66, + [0][0][2][0][RTW89_ACMA][0][19] = 28, + [0][0][2][0][RTW89_CHILE][1][19] = 22, + [0][0][2][0][RTW89_QATAR][1][19] = 66, + [0][0][2][0][RTW89_QATAR][0][19] = 28, + [0][0][2][0][RTW89_UK][1][19] = 66, + [0][0][2][0][RTW89_UK][0][19] = 28, + [0][0][2][0][RTW89_FCC][1][21] = 22, + [0][0][2][0][RTW89_FCC][2][21] = 56, + [0][0][2][0][RTW89_ETSI][1][21] = 66, + [0][0][2][0][RTW89_ETSI][0][21] = 28, + [0][0][2][0][RTW89_MKK][1][21] = 66, + [0][0][2][0][RTW89_MKK][0][21] = 26, + [0][0][2][0][RTW89_IC][1][21] = 22, + [0][0][2][0][RTW89_KCC][1][21] = 24, + [0][0][2][0][RTW89_KCC][0][21] = 24, + [0][0][2][0][RTW89_ACMA][1][21] = 66, + [0][0][2][0][RTW89_ACMA][0][21] = 28, + [0][0][2][0][RTW89_CHILE][1][21] = 22, + [0][0][2][0][RTW89_QATAR][1][21] = 66, + [0][0][2][0][RTW89_QATAR][0][21] = 28, + [0][0][2][0][RTW89_UK][1][21] = 66, + [0][0][2][0][RTW89_UK][0][21] = 28, + [0][0][2][0][RTW89_FCC][1][23] = 22, + [0][0][2][0][RTW89_FCC][2][23] = 70, + [0][0][2][0][RTW89_ETSI][1][23] = 66, + [0][0][2][0][RTW89_ETSI][0][23] = 28, + [0][0][2][0][RTW89_MKK][1][23] = 66, + [0][0][2][0][RTW89_MKK][0][23] = 26, + [0][0][2][0][RTW89_IC][1][23] = 22, + [0][0][2][0][RTW89_KCC][1][23] = 24, + [0][0][2][0][RTW89_KCC][0][23] = 26, + [0][0][2][0][RTW89_ACMA][1][23] = 66, + [0][0][2][0][RTW89_ACMA][0][23] = 28, + [0][0][2][0][RTW89_CHILE][1][23] = 22, + [0][0][2][0][RTW89_QATAR][1][23] = 66, + [0][0][2][0][RTW89_QATAR][0][23] = 28, + [0][0][2][0][RTW89_UK][1][23] = 66, + [0][0][2][0][RTW89_UK][0][23] = 28, + [0][0][2][0][RTW89_FCC][1][25] = 22, + [0][0][2][0][RTW89_FCC][2][25] = 70, + [0][0][2][0][RTW89_ETSI][1][25] = 66, + [0][0][2][0][RTW89_ETSI][0][25] = 28, + [0][0][2][0][RTW89_MKK][1][25] = 66, + [0][0][2][0][RTW89_MKK][0][25] = 26, + [0][0][2][0][RTW89_IC][1][25] = 22, + [0][0][2][0][RTW89_KCC][1][25] = 24, + [0][0][2][0][RTW89_KCC][0][25] = 26, + [0][0][2][0][RTW89_ACMA][1][25] = 66, + [0][0][2][0][RTW89_ACMA][0][25] = 28, + [0][0][2][0][RTW89_CHILE][1][25] = 22, + [0][0][2][0][RTW89_QATAR][1][25] = 66, + [0][0][2][0][RTW89_QATAR][0][25] = 28, + [0][0][2][0][RTW89_UK][1][25] = 66, + [0][0][2][0][RTW89_UK][0][25] = 28, + [0][0][2][0][RTW89_FCC][1][27] = 22, + [0][0][2][0][RTW89_FCC][2][27] = 70, + [0][0][2][0][RTW89_ETSI][1][27] = 66, + [0][0][2][0][RTW89_ETSI][0][27] = 28, + [0][0][2][0][RTW89_MKK][1][27] = 66, + [0][0][2][0][RTW89_MKK][0][27] = 26, + [0][0][2][0][RTW89_IC][1][27] = 22, + [0][0][2][0][RTW89_KCC][1][27] = 24, + [0][0][2][0][RTW89_KCC][0][27] = 26, + [0][0][2][0][RTW89_ACMA][1][27] = 66, + [0][0][2][0][RTW89_ACMA][0][27] = 28, + [0][0][2][0][RTW89_CHILE][1][27] = 22, + [0][0][2][0][RTW89_QATAR][1][27] = 66, + [0][0][2][0][RTW89_QATAR][0][27] = 28, + [0][0][2][0][RTW89_UK][1][27] = 66, + [0][0][2][0][RTW89_UK][0][27] = 28, + [0][0][2][0][RTW89_FCC][1][29] = 22, + [0][0][2][0][RTW89_FCC][2][29] = 70, + [0][0][2][0][RTW89_ETSI][1][29] = 66, + [0][0][2][0][RTW89_ETSI][0][29] = 28, + [0][0][2][0][RTW89_MKK][1][29] = 66, + [0][0][2][0][RTW89_MKK][0][29] = 26, + [0][0][2][0][RTW89_IC][1][29] = 22, + [0][0][2][0][RTW89_KCC][1][29] = 24, + [0][0][2][0][RTW89_KCC][0][29] = 26, + [0][0][2][0][RTW89_ACMA][1][29] = 66, + [0][0][2][0][RTW89_ACMA][0][29] = 28, + [0][0][2][0][RTW89_CHILE][1][29] = 22, + [0][0][2][0][RTW89_QATAR][1][29] = 66, + [0][0][2][0][RTW89_QATAR][0][29] = 28, + [0][0][2][0][RTW89_UK][1][29] = 66, + [0][0][2][0][RTW89_UK][0][29] = 28, + [0][0][2][0][RTW89_FCC][1][30] = 22, + [0][0][2][0][RTW89_FCC][2][30] = 70, + [0][0][2][0][RTW89_ETSI][1][30] = 66, + [0][0][2][0][RTW89_ETSI][0][30] = 28, + [0][0][2][0][RTW89_MKK][1][30] = 66, + [0][0][2][0][RTW89_MKK][0][30] = 26, + [0][0][2][0][RTW89_IC][1][30] = 22, + [0][0][2][0][RTW89_KCC][1][30] = 24, + [0][0][2][0][RTW89_KCC][0][30] = 26, + [0][0][2][0][RTW89_ACMA][1][30] = 66, + [0][0][2][0][RTW89_ACMA][0][30] = 28, + [0][0][2][0][RTW89_CHILE][1][30] = 22, + [0][0][2][0][RTW89_QATAR][1][30] = 66, + [0][0][2][0][RTW89_QATAR][0][30] = 28, + [0][0][2][0][RTW89_UK][1][30] = 66, + [0][0][2][0][RTW89_UK][0][30] = 28, + [0][0][2][0][RTW89_FCC][1][32] = 22, + [0][0][2][0][RTW89_FCC][2][32] = 70, + [0][0][2][0][RTW89_ETSI][1][32] = 66, + [0][0][2][0][RTW89_ETSI][0][32] = 28, + [0][0][2][0][RTW89_MKK][1][32] = 66, + [0][0][2][0][RTW89_MKK][0][32] = 26, + [0][0][2][0][RTW89_IC][1][32] = 22, + [0][0][2][0][RTW89_KCC][1][32] = 24, + [0][0][2][0][RTW89_KCC][0][32] = 26, + [0][0][2][0][RTW89_ACMA][1][32] = 66, + [0][0][2][0][RTW89_ACMA][0][32] = 28, + [0][0][2][0][RTW89_CHILE][1][32] = 22, + [0][0][2][0][RTW89_QATAR][1][32] = 66, + [0][0][2][0][RTW89_QATAR][0][32] = 28, + [0][0][2][0][RTW89_UK][1][32] = 66, + [0][0][2][0][RTW89_UK][0][32] = 28, + [0][0][2][0][RTW89_FCC][1][34] = 22, + [0][0][2][0][RTW89_FCC][2][34] = 70, + [0][0][2][0][RTW89_ETSI][1][34] = 66, + [0][0][2][0][RTW89_ETSI][0][34] = 28, + [0][0][2][0][RTW89_MKK][1][34] = 66, + [0][0][2][0][RTW89_MKK][0][34] = 26, + [0][0][2][0][RTW89_IC][1][34] = 22, + [0][0][2][0][RTW89_KCC][1][34] = 24, + [0][0][2][0][RTW89_KCC][0][34] = 26, + [0][0][2][0][RTW89_ACMA][1][34] = 66, + [0][0][2][0][RTW89_ACMA][0][34] = 28, + [0][0][2][0][RTW89_CHILE][1][34] = 22, + [0][0][2][0][RTW89_QATAR][1][34] = 66, + [0][0][2][0][RTW89_QATAR][0][34] = 28, + [0][0][2][0][RTW89_UK][1][34] = 66, + [0][0][2][0][RTW89_UK][0][34] = 28, + [0][0][2][0][RTW89_FCC][1][36] = 22, + [0][0][2][0][RTW89_FCC][2][36] = 70, + [0][0][2][0][RTW89_ETSI][1][36] = 66, + [0][0][2][0][RTW89_ETSI][0][36] = 28, + [0][0][2][0][RTW89_MKK][1][36] = 66, + [0][0][2][0][RTW89_MKK][0][36] = 26, + [0][0][2][0][RTW89_IC][1][36] = 22, + [0][0][2][0][RTW89_KCC][1][36] = 24, + [0][0][2][0][RTW89_KCC][0][36] = 26, + [0][0][2][0][RTW89_ACMA][1][36] = 66, + [0][0][2][0][RTW89_ACMA][0][36] = 28, + [0][0][2][0][RTW89_CHILE][1][36] = 22, + [0][0][2][0][RTW89_QATAR][1][36] = 66, + [0][0][2][0][RTW89_QATAR][0][36] = 28, + [0][0][2][0][RTW89_UK][1][36] = 66, + [0][0][2][0][RTW89_UK][0][36] = 28, + [0][0][2][0][RTW89_FCC][1][38] = 22, + [0][0][2][0][RTW89_FCC][2][38] = 70, + [0][0][2][0][RTW89_ETSI][1][38] = 66, + [0][0][2][0][RTW89_ETSI][0][38] = 28, + [0][0][2][0][RTW89_MKK][1][38] = 66, + [0][0][2][0][RTW89_MKK][0][38] = 26, + [0][0][2][0][RTW89_IC][1][38] = 22, + [0][0][2][0][RTW89_KCC][1][38] = 24, + [0][0][2][0][RTW89_KCC][0][38] = 26, + [0][0][2][0][RTW89_ACMA][1][38] = 66, + [0][0][2][0][RTW89_ACMA][0][38] = 28, + [0][0][2][0][RTW89_CHILE][1][38] = 22, + [0][0][2][0][RTW89_QATAR][1][38] = 66, + [0][0][2][0][RTW89_QATAR][0][38] = 28, + [0][0][2][0][RTW89_UK][1][38] = 66, + [0][0][2][0][RTW89_UK][0][38] = 28, + [0][0][2][0][RTW89_FCC][1][40] = 22, + [0][0][2][0][RTW89_FCC][2][40] = 70, + [0][0][2][0][RTW89_ETSI][1][40] = 66, + [0][0][2][0][RTW89_ETSI][0][40] = 28, + [0][0][2][0][RTW89_MKK][1][40] = 66, + [0][0][2][0][RTW89_MKK][0][40] = 26, + [0][0][2][0][RTW89_IC][1][40] = 22, + [0][0][2][0][RTW89_KCC][1][40] = 24, + [0][0][2][0][RTW89_KCC][0][40] = 26, + [0][0][2][0][RTW89_ACMA][1][40] = 66, + [0][0][2][0][RTW89_ACMA][0][40] = 28, + [0][0][2][0][RTW89_CHILE][1][40] = 22, + [0][0][2][0][RTW89_QATAR][1][40] = 66, + [0][0][2][0][RTW89_QATAR][0][40] = 28, + [0][0][2][0][RTW89_UK][1][40] = 66, + [0][0][2][0][RTW89_UK][0][40] = 28, + [0][0][2][0][RTW89_FCC][1][42] = 22, + [0][0][2][0][RTW89_FCC][2][42] = 70, + [0][0][2][0][RTW89_ETSI][1][42] = 66, + [0][0][2][0][RTW89_ETSI][0][42] = 28, + [0][0][2][0][RTW89_MKK][1][42] = 66, + [0][0][2][0][RTW89_MKK][0][42] = 26, + [0][0][2][0][RTW89_IC][1][42] = 22, + [0][0][2][0][RTW89_KCC][1][42] = 24, + [0][0][2][0][RTW89_KCC][0][42] = 26, + [0][0][2][0][RTW89_ACMA][1][42] = 66, + [0][0][2][0][RTW89_ACMA][0][42] = 28, + [0][0][2][0][RTW89_CHILE][1][42] = 22, + [0][0][2][0][RTW89_QATAR][1][42] = 66, + [0][0][2][0][RTW89_QATAR][0][42] = 28, + [0][0][2][0][RTW89_UK][1][42] = 66, + [0][0][2][0][RTW89_UK][0][42] = 28, + [0][0][2][0][RTW89_FCC][1][44] = 22, + [0][0][2][0][RTW89_FCC][2][44] = 70, + [0][0][2][0][RTW89_ETSI][1][44] = 66, + [0][0][2][0][RTW89_ETSI][0][44] = 30, + [0][0][2][0][RTW89_MKK][1][44] = 44, + [0][0][2][0][RTW89_MKK][0][44] = 28, + [0][0][2][0][RTW89_IC][1][44] = 22, + [0][0][2][0][RTW89_KCC][1][44] = 24, + [0][0][2][0][RTW89_KCC][0][44] = 26, + [0][0][2][0][RTW89_ACMA][1][44] = 66, + [0][0][2][0][RTW89_ACMA][0][44] = 30, + [0][0][2][0][RTW89_CHILE][1][44] = 22, + [0][0][2][0][RTW89_QATAR][1][44] = 66, + [0][0][2][0][RTW89_QATAR][0][44] = 30, + [0][0][2][0][RTW89_UK][1][44] = 66, + [0][0][2][0][RTW89_UK][0][44] = 30, + [0][0][2][0][RTW89_FCC][1][45] = 22, + [0][0][2][0][RTW89_FCC][2][45] = 127, + [0][0][2][0][RTW89_ETSI][1][45] = 127, + [0][0][2][0][RTW89_ETSI][0][45] = 127, + [0][0][2][0][RTW89_MKK][1][45] = 127, + [0][0][2][0][RTW89_MKK][0][45] = 127, + [0][0][2][0][RTW89_IC][1][45] = 22, + [0][0][2][0][RTW89_KCC][1][45] = 24, + [0][0][2][0][RTW89_KCC][0][45] = 127, + [0][0][2][0][RTW89_ACMA][1][45] = 127, + [0][0][2][0][RTW89_ACMA][0][45] = 127, + [0][0][2][0][RTW89_CHILE][1][45] = 22, + [0][0][2][0][RTW89_QATAR][1][45] = 127, + [0][0][2][0][RTW89_QATAR][0][45] = 127, + [0][0][2][0][RTW89_UK][1][45] = 127, + [0][0][2][0][RTW89_UK][0][45] = 127, + [0][0][2][0][RTW89_FCC][1][47] = 22, + [0][0][2][0][RTW89_FCC][2][47] = 127, + [0][0][2][0][RTW89_ETSI][1][47] = 127, + [0][0][2][0][RTW89_ETSI][0][47] = 127, + [0][0][2][0][RTW89_MKK][1][47] = 127, + [0][0][2][0][RTW89_MKK][0][47] = 127, + [0][0][2][0][RTW89_IC][1][47] = 22, + [0][0][2][0][RTW89_KCC][1][47] = 24, + [0][0][2][0][RTW89_KCC][0][47] = 127, + [0][0][2][0][RTW89_ACMA][1][47] = 127, + [0][0][2][0][RTW89_ACMA][0][47] = 127, + [0][0][2][0][RTW89_CHILE][1][47] = 22, + [0][0][2][0][RTW89_QATAR][1][47] = 127, + [0][0][2][0][RTW89_QATAR][0][47] = 127, + [0][0][2][0][RTW89_UK][1][47] = 127, + [0][0][2][0][RTW89_UK][0][47] = 127, + [0][0][2][0][RTW89_FCC][1][49] = 24, + [0][0][2][0][RTW89_FCC][2][49] = 127, + [0][0][2][0][RTW89_ETSI][1][49] = 127, + [0][0][2][0][RTW89_ETSI][0][49] = 127, + [0][0][2][0][RTW89_MKK][1][49] = 127, + [0][0][2][0][RTW89_MKK][0][49] = 127, + [0][0][2][0][RTW89_IC][1][49] = 24, + [0][0][2][0][RTW89_KCC][1][49] = 24, + [0][0][2][0][RTW89_KCC][0][49] = 127, + [0][0][2][0][RTW89_ACMA][1][49] = 127, + [0][0][2][0][RTW89_ACMA][0][49] = 127, + [0][0][2][0][RTW89_CHILE][1][49] = 24, + [0][0][2][0][RTW89_QATAR][1][49] = 127, + [0][0][2][0][RTW89_QATAR][0][49] = 127, + [0][0][2][0][RTW89_UK][1][49] = 127, + [0][0][2][0][RTW89_UK][0][49] = 127, + [0][0][2][0][RTW89_FCC][1][51] = 22, + [0][0][2][0][RTW89_FCC][2][51] = 127, + [0][0][2][0][RTW89_ETSI][1][51] = 127, + [0][0][2][0][RTW89_ETSI][0][51] = 127, + [0][0][2][0][RTW89_MKK][1][51] = 127, + [0][0][2][0][RTW89_MKK][0][51] = 127, + [0][0][2][0][RTW89_IC][1][51] = 22, + [0][0][2][0][RTW89_KCC][1][51] = 24, + [0][0][2][0][RTW89_KCC][0][51] = 127, + [0][0][2][0][RTW89_ACMA][1][51] = 127, + [0][0][2][0][RTW89_ACMA][0][51] = 127, + [0][0][2][0][RTW89_CHILE][1][51] = 22, + [0][0][2][0][RTW89_QATAR][1][51] = 127, + [0][0][2][0][RTW89_QATAR][0][51] = 127, + [0][0][2][0][RTW89_UK][1][51] = 127, + [0][0][2][0][RTW89_UK][0][51] = 127, + [0][0][2][0][RTW89_FCC][1][53] = 22, + [0][0][2][0][RTW89_FCC][2][53] = 127, + [0][0][2][0][RTW89_ETSI][1][53] = 127, + [0][0][2][0][RTW89_ETSI][0][53] = 127, + [0][0][2][0][RTW89_MKK][1][53] = 127, + [0][0][2][0][RTW89_MKK][0][53] = 127, + [0][0][2][0][RTW89_IC][1][53] = 22, + [0][0][2][0][RTW89_KCC][1][53] = 24, + [0][0][2][0][RTW89_KCC][0][53] = 127, + [0][0][2][0][RTW89_ACMA][1][53] = 127, + [0][0][2][0][RTW89_ACMA][0][53] = 127, + [0][0][2][0][RTW89_CHILE][1][53] = 22, + [0][0][2][0][RTW89_QATAR][1][53] = 127, + [0][0][2][0][RTW89_QATAR][0][53] = 127, + [0][0][2][0][RTW89_UK][1][53] = 127, + [0][0][2][0][RTW89_UK][0][53] = 127, + [0][0][2][0][RTW89_FCC][1][55] = 22, + [0][0][2][0][RTW89_FCC][2][55] = 68, + [0][0][2][0][RTW89_ETSI][1][55] = 127, + [0][0][2][0][RTW89_ETSI][0][55] = 127, + [0][0][2][0][RTW89_MKK][1][55] = 127, + [0][0][2][0][RTW89_MKK][0][55] = 127, + [0][0][2][0][RTW89_IC][1][55] = 22, + [0][0][2][0][RTW89_KCC][1][55] = 26, + [0][0][2][0][RTW89_KCC][0][55] = 127, + [0][0][2][0][RTW89_ACMA][1][55] = 127, + [0][0][2][0][RTW89_ACMA][0][55] = 127, + [0][0][2][0][RTW89_CHILE][1][55] = 22, + [0][0][2][0][RTW89_QATAR][1][55] = 127, + [0][0][2][0][RTW89_QATAR][0][55] = 127, + [0][0][2][0][RTW89_UK][1][55] = 127, + [0][0][2][0][RTW89_UK][0][55] = 127, + [0][0][2][0][RTW89_FCC][1][57] = 22, + [0][0][2][0][RTW89_FCC][2][57] = 68, + [0][0][2][0][RTW89_ETSI][1][57] = 127, + [0][0][2][0][RTW89_ETSI][0][57] = 127, + [0][0][2][0][RTW89_MKK][1][57] = 127, + [0][0][2][0][RTW89_MKK][0][57] = 127, + [0][0][2][0][RTW89_IC][1][57] = 22, + [0][0][2][0][RTW89_KCC][1][57] = 26, + [0][0][2][0][RTW89_KCC][0][57] = 127, + [0][0][2][0][RTW89_ACMA][1][57] = 127, + [0][0][2][0][RTW89_ACMA][0][57] = 127, + [0][0][2][0][RTW89_CHILE][1][57] = 22, + [0][0][2][0][RTW89_QATAR][1][57] = 127, + [0][0][2][0][RTW89_QATAR][0][57] = 127, + [0][0][2][0][RTW89_UK][1][57] = 127, + [0][0][2][0][RTW89_UK][0][57] = 127, + [0][0][2][0][RTW89_FCC][1][59] = 22, + [0][0][2][0][RTW89_FCC][2][59] = 68, + [0][0][2][0][RTW89_ETSI][1][59] = 127, + [0][0][2][0][RTW89_ETSI][0][59] = 127, + [0][0][2][0][RTW89_MKK][1][59] = 127, + [0][0][2][0][RTW89_MKK][0][59] = 127, + [0][0][2][0][RTW89_IC][1][59] = 22, + [0][0][2][0][RTW89_KCC][1][59] = 26, + [0][0][2][0][RTW89_KCC][0][59] = 127, + [0][0][2][0][RTW89_ACMA][1][59] = 127, + [0][0][2][0][RTW89_ACMA][0][59] = 127, + [0][0][2][0][RTW89_CHILE][1][59] = 22, + [0][0][2][0][RTW89_QATAR][1][59] = 127, + [0][0][2][0][RTW89_QATAR][0][59] = 127, + [0][0][2][0][RTW89_UK][1][59] = 127, + [0][0][2][0][RTW89_UK][0][59] = 127, + [0][0][2][0][RTW89_FCC][1][60] = 22, + [0][0][2][0][RTW89_FCC][2][60] = 68, + [0][0][2][0][RTW89_ETSI][1][60] = 127, + [0][0][2][0][RTW89_ETSI][0][60] = 127, + [0][0][2][0][RTW89_MKK][1][60] = 127, + [0][0][2][0][RTW89_MKK][0][60] = 127, + [0][0][2][0][RTW89_IC][1][60] = 22, + [0][0][2][0][RTW89_KCC][1][60] = 26, + [0][0][2][0][RTW89_KCC][0][60] = 127, + [0][0][2][0][RTW89_ACMA][1][60] = 127, + [0][0][2][0][RTW89_ACMA][0][60] = 127, + [0][0][2][0][RTW89_CHILE][1][60] = 22, + [0][0][2][0][RTW89_QATAR][1][60] = 127, + [0][0][2][0][RTW89_QATAR][0][60] = 127, + [0][0][2][0][RTW89_UK][1][60] = 127, + [0][0][2][0][RTW89_UK][0][60] = 127, + [0][0][2][0][RTW89_FCC][1][62] = 22, + [0][0][2][0][RTW89_FCC][2][62] = 68, + [0][0][2][0][RTW89_ETSI][1][62] = 127, + [0][0][2][0][RTW89_ETSI][0][62] = 127, + [0][0][2][0][RTW89_MKK][1][62] = 127, + [0][0][2][0][RTW89_MKK][0][62] = 127, + [0][0][2][0][RTW89_IC][1][62] = 22, + [0][0][2][0][RTW89_KCC][1][62] = 26, + [0][0][2][0][RTW89_KCC][0][62] = 127, + [0][0][2][0][RTW89_ACMA][1][62] = 127, + [0][0][2][0][RTW89_ACMA][0][62] = 127, + [0][0][2][0][RTW89_CHILE][1][62] = 22, + [0][0][2][0][RTW89_QATAR][1][62] = 127, + [0][0][2][0][RTW89_QATAR][0][62] = 127, + [0][0][2][0][RTW89_UK][1][62] = 127, + [0][0][2][0][RTW89_UK][0][62] = 127, + [0][0][2][0][RTW89_FCC][1][64] = 22, + [0][0][2][0][RTW89_FCC][2][64] = 68, + [0][0][2][0][RTW89_ETSI][1][64] = 127, + [0][0][2][0][RTW89_ETSI][0][64] = 127, + [0][0][2][0][RTW89_MKK][1][64] = 127, + [0][0][2][0][RTW89_MKK][0][64] = 127, + [0][0][2][0][RTW89_IC][1][64] = 22, + [0][0][2][0][RTW89_KCC][1][64] = 26, + [0][0][2][0][RTW89_KCC][0][64] = 127, + [0][0][2][0][RTW89_ACMA][1][64] = 127, + [0][0][2][0][RTW89_ACMA][0][64] = 127, + [0][0][2][0][RTW89_CHILE][1][64] = 22, + [0][0][2][0][RTW89_QATAR][1][64] = 127, + [0][0][2][0][RTW89_QATAR][0][64] = 127, + [0][0][2][0][RTW89_UK][1][64] = 127, + [0][0][2][0][RTW89_UK][0][64] = 127, + [0][0][2][0][RTW89_FCC][1][66] = 22, + [0][0][2][0][RTW89_FCC][2][66] = 68, + [0][0][2][0][RTW89_ETSI][1][66] = 127, + [0][0][2][0][RTW89_ETSI][0][66] = 127, + [0][0][2][0][RTW89_MKK][1][66] = 127, + [0][0][2][0][RTW89_MKK][0][66] = 127, + [0][0][2][0][RTW89_IC][1][66] = 22, + [0][0][2][0][RTW89_KCC][1][66] = 26, + [0][0][2][0][RTW89_KCC][0][66] = 127, + [0][0][2][0][RTW89_ACMA][1][66] = 127, + [0][0][2][0][RTW89_ACMA][0][66] = 127, + [0][0][2][0][RTW89_CHILE][1][66] = 22, + [0][0][2][0][RTW89_QATAR][1][66] = 127, + [0][0][2][0][RTW89_QATAR][0][66] = 127, + [0][0][2][0][RTW89_UK][1][66] = 127, + [0][0][2][0][RTW89_UK][0][66] = 127, + [0][0][2][0][RTW89_FCC][1][68] = 22, + [0][0][2][0][RTW89_FCC][2][68] = 68, + [0][0][2][0][RTW89_ETSI][1][68] = 127, + [0][0][2][0][RTW89_ETSI][0][68] = 127, + [0][0][2][0][RTW89_MKK][1][68] = 127, + [0][0][2][0][RTW89_MKK][0][68] = 127, + [0][0][2][0][RTW89_IC][1][68] = 22, + [0][0][2][0][RTW89_KCC][1][68] = 26, + [0][0][2][0][RTW89_KCC][0][68] = 127, + [0][0][2][0][RTW89_ACMA][1][68] = 127, + [0][0][2][0][RTW89_ACMA][0][68] = 127, + [0][0][2][0][RTW89_CHILE][1][68] = 22, + [0][0][2][0][RTW89_QATAR][1][68] = 127, + [0][0][2][0][RTW89_QATAR][0][68] = 127, + [0][0][2][0][RTW89_UK][1][68] = 127, + [0][0][2][0][RTW89_UK][0][68] = 127, + [0][0][2][0][RTW89_FCC][1][70] = 24, + [0][0][2][0][RTW89_FCC][2][70] = 68, + [0][0][2][0][RTW89_ETSI][1][70] = 127, + [0][0][2][0][RTW89_ETSI][0][70] = 127, + [0][0][2][0][RTW89_MKK][1][70] = 127, + [0][0][2][0][RTW89_MKK][0][70] = 127, + [0][0][2][0][RTW89_IC][1][70] = 24, + [0][0][2][0][RTW89_KCC][1][70] = 26, + [0][0][2][0][RTW89_KCC][0][70] = 127, + [0][0][2][0][RTW89_ACMA][1][70] = 127, + [0][0][2][0][RTW89_ACMA][0][70] = 127, + [0][0][2][0][RTW89_CHILE][1][70] = 24, + [0][0][2][0][RTW89_QATAR][1][70] = 127, + [0][0][2][0][RTW89_QATAR][0][70] = 127, + [0][0][2][0][RTW89_UK][1][70] = 127, + [0][0][2][0][RTW89_UK][0][70] = 127, + [0][0][2][0][RTW89_FCC][1][72] = 22, + [0][0][2][0][RTW89_FCC][2][72] = 68, + [0][0][2][0][RTW89_ETSI][1][72] = 127, + [0][0][2][0][RTW89_ETSI][0][72] = 127, + [0][0][2][0][RTW89_MKK][1][72] = 127, + [0][0][2][0][RTW89_MKK][0][72] = 127, + [0][0][2][0][RTW89_IC][1][72] = 22, + [0][0][2][0][RTW89_KCC][1][72] = 26, + [0][0][2][0][RTW89_KCC][0][72] = 127, + [0][0][2][0][RTW89_ACMA][1][72] = 127, + [0][0][2][0][RTW89_ACMA][0][72] = 127, + [0][0][2][0][RTW89_CHILE][1][72] = 22, + [0][0][2][0][RTW89_QATAR][1][72] = 127, + [0][0][2][0][RTW89_QATAR][0][72] = 127, + [0][0][2][0][RTW89_UK][1][72] = 127, + [0][0][2][0][RTW89_UK][0][72] = 127, + [0][0][2][0][RTW89_FCC][1][74] = 22, + [0][0][2][0][RTW89_FCC][2][74] = 68, + [0][0][2][0][RTW89_ETSI][1][74] = 127, + [0][0][2][0][RTW89_ETSI][0][74] = 127, + [0][0][2][0][RTW89_MKK][1][74] = 127, + [0][0][2][0][RTW89_MKK][0][74] = 127, + [0][0][2][0][RTW89_IC][1][74] = 22, + [0][0][2][0][RTW89_KCC][1][74] = 26, + [0][0][2][0][RTW89_KCC][0][74] = 127, + [0][0][2][0][RTW89_ACMA][1][74] = 127, + [0][0][2][0][RTW89_ACMA][0][74] = 127, + [0][0][2][0][RTW89_CHILE][1][74] = 22, + [0][0][2][0][RTW89_QATAR][1][74] = 127, + [0][0][2][0][RTW89_QATAR][0][74] = 127, + [0][0][2][0][RTW89_UK][1][74] = 127, + [0][0][2][0][RTW89_UK][0][74] = 127, + [0][0][2][0][RTW89_FCC][1][75] = 22, + [0][0][2][0][RTW89_FCC][2][75] = 68, + [0][0][2][0][RTW89_ETSI][1][75] = 127, + [0][0][2][0][RTW89_ETSI][0][75] = 127, + [0][0][2][0][RTW89_MKK][1][75] = 127, + [0][0][2][0][RTW89_MKK][0][75] = 127, + [0][0][2][0][RTW89_IC][1][75] = 22, + [0][0][2][0][RTW89_KCC][1][75] = 26, + [0][0][2][0][RTW89_KCC][0][75] = 127, + [0][0][2][0][RTW89_ACMA][1][75] = 127, + [0][0][2][0][RTW89_ACMA][0][75] = 127, + [0][0][2][0][RTW89_CHILE][1][75] = 22, + [0][0][2][0][RTW89_QATAR][1][75] = 127, + [0][0][2][0][RTW89_QATAR][0][75] = 127, + [0][0][2][0][RTW89_UK][1][75] = 127, + [0][0][2][0][RTW89_UK][0][75] = 127, + [0][0][2][0][RTW89_FCC][1][77] = 22, + [0][0][2][0][RTW89_FCC][2][77] = 68, + [0][0][2][0][RTW89_ETSI][1][77] = 127, + [0][0][2][0][RTW89_ETSI][0][77] = 127, + [0][0][2][0][RTW89_MKK][1][77] = 127, + [0][0][2][0][RTW89_MKK][0][77] = 127, + [0][0][2][0][RTW89_IC][1][77] = 22, + [0][0][2][0][RTW89_KCC][1][77] = 26, + [0][0][2][0][RTW89_KCC][0][77] = 127, + [0][0][2][0][RTW89_ACMA][1][77] = 127, + [0][0][2][0][RTW89_ACMA][0][77] = 127, + [0][0][2][0][RTW89_CHILE][1][77] = 22, + [0][0][2][0][RTW89_QATAR][1][77] = 127, + [0][0][2][0][RTW89_QATAR][0][77] = 127, + [0][0][2][0][RTW89_UK][1][77] = 127, + [0][0][2][0][RTW89_UK][0][77] = 127, + [0][0][2][0][RTW89_FCC][1][79] = 22, + [0][0][2][0][RTW89_FCC][2][79] = 68, + [0][0][2][0][RTW89_ETSI][1][79] = 127, + [0][0][2][0][RTW89_ETSI][0][79] = 127, + [0][0][2][0][RTW89_MKK][1][79] = 127, + [0][0][2][0][RTW89_MKK][0][79] = 127, + [0][0][2][0][RTW89_IC][1][79] = 22, + [0][0][2][0][RTW89_KCC][1][79] = 26, + [0][0][2][0][RTW89_KCC][0][79] = 127, + [0][0][2][0][RTW89_ACMA][1][79] = 127, + [0][0][2][0][RTW89_ACMA][0][79] = 127, + [0][0][2][0][RTW89_CHILE][1][79] = 22, + [0][0][2][0][RTW89_QATAR][1][79] = 127, + [0][0][2][0][RTW89_QATAR][0][79] = 127, + [0][0][2][0][RTW89_UK][1][79] = 127, + [0][0][2][0][RTW89_UK][0][79] = 127, + [0][0][2][0][RTW89_FCC][1][81] = 22, + [0][0][2][0][RTW89_FCC][2][81] = 68, + [0][0][2][0][RTW89_ETSI][1][81] = 127, + [0][0][2][0][RTW89_ETSI][0][81] = 127, + [0][0][2][0][RTW89_MKK][1][81] = 127, + [0][0][2][0][RTW89_MKK][0][81] = 127, + [0][0][2][0][RTW89_IC][1][81] = 22, + [0][0][2][0][RTW89_KCC][1][81] = 26, + [0][0][2][0][RTW89_KCC][0][81] = 127, + [0][0][2][0][RTW89_ACMA][1][81] = 127, + [0][0][2][0][RTW89_ACMA][0][81] = 127, + [0][0][2][0][RTW89_CHILE][1][81] = 22, + [0][0][2][0][RTW89_QATAR][1][81] = 127, + [0][0][2][0][RTW89_QATAR][0][81] = 127, + [0][0][2][0][RTW89_UK][1][81] = 127, + [0][0][2][0][RTW89_UK][0][81] = 127, + [0][0][2][0][RTW89_FCC][1][83] = 22, + [0][0][2][0][RTW89_FCC][2][83] = 68, + [0][0][2][0][RTW89_ETSI][1][83] = 127, + [0][0][2][0][RTW89_ETSI][0][83] = 127, + [0][0][2][0][RTW89_MKK][1][83] = 127, + [0][0][2][0][RTW89_MKK][0][83] = 127, + [0][0][2][0][RTW89_IC][1][83] = 22, + [0][0][2][0][RTW89_KCC][1][83] = 32, + [0][0][2][0][RTW89_KCC][0][83] = 127, + [0][0][2][0][RTW89_ACMA][1][83] = 127, + [0][0][2][0][RTW89_ACMA][0][83] = 127, + [0][0][2][0][RTW89_CHILE][1][83] = 22, + [0][0][2][0][RTW89_QATAR][1][83] = 127, + [0][0][2][0][RTW89_QATAR][0][83] = 127, + [0][0][2][0][RTW89_UK][1][83] = 127, + [0][0][2][0][RTW89_UK][0][83] = 127, + [0][0][2][0][RTW89_FCC][1][85] = 22, + [0][0][2][0][RTW89_FCC][2][85] = 68, + [0][0][2][0][RTW89_ETSI][1][85] = 127, + [0][0][2][0][RTW89_ETSI][0][85] = 127, + [0][0][2][0][RTW89_MKK][1][85] = 127, + [0][0][2][0][RTW89_MKK][0][85] = 127, + [0][0][2][0][RTW89_IC][1][85] = 22, + [0][0][2][0][RTW89_KCC][1][85] = 32, + [0][0][2][0][RTW89_KCC][0][85] = 127, + [0][0][2][0][RTW89_ACMA][1][85] = 127, + [0][0][2][0][RTW89_ACMA][0][85] = 127, + [0][0][2][0][RTW89_CHILE][1][85] = 22, + [0][0][2][0][RTW89_QATAR][1][85] = 127, + [0][0][2][0][RTW89_QATAR][0][85] = 127, + [0][0][2][0][RTW89_UK][1][85] = 127, + [0][0][2][0][RTW89_UK][0][85] = 127, + [0][0][2][0][RTW89_FCC][1][87] = 22, + [0][0][2][0][RTW89_FCC][2][87] = 127, + [0][0][2][0][RTW89_ETSI][1][87] = 127, + [0][0][2][0][RTW89_ETSI][0][87] = 127, + [0][0][2][0][RTW89_MKK][1][87] = 127, + [0][0][2][0][RTW89_MKK][0][87] = 127, + [0][0][2][0][RTW89_IC][1][87] = 22, + [0][0][2][0][RTW89_KCC][1][87] = 32, + [0][0][2][0][RTW89_KCC][0][87] = 127, + [0][0][2][0][RTW89_ACMA][1][87] = 127, + [0][0][2][0][RTW89_ACMA][0][87] = 127, + [0][0][2][0][RTW89_CHILE][1][87] = 22, + [0][0][2][0][RTW89_QATAR][1][87] = 127, + [0][0][2][0][RTW89_QATAR][0][87] = 127, + [0][0][2][0][RTW89_UK][1][87] = 127, + [0][0][2][0][RTW89_UK][0][87] = 127, + [0][0][2][0][RTW89_FCC][1][89] = 22, + [0][0][2][0][RTW89_FCC][2][89] = 127, + [0][0][2][0][RTW89_ETSI][1][89] = 127, + [0][0][2][0][RTW89_ETSI][0][89] = 127, + [0][0][2][0][RTW89_MKK][1][89] = 127, + [0][0][2][0][RTW89_MKK][0][89] = 127, + [0][0][2][0][RTW89_IC][1][89] = 22, + [0][0][2][0][RTW89_KCC][1][89] = 32, + [0][0][2][0][RTW89_KCC][0][89] = 127, + [0][0][2][0][RTW89_ACMA][1][89] = 127, + [0][0][2][0][RTW89_ACMA][0][89] = 127, + [0][0][2][0][RTW89_CHILE][1][89] = 22, + [0][0][2][0][RTW89_QATAR][1][89] = 127, + [0][0][2][0][RTW89_QATAR][0][89] = 127, + [0][0][2][0][RTW89_UK][1][89] = 127, + [0][0][2][0][RTW89_UK][0][89] = 127, + [0][0][2][0][RTW89_FCC][1][90] = 22, + [0][0][2][0][RTW89_FCC][2][90] = 127, + [0][0][2][0][RTW89_ETSI][1][90] = 127, + [0][0][2][0][RTW89_ETSI][0][90] = 127, + [0][0][2][0][RTW89_MKK][1][90] = 127, + [0][0][2][0][RTW89_MKK][0][90] = 127, + [0][0][2][0][RTW89_IC][1][90] = 22, + [0][0][2][0][RTW89_KCC][1][90] = 32, + [0][0][2][0][RTW89_KCC][0][90] = 127, + [0][0][2][0][RTW89_ACMA][1][90] = 127, + [0][0][2][0][RTW89_ACMA][0][90] = 127, + [0][0][2][0][RTW89_CHILE][1][90] = 22, + [0][0][2][0][RTW89_QATAR][1][90] = 127, + [0][0][2][0][RTW89_QATAR][0][90] = 127, + [0][0][2][0][RTW89_UK][1][90] = 127, + [0][0][2][0][RTW89_UK][0][90] = 127, + [0][0][2][0][RTW89_FCC][1][92] = 22, + [0][0][2][0][RTW89_FCC][2][92] = 127, + [0][0][2][0][RTW89_ETSI][1][92] = 127, + [0][0][2][0][RTW89_ETSI][0][92] = 127, + [0][0][2][0][RTW89_MKK][1][92] = 127, + [0][0][2][0][RTW89_MKK][0][92] = 127, + [0][0][2][0][RTW89_IC][1][92] = 22, + [0][0][2][0][RTW89_KCC][1][92] = 32, + [0][0][2][0][RTW89_KCC][0][92] = 127, + [0][0][2][0][RTW89_ACMA][1][92] = 127, + [0][0][2][0][RTW89_ACMA][0][92] = 127, + [0][0][2][0][RTW89_CHILE][1][92] = 22, + [0][0][2][0][RTW89_QATAR][1][92] = 127, + [0][0][2][0][RTW89_QATAR][0][92] = 127, + [0][0][2][0][RTW89_UK][1][92] = 127, + [0][0][2][0][RTW89_UK][0][92] = 127, + [0][0][2][0][RTW89_FCC][1][94] = 22, + [0][0][2][0][RTW89_FCC][2][94] = 127, + [0][0][2][0][RTW89_ETSI][1][94] = 127, + [0][0][2][0][RTW89_ETSI][0][94] = 127, + [0][0][2][0][RTW89_MKK][1][94] = 127, + [0][0][2][0][RTW89_MKK][0][94] = 127, + [0][0][2][0][RTW89_IC][1][94] = 22, + [0][0][2][0][RTW89_KCC][1][94] = 32, + [0][0][2][0][RTW89_KCC][0][94] = 127, + [0][0][2][0][RTW89_ACMA][1][94] = 127, + [0][0][2][0][RTW89_ACMA][0][94] = 127, + [0][0][2][0][RTW89_CHILE][1][94] = 22, + [0][0][2][0][RTW89_QATAR][1][94] = 127, + [0][0][2][0][RTW89_QATAR][0][94] = 127, + [0][0][2][0][RTW89_UK][1][94] = 127, + [0][0][2][0][RTW89_UK][0][94] = 127, + [0][0][2][0][RTW89_FCC][1][96] = 22, + [0][0][2][0][RTW89_FCC][2][96] = 127, + [0][0][2][0][RTW89_ETSI][1][96] = 127, + [0][0][2][0][RTW89_ETSI][0][96] = 127, + [0][0][2][0][RTW89_MKK][1][96] = 127, + [0][0][2][0][RTW89_MKK][0][96] = 127, + [0][0][2][0][RTW89_IC][1][96] = 22, + [0][0][2][0][RTW89_KCC][1][96] = 32, + [0][0][2][0][RTW89_KCC][0][96] = 127, + [0][0][2][0][RTW89_ACMA][1][96] = 127, + [0][0][2][0][RTW89_ACMA][0][96] = 127, + [0][0][2][0][RTW89_CHILE][1][96] = 22, + [0][0][2][0][RTW89_QATAR][1][96] = 127, + [0][0][2][0][RTW89_QATAR][0][96] = 127, + [0][0][2][0][RTW89_UK][1][96] = 127, + [0][0][2][0][RTW89_UK][0][96] = 127, + [0][0][2][0][RTW89_FCC][1][98] = 22, + [0][0][2][0][RTW89_FCC][2][98] = 127, + [0][0][2][0][RTW89_ETSI][1][98] = 127, + [0][0][2][0][RTW89_ETSI][0][98] = 127, + [0][0][2][0][RTW89_MKK][1][98] = 127, + [0][0][2][0][RTW89_MKK][0][98] = 127, + [0][0][2][0][RTW89_IC][1][98] = 22, + [0][0][2][0][RTW89_KCC][1][98] = 32, + [0][0][2][0][RTW89_KCC][0][98] = 127, + [0][0][2][0][RTW89_ACMA][1][98] = 127, + [0][0][2][0][RTW89_ACMA][0][98] = 127, + [0][0][2][0][RTW89_CHILE][1][98] = 22, + [0][0][2][0][RTW89_QATAR][1][98] = 127, + [0][0][2][0][RTW89_QATAR][0][98] = 127, + [0][0][2][0][RTW89_UK][1][98] = 127, + [0][0][2][0][RTW89_UK][0][98] = 127, + [0][0][2][0][RTW89_FCC][1][100] = 22, + [0][0][2][0][RTW89_FCC][2][100] = 127, + [0][0][2][0][RTW89_ETSI][1][100] = 127, + [0][0][2][0][RTW89_ETSI][0][100] = 127, + [0][0][2][0][RTW89_MKK][1][100] = 127, + [0][0][2][0][RTW89_MKK][0][100] = 127, + [0][0][2][0][RTW89_IC][1][100] = 22, + [0][0][2][0][RTW89_KCC][1][100] = 32, + [0][0][2][0][RTW89_KCC][0][100] = 127, + [0][0][2][0][RTW89_ACMA][1][100] = 127, + [0][0][2][0][RTW89_ACMA][0][100] = 127, + [0][0][2][0][RTW89_CHILE][1][100] = 22, + [0][0][2][0][RTW89_QATAR][1][100] = 127, + [0][0][2][0][RTW89_QATAR][0][100] = 127, + [0][0][2][0][RTW89_UK][1][100] = 127, + [0][0][2][0][RTW89_UK][0][100] = 127, + [0][0][2][0][RTW89_FCC][1][102] = 22, + [0][0][2][0][RTW89_FCC][2][102] = 127, + [0][0][2][0][RTW89_ETSI][1][102] = 127, + [0][0][2][0][RTW89_ETSI][0][102] = 127, + [0][0][2][0][RTW89_MKK][1][102] = 127, + [0][0][2][0][RTW89_MKK][0][102] = 127, + [0][0][2][0][RTW89_IC][1][102] = 22, + [0][0][2][0][RTW89_KCC][1][102] = 32, + [0][0][2][0][RTW89_KCC][0][102] = 127, + [0][0][2][0][RTW89_ACMA][1][102] = 127, + [0][0][2][0][RTW89_ACMA][0][102] = 127, + [0][0][2][0][RTW89_CHILE][1][102] = 22, + [0][0][2][0][RTW89_QATAR][1][102] = 127, + [0][0][2][0][RTW89_QATAR][0][102] = 127, + [0][0][2][0][RTW89_UK][1][102] = 127, + [0][0][2][0][RTW89_UK][0][102] = 127, + [0][0][2][0][RTW89_FCC][1][104] = 22, + [0][0][2][0][RTW89_FCC][2][104] = 127, + [0][0][2][0][RTW89_ETSI][1][104] = 127, + [0][0][2][0][RTW89_ETSI][0][104] = 127, + [0][0][2][0][RTW89_MKK][1][104] = 127, + [0][0][2][0][RTW89_MKK][0][104] = 127, + [0][0][2][0][RTW89_IC][1][104] = 22, + [0][0][2][0][RTW89_KCC][1][104] = 32, + [0][0][2][0][RTW89_KCC][0][104] = 127, + [0][0][2][0][RTW89_ACMA][1][104] = 127, + [0][0][2][0][RTW89_ACMA][0][104] = 127, + [0][0][2][0][RTW89_CHILE][1][104] = 22, + [0][0][2][0][RTW89_QATAR][1][104] = 127, + [0][0][2][0][RTW89_QATAR][0][104] = 127, + [0][0][2][0][RTW89_UK][1][104] = 127, + [0][0][2][0][RTW89_UK][0][104] = 127, + [0][0][2][0][RTW89_FCC][1][105] = 22, + [0][0][2][0][RTW89_FCC][2][105] = 127, + [0][0][2][0][RTW89_ETSI][1][105] = 127, + [0][0][2][0][RTW89_ETSI][0][105] = 127, + [0][0][2][0][RTW89_MKK][1][105] = 127, + [0][0][2][0][RTW89_MKK][0][105] = 127, + [0][0][2][0][RTW89_IC][1][105] = 22, + [0][0][2][0][RTW89_KCC][1][105] = 32, + [0][0][2][0][RTW89_KCC][0][105] = 127, + [0][0][2][0][RTW89_ACMA][1][105] = 127, + [0][0][2][0][RTW89_ACMA][0][105] = 127, + [0][0][2][0][RTW89_CHILE][1][105] = 22, + [0][0][2][0][RTW89_QATAR][1][105] = 127, + [0][0][2][0][RTW89_QATAR][0][105] = 127, + [0][0][2][0][RTW89_UK][1][105] = 127, + [0][0][2][0][RTW89_UK][0][105] = 127, + [0][0][2][0][RTW89_FCC][1][107] = 24, + [0][0][2][0][RTW89_FCC][2][107] = 127, + [0][0][2][0][RTW89_ETSI][1][107] = 127, + [0][0][2][0][RTW89_ETSI][0][107] = 127, + [0][0][2][0][RTW89_MKK][1][107] = 127, + [0][0][2][0][RTW89_MKK][0][107] = 127, + [0][0][2][0][RTW89_IC][1][107] = 24, + [0][0][2][0][RTW89_KCC][1][107] = 32, + [0][0][2][0][RTW89_KCC][0][107] = 127, + [0][0][2][0][RTW89_ACMA][1][107] = 127, + [0][0][2][0][RTW89_ACMA][0][107] = 127, + [0][0][2][0][RTW89_CHILE][1][107] = 24, + [0][0][2][0][RTW89_QATAR][1][107] = 127, + [0][0][2][0][RTW89_QATAR][0][107] = 127, + [0][0][2][0][RTW89_UK][1][107] = 127, + [0][0][2][0][RTW89_UK][0][107] = 127, + [0][0][2][0][RTW89_FCC][1][109] = 24, + [0][0][2][0][RTW89_FCC][2][109] = 127, + [0][0][2][0][RTW89_ETSI][1][109] = 127, + [0][0][2][0][RTW89_ETSI][0][109] = 127, + [0][0][2][0][RTW89_MKK][1][109] = 127, + [0][0][2][0][RTW89_MKK][0][109] = 127, + [0][0][2][0][RTW89_IC][1][109] = 24, + [0][0][2][0][RTW89_KCC][1][109] = 32, + [0][0][2][0][RTW89_KCC][0][109] = 127, + [0][0][2][0][RTW89_ACMA][1][109] = 127, + [0][0][2][0][RTW89_ACMA][0][109] = 127, + [0][0][2][0][RTW89_CHILE][1][109] = 24, + [0][0][2][0][RTW89_QATAR][1][109] = 127, + [0][0][2][0][RTW89_QATAR][0][109] = 127, + [0][0][2][0][RTW89_UK][1][109] = 127, + [0][0][2][0][RTW89_UK][0][109] = 127, + [0][0][2][0][RTW89_FCC][1][111] = 127, + [0][0][2][0][RTW89_FCC][2][111] = 127, + [0][0][2][0][RTW89_ETSI][1][111] = 127, + [0][0][2][0][RTW89_ETSI][0][111] = 127, + [0][0][2][0][RTW89_MKK][1][111] = 127, + [0][0][2][0][RTW89_MKK][0][111] = 127, + [0][0][2][0][RTW89_IC][1][111] = 127, + [0][0][2][0][RTW89_KCC][1][111] = 127, + [0][0][2][0][RTW89_KCC][0][111] = 127, + [0][0][2][0][RTW89_ACMA][1][111] = 127, + [0][0][2][0][RTW89_ACMA][0][111] = 127, + [0][0][2][0][RTW89_CHILE][1][111] = 127, + [0][0][2][0][RTW89_QATAR][1][111] = 127, + [0][0][2][0][RTW89_QATAR][0][111] = 127, + [0][0][2][0][RTW89_UK][1][111] = 127, + [0][0][2][0][RTW89_UK][0][111] = 127, + [0][0][2][0][RTW89_FCC][1][113] = 127, + [0][0][2][0][RTW89_FCC][2][113] = 127, + [0][0][2][0][RTW89_ETSI][1][113] = 127, + [0][0][2][0][RTW89_ETSI][0][113] = 127, + [0][0][2][0][RTW89_MKK][1][113] = 127, + [0][0][2][0][RTW89_MKK][0][113] = 127, + [0][0][2][0][RTW89_IC][1][113] = 127, + [0][0][2][0][RTW89_KCC][1][113] = 127, + [0][0][2][0][RTW89_KCC][0][113] = 127, + [0][0][2][0][RTW89_ACMA][1][113] = 127, + [0][0][2][0][RTW89_ACMA][0][113] = 127, + [0][0][2][0][RTW89_CHILE][1][113] = 127, + [0][0][2][0][RTW89_QATAR][1][113] = 127, + [0][0][2][0][RTW89_QATAR][0][113] = 127, + [0][0][2][0][RTW89_UK][1][113] = 127, + [0][0][2][0][RTW89_UK][0][113] = 127, + [0][0][2][0][RTW89_FCC][1][115] = 127, + [0][0][2][0][RTW89_FCC][2][115] = 127, + [0][0][2][0][RTW89_ETSI][1][115] = 127, + [0][0][2][0][RTW89_ETSI][0][115] = 127, + [0][0][2][0][RTW89_MKK][1][115] = 127, + [0][0][2][0][RTW89_MKK][0][115] = 127, + [0][0][2][0][RTW89_IC][1][115] = 127, + [0][0][2][0][RTW89_KCC][1][115] = 127, + [0][0][2][0][RTW89_KCC][0][115] = 127, + [0][0][2][0][RTW89_ACMA][1][115] = 127, + [0][0][2][0][RTW89_ACMA][0][115] = 127, + [0][0][2][0][RTW89_CHILE][1][115] = 127, + [0][0][2][0][RTW89_QATAR][1][115] = 127, + [0][0][2][0][RTW89_QATAR][0][115] = 127, + [0][0][2][0][RTW89_UK][1][115] = 127, + [0][0][2][0][RTW89_UK][0][115] = 127, + [0][0][2][0][RTW89_FCC][1][117] = 127, + [0][0][2][0][RTW89_FCC][2][117] = 127, + [0][0][2][0][RTW89_ETSI][1][117] = 127, + [0][0][2][0][RTW89_ETSI][0][117] = 127, + [0][0][2][0][RTW89_MKK][1][117] = 127, + [0][0][2][0][RTW89_MKK][0][117] = 127, + [0][0][2][0][RTW89_IC][1][117] = 127, + [0][0][2][0][RTW89_KCC][1][117] = 127, + [0][0][2][0][RTW89_KCC][0][117] = 127, + [0][0][2][0][RTW89_ACMA][1][117] = 127, + [0][0][2][0][RTW89_ACMA][0][117] = 127, + [0][0][2][0][RTW89_CHILE][1][117] = 127, + [0][0][2][0][RTW89_QATAR][1][117] = 127, + [0][0][2][0][RTW89_QATAR][0][117] = 127, + [0][0][2][0][RTW89_UK][1][117] = 127, + [0][0][2][0][RTW89_UK][0][117] = 127, + [0][0][2][0][RTW89_FCC][1][119] = 127, + [0][0][2][0][RTW89_FCC][2][119] = 127, + [0][0][2][0][RTW89_ETSI][1][119] = 127, + [0][0][2][0][RTW89_ETSI][0][119] = 127, + [0][0][2][0][RTW89_MKK][1][119] = 127, + [0][0][2][0][RTW89_MKK][0][119] = 127, + [0][0][2][0][RTW89_IC][1][119] = 127, + [0][0][2][0][RTW89_KCC][1][119] = 127, + [0][0][2][0][RTW89_KCC][0][119] = 127, + [0][0][2][0][RTW89_ACMA][1][119] = 127, + [0][0][2][0][RTW89_ACMA][0][119] = 127, + [0][0][2][0][RTW89_CHILE][1][119] = 127, + [0][0][2][0][RTW89_QATAR][1][119] = 127, + [0][0][2][0][RTW89_QATAR][0][119] = 127, + [0][0][2][0][RTW89_UK][1][119] = 127, + [0][0][2][0][RTW89_UK][0][119] = 127, + [0][1][2][0][RTW89_FCC][1][0] = -2, + [0][1][2][0][RTW89_FCC][2][0] = 54, + [0][1][2][0][RTW89_ETSI][1][0] = 54, + [0][1][2][0][RTW89_ETSI][0][0] = 18, + [0][1][2][0][RTW89_MKK][1][0] = 56, + [0][1][2][0][RTW89_MKK][0][0] = 16, + [0][1][2][0][RTW89_IC][1][0] = -2, + [0][1][2][0][RTW89_KCC][1][0] = 12, + [0][1][2][0][RTW89_KCC][0][0] = 10, + [0][1][2][0][RTW89_ACMA][1][0] = 54, + [0][1][2][0][RTW89_ACMA][0][0] = 18, + [0][1][2][0][RTW89_CHILE][1][0] = -2, + [0][1][2][0][RTW89_QATAR][1][0] = 54, + [0][1][2][0][RTW89_QATAR][0][0] = 18, + [0][1][2][0][RTW89_UK][1][0] = 54, + [0][1][2][0][RTW89_UK][0][0] = 18, + [0][1][2][0][RTW89_FCC][1][2] = -4, + [0][1][2][0][RTW89_FCC][2][2] = 54, + [0][1][2][0][RTW89_ETSI][1][2] = 54, + [0][1][2][0][RTW89_ETSI][0][2] = 18, + [0][1][2][0][RTW89_MKK][1][2] = 54, + [0][1][2][0][RTW89_MKK][0][2] = 16, + [0][1][2][0][RTW89_IC][1][2] = -4, + [0][1][2][0][RTW89_KCC][1][2] = 12, + [0][1][2][0][RTW89_KCC][0][2] = 12, + [0][1][2][0][RTW89_ACMA][1][2] = 54, + [0][1][2][0][RTW89_ACMA][0][2] = 18, + [0][1][2][0][RTW89_CHILE][1][2] = -4, + [0][1][2][0][RTW89_QATAR][1][2] = 54, + [0][1][2][0][RTW89_QATAR][0][2] = 18, + [0][1][2][0][RTW89_UK][1][2] = 54, + [0][1][2][0][RTW89_UK][0][2] = 18, + [0][1][2][0][RTW89_FCC][1][4] = -4, + [0][1][2][0][RTW89_FCC][2][4] = 54, + [0][1][2][0][RTW89_ETSI][1][4] = 54, + [0][1][2][0][RTW89_ETSI][0][4] = 18, + [0][1][2][0][RTW89_MKK][1][4] = 54, + [0][1][2][0][RTW89_MKK][0][4] = 16, + [0][1][2][0][RTW89_IC][1][4] = -4, + [0][1][2][0][RTW89_KCC][1][4] = 12, + [0][1][2][0][RTW89_KCC][0][4] = 12, + [0][1][2][0][RTW89_ACMA][1][4] = 54, + [0][1][2][0][RTW89_ACMA][0][4] = 18, + [0][1][2][0][RTW89_CHILE][1][4] = -4, + [0][1][2][0][RTW89_QATAR][1][4] = 54, + [0][1][2][0][RTW89_QATAR][0][4] = 18, + [0][1][2][0][RTW89_UK][1][4] = 54, + [0][1][2][0][RTW89_UK][0][4] = 18, + [0][1][2][0][RTW89_FCC][1][6] = -4, + [0][1][2][0][RTW89_FCC][2][6] = 54, + [0][1][2][0][RTW89_ETSI][1][6] = 54, + [0][1][2][0][RTW89_ETSI][0][6] = 18, + [0][1][2][0][RTW89_MKK][1][6] = 54, + [0][1][2][0][RTW89_MKK][0][6] = 16, + [0][1][2][0][RTW89_IC][1][6] = -4, + [0][1][2][0][RTW89_KCC][1][6] = 12, + [0][1][2][0][RTW89_KCC][0][6] = 12, + [0][1][2][0][RTW89_ACMA][1][6] = 54, + [0][1][2][0][RTW89_ACMA][0][6] = 18, + [0][1][2][0][RTW89_CHILE][1][6] = -4, + [0][1][2][0][RTW89_QATAR][1][6] = 54, + [0][1][2][0][RTW89_QATAR][0][6] = 18, + [0][1][2][0][RTW89_UK][1][6] = 54, + [0][1][2][0][RTW89_UK][0][6] = 18, + [0][1][2][0][RTW89_FCC][1][8] = -4, + [0][1][2][0][RTW89_FCC][2][8] = 54, + [0][1][2][0][RTW89_ETSI][1][8] = 54, + [0][1][2][0][RTW89_ETSI][0][8] = 18, + [0][1][2][0][RTW89_MKK][1][8] = 54, + [0][1][2][0][RTW89_MKK][0][8] = 16, + [0][1][2][0][RTW89_IC][1][8] = -4, + [0][1][2][0][RTW89_KCC][1][8] = 12, + [0][1][2][0][RTW89_KCC][0][8] = 12, + [0][1][2][0][RTW89_ACMA][1][8] = 54, + [0][1][2][0][RTW89_ACMA][0][8] = 18, + [0][1][2][0][RTW89_CHILE][1][8] = -4, + [0][1][2][0][RTW89_QATAR][1][8] = 54, + [0][1][2][0][RTW89_QATAR][0][8] = 18, + [0][1][2][0][RTW89_UK][1][8] = 54, + [0][1][2][0][RTW89_UK][0][8] = 18, + [0][1][2][0][RTW89_FCC][1][10] = -4, + [0][1][2][0][RTW89_FCC][2][10] = 54, + [0][1][2][0][RTW89_ETSI][1][10] = 54, + [0][1][2][0][RTW89_ETSI][0][10] = 18, + [0][1][2][0][RTW89_MKK][1][10] = 54, + [0][1][2][0][RTW89_MKK][0][10] = 16, + [0][1][2][0][RTW89_IC][1][10] = -4, + [0][1][2][0][RTW89_KCC][1][10] = 12, + [0][1][2][0][RTW89_KCC][0][10] = 12, + [0][1][2][0][RTW89_ACMA][1][10] = 54, + [0][1][2][0][RTW89_ACMA][0][10] = 18, + [0][1][2][0][RTW89_CHILE][1][10] = -4, + [0][1][2][0][RTW89_QATAR][1][10] = 54, + [0][1][2][0][RTW89_QATAR][0][10] = 18, + [0][1][2][0][RTW89_UK][1][10] = 54, + [0][1][2][0][RTW89_UK][0][10] = 18, + [0][1][2][0][RTW89_FCC][1][12] = -4, + [0][1][2][0][RTW89_FCC][2][12] = 54, + [0][1][2][0][RTW89_ETSI][1][12] = 54, + [0][1][2][0][RTW89_ETSI][0][12] = 18, + [0][1][2][0][RTW89_MKK][1][12] = 54, + [0][1][2][0][RTW89_MKK][0][12] = 16, + [0][1][2][0][RTW89_IC][1][12] = -4, + [0][1][2][0][RTW89_KCC][1][12] = 12, + [0][1][2][0][RTW89_KCC][0][12] = 12, + [0][1][2][0][RTW89_ACMA][1][12] = 54, + [0][1][2][0][RTW89_ACMA][0][12] = 18, + [0][1][2][0][RTW89_CHILE][1][12] = -4, + [0][1][2][0][RTW89_QATAR][1][12] = 54, + [0][1][2][0][RTW89_QATAR][0][12] = 18, + [0][1][2][0][RTW89_UK][1][12] = 54, + [0][1][2][0][RTW89_UK][0][12] = 18, + [0][1][2][0][RTW89_FCC][1][14] = -4, + [0][1][2][0][RTW89_FCC][2][14] = 54, + [0][1][2][0][RTW89_ETSI][1][14] = 54, + [0][1][2][0][RTW89_ETSI][0][14] = 18, + [0][1][2][0][RTW89_MKK][1][14] = 54, + [0][1][2][0][RTW89_MKK][0][14] = 16, + [0][1][2][0][RTW89_IC][1][14] = -4, + [0][1][2][0][RTW89_KCC][1][14] = 12, + [0][1][2][0][RTW89_KCC][0][14] = 12, + [0][1][2][0][RTW89_ACMA][1][14] = 54, + [0][1][2][0][RTW89_ACMA][0][14] = 18, + [0][1][2][0][RTW89_CHILE][1][14] = -4, + [0][1][2][0][RTW89_QATAR][1][14] = 54, + [0][1][2][0][RTW89_QATAR][0][14] = 18, + [0][1][2][0][RTW89_UK][1][14] = 54, + [0][1][2][0][RTW89_UK][0][14] = 18, + [0][1][2][0][RTW89_FCC][1][15] = -4, + [0][1][2][0][RTW89_FCC][2][15] = 54, + [0][1][2][0][RTW89_ETSI][1][15] = 54, + [0][1][2][0][RTW89_ETSI][0][15] = 18, + [0][1][2][0][RTW89_MKK][1][15] = 54, + [0][1][2][0][RTW89_MKK][0][15] = 16, + [0][1][2][0][RTW89_IC][1][15] = -4, + [0][1][2][0][RTW89_KCC][1][15] = 12, + [0][1][2][0][RTW89_KCC][0][15] = 12, + [0][1][2][0][RTW89_ACMA][1][15] = 54, + [0][1][2][0][RTW89_ACMA][0][15] = 18, + [0][1][2][0][RTW89_CHILE][1][15] = -4, + [0][1][2][0][RTW89_QATAR][1][15] = 54, + [0][1][2][0][RTW89_QATAR][0][15] = 18, + [0][1][2][0][RTW89_UK][1][15] = 54, + [0][1][2][0][RTW89_UK][0][15] = 18, + [0][1][2][0][RTW89_FCC][1][17] = -4, + [0][1][2][0][RTW89_FCC][2][17] = 54, + [0][1][2][0][RTW89_ETSI][1][17] = 54, + [0][1][2][0][RTW89_ETSI][0][17] = 18, + [0][1][2][0][RTW89_MKK][1][17] = 54, + [0][1][2][0][RTW89_MKK][0][17] = 16, + [0][1][2][0][RTW89_IC][1][17] = -4, + [0][1][2][0][RTW89_KCC][1][17] = 12, + [0][1][2][0][RTW89_KCC][0][17] = 12, + [0][1][2][0][RTW89_ACMA][1][17] = 54, + [0][1][2][0][RTW89_ACMA][0][17] = 18, + [0][1][2][0][RTW89_CHILE][1][17] = -4, + [0][1][2][0][RTW89_QATAR][1][17] = 54, + [0][1][2][0][RTW89_QATAR][0][17] = 18, + [0][1][2][0][RTW89_UK][1][17] = 54, + [0][1][2][0][RTW89_UK][0][17] = 18, + [0][1][2][0][RTW89_FCC][1][19] = -4, + [0][1][2][0][RTW89_FCC][2][19] = 54, + [0][1][2][0][RTW89_ETSI][1][19] = 54, + [0][1][2][0][RTW89_ETSI][0][19] = 18, + [0][1][2][0][RTW89_MKK][1][19] = 54, + [0][1][2][0][RTW89_MKK][0][19] = 16, + [0][1][2][0][RTW89_IC][1][19] = -4, + [0][1][2][0][RTW89_KCC][1][19] = 12, + [0][1][2][0][RTW89_KCC][0][19] = 12, + [0][1][2][0][RTW89_ACMA][1][19] = 54, + [0][1][2][0][RTW89_ACMA][0][19] = 18, + [0][1][2][0][RTW89_CHILE][1][19] = -4, + [0][1][2][0][RTW89_QATAR][1][19] = 54, + [0][1][2][0][RTW89_QATAR][0][19] = 18, + [0][1][2][0][RTW89_UK][1][19] = 54, + [0][1][2][0][RTW89_UK][0][19] = 18, + [0][1][2][0][RTW89_FCC][1][21] = -4, + [0][1][2][0][RTW89_FCC][2][21] = 54, + [0][1][2][0][RTW89_ETSI][1][21] = 54, + [0][1][2][0][RTW89_ETSI][0][21] = 18, + [0][1][2][0][RTW89_MKK][1][21] = 54, + [0][1][2][0][RTW89_MKK][0][21] = 16, + [0][1][2][0][RTW89_IC][1][21] = -4, + [0][1][2][0][RTW89_KCC][1][21] = 12, + [0][1][2][0][RTW89_KCC][0][21] = 12, + [0][1][2][0][RTW89_ACMA][1][21] = 54, + [0][1][2][0][RTW89_ACMA][0][21] = 18, + [0][1][2][0][RTW89_CHILE][1][21] = -4, + [0][1][2][0][RTW89_QATAR][1][21] = 54, + [0][1][2][0][RTW89_QATAR][0][21] = 18, + [0][1][2][0][RTW89_UK][1][21] = 54, + [0][1][2][0][RTW89_UK][0][21] = 18, + [0][1][2][0][RTW89_FCC][1][23] = -4, + [0][1][2][0][RTW89_FCC][2][23] = 68, + [0][1][2][0][RTW89_ETSI][1][23] = 54, + [0][1][2][0][RTW89_ETSI][0][23] = 18, + [0][1][2][0][RTW89_MKK][1][23] = 54, + [0][1][2][0][RTW89_MKK][0][23] = 16, + [0][1][2][0][RTW89_IC][1][23] = -4, + [0][1][2][0][RTW89_KCC][1][23] = 12, + [0][1][2][0][RTW89_KCC][0][23] = 10, + [0][1][2][0][RTW89_ACMA][1][23] = 54, + [0][1][2][0][RTW89_ACMA][0][23] = 18, + [0][1][2][0][RTW89_CHILE][1][23] = -4, + [0][1][2][0][RTW89_QATAR][1][23] = 54, + [0][1][2][0][RTW89_QATAR][0][23] = 18, + [0][1][2][0][RTW89_UK][1][23] = 54, + [0][1][2][0][RTW89_UK][0][23] = 18, + [0][1][2][0][RTW89_FCC][1][25] = -4, + [0][1][2][0][RTW89_FCC][2][25] = 68, + [0][1][2][0][RTW89_ETSI][1][25] = 54, + [0][1][2][0][RTW89_ETSI][0][25] = 18, + [0][1][2][0][RTW89_MKK][1][25] = 54, + [0][1][2][0][RTW89_MKK][0][25] = 16, + [0][1][2][0][RTW89_IC][1][25] = -4, + [0][1][2][0][RTW89_KCC][1][25] = 12, + [0][1][2][0][RTW89_KCC][0][25] = 14, + [0][1][2][0][RTW89_ACMA][1][25] = 54, + [0][1][2][0][RTW89_ACMA][0][25] = 18, + [0][1][2][0][RTW89_CHILE][1][25] = -4, + [0][1][2][0][RTW89_QATAR][1][25] = 54, + [0][1][2][0][RTW89_QATAR][0][25] = 18, + [0][1][2][0][RTW89_UK][1][25] = 54, + [0][1][2][0][RTW89_UK][0][25] = 18, + [0][1][2][0][RTW89_FCC][1][27] = -4, + [0][1][2][0][RTW89_FCC][2][27] = 68, + [0][1][2][0][RTW89_ETSI][1][27] = 54, + [0][1][2][0][RTW89_ETSI][0][27] = 18, + [0][1][2][0][RTW89_MKK][1][27] = 54, + [0][1][2][0][RTW89_MKK][0][27] = 16, + [0][1][2][0][RTW89_IC][1][27] = -4, + [0][1][2][0][RTW89_KCC][1][27] = 12, + [0][1][2][0][RTW89_KCC][0][27] = 14, + [0][1][2][0][RTW89_ACMA][1][27] = 54, + [0][1][2][0][RTW89_ACMA][0][27] = 18, + [0][1][2][0][RTW89_CHILE][1][27] = -4, + [0][1][2][0][RTW89_QATAR][1][27] = 54, + [0][1][2][0][RTW89_QATAR][0][27] = 18, + [0][1][2][0][RTW89_UK][1][27] = 54, + [0][1][2][0][RTW89_UK][0][27] = 18, + [0][1][2][0][RTW89_FCC][1][29] = -4, + [0][1][2][0][RTW89_FCC][2][29] = 68, + [0][1][2][0][RTW89_ETSI][1][29] = 54, + [0][1][2][0][RTW89_ETSI][0][29] = 18, + [0][1][2][0][RTW89_MKK][1][29] = 54, + [0][1][2][0][RTW89_MKK][0][29] = 16, + [0][1][2][0][RTW89_IC][1][29] = -4, + [0][1][2][0][RTW89_KCC][1][29] = 12, + [0][1][2][0][RTW89_KCC][0][29] = 14, + [0][1][2][0][RTW89_ACMA][1][29] = 54, + [0][1][2][0][RTW89_ACMA][0][29] = 18, + [0][1][2][0][RTW89_CHILE][1][29] = -4, + [0][1][2][0][RTW89_QATAR][1][29] = 54, + [0][1][2][0][RTW89_QATAR][0][29] = 18, + [0][1][2][0][RTW89_UK][1][29] = 54, + [0][1][2][0][RTW89_UK][0][29] = 18, + [0][1][2][0][RTW89_FCC][1][30] = -4, + [0][1][2][0][RTW89_FCC][2][30] = 68, + [0][1][2][0][RTW89_ETSI][1][30] = 54, + [0][1][2][0][RTW89_ETSI][0][30] = 18, + [0][1][2][0][RTW89_MKK][1][30] = 54, + [0][1][2][0][RTW89_MKK][0][30] = 16, + [0][1][2][0][RTW89_IC][1][30] = -4, + [0][1][2][0][RTW89_KCC][1][30] = 12, + [0][1][2][0][RTW89_KCC][0][30] = 14, + [0][1][2][0][RTW89_ACMA][1][30] = 54, + [0][1][2][0][RTW89_ACMA][0][30] = 18, + [0][1][2][0][RTW89_CHILE][1][30] = -4, + [0][1][2][0][RTW89_QATAR][1][30] = 54, + [0][1][2][0][RTW89_QATAR][0][30] = 18, + [0][1][2][0][RTW89_UK][1][30] = 54, + [0][1][2][0][RTW89_UK][0][30] = 18, + [0][1][2][0][RTW89_FCC][1][32] = -4, + [0][1][2][0][RTW89_FCC][2][32] = 68, + [0][1][2][0][RTW89_ETSI][1][32] = 54, + [0][1][2][0][RTW89_ETSI][0][32] = 18, + [0][1][2][0][RTW89_MKK][1][32] = 54, + [0][1][2][0][RTW89_MKK][0][32] = 16, + [0][1][2][0][RTW89_IC][1][32] = -4, + [0][1][2][0][RTW89_KCC][1][32] = 12, + [0][1][2][0][RTW89_KCC][0][32] = 14, + [0][1][2][0][RTW89_ACMA][1][32] = 54, + [0][1][2][0][RTW89_ACMA][0][32] = 18, + [0][1][2][0][RTW89_CHILE][1][32] = -4, + [0][1][2][0][RTW89_QATAR][1][32] = 54, + [0][1][2][0][RTW89_QATAR][0][32] = 18, + [0][1][2][0][RTW89_UK][1][32] = 54, + [0][1][2][0][RTW89_UK][0][32] = 18, + [0][1][2][0][RTW89_FCC][1][34] = -4, + [0][1][2][0][RTW89_FCC][2][34] = 68, + [0][1][2][0][RTW89_ETSI][1][34] = 54, + [0][1][2][0][RTW89_ETSI][0][34] = 18, + [0][1][2][0][RTW89_MKK][1][34] = 54, + [0][1][2][0][RTW89_MKK][0][34] = 16, + [0][1][2][0][RTW89_IC][1][34] = -4, + [0][1][2][0][RTW89_KCC][1][34] = 12, + [0][1][2][0][RTW89_KCC][0][34] = 14, + [0][1][2][0][RTW89_ACMA][1][34] = 54, + [0][1][2][0][RTW89_ACMA][0][34] = 18, + [0][1][2][0][RTW89_CHILE][1][34] = -4, + [0][1][2][0][RTW89_QATAR][1][34] = 54, + [0][1][2][0][RTW89_QATAR][0][34] = 18, + [0][1][2][0][RTW89_UK][1][34] = 54, + [0][1][2][0][RTW89_UK][0][34] = 18, + [0][1][2][0][RTW89_FCC][1][36] = -4, + [0][1][2][0][RTW89_FCC][2][36] = 68, + [0][1][2][0][RTW89_ETSI][1][36] = 54, + [0][1][2][0][RTW89_ETSI][0][36] = 18, + [0][1][2][0][RTW89_MKK][1][36] = 54, + [0][1][2][0][RTW89_MKK][0][36] = 16, + [0][1][2][0][RTW89_IC][1][36] = -4, + [0][1][2][0][RTW89_KCC][1][36] = 12, + [0][1][2][0][RTW89_KCC][0][36] = 14, + [0][1][2][0][RTW89_ACMA][1][36] = 54, + [0][1][2][0][RTW89_ACMA][0][36] = 18, + [0][1][2][0][RTW89_CHILE][1][36] = -4, + [0][1][2][0][RTW89_QATAR][1][36] = 54, + [0][1][2][0][RTW89_QATAR][0][36] = 18, + [0][1][2][0][RTW89_UK][1][36] = 54, + [0][1][2][0][RTW89_UK][0][36] = 18, + [0][1][2][0][RTW89_FCC][1][38] = -4, + [0][1][2][0][RTW89_FCC][2][38] = 68, + [0][1][2][0][RTW89_ETSI][1][38] = 54, + [0][1][2][0][RTW89_ETSI][0][38] = 18, + [0][1][2][0][RTW89_MKK][1][38] = 54, + [0][1][2][0][RTW89_MKK][0][38] = 16, + [0][1][2][0][RTW89_IC][1][38] = -4, + [0][1][2][0][RTW89_KCC][1][38] = 12, + [0][1][2][0][RTW89_KCC][0][38] = 14, + [0][1][2][0][RTW89_ACMA][1][38] = 54, + [0][1][2][0][RTW89_ACMA][0][38] = 18, + [0][1][2][0][RTW89_CHILE][1][38] = -4, + [0][1][2][0][RTW89_QATAR][1][38] = 54, + [0][1][2][0][RTW89_QATAR][0][38] = 18, + [0][1][2][0][RTW89_UK][1][38] = 54, + [0][1][2][0][RTW89_UK][0][38] = 18, + [0][1][2][0][RTW89_FCC][1][40] = -4, + [0][1][2][0][RTW89_FCC][2][40] = 68, + [0][1][2][0][RTW89_ETSI][1][40] = 54, + [0][1][2][0][RTW89_ETSI][0][40] = 18, + [0][1][2][0][RTW89_MKK][1][40] = 54, + [0][1][2][0][RTW89_MKK][0][40] = 16, + [0][1][2][0][RTW89_IC][1][40] = -4, + [0][1][2][0][RTW89_KCC][1][40] = 12, + [0][1][2][0][RTW89_KCC][0][40] = 14, + [0][1][2][0][RTW89_ACMA][1][40] = 54, + [0][1][2][0][RTW89_ACMA][0][40] = 18, + [0][1][2][0][RTW89_CHILE][1][40] = -4, + [0][1][2][0][RTW89_QATAR][1][40] = 54, + [0][1][2][0][RTW89_QATAR][0][40] = 18, + [0][1][2][0][RTW89_UK][1][40] = 54, + [0][1][2][0][RTW89_UK][0][40] = 18, + [0][1][2][0][RTW89_FCC][1][42] = -4, + [0][1][2][0][RTW89_FCC][2][42] = 68, + [0][1][2][0][RTW89_ETSI][1][42] = 54, + [0][1][2][0][RTW89_ETSI][0][42] = 18, + [0][1][2][0][RTW89_MKK][1][42] = 54, + [0][1][2][0][RTW89_MKK][0][42] = 16, + [0][1][2][0][RTW89_IC][1][42] = -4, + [0][1][2][0][RTW89_KCC][1][42] = 12, + [0][1][2][0][RTW89_KCC][0][42] = 14, + [0][1][2][0][RTW89_ACMA][1][42] = 54, + [0][1][2][0][RTW89_ACMA][0][42] = 18, + [0][1][2][0][RTW89_CHILE][1][42] = -4, + [0][1][2][0][RTW89_QATAR][1][42] = 54, + [0][1][2][0][RTW89_QATAR][0][42] = 18, + [0][1][2][0][RTW89_UK][1][42] = 54, + [0][1][2][0][RTW89_UK][0][42] = 18, + [0][1][2][0][RTW89_FCC][1][44] = -2, + [0][1][2][0][RTW89_FCC][2][44] = 68, + [0][1][2][0][RTW89_ETSI][1][44] = 54, + [0][1][2][0][RTW89_ETSI][0][44] = 18, + [0][1][2][0][RTW89_MKK][1][44] = 34, + [0][1][2][0][RTW89_MKK][0][44] = 16, + [0][1][2][0][RTW89_IC][1][44] = -2, + [0][1][2][0][RTW89_KCC][1][44] = 12, + [0][1][2][0][RTW89_KCC][0][44] = 12, + [0][1][2][0][RTW89_ACMA][1][44] = 54, + [0][1][2][0][RTW89_ACMA][0][44] = 18, + [0][1][2][0][RTW89_CHILE][1][44] = -2, + [0][1][2][0][RTW89_QATAR][1][44] = 54, + [0][1][2][0][RTW89_QATAR][0][44] = 18, + [0][1][2][0][RTW89_UK][1][44] = 54, + [0][1][2][0][RTW89_UK][0][44] = 18, + [0][1][2][0][RTW89_FCC][1][45] = -2, + [0][1][2][0][RTW89_FCC][2][45] = 127, + [0][1][2][0][RTW89_ETSI][1][45] = 127, + [0][1][2][0][RTW89_ETSI][0][45] = 127, + [0][1][2][0][RTW89_MKK][1][45] = 127, + [0][1][2][0][RTW89_MKK][0][45] = 127, + [0][1][2][0][RTW89_IC][1][45] = -2, + [0][1][2][0][RTW89_KCC][1][45] = 12, + [0][1][2][0][RTW89_KCC][0][45] = 127, + [0][1][2][0][RTW89_ACMA][1][45] = 127, + [0][1][2][0][RTW89_ACMA][0][45] = 127, + [0][1][2][0][RTW89_CHILE][1][45] = -2, + [0][1][2][0][RTW89_QATAR][1][45] = 127, + [0][1][2][0][RTW89_QATAR][0][45] = 127, + [0][1][2][0][RTW89_UK][1][45] = 127, + [0][1][2][0][RTW89_UK][0][45] = 127, + [0][1][2][0][RTW89_FCC][1][47] = -2, + [0][1][2][0][RTW89_FCC][2][47] = 127, + [0][1][2][0][RTW89_ETSI][1][47] = 127, + [0][1][2][0][RTW89_ETSI][0][47] = 127, + [0][1][2][0][RTW89_MKK][1][47] = 127, + [0][1][2][0][RTW89_MKK][0][47] = 127, + [0][1][2][0][RTW89_IC][1][47] = -2, + [0][1][2][0][RTW89_KCC][1][47] = 12, + [0][1][2][0][RTW89_KCC][0][47] = 127, + [0][1][2][0][RTW89_ACMA][1][47] = 127, + [0][1][2][0][RTW89_ACMA][0][47] = 127, + [0][1][2][0][RTW89_CHILE][1][47] = -2, + [0][1][2][0][RTW89_QATAR][1][47] = 127, + [0][1][2][0][RTW89_QATAR][0][47] = 127, + [0][1][2][0][RTW89_UK][1][47] = 127, + [0][1][2][0][RTW89_UK][0][47] = 127, + [0][1][2][0][RTW89_FCC][1][49] = -2, + [0][1][2][0][RTW89_FCC][2][49] = 127, + [0][1][2][0][RTW89_ETSI][1][49] = 127, + [0][1][2][0][RTW89_ETSI][0][49] = 127, + [0][1][2][0][RTW89_MKK][1][49] = 127, + [0][1][2][0][RTW89_MKK][0][49] = 127, + [0][1][2][0][RTW89_IC][1][49] = -2, + [0][1][2][0][RTW89_KCC][1][49] = 12, + [0][1][2][0][RTW89_KCC][0][49] = 127, + [0][1][2][0][RTW89_ACMA][1][49] = 127, + [0][1][2][0][RTW89_ACMA][0][49] = 127, + [0][1][2][0][RTW89_CHILE][1][49] = -2, + [0][1][2][0][RTW89_QATAR][1][49] = 127, + [0][1][2][0][RTW89_QATAR][0][49] = 127, + [0][1][2][0][RTW89_UK][1][49] = 127, + [0][1][2][0][RTW89_UK][0][49] = 127, + [0][1][2][0][RTW89_FCC][1][51] = -2, + [0][1][2][0][RTW89_FCC][2][51] = 127, + [0][1][2][0][RTW89_ETSI][1][51] = 127, + [0][1][2][0][RTW89_ETSI][0][51] = 127, + [0][1][2][0][RTW89_MKK][1][51] = 127, + [0][1][2][0][RTW89_MKK][0][51] = 127, + [0][1][2][0][RTW89_IC][1][51] = -2, + [0][1][2][0][RTW89_KCC][1][51] = 12, + [0][1][2][0][RTW89_KCC][0][51] = 127, + [0][1][2][0][RTW89_ACMA][1][51] = 127, + [0][1][2][0][RTW89_ACMA][0][51] = 127, + [0][1][2][0][RTW89_CHILE][1][51] = -2, + [0][1][2][0][RTW89_QATAR][1][51] = 127, + [0][1][2][0][RTW89_QATAR][0][51] = 127, + [0][1][2][0][RTW89_UK][1][51] = 127, + [0][1][2][0][RTW89_UK][0][51] = 127, + [0][1][2][0][RTW89_FCC][1][53] = -2, + [0][1][2][0][RTW89_FCC][2][53] = 127, + [0][1][2][0][RTW89_ETSI][1][53] = 127, + [0][1][2][0][RTW89_ETSI][0][53] = 127, + [0][1][2][0][RTW89_MKK][1][53] = 127, + [0][1][2][0][RTW89_MKK][0][53] = 127, + [0][1][2][0][RTW89_IC][1][53] = -2, + [0][1][2][0][RTW89_KCC][1][53] = 12, + [0][1][2][0][RTW89_KCC][0][53] = 127, + [0][1][2][0][RTW89_ACMA][1][53] = 127, + [0][1][2][0][RTW89_ACMA][0][53] = 127, + [0][1][2][0][RTW89_CHILE][1][53] = -2, + [0][1][2][0][RTW89_QATAR][1][53] = 127, + [0][1][2][0][RTW89_QATAR][0][53] = 127, + [0][1][2][0][RTW89_UK][1][53] = 127, + [0][1][2][0][RTW89_UK][0][53] = 127, + [0][1][2][0][RTW89_FCC][1][55] = -2, + [0][1][2][0][RTW89_FCC][2][55] = 68, + [0][1][2][0][RTW89_ETSI][1][55] = 127, + [0][1][2][0][RTW89_ETSI][0][55] = 127, + [0][1][2][0][RTW89_MKK][1][55] = 127, + [0][1][2][0][RTW89_MKK][0][55] = 127, + [0][1][2][0][RTW89_IC][1][55] = -2, + [0][1][2][0][RTW89_KCC][1][55] = 12, + [0][1][2][0][RTW89_KCC][0][55] = 127, + [0][1][2][0][RTW89_ACMA][1][55] = 127, + [0][1][2][0][RTW89_ACMA][0][55] = 127, + [0][1][2][0][RTW89_CHILE][1][55] = -2, + [0][1][2][0][RTW89_QATAR][1][55] = 127, + [0][1][2][0][RTW89_QATAR][0][55] = 127, + [0][1][2][0][RTW89_UK][1][55] = 127, + [0][1][2][0][RTW89_UK][0][55] = 127, + [0][1][2][0][RTW89_FCC][1][57] = -2, + [0][1][2][0][RTW89_FCC][2][57] = 68, + [0][1][2][0][RTW89_ETSI][1][57] = 127, + [0][1][2][0][RTW89_ETSI][0][57] = 127, + [0][1][2][0][RTW89_MKK][1][57] = 127, + [0][1][2][0][RTW89_MKK][0][57] = 127, + [0][1][2][0][RTW89_IC][1][57] = -2, + [0][1][2][0][RTW89_KCC][1][57] = 12, + [0][1][2][0][RTW89_KCC][0][57] = 127, + [0][1][2][0][RTW89_ACMA][1][57] = 127, + [0][1][2][0][RTW89_ACMA][0][57] = 127, + [0][1][2][0][RTW89_CHILE][1][57] = -2, + [0][1][2][0][RTW89_QATAR][1][57] = 127, + [0][1][2][0][RTW89_QATAR][0][57] = 127, + [0][1][2][0][RTW89_UK][1][57] = 127, + [0][1][2][0][RTW89_UK][0][57] = 127, + [0][1][2][0][RTW89_FCC][1][59] = -2, + [0][1][2][0][RTW89_FCC][2][59] = 68, + [0][1][2][0][RTW89_ETSI][1][59] = 127, + [0][1][2][0][RTW89_ETSI][0][59] = 127, + [0][1][2][0][RTW89_MKK][1][59] = 127, + [0][1][2][0][RTW89_MKK][0][59] = 127, + [0][1][2][0][RTW89_IC][1][59] = -2, + [0][1][2][0][RTW89_KCC][1][59] = 12, + [0][1][2][0][RTW89_KCC][0][59] = 127, + [0][1][2][0][RTW89_ACMA][1][59] = 127, + [0][1][2][0][RTW89_ACMA][0][59] = 127, + [0][1][2][0][RTW89_CHILE][1][59] = -2, + [0][1][2][0][RTW89_QATAR][1][59] = 127, + [0][1][2][0][RTW89_QATAR][0][59] = 127, + [0][1][2][0][RTW89_UK][1][59] = 127, + [0][1][2][0][RTW89_UK][0][59] = 127, + [0][1][2][0][RTW89_FCC][1][60] = -2, + [0][1][2][0][RTW89_FCC][2][60] = 68, + [0][1][2][0][RTW89_ETSI][1][60] = 127, + [0][1][2][0][RTW89_ETSI][0][60] = 127, + [0][1][2][0][RTW89_MKK][1][60] = 127, + [0][1][2][0][RTW89_MKK][0][60] = 127, + [0][1][2][0][RTW89_IC][1][60] = -2, + [0][1][2][0][RTW89_KCC][1][60] = 12, + [0][1][2][0][RTW89_KCC][0][60] = 127, + [0][1][2][0][RTW89_ACMA][1][60] = 127, + [0][1][2][0][RTW89_ACMA][0][60] = 127, + [0][1][2][0][RTW89_CHILE][1][60] = -2, + [0][1][2][0][RTW89_QATAR][1][60] = 127, + [0][1][2][0][RTW89_QATAR][0][60] = 127, + [0][1][2][0][RTW89_UK][1][60] = 127, + [0][1][2][0][RTW89_UK][0][60] = 127, + [0][1][2][0][RTW89_FCC][1][62] = -2, + [0][1][2][0][RTW89_FCC][2][62] = 68, + [0][1][2][0][RTW89_ETSI][1][62] = 127, + [0][1][2][0][RTW89_ETSI][0][62] = 127, + [0][1][2][0][RTW89_MKK][1][62] = 127, + [0][1][2][0][RTW89_MKK][0][62] = 127, + [0][1][2][0][RTW89_IC][1][62] = -2, + [0][1][2][0][RTW89_KCC][1][62] = 12, + [0][1][2][0][RTW89_KCC][0][62] = 127, + [0][1][2][0][RTW89_ACMA][1][62] = 127, + [0][1][2][0][RTW89_ACMA][0][62] = 127, + [0][1][2][0][RTW89_CHILE][1][62] = -2, + [0][1][2][0][RTW89_QATAR][1][62] = 127, + [0][1][2][0][RTW89_QATAR][0][62] = 127, + [0][1][2][0][RTW89_UK][1][62] = 127, + [0][1][2][0][RTW89_UK][0][62] = 127, + [0][1][2][0][RTW89_FCC][1][64] = -2, + [0][1][2][0][RTW89_FCC][2][64] = 68, + [0][1][2][0][RTW89_ETSI][1][64] = 127, + [0][1][2][0][RTW89_ETSI][0][64] = 127, + [0][1][2][0][RTW89_MKK][1][64] = 127, + [0][1][2][0][RTW89_MKK][0][64] = 127, + [0][1][2][0][RTW89_IC][1][64] = -2, + [0][1][2][0][RTW89_KCC][1][64] = 12, + [0][1][2][0][RTW89_KCC][0][64] = 127, + [0][1][2][0][RTW89_ACMA][1][64] = 127, + [0][1][2][0][RTW89_ACMA][0][64] = 127, + [0][1][2][0][RTW89_CHILE][1][64] = -2, + [0][1][2][0][RTW89_QATAR][1][64] = 127, + [0][1][2][0][RTW89_QATAR][0][64] = 127, + [0][1][2][0][RTW89_UK][1][64] = 127, + [0][1][2][0][RTW89_UK][0][64] = 127, + [0][1][2][0][RTW89_FCC][1][66] = -2, + [0][1][2][0][RTW89_FCC][2][66] = 68, + [0][1][2][0][RTW89_ETSI][1][66] = 127, + [0][1][2][0][RTW89_ETSI][0][66] = 127, + [0][1][2][0][RTW89_MKK][1][66] = 127, + [0][1][2][0][RTW89_MKK][0][66] = 127, + [0][1][2][0][RTW89_IC][1][66] = -2, + [0][1][2][0][RTW89_KCC][1][66] = 12, + [0][1][2][0][RTW89_KCC][0][66] = 127, + [0][1][2][0][RTW89_ACMA][1][66] = 127, + [0][1][2][0][RTW89_ACMA][0][66] = 127, + [0][1][2][0][RTW89_CHILE][1][66] = -2, + [0][1][2][0][RTW89_QATAR][1][66] = 127, + [0][1][2][0][RTW89_QATAR][0][66] = 127, + [0][1][2][0][RTW89_UK][1][66] = 127, + [0][1][2][0][RTW89_UK][0][66] = 127, + [0][1][2][0][RTW89_FCC][1][68] = -2, + [0][1][2][0][RTW89_FCC][2][68] = 68, + [0][1][2][0][RTW89_ETSI][1][68] = 127, + [0][1][2][0][RTW89_ETSI][0][68] = 127, + [0][1][2][0][RTW89_MKK][1][68] = 127, + [0][1][2][0][RTW89_MKK][0][68] = 127, + [0][1][2][0][RTW89_IC][1][68] = -2, + [0][1][2][0][RTW89_KCC][1][68] = 12, + [0][1][2][0][RTW89_KCC][0][68] = 127, + [0][1][2][0][RTW89_ACMA][1][68] = 127, + [0][1][2][0][RTW89_ACMA][0][68] = 127, + [0][1][2][0][RTW89_CHILE][1][68] = -2, + [0][1][2][0][RTW89_QATAR][1][68] = 127, + [0][1][2][0][RTW89_QATAR][0][68] = 127, + [0][1][2][0][RTW89_UK][1][68] = 127, + [0][1][2][0][RTW89_UK][0][68] = 127, + [0][1][2][0][RTW89_FCC][1][70] = -2, + [0][1][2][0][RTW89_FCC][2][70] = 68, + [0][1][2][0][RTW89_ETSI][1][70] = 127, + [0][1][2][0][RTW89_ETSI][0][70] = 127, + [0][1][2][0][RTW89_MKK][1][70] = 127, + [0][1][2][0][RTW89_MKK][0][70] = 127, + [0][1][2][0][RTW89_IC][1][70] = -2, + [0][1][2][0][RTW89_KCC][1][70] = 12, + [0][1][2][0][RTW89_KCC][0][70] = 127, + [0][1][2][0][RTW89_ACMA][1][70] = 127, + [0][1][2][0][RTW89_ACMA][0][70] = 127, + [0][1][2][0][RTW89_CHILE][1][70] = -2, + [0][1][2][0][RTW89_QATAR][1][70] = 127, + [0][1][2][0][RTW89_QATAR][0][70] = 127, + [0][1][2][0][RTW89_UK][1][70] = 127, + [0][1][2][0][RTW89_UK][0][70] = 127, + [0][1][2][0][RTW89_FCC][1][72] = -2, + [0][1][2][0][RTW89_FCC][2][72] = 68, + [0][1][2][0][RTW89_ETSI][1][72] = 127, + [0][1][2][0][RTW89_ETSI][0][72] = 127, + [0][1][2][0][RTW89_MKK][1][72] = 127, + [0][1][2][0][RTW89_MKK][0][72] = 127, + [0][1][2][0][RTW89_IC][1][72] = -2, + [0][1][2][0][RTW89_KCC][1][72] = 12, + [0][1][2][0][RTW89_KCC][0][72] = 127, + [0][1][2][0][RTW89_ACMA][1][72] = 127, + [0][1][2][0][RTW89_ACMA][0][72] = 127, + [0][1][2][0][RTW89_CHILE][1][72] = -2, + [0][1][2][0][RTW89_QATAR][1][72] = 127, + [0][1][2][0][RTW89_QATAR][0][72] = 127, + [0][1][2][0][RTW89_UK][1][72] = 127, + [0][1][2][0][RTW89_UK][0][72] = 127, + [0][1][2][0][RTW89_FCC][1][74] = -2, + [0][1][2][0][RTW89_FCC][2][74] = 68, + [0][1][2][0][RTW89_ETSI][1][74] = 127, + [0][1][2][0][RTW89_ETSI][0][74] = 127, + [0][1][2][0][RTW89_MKK][1][74] = 127, + [0][1][2][0][RTW89_MKK][0][74] = 127, + [0][1][2][0][RTW89_IC][1][74] = -2, + [0][1][2][0][RTW89_KCC][1][74] = 12, + [0][1][2][0][RTW89_KCC][0][74] = 127, + [0][1][2][0][RTW89_ACMA][1][74] = 127, + [0][1][2][0][RTW89_ACMA][0][74] = 127, + [0][1][2][0][RTW89_CHILE][1][74] = -2, + [0][1][2][0][RTW89_QATAR][1][74] = 127, + [0][1][2][0][RTW89_QATAR][0][74] = 127, + [0][1][2][0][RTW89_UK][1][74] = 127, + [0][1][2][0][RTW89_UK][0][74] = 127, + [0][1][2][0][RTW89_FCC][1][75] = -2, + [0][1][2][0][RTW89_FCC][2][75] = 68, + [0][1][2][0][RTW89_ETSI][1][75] = 127, + [0][1][2][0][RTW89_ETSI][0][75] = 127, + [0][1][2][0][RTW89_MKK][1][75] = 127, + [0][1][2][0][RTW89_MKK][0][75] = 127, + [0][1][2][0][RTW89_IC][1][75] = -2, + [0][1][2][0][RTW89_KCC][1][75] = 12, + [0][1][2][0][RTW89_KCC][0][75] = 127, + [0][1][2][0][RTW89_ACMA][1][75] = 127, + [0][1][2][0][RTW89_ACMA][0][75] = 127, + [0][1][2][0][RTW89_CHILE][1][75] = -2, + [0][1][2][0][RTW89_QATAR][1][75] = 127, + [0][1][2][0][RTW89_QATAR][0][75] = 127, + [0][1][2][0][RTW89_UK][1][75] = 127, + [0][1][2][0][RTW89_UK][0][75] = 127, + [0][1][2][0][RTW89_FCC][1][77] = -2, + [0][1][2][0][RTW89_FCC][2][77] = 68, + [0][1][2][0][RTW89_ETSI][1][77] = 127, + [0][1][2][0][RTW89_ETSI][0][77] = 127, + [0][1][2][0][RTW89_MKK][1][77] = 127, + [0][1][2][0][RTW89_MKK][0][77] = 127, + [0][1][2][0][RTW89_IC][1][77] = -2, + [0][1][2][0][RTW89_KCC][1][77] = 12, + [0][1][2][0][RTW89_KCC][0][77] = 127, + [0][1][2][0][RTW89_ACMA][1][77] = 127, + [0][1][2][0][RTW89_ACMA][0][77] = 127, + [0][1][2][0][RTW89_CHILE][1][77] = -2, + [0][1][2][0][RTW89_QATAR][1][77] = 127, + [0][1][2][0][RTW89_QATAR][0][77] = 127, + [0][1][2][0][RTW89_UK][1][77] = 127, + [0][1][2][0][RTW89_UK][0][77] = 127, + [0][1][2][0][RTW89_FCC][1][79] = -2, + [0][1][2][0][RTW89_FCC][2][79] = 68, + [0][1][2][0][RTW89_ETSI][1][79] = 127, + [0][1][2][0][RTW89_ETSI][0][79] = 127, + [0][1][2][0][RTW89_MKK][1][79] = 127, + [0][1][2][0][RTW89_MKK][0][79] = 127, + [0][1][2][0][RTW89_IC][1][79] = -2, + [0][1][2][0][RTW89_KCC][1][79] = 12, + [0][1][2][0][RTW89_KCC][0][79] = 127, + [0][1][2][0][RTW89_ACMA][1][79] = 127, + [0][1][2][0][RTW89_ACMA][0][79] = 127, + [0][1][2][0][RTW89_CHILE][1][79] = -2, + [0][1][2][0][RTW89_QATAR][1][79] = 127, + [0][1][2][0][RTW89_QATAR][0][79] = 127, + [0][1][2][0][RTW89_UK][1][79] = 127, + [0][1][2][0][RTW89_UK][0][79] = 127, + [0][1][2][0][RTW89_FCC][1][81] = -2, + [0][1][2][0][RTW89_FCC][2][81] = 68, + [0][1][2][0][RTW89_ETSI][1][81] = 127, + [0][1][2][0][RTW89_ETSI][0][81] = 127, + [0][1][2][0][RTW89_MKK][1][81] = 127, + [0][1][2][0][RTW89_MKK][0][81] = 127, + [0][1][2][0][RTW89_IC][1][81] = -2, + [0][1][2][0][RTW89_KCC][1][81] = 12, + [0][1][2][0][RTW89_KCC][0][81] = 127, + [0][1][2][0][RTW89_ACMA][1][81] = 127, + [0][1][2][0][RTW89_ACMA][0][81] = 127, + [0][1][2][0][RTW89_CHILE][1][81] = -2, + [0][1][2][0][RTW89_QATAR][1][81] = 127, + [0][1][2][0][RTW89_QATAR][0][81] = 127, + [0][1][2][0][RTW89_UK][1][81] = 127, + [0][1][2][0][RTW89_UK][0][81] = 127, + [0][1][2][0][RTW89_FCC][1][83] = -2, + [0][1][2][0][RTW89_FCC][2][83] = 68, + [0][1][2][0][RTW89_ETSI][1][83] = 127, + [0][1][2][0][RTW89_ETSI][0][83] = 127, + [0][1][2][0][RTW89_MKK][1][83] = 127, + [0][1][2][0][RTW89_MKK][0][83] = 127, + [0][1][2][0][RTW89_IC][1][83] = -2, + [0][1][2][0][RTW89_KCC][1][83] = 20, + [0][1][2][0][RTW89_KCC][0][83] = 127, + [0][1][2][0][RTW89_ACMA][1][83] = 127, + [0][1][2][0][RTW89_ACMA][0][83] = 127, + [0][1][2][0][RTW89_CHILE][1][83] = -2, + [0][1][2][0][RTW89_QATAR][1][83] = 127, + [0][1][2][0][RTW89_QATAR][0][83] = 127, + [0][1][2][0][RTW89_UK][1][83] = 127, + [0][1][2][0][RTW89_UK][0][83] = 127, + [0][1][2][0][RTW89_FCC][1][85] = -2, + [0][1][2][0][RTW89_FCC][2][85] = 68, + [0][1][2][0][RTW89_ETSI][1][85] = 127, + [0][1][2][0][RTW89_ETSI][0][85] = 127, + [0][1][2][0][RTW89_MKK][1][85] = 127, + [0][1][2][0][RTW89_MKK][0][85] = 127, + [0][1][2][0][RTW89_IC][1][85] = -2, + [0][1][2][0][RTW89_KCC][1][85] = 20, + [0][1][2][0][RTW89_KCC][0][85] = 127, + [0][1][2][0][RTW89_ACMA][1][85] = 127, + [0][1][2][0][RTW89_ACMA][0][85] = 127, + [0][1][2][0][RTW89_CHILE][1][85] = -2, + [0][1][2][0][RTW89_QATAR][1][85] = 127, + [0][1][2][0][RTW89_QATAR][0][85] = 127, + [0][1][2][0][RTW89_UK][1][85] = 127, + [0][1][2][0][RTW89_UK][0][85] = 127, + [0][1][2][0][RTW89_FCC][1][87] = -2, + [0][1][2][0][RTW89_FCC][2][87] = 127, + [0][1][2][0][RTW89_ETSI][1][87] = 127, + [0][1][2][0][RTW89_ETSI][0][87] = 127, + [0][1][2][0][RTW89_MKK][1][87] = 127, + [0][1][2][0][RTW89_MKK][0][87] = 127, + [0][1][2][0][RTW89_IC][1][87] = -2, + [0][1][2][0][RTW89_KCC][1][87] = 20, + [0][1][2][0][RTW89_KCC][0][87] = 127, + [0][1][2][0][RTW89_ACMA][1][87] = 127, + [0][1][2][0][RTW89_ACMA][0][87] = 127, + [0][1][2][0][RTW89_CHILE][1][87] = -2, + [0][1][2][0][RTW89_QATAR][1][87] = 127, + [0][1][2][0][RTW89_QATAR][0][87] = 127, + [0][1][2][0][RTW89_UK][1][87] = 127, + [0][1][2][0][RTW89_UK][0][87] = 127, + [0][1][2][0][RTW89_FCC][1][89] = -2, + [0][1][2][0][RTW89_FCC][2][89] = 127, + [0][1][2][0][RTW89_ETSI][1][89] = 127, + [0][1][2][0][RTW89_ETSI][0][89] = 127, + [0][1][2][0][RTW89_MKK][1][89] = 127, + [0][1][2][0][RTW89_MKK][0][89] = 127, + [0][1][2][0][RTW89_IC][1][89] = -2, + [0][1][2][0][RTW89_KCC][1][89] = 20, + [0][1][2][0][RTW89_KCC][0][89] = 127, + [0][1][2][0][RTW89_ACMA][1][89] = 127, + [0][1][2][0][RTW89_ACMA][0][89] = 127, + [0][1][2][0][RTW89_CHILE][1][89] = -2, + [0][1][2][0][RTW89_QATAR][1][89] = 127, + [0][1][2][0][RTW89_QATAR][0][89] = 127, + [0][1][2][0][RTW89_UK][1][89] = 127, + [0][1][2][0][RTW89_UK][0][89] = 127, + [0][1][2][0][RTW89_FCC][1][90] = -2, + [0][1][2][0][RTW89_FCC][2][90] = 127, + [0][1][2][0][RTW89_ETSI][1][90] = 127, + [0][1][2][0][RTW89_ETSI][0][90] = 127, + [0][1][2][0][RTW89_MKK][1][90] = 127, + [0][1][2][0][RTW89_MKK][0][90] = 127, + [0][1][2][0][RTW89_IC][1][90] = -2, + [0][1][2][0][RTW89_KCC][1][90] = 20, + [0][1][2][0][RTW89_KCC][0][90] = 127, + [0][1][2][0][RTW89_ACMA][1][90] = 127, + [0][1][2][0][RTW89_ACMA][0][90] = 127, + [0][1][2][0][RTW89_CHILE][1][90] = -2, + [0][1][2][0][RTW89_QATAR][1][90] = 127, + [0][1][2][0][RTW89_QATAR][0][90] = 127, + [0][1][2][0][RTW89_UK][1][90] = 127, + [0][1][2][0][RTW89_UK][0][90] = 127, + [0][1][2][0][RTW89_FCC][1][92] = -2, + [0][1][2][0][RTW89_FCC][2][92] = 127, + [0][1][2][0][RTW89_ETSI][1][92] = 127, + [0][1][2][0][RTW89_ETSI][0][92] = 127, + [0][1][2][0][RTW89_MKK][1][92] = 127, + [0][1][2][0][RTW89_MKK][0][92] = 127, + [0][1][2][0][RTW89_IC][1][92] = -2, + [0][1][2][0][RTW89_KCC][1][92] = 20, + [0][1][2][0][RTW89_KCC][0][92] = 127, + [0][1][2][0][RTW89_ACMA][1][92] = 127, + [0][1][2][0][RTW89_ACMA][0][92] = 127, + [0][1][2][0][RTW89_CHILE][1][92] = -2, + [0][1][2][0][RTW89_QATAR][1][92] = 127, + [0][1][2][0][RTW89_QATAR][0][92] = 127, + [0][1][2][0][RTW89_UK][1][92] = 127, + [0][1][2][0][RTW89_UK][0][92] = 127, + [0][1][2][0][RTW89_FCC][1][94] = -2, + [0][1][2][0][RTW89_FCC][2][94] = 127, + [0][1][2][0][RTW89_ETSI][1][94] = 127, + [0][1][2][0][RTW89_ETSI][0][94] = 127, + [0][1][2][0][RTW89_MKK][1][94] = 127, + [0][1][2][0][RTW89_MKK][0][94] = 127, + [0][1][2][0][RTW89_IC][1][94] = -2, + [0][1][2][0][RTW89_KCC][1][94] = 20, + [0][1][2][0][RTW89_KCC][0][94] = 127, + [0][1][2][0][RTW89_ACMA][1][94] = 127, + [0][1][2][0][RTW89_ACMA][0][94] = 127, + [0][1][2][0][RTW89_CHILE][1][94] = -2, + [0][1][2][0][RTW89_QATAR][1][94] = 127, + [0][1][2][0][RTW89_QATAR][0][94] = 127, + [0][1][2][0][RTW89_UK][1][94] = 127, + [0][1][2][0][RTW89_UK][0][94] = 127, + [0][1][2][0][RTW89_FCC][1][96] = -2, + [0][1][2][0][RTW89_FCC][2][96] = 127, + [0][1][2][0][RTW89_ETSI][1][96] = 127, + [0][1][2][0][RTW89_ETSI][0][96] = 127, + [0][1][2][0][RTW89_MKK][1][96] = 127, + [0][1][2][0][RTW89_MKK][0][96] = 127, + [0][1][2][0][RTW89_IC][1][96] = -2, + [0][1][2][0][RTW89_KCC][1][96] = 20, + [0][1][2][0][RTW89_KCC][0][96] = 127, + [0][1][2][0][RTW89_ACMA][1][96] = 127, + [0][1][2][0][RTW89_ACMA][0][96] = 127, + [0][1][2][0][RTW89_CHILE][1][96] = -2, + [0][1][2][0][RTW89_QATAR][1][96] = 127, + [0][1][2][0][RTW89_QATAR][0][96] = 127, + [0][1][2][0][RTW89_UK][1][96] = 127, + [0][1][2][0][RTW89_UK][0][96] = 127, + [0][1][2][0][RTW89_FCC][1][98] = -2, + [0][1][2][0][RTW89_FCC][2][98] = 127, + [0][1][2][0][RTW89_ETSI][1][98] = 127, + [0][1][2][0][RTW89_ETSI][0][98] = 127, + [0][1][2][0][RTW89_MKK][1][98] = 127, + [0][1][2][0][RTW89_MKK][0][98] = 127, + [0][1][2][0][RTW89_IC][1][98] = -2, + [0][1][2][0][RTW89_KCC][1][98] = 20, + [0][1][2][0][RTW89_KCC][0][98] = 127, + [0][1][2][0][RTW89_ACMA][1][98] = 127, + [0][1][2][0][RTW89_ACMA][0][98] = 127, + [0][1][2][0][RTW89_CHILE][1][98] = -2, + [0][1][2][0][RTW89_QATAR][1][98] = 127, + [0][1][2][0][RTW89_QATAR][0][98] = 127, + [0][1][2][0][RTW89_UK][1][98] = 127, + [0][1][2][0][RTW89_UK][0][98] = 127, + [0][1][2][0][RTW89_FCC][1][100] = -2, + [0][1][2][0][RTW89_FCC][2][100] = 127, + [0][1][2][0][RTW89_ETSI][1][100] = 127, + [0][1][2][0][RTW89_ETSI][0][100] = 127, + [0][1][2][0][RTW89_MKK][1][100] = 127, + [0][1][2][0][RTW89_MKK][0][100] = 127, + [0][1][2][0][RTW89_IC][1][100] = -2, + [0][1][2][0][RTW89_KCC][1][100] = 20, + [0][1][2][0][RTW89_KCC][0][100] = 127, + [0][1][2][0][RTW89_ACMA][1][100] = 127, + [0][1][2][0][RTW89_ACMA][0][100] = 127, + [0][1][2][0][RTW89_CHILE][1][100] = -2, + [0][1][2][0][RTW89_QATAR][1][100] = 127, + [0][1][2][0][RTW89_QATAR][0][100] = 127, + [0][1][2][0][RTW89_UK][1][100] = 127, + [0][1][2][0][RTW89_UK][0][100] = 127, + [0][1][2][0][RTW89_FCC][1][102] = -2, + [0][1][2][0][RTW89_FCC][2][102] = 127, + [0][1][2][0][RTW89_ETSI][1][102] = 127, + [0][1][2][0][RTW89_ETSI][0][102] = 127, + [0][1][2][0][RTW89_MKK][1][102] = 127, + [0][1][2][0][RTW89_MKK][0][102] = 127, + [0][1][2][0][RTW89_IC][1][102] = -2, + [0][1][2][0][RTW89_KCC][1][102] = 20, + [0][1][2][0][RTW89_KCC][0][102] = 127, + [0][1][2][0][RTW89_ACMA][1][102] = 127, + [0][1][2][0][RTW89_ACMA][0][102] = 127, + [0][1][2][0][RTW89_CHILE][1][102] = -2, + [0][1][2][0][RTW89_QATAR][1][102] = 127, + [0][1][2][0][RTW89_QATAR][0][102] = 127, + [0][1][2][0][RTW89_UK][1][102] = 127, + [0][1][2][0][RTW89_UK][0][102] = 127, + [0][1][2][0][RTW89_FCC][1][104] = -2, + [0][1][2][0][RTW89_FCC][2][104] = 127, + [0][1][2][0][RTW89_ETSI][1][104] = 127, + [0][1][2][0][RTW89_ETSI][0][104] = 127, + [0][1][2][0][RTW89_MKK][1][104] = 127, + [0][1][2][0][RTW89_MKK][0][104] = 127, + [0][1][2][0][RTW89_IC][1][104] = -2, + [0][1][2][0][RTW89_KCC][1][104] = 20, + [0][1][2][0][RTW89_KCC][0][104] = 127, + [0][1][2][0][RTW89_ACMA][1][104] = 127, + [0][1][2][0][RTW89_ACMA][0][104] = 127, + [0][1][2][0][RTW89_CHILE][1][104] = -2, + [0][1][2][0][RTW89_QATAR][1][104] = 127, + [0][1][2][0][RTW89_QATAR][0][104] = 127, + [0][1][2][0][RTW89_UK][1][104] = 127, + [0][1][2][0][RTW89_UK][0][104] = 127, + [0][1][2][0][RTW89_FCC][1][105] = -2, + [0][1][2][0][RTW89_FCC][2][105] = 127, + [0][1][2][0][RTW89_ETSI][1][105] = 127, + [0][1][2][0][RTW89_ETSI][0][105] = 127, + [0][1][2][0][RTW89_MKK][1][105] = 127, + [0][1][2][0][RTW89_MKK][0][105] = 127, + [0][1][2][0][RTW89_IC][1][105] = -2, + [0][1][2][0][RTW89_KCC][1][105] = 20, + [0][1][2][0][RTW89_KCC][0][105] = 127, + [0][1][2][0][RTW89_ACMA][1][105] = 127, + [0][1][2][0][RTW89_ACMA][0][105] = 127, + [0][1][2][0][RTW89_CHILE][1][105] = -2, + [0][1][2][0][RTW89_QATAR][1][105] = 127, + [0][1][2][0][RTW89_QATAR][0][105] = 127, + [0][1][2][0][RTW89_UK][1][105] = 127, + [0][1][2][0][RTW89_UK][0][105] = 127, + [0][1][2][0][RTW89_FCC][1][107] = 1, + [0][1][2][0][RTW89_FCC][2][107] = 127, + [0][1][2][0][RTW89_ETSI][1][107] = 127, + [0][1][2][0][RTW89_ETSI][0][107] = 127, + [0][1][2][0][RTW89_MKK][1][107] = 127, + [0][1][2][0][RTW89_MKK][0][107] = 127, + [0][1][2][0][RTW89_IC][1][107] = 1, + [0][1][2][0][RTW89_KCC][1][107] = 20, + [0][1][2][0][RTW89_KCC][0][107] = 127, + [0][1][2][0][RTW89_ACMA][1][107] = 127, + [0][1][2][0][RTW89_ACMA][0][107] = 127, + [0][1][2][0][RTW89_CHILE][1][107] = 1, + [0][1][2][0][RTW89_QATAR][1][107] = 127, + [0][1][2][0][RTW89_QATAR][0][107] = 127, + [0][1][2][0][RTW89_UK][1][107] = 127, + [0][1][2][0][RTW89_UK][0][107] = 127, + [0][1][2][0][RTW89_FCC][1][109] = 1, + [0][1][2][0][RTW89_FCC][2][109] = 127, + [0][1][2][0][RTW89_ETSI][1][109] = 127, + [0][1][2][0][RTW89_ETSI][0][109] = 127, + [0][1][2][0][RTW89_MKK][1][109] = 127, + [0][1][2][0][RTW89_MKK][0][109] = 127, + [0][1][2][0][RTW89_IC][1][109] = 1, + [0][1][2][0][RTW89_KCC][1][109] = 20, + [0][1][2][0][RTW89_KCC][0][109] = 127, + [0][1][2][0][RTW89_ACMA][1][109] = 127, + [0][1][2][0][RTW89_ACMA][0][109] = 127, + [0][1][2][0][RTW89_CHILE][1][109] = 1, + [0][1][2][0][RTW89_QATAR][1][109] = 127, + [0][1][2][0][RTW89_QATAR][0][109] = 127, + [0][1][2][0][RTW89_UK][1][109] = 127, + [0][1][2][0][RTW89_UK][0][109] = 127, + [0][1][2][0][RTW89_FCC][1][111] = 127, + [0][1][2][0][RTW89_FCC][2][111] = 127, + [0][1][2][0][RTW89_ETSI][1][111] = 127, + [0][1][2][0][RTW89_ETSI][0][111] = 127, + [0][1][2][0][RTW89_MKK][1][111] = 127, + [0][1][2][0][RTW89_MKK][0][111] = 127, + [0][1][2][0][RTW89_IC][1][111] = 127, + [0][1][2][0][RTW89_KCC][1][111] = 127, + [0][1][2][0][RTW89_KCC][0][111] = 127, + [0][1][2][0][RTW89_ACMA][1][111] = 127, + [0][1][2][0][RTW89_ACMA][0][111] = 127, + [0][1][2][0][RTW89_CHILE][1][111] = 127, + [0][1][2][0][RTW89_QATAR][1][111] = 127, + [0][1][2][0][RTW89_QATAR][0][111] = 127, + [0][1][2][0][RTW89_UK][1][111] = 127, + [0][1][2][0][RTW89_UK][0][111] = 127, + [0][1][2][0][RTW89_FCC][1][113] = 127, + [0][1][2][0][RTW89_FCC][2][113] = 127, + [0][1][2][0][RTW89_ETSI][1][113] = 127, + [0][1][2][0][RTW89_ETSI][0][113] = 127, + [0][1][2][0][RTW89_MKK][1][113] = 127, + [0][1][2][0][RTW89_MKK][0][113] = 127, + [0][1][2][0][RTW89_IC][1][113] = 127, + [0][1][2][0][RTW89_KCC][1][113] = 127, + [0][1][2][0][RTW89_KCC][0][113] = 127, + [0][1][2][0][RTW89_ACMA][1][113] = 127, + [0][1][2][0][RTW89_ACMA][0][113] = 127, + [0][1][2][0][RTW89_CHILE][1][113] = 127, + [0][1][2][0][RTW89_QATAR][1][113] = 127, + [0][1][2][0][RTW89_QATAR][0][113] = 127, + [0][1][2][0][RTW89_UK][1][113] = 127, + [0][1][2][0][RTW89_UK][0][113] = 127, + [0][1][2][0][RTW89_FCC][1][115] = 127, + [0][1][2][0][RTW89_FCC][2][115] = 127, + [0][1][2][0][RTW89_ETSI][1][115] = 127, + [0][1][2][0][RTW89_ETSI][0][115] = 127, + [0][1][2][0][RTW89_MKK][1][115] = 127, + [0][1][2][0][RTW89_MKK][0][115] = 127, + [0][1][2][0][RTW89_IC][1][115] = 127, + [0][1][2][0][RTW89_KCC][1][115] = 127, + [0][1][2][0][RTW89_KCC][0][115] = 127, + [0][1][2][0][RTW89_ACMA][1][115] = 127, + [0][1][2][0][RTW89_ACMA][0][115] = 127, + [0][1][2][0][RTW89_CHILE][1][115] = 127, + [0][1][2][0][RTW89_QATAR][1][115] = 127, + [0][1][2][0][RTW89_QATAR][0][115] = 127, + [0][1][2][0][RTW89_UK][1][115] = 127, + [0][1][2][0][RTW89_UK][0][115] = 127, + [0][1][2][0][RTW89_FCC][1][117] = 127, + [0][1][2][0][RTW89_FCC][2][117] = 127, + [0][1][2][0][RTW89_ETSI][1][117] = 127, + [0][1][2][0][RTW89_ETSI][0][117] = 127, + [0][1][2][0][RTW89_MKK][1][117] = 127, + [0][1][2][0][RTW89_MKK][0][117] = 127, + [0][1][2][0][RTW89_IC][1][117] = 127, + [0][1][2][0][RTW89_KCC][1][117] = 127, + [0][1][2][0][RTW89_KCC][0][117] = 127, + [0][1][2][0][RTW89_ACMA][1][117] = 127, + [0][1][2][0][RTW89_ACMA][0][117] = 127, + [0][1][2][0][RTW89_CHILE][1][117] = 127, + [0][1][2][0][RTW89_QATAR][1][117] = 127, + [0][1][2][0][RTW89_QATAR][0][117] = 127, + [0][1][2][0][RTW89_UK][1][117] = 127, + [0][1][2][0][RTW89_UK][0][117] = 127, + [0][1][2][0][RTW89_FCC][1][119] = 127, + [0][1][2][0][RTW89_FCC][2][119] = 127, + [0][1][2][0][RTW89_ETSI][1][119] = 127, + [0][1][2][0][RTW89_ETSI][0][119] = 127, + [0][1][2][0][RTW89_MKK][1][119] = 127, + [0][1][2][0][RTW89_MKK][0][119] = 127, + [0][1][2][0][RTW89_IC][1][119] = 127, + [0][1][2][0][RTW89_KCC][1][119] = 127, + [0][1][2][0][RTW89_KCC][0][119] = 127, + [0][1][2][0][RTW89_ACMA][1][119] = 127, + [0][1][2][0][RTW89_ACMA][0][119] = 127, + [0][1][2][0][RTW89_CHILE][1][119] = 127, + [0][1][2][0][RTW89_QATAR][1][119] = 127, + [0][1][2][0][RTW89_QATAR][0][119] = 127, + [0][1][2][0][RTW89_UK][1][119] = 127, + [0][1][2][0][RTW89_UK][0][119] = 127, + [0][1][2][1][RTW89_FCC][1][0] = -2, + [0][1][2][1][RTW89_FCC][2][0] = 54, + [0][1][2][1][RTW89_ETSI][1][0] = 42, + [0][1][2][1][RTW89_ETSI][0][0] = 6, + [0][1][2][1][RTW89_MKK][1][0] = 56, + [0][1][2][1][RTW89_MKK][0][0] = 16, + [0][1][2][1][RTW89_IC][1][0] = -2, + [0][1][2][1][RTW89_KCC][1][0] = 12, + [0][1][2][1][RTW89_KCC][0][0] = 10, + [0][1][2][1][RTW89_ACMA][1][0] = 42, + [0][1][2][1][RTW89_ACMA][0][0] = 6, + [0][1][2][1][RTW89_CHILE][1][0] = -2, + [0][1][2][1][RTW89_QATAR][1][0] = 42, + [0][1][2][1][RTW89_QATAR][0][0] = 6, + [0][1][2][1][RTW89_UK][1][0] = 42, + [0][1][2][1][RTW89_UK][0][0] = 6, + [0][1][2][1][RTW89_FCC][1][2] = -4, + [0][1][2][1][RTW89_FCC][2][2] = 54, + [0][1][2][1][RTW89_ETSI][1][2] = 42, + [0][1][2][1][RTW89_ETSI][0][2] = 6, + [0][1][2][1][RTW89_MKK][1][2] = 54, + [0][1][2][1][RTW89_MKK][0][2] = 16, + [0][1][2][1][RTW89_IC][1][2] = -4, + [0][1][2][1][RTW89_KCC][1][2] = 12, + [0][1][2][1][RTW89_KCC][0][2] = 12, + [0][1][2][1][RTW89_ACMA][1][2] = 42, + [0][1][2][1][RTW89_ACMA][0][2] = 6, + [0][1][2][1][RTW89_CHILE][1][2] = -4, + [0][1][2][1][RTW89_QATAR][1][2] = 42, + [0][1][2][1][RTW89_QATAR][0][2] = 6, + [0][1][2][1][RTW89_UK][1][2] = 42, + [0][1][2][1][RTW89_UK][0][2] = 6, + [0][1][2][1][RTW89_FCC][1][4] = -4, + [0][1][2][1][RTW89_FCC][2][4] = 54, + [0][1][2][1][RTW89_ETSI][1][4] = 42, + [0][1][2][1][RTW89_ETSI][0][4] = 6, + [0][1][2][1][RTW89_MKK][1][4] = 54, + [0][1][2][1][RTW89_MKK][0][4] = 16, + [0][1][2][1][RTW89_IC][1][4] = -4, + [0][1][2][1][RTW89_KCC][1][4] = 12, + [0][1][2][1][RTW89_KCC][0][4] = 12, + [0][1][2][1][RTW89_ACMA][1][4] = 42, + [0][1][2][1][RTW89_ACMA][0][4] = 6, + [0][1][2][1][RTW89_CHILE][1][4] = -4, + [0][1][2][1][RTW89_QATAR][1][4] = 42, + [0][1][2][1][RTW89_QATAR][0][4] = 6, + [0][1][2][1][RTW89_UK][1][4] = 42, + [0][1][2][1][RTW89_UK][0][4] = 6, + [0][1][2][1][RTW89_FCC][1][6] = -4, + [0][1][2][1][RTW89_FCC][2][6] = 54, + [0][1][2][1][RTW89_ETSI][1][6] = 42, + [0][1][2][1][RTW89_ETSI][0][6] = 6, + [0][1][2][1][RTW89_MKK][1][6] = 54, + [0][1][2][1][RTW89_MKK][0][6] = 16, + [0][1][2][1][RTW89_IC][1][6] = -4, + [0][1][2][1][RTW89_KCC][1][6] = 12, + [0][1][2][1][RTW89_KCC][0][6] = 12, + [0][1][2][1][RTW89_ACMA][1][6] = 42, + [0][1][2][1][RTW89_ACMA][0][6] = 6, + [0][1][2][1][RTW89_CHILE][1][6] = -4, + [0][1][2][1][RTW89_QATAR][1][6] = 42, + [0][1][2][1][RTW89_QATAR][0][6] = 6, + [0][1][2][1][RTW89_UK][1][6] = 42, + [0][1][2][1][RTW89_UK][0][6] = 6, + [0][1][2][1][RTW89_FCC][1][8] = -4, + [0][1][2][1][RTW89_FCC][2][8] = 54, + [0][1][2][1][RTW89_ETSI][1][8] = 42, + [0][1][2][1][RTW89_ETSI][0][8] = 6, + [0][1][2][1][RTW89_MKK][1][8] = 54, + [0][1][2][1][RTW89_MKK][0][8] = 16, + [0][1][2][1][RTW89_IC][1][8] = -4, + [0][1][2][1][RTW89_KCC][1][8] = 12, + [0][1][2][1][RTW89_KCC][0][8] = 12, + [0][1][2][1][RTW89_ACMA][1][8] = 42, + [0][1][2][1][RTW89_ACMA][0][8] = 6, + [0][1][2][1][RTW89_CHILE][1][8] = -4, + [0][1][2][1][RTW89_QATAR][1][8] = 42, + [0][1][2][1][RTW89_QATAR][0][8] = 6, + [0][1][2][1][RTW89_UK][1][8] = 42, + [0][1][2][1][RTW89_UK][0][8] = 6, + [0][1][2][1][RTW89_FCC][1][10] = -4, + [0][1][2][1][RTW89_FCC][2][10] = 54, + [0][1][2][1][RTW89_ETSI][1][10] = 42, + [0][1][2][1][RTW89_ETSI][0][10] = 6, + [0][1][2][1][RTW89_MKK][1][10] = 54, + [0][1][2][1][RTW89_MKK][0][10] = 16, + [0][1][2][1][RTW89_IC][1][10] = -4, + [0][1][2][1][RTW89_KCC][1][10] = 12, + [0][1][2][1][RTW89_KCC][0][10] = 12, + [0][1][2][1][RTW89_ACMA][1][10] = 42, + [0][1][2][1][RTW89_ACMA][0][10] = 6, + [0][1][2][1][RTW89_CHILE][1][10] = -4, + [0][1][2][1][RTW89_QATAR][1][10] = 42, + [0][1][2][1][RTW89_QATAR][0][10] = 6, + [0][1][2][1][RTW89_UK][1][10] = 42, + [0][1][2][1][RTW89_UK][0][10] = 6, + [0][1][2][1][RTW89_FCC][1][12] = -4, + [0][1][2][1][RTW89_FCC][2][12] = 54, + [0][1][2][1][RTW89_ETSI][1][12] = 42, + [0][1][2][1][RTW89_ETSI][0][12] = 6, + [0][1][2][1][RTW89_MKK][1][12] = 54, + [0][1][2][1][RTW89_MKK][0][12] = 16, + [0][1][2][1][RTW89_IC][1][12] = -4, + [0][1][2][1][RTW89_KCC][1][12] = 12, + [0][1][2][1][RTW89_KCC][0][12] = 12, + [0][1][2][1][RTW89_ACMA][1][12] = 42, + [0][1][2][1][RTW89_ACMA][0][12] = 6, + [0][1][2][1][RTW89_CHILE][1][12] = -4, + [0][1][2][1][RTW89_QATAR][1][12] = 42, + [0][1][2][1][RTW89_QATAR][0][12] = 6, + [0][1][2][1][RTW89_UK][1][12] = 42, + [0][1][2][1][RTW89_UK][0][12] = 6, + [0][1][2][1][RTW89_FCC][1][14] = -4, + [0][1][2][1][RTW89_FCC][2][14] = 54, + [0][1][2][1][RTW89_ETSI][1][14] = 42, + [0][1][2][1][RTW89_ETSI][0][14] = 6, + [0][1][2][1][RTW89_MKK][1][14] = 54, + [0][1][2][1][RTW89_MKK][0][14] = 16, + [0][1][2][1][RTW89_IC][1][14] = -4, + [0][1][2][1][RTW89_KCC][1][14] = 12, + [0][1][2][1][RTW89_KCC][0][14] = 12, + [0][1][2][1][RTW89_ACMA][1][14] = 42, + [0][1][2][1][RTW89_ACMA][0][14] = 6, + [0][1][2][1][RTW89_CHILE][1][14] = -4, + [0][1][2][1][RTW89_QATAR][1][14] = 42, + [0][1][2][1][RTW89_QATAR][0][14] = 6, + [0][1][2][1][RTW89_UK][1][14] = 42, + [0][1][2][1][RTW89_UK][0][14] = 6, + [0][1][2][1][RTW89_FCC][1][15] = -4, + [0][1][2][1][RTW89_FCC][2][15] = 54, + [0][1][2][1][RTW89_ETSI][1][15] = 42, + [0][1][2][1][RTW89_ETSI][0][15] = 6, + [0][1][2][1][RTW89_MKK][1][15] = 54, + [0][1][2][1][RTW89_MKK][0][15] = 16, + [0][1][2][1][RTW89_IC][1][15] = -4, + [0][1][2][1][RTW89_KCC][1][15] = 12, + [0][1][2][1][RTW89_KCC][0][15] = 12, + [0][1][2][1][RTW89_ACMA][1][15] = 42, + [0][1][2][1][RTW89_ACMA][0][15] = 6, + [0][1][2][1][RTW89_CHILE][1][15] = -4, + [0][1][2][1][RTW89_QATAR][1][15] = 42, + [0][1][2][1][RTW89_QATAR][0][15] = 6, + [0][1][2][1][RTW89_UK][1][15] = 42, + [0][1][2][1][RTW89_UK][0][15] = 6, + [0][1][2][1][RTW89_FCC][1][17] = -4, + [0][1][2][1][RTW89_FCC][2][17] = 54, + [0][1][2][1][RTW89_ETSI][1][17] = 42, + [0][1][2][1][RTW89_ETSI][0][17] = 6, + [0][1][2][1][RTW89_MKK][1][17] = 54, + [0][1][2][1][RTW89_MKK][0][17] = 16, + [0][1][2][1][RTW89_IC][1][17] = -4, + [0][1][2][1][RTW89_KCC][1][17] = 12, + [0][1][2][1][RTW89_KCC][0][17] = 12, + [0][1][2][1][RTW89_ACMA][1][17] = 42, + [0][1][2][1][RTW89_ACMA][0][17] = 6, + [0][1][2][1][RTW89_CHILE][1][17] = -4, + [0][1][2][1][RTW89_QATAR][1][17] = 42, + [0][1][2][1][RTW89_QATAR][0][17] = 6, + [0][1][2][1][RTW89_UK][1][17] = 42, + [0][1][2][1][RTW89_UK][0][17] = 6, + [0][1][2][1][RTW89_FCC][1][19] = -4, + [0][1][2][1][RTW89_FCC][2][19] = 54, + [0][1][2][1][RTW89_ETSI][1][19] = 42, + [0][1][2][1][RTW89_ETSI][0][19] = 6, + [0][1][2][1][RTW89_MKK][1][19] = 54, + [0][1][2][1][RTW89_MKK][0][19] = 16, + [0][1][2][1][RTW89_IC][1][19] = -4, + [0][1][2][1][RTW89_KCC][1][19] = 12, + [0][1][2][1][RTW89_KCC][0][19] = 12, + [0][1][2][1][RTW89_ACMA][1][19] = 42, + [0][1][2][1][RTW89_ACMA][0][19] = 6, + [0][1][2][1][RTW89_CHILE][1][19] = -4, + [0][1][2][1][RTW89_QATAR][1][19] = 42, + [0][1][2][1][RTW89_QATAR][0][19] = 6, + [0][1][2][1][RTW89_UK][1][19] = 42, + [0][1][2][1][RTW89_UK][0][19] = 6, + [0][1][2][1][RTW89_FCC][1][21] = -4, + [0][1][2][1][RTW89_FCC][2][21] = 54, + [0][1][2][1][RTW89_ETSI][1][21] = 42, + [0][1][2][1][RTW89_ETSI][0][21] = 6, + [0][1][2][1][RTW89_MKK][1][21] = 54, + [0][1][2][1][RTW89_MKK][0][21] = 16, + [0][1][2][1][RTW89_IC][1][21] = -4, + [0][1][2][1][RTW89_KCC][1][21] = 12, + [0][1][2][1][RTW89_KCC][0][21] = 12, + [0][1][2][1][RTW89_ACMA][1][21] = 42, + [0][1][2][1][RTW89_ACMA][0][21] = 6, + [0][1][2][1][RTW89_CHILE][1][21] = -4, + [0][1][2][1][RTW89_QATAR][1][21] = 42, + [0][1][2][1][RTW89_QATAR][0][21] = 6, + [0][1][2][1][RTW89_UK][1][21] = 42, + [0][1][2][1][RTW89_UK][0][21] = 6, + [0][1][2][1][RTW89_FCC][1][23] = -4, + [0][1][2][1][RTW89_FCC][2][23] = 68, + [0][1][2][1][RTW89_ETSI][1][23] = 42, + [0][1][2][1][RTW89_ETSI][0][23] = 6, + [0][1][2][1][RTW89_MKK][1][23] = 54, + [0][1][2][1][RTW89_MKK][0][23] = 16, + [0][1][2][1][RTW89_IC][1][23] = -4, + [0][1][2][1][RTW89_KCC][1][23] = 12, + [0][1][2][1][RTW89_KCC][0][23] = 10, + [0][1][2][1][RTW89_ACMA][1][23] = 42, + [0][1][2][1][RTW89_ACMA][0][23] = 6, + [0][1][2][1][RTW89_CHILE][1][23] = -4, + [0][1][2][1][RTW89_QATAR][1][23] = 42, + [0][1][2][1][RTW89_QATAR][0][23] = 6, + [0][1][2][1][RTW89_UK][1][23] = 42, + [0][1][2][1][RTW89_UK][0][23] = 6, + [0][1][2][1][RTW89_FCC][1][25] = -4, + [0][1][2][1][RTW89_FCC][2][25] = 68, + [0][1][2][1][RTW89_ETSI][1][25] = 42, + [0][1][2][1][RTW89_ETSI][0][25] = 6, + [0][1][2][1][RTW89_MKK][1][25] = 54, + [0][1][2][1][RTW89_MKK][0][25] = 16, + [0][1][2][1][RTW89_IC][1][25] = -4, + [0][1][2][1][RTW89_KCC][1][25] = 12, + [0][1][2][1][RTW89_KCC][0][25] = 14, + [0][1][2][1][RTW89_ACMA][1][25] = 42, + [0][1][2][1][RTW89_ACMA][0][25] = 6, + [0][1][2][1][RTW89_CHILE][1][25] = -4, + [0][1][2][1][RTW89_QATAR][1][25] = 42, + [0][1][2][1][RTW89_QATAR][0][25] = 6, + [0][1][2][1][RTW89_UK][1][25] = 42, + [0][1][2][1][RTW89_UK][0][25] = 6, + [0][1][2][1][RTW89_FCC][1][27] = -4, + [0][1][2][1][RTW89_FCC][2][27] = 68, + [0][1][2][1][RTW89_ETSI][1][27] = 42, + [0][1][2][1][RTW89_ETSI][0][27] = 6, + [0][1][2][1][RTW89_MKK][1][27] = 54, + [0][1][2][1][RTW89_MKK][0][27] = 16, + [0][1][2][1][RTW89_IC][1][27] = -4, + [0][1][2][1][RTW89_KCC][1][27] = 12, + [0][1][2][1][RTW89_KCC][0][27] = 14, + [0][1][2][1][RTW89_ACMA][1][27] = 42, + [0][1][2][1][RTW89_ACMA][0][27] = 6, + [0][1][2][1][RTW89_CHILE][1][27] = -4, + [0][1][2][1][RTW89_QATAR][1][27] = 42, + [0][1][2][1][RTW89_QATAR][0][27] = 6, + [0][1][2][1][RTW89_UK][1][27] = 42, + [0][1][2][1][RTW89_UK][0][27] = 6, + [0][1][2][1][RTW89_FCC][1][29] = -4, + [0][1][2][1][RTW89_FCC][2][29] = 68, + [0][1][2][1][RTW89_ETSI][1][29] = 42, + [0][1][2][1][RTW89_ETSI][0][29] = 6, + [0][1][2][1][RTW89_MKK][1][29] = 54, + [0][1][2][1][RTW89_MKK][0][29] = 16, + [0][1][2][1][RTW89_IC][1][29] = -4, + [0][1][2][1][RTW89_KCC][1][29] = 12, + [0][1][2][1][RTW89_KCC][0][29] = 14, + [0][1][2][1][RTW89_ACMA][1][29] = 42, + [0][1][2][1][RTW89_ACMA][0][29] = 6, + [0][1][2][1][RTW89_CHILE][1][29] = -4, + [0][1][2][1][RTW89_QATAR][1][29] = 42, + [0][1][2][1][RTW89_QATAR][0][29] = 6, + [0][1][2][1][RTW89_UK][1][29] = 42, + [0][1][2][1][RTW89_UK][0][29] = 6, + [0][1][2][1][RTW89_FCC][1][30] = -4, + [0][1][2][1][RTW89_FCC][2][30] = 68, + [0][1][2][1][RTW89_ETSI][1][30] = 42, + [0][1][2][1][RTW89_ETSI][0][30] = 6, + [0][1][2][1][RTW89_MKK][1][30] = 54, + [0][1][2][1][RTW89_MKK][0][30] = 16, + [0][1][2][1][RTW89_IC][1][30] = -4, + [0][1][2][1][RTW89_KCC][1][30] = 12, + [0][1][2][1][RTW89_KCC][0][30] = 14, + [0][1][2][1][RTW89_ACMA][1][30] = 42, + [0][1][2][1][RTW89_ACMA][0][30] = 6, + [0][1][2][1][RTW89_CHILE][1][30] = -4, + [0][1][2][1][RTW89_QATAR][1][30] = 42, + [0][1][2][1][RTW89_QATAR][0][30] = 6, + [0][1][2][1][RTW89_UK][1][30] = 42, + [0][1][2][1][RTW89_UK][0][30] = 6, + [0][1][2][1][RTW89_FCC][1][32] = -4, + [0][1][2][1][RTW89_FCC][2][32] = 68, + [0][1][2][1][RTW89_ETSI][1][32] = 42, + [0][1][2][1][RTW89_ETSI][0][32] = 6, + [0][1][2][1][RTW89_MKK][1][32] = 54, + [0][1][2][1][RTW89_MKK][0][32] = 16, + [0][1][2][1][RTW89_IC][1][32] = -4, + [0][1][2][1][RTW89_KCC][1][32] = 12, + [0][1][2][1][RTW89_KCC][0][32] = 14, + [0][1][2][1][RTW89_ACMA][1][32] = 42, + [0][1][2][1][RTW89_ACMA][0][32] = 6, + [0][1][2][1][RTW89_CHILE][1][32] = -4, + [0][1][2][1][RTW89_QATAR][1][32] = 42, + [0][1][2][1][RTW89_QATAR][0][32] = 6, + [0][1][2][1][RTW89_UK][1][32] = 42, + [0][1][2][1][RTW89_UK][0][32] = 6, + [0][1][2][1][RTW89_FCC][1][34] = -4, + [0][1][2][1][RTW89_FCC][2][34] = 68, + [0][1][2][1][RTW89_ETSI][1][34] = 42, + [0][1][2][1][RTW89_ETSI][0][34] = 6, + [0][1][2][1][RTW89_MKK][1][34] = 54, + [0][1][2][1][RTW89_MKK][0][34] = 16, + [0][1][2][1][RTW89_IC][1][34] = -4, + [0][1][2][1][RTW89_KCC][1][34] = 12, + [0][1][2][1][RTW89_KCC][0][34] = 14, + [0][1][2][1][RTW89_ACMA][1][34] = 42, + [0][1][2][1][RTW89_ACMA][0][34] = 6, + [0][1][2][1][RTW89_CHILE][1][34] = -4, + [0][1][2][1][RTW89_QATAR][1][34] = 42, + [0][1][2][1][RTW89_QATAR][0][34] = 6, + [0][1][2][1][RTW89_UK][1][34] = 42, + [0][1][2][1][RTW89_UK][0][34] = 6, + [0][1][2][1][RTW89_FCC][1][36] = -4, + [0][1][2][1][RTW89_FCC][2][36] = 68, + [0][1][2][1][RTW89_ETSI][1][36] = 42, + [0][1][2][1][RTW89_ETSI][0][36] = 6, + [0][1][2][1][RTW89_MKK][1][36] = 54, + [0][1][2][1][RTW89_MKK][0][36] = 16, + [0][1][2][1][RTW89_IC][1][36] = -4, + [0][1][2][1][RTW89_KCC][1][36] = 12, + [0][1][2][1][RTW89_KCC][0][36] = 14, + [0][1][2][1][RTW89_ACMA][1][36] = 42, + [0][1][2][1][RTW89_ACMA][0][36] = 6, + [0][1][2][1][RTW89_CHILE][1][36] = -4, + [0][1][2][1][RTW89_QATAR][1][36] = 42, + [0][1][2][1][RTW89_QATAR][0][36] = 6, + [0][1][2][1][RTW89_UK][1][36] = 42, + [0][1][2][1][RTW89_UK][0][36] = 6, + [0][1][2][1][RTW89_FCC][1][38] = -4, + [0][1][2][1][RTW89_FCC][2][38] = 68, + [0][1][2][1][RTW89_ETSI][1][38] = 42, + [0][1][2][1][RTW89_ETSI][0][38] = 6, + [0][1][2][1][RTW89_MKK][1][38] = 54, + [0][1][2][1][RTW89_MKK][0][38] = 16, + [0][1][2][1][RTW89_IC][1][38] = -4, + [0][1][2][1][RTW89_KCC][1][38] = 12, + [0][1][2][1][RTW89_KCC][0][38] = 14, + [0][1][2][1][RTW89_ACMA][1][38] = 42, + [0][1][2][1][RTW89_ACMA][0][38] = 6, + [0][1][2][1][RTW89_CHILE][1][38] = -4, + [0][1][2][1][RTW89_QATAR][1][38] = 42, + [0][1][2][1][RTW89_QATAR][0][38] = 6, + [0][1][2][1][RTW89_UK][1][38] = 42, + [0][1][2][1][RTW89_UK][0][38] = 6, + [0][1][2][1][RTW89_FCC][1][40] = -4, + [0][1][2][1][RTW89_FCC][2][40] = 68, + [0][1][2][1][RTW89_ETSI][1][40] = 42, + [0][1][2][1][RTW89_ETSI][0][40] = 6, + [0][1][2][1][RTW89_MKK][1][40] = 54, + [0][1][2][1][RTW89_MKK][0][40] = 16, + [0][1][2][1][RTW89_IC][1][40] = -4, + [0][1][2][1][RTW89_KCC][1][40] = 12, + [0][1][2][1][RTW89_KCC][0][40] = 14, + [0][1][2][1][RTW89_ACMA][1][40] = 42, + [0][1][2][1][RTW89_ACMA][0][40] = 6, + [0][1][2][1][RTW89_CHILE][1][40] = -4, + [0][1][2][1][RTW89_QATAR][1][40] = 42, + [0][1][2][1][RTW89_QATAR][0][40] = 6, + [0][1][2][1][RTW89_UK][1][40] = 42, + [0][1][2][1][RTW89_UK][0][40] = 6, + [0][1][2][1][RTW89_FCC][1][42] = -4, + [0][1][2][1][RTW89_FCC][2][42] = 68, + [0][1][2][1][RTW89_ETSI][1][42] = 42, + [0][1][2][1][RTW89_ETSI][0][42] = 6, + [0][1][2][1][RTW89_MKK][1][42] = 54, + [0][1][2][1][RTW89_MKK][0][42] = 16, + [0][1][2][1][RTW89_IC][1][42] = -4, + [0][1][2][1][RTW89_KCC][1][42] = 12, + [0][1][2][1][RTW89_KCC][0][42] = 14, + [0][1][2][1][RTW89_ACMA][1][42] = 42, + [0][1][2][1][RTW89_ACMA][0][42] = 6, + [0][1][2][1][RTW89_CHILE][1][42] = -4, + [0][1][2][1][RTW89_QATAR][1][42] = 42, + [0][1][2][1][RTW89_QATAR][0][42] = 6, + [0][1][2][1][RTW89_UK][1][42] = 42, + [0][1][2][1][RTW89_UK][0][42] = 6, + [0][1][2][1][RTW89_FCC][1][44] = -2, + [0][1][2][1][RTW89_FCC][2][44] = 68, + [0][1][2][1][RTW89_ETSI][1][44] = 42, + [0][1][2][1][RTW89_ETSI][0][44] = 6, + [0][1][2][1][RTW89_MKK][1][44] = 34, + [0][1][2][1][RTW89_MKK][0][44] = 16, + [0][1][2][1][RTW89_IC][1][44] = -2, + [0][1][2][1][RTW89_KCC][1][44] = 12, + [0][1][2][1][RTW89_KCC][0][44] = 12, + [0][1][2][1][RTW89_ACMA][1][44] = 42, + [0][1][2][1][RTW89_ACMA][0][44] = 6, + [0][1][2][1][RTW89_CHILE][1][44] = -2, + [0][1][2][1][RTW89_QATAR][1][44] = 42, + [0][1][2][1][RTW89_QATAR][0][44] = 6, + [0][1][2][1][RTW89_UK][1][44] = 42, + [0][1][2][1][RTW89_UK][0][44] = 6, + [0][1][2][1][RTW89_FCC][1][45] = -2, + [0][1][2][1][RTW89_FCC][2][45] = 127, + [0][1][2][1][RTW89_ETSI][1][45] = 127, + [0][1][2][1][RTW89_ETSI][0][45] = 127, + [0][1][2][1][RTW89_MKK][1][45] = 127, + [0][1][2][1][RTW89_MKK][0][45] = 127, + [0][1][2][1][RTW89_IC][1][45] = -2, + [0][1][2][1][RTW89_KCC][1][45] = 12, + [0][1][2][1][RTW89_KCC][0][45] = 127, + [0][1][2][1][RTW89_ACMA][1][45] = 127, + [0][1][2][1][RTW89_ACMA][0][45] = 127, + [0][1][2][1][RTW89_CHILE][1][45] = -2, + [0][1][2][1][RTW89_QATAR][1][45] = 127, + [0][1][2][1][RTW89_QATAR][0][45] = 127, + [0][1][2][1][RTW89_UK][1][45] = 127, + [0][1][2][1][RTW89_UK][0][45] = 127, + [0][1][2][1][RTW89_FCC][1][47] = -2, + [0][1][2][1][RTW89_FCC][2][47] = 127, + [0][1][2][1][RTW89_ETSI][1][47] = 127, + [0][1][2][1][RTW89_ETSI][0][47] = 127, + [0][1][2][1][RTW89_MKK][1][47] = 127, + [0][1][2][1][RTW89_MKK][0][47] = 127, + [0][1][2][1][RTW89_IC][1][47] = -2, + [0][1][2][1][RTW89_KCC][1][47] = 12, + [0][1][2][1][RTW89_KCC][0][47] = 127, + [0][1][2][1][RTW89_ACMA][1][47] = 127, + [0][1][2][1][RTW89_ACMA][0][47] = 127, + [0][1][2][1][RTW89_CHILE][1][47] = -2, + [0][1][2][1][RTW89_QATAR][1][47] = 127, + [0][1][2][1][RTW89_QATAR][0][47] = 127, + [0][1][2][1][RTW89_UK][1][47] = 127, + [0][1][2][1][RTW89_UK][0][47] = 127, + [0][1][2][1][RTW89_FCC][1][49] = -2, + [0][1][2][1][RTW89_FCC][2][49] = 127, + [0][1][2][1][RTW89_ETSI][1][49] = 127, + [0][1][2][1][RTW89_ETSI][0][49] = 127, + [0][1][2][1][RTW89_MKK][1][49] = 127, + [0][1][2][1][RTW89_MKK][0][49] = 127, + [0][1][2][1][RTW89_IC][1][49] = -2, + [0][1][2][1][RTW89_KCC][1][49] = 12, + [0][1][2][1][RTW89_KCC][0][49] = 127, + [0][1][2][1][RTW89_ACMA][1][49] = 127, + [0][1][2][1][RTW89_ACMA][0][49] = 127, + [0][1][2][1][RTW89_CHILE][1][49] = -2, + [0][1][2][1][RTW89_QATAR][1][49] = 127, + [0][1][2][1][RTW89_QATAR][0][49] = 127, + [0][1][2][1][RTW89_UK][1][49] = 127, + [0][1][2][1][RTW89_UK][0][49] = 127, + [0][1][2][1][RTW89_FCC][1][51] = -2, + [0][1][2][1][RTW89_FCC][2][51] = 127, + [0][1][2][1][RTW89_ETSI][1][51] = 127, + [0][1][2][1][RTW89_ETSI][0][51] = 127, + [0][1][2][1][RTW89_MKK][1][51] = 127, + [0][1][2][1][RTW89_MKK][0][51] = 127, + [0][1][2][1][RTW89_IC][1][51] = -2, + [0][1][2][1][RTW89_KCC][1][51] = 12, + [0][1][2][1][RTW89_KCC][0][51] = 127, + [0][1][2][1][RTW89_ACMA][1][51] = 127, + [0][1][2][1][RTW89_ACMA][0][51] = 127, + [0][1][2][1][RTW89_CHILE][1][51] = -2, + [0][1][2][1][RTW89_QATAR][1][51] = 127, + [0][1][2][1][RTW89_QATAR][0][51] = 127, + [0][1][2][1][RTW89_UK][1][51] = 127, + [0][1][2][1][RTW89_UK][0][51] = 127, + [0][1][2][1][RTW89_FCC][1][53] = -2, + [0][1][2][1][RTW89_FCC][2][53] = 127, + [0][1][2][1][RTW89_ETSI][1][53] = 127, + [0][1][2][1][RTW89_ETSI][0][53] = 127, + [0][1][2][1][RTW89_MKK][1][53] = 127, + [0][1][2][1][RTW89_MKK][0][53] = 127, + [0][1][2][1][RTW89_IC][1][53] = -2, + [0][1][2][1][RTW89_KCC][1][53] = 12, + [0][1][2][1][RTW89_KCC][0][53] = 127, + [0][1][2][1][RTW89_ACMA][1][53] = 127, + [0][1][2][1][RTW89_ACMA][0][53] = 127, + [0][1][2][1][RTW89_CHILE][1][53] = -2, + [0][1][2][1][RTW89_QATAR][1][53] = 127, + [0][1][2][1][RTW89_QATAR][0][53] = 127, + [0][1][2][1][RTW89_UK][1][53] = 127, + [0][1][2][1][RTW89_UK][0][53] = 127, + [0][1][2][1][RTW89_FCC][1][55] = -2, + [0][1][2][1][RTW89_FCC][2][55] = 68, + [0][1][2][1][RTW89_ETSI][1][55] = 127, + [0][1][2][1][RTW89_ETSI][0][55] = 127, + [0][1][2][1][RTW89_MKK][1][55] = 127, + [0][1][2][1][RTW89_MKK][0][55] = 127, + [0][1][2][1][RTW89_IC][1][55] = -2, + [0][1][2][1][RTW89_KCC][1][55] = 12, + [0][1][2][1][RTW89_KCC][0][55] = 127, + [0][1][2][1][RTW89_ACMA][1][55] = 127, + [0][1][2][1][RTW89_ACMA][0][55] = 127, + [0][1][2][1][RTW89_CHILE][1][55] = -2, + [0][1][2][1][RTW89_QATAR][1][55] = 127, + [0][1][2][1][RTW89_QATAR][0][55] = 127, + [0][1][2][1][RTW89_UK][1][55] = 127, + [0][1][2][1][RTW89_UK][0][55] = 127, + [0][1][2][1][RTW89_FCC][1][57] = -2, + [0][1][2][1][RTW89_FCC][2][57] = 68, + [0][1][2][1][RTW89_ETSI][1][57] = 127, + [0][1][2][1][RTW89_ETSI][0][57] = 127, + [0][1][2][1][RTW89_MKK][1][57] = 127, + [0][1][2][1][RTW89_MKK][0][57] = 127, + [0][1][2][1][RTW89_IC][1][57] = -2, + [0][1][2][1][RTW89_KCC][1][57] = 12, + [0][1][2][1][RTW89_KCC][0][57] = 127, + [0][1][2][1][RTW89_ACMA][1][57] = 127, + [0][1][2][1][RTW89_ACMA][0][57] = 127, + [0][1][2][1][RTW89_CHILE][1][57] = -2, + [0][1][2][1][RTW89_QATAR][1][57] = 127, + [0][1][2][1][RTW89_QATAR][0][57] = 127, + [0][1][2][1][RTW89_UK][1][57] = 127, + [0][1][2][1][RTW89_UK][0][57] = 127, + [0][1][2][1][RTW89_FCC][1][59] = -2, + [0][1][2][1][RTW89_FCC][2][59] = 68, + [0][1][2][1][RTW89_ETSI][1][59] = 127, + [0][1][2][1][RTW89_ETSI][0][59] = 127, + [0][1][2][1][RTW89_MKK][1][59] = 127, + [0][1][2][1][RTW89_MKK][0][59] = 127, + [0][1][2][1][RTW89_IC][1][59] = -2, + [0][1][2][1][RTW89_KCC][1][59] = 12, + [0][1][2][1][RTW89_KCC][0][59] = 127, + [0][1][2][1][RTW89_ACMA][1][59] = 127, + [0][1][2][1][RTW89_ACMA][0][59] = 127, + [0][1][2][1][RTW89_CHILE][1][59] = -2, + [0][1][2][1][RTW89_QATAR][1][59] = 127, + [0][1][2][1][RTW89_QATAR][0][59] = 127, + [0][1][2][1][RTW89_UK][1][59] = 127, + [0][1][2][1][RTW89_UK][0][59] = 127, + [0][1][2][1][RTW89_FCC][1][60] = -2, + [0][1][2][1][RTW89_FCC][2][60] = 68, + [0][1][2][1][RTW89_ETSI][1][60] = 127, + [0][1][2][1][RTW89_ETSI][0][60] = 127, + [0][1][2][1][RTW89_MKK][1][60] = 127, + [0][1][2][1][RTW89_MKK][0][60] = 127, + [0][1][2][1][RTW89_IC][1][60] = -2, + [0][1][2][1][RTW89_KCC][1][60] = 12, + [0][1][2][1][RTW89_KCC][0][60] = 127, + [0][1][2][1][RTW89_ACMA][1][60] = 127, + [0][1][2][1][RTW89_ACMA][0][60] = 127, + [0][1][2][1][RTW89_CHILE][1][60] = -2, + [0][1][2][1][RTW89_QATAR][1][60] = 127, + [0][1][2][1][RTW89_QATAR][0][60] = 127, + [0][1][2][1][RTW89_UK][1][60] = 127, + [0][1][2][1][RTW89_UK][0][60] = 127, + [0][1][2][1][RTW89_FCC][1][62] = -2, + [0][1][2][1][RTW89_FCC][2][62] = 68, + [0][1][2][1][RTW89_ETSI][1][62] = 127, + [0][1][2][1][RTW89_ETSI][0][62] = 127, + [0][1][2][1][RTW89_MKK][1][62] = 127, + [0][1][2][1][RTW89_MKK][0][62] = 127, + [0][1][2][1][RTW89_IC][1][62] = -2, + [0][1][2][1][RTW89_KCC][1][62] = 12, + [0][1][2][1][RTW89_KCC][0][62] = 127, + [0][1][2][1][RTW89_ACMA][1][62] = 127, + [0][1][2][1][RTW89_ACMA][0][62] = 127, + [0][1][2][1][RTW89_CHILE][1][62] = -2, + [0][1][2][1][RTW89_QATAR][1][62] = 127, + [0][1][2][1][RTW89_QATAR][0][62] = 127, + [0][1][2][1][RTW89_UK][1][62] = 127, + [0][1][2][1][RTW89_UK][0][62] = 127, + [0][1][2][1][RTW89_FCC][1][64] = -2, + [0][1][2][1][RTW89_FCC][2][64] = 68, + [0][1][2][1][RTW89_ETSI][1][64] = 127, + [0][1][2][1][RTW89_ETSI][0][64] = 127, + [0][1][2][1][RTW89_MKK][1][64] = 127, + [0][1][2][1][RTW89_MKK][0][64] = 127, + [0][1][2][1][RTW89_IC][1][64] = -2, + [0][1][2][1][RTW89_KCC][1][64] = 12, + [0][1][2][1][RTW89_KCC][0][64] = 127, + [0][1][2][1][RTW89_ACMA][1][64] = 127, + [0][1][2][1][RTW89_ACMA][0][64] = 127, + [0][1][2][1][RTW89_CHILE][1][64] = -2, + [0][1][2][1][RTW89_QATAR][1][64] = 127, + [0][1][2][1][RTW89_QATAR][0][64] = 127, + [0][1][2][1][RTW89_UK][1][64] = 127, + [0][1][2][1][RTW89_UK][0][64] = 127, + [0][1][2][1][RTW89_FCC][1][66] = -2, + [0][1][2][1][RTW89_FCC][2][66] = 68, + [0][1][2][1][RTW89_ETSI][1][66] = 127, + [0][1][2][1][RTW89_ETSI][0][66] = 127, + [0][1][2][1][RTW89_MKK][1][66] = 127, + [0][1][2][1][RTW89_MKK][0][66] = 127, + [0][1][2][1][RTW89_IC][1][66] = -2, + [0][1][2][1][RTW89_KCC][1][66] = 12, + [0][1][2][1][RTW89_KCC][0][66] = 127, + [0][1][2][1][RTW89_ACMA][1][66] = 127, + [0][1][2][1][RTW89_ACMA][0][66] = 127, + [0][1][2][1][RTW89_CHILE][1][66] = -2, + [0][1][2][1][RTW89_QATAR][1][66] = 127, + [0][1][2][1][RTW89_QATAR][0][66] = 127, + [0][1][2][1][RTW89_UK][1][66] = 127, + [0][1][2][1][RTW89_UK][0][66] = 127, + [0][1][2][1][RTW89_FCC][1][68] = -2, + [0][1][2][1][RTW89_FCC][2][68] = 68, + [0][1][2][1][RTW89_ETSI][1][68] = 127, + [0][1][2][1][RTW89_ETSI][0][68] = 127, + [0][1][2][1][RTW89_MKK][1][68] = 127, + [0][1][2][1][RTW89_MKK][0][68] = 127, + [0][1][2][1][RTW89_IC][1][68] = -2, + [0][1][2][1][RTW89_KCC][1][68] = 12, + [0][1][2][1][RTW89_KCC][0][68] = 127, + [0][1][2][1][RTW89_ACMA][1][68] = 127, + [0][1][2][1][RTW89_ACMA][0][68] = 127, + [0][1][2][1][RTW89_CHILE][1][68] = -2, + [0][1][2][1][RTW89_QATAR][1][68] = 127, + [0][1][2][1][RTW89_QATAR][0][68] = 127, + [0][1][2][1][RTW89_UK][1][68] = 127, + [0][1][2][1][RTW89_UK][0][68] = 127, + [0][1][2][1][RTW89_FCC][1][70] = -2, + [0][1][2][1][RTW89_FCC][2][70] = 68, + [0][1][2][1][RTW89_ETSI][1][70] = 127, + [0][1][2][1][RTW89_ETSI][0][70] = 127, + [0][1][2][1][RTW89_MKK][1][70] = 127, + [0][1][2][1][RTW89_MKK][0][70] = 127, + [0][1][2][1][RTW89_IC][1][70] = -2, + [0][1][2][1][RTW89_KCC][1][70] = 12, + [0][1][2][1][RTW89_KCC][0][70] = 127, + [0][1][2][1][RTW89_ACMA][1][70] = 127, + [0][1][2][1][RTW89_ACMA][0][70] = 127, + [0][1][2][1][RTW89_CHILE][1][70] = -2, + [0][1][2][1][RTW89_QATAR][1][70] = 127, + [0][1][2][1][RTW89_QATAR][0][70] = 127, + [0][1][2][1][RTW89_UK][1][70] = 127, + [0][1][2][1][RTW89_UK][0][70] = 127, + [0][1][2][1][RTW89_FCC][1][72] = -2, + [0][1][2][1][RTW89_FCC][2][72] = 68, + [0][1][2][1][RTW89_ETSI][1][72] = 127, + [0][1][2][1][RTW89_ETSI][0][72] = 127, + [0][1][2][1][RTW89_MKK][1][72] = 127, + [0][1][2][1][RTW89_MKK][0][72] = 127, + [0][1][2][1][RTW89_IC][1][72] = -2, + [0][1][2][1][RTW89_KCC][1][72] = 12, + [0][1][2][1][RTW89_KCC][0][72] = 127, + [0][1][2][1][RTW89_ACMA][1][72] = 127, + [0][1][2][1][RTW89_ACMA][0][72] = 127, + [0][1][2][1][RTW89_CHILE][1][72] = -2, + [0][1][2][1][RTW89_QATAR][1][72] = 127, + [0][1][2][1][RTW89_QATAR][0][72] = 127, + [0][1][2][1][RTW89_UK][1][72] = 127, + [0][1][2][1][RTW89_UK][0][72] = 127, + [0][1][2][1][RTW89_FCC][1][74] = -2, + [0][1][2][1][RTW89_FCC][2][74] = 68, + [0][1][2][1][RTW89_ETSI][1][74] = 127, + [0][1][2][1][RTW89_ETSI][0][74] = 127, + [0][1][2][1][RTW89_MKK][1][74] = 127, + [0][1][2][1][RTW89_MKK][0][74] = 127, + [0][1][2][1][RTW89_IC][1][74] = -2, + [0][1][2][1][RTW89_KCC][1][74] = 12, + [0][1][2][1][RTW89_KCC][0][74] = 127, + [0][1][2][1][RTW89_ACMA][1][74] = 127, + [0][1][2][1][RTW89_ACMA][0][74] = 127, + [0][1][2][1][RTW89_CHILE][1][74] = -2, + [0][1][2][1][RTW89_QATAR][1][74] = 127, + [0][1][2][1][RTW89_QATAR][0][74] = 127, + [0][1][2][1][RTW89_UK][1][74] = 127, + [0][1][2][1][RTW89_UK][0][74] = 127, + [0][1][2][1][RTW89_FCC][1][75] = -2, + [0][1][2][1][RTW89_FCC][2][75] = 68, + [0][1][2][1][RTW89_ETSI][1][75] = 127, + [0][1][2][1][RTW89_ETSI][0][75] = 127, + [0][1][2][1][RTW89_MKK][1][75] = 127, + [0][1][2][1][RTW89_MKK][0][75] = 127, + [0][1][2][1][RTW89_IC][1][75] = -2, + [0][1][2][1][RTW89_KCC][1][75] = 12, + [0][1][2][1][RTW89_KCC][0][75] = 127, + [0][1][2][1][RTW89_ACMA][1][75] = 127, + [0][1][2][1][RTW89_ACMA][0][75] = 127, + [0][1][2][1][RTW89_CHILE][1][75] = -2, + [0][1][2][1][RTW89_QATAR][1][75] = 127, + [0][1][2][1][RTW89_QATAR][0][75] = 127, + [0][1][2][1][RTW89_UK][1][75] = 127, + [0][1][2][1][RTW89_UK][0][75] = 127, + [0][1][2][1][RTW89_FCC][1][77] = -2, + [0][1][2][1][RTW89_FCC][2][77] = 68, + [0][1][2][1][RTW89_ETSI][1][77] = 127, + [0][1][2][1][RTW89_ETSI][0][77] = 127, + [0][1][2][1][RTW89_MKK][1][77] = 127, + [0][1][2][1][RTW89_MKK][0][77] = 127, + [0][1][2][1][RTW89_IC][1][77] = -2, + [0][1][2][1][RTW89_KCC][1][77] = 12, + [0][1][2][1][RTW89_KCC][0][77] = 127, + [0][1][2][1][RTW89_ACMA][1][77] = 127, + [0][1][2][1][RTW89_ACMA][0][77] = 127, + [0][1][2][1][RTW89_CHILE][1][77] = -2, + [0][1][2][1][RTW89_QATAR][1][77] = 127, + [0][1][2][1][RTW89_QATAR][0][77] = 127, + [0][1][2][1][RTW89_UK][1][77] = 127, + [0][1][2][1][RTW89_UK][0][77] = 127, + [0][1][2][1][RTW89_FCC][1][79] = -2, + [0][1][2][1][RTW89_FCC][2][79] = 68, + [0][1][2][1][RTW89_ETSI][1][79] = 127, + [0][1][2][1][RTW89_ETSI][0][79] = 127, + [0][1][2][1][RTW89_MKK][1][79] = 127, + [0][1][2][1][RTW89_MKK][0][79] = 127, + [0][1][2][1][RTW89_IC][1][79] = -2, + [0][1][2][1][RTW89_KCC][1][79] = 12, + [0][1][2][1][RTW89_KCC][0][79] = 127, + [0][1][2][1][RTW89_ACMA][1][79] = 127, + [0][1][2][1][RTW89_ACMA][0][79] = 127, + [0][1][2][1][RTW89_CHILE][1][79] = -2, + [0][1][2][1][RTW89_QATAR][1][79] = 127, + [0][1][2][1][RTW89_QATAR][0][79] = 127, + [0][1][2][1][RTW89_UK][1][79] = 127, + [0][1][2][1][RTW89_UK][0][79] = 127, + [0][1][2][1][RTW89_FCC][1][81] = -2, + [0][1][2][1][RTW89_FCC][2][81] = 68, + [0][1][2][1][RTW89_ETSI][1][81] = 127, + [0][1][2][1][RTW89_ETSI][0][81] = 127, + [0][1][2][1][RTW89_MKK][1][81] = 127, + [0][1][2][1][RTW89_MKK][0][81] = 127, + [0][1][2][1][RTW89_IC][1][81] = -2, + [0][1][2][1][RTW89_KCC][1][81] = 12, + [0][1][2][1][RTW89_KCC][0][81] = 127, + [0][1][2][1][RTW89_ACMA][1][81] = 127, + [0][1][2][1][RTW89_ACMA][0][81] = 127, + [0][1][2][1][RTW89_CHILE][1][81] = -2, + [0][1][2][1][RTW89_QATAR][1][81] = 127, + [0][1][2][1][RTW89_QATAR][0][81] = 127, + [0][1][2][1][RTW89_UK][1][81] = 127, + [0][1][2][1][RTW89_UK][0][81] = 127, + [0][1][2][1][RTW89_FCC][1][83] = -2, + [0][1][2][1][RTW89_FCC][2][83] = 68, + [0][1][2][1][RTW89_ETSI][1][83] = 127, + [0][1][2][1][RTW89_ETSI][0][83] = 127, + [0][1][2][1][RTW89_MKK][1][83] = 127, + [0][1][2][1][RTW89_MKK][0][83] = 127, + [0][1][2][1][RTW89_IC][1][83] = -2, + [0][1][2][1][RTW89_KCC][1][83] = 20, + [0][1][2][1][RTW89_KCC][0][83] = 127, + [0][1][2][1][RTW89_ACMA][1][83] = 127, + [0][1][2][1][RTW89_ACMA][0][83] = 127, + [0][1][2][1][RTW89_CHILE][1][83] = -2, + [0][1][2][1][RTW89_QATAR][1][83] = 127, + [0][1][2][1][RTW89_QATAR][0][83] = 127, + [0][1][2][1][RTW89_UK][1][83] = 127, + [0][1][2][1][RTW89_UK][0][83] = 127, + [0][1][2][1][RTW89_FCC][1][85] = -2, + [0][1][2][1][RTW89_FCC][2][85] = 68, + [0][1][2][1][RTW89_ETSI][1][85] = 127, + [0][1][2][1][RTW89_ETSI][0][85] = 127, + [0][1][2][1][RTW89_MKK][1][85] = 127, + [0][1][2][1][RTW89_MKK][0][85] = 127, + [0][1][2][1][RTW89_IC][1][85] = -2, + [0][1][2][1][RTW89_KCC][1][85] = 20, + [0][1][2][1][RTW89_KCC][0][85] = 127, + [0][1][2][1][RTW89_ACMA][1][85] = 127, + [0][1][2][1][RTW89_ACMA][0][85] = 127, + [0][1][2][1][RTW89_CHILE][1][85] = -2, + [0][1][2][1][RTW89_QATAR][1][85] = 127, + [0][1][2][1][RTW89_QATAR][0][85] = 127, + [0][1][2][1][RTW89_UK][1][85] = 127, + [0][1][2][1][RTW89_UK][0][85] = 127, + [0][1][2][1][RTW89_FCC][1][87] = -2, + [0][1][2][1][RTW89_FCC][2][87] = 127, + [0][1][2][1][RTW89_ETSI][1][87] = 127, + [0][1][2][1][RTW89_ETSI][0][87] = 127, + [0][1][2][1][RTW89_MKK][1][87] = 127, + [0][1][2][1][RTW89_MKK][0][87] = 127, + [0][1][2][1][RTW89_IC][1][87] = -2, + [0][1][2][1][RTW89_KCC][1][87] = 20, + [0][1][2][1][RTW89_KCC][0][87] = 127, + [0][1][2][1][RTW89_ACMA][1][87] = 127, + [0][1][2][1][RTW89_ACMA][0][87] = 127, + [0][1][2][1][RTW89_CHILE][1][87] = -2, + [0][1][2][1][RTW89_QATAR][1][87] = 127, + [0][1][2][1][RTW89_QATAR][0][87] = 127, + [0][1][2][1][RTW89_UK][1][87] = 127, + [0][1][2][1][RTW89_UK][0][87] = 127, + [0][1][2][1][RTW89_FCC][1][89] = -2, + [0][1][2][1][RTW89_FCC][2][89] = 127, + [0][1][2][1][RTW89_ETSI][1][89] = 127, + [0][1][2][1][RTW89_ETSI][0][89] = 127, + [0][1][2][1][RTW89_MKK][1][89] = 127, + [0][1][2][1][RTW89_MKK][0][89] = 127, + [0][1][2][1][RTW89_IC][1][89] = -2, + [0][1][2][1][RTW89_KCC][1][89] = 20, + [0][1][2][1][RTW89_KCC][0][89] = 127, + [0][1][2][1][RTW89_ACMA][1][89] = 127, + [0][1][2][1][RTW89_ACMA][0][89] = 127, + [0][1][2][1][RTW89_CHILE][1][89] = -2, + [0][1][2][1][RTW89_QATAR][1][89] = 127, + [0][1][2][1][RTW89_QATAR][0][89] = 127, + [0][1][2][1][RTW89_UK][1][89] = 127, + [0][1][2][1][RTW89_UK][0][89] = 127, + [0][1][2][1][RTW89_FCC][1][90] = -2, + [0][1][2][1][RTW89_FCC][2][90] = 127, + [0][1][2][1][RTW89_ETSI][1][90] = 127, + [0][1][2][1][RTW89_ETSI][0][90] = 127, + [0][1][2][1][RTW89_MKK][1][90] = 127, + [0][1][2][1][RTW89_MKK][0][90] = 127, + [0][1][2][1][RTW89_IC][1][90] = -2, + [0][1][2][1][RTW89_KCC][1][90] = 20, + [0][1][2][1][RTW89_KCC][0][90] = 127, + [0][1][2][1][RTW89_ACMA][1][90] = 127, + [0][1][2][1][RTW89_ACMA][0][90] = 127, + [0][1][2][1][RTW89_CHILE][1][90] = -2, + [0][1][2][1][RTW89_QATAR][1][90] = 127, + [0][1][2][1][RTW89_QATAR][0][90] = 127, + [0][1][2][1][RTW89_UK][1][90] = 127, + [0][1][2][1][RTW89_UK][0][90] = 127, + [0][1][2][1][RTW89_FCC][1][92] = -2, + [0][1][2][1][RTW89_FCC][2][92] = 127, + [0][1][2][1][RTW89_ETSI][1][92] = 127, + [0][1][2][1][RTW89_ETSI][0][92] = 127, + [0][1][2][1][RTW89_MKK][1][92] = 127, + [0][1][2][1][RTW89_MKK][0][92] = 127, + [0][1][2][1][RTW89_IC][1][92] = -2, + [0][1][2][1][RTW89_KCC][1][92] = 20, + [0][1][2][1][RTW89_KCC][0][92] = 127, + [0][1][2][1][RTW89_ACMA][1][92] = 127, + [0][1][2][1][RTW89_ACMA][0][92] = 127, + [0][1][2][1][RTW89_CHILE][1][92] = -2, + [0][1][2][1][RTW89_QATAR][1][92] = 127, + [0][1][2][1][RTW89_QATAR][0][92] = 127, + [0][1][2][1][RTW89_UK][1][92] = 127, + [0][1][2][1][RTW89_UK][0][92] = 127, + [0][1][2][1][RTW89_FCC][1][94] = -2, + [0][1][2][1][RTW89_FCC][2][94] = 127, + [0][1][2][1][RTW89_ETSI][1][94] = 127, + [0][1][2][1][RTW89_ETSI][0][94] = 127, + [0][1][2][1][RTW89_MKK][1][94] = 127, + [0][1][2][1][RTW89_MKK][0][94] = 127, + [0][1][2][1][RTW89_IC][1][94] = -2, + [0][1][2][1][RTW89_KCC][1][94] = 20, + [0][1][2][1][RTW89_KCC][0][94] = 127, + [0][1][2][1][RTW89_ACMA][1][94] = 127, + [0][1][2][1][RTW89_ACMA][0][94] = 127, + [0][1][2][1][RTW89_CHILE][1][94] = -2, + [0][1][2][1][RTW89_QATAR][1][94] = 127, + [0][1][2][1][RTW89_QATAR][0][94] = 127, + [0][1][2][1][RTW89_UK][1][94] = 127, + [0][1][2][1][RTW89_UK][0][94] = 127, + [0][1][2][1][RTW89_FCC][1][96] = -2, + [0][1][2][1][RTW89_FCC][2][96] = 127, + [0][1][2][1][RTW89_ETSI][1][96] = 127, + [0][1][2][1][RTW89_ETSI][0][96] = 127, + [0][1][2][1][RTW89_MKK][1][96] = 127, + [0][1][2][1][RTW89_MKK][0][96] = 127, + [0][1][2][1][RTW89_IC][1][96] = -2, + [0][1][2][1][RTW89_KCC][1][96] = 20, + [0][1][2][1][RTW89_KCC][0][96] = 127, + [0][1][2][1][RTW89_ACMA][1][96] = 127, + [0][1][2][1][RTW89_ACMA][0][96] = 127, + [0][1][2][1][RTW89_CHILE][1][96] = -2, + [0][1][2][1][RTW89_QATAR][1][96] = 127, + [0][1][2][1][RTW89_QATAR][0][96] = 127, + [0][1][2][1][RTW89_UK][1][96] = 127, + [0][1][2][1][RTW89_UK][0][96] = 127, + [0][1][2][1][RTW89_FCC][1][98] = -2, + [0][1][2][1][RTW89_FCC][2][98] = 127, + [0][1][2][1][RTW89_ETSI][1][98] = 127, + [0][1][2][1][RTW89_ETSI][0][98] = 127, + [0][1][2][1][RTW89_MKK][1][98] = 127, + [0][1][2][1][RTW89_MKK][0][98] = 127, + [0][1][2][1][RTW89_IC][1][98] = -2, + [0][1][2][1][RTW89_KCC][1][98] = 20, + [0][1][2][1][RTW89_KCC][0][98] = 127, + [0][1][2][1][RTW89_ACMA][1][98] = 127, + [0][1][2][1][RTW89_ACMA][0][98] = 127, + [0][1][2][1][RTW89_CHILE][1][98] = -2, + [0][1][2][1][RTW89_QATAR][1][98] = 127, + [0][1][2][1][RTW89_QATAR][0][98] = 127, + [0][1][2][1][RTW89_UK][1][98] = 127, + [0][1][2][1][RTW89_UK][0][98] = 127, + [0][1][2][1][RTW89_FCC][1][100] = -2, + [0][1][2][1][RTW89_FCC][2][100] = 127, + [0][1][2][1][RTW89_ETSI][1][100] = 127, + [0][1][2][1][RTW89_ETSI][0][100] = 127, + [0][1][2][1][RTW89_MKK][1][100] = 127, + [0][1][2][1][RTW89_MKK][0][100] = 127, + [0][1][2][1][RTW89_IC][1][100] = -2, + [0][1][2][1][RTW89_KCC][1][100] = 20, + [0][1][2][1][RTW89_KCC][0][100] = 127, + [0][1][2][1][RTW89_ACMA][1][100] = 127, + [0][1][2][1][RTW89_ACMA][0][100] = 127, + [0][1][2][1][RTW89_CHILE][1][100] = -2, + [0][1][2][1][RTW89_QATAR][1][100] = 127, + [0][1][2][1][RTW89_QATAR][0][100] = 127, + [0][1][2][1][RTW89_UK][1][100] = 127, + [0][1][2][1][RTW89_UK][0][100] = 127, + [0][1][2][1][RTW89_FCC][1][102] = -2, + [0][1][2][1][RTW89_FCC][2][102] = 127, + [0][1][2][1][RTW89_ETSI][1][102] = 127, + [0][1][2][1][RTW89_ETSI][0][102] = 127, + [0][1][2][1][RTW89_MKK][1][102] = 127, + [0][1][2][1][RTW89_MKK][0][102] = 127, + [0][1][2][1][RTW89_IC][1][102] = -2, + [0][1][2][1][RTW89_KCC][1][102] = 20, + [0][1][2][1][RTW89_KCC][0][102] = 127, + [0][1][2][1][RTW89_ACMA][1][102] = 127, + [0][1][2][1][RTW89_ACMA][0][102] = 127, + [0][1][2][1][RTW89_CHILE][1][102] = -2, + [0][1][2][1][RTW89_QATAR][1][102] = 127, + [0][1][2][1][RTW89_QATAR][0][102] = 127, + [0][1][2][1][RTW89_UK][1][102] = 127, + [0][1][2][1][RTW89_UK][0][102] = 127, + [0][1][2][1][RTW89_FCC][1][104] = -2, + [0][1][2][1][RTW89_FCC][2][104] = 127, + [0][1][2][1][RTW89_ETSI][1][104] = 127, + [0][1][2][1][RTW89_ETSI][0][104] = 127, + [0][1][2][1][RTW89_MKK][1][104] = 127, + [0][1][2][1][RTW89_MKK][0][104] = 127, + [0][1][2][1][RTW89_IC][1][104] = -2, + [0][1][2][1][RTW89_KCC][1][104] = 20, + [0][1][2][1][RTW89_KCC][0][104] = 127, + [0][1][2][1][RTW89_ACMA][1][104] = 127, + [0][1][2][1][RTW89_ACMA][0][104] = 127, + [0][1][2][1][RTW89_CHILE][1][104] = -2, + [0][1][2][1][RTW89_QATAR][1][104] = 127, + [0][1][2][1][RTW89_QATAR][0][104] = 127, + [0][1][2][1][RTW89_UK][1][104] = 127, + [0][1][2][1][RTW89_UK][0][104] = 127, + [0][1][2][1][RTW89_FCC][1][105] = -2, + [0][1][2][1][RTW89_FCC][2][105] = 127, + [0][1][2][1][RTW89_ETSI][1][105] = 127, + [0][1][2][1][RTW89_ETSI][0][105] = 127, + [0][1][2][1][RTW89_MKK][1][105] = 127, + [0][1][2][1][RTW89_MKK][0][105] = 127, + [0][1][2][1][RTW89_IC][1][105] = -2, + [0][1][2][1][RTW89_KCC][1][105] = 20, + [0][1][2][1][RTW89_KCC][0][105] = 127, + [0][1][2][1][RTW89_ACMA][1][105] = 127, + [0][1][2][1][RTW89_ACMA][0][105] = 127, + [0][1][2][1][RTW89_CHILE][1][105] = -2, + [0][1][2][1][RTW89_QATAR][1][105] = 127, + [0][1][2][1][RTW89_QATAR][0][105] = 127, + [0][1][2][1][RTW89_UK][1][105] = 127, + [0][1][2][1][RTW89_UK][0][105] = 127, + [0][1][2][1][RTW89_FCC][1][107] = 1, + [0][1][2][1][RTW89_FCC][2][107] = 127, + [0][1][2][1][RTW89_ETSI][1][107] = 127, + [0][1][2][1][RTW89_ETSI][0][107] = 127, + [0][1][2][1][RTW89_MKK][1][107] = 127, + [0][1][2][1][RTW89_MKK][0][107] = 127, + [0][1][2][1][RTW89_IC][1][107] = 1, + [0][1][2][1][RTW89_KCC][1][107] = 20, + [0][1][2][1][RTW89_KCC][0][107] = 127, + [0][1][2][1][RTW89_ACMA][1][107] = 127, + [0][1][2][1][RTW89_ACMA][0][107] = 127, + [0][1][2][1][RTW89_CHILE][1][107] = 1, + [0][1][2][1][RTW89_QATAR][1][107] = 127, + [0][1][2][1][RTW89_QATAR][0][107] = 127, + [0][1][2][1][RTW89_UK][1][107] = 127, + [0][1][2][1][RTW89_UK][0][107] = 127, + [0][1][2][1][RTW89_FCC][1][109] = 1, + [0][1][2][1][RTW89_FCC][2][109] = 127, + [0][1][2][1][RTW89_ETSI][1][109] = 127, + [0][1][2][1][RTW89_ETSI][0][109] = 127, + [0][1][2][1][RTW89_MKK][1][109] = 127, + [0][1][2][1][RTW89_MKK][0][109] = 127, + [0][1][2][1][RTW89_IC][1][109] = 1, + [0][1][2][1][RTW89_KCC][1][109] = 20, + [0][1][2][1][RTW89_KCC][0][109] = 127, + [0][1][2][1][RTW89_ACMA][1][109] = 127, + [0][1][2][1][RTW89_ACMA][0][109] = 127, + [0][1][2][1][RTW89_CHILE][1][109] = 1, + [0][1][2][1][RTW89_QATAR][1][109] = 127, + [0][1][2][1][RTW89_QATAR][0][109] = 127, + [0][1][2][1][RTW89_UK][1][109] = 127, + [0][1][2][1][RTW89_UK][0][109] = 127, + [0][1][2][1][RTW89_FCC][1][111] = 127, + [0][1][2][1][RTW89_FCC][2][111] = 127, + [0][1][2][1][RTW89_ETSI][1][111] = 127, + [0][1][2][1][RTW89_ETSI][0][111] = 127, + [0][1][2][1][RTW89_MKK][1][111] = 127, + [0][1][2][1][RTW89_MKK][0][111] = 127, + [0][1][2][1][RTW89_IC][1][111] = 127, + [0][1][2][1][RTW89_KCC][1][111] = 127, + [0][1][2][1][RTW89_KCC][0][111] = 127, + [0][1][2][1][RTW89_ACMA][1][111] = 127, + [0][1][2][1][RTW89_ACMA][0][111] = 127, + [0][1][2][1][RTW89_CHILE][1][111] = 127, + [0][1][2][1][RTW89_QATAR][1][111] = 127, + [0][1][2][1][RTW89_QATAR][0][111] = 127, + [0][1][2][1][RTW89_UK][1][111] = 127, + [0][1][2][1][RTW89_UK][0][111] = 127, + [0][1][2][1][RTW89_FCC][1][113] = 127, + [0][1][2][1][RTW89_FCC][2][113] = 127, + [0][1][2][1][RTW89_ETSI][1][113] = 127, + [0][1][2][1][RTW89_ETSI][0][113] = 127, + [0][1][2][1][RTW89_MKK][1][113] = 127, + [0][1][2][1][RTW89_MKK][0][113] = 127, + [0][1][2][1][RTW89_IC][1][113] = 127, + [0][1][2][1][RTW89_KCC][1][113] = 127, + [0][1][2][1][RTW89_KCC][0][113] = 127, + [0][1][2][1][RTW89_ACMA][1][113] = 127, + [0][1][2][1][RTW89_ACMA][0][113] = 127, + [0][1][2][1][RTW89_CHILE][1][113] = 127, + [0][1][2][1][RTW89_QATAR][1][113] = 127, + [0][1][2][1][RTW89_QATAR][0][113] = 127, + [0][1][2][1][RTW89_UK][1][113] = 127, + [0][1][2][1][RTW89_UK][0][113] = 127, + [0][1][2][1][RTW89_FCC][1][115] = 127, + [0][1][2][1][RTW89_FCC][2][115] = 127, + [0][1][2][1][RTW89_ETSI][1][115] = 127, + [0][1][2][1][RTW89_ETSI][0][115] = 127, + [0][1][2][1][RTW89_MKK][1][115] = 127, + [0][1][2][1][RTW89_MKK][0][115] = 127, + [0][1][2][1][RTW89_IC][1][115] = 127, + [0][1][2][1][RTW89_KCC][1][115] = 127, + [0][1][2][1][RTW89_KCC][0][115] = 127, + [0][1][2][1][RTW89_ACMA][1][115] = 127, + [0][1][2][1][RTW89_ACMA][0][115] = 127, + [0][1][2][1][RTW89_CHILE][1][115] = 127, + [0][1][2][1][RTW89_QATAR][1][115] = 127, + [0][1][2][1][RTW89_QATAR][0][115] = 127, + [0][1][2][1][RTW89_UK][1][115] = 127, + [0][1][2][1][RTW89_UK][0][115] = 127, + [0][1][2][1][RTW89_FCC][1][117] = 127, + [0][1][2][1][RTW89_FCC][2][117] = 127, + [0][1][2][1][RTW89_ETSI][1][117] = 127, + [0][1][2][1][RTW89_ETSI][0][117] = 127, + [0][1][2][1][RTW89_MKK][1][117] = 127, + [0][1][2][1][RTW89_MKK][0][117] = 127, + [0][1][2][1][RTW89_IC][1][117] = 127, + [0][1][2][1][RTW89_KCC][1][117] = 127, + [0][1][2][1][RTW89_KCC][0][117] = 127, + [0][1][2][1][RTW89_ACMA][1][117] = 127, + [0][1][2][1][RTW89_ACMA][0][117] = 127, + [0][1][2][1][RTW89_CHILE][1][117] = 127, + [0][1][2][1][RTW89_QATAR][1][117] = 127, + [0][1][2][1][RTW89_QATAR][0][117] = 127, + [0][1][2][1][RTW89_UK][1][117] = 127, + [0][1][2][1][RTW89_UK][0][117] = 127, + [0][1][2][1][RTW89_FCC][1][119] = 127, + [0][1][2][1][RTW89_FCC][2][119] = 127, + [0][1][2][1][RTW89_ETSI][1][119] = 127, + [0][1][2][1][RTW89_ETSI][0][119] = 127, + [0][1][2][1][RTW89_MKK][1][119] = 127, + [0][1][2][1][RTW89_MKK][0][119] = 127, + [0][1][2][1][RTW89_IC][1][119] = 127, + [0][1][2][1][RTW89_KCC][1][119] = 127, + [0][1][2][1][RTW89_KCC][0][119] = 127, + [0][1][2][1][RTW89_ACMA][1][119] = 127, + [0][1][2][1][RTW89_ACMA][0][119] = 127, + [0][1][2][1][RTW89_CHILE][1][119] = 127, + [0][1][2][1][RTW89_QATAR][1][119] = 127, + [0][1][2][1][RTW89_QATAR][0][119] = 127, + [0][1][2][1][RTW89_UK][1][119] = 127, + [0][1][2][1][RTW89_UK][0][119] = 127, + [1][0][2][0][RTW89_FCC][1][1] = 34, + [1][0][2][0][RTW89_FCC][2][1] = 70, + [1][0][2][0][RTW89_ETSI][1][1] = 66, + [1][0][2][0][RTW89_ETSI][0][1] = 30, + [1][0][2][0][RTW89_MKK][1][1] = 62, + [1][0][2][0][RTW89_MKK][0][1] = 26, + [1][0][2][0][RTW89_IC][1][1] = 34, + [1][0][2][0][RTW89_KCC][1][1] = 40, + [1][0][2][0][RTW89_KCC][0][1] = 24, + [1][0][2][0][RTW89_ACMA][1][1] = 66, + [1][0][2][0][RTW89_ACMA][0][1] = 30, + [1][0][2][0][RTW89_CHILE][1][1] = 34, + [1][0][2][0][RTW89_QATAR][1][1] = 66, + [1][0][2][0][RTW89_QATAR][0][1] = 30, + [1][0][2][0][RTW89_UK][1][1] = 66, + [1][0][2][0][RTW89_UK][0][1] = 30, + [1][0][2][0][RTW89_FCC][1][5] = 34, + [1][0][2][0][RTW89_FCC][2][5] = 70, + [1][0][2][0][RTW89_ETSI][1][5] = 66, + [1][0][2][0][RTW89_ETSI][0][5] = 30, + [1][0][2][0][RTW89_MKK][1][5] = 62, + [1][0][2][0][RTW89_MKK][0][5] = 26, + [1][0][2][0][RTW89_IC][1][5] = 34, + [1][0][2][0][RTW89_KCC][1][5] = 40, + [1][0][2][0][RTW89_KCC][0][5] = 24, + [1][0][2][0][RTW89_ACMA][1][5] = 66, + [1][0][2][0][RTW89_ACMA][0][5] = 30, + [1][0][2][0][RTW89_CHILE][1][5] = 34, + [1][0][2][0][RTW89_QATAR][1][5] = 66, + [1][0][2][0][RTW89_QATAR][0][5] = 30, + [1][0][2][0][RTW89_UK][1][5] = 66, + [1][0][2][0][RTW89_UK][0][5] = 30, + [1][0][2][0][RTW89_FCC][1][9] = 34, + [1][0][2][0][RTW89_FCC][2][9] = 70, + [1][0][2][0][RTW89_ETSI][1][9] = 66, + [1][0][2][0][RTW89_ETSI][0][9] = 30, + [1][0][2][0][RTW89_MKK][1][9] = 62, + [1][0][2][0][RTW89_MKK][0][9] = 26, + [1][0][2][0][RTW89_IC][1][9] = 34, + [1][0][2][0][RTW89_KCC][1][9] = 40, + [1][0][2][0][RTW89_KCC][0][9] = 24, + [1][0][2][0][RTW89_ACMA][1][9] = 66, + [1][0][2][0][RTW89_ACMA][0][9] = 30, + [1][0][2][0][RTW89_CHILE][1][9] = 34, + [1][0][2][0][RTW89_QATAR][1][9] = 66, + [1][0][2][0][RTW89_QATAR][0][9] = 30, + [1][0][2][0][RTW89_UK][1][9] = 66, + [1][0][2][0][RTW89_UK][0][9] = 30, + [1][0][2][0][RTW89_FCC][1][13] = 34, + [1][0][2][0][RTW89_FCC][2][13] = 70, + [1][0][2][0][RTW89_ETSI][1][13] = 66, + [1][0][2][0][RTW89_ETSI][0][13] = 30, + [1][0][2][0][RTW89_MKK][1][13] = 62, + [1][0][2][0][RTW89_MKK][0][13] = 26, + [1][0][2][0][RTW89_IC][1][13] = 34, + [1][0][2][0][RTW89_KCC][1][13] = 40, + [1][0][2][0][RTW89_KCC][0][13] = 24, + [1][0][2][0][RTW89_ACMA][1][13] = 66, + [1][0][2][0][RTW89_ACMA][0][13] = 30, + [1][0][2][0][RTW89_CHILE][1][13] = 34, + [1][0][2][0][RTW89_QATAR][1][13] = 66, + [1][0][2][0][RTW89_QATAR][0][13] = 30, + [1][0][2][0][RTW89_UK][1][13] = 66, + [1][0][2][0][RTW89_UK][0][13] = 30, + [1][0][2][0][RTW89_FCC][1][16] = 34, + [1][0][2][0][RTW89_FCC][2][16] = 70, + [1][0][2][0][RTW89_ETSI][1][16] = 66, + [1][0][2][0][RTW89_ETSI][0][16] = 30, + [1][0][2][0][RTW89_MKK][1][16] = 62, + [1][0][2][0][RTW89_MKK][0][16] = 26, + [1][0][2][0][RTW89_IC][1][16] = 34, + [1][0][2][0][RTW89_KCC][1][16] = 40, + [1][0][2][0][RTW89_KCC][0][16] = 24, + [1][0][2][0][RTW89_ACMA][1][16] = 66, + [1][0][2][0][RTW89_ACMA][0][16] = 30, + [1][0][2][0][RTW89_CHILE][1][16] = 34, + [1][0][2][0][RTW89_QATAR][1][16] = 66, + [1][0][2][0][RTW89_QATAR][0][16] = 30, + [1][0][2][0][RTW89_UK][1][16] = 66, + [1][0][2][0][RTW89_UK][0][16] = 30, + [1][0][2][0][RTW89_FCC][1][20] = 34, + [1][0][2][0][RTW89_FCC][2][20] = 70, + [1][0][2][0][RTW89_ETSI][1][20] = 66, + [1][0][2][0][RTW89_ETSI][0][20] = 30, + [1][0][2][0][RTW89_MKK][1][20] = 62, + [1][0][2][0][RTW89_MKK][0][20] = 26, + [1][0][2][0][RTW89_IC][1][20] = 34, + [1][0][2][0][RTW89_KCC][1][20] = 40, + [1][0][2][0][RTW89_KCC][0][20] = 24, + [1][0][2][0][RTW89_ACMA][1][20] = 66, + [1][0][2][0][RTW89_ACMA][0][20] = 30, + [1][0][2][0][RTW89_CHILE][1][20] = 34, + [1][0][2][0][RTW89_QATAR][1][20] = 66, + [1][0][2][0][RTW89_QATAR][0][20] = 30, + [1][0][2][0][RTW89_UK][1][20] = 66, + [1][0][2][0][RTW89_UK][0][20] = 30, + [1][0][2][0][RTW89_FCC][1][24] = 36, + [1][0][2][0][RTW89_FCC][2][24] = 70, + [1][0][2][0][RTW89_ETSI][1][24] = 66, + [1][0][2][0][RTW89_ETSI][0][24] = 30, + [1][0][2][0][RTW89_MKK][1][24] = 64, + [1][0][2][0][RTW89_MKK][0][24] = 28, + [1][0][2][0][RTW89_IC][1][24] = 36, + [1][0][2][0][RTW89_KCC][1][24] = 40, + [1][0][2][0][RTW89_KCC][0][24] = 26, + [1][0][2][0][RTW89_ACMA][1][24] = 66, + [1][0][2][0][RTW89_ACMA][0][24] = 30, + [1][0][2][0][RTW89_CHILE][1][24] = 36, + [1][0][2][0][RTW89_QATAR][1][24] = 66, + [1][0][2][0][RTW89_QATAR][0][24] = 30, + [1][0][2][0][RTW89_UK][1][24] = 66, + [1][0][2][0][RTW89_UK][0][24] = 30, + [1][0][2][0][RTW89_FCC][1][28] = 34, + [1][0][2][0][RTW89_FCC][2][28] = 70, + [1][0][2][0][RTW89_ETSI][1][28] = 66, + [1][0][2][0][RTW89_ETSI][0][28] = 30, + [1][0][2][0][RTW89_MKK][1][28] = 64, + [1][0][2][0][RTW89_MKK][0][28] = 26, + [1][0][2][0][RTW89_IC][1][28] = 34, + [1][0][2][0][RTW89_KCC][1][28] = 40, + [1][0][2][0][RTW89_KCC][0][28] = 26, + [1][0][2][0][RTW89_ACMA][1][28] = 66, + [1][0][2][0][RTW89_ACMA][0][28] = 30, + [1][0][2][0][RTW89_CHILE][1][28] = 34, + [1][0][2][0][RTW89_QATAR][1][28] = 66, + [1][0][2][0][RTW89_QATAR][0][28] = 30, + [1][0][2][0][RTW89_UK][1][28] = 66, + [1][0][2][0][RTW89_UK][0][28] = 30, + [1][0][2][0][RTW89_FCC][1][31] = 34, + [1][0][2][0][RTW89_FCC][2][31] = 70, + [1][0][2][0][RTW89_ETSI][1][31] = 66, + [1][0][2][0][RTW89_ETSI][0][31] = 30, + [1][0][2][0][RTW89_MKK][1][31] = 64, + [1][0][2][0][RTW89_MKK][0][31] = 26, + [1][0][2][0][RTW89_IC][1][31] = 34, + [1][0][2][0][RTW89_KCC][1][31] = 40, + [1][0][2][0][RTW89_KCC][0][31] = 26, + [1][0][2][0][RTW89_ACMA][1][31] = 66, + [1][0][2][0][RTW89_ACMA][0][31] = 30, + [1][0][2][0][RTW89_CHILE][1][31] = 34, + [1][0][2][0][RTW89_QATAR][1][31] = 66, + [1][0][2][0][RTW89_QATAR][0][31] = 30, + [1][0][2][0][RTW89_UK][1][31] = 66, + [1][0][2][0][RTW89_UK][0][31] = 30, + [1][0][2][0][RTW89_FCC][1][35] = 34, + [1][0][2][0][RTW89_FCC][2][35] = 70, + [1][0][2][0][RTW89_ETSI][1][35] = 66, + [1][0][2][0][RTW89_ETSI][0][35] = 30, + [1][0][2][0][RTW89_MKK][1][35] = 64, + [1][0][2][0][RTW89_MKK][0][35] = 26, + [1][0][2][0][RTW89_IC][1][35] = 34, + [1][0][2][0][RTW89_KCC][1][35] = 40, + [1][0][2][0][RTW89_KCC][0][35] = 26, + [1][0][2][0][RTW89_ACMA][1][35] = 66, + [1][0][2][0][RTW89_ACMA][0][35] = 30, + [1][0][2][0][RTW89_CHILE][1][35] = 34, + [1][0][2][0][RTW89_QATAR][1][35] = 66, + [1][0][2][0][RTW89_QATAR][0][35] = 30, + [1][0][2][0][RTW89_UK][1][35] = 66, + [1][0][2][0][RTW89_UK][0][35] = 30, + [1][0][2][0][RTW89_FCC][1][39] = 34, + [1][0][2][0][RTW89_FCC][2][39] = 70, + [1][0][2][0][RTW89_ETSI][1][39] = 66, + [1][0][2][0][RTW89_ETSI][0][39] = 30, + [1][0][2][0][RTW89_MKK][1][39] = 64, + [1][0][2][0][RTW89_MKK][0][39] = 26, + [1][0][2][0][RTW89_IC][1][39] = 34, + [1][0][2][0][RTW89_KCC][1][39] = 40, + [1][0][2][0][RTW89_KCC][0][39] = 26, + [1][0][2][0][RTW89_ACMA][1][39] = 66, + [1][0][2][0][RTW89_ACMA][0][39] = 30, + [1][0][2][0][RTW89_CHILE][1][39] = 34, + [1][0][2][0][RTW89_QATAR][1][39] = 66, + [1][0][2][0][RTW89_QATAR][0][39] = 30, + [1][0][2][0][RTW89_UK][1][39] = 66, + [1][0][2][0][RTW89_UK][0][39] = 30, + [1][0][2][0][RTW89_FCC][1][43] = 34, + [1][0][2][0][RTW89_FCC][2][43] = 70, + [1][0][2][0][RTW89_ETSI][1][43] = 66, + [1][0][2][0][RTW89_ETSI][0][43] = 30, + [1][0][2][0][RTW89_MKK][1][43] = 64, + [1][0][2][0][RTW89_MKK][0][43] = 26, + [1][0][2][0][RTW89_IC][1][43] = 34, + [1][0][2][0][RTW89_KCC][1][43] = 40, + [1][0][2][0][RTW89_KCC][0][43] = 26, + [1][0][2][0][RTW89_ACMA][1][43] = 66, + [1][0][2][0][RTW89_ACMA][0][43] = 30, + [1][0][2][0][RTW89_CHILE][1][43] = 34, + [1][0][2][0][RTW89_QATAR][1][43] = 66, + [1][0][2][0][RTW89_QATAR][0][43] = 30, + [1][0][2][0][RTW89_UK][1][43] = 66, + [1][0][2][0][RTW89_UK][0][43] = 30, + [1][0][2][0][RTW89_FCC][1][46] = 34, + [1][0][2][0][RTW89_FCC][2][46] = 127, + [1][0][2][0][RTW89_ETSI][1][46] = 127, + [1][0][2][0][RTW89_ETSI][0][46] = 127, + [1][0][2][0][RTW89_MKK][1][46] = 127, + [1][0][2][0][RTW89_MKK][0][46] = 127, + [1][0][2][0][RTW89_IC][1][46] = 34, + [1][0][2][0][RTW89_KCC][1][46] = 40, + [1][0][2][0][RTW89_KCC][0][46] = 127, + [1][0][2][0][RTW89_ACMA][1][46] = 127, + [1][0][2][0][RTW89_ACMA][0][46] = 127, + [1][0][2][0][RTW89_CHILE][1][46] = 34, + [1][0][2][0][RTW89_QATAR][1][46] = 127, + [1][0][2][0][RTW89_QATAR][0][46] = 127, + [1][0][2][0][RTW89_UK][1][46] = 127, + [1][0][2][0][RTW89_UK][0][46] = 127, + [1][0][2][0][RTW89_FCC][1][50] = 34, + [1][0][2][0][RTW89_FCC][2][50] = 127, + [1][0][2][0][RTW89_ETSI][1][50] = 127, + [1][0][2][0][RTW89_ETSI][0][50] = 127, + [1][0][2][0][RTW89_MKK][1][50] = 127, + [1][0][2][0][RTW89_MKK][0][50] = 127, + [1][0][2][0][RTW89_IC][1][50] = 34, + [1][0][2][0][RTW89_KCC][1][50] = 40, + [1][0][2][0][RTW89_KCC][0][50] = 127, + [1][0][2][0][RTW89_ACMA][1][50] = 127, + [1][0][2][0][RTW89_ACMA][0][50] = 127, + [1][0][2][0][RTW89_CHILE][1][50] = 34, + [1][0][2][0][RTW89_QATAR][1][50] = 127, + [1][0][2][0][RTW89_QATAR][0][50] = 127, + [1][0][2][0][RTW89_UK][1][50] = 127, + [1][0][2][0][RTW89_UK][0][50] = 127, + [1][0][2][0][RTW89_FCC][1][54] = 36, + [1][0][2][0][RTW89_FCC][2][54] = 127, + [1][0][2][0][RTW89_ETSI][1][54] = 127, + [1][0][2][0][RTW89_ETSI][0][54] = 127, + [1][0][2][0][RTW89_MKK][1][54] = 127, + [1][0][2][0][RTW89_MKK][0][54] = 127, + [1][0][2][0][RTW89_IC][1][54] = 36, + [1][0][2][0][RTW89_KCC][1][54] = 40, + [1][0][2][0][RTW89_KCC][0][54] = 127, + [1][0][2][0][RTW89_ACMA][1][54] = 127, + [1][0][2][0][RTW89_ACMA][0][54] = 127, + [1][0][2][0][RTW89_CHILE][1][54] = 36, + [1][0][2][0][RTW89_QATAR][1][54] = 127, + [1][0][2][0][RTW89_QATAR][0][54] = 127, + [1][0][2][0][RTW89_UK][1][54] = 127, + [1][0][2][0][RTW89_UK][0][54] = 127, + [1][0][2][0][RTW89_FCC][1][58] = 36, + [1][0][2][0][RTW89_FCC][2][58] = 66, + [1][0][2][0][RTW89_ETSI][1][58] = 127, + [1][0][2][0][RTW89_ETSI][0][58] = 127, + [1][0][2][0][RTW89_MKK][1][58] = 127, + [1][0][2][0][RTW89_MKK][0][58] = 127, + [1][0][2][0][RTW89_IC][1][58] = 36, + [1][0][2][0][RTW89_KCC][1][58] = 40, + [1][0][2][0][RTW89_KCC][0][58] = 127, + [1][0][2][0][RTW89_ACMA][1][58] = 127, + [1][0][2][0][RTW89_ACMA][0][58] = 127, + [1][0][2][0][RTW89_CHILE][1][58] = 36, + [1][0][2][0][RTW89_QATAR][1][58] = 127, + [1][0][2][0][RTW89_QATAR][0][58] = 127, + [1][0][2][0][RTW89_UK][1][58] = 127, + [1][0][2][0][RTW89_UK][0][58] = 127, + [1][0][2][0][RTW89_FCC][1][61] = 34, + [1][0][2][0][RTW89_FCC][2][61] = 66, + [1][0][2][0][RTW89_ETSI][1][61] = 127, + [1][0][2][0][RTW89_ETSI][0][61] = 127, + [1][0][2][0][RTW89_MKK][1][61] = 127, + [1][0][2][0][RTW89_MKK][0][61] = 127, + [1][0][2][0][RTW89_IC][1][61] = 34, + [1][0][2][0][RTW89_KCC][1][61] = 40, + [1][0][2][0][RTW89_KCC][0][61] = 127, + [1][0][2][0][RTW89_ACMA][1][61] = 127, + [1][0][2][0][RTW89_ACMA][0][61] = 127, + [1][0][2][0][RTW89_CHILE][1][61] = 34, + [1][0][2][0][RTW89_QATAR][1][61] = 127, + [1][0][2][0][RTW89_QATAR][0][61] = 127, + [1][0][2][0][RTW89_UK][1][61] = 127, + [1][0][2][0][RTW89_UK][0][61] = 127, + [1][0][2][0][RTW89_FCC][1][65] = 34, + [1][0][2][0][RTW89_FCC][2][65] = 66, + [1][0][2][0][RTW89_ETSI][1][65] = 127, + [1][0][2][0][RTW89_ETSI][0][65] = 127, + [1][0][2][0][RTW89_MKK][1][65] = 127, + [1][0][2][0][RTW89_MKK][0][65] = 127, + [1][0][2][0][RTW89_IC][1][65] = 34, + [1][0][2][0][RTW89_KCC][1][65] = 40, + [1][0][2][0][RTW89_KCC][0][65] = 127, + [1][0][2][0][RTW89_ACMA][1][65] = 127, + [1][0][2][0][RTW89_ACMA][0][65] = 127, + [1][0][2][0][RTW89_CHILE][1][65] = 34, + [1][0][2][0][RTW89_QATAR][1][65] = 127, + [1][0][2][0][RTW89_QATAR][0][65] = 127, + [1][0][2][0][RTW89_UK][1][65] = 127, + [1][0][2][0][RTW89_UK][0][65] = 127, + [1][0][2][0][RTW89_FCC][1][69] = 34, + [1][0][2][0][RTW89_FCC][2][69] = 66, + [1][0][2][0][RTW89_ETSI][1][69] = 127, + [1][0][2][0][RTW89_ETSI][0][69] = 127, + [1][0][2][0][RTW89_MKK][1][69] = 127, + [1][0][2][0][RTW89_MKK][0][69] = 127, + [1][0][2][0][RTW89_IC][1][69] = 34, + [1][0][2][0][RTW89_KCC][1][69] = 40, + [1][0][2][0][RTW89_KCC][0][69] = 127, + [1][0][2][0][RTW89_ACMA][1][69] = 127, + [1][0][2][0][RTW89_ACMA][0][69] = 127, + [1][0][2][0][RTW89_CHILE][1][69] = 34, + [1][0][2][0][RTW89_QATAR][1][69] = 127, + [1][0][2][0][RTW89_QATAR][0][69] = 127, + [1][0][2][0][RTW89_UK][1][69] = 127, + [1][0][2][0][RTW89_UK][0][69] = 127, + [1][0][2][0][RTW89_FCC][1][73] = 34, + [1][0][2][0][RTW89_FCC][2][73] = 66, + [1][0][2][0][RTW89_ETSI][1][73] = 127, + [1][0][2][0][RTW89_ETSI][0][73] = 127, + [1][0][2][0][RTW89_MKK][1][73] = 127, + [1][0][2][0][RTW89_MKK][0][73] = 127, + [1][0][2][0][RTW89_IC][1][73] = 34, + [1][0][2][0][RTW89_KCC][1][73] = 40, + [1][0][2][0][RTW89_KCC][0][73] = 127, + [1][0][2][0][RTW89_ACMA][1][73] = 127, + [1][0][2][0][RTW89_ACMA][0][73] = 127, + [1][0][2][0][RTW89_CHILE][1][73] = 34, + [1][0][2][0][RTW89_QATAR][1][73] = 127, + [1][0][2][0][RTW89_QATAR][0][73] = 127, + [1][0][2][0][RTW89_UK][1][73] = 127, + [1][0][2][0][RTW89_UK][0][73] = 127, + [1][0][2][0][RTW89_FCC][1][76] = 34, + [1][0][2][0][RTW89_FCC][2][76] = 66, + [1][0][2][0][RTW89_ETSI][1][76] = 127, + [1][0][2][0][RTW89_ETSI][0][76] = 127, + [1][0][2][0][RTW89_MKK][1][76] = 127, + [1][0][2][0][RTW89_MKK][0][76] = 127, + [1][0][2][0][RTW89_IC][1][76] = 34, + [1][0][2][0][RTW89_KCC][1][76] = 40, + [1][0][2][0][RTW89_KCC][0][76] = 127, + [1][0][2][0][RTW89_ACMA][1][76] = 127, + [1][0][2][0][RTW89_ACMA][0][76] = 127, + [1][0][2][0][RTW89_CHILE][1][76] = 34, + [1][0][2][0][RTW89_QATAR][1][76] = 127, + [1][0][2][0][RTW89_QATAR][0][76] = 127, + [1][0][2][0][RTW89_UK][1][76] = 127, + [1][0][2][0][RTW89_UK][0][76] = 127, + [1][0][2][0][RTW89_FCC][1][80] = 34, + [1][0][2][0][RTW89_FCC][2][80] = 66, + [1][0][2][0][RTW89_ETSI][1][80] = 127, + [1][0][2][0][RTW89_ETSI][0][80] = 127, + [1][0][2][0][RTW89_MKK][1][80] = 127, + [1][0][2][0][RTW89_MKK][0][80] = 127, + [1][0][2][0][RTW89_IC][1][80] = 34, + [1][0][2][0][RTW89_KCC][1][80] = 42, + [1][0][2][0][RTW89_KCC][0][80] = 127, + [1][0][2][0][RTW89_ACMA][1][80] = 127, + [1][0][2][0][RTW89_ACMA][0][80] = 127, + [1][0][2][0][RTW89_CHILE][1][80] = 34, + [1][0][2][0][RTW89_QATAR][1][80] = 127, + [1][0][2][0][RTW89_QATAR][0][80] = 127, + [1][0][2][0][RTW89_UK][1][80] = 127, + [1][0][2][0][RTW89_UK][0][80] = 127, + [1][0][2][0][RTW89_FCC][1][84] = 34, + [1][0][2][0][RTW89_FCC][2][84] = 66, + [1][0][2][0][RTW89_ETSI][1][84] = 127, + [1][0][2][0][RTW89_ETSI][0][84] = 127, + [1][0][2][0][RTW89_MKK][1][84] = 127, + [1][0][2][0][RTW89_MKK][0][84] = 127, + [1][0][2][0][RTW89_IC][1][84] = 34, + [1][0][2][0][RTW89_KCC][1][84] = 42, + [1][0][2][0][RTW89_KCC][0][84] = 127, + [1][0][2][0][RTW89_ACMA][1][84] = 127, + [1][0][2][0][RTW89_ACMA][0][84] = 127, + [1][0][2][0][RTW89_CHILE][1][84] = 34, + [1][0][2][0][RTW89_QATAR][1][84] = 127, + [1][0][2][0][RTW89_QATAR][0][84] = 127, + [1][0][2][0][RTW89_UK][1][84] = 127, + [1][0][2][0][RTW89_UK][0][84] = 127, + [1][0][2][0][RTW89_FCC][1][88] = 34, + [1][0][2][0][RTW89_FCC][2][88] = 127, + [1][0][2][0][RTW89_ETSI][1][88] = 127, + [1][0][2][0][RTW89_ETSI][0][88] = 127, + [1][0][2][0][RTW89_MKK][1][88] = 127, + [1][0][2][0][RTW89_MKK][0][88] = 127, + [1][0][2][0][RTW89_IC][1][88] = 34, + [1][0][2][0][RTW89_KCC][1][88] = 42, + [1][0][2][0][RTW89_KCC][0][88] = 127, + [1][0][2][0][RTW89_ACMA][1][88] = 127, + [1][0][2][0][RTW89_ACMA][0][88] = 127, + [1][0][2][0][RTW89_CHILE][1][88] = 34, + [1][0][2][0][RTW89_QATAR][1][88] = 127, + [1][0][2][0][RTW89_QATAR][0][88] = 127, + [1][0][2][0][RTW89_UK][1][88] = 127, + [1][0][2][0][RTW89_UK][0][88] = 127, + [1][0][2][0][RTW89_FCC][1][91] = 36, + [1][0][2][0][RTW89_FCC][2][91] = 127, + [1][0][2][0][RTW89_ETSI][1][91] = 127, + [1][0][2][0][RTW89_ETSI][0][91] = 127, + [1][0][2][0][RTW89_MKK][1][91] = 127, + [1][0][2][0][RTW89_MKK][0][91] = 127, + [1][0][2][0][RTW89_IC][1][91] = 36, + [1][0][2][0][RTW89_KCC][1][91] = 42, + [1][0][2][0][RTW89_KCC][0][91] = 127, + [1][0][2][0][RTW89_ACMA][1][91] = 127, + [1][0][2][0][RTW89_ACMA][0][91] = 127, + [1][0][2][0][RTW89_CHILE][1][91] = 36, + [1][0][2][0][RTW89_QATAR][1][91] = 127, + [1][0][2][0][RTW89_QATAR][0][91] = 127, + [1][0][2][0][RTW89_UK][1][91] = 127, + [1][0][2][0][RTW89_UK][0][91] = 127, + [1][0][2][0][RTW89_FCC][1][95] = 34, + [1][0][2][0][RTW89_FCC][2][95] = 127, + [1][0][2][0][RTW89_ETSI][1][95] = 127, + [1][0][2][0][RTW89_ETSI][0][95] = 127, + [1][0][2][0][RTW89_MKK][1][95] = 127, + [1][0][2][0][RTW89_MKK][0][95] = 127, + [1][0][2][0][RTW89_IC][1][95] = 34, + [1][0][2][0][RTW89_KCC][1][95] = 42, + [1][0][2][0][RTW89_KCC][0][95] = 127, + [1][0][2][0][RTW89_ACMA][1][95] = 127, + [1][0][2][0][RTW89_ACMA][0][95] = 127, + [1][0][2][0][RTW89_CHILE][1][95] = 34, + [1][0][2][0][RTW89_QATAR][1][95] = 127, + [1][0][2][0][RTW89_QATAR][0][95] = 127, + [1][0][2][0][RTW89_UK][1][95] = 127, + [1][0][2][0][RTW89_UK][0][95] = 127, + [1][0][2][0][RTW89_FCC][1][99] = 34, + [1][0][2][0][RTW89_FCC][2][99] = 127, + [1][0][2][0][RTW89_ETSI][1][99] = 127, + [1][0][2][0][RTW89_ETSI][0][99] = 127, + [1][0][2][0][RTW89_MKK][1][99] = 127, + [1][0][2][0][RTW89_MKK][0][99] = 127, + [1][0][2][0][RTW89_IC][1][99] = 34, + [1][0][2][0][RTW89_KCC][1][99] = 42, + [1][0][2][0][RTW89_KCC][0][99] = 127, + [1][0][2][0][RTW89_ACMA][1][99] = 127, + [1][0][2][0][RTW89_ACMA][0][99] = 127, + [1][0][2][0][RTW89_CHILE][1][99] = 34, + [1][0][2][0][RTW89_QATAR][1][99] = 127, + [1][0][2][0][RTW89_QATAR][0][99] = 127, + [1][0][2][0][RTW89_UK][1][99] = 127, + [1][0][2][0][RTW89_UK][0][99] = 127, + [1][0][2][0][RTW89_FCC][1][103] = 34, + [1][0][2][0][RTW89_FCC][2][103] = 127, + [1][0][2][0][RTW89_ETSI][1][103] = 127, + [1][0][2][0][RTW89_ETSI][0][103] = 127, + [1][0][2][0][RTW89_MKK][1][103] = 127, + [1][0][2][0][RTW89_MKK][0][103] = 127, + [1][0][2][0][RTW89_IC][1][103] = 34, + [1][0][2][0][RTW89_KCC][1][103] = 42, + [1][0][2][0][RTW89_KCC][0][103] = 127, + [1][0][2][0][RTW89_ACMA][1][103] = 127, + [1][0][2][0][RTW89_ACMA][0][103] = 127, + [1][0][2][0][RTW89_CHILE][1][103] = 34, + [1][0][2][0][RTW89_QATAR][1][103] = 127, + [1][0][2][0][RTW89_QATAR][0][103] = 127, + [1][0][2][0][RTW89_UK][1][103] = 127, + [1][0][2][0][RTW89_UK][0][103] = 127, + [1][0][2][0][RTW89_FCC][1][106] = 36, + [1][0][2][0][RTW89_FCC][2][106] = 127, + [1][0][2][0][RTW89_ETSI][1][106] = 127, + [1][0][2][0][RTW89_ETSI][0][106] = 127, + [1][0][2][0][RTW89_MKK][1][106] = 127, + [1][0][2][0][RTW89_MKK][0][106] = 127, + [1][0][2][0][RTW89_IC][1][106] = 36, + [1][0][2][0][RTW89_KCC][1][106] = 42, + [1][0][2][0][RTW89_KCC][0][106] = 127, + [1][0][2][0][RTW89_ACMA][1][106] = 127, + [1][0][2][0][RTW89_ACMA][0][106] = 127, + [1][0][2][0][RTW89_CHILE][1][106] = 36, + [1][0][2][0][RTW89_QATAR][1][106] = 127, + [1][0][2][0][RTW89_QATAR][0][106] = 127, + [1][0][2][0][RTW89_UK][1][106] = 127, + [1][0][2][0][RTW89_UK][0][106] = 127, + [1][0][2][0][RTW89_FCC][1][110] = 127, + [1][0][2][0][RTW89_FCC][2][110] = 127, + [1][0][2][0][RTW89_ETSI][1][110] = 127, + [1][0][2][0][RTW89_ETSI][0][110] = 127, + [1][0][2][0][RTW89_MKK][1][110] = 127, + [1][0][2][0][RTW89_MKK][0][110] = 127, + [1][0][2][0][RTW89_IC][1][110] = 127, + [1][0][2][0][RTW89_KCC][1][110] = 127, + [1][0][2][0][RTW89_KCC][0][110] = 127, + [1][0][2][0][RTW89_ACMA][1][110] = 127, + [1][0][2][0][RTW89_ACMA][0][110] = 127, + [1][0][2][0][RTW89_CHILE][1][110] = 127, + [1][0][2][0][RTW89_QATAR][1][110] = 127, + [1][0][2][0][RTW89_QATAR][0][110] = 127, + [1][0][2][0][RTW89_UK][1][110] = 127, + [1][0][2][0][RTW89_UK][0][110] = 127, + [1][0][2][0][RTW89_FCC][1][114] = 127, + [1][0][2][0][RTW89_FCC][2][114] = 127, + [1][0][2][0][RTW89_ETSI][1][114] = 127, + [1][0][2][0][RTW89_ETSI][0][114] = 127, + [1][0][2][0][RTW89_MKK][1][114] = 127, + [1][0][2][0][RTW89_MKK][0][114] = 127, + [1][0][2][0][RTW89_IC][1][114] = 127, + [1][0][2][0][RTW89_KCC][1][114] = 127, + [1][0][2][0][RTW89_KCC][0][114] = 127, + [1][0][2][0][RTW89_ACMA][1][114] = 127, + [1][0][2][0][RTW89_ACMA][0][114] = 127, + [1][0][2][0][RTW89_CHILE][1][114] = 127, + [1][0][2][0][RTW89_QATAR][1][114] = 127, + [1][0][2][0][RTW89_QATAR][0][114] = 127, + [1][0][2][0][RTW89_UK][1][114] = 127, + [1][0][2][0][RTW89_UK][0][114] = 127, + [1][0][2][0][RTW89_FCC][1][118] = 127, + [1][0][2][0][RTW89_FCC][2][118] = 127, + [1][0][2][0][RTW89_ETSI][1][118] = 127, + [1][0][2][0][RTW89_ETSI][0][118] = 127, + [1][0][2][0][RTW89_MKK][1][118] = 127, + [1][0][2][0][RTW89_MKK][0][118] = 127, + [1][0][2][0][RTW89_IC][1][118] = 127, + [1][0][2][0][RTW89_KCC][1][118] = 127, + [1][0][2][0][RTW89_KCC][0][118] = 127, + [1][0][2][0][RTW89_ACMA][1][118] = 127, + [1][0][2][0][RTW89_ACMA][0][118] = 127, + [1][0][2][0][RTW89_CHILE][1][118] = 127, + [1][0][2][0][RTW89_QATAR][1][118] = 127, + [1][0][2][0][RTW89_QATAR][0][118] = 127, + [1][0][2][0][RTW89_UK][1][118] = 127, + [1][0][2][0][RTW89_UK][0][118] = 127, + [1][1][2][0][RTW89_FCC][1][1] = 10, + [1][1][2][0][RTW89_FCC][2][1] = 58, + [1][1][2][0][RTW89_ETSI][1][1] = 54, + [1][1][2][0][RTW89_ETSI][0][1] = 18, + [1][1][2][0][RTW89_MKK][1][1] = 52, + [1][1][2][0][RTW89_MKK][0][1] = 12, + [1][1][2][0][RTW89_IC][1][1] = 10, + [1][1][2][0][RTW89_KCC][1][1] = 28, + [1][1][2][0][RTW89_KCC][0][1] = 12, + [1][1][2][0][RTW89_ACMA][1][1] = 54, + [1][1][2][0][RTW89_ACMA][0][1] = 18, + [1][1][2][0][RTW89_CHILE][1][1] = 10, + [1][1][2][0][RTW89_QATAR][1][1] = 54, + [1][1][2][0][RTW89_QATAR][0][1] = 18, + [1][1][2][0][RTW89_UK][1][1] = 54, + [1][1][2][0][RTW89_UK][0][1] = 18, + [1][1][2][0][RTW89_FCC][1][5] = 10, + [1][1][2][0][RTW89_FCC][2][5] = 58, + [1][1][2][0][RTW89_ETSI][1][5] = 54, + [1][1][2][0][RTW89_ETSI][0][5] = 16, + [1][1][2][0][RTW89_MKK][1][5] = 52, + [1][1][2][0][RTW89_MKK][0][5] = 12, + [1][1][2][0][RTW89_IC][1][5] = 10, + [1][1][2][0][RTW89_KCC][1][5] = 28, + [1][1][2][0][RTW89_KCC][0][5] = 12, + [1][1][2][0][RTW89_ACMA][1][5] = 54, + [1][1][2][0][RTW89_ACMA][0][5] = 16, + [1][1][2][0][RTW89_CHILE][1][5] = 10, + [1][1][2][0][RTW89_QATAR][1][5] = 54, + [1][1][2][0][RTW89_QATAR][0][5] = 16, + [1][1][2][0][RTW89_UK][1][5] = 54, + [1][1][2][0][RTW89_UK][0][5] = 16, + [1][1][2][0][RTW89_FCC][1][9] = 10, + [1][1][2][0][RTW89_FCC][2][9] = 58, + [1][1][2][0][RTW89_ETSI][1][9] = 54, + [1][1][2][0][RTW89_ETSI][0][9] = 16, + [1][1][2][0][RTW89_MKK][1][9] = 52, + [1][1][2][0][RTW89_MKK][0][9] = 12, + [1][1][2][0][RTW89_IC][1][9] = 10, + [1][1][2][0][RTW89_KCC][1][9] = 28, + [1][1][2][0][RTW89_KCC][0][9] = 12, + [1][1][2][0][RTW89_ACMA][1][9] = 54, + [1][1][2][0][RTW89_ACMA][0][9] = 16, + [1][1][2][0][RTW89_CHILE][1][9] = 10, + [1][1][2][0][RTW89_QATAR][1][9] = 54, + [1][1][2][0][RTW89_QATAR][0][9] = 16, + [1][1][2][0][RTW89_UK][1][9] = 54, + [1][1][2][0][RTW89_UK][0][9] = 16, + [1][1][2][0][RTW89_FCC][1][13] = 10, + [1][1][2][0][RTW89_FCC][2][13] = 58, + [1][1][2][0][RTW89_ETSI][1][13] = 54, + [1][1][2][0][RTW89_ETSI][0][13] = 16, + [1][1][2][0][RTW89_MKK][1][13] = 52, + [1][1][2][0][RTW89_MKK][0][13] = 12, + [1][1][2][0][RTW89_IC][1][13] = 10, + [1][1][2][0][RTW89_KCC][1][13] = 28, + [1][1][2][0][RTW89_KCC][0][13] = 12, + [1][1][2][0][RTW89_ACMA][1][13] = 54, + [1][1][2][0][RTW89_ACMA][0][13] = 16, + [1][1][2][0][RTW89_CHILE][1][13] = 10, + [1][1][2][0][RTW89_QATAR][1][13] = 54, + [1][1][2][0][RTW89_QATAR][0][13] = 16, + [1][1][2][0][RTW89_UK][1][13] = 54, + [1][1][2][0][RTW89_UK][0][13] = 16, + [1][1][2][0][RTW89_FCC][1][16] = 10, + [1][1][2][0][RTW89_FCC][2][16] = 58, + [1][1][2][0][RTW89_ETSI][1][16] = 54, + [1][1][2][0][RTW89_ETSI][0][16] = 16, + [1][1][2][0][RTW89_MKK][1][16] = 52, + [1][1][2][0][RTW89_MKK][0][16] = 12, + [1][1][2][0][RTW89_IC][1][16] = 10, + [1][1][2][0][RTW89_KCC][1][16] = 28, + [1][1][2][0][RTW89_KCC][0][16] = 12, + [1][1][2][0][RTW89_ACMA][1][16] = 54, + [1][1][2][0][RTW89_ACMA][0][16] = 16, + [1][1][2][0][RTW89_CHILE][1][16] = 10, + [1][1][2][0][RTW89_QATAR][1][16] = 54, + [1][1][2][0][RTW89_QATAR][0][16] = 16, + [1][1][2][0][RTW89_UK][1][16] = 54, + [1][1][2][0][RTW89_UK][0][16] = 16, + [1][1][2][0][RTW89_FCC][1][20] = 10, + [1][1][2][0][RTW89_FCC][2][20] = 58, + [1][1][2][0][RTW89_ETSI][1][20] = 54, + [1][1][2][0][RTW89_ETSI][0][20] = 16, + [1][1][2][0][RTW89_MKK][1][20] = 52, + [1][1][2][0][RTW89_MKK][0][20] = 12, + [1][1][2][0][RTW89_IC][1][20] = 10, + [1][1][2][0][RTW89_KCC][1][20] = 28, + [1][1][2][0][RTW89_KCC][0][20] = 12, + [1][1][2][0][RTW89_ACMA][1][20] = 54, + [1][1][2][0][RTW89_ACMA][0][20] = 16, + [1][1][2][0][RTW89_CHILE][1][20] = 10, + [1][1][2][0][RTW89_QATAR][1][20] = 54, + [1][1][2][0][RTW89_QATAR][0][20] = 16, + [1][1][2][0][RTW89_UK][1][20] = 54, + [1][1][2][0][RTW89_UK][0][20] = 16, + [1][1][2][0][RTW89_FCC][1][24] = 10, + [1][1][2][0][RTW89_FCC][2][24] = 70, + [1][1][2][0][RTW89_ETSI][1][24] = 54, + [1][1][2][0][RTW89_ETSI][0][24] = 16, + [1][1][2][0][RTW89_MKK][1][24] = 54, + [1][1][2][0][RTW89_MKK][0][24] = 14, + [1][1][2][0][RTW89_IC][1][24] = 10, + [1][1][2][0][RTW89_KCC][1][24] = 28, + [1][1][2][0][RTW89_KCC][0][24] = 12, + [1][1][2][0][RTW89_ACMA][1][24] = 54, + [1][1][2][0][RTW89_ACMA][0][24] = 16, + [1][1][2][0][RTW89_CHILE][1][24] = 10, + [1][1][2][0][RTW89_QATAR][1][24] = 54, + [1][1][2][0][RTW89_QATAR][0][24] = 16, + [1][1][2][0][RTW89_UK][1][24] = 54, + [1][1][2][0][RTW89_UK][0][24] = 16, + [1][1][2][0][RTW89_FCC][1][28] = 10, + [1][1][2][0][RTW89_FCC][2][28] = 70, + [1][1][2][0][RTW89_ETSI][1][28] = 54, + [1][1][2][0][RTW89_ETSI][0][28] = 16, + [1][1][2][0][RTW89_MKK][1][28] = 52, + [1][1][2][0][RTW89_MKK][0][28] = 14, + [1][1][2][0][RTW89_IC][1][28] = 10, + [1][1][2][0][RTW89_KCC][1][28] = 28, + [1][1][2][0][RTW89_KCC][0][28] = 14, + [1][1][2][0][RTW89_ACMA][1][28] = 54, + [1][1][2][0][RTW89_ACMA][0][28] = 16, + [1][1][2][0][RTW89_CHILE][1][28] = 10, + [1][1][2][0][RTW89_QATAR][1][28] = 54, + [1][1][2][0][RTW89_QATAR][0][28] = 16, + [1][1][2][0][RTW89_UK][1][28] = 54, + [1][1][2][0][RTW89_UK][0][28] = 16, + [1][1][2][0][RTW89_FCC][1][31] = 10, + [1][1][2][0][RTW89_FCC][2][31] = 70, + [1][1][2][0][RTW89_ETSI][1][31] = 54, + [1][1][2][0][RTW89_ETSI][0][31] = 16, + [1][1][2][0][RTW89_MKK][1][31] = 52, + [1][1][2][0][RTW89_MKK][0][31] = 14, + [1][1][2][0][RTW89_IC][1][31] = 10, + [1][1][2][0][RTW89_KCC][1][31] = 28, + [1][1][2][0][RTW89_KCC][0][31] = 14, + [1][1][2][0][RTW89_ACMA][1][31] = 54, + [1][1][2][0][RTW89_ACMA][0][31] = 16, + [1][1][2][0][RTW89_CHILE][1][31] = 10, + [1][1][2][0][RTW89_QATAR][1][31] = 54, + [1][1][2][0][RTW89_QATAR][0][31] = 16, + [1][1][2][0][RTW89_UK][1][31] = 54, + [1][1][2][0][RTW89_UK][0][31] = 16, + [1][1][2][0][RTW89_FCC][1][35] = 10, + [1][1][2][0][RTW89_FCC][2][35] = 70, + [1][1][2][0][RTW89_ETSI][1][35] = 54, + [1][1][2][0][RTW89_ETSI][0][35] = 16, + [1][1][2][0][RTW89_MKK][1][35] = 52, + [1][1][2][0][RTW89_MKK][0][35] = 14, + [1][1][2][0][RTW89_IC][1][35] = 10, + [1][1][2][0][RTW89_KCC][1][35] = 28, + [1][1][2][0][RTW89_KCC][0][35] = 14, + [1][1][2][0][RTW89_ACMA][1][35] = 54, + [1][1][2][0][RTW89_ACMA][0][35] = 16, + [1][1][2][0][RTW89_CHILE][1][35] = 10, + [1][1][2][0][RTW89_QATAR][1][35] = 54, + [1][1][2][0][RTW89_QATAR][0][35] = 16, + [1][1][2][0][RTW89_UK][1][35] = 54, + [1][1][2][0][RTW89_UK][0][35] = 16, + [1][1][2][0][RTW89_FCC][1][39] = 10, + [1][1][2][0][RTW89_FCC][2][39] = 70, + [1][1][2][0][RTW89_ETSI][1][39] = 54, + [1][1][2][0][RTW89_ETSI][0][39] = 16, + [1][1][2][0][RTW89_MKK][1][39] = 52, + [1][1][2][0][RTW89_MKK][0][39] = 14, + [1][1][2][0][RTW89_IC][1][39] = 10, + [1][1][2][0][RTW89_KCC][1][39] = 28, + [1][1][2][0][RTW89_KCC][0][39] = 14, + [1][1][2][0][RTW89_ACMA][1][39] = 54, + [1][1][2][0][RTW89_ACMA][0][39] = 16, + [1][1][2][0][RTW89_CHILE][1][39] = 10, + [1][1][2][0][RTW89_QATAR][1][39] = 54, + [1][1][2][0][RTW89_QATAR][0][39] = 16, + [1][1][2][0][RTW89_UK][1][39] = 54, + [1][1][2][0][RTW89_UK][0][39] = 16, + [1][1][2][0][RTW89_FCC][1][43] = 10, + [1][1][2][0][RTW89_FCC][2][43] = 70, + [1][1][2][0][RTW89_ETSI][1][43] = 54, + [1][1][2][0][RTW89_ETSI][0][43] = 16, + [1][1][2][0][RTW89_MKK][1][43] = 52, + [1][1][2][0][RTW89_MKK][0][43] = 14, + [1][1][2][0][RTW89_IC][1][43] = 10, + [1][1][2][0][RTW89_KCC][1][43] = 28, + [1][1][2][0][RTW89_KCC][0][43] = 14, + [1][1][2][0][RTW89_ACMA][1][43] = 54, + [1][1][2][0][RTW89_ACMA][0][43] = 16, + [1][1][2][0][RTW89_CHILE][1][43] = 10, + [1][1][2][0][RTW89_QATAR][1][43] = 54, + [1][1][2][0][RTW89_QATAR][0][43] = 16, + [1][1][2][0][RTW89_UK][1][43] = 54, + [1][1][2][0][RTW89_UK][0][43] = 16, + [1][1][2][0][RTW89_FCC][1][46] = 12, + [1][1][2][0][RTW89_FCC][2][46] = 127, + [1][1][2][0][RTW89_ETSI][1][46] = 127, + [1][1][2][0][RTW89_ETSI][0][46] = 127, + [1][1][2][0][RTW89_MKK][1][46] = 127, + [1][1][2][0][RTW89_MKK][0][46] = 127, + [1][1][2][0][RTW89_IC][1][46] = 12, + [1][1][2][0][RTW89_KCC][1][46] = 28, + [1][1][2][0][RTW89_KCC][0][46] = 127, + [1][1][2][0][RTW89_ACMA][1][46] = 127, + [1][1][2][0][RTW89_ACMA][0][46] = 127, + [1][1][2][0][RTW89_CHILE][1][46] = 12, + [1][1][2][0][RTW89_QATAR][1][46] = 127, + [1][1][2][0][RTW89_QATAR][0][46] = 127, + [1][1][2][0][RTW89_UK][1][46] = 127, + [1][1][2][0][RTW89_UK][0][46] = 127, + [1][1][2][0][RTW89_FCC][1][50] = 12, + [1][1][2][0][RTW89_FCC][2][50] = 127, + [1][1][2][0][RTW89_ETSI][1][50] = 127, + [1][1][2][0][RTW89_ETSI][0][50] = 127, + [1][1][2][0][RTW89_MKK][1][50] = 127, + [1][1][2][0][RTW89_MKK][0][50] = 127, + [1][1][2][0][RTW89_IC][1][50] = 12, + [1][1][2][0][RTW89_KCC][1][50] = 28, + [1][1][2][0][RTW89_KCC][0][50] = 127, + [1][1][2][0][RTW89_ACMA][1][50] = 127, + [1][1][2][0][RTW89_ACMA][0][50] = 127, + [1][1][2][0][RTW89_CHILE][1][50] = 12, + [1][1][2][0][RTW89_QATAR][1][50] = 127, + [1][1][2][0][RTW89_QATAR][0][50] = 127, + [1][1][2][0][RTW89_UK][1][50] = 127, + [1][1][2][0][RTW89_UK][0][50] = 127, + [1][1][2][0][RTW89_FCC][1][54] = 10, + [1][1][2][0][RTW89_FCC][2][54] = 127, + [1][1][2][0][RTW89_ETSI][1][54] = 127, + [1][1][2][0][RTW89_ETSI][0][54] = 127, + [1][1][2][0][RTW89_MKK][1][54] = 127, + [1][1][2][0][RTW89_MKK][0][54] = 127, + [1][1][2][0][RTW89_IC][1][54] = 10, + [1][1][2][0][RTW89_KCC][1][54] = 28, + [1][1][2][0][RTW89_KCC][0][54] = 127, + [1][1][2][0][RTW89_ACMA][1][54] = 127, + [1][1][2][0][RTW89_ACMA][0][54] = 127, + [1][1][2][0][RTW89_CHILE][1][54] = 10, + [1][1][2][0][RTW89_QATAR][1][54] = 127, + [1][1][2][0][RTW89_QATAR][0][54] = 127, + [1][1][2][0][RTW89_UK][1][54] = 127, + [1][1][2][0][RTW89_UK][0][54] = 127, + [1][1][2][0][RTW89_FCC][1][58] = 10, + [1][1][2][0][RTW89_FCC][2][58] = 66, + [1][1][2][0][RTW89_ETSI][1][58] = 127, + [1][1][2][0][RTW89_ETSI][0][58] = 127, + [1][1][2][0][RTW89_MKK][1][58] = 127, + [1][1][2][0][RTW89_MKK][0][58] = 127, + [1][1][2][0][RTW89_IC][1][58] = 10, + [1][1][2][0][RTW89_KCC][1][58] = 28, + [1][1][2][0][RTW89_KCC][0][58] = 127, + [1][1][2][0][RTW89_ACMA][1][58] = 127, + [1][1][2][0][RTW89_ACMA][0][58] = 127, + [1][1][2][0][RTW89_CHILE][1][58] = 10, + [1][1][2][0][RTW89_QATAR][1][58] = 127, + [1][1][2][0][RTW89_QATAR][0][58] = 127, + [1][1][2][0][RTW89_UK][1][58] = 127, + [1][1][2][0][RTW89_UK][0][58] = 127, + [1][1][2][0][RTW89_FCC][1][61] = 10, + [1][1][2][0][RTW89_FCC][2][61] = 66, + [1][1][2][0][RTW89_ETSI][1][61] = 127, + [1][1][2][0][RTW89_ETSI][0][61] = 127, + [1][1][2][0][RTW89_MKK][1][61] = 127, + [1][1][2][0][RTW89_MKK][0][61] = 127, + [1][1][2][0][RTW89_IC][1][61] = 10, + [1][1][2][0][RTW89_KCC][1][61] = 28, + [1][1][2][0][RTW89_KCC][0][61] = 127, + [1][1][2][0][RTW89_ACMA][1][61] = 127, + [1][1][2][0][RTW89_ACMA][0][61] = 127, + [1][1][2][0][RTW89_CHILE][1][61] = 10, + [1][1][2][0][RTW89_QATAR][1][61] = 127, + [1][1][2][0][RTW89_QATAR][0][61] = 127, + [1][1][2][0][RTW89_UK][1][61] = 127, + [1][1][2][0][RTW89_UK][0][61] = 127, + [1][1][2][0][RTW89_FCC][1][65] = 10, + [1][1][2][0][RTW89_FCC][2][65] = 66, + [1][1][2][0][RTW89_ETSI][1][65] = 127, + [1][1][2][0][RTW89_ETSI][0][65] = 127, + [1][1][2][0][RTW89_MKK][1][65] = 127, + [1][1][2][0][RTW89_MKK][0][65] = 127, + [1][1][2][0][RTW89_IC][1][65] = 10, + [1][1][2][0][RTW89_KCC][1][65] = 28, + [1][1][2][0][RTW89_KCC][0][65] = 127, + [1][1][2][0][RTW89_ACMA][1][65] = 127, + [1][1][2][0][RTW89_ACMA][0][65] = 127, + [1][1][2][0][RTW89_CHILE][1][65] = 10, + [1][1][2][0][RTW89_QATAR][1][65] = 127, + [1][1][2][0][RTW89_QATAR][0][65] = 127, + [1][1][2][0][RTW89_UK][1][65] = 127, + [1][1][2][0][RTW89_UK][0][65] = 127, + [1][1][2][0][RTW89_FCC][1][69] = 10, + [1][1][2][0][RTW89_FCC][2][69] = 66, + [1][1][2][0][RTW89_ETSI][1][69] = 127, + [1][1][2][0][RTW89_ETSI][0][69] = 127, + [1][1][2][0][RTW89_MKK][1][69] = 127, + [1][1][2][0][RTW89_MKK][0][69] = 127, + [1][1][2][0][RTW89_IC][1][69] = 10, + [1][1][2][0][RTW89_KCC][1][69] = 28, + [1][1][2][0][RTW89_KCC][0][69] = 127, + [1][1][2][0][RTW89_ACMA][1][69] = 127, + [1][1][2][0][RTW89_ACMA][0][69] = 127, + [1][1][2][0][RTW89_CHILE][1][69] = 10, + [1][1][2][0][RTW89_QATAR][1][69] = 127, + [1][1][2][0][RTW89_QATAR][0][69] = 127, + [1][1][2][0][RTW89_UK][1][69] = 127, + [1][1][2][0][RTW89_UK][0][69] = 127, + [1][1][2][0][RTW89_FCC][1][73] = 10, + [1][1][2][0][RTW89_FCC][2][73] = 66, + [1][1][2][0][RTW89_ETSI][1][73] = 127, + [1][1][2][0][RTW89_ETSI][0][73] = 127, + [1][1][2][0][RTW89_MKK][1][73] = 127, + [1][1][2][0][RTW89_MKK][0][73] = 127, + [1][1][2][0][RTW89_IC][1][73] = 10, + [1][1][2][0][RTW89_KCC][1][73] = 28, + [1][1][2][0][RTW89_KCC][0][73] = 127, + [1][1][2][0][RTW89_ACMA][1][73] = 127, + [1][1][2][0][RTW89_ACMA][0][73] = 127, + [1][1][2][0][RTW89_CHILE][1][73] = 10, + [1][1][2][0][RTW89_QATAR][1][73] = 127, + [1][1][2][0][RTW89_QATAR][0][73] = 127, + [1][1][2][0][RTW89_UK][1][73] = 127, + [1][1][2][0][RTW89_UK][0][73] = 127, + [1][1][2][0][RTW89_FCC][1][76] = 10, + [1][1][2][0][RTW89_FCC][2][76] = 66, + [1][1][2][0][RTW89_ETSI][1][76] = 127, + [1][1][2][0][RTW89_ETSI][0][76] = 127, + [1][1][2][0][RTW89_MKK][1][76] = 127, + [1][1][2][0][RTW89_MKK][0][76] = 127, + [1][1][2][0][RTW89_IC][1][76] = 10, + [1][1][2][0][RTW89_KCC][1][76] = 28, + [1][1][2][0][RTW89_KCC][0][76] = 127, + [1][1][2][0][RTW89_ACMA][1][76] = 127, + [1][1][2][0][RTW89_ACMA][0][76] = 127, + [1][1][2][0][RTW89_CHILE][1][76] = 10, + [1][1][2][0][RTW89_QATAR][1][76] = 127, + [1][1][2][0][RTW89_QATAR][0][76] = 127, + [1][1][2][0][RTW89_UK][1][76] = 127, + [1][1][2][0][RTW89_UK][0][76] = 127, + [1][1][2][0][RTW89_FCC][1][80] = 10, + [1][1][2][0][RTW89_FCC][2][80] = 66, + [1][1][2][0][RTW89_ETSI][1][80] = 127, + [1][1][2][0][RTW89_ETSI][0][80] = 127, + [1][1][2][0][RTW89_MKK][1][80] = 127, + [1][1][2][0][RTW89_MKK][0][80] = 127, + [1][1][2][0][RTW89_IC][1][80] = 10, + [1][1][2][0][RTW89_KCC][1][80] = 32, + [1][1][2][0][RTW89_KCC][0][80] = 127, + [1][1][2][0][RTW89_ACMA][1][80] = 127, + [1][1][2][0][RTW89_ACMA][0][80] = 127, + [1][1][2][0][RTW89_CHILE][1][80] = 10, + [1][1][2][0][RTW89_QATAR][1][80] = 127, + [1][1][2][0][RTW89_QATAR][0][80] = 127, + [1][1][2][0][RTW89_UK][1][80] = 127, + [1][1][2][0][RTW89_UK][0][80] = 127, + [1][1][2][0][RTW89_FCC][1][84] = 10, + [1][1][2][0][RTW89_FCC][2][84] = 66, + [1][1][2][0][RTW89_ETSI][1][84] = 127, + [1][1][2][0][RTW89_ETSI][0][84] = 127, + [1][1][2][0][RTW89_MKK][1][84] = 127, + [1][1][2][0][RTW89_MKK][0][84] = 127, + [1][1][2][0][RTW89_IC][1][84] = 10, + [1][1][2][0][RTW89_KCC][1][84] = 32, + [1][1][2][0][RTW89_KCC][0][84] = 127, + [1][1][2][0][RTW89_ACMA][1][84] = 127, + [1][1][2][0][RTW89_ACMA][0][84] = 127, + [1][1][2][0][RTW89_CHILE][1][84] = 10, + [1][1][2][0][RTW89_QATAR][1][84] = 127, + [1][1][2][0][RTW89_QATAR][0][84] = 127, + [1][1][2][0][RTW89_UK][1][84] = 127, + [1][1][2][0][RTW89_UK][0][84] = 127, + [1][1][2][0][RTW89_FCC][1][88] = 10, + [1][1][2][0][RTW89_FCC][2][88] = 127, + [1][1][2][0][RTW89_ETSI][1][88] = 127, + [1][1][2][0][RTW89_ETSI][0][88] = 127, + [1][1][2][0][RTW89_MKK][1][88] = 127, + [1][1][2][0][RTW89_MKK][0][88] = 127, + [1][1][2][0][RTW89_IC][1][88] = 10, + [1][1][2][0][RTW89_KCC][1][88] = 32, + [1][1][2][0][RTW89_KCC][0][88] = 127, + [1][1][2][0][RTW89_ACMA][1][88] = 127, + [1][1][2][0][RTW89_ACMA][0][88] = 127, + [1][1][2][0][RTW89_CHILE][1][88] = 10, + [1][1][2][0][RTW89_QATAR][1][88] = 127, + [1][1][2][0][RTW89_QATAR][0][88] = 127, + [1][1][2][0][RTW89_UK][1][88] = 127, + [1][1][2][0][RTW89_UK][0][88] = 127, + [1][1][2][0][RTW89_FCC][1][91] = 12, + [1][1][2][0][RTW89_FCC][2][91] = 127, + [1][1][2][0][RTW89_ETSI][1][91] = 127, + [1][1][2][0][RTW89_ETSI][0][91] = 127, + [1][1][2][0][RTW89_MKK][1][91] = 127, + [1][1][2][0][RTW89_MKK][0][91] = 127, + [1][1][2][0][RTW89_IC][1][91] = 12, + [1][1][2][0][RTW89_KCC][1][91] = 32, + [1][1][2][0][RTW89_KCC][0][91] = 127, + [1][1][2][0][RTW89_ACMA][1][91] = 127, + [1][1][2][0][RTW89_ACMA][0][91] = 127, + [1][1][2][0][RTW89_CHILE][1][91] = 12, + [1][1][2][0][RTW89_QATAR][1][91] = 127, + [1][1][2][0][RTW89_QATAR][0][91] = 127, + [1][1][2][0][RTW89_UK][1][91] = 127, + [1][1][2][0][RTW89_UK][0][91] = 127, + [1][1][2][0][RTW89_FCC][1][95] = 10, + [1][1][2][0][RTW89_FCC][2][95] = 127, + [1][1][2][0][RTW89_ETSI][1][95] = 127, + [1][1][2][0][RTW89_ETSI][0][95] = 127, + [1][1][2][0][RTW89_MKK][1][95] = 127, + [1][1][2][0][RTW89_MKK][0][95] = 127, + [1][1][2][0][RTW89_IC][1][95] = 10, + [1][1][2][0][RTW89_KCC][1][95] = 32, + [1][1][2][0][RTW89_KCC][0][95] = 127, + [1][1][2][0][RTW89_ACMA][1][95] = 127, + [1][1][2][0][RTW89_ACMA][0][95] = 127, + [1][1][2][0][RTW89_CHILE][1][95] = 10, + [1][1][2][0][RTW89_QATAR][1][95] = 127, + [1][1][2][0][RTW89_QATAR][0][95] = 127, + [1][1][2][0][RTW89_UK][1][95] = 127, + [1][1][2][0][RTW89_UK][0][95] = 127, + [1][1][2][0][RTW89_FCC][1][99] = 10, + [1][1][2][0][RTW89_FCC][2][99] = 127, + [1][1][2][0][RTW89_ETSI][1][99] = 127, + [1][1][2][0][RTW89_ETSI][0][99] = 127, + [1][1][2][0][RTW89_MKK][1][99] = 127, + [1][1][2][0][RTW89_MKK][0][99] = 127, + [1][1][2][0][RTW89_IC][1][99] = 10, + [1][1][2][0][RTW89_KCC][1][99] = 32, + [1][1][2][0][RTW89_KCC][0][99] = 127, + [1][1][2][0][RTW89_ACMA][1][99] = 127, + [1][1][2][0][RTW89_ACMA][0][99] = 127, + [1][1][2][0][RTW89_CHILE][1][99] = 10, + [1][1][2][0][RTW89_QATAR][1][99] = 127, + [1][1][2][0][RTW89_QATAR][0][99] = 127, + [1][1][2][0][RTW89_UK][1][99] = 127, + [1][1][2][0][RTW89_UK][0][99] = 127, + [1][1][2][0][RTW89_FCC][1][103] = 10, + [1][1][2][0][RTW89_FCC][2][103] = 127, + [1][1][2][0][RTW89_ETSI][1][103] = 127, + [1][1][2][0][RTW89_ETSI][0][103] = 127, + [1][1][2][0][RTW89_MKK][1][103] = 127, + [1][1][2][0][RTW89_MKK][0][103] = 127, + [1][1][2][0][RTW89_IC][1][103] = 10, + [1][1][2][0][RTW89_KCC][1][103] = 32, + [1][1][2][0][RTW89_KCC][0][103] = 127, + [1][1][2][0][RTW89_ACMA][1][103] = 127, + [1][1][2][0][RTW89_ACMA][0][103] = 127, + [1][1][2][0][RTW89_CHILE][1][103] = 10, + [1][1][2][0][RTW89_QATAR][1][103] = 127, + [1][1][2][0][RTW89_QATAR][0][103] = 127, + [1][1][2][0][RTW89_UK][1][103] = 127, + [1][1][2][0][RTW89_UK][0][103] = 127, + [1][1][2][0][RTW89_FCC][1][106] = 12, + [1][1][2][0][RTW89_FCC][2][106] = 127, + [1][1][2][0][RTW89_ETSI][1][106] = 127, + [1][1][2][0][RTW89_ETSI][0][106] = 127, + [1][1][2][0][RTW89_MKK][1][106] = 127, + [1][1][2][0][RTW89_MKK][0][106] = 127, + [1][1][2][0][RTW89_IC][1][106] = 12, + [1][1][2][0][RTW89_KCC][1][106] = 32, + [1][1][2][0][RTW89_KCC][0][106] = 127, + [1][1][2][0][RTW89_ACMA][1][106] = 127, + [1][1][2][0][RTW89_ACMA][0][106] = 127, + [1][1][2][0][RTW89_CHILE][1][106] = 12, + [1][1][2][0][RTW89_QATAR][1][106] = 127, + [1][1][2][0][RTW89_QATAR][0][106] = 127, + [1][1][2][0][RTW89_UK][1][106] = 127, + [1][1][2][0][RTW89_UK][0][106] = 127, + [1][1][2][0][RTW89_FCC][1][110] = 127, + [1][1][2][0][RTW89_FCC][2][110] = 127, + [1][1][2][0][RTW89_ETSI][1][110] = 127, + [1][1][2][0][RTW89_ETSI][0][110] = 127, + [1][1][2][0][RTW89_MKK][1][110] = 127, + [1][1][2][0][RTW89_MKK][0][110] = 127, + [1][1][2][0][RTW89_IC][1][110] = 127, + [1][1][2][0][RTW89_KCC][1][110] = 127, + [1][1][2][0][RTW89_KCC][0][110] = 127, + [1][1][2][0][RTW89_ACMA][1][110] = 127, + [1][1][2][0][RTW89_ACMA][0][110] = 127, + [1][1][2][0][RTW89_CHILE][1][110] = 127, + [1][1][2][0][RTW89_QATAR][1][110] = 127, + [1][1][2][0][RTW89_QATAR][0][110] = 127, + [1][1][2][0][RTW89_UK][1][110] = 127, + [1][1][2][0][RTW89_UK][0][110] = 127, + [1][1][2][0][RTW89_FCC][1][114] = 127, + [1][1][2][0][RTW89_FCC][2][114] = 127, + [1][1][2][0][RTW89_ETSI][1][114] = 127, + [1][1][2][0][RTW89_ETSI][0][114] = 127, + [1][1][2][0][RTW89_MKK][1][114] = 127, + [1][1][2][0][RTW89_MKK][0][114] = 127, + [1][1][2][0][RTW89_IC][1][114] = 127, + [1][1][2][0][RTW89_KCC][1][114] = 127, + [1][1][2][0][RTW89_KCC][0][114] = 127, + [1][1][2][0][RTW89_ACMA][1][114] = 127, + [1][1][2][0][RTW89_ACMA][0][114] = 127, + [1][1][2][0][RTW89_CHILE][1][114] = 127, + [1][1][2][0][RTW89_QATAR][1][114] = 127, + [1][1][2][0][RTW89_QATAR][0][114] = 127, + [1][1][2][0][RTW89_UK][1][114] = 127, + [1][1][2][0][RTW89_UK][0][114] = 127, + [1][1][2][0][RTW89_FCC][1][118] = 127, + [1][1][2][0][RTW89_FCC][2][118] = 127, + [1][1][2][0][RTW89_ETSI][1][118] = 127, + [1][1][2][0][RTW89_ETSI][0][118] = 127, + [1][1][2][0][RTW89_MKK][1][118] = 127, + [1][1][2][0][RTW89_MKK][0][118] = 127, + [1][1][2][0][RTW89_IC][1][118] = 127, + [1][1][2][0][RTW89_KCC][1][118] = 127, + [1][1][2][0][RTW89_KCC][0][118] = 127, + [1][1][2][0][RTW89_ACMA][1][118] = 127, + [1][1][2][0][RTW89_ACMA][0][118] = 127, + [1][1][2][0][RTW89_CHILE][1][118] = 127, + [1][1][2][0][RTW89_QATAR][1][118] = 127, + [1][1][2][0][RTW89_QATAR][0][118] = 127, + [1][1][2][0][RTW89_UK][1][118] = 127, + [1][1][2][0][RTW89_UK][0][118] = 127, + [1][1][2][1][RTW89_FCC][1][1] = 10, + [1][1][2][1][RTW89_FCC][2][1] = 58, + [1][1][2][1][RTW89_ETSI][1][1] = 42, + [1][1][2][1][RTW89_ETSI][0][1] = 6, + [1][1][2][1][RTW89_MKK][1][1] = 52, + [1][1][2][1][RTW89_MKK][0][1] = 12, + [1][1][2][1][RTW89_IC][1][1] = 10, + [1][1][2][1][RTW89_KCC][1][1] = 28, + [1][1][2][1][RTW89_KCC][0][1] = 12, + [1][1][2][1][RTW89_ACMA][1][1] = 42, + [1][1][2][1][RTW89_ACMA][0][1] = 6, + [1][1][2][1][RTW89_CHILE][1][1] = 10, + [1][1][2][1][RTW89_QATAR][1][1] = 42, + [1][1][2][1][RTW89_QATAR][0][1] = 6, + [1][1][2][1][RTW89_UK][1][1] = 42, + [1][1][2][1][RTW89_UK][0][1] = 6, + [1][1][2][1][RTW89_FCC][1][5] = 10, + [1][1][2][1][RTW89_FCC][2][5] = 58, + [1][1][2][1][RTW89_ETSI][1][5] = 42, + [1][1][2][1][RTW89_ETSI][0][5] = 6, + [1][1][2][1][RTW89_MKK][1][5] = 52, + [1][1][2][1][RTW89_MKK][0][5] = 12, + [1][1][2][1][RTW89_IC][1][5] = 10, + [1][1][2][1][RTW89_KCC][1][5] = 28, + [1][1][2][1][RTW89_KCC][0][5] = 12, + [1][1][2][1][RTW89_ACMA][1][5] = 42, + [1][1][2][1][RTW89_ACMA][0][5] = 6, + [1][1][2][1][RTW89_CHILE][1][5] = 10, + [1][1][2][1][RTW89_QATAR][1][5] = 42, + [1][1][2][1][RTW89_QATAR][0][5] = 6, + [1][1][2][1][RTW89_UK][1][5] = 42, + [1][1][2][1][RTW89_UK][0][5] = 6, + [1][1][2][1][RTW89_FCC][1][9] = 10, + [1][1][2][1][RTW89_FCC][2][9] = 58, + [1][1][2][1][RTW89_ETSI][1][9] = 42, + [1][1][2][1][RTW89_ETSI][0][9] = 6, + [1][1][2][1][RTW89_MKK][1][9] = 52, + [1][1][2][1][RTW89_MKK][0][9] = 12, + [1][1][2][1][RTW89_IC][1][9] = 10, + [1][1][2][1][RTW89_KCC][1][9] = 28, + [1][1][2][1][RTW89_KCC][0][9] = 12, + [1][1][2][1][RTW89_ACMA][1][9] = 42, + [1][1][2][1][RTW89_ACMA][0][9] = 6, + [1][1][2][1][RTW89_CHILE][1][9] = 10, + [1][1][2][1][RTW89_QATAR][1][9] = 42, + [1][1][2][1][RTW89_QATAR][0][9] = 6, + [1][1][2][1][RTW89_UK][1][9] = 42, + [1][1][2][1][RTW89_UK][0][9] = 6, + [1][1][2][1][RTW89_FCC][1][13] = 10, + [1][1][2][1][RTW89_FCC][2][13] = 58, + [1][1][2][1][RTW89_ETSI][1][13] = 42, + [1][1][2][1][RTW89_ETSI][0][13] = 6, + [1][1][2][1][RTW89_MKK][1][13] = 52, + [1][1][2][1][RTW89_MKK][0][13] = 12, + [1][1][2][1][RTW89_IC][1][13] = 10, + [1][1][2][1][RTW89_KCC][1][13] = 28, + [1][1][2][1][RTW89_KCC][0][13] = 12, + [1][1][2][1][RTW89_ACMA][1][13] = 42, + [1][1][2][1][RTW89_ACMA][0][13] = 6, + [1][1][2][1][RTW89_CHILE][1][13] = 10, + [1][1][2][1][RTW89_QATAR][1][13] = 42, + [1][1][2][1][RTW89_QATAR][0][13] = 6, + [1][1][2][1][RTW89_UK][1][13] = 42, + [1][1][2][1][RTW89_UK][0][13] = 6, + [1][1][2][1][RTW89_FCC][1][16] = 10, + [1][1][2][1][RTW89_FCC][2][16] = 58, + [1][1][2][1][RTW89_ETSI][1][16] = 42, + [1][1][2][1][RTW89_ETSI][0][16] = 6, + [1][1][2][1][RTW89_MKK][1][16] = 52, + [1][1][2][1][RTW89_MKK][0][16] = 12, + [1][1][2][1][RTW89_IC][1][16] = 10, + [1][1][2][1][RTW89_KCC][1][16] = 28, + [1][1][2][1][RTW89_KCC][0][16] = 12, + [1][1][2][1][RTW89_ACMA][1][16] = 42, + [1][1][2][1][RTW89_ACMA][0][16] = 6, + [1][1][2][1][RTW89_CHILE][1][16] = 10, + [1][1][2][1][RTW89_QATAR][1][16] = 42, + [1][1][2][1][RTW89_QATAR][0][16] = 6, + [1][1][2][1][RTW89_UK][1][16] = 42, + [1][1][2][1][RTW89_UK][0][16] = 6, + [1][1][2][1][RTW89_FCC][1][20] = 10, + [1][1][2][1][RTW89_FCC][2][20] = 58, + [1][1][2][1][RTW89_ETSI][1][20] = 42, + [1][1][2][1][RTW89_ETSI][0][20] = 6, + [1][1][2][1][RTW89_MKK][1][20] = 52, + [1][1][2][1][RTW89_MKK][0][20] = 12, + [1][1][2][1][RTW89_IC][1][20] = 10, + [1][1][2][1][RTW89_KCC][1][20] = 28, + [1][1][2][1][RTW89_KCC][0][20] = 12, + [1][1][2][1][RTW89_ACMA][1][20] = 42, + [1][1][2][1][RTW89_ACMA][0][20] = 6, + [1][1][2][1][RTW89_CHILE][1][20] = 10, + [1][1][2][1][RTW89_QATAR][1][20] = 42, + [1][1][2][1][RTW89_QATAR][0][20] = 6, + [1][1][2][1][RTW89_UK][1][20] = 42, + [1][1][2][1][RTW89_UK][0][20] = 6, + [1][1][2][1][RTW89_FCC][1][24] = 10, + [1][1][2][1][RTW89_FCC][2][24] = 70, + [1][1][2][1][RTW89_ETSI][1][24] = 42, + [1][1][2][1][RTW89_ETSI][0][24] = 6, + [1][1][2][1][RTW89_MKK][1][24] = 54, + [1][1][2][1][RTW89_MKK][0][24] = 14, + [1][1][2][1][RTW89_IC][1][24] = 10, + [1][1][2][1][RTW89_KCC][1][24] = 28, + [1][1][2][1][RTW89_KCC][0][24] = 12, + [1][1][2][1][RTW89_ACMA][1][24] = 42, + [1][1][2][1][RTW89_ACMA][0][24] = 6, + [1][1][2][1][RTW89_CHILE][1][24] = 10, + [1][1][2][1][RTW89_QATAR][1][24] = 42, + [1][1][2][1][RTW89_QATAR][0][24] = 6, + [1][1][2][1][RTW89_UK][1][24] = 42, + [1][1][2][1][RTW89_UK][0][24] = 6, + [1][1][2][1][RTW89_FCC][1][28] = 10, + [1][1][2][1][RTW89_FCC][2][28] = 70, + [1][1][2][1][RTW89_ETSI][1][28] = 42, + [1][1][2][1][RTW89_ETSI][0][28] = 6, + [1][1][2][1][RTW89_MKK][1][28] = 52, + [1][1][2][1][RTW89_MKK][0][28] = 14, + [1][1][2][1][RTW89_IC][1][28] = 10, + [1][1][2][1][RTW89_KCC][1][28] = 28, + [1][1][2][1][RTW89_KCC][0][28] = 14, + [1][1][2][1][RTW89_ACMA][1][28] = 42, + [1][1][2][1][RTW89_ACMA][0][28] = 6, + [1][1][2][1][RTW89_CHILE][1][28] = 10, + [1][1][2][1][RTW89_QATAR][1][28] = 42, + [1][1][2][1][RTW89_QATAR][0][28] = 6, + [1][1][2][1][RTW89_UK][1][28] = 42, + [1][1][2][1][RTW89_UK][0][28] = 6, + [1][1][2][1][RTW89_FCC][1][31] = 10, + [1][1][2][1][RTW89_FCC][2][31] = 70, + [1][1][2][1][RTW89_ETSI][1][31] = 42, + [1][1][2][1][RTW89_ETSI][0][31] = 6, + [1][1][2][1][RTW89_MKK][1][31] = 52, + [1][1][2][1][RTW89_MKK][0][31] = 14, + [1][1][2][1][RTW89_IC][1][31] = 10, + [1][1][2][1][RTW89_KCC][1][31] = 28, + [1][1][2][1][RTW89_KCC][0][31] = 14, + [1][1][2][1][RTW89_ACMA][1][31] = 42, + [1][1][2][1][RTW89_ACMA][0][31] = 6, + [1][1][2][1][RTW89_CHILE][1][31] = 10, + [1][1][2][1][RTW89_QATAR][1][31] = 42, + [1][1][2][1][RTW89_QATAR][0][31] = 6, + [1][1][2][1][RTW89_UK][1][31] = 42, + [1][1][2][1][RTW89_UK][0][31] = 6, + [1][1][2][1][RTW89_FCC][1][35] = 10, + [1][1][2][1][RTW89_FCC][2][35] = 70, + [1][1][2][1][RTW89_ETSI][1][35] = 42, + [1][1][2][1][RTW89_ETSI][0][35] = 6, + [1][1][2][1][RTW89_MKK][1][35] = 52, + [1][1][2][1][RTW89_MKK][0][35] = 14, + [1][1][2][1][RTW89_IC][1][35] = 10, + [1][1][2][1][RTW89_KCC][1][35] = 28, + [1][1][2][1][RTW89_KCC][0][35] = 14, + [1][1][2][1][RTW89_ACMA][1][35] = 42, + [1][1][2][1][RTW89_ACMA][0][35] = 6, + [1][1][2][1][RTW89_CHILE][1][35] = 10, + [1][1][2][1][RTW89_QATAR][1][35] = 42, + [1][1][2][1][RTW89_QATAR][0][35] = 6, + [1][1][2][1][RTW89_UK][1][35] = 42, + [1][1][2][1][RTW89_UK][0][35] = 6, + [1][1][2][1][RTW89_FCC][1][39] = 10, + [1][1][2][1][RTW89_FCC][2][39] = 70, + [1][1][2][1][RTW89_ETSI][1][39] = 42, + [1][1][2][1][RTW89_ETSI][0][39] = 6, + [1][1][2][1][RTW89_MKK][1][39] = 52, + [1][1][2][1][RTW89_MKK][0][39] = 14, + [1][1][2][1][RTW89_IC][1][39] = 10, + [1][1][2][1][RTW89_KCC][1][39] = 28, + [1][1][2][1][RTW89_KCC][0][39] = 14, + [1][1][2][1][RTW89_ACMA][1][39] = 42, + [1][1][2][1][RTW89_ACMA][0][39] = 6, + [1][1][2][1][RTW89_CHILE][1][39] = 10, + [1][1][2][1][RTW89_QATAR][1][39] = 42, + [1][1][2][1][RTW89_QATAR][0][39] = 6, + [1][1][2][1][RTW89_UK][1][39] = 42, + [1][1][2][1][RTW89_UK][0][39] = 6, + [1][1][2][1][RTW89_FCC][1][43] = 10, + [1][1][2][1][RTW89_FCC][2][43] = 70, + [1][1][2][1][RTW89_ETSI][1][43] = 42, + [1][1][2][1][RTW89_ETSI][0][43] = 6, + [1][1][2][1][RTW89_MKK][1][43] = 52, + [1][1][2][1][RTW89_MKK][0][43] = 14, + [1][1][2][1][RTW89_IC][1][43] = 10, + [1][1][2][1][RTW89_KCC][1][43] = 28, + [1][1][2][1][RTW89_KCC][0][43] = 14, + [1][1][2][1][RTW89_ACMA][1][43] = 42, + [1][1][2][1][RTW89_ACMA][0][43] = 6, + [1][1][2][1][RTW89_CHILE][1][43] = 10, + [1][1][2][1][RTW89_QATAR][1][43] = 42, + [1][1][2][1][RTW89_QATAR][0][43] = 6, + [1][1][2][1][RTW89_UK][1][43] = 42, + [1][1][2][1][RTW89_UK][0][43] = 6, + [1][1][2][1][RTW89_FCC][1][46] = 12, + [1][1][2][1][RTW89_FCC][2][46] = 127, + [1][1][2][1][RTW89_ETSI][1][46] = 127, + [1][1][2][1][RTW89_ETSI][0][46] = 127, + [1][1][2][1][RTW89_MKK][1][46] = 127, + [1][1][2][1][RTW89_MKK][0][46] = 127, + [1][1][2][1][RTW89_IC][1][46] = 12, + [1][1][2][1][RTW89_KCC][1][46] = 28, + [1][1][2][1][RTW89_KCC][0][46] = 127, + [1][1][2][1][RTW89_ACMA][1][46] = 127, + [1][1][2][1][RTW89_ACMA][0][46] = 127, + [1][1][2][1][RTW89_CHILE][1][46] = 12, + [1][1][2][1][RTW89_QATAR][1][46] = 127, + [1][1][2][1][RTW89_QATAR][0][46] = 127, + [1][1][2][1][RTW89_UK][1][46] = 127, + [1][1][2][1][RTW89_UK][0][46] = 127, + [1][1][2][1][RTW89_FCC][1][50] = 12, + [1][1][2][1][RTW89_FCC][2][50] = 127, + [1][1][2][1][RTW89_ETSI][1][50] = 127, + [1][1][2][1][RTW89_ETSI][0][50] = 127, + [1][1][2][1][RTW89_MKK][1][50] = 127, + [1][1][2][1][RTW89_MKK][0][50] = 127, + [1][1][2][1][RTW89_IC][1][50] = 12, + [1][1][2][1][RTW89_KCC][1][50] = 28, + [1][1][2][1][RTW89_KCC][0][50] = 127, + [1][1][2][1][RTW89_ACMA][1][50] = 127, + [1][1][2][1][RTW89_ACMA][0][50] = 127, + [1][1][2][1][RTW89_CHILE][1][50] = 12, + [1][1][2][1][RTW89_QATAR][1][50] = 127, + [1][1][2][1][RTW89_QATAR][0][50] = 127, + [1][1][2][1][RTW89_UK][1][50] = 127, + [1][1][2][1][RTW89_UK][0][50] = 127, + [1][1][2][1][RTW89_FCC][1][54] = 10, + [1][1][2][1][RTW89_FCC][2][54] = 127, + [1][1][2][1][RTW89_ETSI][1][54] = 127, + [1][1][2][1][RTW89_ETSI][0][54] = 127, + [1][1][2][1][RTW89_MKK][1][54] = 127, + [1][1][2][1][RTW89_MKK][0][54] = 127, + [1][1][2][1][RTW89_IC][1][54] = 10, + [1][1][2][1][RTW89_KCC][1][54] = 28, + [1][1][2][1][RTW89_KCC][0][54] = 127, + [1][1][2][1][RTW89_ACMA][1][54] = 127, + [1][1][2][1][RTW89_ACMA][0][54] = 127, + [1][1][2][1][RTW89_CHILE][1][54] = 10, + [1][1][2][1][RTW89_QATAR][1][54] = 127, + [1][1][2][1][RTW89_QATAR][0][54] = 127, + [1][1][2][1][RTW89_UK][1][54] = 127, + [1][1][2][1][RTW89_UK][0][54] = 127, + [1][1][2][1][RTW89_FCC][1][58] = 10, + [1][1][2][1][RTW89_FCC][2][58] = 66, + [1][1][2][1][RTW89_ETSI][1][58] = 127, + [1][1][2][1][RTW89_ETSI][0][58] = 127, + [1][1][2][1][RTW89_MKK][1][58] = 127, + [1][1][2][1][RTW89_MKK][0][58] = 127, + [1][1][2][1][RTW89_IC][1][58] = 10, + [1][1][2][1][RTW89_KCC][1][58] = 28, + [1][1][2][1][RTW89_KCC][0][58] = 127, + [1][1][2][1][RTW89_ACMA][1][58] = 127, + [1][1][2][1][RTW89_ACMA][0][58] = 127, + [1][1][2][1][RTW89_CHILE][1][58] = 10, + [1][1][2][1][RTW89_QATAR][1][58] = 127, + [1][1][2][1][RTW89_QATAR][0][58] = 127, + [1][1][2][1][RTW89_UK][1][58] = 127, + [1][1][2][1][RTW89_UK][0][58] = 127, + [1][1][2][1][RTW89_FCC][1][61] = 10, + [1][1][2][1][RTW89_FCC][2][61] = 66, + [1][1][2][1][RTW89_ETSI][1][61] = 127, + [1][1][2][1][RTW89_ETSI][0][61] = 127, + [1][1][2][1][RTW89_MKK][1][61] = 127, + [1][1][2][1][RTW89_MKK][0][61] = 127, + [1][1][2][1][RTW89_IC][1][61] = 10, + [1][1][2][1][RTW89_KCC][1][61] = 28, + [1][1][2][1][RTW89_KCC][0][61] = 127, + [1][1][2][1][RTW89_ACMA][1][61] = 127, + [1][1][2][1][RTW89_ACMA][0][61] = 127, + [1][1][2][1][RTW89_CHILE][1][61] = 10, + [1][1][2][1][RTW89_QATAR][1][61] = 127, + [1][1][2][1][RTW89_QATAR][0][61] = 127, + [1][1][2][1][RTW89_UK][1][61] = 127, + [1][1][2][1][RTW89_UK][0][61] = 127, + [1][1][2][1][RTW89_FCC][1][65] = 10, + [1][1][2][1][RTW89_FCC][2][65] = 66, + [1][1][2][1][RTW89_ETSI][1][65] = 127, + [1][1][2][1][RTW89_ETSI][0][65] = 127, + [1][1][2][1][RTW89_MKK][1][65] = 127, + [1][1][2][1][RTW89_MKK][0][65] = 127, + [1][1][2][1][RTW89_IC][1][65] = 10, + [1][1][2][1][RTW89_KCC][1][65] = 28, + [1][1][2][1][RTW89_KCC][0][65] = 127, + [1][1][2][1][RTW89_ACMA][1][65] = 127, + [1][1][2][1][RTW89_ACMA][0][65] = 127, + [1][1][2][1][RTW89_CHILE][1][65] = 10, + [1][1][2][1][RTW89_QATAR][1][65] = 127, + [1][1][2][1][RTW89_QATAR][0][65] = 127, + [1][1][2][1][RTW89_UK][1][65] = 127, + [1][1][2][1][RTW89_UK][0][65] = 127, + [1][1][2][1][RTW89_FCC][1][69] = 10, + [1][1][2][1][RTW89_FCC][2][69] = 66, + [1][1][2][1][RTW89_ETSI][1][69] = 127, + [1][1][2][1][RTW89_ETSI][0][69] = 127, + [1][1][2][1][RTW89_MKK][1][69] = 127, + [1][1][2][1][RTW89_MKK][0][69] = 127, + [1][1][2][1][RTW89_IC][1][69] = 10, + [1][1][2][1][RTW89_KCC][1][69] = 28, + [1][1][2][1][RTW89_KCC][0][69] = 127, + [1][1][2][1][RTW89_ACMA][1][69] = 127, + [1][1][2][1][RTW89_ACMA][0][69] = 127, + [1][1][2][1][RTW89_CHILE][1][69] = 10, + [1][1][2][1][RTW89_QATAR][1][69] = 127, + [1][1][2][1][RTW89_QATAR][0][69] = 127, + [1][1][2][1][RTW89_UK][1][69] = 127, + [1][1][2][1][RTW89_UK][0][69] = 127, + [1][1][2][1][RTW89_FCC][1][73] = 10, + [1][1][2][1][RTW89_FCC][2][73] = 66, + [1][1][2][1][RTW89_ETSI][1][73] = 127, + [1][1][2][1][RTW89_ETSI][0][73] = 127, + [1][1][2][1][RTW89_MKK][1][73] = 127, + [1][1][2][1][RTW89_MKK][0][73] = 127, + [1][1][2][1][RTW89_IC][1][73] = 10, + [1][1][2][1][RTW89_KCC][1][73] = 28, + [1][1][2][1][RTW89_KCC][0][73] = 127, + [1][1][2][1][RTW89_ACMA][1][73] = 127, + [1][1][2][1][RTW89_ACMA][0][73] = 127, + [1][1][2][1][RTW89_CHILE][1][73] = 10, + [1][1][2][1][RTW89_QATAR][1][73] = 127, + [1][1][2][1][RTW89_QATAR][0][73] = 127, + [1][1][2][1][RTW89_UK][1][73] = 127, + [1][1][2][1][RTW89_UK][0][73] = 127, + [1][1][2][1][RTW89_FCC][1][76] = 10, + [1][1][2][1][RTW89_FCC][2][76] = 66, + [1][1][2][1][RTW89_ETSI][1][76] = 127, + [1][1][2][1][RTW89_ETSI][0][76] = 127, + [1][1][2][1][RTW89_MKK][1][76] = 127, + [1][1][2][1][RTW89_MKK][0][76] = 127, + [1][1][2][1][RTW89_IC][1][76] = 10, + [1][1][2][1][RTW89_KCC][1][76] = 28, + [1][1][2][1][RTW89_KCC][0][76] = 127, + [1][1][2][1][RTW89_ACMA][1][76] = 127, + [1][1][2][1][RTW89_ACMA][0][76] = 127, + [1][1][2][1][RTW89_CHILE][1][76] = 10, + [1][1][2][1][RTW89_QATAR][1][76] = 127, + [1][1][2][1][RTW89_QATAR][0][76] = 127, + [1][1][2][1][RTW89_UK][1][76] = 127, + [1][1][2][1][RTW89_UK][0][76] = 127, + [1][1][2][1][RTW89_FCC][1][80] = 10, + [1][1][2][1][RTW89_FCC][2][80] = 66, + [1][1][2][1][RTW89_ETSI][1][80] = 127, + [1][1][2][1][RTW89_ETSI][0][80] = 127, + [1][1][2][1][RTW89_MKK][1][80] = 127, + [1][1][2][1][RTW89_MKK][0][80] = 127, + [1][1][2][1][RTW89_IC][1][80] = 10, + [1][1][2][1][RTW89_KCC][1][80] = 32, + [1][1][2][1][RTW89_KCC][0][80] = 127, + [1][1][2][1][RTW89_ACMA][1][80] = 127, + [1][1][2][1][RTW89_ACMA][0][80] = 127, + [1][1][2][1][RTW89_CHILE][1][80] = 10, + [1][1][2][1][RTW89_QATAR][1][80] = 127, + [1][1][2][1][RTW89_QATAR][0][80] = 127, + [1][1][2][1][RTW89_UK][1][80] = 127, + [1][1][2][1][RTW89_UK][0][80] = 127, + [1][1][2][1][RTW89_FCC][1][84] = 10, + [1][1][2][1][RTW89_FCC][2][84] = 66, + [1][1][2][1][RTW89_ETSI][1][84] = 127, + [1][1][2][1][RTW89_ETSI][0][84] = 127, + [1][1][2][1][RTW89_MKK][1][84] = 127, + [1][1][2][1][RTW89_MKK][0][84] = 127, + [1][1][2][1][RTW89_IC][1][84] = 10, + [1][1][2][1][RTW89_KCC][1][84] = 32, + [1][1][2][1][RTW89_KCC][0][84] = 127, + [1][1][2][1][RTW89_ACMA][1][84] = 127, + [1][1][2][1][RTW89_ACMA][0][84] = 127, + [1][1][2][1][RTW89_CHILE][1][84] = 10, + [1][1][2][1][RTW89_QATAR][1][84] = 127, + [1][1][2][1][RTW89_QATAR][0][84] = 127, + [1][1][2][1][RTW89_UK][1][84] = 127, + [1][1][2][1][RTW89_UK][0][84] = 127, + [1][1][2][1][RTW89_FCC][1][88] = 10, + [1][1][2][1][RTW89_FCC][2][88] = 127, + [1][1][2][1][RTW89_ETSI][1][88] = 127, + [1][1][2][1][RTW89_ETSI][0][88] = 127, + [1][1][2][1][RTW89_MKK][1][88] = 127, + [1][1][2][1][RTW89_MKK][0][88] = 127, + [1][1][2][1][RTW89_IC][1][88] = 10, + [1][1][2][1][RTW89_KCC][1][88] = 32, + [1][1][2][1][RTW89_KCC][0][88] = 127, + [1][1][2][1][RTW89_ACMA][1][88] = 127, + [1][1][2][1][RTW89_ACMA][0][88] = 127, + [1][1][2][1][RTW89_CHILE][1][88] = 10, + [1][1][2][1][RTW89_QATAR][1][88] = 127, + [1][1][2][1][RTW89_QATAR][0][88] = 127, + [1][1][2][1][RTW89_UK][1][88] = 127, + [1][1][2][1][RTW89_UK][0][88] = 127, + [1][1][2][1][RTW89_FCC][1][91] = 12, + [1][1][2][1][RTW89_FCC][2][91] = 127, + [1][1][2][1][RTW89_ETSI][1][91] = 127, + [1][1][2][1][RTW89_ETSI][0][91] = 127, + [1][1][2][1][RTW89_MKK][1][91] = 127, + [1][1][2][1][RTW89_MKK][0][91] = 127, + [1][1][2][1][RTW89_IC][1][91] = 12, + [1][1][2][1][RTW89_KCC][1][91] = 32, + [1][1][2][1][RTW89_KCC][0][91] = 127, + [1][1][2][1][RTW89_ACMA][1][91] = 127, + [1][1][2][1][RTW89_ACMA][0][91] = 127, + [1][1][2][1][RTW89_CHILE][1][91] = 12, + [1][1][2][1][RTW89_QATAR][1][91] = 127, + [1][1][2][1][RTW89_QATAR][0][91] = 127, + [1][1][2][1][RTW89_UK][1][91] = 127, + [1][1][2][1][RTW89_UK][0][91] = 127, + [1][1][2][1][RTW89_FCC][1][95] = 10, + [1][1][2][1][RTW89_FCC][2][95] = 127, + [1][1][2][1][RTW89_ETSI][1][95] = 127, + [1][1][2][1][RTW89_ETSI][0][95] = 127, + [1][1][2][1][RTW89_MKK][1][95] = 127, + [1][1][2][1][RTW89_MKK][0][95] = 127, + [1][1][2][1][RTW89_IC][1][95] = 10, + [1][1][2][1][RTW89_KCC][1][95] = 32, + [1][1][2][1][RTW89_KCC][0][95] = 127, + [1][1][2][1][RTW89_ACMA][1][95] = 127, + [1][1][2][1][RTW89_ACMA][0][95] = 127, + [1][1][2][1][RTW89_CHILE][1][95] = 10, + [1][1][2][1][RTW89_QATAR][1][95] = 127, + [1][1][2][1][RTW89_QATAR][0][95] = 127, + [1][1][2][1][RTW89_UK][1][95] = 127, + [1][1][2][1][RTW89_UK][0][95] = 127, + [1][1][2][1][RTW89_FCC][1][99] = 10, + [1][1][2][1][RTW89_FCC][2][99] = 127, + [1][1][2][1][RTW89_ETSI][1][99] = 127, + [1][1][2][1][RTW89_ETSI][0][99] = 127, + [1][1][2][1][RTW89_MKK][1][99] = 127, + [1][1][2][1][RTW89_MKK][0][99] = 127, + [1][1][2][1][RTW89_IC][1][99] = 10, + [1][1][2][1][RTW89_KCC][1][99] = 32, + [1][1][2][1][RTW89_KCC][0][99] = 127, + [1][1][2][1][RTW89_ACMA][1][99] = 127, + [1][1][2][1][RTW89_ACMA][0][99] = 127, + [1][1][2][1][RTW89_CHILE][1][99] = 10, + [1][1][2][1][RTW89_QATAR][1][99] = 127, + [1][1][2][1][RTW89_QATAR][0][99] = 127, + [1][1][2][1][RTW89_UK][1][99] = 127, + [1][1][2][1][RTW89_UK][0][99] = 127, + [1][1][2][1][RTW89_FCC][1][103] = 10, + [1][1][2][1][RTW89_FCC][2][103] = 127, + [1][1][2][1][RTW89_ETSI][1][103] = 127, + [1][1][2][1][RTW89_ETSI][0][103] = 127, + [1][1][2][1][RTW89_MKK][1][103] = 127, + [1][1][2][1][RTW89_MKK][0][103] = 127, + [1][1][2][1][RTW89_IC][1][103] = 10, + [1][1][2][1][RTW89_KCC][1][103] = 32, + [1][1][2][1][RTW89_KCC][0][103] = 127, + [1][1][2][1][RTW89_ACMA][1][103] = 127, + [1][1][2][1][RTW89_ACMA][0][103] = 127, + [1][1][2][1][RTW89_CHILE][1][103] = 10, + [1][1][2][1][RTW89_QATAR][1][103] = 127, + [1][1][2][1][RTW89_QATAR][0][103] = 127, + [1][1][2][1][RTW89_UK][1][103] = 127, + [1][1][2][1][RTW89_UK][0][103] = 127, + [1][1][2][1][RTW89_FCC][1][106] = 12, + [1][1][2][1][RTW89_FCC][2][106] = 127, + [1][1][2][1][RTW89_ETSI][1][106] = 127, + [1][1][2][1][RTW89_ETSI][0][106] = 127, + [1][1][2][1][RTW89_MKK][1][106] = 127, + [1][1][2][1][RTW89_MKK][0][106] = 127, + [1][1][2][1][RTW89_IC][1][106] = 12, + [1][1][2][1][RTW89_KCC][1][106] = 32, + [1][1][2][1][RTW89_KCC][0][106] = 127, + [1][1][2][1][RTW89_ACMA][1][106] = 127, + [1][1][2][1][RTW89_ACMA][0][106] = 127, + [1][1][2][1][RTW89_CHILE][1][106] = 12, + [1][1][2][1][RTW89_QATAR][1][106] = 127, + [1][1][2][1][RTW89_QATAR][0][106] = 127, + [1][1][2][1][RTW89_UK][1][106] = 127, + [1][1][2][1][RTW89_UK][0][106] = 127, + [1][1][2][1][RTW89_FCC][1][110] = 127, + [1][1][2][1][RTW89_FCC][2][110] = 127, + [1][1][2][1][RTW89_ETSI][1][110] = 127, + [1][1][2][1][RTW89_ETSI][0][110] = 127, + [1][1][2][1][RTW89_MKK][1][110] = 127, + [1][1][2][1][RTW89_MKK][0][110] = 127, + [1][1][2][1][RTW89_IC][1][110] = 127, + [1][1][2][1][RTW89_KCC][1][110] = 127, + [1][1][2][1][RTW89_KCC][0][110] = 127, + [1][1][2][1][RTW89_ACMA][1][110] = 127, + [1][1][2][1][RTW89_ACMA][0][110] = 127, + [1][1][2][1][RTW89_CHILE][1][110] = 127, + [1][1][2][1][RTW89_QATAR][1][110] = 127, + [1][1][2][1][RTW89_QATAR][0][110] = 127, + [1][1][2][1][RTW89_UK][1][110] = 127, + [1][1][2][1][RTW89_UK][0][110] = 127, + [1][1][2][1][RTW89_FCC][1][114] = 127, + [1][1][2][1][RTW89_FCC][2][114] = 127, + [1][1][2][1][RTW89_ETSI][1][114] = 127, + [1][1][2][1][RTW89_ETSI][0][114] = 127, + [1][1][2][1][RTW89_MKK][1][114] = 127, + [1][1][2][1][RTW89_MKK][0][114] = 127, + [1][1][2][1][RTW89_IC][1][114] = 127, + [1][1][2][1][RTW89_KCC][1][114] = 127, + [1][1][2][1][RTW89_KCC][0][114] = 127, + [1][1][2][1][RTW89_ACMA][1][114] = 127, + [1][1][2][1][RTW89_ACMA][0][114] = 127, + [1][1][2][1][RTW89_CHILE][1][114] = 127, + [1][1][2][1][RTW89_QATAR][1][114] = 127, + [1][1][2][1][RTW89_QATAR][0][114] = 127, + [1][1][2][1][RTW89_UK][1][114] = 127, + [1][1][2][1][RTW89_UK][0][114] = 127, + [1][1][2][1][RTW89_FCC][1][118] = 127, + [1][1][2][1][RTW89_FCC][2][118] = 127, + [1][1][2][1][RTW89_ETSI][1][118] = 127, + [1][1][2][1][RTW89_ETSI][0][118] = 127, + [1][1][2][1][RTW89_MKK][1][118] = 127, + [1][1][2][1][RTW89_MKK][0][118] = 127, + [1][1][2][1][RTW89_IC][1][118] = 127, + [1][1][2][1][RTW89_KCC][1][118] = 127, + [1][1][2][1][RTW89_KCC][0][118] = 127, + [1][1][2][1][RTW89_ACMA][1][118] = 127, + [1][1][2][1][RTW89_ACMA][0][118] = 127, + [1][1][2][1][RTW89_CHILE][1][118] = 127, + [1][1][2][1][RTW89_QATAR][1][118] = 127, + [1][1][2][1][RTW89_QATAR][0][118] = 127, + [1][1][2][1][RTW89_UK][1][118] = 127, + [1][1][2][1][RTW89_UK][0][118] = 127, + [2][0][2][0][RTW89_FCC][1][3] = 46, + [2][0][2][0][RTW89_FCC][2][3] = 60, + [2][0][2][0][RTW89_ETSI][1][3] = 58, + [2][0][2][0][RTW89_ETSI][0][3] = 30, + [2][0][2][0][RTW89_MKK][1][3] = 58, + [2][0][2][0][RTW89_MKK][0][3] = 26, + [2][0][2][0][RTW89_IC][1][3] = 46, + [2][0][2][0][RTW89_KCC][1][3] = 50, + [2][0][2][0][RTW89_KCC][0][3] = 24, + [2][0][2][0][RTW89_ACMA][1][3] = 58, + [2][0][2][0][RTW89_ACMA][0][3] = 30, + [2][0][2][0][RTW89_CHILE][1][3] = 46, + [2][0][2][0][RTW89_QATAR][1][3] = 58, + [2][0][2][0][RTW89_QATAR][0][3] = 30, + [2][0][2][0][RTW89_UK][1][3] = 58, + [2][0][2][0][RTW89_UK][0][3] = 30, + [2][0][2][0][RTW89_FCC][1][11] = 46, + [2][0][2][0][RTW89_FCC][2][11] = 60, + [2][0][2][0][RTW89_ETSI][1][11] = 58, + [2][0][2][0][RTW89_ETSI][0][11] = 30, + [2][0][2][0][RTW89_MKK][1][11] = 58, + [2][0][2][0][RTW89_MKK][0][11] = 24, + [2][0][2][0][RTW89_IC][1][11] = 46, + [2][0][2][0][RTW89_KCC][1][11] = 50, + [2][0][2][0][RTW89_KCC][0][11] = 24, + [2][0][2][0][RTW89_ACMA][1][11] = 58, + [2][0][2][0][RTW89_ACMA][0][11] = 30, + [2][0][2][0][RTW89_CHILE][1][11] = 46, + [2][0][2][0][RTW89_QATAR][1][11] = 58, + [2][0][2][0][RTW89_QATAR][0][11] = 30, + [2][0][2][0][RTW89_UK][1][11] = 58, + [2][0][2][0][RTW89_UK][0][11] = 30, + [2][0][2][0][RTW89_FCC][1][18] = 46, + [2][0][2][0][RTW89_FCC][2][18] = 60, + [2][0][2][0][RTW89_ETSI][1][18] = 58, + [2][0][2][0][RTW89_ETSI][0][18] = 30, + [2][0][2][0][RTW89_MKK][1][18] = 58, + [2][0][2][0][RTW89_MKK][0][18] = 24, + [2][0][2][0][RTW89_IC][1][18] = 46, + [2][0][2][0][RTW89_KCC][1][18] = 50, + [2][0][2][0][RTW89_KCC][0][18] = 24, + [2][0][2][0][RTW89_ACMA][1][18] = 58, + [2][0][2][0][RTW89_ACMA][0][18] = 30, + [2][0][2][0][RTW89_CHILE][1][18] = 46, + [2][0][2][0][RTW89_QATAR][1][18] = 58, + [2][0][2][0][RTW89_QATAR][0][18] = 30, + [2][0][2][0][RTW89_UK][1][18] = 58, + [2][0][2][0][RTW89_UK][0][18] = 30, + [2][0][2][0][RTW89_FCC][1][26] = 46, + [2][0][2][0][RTW89_FCC][2][26] = 60, + [2][0][2][0][RTW89_ETSI][1][26] = 58, + [2][0][2][0][RTW89_ETSI][0][26] = 30, + [2][0][2][0][RTW89_MKK][1][26] = 58, + [2][0][2][0][RTW89_MKK][0][26] = 24, + [2][0][2][0][RTW89_IC][1][26] = 46, + [2][0][2][0][RTW89_KCC][1][26] = 50, + [2][0][2][0][RTW89_KCC][0][26] = 26, + [2][0][2][0][RTW89_ACMA][1][26] = 58, + [2][0][2][0][RTW89_ACMA][0][26] = 30, + [2][0][2][0][RTW89_CHILE][1][26] = 46, + [2][0][2][0][RTW89_QATAR][1][26] = 58, + [2][0][2][0][RTW89_QATAR][0][26] = 30, + [2][0][2][0][RTW89_UK][1][26] = 58, + [2][0][2][0][RTW89_UK][0][26] = 30, + [2][0][2][0][RTW89_FCC][1][33] = 46, + [2][0][2][0][RTW89_FCC][2][33] = 60, + [2][0][2][0][RTW89_ETSI][1][33] = 58, + [2][0][2][0][RTW89_ETSI][0][33] = 30, + [2][0][2][0][RTW89_MKK][1][33] = 58, + [2][0][2][0][RTW89_MKK][0][33] = 24, + [2][0][2][0][RTW89_IC][1][33] = 46, + [2][0][2][0][RTW89_KCC][1][33] = 50, + [2][0][2][0][RTW89_KCC][0][33] = 24, + [2][0][2][0][RTW89_ACMA][1][33] = 58, + [2][0][2][0][RTW89_ACMA][0][33] = 30, + [2][0][2][0][RTW89_CHILE][1][33] = 46, + [2][0][2][0][RTW89_QATAR][1][33] = 58, + [2][0][2][0][RTW89_QATAR][0][33] = 30, + [2][0][2][0][RTW89_UK][1][33] = 58, + [2][0][2][0][RTW89_UK][0][33] = 30, + [2][0][2][0][RTW89_FCC][1][41] = 46, + [2][0][2][0][RTW89_FCC][2][41] = 60, + [2][0][2][0][RTW89_ETSI][1][41] = 58, + [2][0][2][0][RTW89_ETSI][0][41] = 30, + [2][0][2][0][RTW89_MKK][1][41] = 58, + [2][0][2][0][RTW89_MKK][0][41] = 24, + [2][0][2][0][RTW89_IC][1][41] = 46, + [2][0][2][0][RTW89_KCC][1][41] = 50, + [2][0][2][0][RTW89_KCC][0][41] = 24, + [2][0][2][0][RTW89_ACMA][1][41] = 58, + [2][0][2][0][RTW89_ACMA][0][41] = 30, + [2][0][2][0][RTW89_CHILE][1][41] = 46, + [2][0][2][0][RTW89_QATAR][1][41] = 58, + [2][0][2][0][RTW89_QATAR][0][41] = 30, + [2][0][2][0][RTW89_UK][1][41] = 58, + [2][0][2][0][RTW89_UK][0][41] = 30, + [2][0][2][0][RTW89_FCC][1][48] = 46, + [2][0][2][0][RTW89_FCC][2][48] = 127, + [2][0][2][0][RTW89_ETSI][1][48] = 127, + [2][0][2][0][RTW89_ETSI][0][48] = 127, + [2][0][2][0][RTW89_MKK][1][48] = 127, + [2][0][2][0][RTW89_MKK][0][48] = 127, + [2][0][2][0][RTW89_IC][1][48] = 46, + [2][0][2][0][RTW89_KCC][1][48] = 48, + [2][0][2][0][RTW89_KCC][0][48] = 127, + [2][0][2][0][RTW89_ACMA][1][48] = 127, + [2][0][2][0][RTW89_ACMA][0][48] = 127, + [2][0][2][0][RTW89_CHILE][1][48] = 46, + [2][0][2][0][RTW89_QATAR][1][48] = 127, + [2][0][2][0][RTW89_QATAR][0][48] = 127, + [2][0][2][0][RTW89_UK][1][48] = 127, + [2][0][2][0][RTW89_UK][0][48] = 127, + [2][0][2][0][RTW89_FCC][1][56] = 46, + [2][0][2][0][RTW89_FCC][2][56] = 127, + [2][0][2][0][RTW89_ETSI][1][56] = 127, + [2][0][2][0][RTW89_ETSI][0][56] = 127, + [2][0][2][0][RTW89_MKK][1][56] = 127, + [2][0][2][0][RTW89_MKK][0][56] = 127, + [2][0][2][0][RTW89_IC][1][56] = 46, + [2][0][2][0][RTW89_KCC][1][56] = 48, + [2][0][2][0][RTW89_KCC][0][56] = 127, + [2][0][2][0][RTW89_ACMA][1][56] = 127, + [2][0][2][0][RTW89_ACMA][0][56] = 127, + [2][0][2][0][RTW89_CHILE][1][56] = 46, + [2][0][2][0][RTW89_QATAR][1][56] = 127, + [2][0][2][0][RTW89_QATAR][0][56] = 127, + [2][0][2][0][RTW89_UK][1][56] = 127, + [2][0][2][0][RTW89_UK][0][56] = 127, + [2][0][2][0][RTW89_FCC][1][63] = 46, + [2][0][2][0][RTW89_FCC][2][63] = 58, + [2][0][2][0][RTW89_ETSI][1][63] = 127, + [2][0][2][0][RTW89_ETSI][0][63] = 127, + [2][0][2][0][RTW89_MKK][1][63] = 127, + [2][0][2][0][RTW89_MKK][0][63] = 127, + [2][0][2][0][RTW89_IC][1][63] = 46, + [2][0][2][0][RTW89_KCC][1][63] = 48, + [2][0][2][0][RTW89_KCC][0][63] = 127, + [2][0][2][0][RTW89_ACMA][1][63] = 127, + [2][0][2][0][RTW89_ACMA][0][63] = 127, + [2][0][2][0][RTW89_CHILE][1][63] = 46, + [2][0][2][0][RTW89_QATAR][1][63] = 127, + [2][0][2][0][RTW89_QATAR][0][63] = 127, + [2][0][2][0][RTW89_UK][1][63] = 127, + [2][0][2][0][RTW89_UK][0][63] = 127, + [2][0][2][0][RTW89_FCC][1][71] = 46, + [2][0][2][0][RTW89_FCC][2][71] = 58, + [2][0][2][0][RTW89_ETSI][1][71] = 127, + [2][0][2][0][RTW89_ETSI][0][71] = 127, + [2][0][2][0][RTW89_MKK][1][71] = 127, + [2][0][2][0][RTW89_MKK][0][71] = 127, + [2][0][2][0][RTW89_IC][1][71] = 46, + [2][0][2][0][RTW89_KCC][1][71] = 48, + [2][0][2][0][RTW89_KCC][0][71] = 127, + [2][0][2][0][RTW89_ACMA][1][71] = 127, + [2][0][2][0][RTW89_ACMA][0][71] = 127, + [2][0][2][0][RTW89_CHILE][1][71] = 46, + [2][0][2][0][RTW89_QATAR][1][71] = 127, + [2][0][2][0][RTW89_QATAR][0][71] = 127, + [2][0][2][0][RTW89_UK][1][71] = 127, + [2][0][2][0][RTW89_UK][0][71] = 127, + [2][0][2][0][RTW89_FCC][1][78] = 46, + [2][0][2][0][RTW89_FCC][2][78] = 58, + [2][0][2][0][RTW89_ETSI][1][78] = 127, + [2][0][2][0][RTW89_ETSI][0][78] = 127, + [2][0][2][0][RTW89_MKK][1][78] = 127, + [2][0][2][0][RTW89_MKK][0][78] = 127, + [2][0][2][0][RTW89_IC][1][78] = 46, + [2][0][2][0][RTW89_KCC][1][78] = 52, + [2][0][2][0][RTW89_KCC][0][78] = 127, + [2][0][2][0][RTW89_ACMA][1][78] = 127, + [2][0][2][0][RTW89_ACMA][0][78] = 127, + [2][0][2][0][RTW89_CHILE][1][78] = 46, + [2][0][2][0][RTW89_QATAR][1][78] = 127, + [2][0][2][0][RTW89_QATAR][0][78] = 127, + [2][0][2][0][RTW89_UK][1][78] = 127, + [2][0][2][0][RTW89_UK][0][78] = 127, + [2][0][2][0][RTW89_FCC][1][86] = 46, + [2][0][2][0][RTW89_FCC][2][86] = 127, + [2][0][2][0][RTW89_ETSI][1][86] = 127, + [2][0][2][0][RTW89_ETSI][0][86] = 127, + [2][0][2][0][RTW89_MKK][1][86] = 127, + [2][0][2][0][RTW89_MKK][0][86] = 127, + [2][0][2][0][RTW89_IC][1][86] = 46, + [2][0][2][0][RTW89_KCC][1][86] = 52, + [2][0][2][0][RTW89_KCC][0][86] = 127, + [2][0][2][0][RTW89_ACMA][1][86] = 127, + [2][0][2][0][RTW89_ACMA][0][86] = 127, + [2][0][2][0][RTW89_CHILE][1][86] = 46, + [2][0][2][0][RTW89_QATAR][1][86] = 127, + [2][0][2][0][RTW89_QATAR][0][86] = 127, + [2][0][2][0][RTW89_UK][1][86] = 127, + [2][0][2][0][RTW89_UK][0][86] = 127, + [2][0][2][0][RTW89_FCC][1][93] = 46, + [2][0][2][0][RTW89_FCC][2][93] = 127, + [2][0][2][0][RTW89_ETSI][1][93] = 127, + [2][0][2][0][RTW89_ETSI][0][93] = 127, + [2][0][2][0][RTW89_MKK][1][93] = 127, + [2][0][2][0][RTW89_MKK][0][93] = 127, + [2][0][2][0][RTW89_IC][1][93] = 46, + [2][0][2][0][RTW89_KCC][1][93] = 50, + [2][0][2][0][RTW89_KCC][0][93] = 127, + [2][0][2][0][RTW89_ACMA][1][93] = 127, + [2][0][2][0][RTW89_ACMA][0][93] = 127, + [2][0][2][0][RTW89_CHILE][1][93] = 46, + [2][0][2][0][RTW89_QATAR][1][93] = 127, + [2][0][2][0][RTW89_QATAR][0][93] = 127, + [2][0][2][0][RTW89_UK][1][93] = 127, + [2][0][2][0][RTW89_UK][0][93] = 127, + [2][0][2][0][RTW89_FCC][1][101] = 44, + [2][0][2][0][RTW89_FCC][2][101] = 127, + [2][0][2][0][RTW89_ETSI][1][101] = 127, + [2][0][2][0][RTW89_ETSI][0][101] = 127, + [2][0][2][0][RTW89_MKK][1][101] = 127, + [2][0][2][0][RTW89_MKK][0][101] = 127, + [2][0][2][0][RTW89_IC][1][101] = 44, + [2][0][2][0][RTW89_KCC][1][101] = 50, + [2][0][2][0][RTW89_KCC][0][101] = 127, + [2][0][2][0][RTW89_ACMA][1][101] = 127, + [2][0][2][0][RTW89_ACMA][0][101] = 127, + [2][0][2][0][RTW89_CHILE][1][101] = 44, + [2][0][2][0][RTW89_QATAR][1][101] = 127, + [2][0][2][0][RTW89_QATAR][0][101] = 127, + [2][0][2][0][RTW89_UK][1][101] = 127, + [2][0][2][0][RTW89_UK][0][101] = 127, + [2][0][2][0][RTW89_FCC][1][108] = 127, + [2][0][2][0][RTW89_FCC][2][108] = 127, + [2][0][2][0][RTW89_ETSI][1][108] = 127, + [2][0][2][0][RTW89_ETSI][0][108] = 127, + [2][0][2][0][RTW89_MKK][1][108] = 127, + [2][0][2][0][RTW89_MKK][0][108] = 127, + [2][0][2][0][RTW89_IC][1][108] = 127, + [2][0][2][0][RTW89_KCC][1][108] = 127, + [2][0][2][0][RTW89_KCC][0][108] = 127, + [2][0][2][0][RTW89_ACMA][1][108] = 127, + [2][0][2][0][RTW89_ACMA][0][108] = 127, + [2][0][2][0][RTW89_CHILE][1][108] = 127, + [2][0][2][0][RTW89_QATAR][1][108] = 127, + [2][0][2][0][RTW89_QATAR][0][108] = 127, + [2][0][2][0][RTW89_UK][1][108] = 127, + [2][0][2][0][RTW89_UK][0][108] = 127, + [2][0][2][0][RTW89_FCC][1][116] = 127, + [2][0][2][0][RTW89_FCC][2][116] = 127, + [2][0][2][0][RTW89_ETSI][1][116] = 127, + [2][0][2][0][RTW89_ETSI][0][116] = 127, + [2][0][2][0][RTW89_MKK][1][116] = 127, + [2][0][2][0][RTW89_MKK][0][116] = 127, + [2][0][2][0][RTW89_IC][1][116] = 127, + [2][0][2][0][RTW89_KCC][1][116] = 127, + [2][0][2][0][RTW89_KCC][0][116] = 127, + [2][0][2][0][RTW89_ACMA][1][116] = 127, + [2][0][2][0][RTW89_ACMA][0][116] = 127, + [2][0][2][0][RTW89_CHILE][1][116] = 127, + [2][0][2][0][RTW89_QATAR][1][116] = 127, + [2][0][2][0][RTW89_QATAR][0][116] = 127, + [2][0][2][0][RTW89_UK][1][116] = 127, + [2][0][2][0][RTW89_UK][0][116] = 127, + [2][1][2][0][RTW89_FCC][1][3] = 22, + [2][1][2][0][RTW89_FCC][2][3] = 50, + [2][1][2][0][RTW89_ETSI][1][3] = 54, + [2][1][2][0][RTW89_ETSI][0][3] = 16, + [2][1][2][0][RTW89_MKK][1][3] = 52, + [2][1][2][0][RTW89_MKK][0][3] = 14, + [2][1][2][0][RTW89_IC][1][3] = 22, + [2][1][2][0][RTW89_KCC][1][3] = 38, + [2][1][2][0][RTW89_KCC][0][3] = 12, + [2][1][2][0][RTW89_ACMA][1][3] = 54, + [2][1][2][0][RTW89_ACMA][0][3] = 16, + [2][1][2][0][RTW89_CHILE][1][3] = 22, + [2][1][2][0][RTW89_QATAR][1][3] = 54, + [2][1][2][0][RTW89_QATAR][0][3] = 16, + [2][1][2][0][RTW89_UK][1][3] = 54, + [2][1][2][0][RTW89_UK][0][3] = 16, + [2][1][2][0][RTW89_FCC][1][11] = 20, + [2][1][2][0][RTW89_FCC][2][11] = 50, + [2][1][2][0][RTW89_ETSI][1][11] = 54, + [2][1][2][0][RTW89_ETSI][0][11] = 16, + [2][1][2][0][RTW89_MKK][1][11] = 52, + [2][1][2][0][RTW89_MKK][0][11] = 12, + [2][1][2][0][RTW89_IC][1][11] = 20, + [2][1][2][0][RTW89_KCC][1][11] = 38, + [2][1][2][0][RTW89_KCC][0][11] = 12, + [2][1][2][0][RTW89_ACMA][1][11] = 54, + [2][1][2][0][RTW89_ACMA][0][11] = 16, + [2][1][2][0][RTW89_CHILE][1][11] = 20, + [2][1][2][0][RTW89_QATAR][1][11] = 54, + [2][1][2][0][RTW89_QATAR][0][11] = 16, + [2][1][2][0][RTW89_UK][1][11] = 54, + [2][1][2][0][RTW89_UK][0][11] = 16, + [2][1][2][0][RTW89_FCC][1][18] = 20, + [2][1][2][0][RTW89_FCC][2][18] = 50, + [2][1][2][0][RTW89_ETSI][1][18] = 54, + [2][1][2][0][RTW89_ETSI][0][18] = 16, + [2][1][2][0][RTW89_MKK][1][18] = 52, + [2][1][2][0][RTW89_MKK][0][18] = 12, + [2][1][2][0][RTW89_IC][1][18] = 20, + [2][1][2][0][RTW89_KCC][1][18] = 38, + [2][1][2][0][RTW89_KCC][0][18] = 12, + [2][1][2][0][RTW89_ACMA][1][18] = 54, + [2][1][2][0][RTW89_ACMA][0][18] = 16, + [2][1][2][0][RTW89_CHILE][1][18] = 20, + [2][1][2][0][RTW89_QATAR][1][18] = 54, + [2][1][2][0][RTW89_QATAR][0][18] = 16, + [2][1][2][0][RTW89_UK][1][18] = 54, + [2][1][2][0][RTW89_UK][0][18] = 16, + [2][1][2][0][RTW89_FCC][1][26] = 20, + [2][1][2][0][RTW89_FCC][2][26] = 60, + [2][1][2][0][RTW89_ETSI][1][26] = 54, + [2][1][2][0][RTW89_ETSI][0][26] = 16, + [2][1][2][0][RTW89_MKK][1][26] = 52, + [2][1][2][0][RTW89_MKK][0][26] = 12, + [2][1][2][0][RTW89_IC][1][26] = 20, + [2][1][2][0][RTW89_KCC][1][26] = 38, + [2][1][2][0][RTW89_KCC][0][26] = 12, + [2][1][2][0][RTW89_ACMA][1][26] = 54, + [2][1][2][0][RTW89_ACMA][0][26] = 16, + [2][1][2][0][RTW89_CHILE][1][26] = 20, + [2][1][2][0][RTW89_QATAR][1][26] = 54, + [2][1][2][0][RTW89_QATAR][0][26] = 16, + [2][1][2][0][RTW89_UK][1][26] = 54, + [2][1][2][0][RTW89_UK][0][26] = 16, + [2][1][2][0][RTW89_FCC][1][33] = 20, + [2][1][2][0][RTW89_FCC][2][33] = 60, + [2][1][2][0][RTW89_ETSI][1][33] = 54, + [2][1][2][0][RTW89_ETSI][0][33] = 16, + [2][1][2][0][RTW89_MKK][1][33] = 48, + [2][1][2][0][RTW89_MKK][0][33] = 12, + [2][1][2][0][RTW89_IC][1][33] = 20, + [2][1][2][0][RTW89_KCC][1][33] = 38, + [2][1][2][0][RTW89_KCC][0][33] = 12, + [2][1][2][0][RTW89_ACMA][1][33] = 54, + [2][1][2][0][RTW89_ACMA][0][33] = 16, + [2][1][2][0][RTW89_CHILE][1][33] = 20, + [2][1][2][0][RTW89_QATAR][1][33] = 54, + [2][1][2][0][RTW89_QATAR][0][33] = 16, + [2][1][2][0][RTW89_UK][1][33] = 54, + [2][1][2][0][RTW89_UK][0][33] = 16, + [2][1][2][0][RTW89_FCC][1][41] = 22, + [2][1][2][0][RTW89_FCC][2][41] = 60, + [2][1][2][0][RTW89_ETSI][1][41] = 54, + [2][1][2][0][RTW89_ETSI][0][41] = 18, + [2][1][2][0][RTW89_MKK][1][41] = 48, + [2][1][2][0][RTW89_MKK][0][41] = 12, + [2][1][2][0][RTW89_IC][1][41] = 22, + [2][1][2][0][RTW89_KCC][1][41] = 38, + [2][1][2][0][RTW89_KCC][0][41] = 12, + [2][1][2][0][RTW89_ACMA][1][41] = 54, + [2][1][2][0][RTW89_ACMA][0][41] = 18, + [2][1][2][0][RTW89_CHILE][1][41] = 22, + [2][1][2][0][RTW89_QATAR][1][41] = 54, + [2][1][2][0][RTW89_QATAR][0][41] = 18, + [2][1][2][0][RTW89_UK][1][41] = 54, + [2][1][2][0][RTW89_UK][0][41] = 18, + [2][1][2][0][RTW89_FCC][1][48] = 22, + [2][1][2][0][RTW89_FCC][2][48] = 127, + [2][1][2][0][RTW89_ETSI][1][48] = 127, + [2][1][2][0][RTW89_ETSI][0][48] = 127, + [2][1][2][0][RTW89_MKK][1][48] = 127, + [2][1][2][0][RTW89_MKK][0][48] = 127, + [2][1][2][0][RTW89_IC][1][48] = 22, + [2][1][2][0][RTW89_KCC][1][48] = 38, + [2][1][2][0][RTW89_KCC][0][48] = 127, + [2][1][2][0][RTW89_ACMA][1][48] = 127, + [2][1][2][0][RTW89_ACMA][0][48] = 127, + [2][1][2][0][RTW89_CHILE][1][48] = 22, + [2][1][2][0][RTW89_QATAR][1][48] = 127, + [2][1][2][0][RTW89_QATAR][0][48] = 127, + [2][1][2][0][RTW89_UK][1][48] = 127, + [2][1][2][0][RTW89_UK][0][48] = 127, + [2][1][2][0][RTW89_FCC][1][56] = 20, + [2][1][2][0][RTW89_FCC][2][56] = 127, + [2][1][2][0][RTW89_ETSI][1][56] = 127, + [2][1][2][0][RTW89_ETSI][0][56] = 127, + [2][1][2][0][RTW89_MKK][1][56] = 127, + [2][1][2][0][RTW89_MKK][0][56] = 127, + [2][1][2][0][RTW89_IC][1][56] = 20, + [2][1][2][0][RTW89_KCC][1][56] = 38, + [2][1][2][0][RTW89_KCC][0][56] = 127, + [2][1][2][0][RTW89_ACMA][1][56] = 127, + [2][1][2][0][RTW89_ACMA][0][56] = 127, + [2][1][2][0][RTW89_CHILE][1][56] = 20, + [2][1][2][0][RTW89_QATAR][1][56] = 127, + [2][1][2][0][RTW89_QATAR][0][56] = 127, + [2][1][2][0][RTW89_UK][1][56] = 127, + [2][1][2][0][RTW89_UK][0][56] = 127, + [2][1][2][0][RTW89_FCC][1][63] = 22, + [2][1][2][0][RTW89_FCC][2][63] = 58, + [2][1][2][0][RTW89_ETSI][1][63] = 127, + [2][1][2][0][RTW89_ETSI][0][63] = 127, + [2][1][2][0][RTW89_MKK][1][63] = 127, + [2][1][2][0][RTW89_MKK][0][63] = 127, + [2][1][2][0][RTW89_IC][1][63] = 22, + [2][1][2][0][RTW89_KCC][1][63] = 38, + [2][1][2][0][RTW89_KCC][0][63] = 127, + [2][1][2][0][RTW89_ACMA][1][63] = 127, + [2][1][2][0][RTW89_ACMA][0][63] = 127, + [2][1][2][0][RTW89_CHILE][1][63] = 22, + [2][1][2][0][RTW89_QATAR][1][63] = 127, + [2][1][2][0][RTW89_QATAR][0][63] = 127, + [2][1][2][0][RTW89_UK][1][63] = 127, + [2][1][2][0][RTW89_UK][0][63] = 127, + [2][1][2][0][RTW89_FCC][1][71] = 20, + [2][1][2][0][RTW89_FCC][2][71] = 58, + [2][1][2][0][RTW89_ETSI][1][71] = 127, + [2][1][2][0][RTW89_ETSI][0][71] = 127, + [2][1][2][0][RTW89_MKK][1][71] = 127, + [2][1][2][0][RTW89_MKK][0][71] = 127, + [2][1][2][0][RTW89_IC][1][71] = 20, + [2][1][2][0][RTW89_KCC][1][71] = 38, + [2][1][2][0][RTW89_KCC][0][71] = 127, + [2][1][2][0][RTW89_ACMA][1][71] = 127, + [2][1][2][0][RTW89_ACMA][0][71] = 127, + [2][1][2][0][RTW89_CHILE][1][71] = 20, + [2][1][2][0][RTW89_QATAR][1][71] = 127, + [2][1][2][0][RTW89_QATAR][0][71] = 127, + [2][1][2][0][RTW89_UK][1][71] = 127, + [2][1][2][0][RTW89_UK][0][71] = 127, + [2][1][2][0][RTW89_FCC][1][78] = 20, + [2][1][2][0][RTW89_FCC][2][78] = 58, + [2][1][2][0][RTW89_ETSI][1][78] = 127, + [2][1][2][0][RTW89_ETSI][0][78] = 127, + [2][1][2][0][RTW89_MKK][1][78] = 127, + [2][1][2][0][RTW89_MKK][0][78] = 127, + [2][1][2][0][RTW89_IC][1][78] = 20, + [2][1][2][0][RTW89_KCC][1][78] = 38, + [2][1][2][0][RTW89_KCC][0][78] = 127, + [2][1][2][0][RTW89_ACMA][1][78] = 127, + [2][1][2][0][RTW89_ACMA][0][78] = 127, + [2][1][2][0][RTW89_CHILE][1][78] = 20, + [2][1][2][0][RTW89_QATAR][1][78] = 127, + [2][1][2][0][RTW89_QATAR][0][78] = 127, + [2][1][2][0][RTW89_UK][1][78] = 127, + [2][1][2][0][RTW89_UK][0][78] = 127, + [2][1][2][0][RTW89_FCC][1][86] = 20, + [2][1][2][0][RTW89_FCC][2][86] = 127, + [2][1][2][0][RTW89_ETSI][1][86] = 127, + [2][1][2][0][RTW89_ETSI][0][86] = 127, + [2][1][2][0][RTW89_MKK][1][86] = 127, + [2][1][2][0][RTW89_MKK][0][86] = 127, + [2][1][2][0][RTW89_IC][1][86] = 20, + [2][1][2][0][RTW89_KCC][1][86] = 38, + [2][1][2][0][RTW89_KCC][0][86] = 127, + [2][1][2][0][RTW89_ACMA][1][86] = 127, + [2][1][2][0][RTW89_ACMA][0][86] = 127, + [2][1][2][0][RTW89_CHILE][1][86] = 20, + [2][1][2][0][RTW89_QATAR][1][86] = 127, + [2][1][2][0][RTW89_QATAR][0][86] = 127, + [2][1][2][0][RTW89_UK][1][86] = 127, + [2][1][2][0][RTW89_UK][0][86] = 127, + [2][1][2][0][RTW89_FCC][1][93] = 22, + [2][1][2][0][RTW89_FCC][2][93] = 127, + [2][1][2][0][RTW89_ETSI][1][93] = 127, + [2][1][2][0][RTW89_ETSI][0][93] = 127, + [2][1][2][0][RTW89_MKK][1][93] = 127, + [2][1][2][0][RTW89_MKK][0][93] = 127, + [2][1][2][0][RTW89_IC][1][93] = 22, + [2][1][2][0][RTW89_KCC][1][93] = 38, + [2][1][2][0][RTW89_KCC][0][93] = 127, + [2][1][2][0][RTW89_ACMA][1][93] = 127, + [2][1][2][0][RTW89_ACMA][0][93] = 127, + [2][1][2][0][RTW89_CHILE][1][93] = 22, + [2][1][2][0][RTW89_QATAR][1][93] = 127, + [2][1][2][0][RTW89_QATAR][0][93] = 127, + [2][1][2][0][RTW89_UK][1][93] = 127, + [2][1][2][0][RTW89_UK][0][93] = 127, + [2][1][2][0][RTW89_FCC][1][101] = 22, + [2][1][2][0][RTW89_FCC][2][101] = 127, + [2][1][2][0][RTW89_ETSI][1][101] = 127, + [2][1][2][0][RTW89_ETSI][0][101] = 127, + [2][1][2][0][RTW89_MKK][1][101] = 127, + [2][1][2][0][RTW89_MKK][0][101] = 127, + [2][1][2][0][RTW89_IC][1][101] = 22, + [2][1][2][0][RTW89_KCC][1][101] = 38, + [2][1][2][0][RTW89_KCC][0][101] = 127, + [2][1][2][0][RTW89_ACMA][1][101] = 127, + [2][1][2][0][RTW89_ACMA][0][101] = 127, + [2][1][2][0][RTW89_CHILE][1][101] = 22, + [2][1][2][0][RTW89_QATAR][1][101] = 127, + [2][1][2][0][RTW89_QATAR][0][101] = 127, + [2][1][2][0][RTW89_UK][1][101] = 127, + [2][1][2][0][RTW89_UK][0][101] = 127, + [2][1][2][0][RTW89_FCC][1][108] = 127, + [2][1][2][0][RTW89_FCC][2][108] = 127, + [2][1][2][0][RTW89_ETSI][1][108] = 127, + [2][1][2][0][RTW89_ETSI][0][108] = 127, + [2][1][2][0][RTW89_MKK][1][108] = 127, + [2][1][2][0][RTW89_MKK][0][108] = 127, + [2][1][2][0][RTW89_IC][1][108] = 127, + [2][1][2][0][RTW89_KCC][1][108] = 127, + [2][1][2][0][RTW89_KCC][0][108] = 127, + [2][1][2][0][RTW89_ACMA][1][108] = 127, + [2][1][2][0][RTW89_ACMA][0][108] = 127, + [2][1][2][0][RTW89_CHILE][1][108] = 127, + [2][1][2][0][RTW89_QATAR][1][108] = 127, + [2][1][2][0][RTW89_QATAR][0][108] = 127, + [2][1][2][0][RTW89_UK][1][108] = 127, + [2][1][2][0][RTW89_UK][0][108] = 127, + [2][1][2][0][RTW89_FCC][1][116] = 127, + [2][1][2][0][RTW89_FCC][2][116] = 127, + [2][1][2][0][RTW89_ETSI][1][116] = 127, + [2][1][2][0][RTW89_ETSI][0][116] = 127, + [2][1][2][0][RTW89_MKK][1][116] = 127, + [2][1][2][0][RTW89_MKK][0][116] = 127, + [2][1][2][0][RTW89_IC][1][116] = 127, + [2][1][2][0][RTW89_KCC][1][116] = 127, + [2][1][2][0][RTW89_KCC][0][116] = 127, + [2][1][2][0][RTW89_ACMA][1][116] = 127, + [2][1][2][0][RTW89_ACMA][0][116] = 127, + [2][1][2][0][RTW89_CHILE][1][116] = 127, + [2][1][2][0][RTW89_QATAR][1][116] = 127, + [2][1][2][0][RTW89_QATAR][0][116] = 127, + [2][1][2][0][RTW89_UK][1][116] = 127, + [2][1][2][0][RTW89_UK][0][116] = 127, + [2][1][2][1][RTW89_FCC][1][3] = 22, + [2][1][2][1][RTW89_FCC][2][3] = 50, + [2][1][2][1][RTW89_ETSI][1][3] = 42, + [2][1][2][1][RTW89_ETSI][0][3] = 6, + [2][1][2][1][RTW89_MKK][1][3] = 52, + [2][1][2][1][RTW89_MKK][0][3] = 14, + [2][1][2][1][RTW89_IC][1][3] = 22, + [2][1][2][1][RTW89_KCC][1][3] = 38, + [2][1][2][1][RTW89_KCC][0][3] = 12, + [2][1][2][1][RTW89_ACMA][1][3] = 42, + [2][1][2][1][RTW89_ACMA][0][3] = 6, + [2][1][2][1][RTW89_CHILE][1][3] = 22, + [2][1][2][1][RTW89_QATAR][1][3] = 42, + [2][1][2][1][RTW89_QATAR][0][3] = 6, + [2][1][2][1][RTW89_UK][1][3] = 42, + [2][1][2][1][RTW89_UK][0][3] = 6, + [2][1][2][1][RTW89_FCC][1][11] = 20, + [2][1][2][1][RTW89_FCC][2][11] = 50, + [2][1][2][1][RTW89_ETSI][1][11] = 42, + [2][1][2][1][RTW89_ETSI][0][11] = 6, + [2][1][2][1][RTW89_MKK][1][11] = 52, + [2][1][2][1][RTW89_MKK][0][11] = 12, + [2][1][2][1][RTW89_IC][1][11] = 20, + [2][1][2][1][RTW89_KCC][1][11] = 38, + [2][1][2][1][RTW89_KCC][0][11] = 12, + [2][1][2][1][RTW89_ACMA][1][11] = 42, + [2][1][2][1][RTW89_ACMA][0][11] = 6, + [2][1][2][1][RTW89_CHILE][1][11] = 20, + [2][1][2][1][RTW89_QATAR][1][11] = 42, + [2][1][2][1][RTW89_QATAR][0][11] = 6, + [2][1][2][1][RTW89_UK][1][11] = 42, + [2][1][2][1][RTW89_UK][0][11] = 6, + [2][1][2][1][RTW89_FCC][1][18] = 20, + [2][1][2][1][RTW89_FCC][2][18] = 50, + [2][1][2][1][RTW89_ETSI][1][18] = 42, + [2][1][2][1][RTW89_ETSI][0][18] = 6, + [2][1][2][1][RTW89_MKK][1][18] = 52, + [2][1][2][1][RTW89_MKK][0][18] = 12, + [2][1][2][1][RTW89_IC][1][18] = 20, + [2][1][2][1][RTW89_KCC][1][18] = 38, + [2][1][2][1][RTW89_KCC][0][18] = 12, + [2][1][2][1][RTW89_ACMA][1][18] = 42, + [2][1][2][1][RTW89_ACMA][0][18] = 6, + [2][1][2][1][RTW89_CHILE][1][18] = 20, + [2][1][2][1][RTW89_QATAR][1][18] = 42, + [2][1][2][1][RTW89_QATAR][0][18] = 6, + [2][1][2][1][RTW89_UK][1][18] = 42, + [2][1][2][1][RTW89_UK][0][18] = 6, + [2][1][2][1][RTW89_FCC][1][26] = 20, + [2][1][2][1][RTW89_FCC][2][26] = 60, + [2][1][2][1][RTW89_ETSI][1][26] = 42, + [2][1][2][1][RTW89_ETSI][0][26] = 6, + [2][1][2][1][RTW89_MKK][1][26] = 52, + [2][1][2][1][RTW89_MKK][0][26] = 12, + [2][1][2][1][RTW89_IC][1][26] = 20, + [2][1][2][1][RTW89_KCC][1][26] = 38, + [2][1][2][1][RTW89_KCC][0][26] = 12, + [2][1][2][1][RTW89_ACMA][1][26] = 42, + [2][1][2][1][RTW89_ACMA][0][26] = 6, + [2][1][2][1][RTW89_CHILE][1][26] = 20, + [2][1][2][1][RTW89_QATAR][1][26] = 42, + [2][1][2][1][RTW89_QATAR][0][26] = 6, + [2][1][2][1][RTW89_UK][1][26] = 42, + [2][1][2][1][RTW89_UK][0][26] = 6, + [2][1][2][1][RTW89_FCC][1][33] = 20, + [2][1][2][1][RTW89_FCC][2][33] = 60, + [2][1][2][1][RTW89_ETSI][1][33] = 42, + [2][1][2][1][RTW89_ETSI][0][33] = 6, + [2][1][2][1][RTW89_MKK][1][33] = 48, + [2][1][2][1][RTW89_MKK][0][33] = 12, + [2][1][2][1][RTW89_IC][1][33] = 20, + [2][1][2][1][RTW89_KCC][1][33] = 38, + [2][1][2][1][RTW89_KCC][0][33] = 12, + [2][1][2][1][RTW89_ACMA][1][33] = 42, + [2][1][2][1][RTW89_ACMA][0][33] = 6, + [2][1][2][1][RTW89_CHILE][1][33] = 20, + [2][1][2][1][RTW89_QATAR][1][33] = 42, + [2][1][2][1][RTW89_QATAR][0][33] = 6, + [2][1][2][1][RTW89_UK][1][33] = 42, + [2][1][2][1][RTW89_UK][0][33] = 6, + [2][1][2][1][RTW89_FCC][1][41] = 22, + [2][1][2][1][RTW89_FCC][2][41] = 60, + [2][1][2][1][RTW89_ETSI][1][41] = 42, + [2][1][2][1][RTW89_ETSI][0][41] = 6, + [2][1][2][1][RTW89_MKK][1][41] = 48, + [2][1][2][1][RTW89_MKK][0][41] = 12, + [2][1][2][1][RTW89_IC][1][41] = 22, + [2][1][2][1][RTW89_KCC][1][41] = 38, + [2][1][2][1][RTW89_KCC][0][41] = 12, + [2][1][2][1][RTW89_ACMA][1][41] = 42, + [2][1][2][1][RTW89_ACMA][0][41] = 6, + [2][1][2][1][RTW89_CHILE][1][41] = 22, + [2][1][2][1][RTW89_QATAR][1][41] = 42, + [2][1][2][1][RTW89_QATAR][0][41] = 6, + [2][1][2][1][RTW89_UK][1][41] = 42, + [2][1][2][1][RTW89_UK][0][41] = 6, + [2][1][2][1][RTW89_FCC][1][48] = 22, + [2][1][2][1][RTW89_FCC][2][48] = 127, + [2][1][2][1][RTW89_ETSI][1][48] = 127, + [2][1][2][1][RTW89_ETSI][0][48] = 127, + [2][1][2][1][RTW89_MKK][1][48] = 127, + [2][1][2][1][RTW89_MKK][0][48] = 127, + [2][1][2][1][RTW89_IC][1][48] = 22, + [2][1][2][1][RTW89_KCC][1][48] = 38, + [2][1][2][1][RTW89_KCC][0][48] = 127, + [2][1][2][1][RTW89_ACMA][1][48] = 127, + [2][1][2][1][RTW89_ACMA][0][48] = 127, + [2][1][2][1][RTW89_CHILE][1][48] = 22, + [2][1][2][1][RTW89_QATAR][1][48] = 127, + [2][1][2][1][RTW89_QATAR][0][48] = 127, + [2][1][2][1][RTW89_UK][1][48] = 127, + [2][1][2][1][RTW89_UK][0][48] = 127, + [2][1][2][1][RTW89_FCC][1][56] = 20, + [2][1][2][1][RTW89_FCC][2][56] = 127, + [2][1][2][1][RTW89_ETSI][1][56] = 127, + [2][1][2][1][RTW89_ETSI][0][56] = 127, + [2][1][2][1][RTW89_MKK][1][56] = 127, + [2][1][2][1][RTW89_MKK][0][56] = 127, + [2][1][2][1][RTW89_IC][1][56] = 20, + [2][1][2][1][RTW89_KCC][1][56] = 38, + [2][1][2][1][RTW89_KCC][0][56] = 127, + [2][1][2][1][RTW89_ACMA][1][56] = 127, + [2][1][2][1][RTW89_ACMA][0][56] = 127, + [2][1][2][1][RTW89_CHILE][1][56] = 20, + [2][1][2][1][RTW89_QATAR][1][56] = 127, + [2][1][2][1][RTW89_QATAR][0][56] = 127, + [2][1][2][1][RTW89_UK][1][56] = 127, + [2][1][2][1][RTW89_UK][0][56] = 127, + [2][1][2][1][RTW89_FCC][1][63] = 22, + [2][1][2][1][RTW89_FCC][2][63] = 58, + [2][1][2][1][RTW89_ETSI][1][63] = 127, + [2][1][2][1][RTW89_ETSI][0][63] = 127, + [2][1][2][1][RTW89_MKK][1][63] = 127, + [2][1][2][1][RTW89_MKK][0][63] = 127, + [2][1][2][1][RTW89_IC][1][63] = 22, + [2][1][2][1][RTW89_KCC][1][63] = 38, + [2][1][2][1][RTW89_KCC][0][63] = 127, + [2][1][2][1][RTW89_ACMA][1][63] = 127, + [2][1][2][1][RTW89_ACMA][0][63] = 127, + [2][1][2][1][RTW89_CHILE][1][63] = 22, + [2][1][2][1][RTW89_QATAR][1][63] = 127, + [2][1][2][1][RTW89_QATAR][0][63] = 127, + [2][1][2][1][RTW89_UK][1][63] = 127, + [2][1][2][1][RTW89_UK][0][63] = 127, + [2][1][2][1][RTW89_FCC][1][71] = 20, + [2][1][2][1][RTW89_FCC][2][71] = 58, + [2][1][2][1][RTW89_ETSI][1][71] = 127, + [2][1][2][1][RTW89_ETSI][0][71] = 127, + [2][1][2][1][RTW89_MKK][1][71] = 127, + [2][1][2][1][RTW89_MKK][0][71] = 127, + [2][1][2][1][RTW89_IC][1][71] = 20, + [2][1][2][1][RTW89_KCC][1][71] = 38, + [2][1][2][1][RTW89_KCC][0][71] = 127, + [2][1][2][1][RTW89_ACMA][1][71] = 127, + [2][1][2][1][RTW89_ACMA][0][71] = 127, + [2][1][2][1][RTW89_CHILE][1][71] = 20, + [2][1][2][1][RTW89_QATAR][1][71] = 127, + [2][1][2][1][RTW89_QATAR][0][71] = 127, + [2][1][2][1][RTW89_UK][1][71] = 127, + [2][1][2][1][RTW89_UK][0][71] = 127, + [2][1][2][1][RTW89_FCC][1][78] = 20, + [2][1][2][1][RTW89_FCC][2][78] = 58, + [2][1][2][1][RTW89_ETSI][1][78] = 127, + [2][1][2][1][RTW89_ETSI][0][78] = 127, + [2][1][2][1][RTW89_MKK][1][78] = 127, + [2][1][2][1][RTW89_MKK][0][78] = 127, + [2][1][2][1][RTW89_IC][1][78] = 20, + [2][1][2][1][RTW89_KCC][1][78] = 38, + [2][1][2][1][RTW89_KCC][0][78] = 127, + [2][1][2][1][RTW89_ACMA][1][78] = 127, + [2][1][2][1][RTW89_ACMA][0][78] = 127, + [2][1][2][1][RTW89_CHILE][1][78] = 20, + [2][1][2][1][RTW89_QATAR][1][78] = 127, + [2][1][2][1][RTW89_QATAR][0][78] = 127, + [2][1][2][1][RTW89_UK][1][78] = 127, + [2][1][2][1][RTW89_UK][0][78] = 127, + [2][1][2][1][RTW89_FCC][1][86] = 20, + [2][1][2][1][RTW89_FCC][2][86] = 127, + [2][1][2][1][RTW89_ETSI][1][86] = 127, + [2][1][2][1][RTW89_ETSI][0][86] = 127, + [2][1][2][1][RTW89_MKK][1][86] = 127, + [2][1][2][1][RTW89_MKK][0][86] = 127, + [2][1][2][1][RTW89_IC][1][86] = 20, + [2][1][2][1][RTW89_KCC][1][86] = 38, + [2][1][2][1][RTW89_KCC][0][86] = 127, + [2][1][2][1][RTW89_ACMA][1][86] = 127, + [2][1][2][1][RTW89_ACMA][0][86] = 127, + [2][1][2][1][RTW89_CHILE][1][86] = 20, + [2][1][2][1][RTW89_QATAR][1][86] = 127, + [2][1][2][1][RTW89_QATAR][0][86] = 127, + [2][1][2][1][RTW89_UK][1][86] = 127, + [2][1][2][1][RTW89_UK][0][86] = 127, + [2][1][2][1][RTW89_FCC][1][93] = 22, + [2][1][2][1][RTW89_FCC][2][93] = 127, + [2][1][2][1][RTW89_ETSI][1][93] = 127, + [2][1][2][1][RTW89_ETSI][0][93] = 127, + [2][1][2][1][RTW89_MKK][1][93] = 127, + [2][1][2][1][RTW89_MKK][0][93] = 127, + [2][1][2][1][RTW89_IC][1][93] = 22, + [2][1][2][1][RTW89_KCC][1][93] = 38, + [2][1][2][1][RTW89_KCC][0][93] = 127, + [2][1][2][1][RTW89_ACMA][1][93] = 127, + [2][1][2][1][RTW89_ACMA][0][93] = 127, + [2][1][2][1][RTW89_CHILE][1][93] = 22, + [2][1][2][1][RTW89_QATAR][1][93] = 127, + [2][1][2][1][RTW89_QATAR][0][93] = 127, + [2][1][2][1][RTW89_UK][1][93] = 127, + [2][1][2][1][RTW89_UK][0][93] = 127, + [2][1][2][1][RTW89_FCC][1][101] = 22, + [2][1][2][1][RTW89_FCC][2][101] = 127, + [2][1][2][1][RTW89_ETSI][1][101] = 127, + [2][1][2][1][RTW89_ETSI][0][101] = 127, + [2][1][2][1][RTW89_MKK][1][101] = 127, + [2][1][2][1][RTW89_MKK][0][101] = 127, + [2][1][2][1][RTW89_IC][1][101] = 22, + [2][1][2][1][RTW89_KCC][1][101] = 38, + [2][1][2][1][RTW89_KCC][0][101] = 127, + [2][1][2][1][RTW89_ACMA][1][101] = 127, + [2][1][2][1][RTW89_ACMA][0][101] = 127, + [2][1][2][1][RTW89_CHILE][1][101] = 22, + [2][1][2][1][RTW89_QATAR][1][101] = 127, + [2][1][2][1][RTW89_QATAR][0][101] = 127, + [2][1][2][1][RTW89_UK][1][101] = 127, + [2][1][2][1][RTW89_UK][0][101] = 127, + [2][1][2][1][RTW89_FCC][1][108] = 127, + [2][1][2][1][RTW89_FCC][2][108] = 127, + [2][1][2][1][RTW89_ETSI][1][108] = 127, + [2][1][2][1][RTW89_ETSI][0][108] = 127, + [2][1][2][1][RTW89_MKK][1][108] = 127, + [2][1][2][1][RTW89_MKK][0][108] = 127, + [2][1][2][1][RTW89_IC][1][108] = 127, + [2][1][2][1][RTW89_KCC][1][108] = 127, + [2][1][2][1][RTW89_KCC][0][108] = 127, + [2][1][2][1][RTW89_ACMA][1][108] = 127, + [2][1][2][1][RTW89_ACMA][0][108] = 127, + [2][1][2][1][RTW89_CHILE][1][108] = 127, + [2][1][2][1][RTW89_QATAR][1][108] = 127, + [2][1][2][1][RTW89_QATAR][0][108] = 127, + [2][1][2][1][RTW89_UK][1][108] = 127, + [2][1][2][1][RTW89_UK][0][108] = 127, + [2][1][2][1][RTW89_FCC][1][116] = 127, + [2][1][2][1][RTW89_FCC][2][116] = 127, + [2][1][2][1][RTW89_ETSI][1][116] = 127, + [2][1][2][1][RTW89_ETSI][0][116] = 127, + [2][1][2][1][RTW89_MKK][1][116] = 127, + [2][1][2][1][RTW89_MKK][0][116] = 127, + [2][1][2][1][RTW89_IC][1][116] = 127, + [2][1][2][1][RTW89_KCC][1][116] = 127, + [2][1][2][1][RTW89_KCC][0][116] = 127, + [2][1][2][1][RTW89_ACMA][1][116] = 127, + [2][1][2][1][RTW89_ACMA][0][116] = 127, + [2][1][2][1][RTW89_CHILE][1][116] = 127, + [2][1][2][1][RTW89_QATAR][1][116] = 127, + [2][1][2][1][RTW89_QATAR][0][116] = 127, + [2][1][2][1][RTW89_UK][1][116] = 127, + [2][1][2][1][RTW89_UK][0][116] = 127, + [3][0][2][0][RTW89_FCC][1][7] = 52, + [3][0][2][0][RTW89_FCC][2][7] = 52, + [3][0][2][0][RTW89_ETSI][1][7] = 50, + [3][0][2][0][RTW89_ETSI][0][7] = 30, + [3][0][2][0][RTW89_MKK][1][7] = 50, + [3][0][2][0][RTW89_MKK][0][7] = 22, + [3][0][2][0][RTW89_IC][1][7] = 52, + [3][0][2][0][RTW89_KCC][1][7] = 42, + [3][0][2][0][RTW89_KCC][0][7] = 24, + [3][0][2][0][RTW89_ACMA][1][7] = 50, + [3][0][2][0][RTW89_ACMA][0][7] = 30, + [3][0][2][0][RTW89_CHILE][1][7] = 52, + [3][0][2][0][RTW89_QATAR][1][7] = 50, + [3][0][2][0][RTW89_QATAR][0][7] = 30, + [3][0][2][0][RTW89_UK][1][7] = 50, + [3][0][2][0][RTW89_UK][0][7] = 30, + [3][0][2][0][RTW89_FCC][1][22] = 52, + [3][0][2][0][RTW89_FCC][2][22] = 52, + [3][0][2][0][RTW89_ETSI][1][22] = 50, + [3][0][2][0][RTW89_ETSI][0][22] = 30, + [3][0][2][0][RTW89_MKK][1][22] = 50, + [3][0][2][0][RTW89_MKK][0][22] = 20, + [3][0][2][0][RTW89_IC][1][22] = 52, + [3][0][2][0][RTW89_KCC][1][22] = 42, + [3][0][2][0][RTW89_KCC][0][22] = 24, + [3][0][2][0][RTW89_ACMA][1][22] = 50, + [3][0][2][0][RTW89_ACMA][0][22] = 30, + [3][0][2][0][RTW89_CHILE][1][22] = 52, + [3][0][2][0][RTW89_QATAR][1][22] = 50, + [3][0][2][0][RTW89_QATAR][0][22] = 30, + [3][0][2][0][RTW89_UK][1][22] = 50, + [3][0][2][0][RTW89_UK][0][22] = 30, + [3][0][2][0][RTW89_FCC][1][37] = 52, + [3][0][2][0][RTW89_FCC][2][37] = 52, + [3][0][2][0][RTW89_ETSI][1][37] = 50, + [3][0][2][0][RTW89_ETSI][0][37] = 30, + [3][0][2][0][RTW89_MKK][1][37] = 50, + [3][0][2][0][RTW89_MKK][0][37] = 20, + [3][0][2][0][RTW89_IC][1][37] = 52, + [3][0][2][0][RTW89_KCC][1][37] = 42, + [3][0][2][0][RTW89_KCC][0][37] = 24, + [3][0][2][0][RTW89_ACMA][1][37] = 50, + [3][0][2][0][RTW89_ACMA][0][37] = 30, + [3][0][2][0][RTW89_CHILE][1][37] = 52, + [3][0][2][0][RTW89_QATAR][1][37] = 50, + [3][0][2][0][RTW89_QATAR][0][37] = 30, + [3][0][2][0][RTW89_UK][1][37] = 50, + [3][0][2][0][RTW89_UK][0][37] = 30, + [3][0][2][0][RTW89_FCC][1][52] = 54, + [3][0][2][0][RTW89_FCC][2][52] = 127, + [3][0][2][0][RTW89_ETSI][1][52] = 127, + [3][0][2][0][RTW89_ETSI][0][52] = 127, + [3][0][2][0][RTW89_MKK][1][52] = 127, + [3][0][2][0][RTW89_MKK][0][52] = 127, + [3][0][2][0][RTW89_IC][1][52] = 54, + [3][0][2][0][RTW89_KCC][1][52] = 56, + [3][0][2][0][RTW89_KCC][0][52] = 127, + [3][0][2][0][RTW89_ACMA][1][52] = 127, + [3][0][2][0][RTW89_ACMA][0][52] = 127, + [3][0][2][0][RTW89_CHILE][1][52] = 54, + [3][0][2][0][RTW89_QATAR][1][52] = 127, + [3][0][2][0][RTW89_QATAR][0][52] = 127, + [3][0][2][0][RTW89_UK][1][52] = 127, + [3][0][2][0][RTW89_UK][0][52] = 127, + [3][0][2][0][RTW89_FCC][1][67] = 54, + [3][0][2][0][RTW89_FCC][2][67] = 54, + [3][0][2][0][RTW89_ETSI][1][67] = 127, + [3][0][2][0][RTW89_ETSI][0][67] = 127, + [3][0][2][0][RTW89_MKK][1][67] = 127, + [3][0][2][0][RTW89_MKK][0][67] = 127, + [3][0][2][0][RTW89_IC][1][67] = 54, + [3][0][2][0][RTW89_KCC][1][67] = 54, + [3][0][2][0][RTW89_KCC][0][67] = 127, + [3][0][2][0][RTW89_ACMA][1][67] = 127, + [3][0][2][0][RTW89_ACMA][0][67] = 127, + [3][0][2][0][RTW89_CHILE][1][67] = 54, + [3][0][2][0][RTW89_QATAR][1][67] = 127, + [3][0][2][0][RTW89_QATAR][0][67] = 127, + [3][0][2][0][RTW89_UK][1][67] = 127, + [3][0][2][0][RTW89_UK][0][67] = 127, + [3][0][2][0][RTW89_FCC][1][82] = 46, + [3][0][2][0][RTW89_FCC][2][82] = 127, + [3][0][2][0][RTW89_ETSI][1][82] = 127, + [3][0][2][0][RTW89_ETSI][0][82] = 127, + [3][0][2][0][RTW89_MKK][1][82] = 127, + [3][0][2][0][RTW89_MKK][0][82] = 127, + [3][0][2][0][RTW89_IC][1][82] = 46, + [3][0][2][0][RTW89_KCC][1][82] = 26, + [3][0][2][0][RTW89_KCC][0][82] = 127, + [3][0][2][0][RTW89_ACMA][1][82] = 127, + [3][0][2][0][RTW89_ACMA][0][82] = 127, + [3][0][2][0][RTW89_CHILE][1][82] = 46, + [3][0][2][0][RTW89_QATAR][1][82] = 127, + [3][0][2][0][RTW89_QATAR][0][82] = 127, + [3][0][2][0][RTW89_UK][1][82] = 127, + [3][0][2][0][RTW89_UK][0][82] = 127, + [3][0][2][0][RTW89_FCC][1][97] = 40, + [3][0][2][0][RTW89_FCC][2][97] = 127, + [3][0][2][0][RTW89_ETSI][1][97] = 127, + [3][0][2][0][RTW89_ETSI][0][97] = 127, + [3][0][2][0][RTW89_MKK][1][97] = 127, + [3][0][2][0][RTW89_MKK][0][97] = 127, + [3][0][2][0][RTW89_IC][1][97] = 40, + [3][0][2][0][RTW89_KCC][1][97] = 26, + [3][0][2][0][RTW89_KCC][0][97] = 127, + [3][0][2][0][RTW89_ACMA][1][97] = 127, + [3][0][2][0][RTW89_ACMA][0][97] = 127, + [3][0][2][0][RTW89_CHILE][1][97] = 40, + [3][0][2][0][RTW89_QATAR][1][97] = 127, + [3][0][2][0][RTW89_QATAR][0][97] = 127, + [3][0][2][0][RTW89_UK][1][97] = 127, + [3][0][2][0][RTW89_UK][0][97] = 127, + [3][0][2][0][RTW89_FCC][1][112] = 127, + [3][0][2][0][RTW89_FCC][2][112] = 127, + [3][0][2][0][RTW89_ETSI][1][112] = 127, + [3][0][2][0][RTW89_ETSI][0][112] = 127, + [3][0][2][0][RTW89_MKK][1][112] = 127, + [3][0][2][0][RTW89_MKK][0][112] = 127, + [3][0][2][0][RTW89_IC][1][112] = 127, + [3][0][2][0][RTW89_KCC][1][112] = 127, + [3][0][2][0][RTW89_KCC][0][112] = 127, + [3][0][2][0][RTW89_ACMA][1][112] = 127, + [3][0][2][0][RTW89_ACMA][0][112] = 127, + [3][0][2][0][RTW89_CHILE][1][112] = 127, + [3][0][2][0][RTW89_QATAR][1][112] = 127, + [3][0][2][0][RTW89_QATAR][0][112] = 127, + [3][0][2][0][RTW89_UK][1][112] = 127, + [3][0][2][0][RTW89_UK][0][112] = 127, + [3][1][2][0][RTW89_FCC][1][7] = 32, + [3][1][2][0][RTW89_FCC][2][7] = 46, + [3][1][2][0][RTW89_ETSI][1][7] = 50, + [3][1][2][0][RTW89_ETSI][0][7] = 18, + [3][1][2][0][RTW89_MKK][1][7] = 38, + [3][1][2][0][RTW89_MKK][0][7] = 10, + [3][1][2][0][RTW89_IC][1][7] = 32, + [3][1][2][0][RTW89_KCC][1][7] = 40, + [3][1][2][0][RTW89_KCC][0][7] = 12, + [3][1][2][0][RTW89_ACMA][1][7] = 50, + [3][1][2][0][RTW89_ACMA][0][7] = 18, + [3][1][2][0][RTW89_CHILE][1][7] = 32, + [3][1][2][0][RTW89_QATAR][1][7] = 50, + [3][1][2][0][RTW89_QATAR][0][7] = 18, + [3][1][2][0][RTW89_UK][1][7] = 50, + [3][1][2][0][RTW89_UK][0][7] = 18, + [3][1][2][0][RTW89_FCC][1][22] = 30, + [3][1][2][0][RTW89_FCC][2][22] = 52, + [3][1][2][0][RTW89_ETSI][1][22] = 46, + [3][1][2][0][RTW89_ETSI][0][22] = 16, + [3][1][2][0][RTW89_MKK][1][22] = 48, + [3][1][2][0][RTW89_MKK][0][22] = 8, + [3][1][2][0][RTW89_IC][1][22] = 30, + [3][1][2][0][RTW89_KCC][1][22] = 40, + [3][1][2][0][RTW89_KCC][0][22] = 12, + [3][1][2][0][RTW89_ACMA][1][22] = 46, + [3][1][2][0][RTW89_ACMA][0][22] = 16, + [3][1][2][0][RTW89_CHILE][1][22] = 30, + [3][1][2][0][RTW89_QATAR][1][22] = 46, + [3][1][2][0][RTW89_QATAR][0][22] = 16, + [3][1][2][0][RTW89_UK][1][22] = 46, + [3][1][2][0][RTW89_UK][0][22] = 16, + [3][1][2][0][RTW89_FCC][1][37] = 30, + [3][1][2][0][RTW89_FCC][2][37] = 52, + [3][1][2][0][RTW89_ETSI][1][37] = 46, + [3][1][2][0][RTW89_ETSI][0][37] = 16, + [3][1][2][0][RTW89_MKK][1][37] = 48, + [3][1][2][0][RTW89_MKK][0][37] = 8, + [3][1][2][0][RTW89_IC][1][37] = 30, + [3][1][2][0][RTW89_KCC][1][37] = 40, + [3][1][2][0][RTW89_KCC][0][37] = 12, + [3][1][2][0][RTW89_ACMA][1][37] = 46, + [3][1][2][0][RTW89_ACMA][0][37] = 16, + [3][1][2][0][RTW89_CHILE][1][37] = 30, + [3][1][2][0][RTW89_QATAR][1][37] = 46, + [3][1][2][0][RTW89_QATAR][0][37] = 16, + [3][1][2][0][RTW89_UK][1][37] = 46, + [3][1][2][0][RTW89_UK][0][37] = 16, + [3][1][2][0][RTW89_FCC][1][52] = 30, + [3][1][2][0][RTW89_FCC][2][52] = 127, + [3][1][2][0][RTW89_ETSI][1][52] = 127, + [3][1][2][0][RTW89_ETSI][0][52] = 127, + [3][1][2][0][RTW89_MKK][1][52] = 127, + [3][1][2][0][RTW89_MKK][0][52] = 127, + [3][1][2][0][RTW89_IC][1][52] = 30, + [3][1][2][0][RTW89_KCC][1][52] = 48, + [3][1][2][0][RTW89_KCC][0][52] = 127, + [3][1][2][0][RTW89_ACMA][1][52] = 127, + [3][1][2][0][RTW89_ACMA][0][52] = 127, + [3][1][2][0][RTW89_CHILE][1][52] = 30, + [3][1][2][0][RTW89_QATAR][1][52] = 127, + [3][1][2][0][RTW89_QATAR][0][52] = 127, + [3][1][2][0][RTW89_UK][1][52] = 127, + [3][1][2][0][RTW89_UK][0][52] = 127, + [3][1][2][0][RTW89_FCC][1][67] = 32, + [3][1][2][0][RTW89_FCC][2][67] = 54, + [3][1][2][0][RTW89_ETSI][1][67] = 127, + [3][1][2][0][RTW89_ETSI][0][67] = 127, + [3][1][2][0][RTW89_MKK][1][67] = 127, + [3][1][2][0][RTW89_MKK][0][67] = 127, + [3][1][2][0][RTW89_IC][1][67] = 32, + [3][1][2][0][RTW89_KCC][1][67] = 48, + [3][1][2][0][RTW89_KCC][0][67] = 127, + [3][1][2][0][RTW89_ACMA][1][67] = 127, + [3][1][2][0][RTW89_ACMA][0][67] = 127, + [3][1][2][0][RTW89_CHILE][1][67] = 32, + [3][1][2][0][RTW89_QATAR][1][67] = 127, + [3][1][2][0][RTW89_QATAR][0][67] = 127, + [3][1][2][0][RTW89_UK][1][67] = 127, + [3][1][2][0][RTW89_UK][0][67] = 127, + [3][1][2][0][RTW89_FCC][1][82] = 32, + [3][1][2][0][RTW89_FCC][2][82] = 127, + [3][1][2][0][RTW89_ETSI][1][82] = 127, + [3][1][2][0][RTW89_ETSI][0][82] = 127, + [3][1][2][0][RTW89_MKK][1][82] = 127, + [3][1][2][0][RTW89_MKK][0][82] = 127, + [3][1][2][0][RTW89_IC][1][82] = 32, + [3][1][2][0][RTW89_KCC][1][82] = 24, + [3][1][2][0][RTW89_KCC][0][82] = 127, + [3][1][2][0][RTW89_ACMA][1][82] = 127, + [3][1][2][0][RTW89_ACMA][0][82] = 127, + [3][1][2][0][RTW89_CHILE][1][82] = 32, + [3][1][2][0][RTW89_QATAR][1][82] = 127, + [3][1][2][0][RTW89_QATAR][0][82] = 127, + [3][1][2][0][RTW89_UK][1][82] = 127, + [3][1][2][0][RTW89_UK][0][82] = 127, + [3][1][2][0][RTW89_FCC][1][97] = 32, + [3][1][2][0][RTW89_FCC][2][97] = 127, + [3][1][2][0][RTW89_ETSI][1][97] = 127, + [3][1][2][0][RTW89_ETSI][0][97] = 127, + [3][1][2][0][RTW89_MKK][1][97] = 127, + [3][1][2][0][RTW89_MKK][0][97] = 127, + [3][1][2][0][RTW89_IC][1][97] = 32, + [3][1][2][0][RTW89_KCC][1][97] = 24, + [3][1][2][0][RTW89_KCC][0][97] = 127, + [3][1][2][0][RTW89_ACMA][1][97] = 127, + [3][1][2][0][RTW89_ACMA][0][97] = 127, + [3][1][2][0][RTW89_CHILE][1][97] = 32, + [3][1][2][0][RTW89_QATAR][1][97] = 127, + [3][1][2][0][RTW89_QATAR][0][97] = 127, + [3][1][2][0][RTW89_UK][1][97] = 127, + [3][1][2][0][RTW89_UK][0][97] = 127, + [3][1][2][0][RTW89_FCC][1][112] = 127, + [3][1][2][0][RTW89_FCC][2][112] = 127, + [3][1][2][0][RTW89_ETSI][1][112] = 127, + [3][1][2][0][RTW89_ETSI][0][112] = 127, + [3][1][2][0][RTW89_MKK][1][112] = 127, + [3][1][2][0][RTW89_MKK][0][112] = 127, + [3][1][2][0][RTW89_IC][1][112] = 127, + [3][1][2][0][RTW89_KCC][1][112] = 127, + [3][1][2][0][RTW89_KCC][0][112] = 127, + [3][1][2][0][RTW89_ACMA][1][112] = 127, + [3][1][2][0][RTW89_ACMA][0][112] = 127, + [3][1][2][0][RTW89_CHILE][1][112] = 127, + [3][1][2][0][RTW89_QATAR][1][112] = 127, + [3][1][2][0][RTW89_QATAR][0][112] = 127, + [3][1][2][0][RTW89_UK][1][112] = 127, + [3][1][2][0][RTW89_UK][0][112] = 127, + [3][1][2][1][RTW89_FCC][1][7] = 32, + [3][1][2][1][RTW89_FCC][2][7] = 46, + [3][1][2][1][RTW89_ETSI][1][7] = 42, + [3][1][2][1][RTW89_ETSI][0][7] = 6, + [3][1][2][1][RTW89_MKK][1][7] = 38, + [3][1][2][1][RTW89_MKK][0][7] = 10, + [3][1][2][1][RTW89_IC][1][7] = 32, + [3][1][2][1][RTW89_KCC][1][7] = 40, + [3][1][2][1][RTW89_KCC][0][7] = 12, + [3][1][2][1][RTW89_ACMA][1][7] = 42, + [3][1][2][1][RTW89_ACMA][0][7] = 6, + [3][1][2][1][RTW89_CHILE][1][7] = 32, + [3][1][2][1][RTW89_QATAR][1][7] = 42, + [3][1][2][1][RTW89_QATAR][0][7] = 6, + [3][1][2][1][RTW89_UK][1][7] = 42, + [3][1][2][1][RTW89_UK][0][7] = 6, + [3][1][2][1][RTW89_FCC][1][22] = 30, + [3][1][2][1][RTW89_FCC][2][22] = 52, + [3][1][2][1][RTW89_ETSI][1][22] = 42, + [3][1][2][1][RTW89_ETSI][0][22] = 6, + [3][1][2][1][RTW89_MKK][1][22] = 48, + [3][1][2][1][RTW89_MKK][0][22] = 8, + [3][1][2][1][RTW89_IC][1][22] = 30, + [3][1][2][1][RTW89_KCC][1][22] = 40, + [3][1][2][1][RTW89_KCC][0][22] = 12, + [3][1][2][1][RTW89_ACMA][1][22] = 42, + [3][1][2][1][RTW89_ACMA][0][22] = 6, + [3][1][2][1][RTW89_CHILE][1][22] = 30, + [3][1][2][1][RTW89_QATAR][1][22] = 42, + [3][1][2][1][RTW89_QATAR][0][22] = 6, + [3][1][2][1][RTW89_UK][1][22] = 42, + [3][1][2][1][RTW89_UK][0][22] = 6, + [3][1][2][1][RTW89_FCC][1][37] = 30, + [3][1][2][1][RTW89_FCC][2][37] = 52, + [3][1][2][1][RTW89_ETSI][1][37] = 42, + [3][1][2][1][RTW89_ETSI][0][37] = 6, + [3][1][2][1][RTW89_MKK][1][37] = 48, + [3][1][2][1][RTW89_MKK][0][37] = 8, + [3][1][2][1][RTW89_IC][1][37] = 30, + [3][1][2][1][RTW89_KCC][1][37] = 40, + [3][1][2][1][RTW89_KCC][0][37] = 12, + [3][1][2][1][RTW89_ACMA][1][37] = 42, + [3][1][2][1][RTW89_ACMA][0][37] = 6, + [3][1][2][1][RTW89_CHILE][1][37] = 30, + [3][1][2][1][RTW89_QATAR][1][37] = 42, + [3][1][2][1][RTW89_QATAR][0][37] = 6, + [3][1][2][1][RTW89_UK][1][37] = 42, + [3][1][2][1][RTW89_UK][0][37] = 6, + [3][1][2][1][RTW89_FCC][1][52] = 30, + [3][1][2][1][RTW89_FCC][2][52] = 127, + [3][1][2][1][RTW89_ETSI][1][52] = 127, + [3][1][2][1][RTW89_ETSI][0][52] = 127, + [3][1][2][1][RTW89_MKK][1][52] = 127, + [3][1][2][1][RTW89_MKK][0][52] = 127, + [3][1][2][1][RTW89_IC][1][52] = 30, + [3][1][2][1][RTW89_KCC][1][52] = 48, + [3][1][2][1][RTW89_KCC][0][52] = 127, + [3][1][2][1][RTW89_ACMA][1][52] = 127, + [3][1][2][1][RTW89_ACMA][0][52] = 127, + [3][1][2][1][RTW89_CHILE][1][52] = 30, + [3][1][2][1][RTW89_QATAR][1][52] = 127, + [3][1][2][1][RTW89_QATAR][0][52] = 127, + [3][1][2][1][RTW89_UK][1][52] = 127, + [3][1][2][1][RTW89_UK][0][52] = 127, + [3][1][2][1][RTW89_FCC][1][67] = 32, + [3][1][2][1][RTW89_FCC][2][67] = 54, + [3][1][2][1][RTW89_ETSI][1][67] = 127, + [3][1][2][1][RTW89_ETSI][0][67] = 127, + [3][1][2][1][RTW89_MKK][1][67] = 127, + [3][1][2][1][RTW89_MKK][0][67] = 127, + [3][1][2][1][RTW89_IC][1][67] = 32, + [3][1][2][1][RTW89_KCC][1][67] = 48, + [3][1][2][1][RTW89_KCC][0][67] = 127, + [3][1][2][1][RTW89_ACMA][1][67] = 127, + [3][1][2][1][RTW89_ACMA][0][67] = 127, + [3][1][2][1][RTW89_CHILE][1][67] = 32, + [3][1][2][1][RTW89_QATAR][1][67] = 127, + [3][1][2][1][RTW89_QATAR][0][67] = 127, + [3][1][2][1][RTW89_UK][1][67] = 127, + [3][1][2][1][RTW89_UK][0][67] = 127, + [3][1][2][1][RTW89_FCC][1][82] = 32, + [3][1][2][1][RTW89_FCC][2][82] = 127, + [3][1][2][1][RTW89_ETSI][1][82] = 127, + [3][1][2][1][RTW89_ETSI][0][82] = 127, + [3][1][2][1][RTW89_MKK][1][82] = 127, + [3][1][2][1][RTW89_MKK][0][82] = 127, + [3][1][2][1][RTW89_IC][1][82] = 32, + [3][1][2][1][RTW89_KCC][1][82] = 24, + [3][1][2][1][RTW89_KCC][0][82] = 127, + [3][1][2][1][RTW89_ACMA][1][82] = 127, + [3][1][2][1][RTW89_ACMA][0][82] = 127, + [3][1][2][1][RTW89_CHILE][1][82] = 32, + [3][1][2][1][RTW89_QATAR][1][82] = 127, + [3][1][2][1][RTW89_QATAR][0][82] = 127, + [3][1][2][1][RTW89_UK][1][82] = 127, + [3][1][2][1][RTW89_UK][0][82] = 127, + [3][1][2][1][RTW89_FCC][1][97] = 32, + [3][1][2][1][RTW89_FCC][2][97] = 127, + [3][1][2][1][RTW89_ETSI][1][97] = 127, + [3][1][2][1][RTW89_ETSI][0][97] = 127, + [3][1][2][1][RTW89_MKK][1][97] = 127, + [3][1][2][1][RTW89_MKK][0][97] = 127, + [3][1][2][1][RTW89_IC][1][97] = 32, + [3][1][2][1][RTW89_KCC][1][97] = 24, + [3][1][2][1][RTW89_KCC][0][97] = 127, + [3][1][2][1][RTW89_ACMA][1][97] = 127, + [3][1][2][1][RTW89_ACMA][0][97] = 127, + [3][1][2][1][RTW89_CHILE][1][97] = 32, + [3][1][2][1][RTW89_QATAR][1][97] = 127, + [3][1][2][1][RTW89_QATAR][0][97] = 127, + [3][1][2][1][RTW89_UK][1][97] = 127, + [3][1][2][1][RTW89_UK][0][97] = 127, + [3][1][2][1][RTW89_FCC][1][112] = 127, + [3][1][2][1][RTW89_FCC][2][112] = 127, + [3][1][2][1][RTW89_ETSI][1][112] = 127, + [3][1][2][1][RTW89_ETSI][0][112] = 127, + [3][1][2][1][RTW89_MKK][1][112] = 127, + [3][1][2][1][RTW89_MKK][0][112] = 127, + [3][1][2][1][RTW89_IC][1][112] = 127, + [3][1][2][1][RTW89_KCC][1][112] = 127, + [3][1][2][1][RTW89_KCC][0][112] = 127, + [3][1][2][1][RTW89_ACMA][1][112] = 127, + [3][1][2][1][RTW89_ACMA][0][112] = 127, + [3][1][2][1][RTW89_CHILE][1][112] = 127, + [3][1][2][1][RTW89_QATAR][1][112] = 127, + [3][1][2][1][RTW89_QATAR][0][112] = 127, + [3][1][2][1][RTW89_UK][1][112] = 127, + [3][1][2][1][RTW89_UK][0][112] = 127, }; static -- cgit v1.2.3 From dad142c3f56a2459b1f18cac63e1a436d0a31c84 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 2 Jun 2023 23:05:55 +0800 Subject: wifi: rtw89: 8852c: update TX power tables to R63 with 6 GHz power type (3 of 3) Update TX power tables to RF version R63. TX power tables' changes: * TX power byrate: tweak a bit * TX power limit, TX power limit RU, TX power shape: configure values for MEXICO, UKRAINE, CHILE, QATAR tweak a bit on other configured values * 6 GHz TX power limit, 6 GHz TX power limit RU: add an extra dimension for 6 GHz regulatory power type, i.e. STD (standard power), LPI (low power indoor), VLP (very low power) Besides, we adjust TX power handling at 6 GHz in phy to consider 6 GHz regulatory power type. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602150556.36777-8-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 3 +- drivers/net/wireless/realtek/rtw89/phy.c | 8 +- .../net/wireless/realtek/rtw89/rtw8852c_table.c | 8451 +++++++++++++++++--- 3 files changed, 7306 insertions(+), 1156 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 84dff8188dd2..7e1e508956c8 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3049,7 +3049,8 @@ struct rtw89_txpwr_rule_6ghz { [RTW89_REGD_NUM][NUM_OF_RTW89_REG_6GHZ_POWER] [RTW89_6G_CH_NUM]; const s8 (*lmt_ru)[RTW89_RU_NUM][RTW89_NTX_NUM] - [RTW89_REGD_NUM][RTW89_6G_CH_NUM]; + [RTW89_REGD_NUM][NUM_OF_RTW89_REG_6GHZ_POWER] + [RTW89_6G_CH_NUM]; }; struct rtw89_rfe_parms { diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 7152f093b8e6..e2eb9422a6bb 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1881,8 +1881,10 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, const struct rtw89_txpwr_rule_2ghz *rule_2ghz = &rfe_parms->rule_2ghz; const struct rtw89_txpwr_rule_5ghz *rule_5ghz = &rfe_parms->rule_5ghz; const struct rtw89_txpwr_rule_6ghz *rule_6ghz = &rfe_parms->rule_6ghz; + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; u8 ch_idx = rtw89_channel_to_idx(rtwdev, band, ch); u8 regd = rtw89_regd_get(rtwdev, band); + u8 reg6 = regulatory->reg_6ghz_power; s8 lmt_ru = 0, sar; switch (band) { @@ -1901,11 +1903,13 @@ static s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, lmt_ru = (*rule_5ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx]; break; case RTW89_BAND_6G: - lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][regd][ch_idx]; + lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][regd][reg6][ch_idx]; if (lmt_ru) break; - lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][RTW89_WW][ch_idx]; + lmt_ru = (*rule_6ghz->lmt_ru)[ru][ntx][RTW89_WW] + [RTW89_REG_6GHZ_POWER_DFLT] + [ch_idx]; break; default: rtw89_warn(rtwdev, "unknown band type: %d\n", band); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c index 5c59ff182c6e..25871a6fddd2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c @@ -46127,1159 +46127,7304 @@ const s8 rtw89_8852c_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] static const s8 rtw89_8852c_txpwr_lmt_ru_6g[RTW89_RU_NUM][RTW89_NTX_NUM] - [RTW89_REGD_NUM][RTW89_6G_CH_NUM] = { - [0][0][RTW89_WW][0] = -16, - [0][0][RTW89_WW][2] = -18, - [0][0][RTW89_WW][4] = -18, - [0][0][RTW89_WW][6] = -18, - [0][0][RTW89_WW][8] = -18, - [0][0][RTW89_WW][10] = -18, - [0][0][RTW89_WW][12] = -18, - [0][0][RTW89_WW][14] = -18, - [0][0][RTW89_WW][15] = -18, - [0][0][RTW89_WW][17] = -18, - [0][0][RTW89_WW][19] = -18, - [0][0][RTW89_WW][21] = -18, - [0][0][RTW89_WW][23] = -18, - [0][0][RTW89_WW][25] = -18, - [0][0][RTW89_WW][27] = -18, - [0][0][RTW89_WW][29] = -18, - [0][0][RTW89_WW][30] = -18, - [0][0][RTW89_WW][32] = -18, - [0][0][RTW89_WW][34] = -18, - [0][0][RTW89_WW][36] = -18, - [0][0][RTW89_WW][38] = -18, - [0][0][RTW89_WW][40] = -18, - [0][0][RTW89_WW][42] = -18, - [0][0][RTW89_WW][44] = -16, - [0][0][RTW89_WW][45] = -16, - [0][0][RTW89_WW][47] = -18, - [0][0][RTW89_WW][49] = -18, - [0][0][RTW89_WW][51] = -18, - [0][0][RTW89_WW][53] = -16, - [0][0][RTW89_WW][55] = -18, - [0][0][RTW89_WW][57] = -18, - [0][0][RTW89_WW][59] = -18, - [0][0][RTW89_WW][60] = -18, - [0][0][RTW89_WW][62] = -18, - [0][0][RTW89_WW][64] = -18, - [0][0][RTW89_WW][66] = -18, - [0][0][RTW89_WW][68] = -18, - [0][0][RTW89_WW][70] = -16, - [0][0][RTW89_WW][72] = -18, - [0][0][RTW89_WW][74] = -18, - [0][0][RTW89_WW][75] = -18, - [0][0][RTW89_WW][77] = -18, - [0][0][RTW89_WW][79] = -18, - [0][0][RTW89_WW][81] = -18, - [0][0][RTW89_WW][83] = -18, - [0][0][RTW89_WW][85] = -18, - [0][0][RTW89_WW][87] = -16, - [0][0][RTW89_WW][89] = -16, - [0][0][RTW89_WW][90] = -16, - [0][0][RTW89_WW][92] = -16, - [0][0][RTW89_WW][94] = -16, - [0][0][RTW89_WW][96] = -16, - [0][0][RTW89_WW][98] = -16, - [0][0][RTW89_WW][100] = -16, - [0][0][RTW89_WW][102] = -16, - [0][0][RTW89_WW][104] = -16, - [0][0][RTW89_WW][105] = -16, - [0][0][RTW89_WW][107] = -12, - [0][0][RTW89_WW][109] = -12, - [0][0][RTW89_WW][111] = 0, - [0][0][RTW89_WW][113] = 0, - [0][0][RTW89_WW][115] = 0, - [0][0][RTW89_WW][117] = 0, - [0][0][RTW89_WW][119] = 0, - [0][1][RTW89_WW][0] = -40, - [0][1][RTW89_WW][2] = -40, - [0][1][RTW89_WW][4] = -40, - [0][1][RTW89_WW][6] = -40, - [0][1][RTW89_WW][8] = -40, - [0][1][RTW89_WW][10] = -40, - [0][1][RTW89_WW][12] = -40, - [0][1][RTW89_WW][14] = -40, - [0][1][RTW89_WW][15] = -40, - [0][1][RTW89_WW][17] = -40, - [0][1][RTW89_WW][19] = -40, - [0][1][RTW89_WW][21] = -40, - [0][1][RTW89_WW][23] = -40, - [0][1][RTW89_WW][25] = -40, - [0][1][RTW89_WW][27] = -40, - [0][1][RTW89_WW][29] = -40, - [0][1][RTW89_WW][30] = -40, - [0][1][RTW89_WW][32] = -40, - [0][1][RTW89_WW][34] = -40, - [0][1][RTW89_WW][36] = -40, - [0][1][RTW89_WW][38] = -40, - [0][1][RTW89_WW][40] = -40, - [0][1][RTW89_WW][42] = -40, - [0][1][RTW89_WW][44] = -40, - [0][1][RTW89_WW][45] = -40, - [0][1][RTW89_WW][47] = -40, - [0][1][RTW89_WW][49] = -40, - [0][1][RTW89_WW][51] = -40, - [0][1][RTW89_WW][53] = -40, - [0][1][RTW89_WW][55] = -40, - [0][1][RTW89_WW][57] = -40, - [0][1][RTW89_WW][59] = -40, - [0][1][RTW89_WW][60] = -40, - [0][1][RTW89_WW][62] = -40, - [0][1][RTW89_WW][64] = -40, - [0][1][RTW89_WW][66] = -40, - [0][1][RTW89_WW][68] = -40, - [0][1][RTW89_WW][70] = -38, - [0][1][RTW89_WW][72] = -38, - [0][1][RTW89_WW][74] = -38, - [0][1][RTW89_WW][75] = -38, - [0][1][RTW89_WW][77] = -38, - [0][1][RTW89_WW][79] = -38, - [0][1][RTW89_WW][81] = -38, - [0][1][RTW89_WW][83] = -38, - [0][1][RTW89_WW][85] = -38, - [0][1][RTW89_WW][87] = -40, - [0][1][RTW89_WW][89] = -38, - [0][1][RTW89_WW][90] = -38, - [0][1][RTW89_WW][92] = -38, - [0][1][RTW89_WW][94] = -38, - [0][1][RTW89_WW][96] = -38, - [0][1][RTW89_WW][98] = -38, - [0][1][RTW89_WW][100] = -38, - [0][1][RTW89_WW][102] = -38, - [0][1][RTW89_WW][104] = -38, - [0][1][RTW89_WW][105] = -38, - [0][1][RTW89_WW][107] = -34, - [0][1][RTW89_WW][109] = -34, - [0][1][RTW89_WW][111] = 0, - [0][1][RTW89_WW][113] = 0, - [0][1][RTW89_WW][115] = 0, - [0][1][RTW89_WW][117] = 0, - [0][1][RTW89_WW][119] = 0, - [1][0][RTW89_WW][0] = -4, - [1][0][RTW89_WW][2] = -4, - [1][0][RTW89_WW][4] = -4, - [1][0][RTW89_WW][6] = -4, - [1][0][RTW89_WW][8] = -4, - [1][0][RTW89_WW][10] = -4, - [1][0][RTW89_WW][12] = -4, - [1][0][RTW89_WW][14] = -4, - [1][0][RTW89_WW][15] = -4, - [1][0][RTW89_WW][17] = -4, - [1][0][RTW89_WW][19] = -4, - [1][0][RTW89_WW][21] = -4, - [1][0][RTW89_WW][23] = -4, - [1][0][RTW89_WW][25] = -4, - [1][0][RTW89_WW][27] = -4, - [1][0][RTW89_WW][29] = -4, - [1][0][RTW89_WW][30] = -4, - [1][0][RTW89_WW][32] = -4, - [1][0][RTW89_WW][34] = -4, - [1][0][RTW89_WW][36] = -4, - [1][0][RTW89_WW][38] = -4, - [1][0][RTW89_WW][40] = -4, - [1][0][RTW89_WW][42] = -4, - [1][0][RTW89_WW][44] = -4, - [1][0][RTW89_WW][45] = -4, - [1][0][RTW89_WW][47] = -4, - [1][0][RTW89_WW][49] = -4, - [1][0][RTW89_WW][51] = -4, - [1][0][RTW89_WW][53] = -4, - [1][0][RTW89_WW][55] = -4, - [1][0][RTW89_WW][57] = -4, - [1][0][RTW89_WW][59] = -4, - [1][0][RTW89_WW][60] = -4, - [1][0][RTW89_WW][62] = -4, - [1][0][RTW89_WW][64] = -4, - [1][0][RTW89_WW][66] = -4, - [1][0][RTW89_WW][68] = -4, - [1][0][RTW89_WW][70] = -4, - [1][0][RTW89_WW][72] = -4, - [1][0][RTW89_WW][74] = -4, - [1][0][RTW89_WW][75] = -4, - [1][0][RTW89_WW][77] = -4, - [1][0][RTW89_WW][79] = -4, - [1][0][RTW89_WW][81] = -4, - [1][0][RTW89_WW][83] = -4, - [1][0][RTW89_WW][85] = -4, - [1][0][RTW89_WW][87] = -4, - [1][0][RTW89_WW][89] = -4, - [1][0][RTW89_WW][90] = -4, - [1][0][RTW89_WW][92] = -4, - [1][0][RTW89_WW][94] = -4, - [1][0][RTW89_WW][96] = -4, - [1][0][RTW89_WW][98] = -4, - [1][0][RTW89_WW][100] = -4, - [1][0][RTW89_WW][102] = -4, - [1][0][RTW89_WW][104] = -4, - [1][0][RTW89_WW][105] = -4, - [1][0][RTW89_WW][107] = 1, - [1][0][RTW89_WW][109] = 2, - [1][0][RTW89_WW][111] = 0, - [1][0][RTW89_WW][113] = 0, - [1][0][RTW89_WW][115] = 0, - [1][0][RTW89_WW][117] = 0, - [1][0][RTW89_WW][119] = 0, - [1][1][RTW89_WW][0] = -26, - [1][1][RTW89_WW][2] = -28, - [1][1][RTW89_WW][4] = -28, - [1][1][RTW89_WW][6] = -28, - [1][1][RTW89_WW][8] = -28, - [1][1][RTW89_WW][10] = -28, - [1][1][RTW89_WW][12] = -28, - [1][1][RTW89_WW][14] = -28, - [1][1][RTW89_WW][15] = -28, - [1][1][RTW89_WW][17] = -28, - [1][1][RTW89_WW][19] = -28, - [1][1][RTW89_WW][21] = -28, - [1][1][RTW89_WW][23] = -28, - [1][1][RTW89_WW][25] = -28, - [1][1][RTW89_WW][27] = -28, - [1][1][RTW89_WW][29] = -28, - [1][1][RTW89_WW][30] = -28, - [1][1][RTW89_WW][32] = -28, - [1][1][RTW89_WW][34] = -28, - [1][1][RTW89_WW][36] = -28, - [1][1][RTW89_WW][38] = -28, - [1][1][RTW89_WW][40] = -28, - [1][1][RTW89_WW][42] = -28, - [1][1][RTW89_WW][44] = -28, - [1][1][RTW89_WW][45] = -26, - [1][1][RTW89_WW][47] = -28, - [1][1][RTW89_WW][49] = -28, - [1][1][RTW89_WW][51] = -28, - [1][1][RTW89_WW][53] = -26, - [1][1][RTW89_WW][55] = -28, - [1][1][RTW89_WW][57] = -28, - [1][1][RTW89_WW][59] = -28, - [1][1][RTW89_WW][60] = -28, - [1][1][RTW89_WW][62] = -28, - [1][1][RTW89_WW][64] = -28, - [1][1][RTW89_WW][66] = -28, - [1][1][RTW89_WW][68] = -28, - [1][1][RTW89_WW][70] = -26, - [1][1][RTW89_WW][72] = -28, - [1][1][RTW89_WW][74] = -28, - [1][1][RTW89_WW][75] = -28, - [1][1][RTW89_WW][77] = -28, - [1][1][RTW89_WW][79] = -28, - [1][1][RTW89_WW][81] = -28, - [1][1][RTW89_WW][83] = -28, - [1][1][RTW89_WW][85] = -28, - [1][1][RTW89_WW][87] = -28, - [1][1][RTW89_WW][89] = -26, - [1][1][RTW89_WW][90] = -26, - [1][1][RTW89_WW][92] = -26, - [1][1][RTW89_WW][94] = -26, - [1][1][RTW89_WW][96] = -26, - [1][1][RTW89_WW][98] = -26, - [1][1][RTW89_WW][100] = -26, - [1][1][RTW89_WW][102] = -26, - [1][1][RTW89_WW][104] = -26, - [1][1][RTW89_WW][105] = -26, - [1][1][RTW89_WW][107] = -22, - [1][1][RTW89_WW][109] = -22, - [1][1][RTW89_WW][111] = 0, - [1][1][RTW89_WW][113] = 0, - [1][1][RTW89_WW][115] = 0, - [1][1][RTW89_WW][117] = 0, - [1][1][RTW89_WW][119] = 0, - [2][0][RTW89_WW][0] = 8, - [2][0][RTW89_WW][2] = 8, - [2][0][RTW89_WW][4] = 8, - [2][0][RTW89_WW][6] = 8, - [2][0][RTW89_WW][8] = 8, - [2][0][RTW89_WW][10] = 8, - [2][0][RTW89_WW][12] = 8, - [2][0][RTW89_WW][14] = 8, - [2][0][RTW89_WW][15] = 8, - [2][0][RTW89_WW][17] = 8, - [2][0][RTW89_WW][19] = 8, - [2][0][RTW89_WW][21] = 8, - [2][0][RTW89_WW][23] = 8, - [2][0][RTW89_WW][25] = 8, - [2][0][RTW89_WW][27] = 8, - [2][0][RTW89_WW][29] = 8, - [2][0][RTW89_WW][30] = 8, - [2][0][RTW89_WW][32] = 8, - [2][0][RTW89_WW][34] = 8, - [2][0][RTW89_WW][36] = 8, - [2][0][RTW89_WW][38] = 8, - [2][0][RTW89_WW][40] = 8, - [2][0][RTW89_WW][42] = 8, - [2][0][RTW89_WW][44] = 8, - [2][0][RTW89_WW][45] = 8, - [2][0][RTW89_WW][47] = 8, - [2][0][RTW89_WW][49] = 8, - [2][0][RTW89_WW][51] = 8, - [2][0][RTW89_WW][53] = 8, - [2][0][RTW89_WW][55] = 8, - [2][0][RTW89_WW][57] = 8, - [2][0][RTW89_WW][59] = 8, - [2][0][RTW89_WW][60] = 8, - [2][0][RTW89_WW][62] = 8, - [2][0][RTW89_WW][64] = 8, - [2][0][RTW89_WW][66] = 8, - [2][0][RTW89_WW][68] = 8, - [2][0][RTW89_WW][70] = 8, - [2][0][RTW89_WW][72] = 8, - [2][0][RTW89_WW][74] = 8, - [2][0][RTW89_WW][75] = 8, - [2][0][RTW89_WW][77] = 8, - [2][0][RTW89_WW][79] = 8, - [2][0][RTW89_WW][81] = 8, - [2][0][RTW89_WW][83] = 8, - [2][0][RTW89_WW][85] = 8, - [2][0][RTW89_WW][87] = 8, - [2][0][RTW89_WW][89] = 8, - [2][0][RTW89_WW][90] = 8, - [2][0][RTW89_WW][92] = 8, - [2][0][RTW89_WW][94] = 8, - [2][0][RTW89_WW][96] = 8, - [2][0][RTW89_WW][98] = 8, - [2][0][RTW89_WW][100] = 8, - [2][0][RTW89_WW][102] = 8, - [2][0][RTW89_WW][104] = 8, - [2][0][RTW89_WW][105] = 8, - [2][0][RTW89_WW][107] = 10, - [2][0][RTW89_WW][109] = 12, - [2][0][RTW89_WW][111] = 0, - [2][0][RTW89_WW][113] = 0, - [2][0][RTW89_WW][115] = 0, - [2][0][RTW89_WW][117] = 0, - [2][0][RTW89_WW][119] = 0, - [2][1][RTW89_WW][0] = -16, - [2][1][RTW89_WW][2] = -16, - [2][1][RTW89_WW][4] = -16, - [2][1][RTW89_WW][6] = -16, - [2][1][RTW89_WW][8] = -16, - [2][1][RTW89_WW][10] = -16, - [2][1][RTW89_WW][12] = -16, - [2][1][RTW89_WW][14] = -16, - [2][1][RTW89_WW][15] = -16, - [2][1][RTW89_WW][17] = -16, - [2][1][RTW89_WW][19] = -16, - [2][1][RTW89_WW][21] = -16, - [2][1][RTW89_WW][23] = -16, - [2][1][RTW89_WW][25] = -16, - [2][1][RTW89_WW][27] = -16, - [2][1][RTW89_WW][29] = -16, - [2][1][RTW89_WW][30] = -16, - [2][1][RTW89_WW][32] = -16, - [2][1][RTW89_WW][34] = -16, - [2][1][RTW89_WW][36] = -16, - [2][1][RTW89_WW][38] = -16, - [2][1][RTW89_WW][40] = -16, - [2][1][RTW89_WW][42] = -16, - [2][1][RTW89_WW][44] = -16, - [2][1][RTW89_WW][45] = -16, - [2][1][RTW89_WW][47] = -16, - [2][1][RTW89_WW][49] = -16, - [2][1][RTW89_WW][51] = -16, - [2][1][RTW89_WW][53] = -16, - [2][1][RTW89_WW][55] = -16, - [2][1][RTW89_WW][57] = -16, - [2][1][RTW89_WW][59] = -16, - [2][1][RTW89_WW][60] = -16, - [2][1][RTW89_WW][62] = -16, - [2][1][RTW89_WW][64] = -16, - [2][1][RTW89_WW][66] = -16, - [2][1][RTW89_WW][68] = -16, - [2][1][RTW89_WW][70] = -16, - [2][1][RTW89_WW][72] = -16, - [2][1][RTW89_WW][74] = -16, - [2][1][RTW89_WW][75] = -16, - [2][1][RTW89_WW][77] = -16, - [2][1][RTW89_WW][79] = -16, - [2][1][RTW89_WW][81] = -16, - [2][1][RTW89_WW][83] = -16, - [2][1][RTW89_WW][85] = -18, - [2][1][RTW89_WW][87] = -16, - [2][1][RTW89_WW][89] = -16, - [2][1][RTW89_WW][90] = -16, - [2][1][RTW89_WW][92] = -16, - [2][1][RTW89_WW][94] = -16, - [2][1][RTW89_WW][96] = -16, - [2][1][RTW89_WW][98] = -16, - [2][1][RTW89_WW][100] = -16, - [2][1][RTW89_WW][102] = -16, - [2][1][RTW89_WW][104] = -16, - [2][1][RTW89_WW][105] = -16, - [2][1][RTW89_WW][107] = -12, - [2][1][RTW89_WW][109] = -10, - [2][1][RTW89_WW][111] = 0, - [2][1][RTW89_WW][113] = 0, - [2][1][RTW89_WW][115] = 0, - [2][1][RTW89_WW][117] = 0, - [2][1][RTW89_WW][119] = 0, - [0][0][RTW89_FCC][0] = -16, - [0][0][RTW89_ETSI][0] = 32, - [0][0][RTW89_FCC][2] = -18, - [0][0][RTW89_ETSI][2] = 32, - [0][0][RTW89_FCC][4] = -18, - [0][0][RTW89_ETSI][4] = 32, - [0][0][RTW89_FCC][6] = -18, - [0][0][RTW89_ETSI][6] = 32, - [0][0][RTW89_FCC][8] = -18, - [0][0][RTW89_ETSI][8] = 32, - [0][0][RTW89_FCC][10] = -18, - [0][0][RTW89_ETSI][10] = 32, - [0][0][RTW89_FCC][12] = -18, - [0][0][RTW89_ETSI][12] = 32, - [0][0][RTW89_FCC][14] = -18, - [0][0][RTW89_ETSI][14] = 32, - [0][0][RTW89_FCC][15] = -18, - [0][0][RTW89_ETSI][15] = 32, - [0][0][RTW89_FCC][17] = -18, - [0][0][RTW89_ETSI][17] = 32, - [0][0][RTW89_FCC][19] = -18, - [0][0][RTW89_ETSI][19] = 32, - [0][0][RTW89_FCC][21] = -18, - [0][0][RTW89_ETSI][21] = 32, - [0][0][RTW89_FCC][23] = -18, - [0][0][RTW89_ETSI][23] = 32, - [0][0][RTW89_FCC][25] = -18, - [0][0][RTW89_ETSI][25] = 32, - [0][0][RTW89_FCC][27] = -18, - [0][0][RTW89_ETSI][27] = 32, - [0][0][RTW89_FCC][29] = -18, - [0][0][RTW89_ETSI][29] = 32, - [0][0][RTW89_FCC][30] = -18, - [0][0][RTW89_ETSI][30] = 32, - [0][0][RTW89_FCC][32] = -18, - [0][0][RTW89_ETSI][32] = 32, - [0][0][RTW89_FCC][34] = -18, - [0][0][RTW89_ETSI][34] = 32, - [0][0][RTW89_FCC][36] = -18, - [0][0][RTW89_ETSI][36] = 32, - [0][0][RTW89_FCC][38] = -18, - [0][0][RTW89_ETSI][38] = 32, - [0][0][RTW89_FCC][40] = -18, - [0][0][RTW89_ETSI][40] = 32, - [0][0][RTW89_FCC][42] = -18, - [0][0][RTW89_ETSI][42] = 32, - [0][0][RTW89_FCC][44] = -16, - [0][0][RTW89_ETSI][44] = 32, - [0][0][RTW89_FCC][45] = -16, - [0][0][RTW89_ETSI][45] = 127, - [0][0][RTW89_FCC][47] = -18, - [0][0][RTW89_ETSI][47] = 127, - [0][0][RTW89_FCC][49] = -18, - [0][0][RTW89_ETSI][49] = 127, - [0][0][RTW89_FCC][51] = -18, - [0][0][RTW89_ETSI][51] = 127, - [0][0][RTW89_FCC][53] = -16, - [0][0][RTW89_ETSI][53] = 127, - [0][0][RTW89_FCC][55] = -18, - [0][0][RTW89_ETSI][55] = 127, - [0][0][RTW89_FCC][57] = -18, - [0][0][RTW89_ETSI][57] = 127, - [0][0][RTW89_FCC][59] = -18, - [0][0][RTW89_ETSI][59] = 127, - [0][0][RTW89_FCC][60] = -18, - [0][0][RTW89_ETSI][60] = 127, - [0][0][RTW89_FCC][62] = -18, - [0][0][RTW89_ETSI][62] = 127, - [0][0][RTW89_FCC][64] = -18, - [0][0][RTW89_ETSI][64] = 127, - [0][0][RTW89_FCC][66] = -18, - [0][0][RTW89_ETSI][66] = 127, - [0][0][RTW89_FCC][68] = -18, - [0][0][RTW89_ETSI][68] = 127, - [0][0][RTW89_FCC][70] = -16, - [0][0][RTW89_ETSI][70] = 127, - [0][0][RTW89_FCC][72] = -18, - [0][0][RTW89_ETSI][72] = 127, - [0][0][RTW89_FCC][74] = -18, - [0][0][RTW89_ETSI][74] = 127, - [0][0][RTW89_FCC][75] = -18, - [0][0][RTW89_ETSI][75] = 127, - [0][0][RTW89_FCC][77] = -18, - [0][0][RTW89_ETSI][77] = 127, - [0][0][RTW89_FCC][79] = -18, - [0][0][RTW89_ETSI][79] = 127, - [0][0][RTW89_FCC][81] = -18, - [0][0][RTW89_ETSI][81] = 127, - [0][0][RTW89_FCC][83] = -18, - [0][0][RTW89_ETSI][83] = 127, - [0][0][RTW89_FCC][85] = -18, - [0][0][RTW89_ETSI][85] = 127, - [0][0][RTW89_FCC][87] = -16, - [0][0][RTW89_ETSI][87] = 127, - [0][0][RTW89_FCC][89] = -16, - [0][0][RTW89_ETSI][89] = 127, - [0][0][RTW89_FCC][90] = -16, - [0][0][RTW89_ETSI][90] = 127, - [0][0][RTW89_FCC][92] = -16, - [0][0][RTW89_ETSI][92] = 127, - [0][0][RTW89_FCC][94] = -16, - [0][0][RTW89_ETSI][94] = 127, - [0][0][RTW89_FCC][96] = -16, - [0][0][RTW89_ETSI][96] = 127, - [0][0][RTW89_FCC][98] = -16, - [0][0][RTW89_ETSI][98] = 127, - [0][0][RTW89_FCC][100] = -16, - [0][0][RTW89_ETSI][100] = 127, - [0][0][RTW89_FCC][102] = -16, - [0][0][RTW89_ETSI][102] = 127, - [0][0][RTW89_FCC][104] = -16, - [0][0][RTW89_ETSI][104] = 127, - [0][0][RTW89_FCC][105] = -16, - [0][0][RTW89_ETSI][105] = 127, - [0][0][RTW89_FCC][107] = -12, - [0][0][RTW89_ETSI][107] = 127, - [0][0][RTW89_FCC][109] = -12, - [0][0][RTW89_ETSI][109] = 127, - [0][0][RTW89_FCC][111] = 127, - [0][0][RTW89_ETSI][111] = 127, - [0][0][RTW89_FCC][113] = 127, - [0][0][RTW89_ETSI][113] = 127, - [0][0][RTW89_FCC][115] = 127, - [0][0][RTW89_ETSI][115] = 127, - [0][0][RTW89_FCC][117] = 127, - [0][0][RTW89_ETSI][117] = 127, - [0][0][RTW89_FCC][119] = 127, - [0][0][RTW89_ETSI][119] = 127, - [0][1][RTW89_FCC][0] = -40, - [0][1][RTW89_ETSI][0] = 20, - [0][1][RTW89_FCC][2] = -40, - [0][1][RTW89_ETSI][2] = 20, - [0][1][RTW89_FCC][4] = -40, - [0][1][RTW89_ETSI][4] = 20, - [0][1][RTW89_FCC][6] = -40, - [0][1][RTW89_ETSI][6] = 20, - [0][1][RTW89_FCC][8] = -40, - [0][1][RTW89_ETSI][8] = 20, - [0][1][RTW89_FCC][10] = -40, - [0][1][RTW89_ETSI][10] = 20, - [0][1][RTW89_FCC][12] = -40, - [0][1][RTW89_ETSI][12] = 20, - [0][1][RTW89_FCC][14] = -40, - [0][1][RTW89_ETSI][14] = 20, - [0][1][RTW89_FCC][15] = -40, - [0][1][RTW89_ETSI][15] = 20, - [0][1][RTW89_FCC][17] = -40, - [0][1][RTW89_ETSI][17] = 20, - [0][1][RTW89_FCC][19] = -40, - [0][1][RTW89_ETSI][19] = 20, - [0][1][RTW89_FCC][21] = -40, - [0][1][RTW89_ETSI][21] = 20, - [0][1][RTW89_FCC][23] = -40, - [0][1][RTW89_ETSI][23] = 20, - [0][1][RTW89_FCC][25] = -40, - [0][1][RTW89_ETSI][25] = 20, - [0][1][RTW89_FCC][27] = -40, - [0][1][RTW89_ETSI][27] = 20, - [0][1][RTW89_FCC][29] = -40, - [0][1][RTW89_ETSI][29] = 20, - [0][1][RTW89_FCC][30] = -40, - [0][1][RTW89_ETSI][30] = 20, - [0][1][RTW89_FCC][32] = -40, - [0][1][RTW89_ETSI][32] = 20, - [0][1][RTW89_FCC][34] = -40, - [0][1][RTW89_ETSI][34] = 20, - [0][1][RTW89_FCC][36] = -40, - [0][1][RTW89_ETSI][36] = 20, - [0][1][RTW89_FCC][38] = -40, - [0][1][RTW89_ETSI][38] = 20, - [0][1][RTW89_FCC][40] = -40, - [0][1][RTW89_ETSI][40] = 20, - [0][1][RTW89_FCC][42] = -40, - [0][1][RTW89_ETSI][42] = 20, - [0][1][RTW89_FCC][44] = -40, - [0][1][RTW89_ETSI][44] = 20, - [0][1][RTW89_FCC][45] = -40, - [0][1][RTW89_ETSI][45] = 127, - [0][1][RTW89_FCC][47] = -40, - [0][1][RTW89_ETSI][47] = 127, - [0][1][RTW89_FCC][49] = -40, - [0][1][RTW89_ETSI][49] = 127, - [0][1][RTW89_FCC][51] = -40, - [0][1][RTW89_ETSI][51] = 127, - [0][1][RTW89_FCC][53] = -40, - [0][1][RTW89_ETSI][53] = 127, - [0][1][RTW89_FCC][55] = -40, - [0][1][RTW89_ETSI][55] = 127, - [0][1][RTW89_FCC][57] = -40, - [0][1][RTW89_ETSI][57] = 127, - [0][1][RTW89_FCC][59] = -40, - [0][1][RTW89_ETSI][59] = 127, - [0][1][RTW89_FCC][60] = -40, - [0][1][RTW89_ETSI][60] = 127, - [0][1][RTW89_FCC][62] = -40, - [0][1][RTW89_ETSI][62] = 127, - [0][1][RTW89_FCC][64] = -40, - [0][1][RTW89_ETSI][64] = 127, - [0][1][RTW89_FCC][66] = -40, - [0][1][RTW89_ETSI][66] = 127, - [0][1][RTW89_FCC][68] = -40, - [0][1][RTW89_ETSI][68] = 127, - [0][1][RTW89_FCC][70] = -38, - [0][1][RTW89_ETSI][70] = 127, - [0][1][RTW89_FCC][72] = -38, - [0][1][RTW89_ETSI][72] = 127, - [0][1][RTW89_FCC][74] = -38, - [0][1][RTW89_ETSI][74] = 127, - [0][1][RTW89_FCC][75] = -38, - [0][1][RTW89_ETSI][75] = 127, - [0][1][RTW89_FCC][77] = -38, - [0][1][RTW89_ETSI][77] = 127, - [0][1][RTW89_FCC][79] = -38, - [0][1][RTW89_ETSI][79] = 127, - [0][1][RTW89_FCC][81] = -38, - [0][1][RTW89_ETSI][81] = 127, - [0][1][RTW89_FCC][83] = -38, - [0][1][RTW89_ETSI][83] = 127, - [0][1][RTW89_FCC][85] = -38, - [0][1][RTW89_ETSI][85] = 127, - [0][1][RTW89_FCC][87] = -40, - [0][1][RTW89_ETSI][87] = 127, - [0][1][RTW89_FCC][89] = -38, - [0][1][RTW89_ETSI][89] = 127, - [0][1][RTW89_FCC][90] = -38, - [0][1][RTW89_ETSI][90] = 127, - [0][1][RTW89_FCC][92] = -38, - [0][1][RTW89_ETSI][92] = 127, - [0][1][RTW89_FCC][94] = -38, - [0][1][RTW89_ETSI][94] = 127, - [0][1][RTW89_FCC][96] = -38, - [0][1][RTW89_ETSI][96] = 127, - [0][1][RTW89_FCC][98] = -38, - [0][1][RTW89_ETSI][98] = 127, - [0][1][RTW89_FCC][100] = -38, - [0][1][RTW89_ETSI][100] = 127, - [0][1][RTW89_FCC][102] = -38, - [0][1][RTW89_ETSI][102] = 127, - [0][1][RTW89_FCC][104] = -38, - [0][1][RTW89_ETSI][104] = 127, - [0][1][RTW89_FCC][105] = -38, - [0][1][RTW89_ETSI][105] = 127, - [0][1][RTW89_FCC][107] = -34, - [0][1][RTW89_ETSI][107] = 127, - [0][1][RTW89_FCC][109] = -34, - [0][1][RTW89_ETSI][109] = 127, - [0][1][RTW89_FCC][111] = 127, - [0][1][RTW89_ETSI][111] = 127, - [0][1][RTW89_FCC][113] = 127, - [0][1][RTW89_ETSI][113] = 127, - [0][1][RTW89_FCC][115] = 127, - [0][1][RTW89_ETSI][115] = 127, - [0][1][RTW89_FCC][117] = 127, - [0][1][RTW89_ETSI][117] = 127, - [0][1][RTW89_FCC][119] = 127, - [0][1][RTW89_ETSI][119] = 127, - [1][0][RTW89_FCC][0] = -4, - [1][0][RTW89_ETSI][0] = 46, - [1][0][RTW89_FCC][2] = -4, - [1][0][RTW89_ETSI][2] = 46, - [1][0][RTW89_FCC][4] = -4, - [1][0][RTW89_ETSI][4] = 46, - [1][0][RTW89_FCC][6] = -4, - [1][0][RTW89_ETSI][6] = 46, - [1][0][RTW89_FCC][8] = -4, - [1][0][RTW89_ETSI][8] = 46, - [1][0][RTW89_FCC][10] = -4, - [1][0][RTW89_ETSI][10] = 46, - [1][0][RTW89_FCC][12] = -4, - [1][0][RTW89_ETSI][12] = 46, - [1][0][RTW89_FCC][14] = -4, - [1][0][RTW89_ETSI][14] = 46, - [1][0][RTW89_FCC][15] = -4, - [1][0][RTW89_ETSI][15] = 46, - [1][0][RTW89_FCC][17] = -4, - [1][0][RTW89_ETSI][17] = 46, - [1][0][RTW89_FCC][19] = -4, - [1][0][RTW89_ETSI][19] = 46, - [1][0][RTW89_FCC][21] = -4, - [1][0][RTW89_ETSI][21] = 46, - [1][0][RTW89_FCC][23] = -4, - [1][0][RTW89_ETSI][23] = 46, - [1][0][RTW89_FCC][25] = -4, - [1][0][RTW89_ETSI][25] = 46, - [1][0][RTW89_FCC][27] = -4, - [1][0][RTW89_ETSI][27] = 46, - [1][0][RTW89_FCC][29] = -4, - [1][0][RTW89_ETSI][29] = 46, - [1][0][RTW89_FCC][30] = -4, - [1][0][RTW89_ETSI][30] = 46, - [1][0][RTW89_FCC][32] = -4, - [1][0][RTW89_ETSI][32] = 46, - [1][0][RTW89_FCC][34] = -4, - [1][0][RTW89_ETSI][34] = 46, - [1][0][RTW89_FCC][36] = -4, - [1][0][RTW89_ETSI][36] = 46, - [1][0][RTW89_FCC][38] = -4, - [1][0][RTW89_ETSI][38] = 46, - [1][0][RTW89_FCC][40] = -4, - [1][0][RTW89_ETSI][40] = 46, - [1][0][RTW89_FCC][42] = -4, - [1][0][RTW89_ETSI][42] = 46, - [1][0][RTW89_FCC][44] = -4, - [1][0][RTW89_ETSI][44] = 46, - [1][0][RTW89_FCC][45] = -4, - [1][0][RTW89_ETSI][45] = 127, - [1][0][RTW89_FCC][47] = -4, - [1][0][RTW89_ETSI][47] = 127, - [1][0][RTW89_FCC][49] = -4, - [1][0][RTW89_ETSI][49] = 127, - [1][0][RTW89_FCC][51] = -4, - [1][0][RTW89_ETSI][51] = 127, - [1][0][RTW89_FCC][53] = -4, - [1][0][RTW89_ETSI][53] = 127, - [1][0][RTW89_FCC][55] = -4, - [1][0][RTW89_ETSI][55] = 127, - [1][0][RTW89_FCC][57] = -4, - [1][0][RTW89_ETSI][57] = 127, - [1][0][RTW89_FCC][59] = -4, - [1][0][RTW89_ETSI][59] = 127, - [1][0][RTW89_FCC][60] = -4, - [1][0][RTW89_ETSI][60] = 127, - [1][0][RTW89_FCC][62] = -4, - [1][0][RTW89_ETSI][62] = 127, - [1][0][RTW89_FCC][64] = -4, - [1][0][RTW89_ETSI][64] = 127, - [1][0][RTW89_FCC][66] = -4, - [1][0][RTW89_ETSI][66] = 127, - [1][0][RTW89_FCC][68] = -4, - [1][0][RTW89_ETSI][68] = 127, - [1][0][RTW89_FCC][70] = -4, - [1][0][RTW89_ETSI][70] = 127, - [1][0][RTW89_FCC][72] = -4, - [1][0][RTW89_ETSI][72] = 127, - [1][0][RTW89_FCC][74] = -4, - [1][0][RTW89_ETSI][74] = 127, - [1][0][RTW89_FCC][75] = -4, - [1][0][RTW89_ETSI][75] = 127, - [1][0][RTW89_FCC][77] = -4, - [1][0][RTW89_ETSI][77] = 127, - [1][0][RTW89_FCC][79] = -4, - [1][0][RTW89_ETSI][79] = 127, - [1][0][RTW89_FCC][81] = -4, - [1][0][RTW89_ETSI][81] = 127, - [1][0][RTW89_FCC][83] = -4, - [1][0][RTW89_ETSI][83] = 127, - [1][0][RTW89_FCC][85] = -4, - [1][0][RTW89_ETSI][85] = 127, - [1][0][RTW89_FCC][87] = -4, - [1][0][RTW89_ETSI][87] = 127, - [1][0][RTW89_FCC][89] = -4, - [1][0][RTW89_ETSI][89] = 127, - [1][0][RTW89_FCC][90] = -4, - [1][0][RTW89_ETSI][90] = 127, - [1][0][RTW89_FCC][92] = -4, - [1][0][RTW89_ETSI][92] = 127, - [1][0][RTW89_FCC][94] = -4, - [1][0][RTW89_ETSI][94] = 127, - [1][0][RTW89_FCC][96] = -4, - [1][0][RTW89_ETSI][96] = 127, - [1][0][RTW89_FCC][98] = -4, - [1][0][RTW89_ETSI][98] = 127, - [1][0][RTW89_FCC][100] = -4, - [1][0][RTW89_ETSI][100] = 127, - [1][0][RTW89_FCC][102] = -4, - [1][0][RTW89_ETSI][102] = 127, - [1][0][RTW89_FCC][104] = -4, - [1][0][RTW89_ETSI][104] = 127, - [1][0][RTW89_FCC][105] = -4, - [1][0][RTW89_ETSI][105] = 127, - [1][0][RTW89_FCC][107] = 0, - [1][0][RTW89_ETSI][107] = 127, - [1][0][RTW89_FCC][109] = 2, - [1][0][RTW89_ETSI][109] = 127, - [1][0][RTW89_FCC][111] = 127, - [1][0][RTW89_ETSI][111] = 127, - [1][0][RTW89_FCC][113] = 127, - [1][0][RTW89_ETSI][113] = 127, - [1][0][RTW89_FCC][115] = 127, - [1][0][RTW89_ETSI][115] = 127, - [1][0][RTW89_FCC][117] = 127, - [1][0][RTW89_ETSI][117] = 127, - [1][0][RTW89_FCC][119] = 127, - [1][0][RTW89_ETSI][119] = 127, - [1][1][RTW89_FCC][0] = -26, - [1][1][RTW89_ETSI][0] = 32, - [1][1][RTW89_FCC][2] = -28, - [1][1][RTW89_ETSI][2] = 32, - [1][1][RTW89_FCC][4] = -28, - [1][1][RTW89_ETSI][4] = 32, - [1][1][RTW89_FCC][6] = -28, - [1][1][RTW89_ETSI][6] = 32, - [1][1][RTW89_FCC][8] = -28, - [1][1][RTW89_ETSI][8] = 32, - [1][1][RTW89_FCC][10] = -28, - [1][1][RTW89_ETSI][10] = 32, - [1][1][RTW89_FCC][12] = -28, - [1][1][RTW89_ETSI][12] = 32, - [1][1][RTW89_FCC][14] = -28, - [1][1][RTW89_ETSI][14] = 32, - [1][1][RTW89_FCC][15] = -28, - [1][1][RTW89_ETSI][15] = 32, - [1][1][RTW89_FCC][17] = -28, - [1][1][RTW89_ETSI][17] = 32, - [1][1][RTW89_FCC][19] = -28, - [1][1][RTW89_ETSI][19] = 32, - [1][1][RTW89_FCC][21] = -28, - [1][1][RTW89_ETSI][21] = 32, - [1][1][RTW89_FCC][23] = -28, - [1][1][RTW89_ETSI][23] = 32, - [1][1][RTW89_FCC][25] = -28, - [1][1][RTW89_ETSI][25] = 32, - [1][1][RTW89_FCC][27] = -28, - [1][1][RTW89_ETSI][27] = 32, - [1][1][RTW89_FCC][29] = -28, - [1][1][RTW89_ETSI][29] = 32, - [1][1][RTW89_FCC][30] = -28, - [1][1][RTW89_ETSI][30] = 32, - [1][1][RTW89_FCC][32] = -28, - [1][1][RTW89_ETSI][32] = 32, - [1][1][RTW89_FCC][34] = -28, - [1][1][RTW89_ETSI][34] = 32, - [1][1][RTW89_FCC][36] = -28, - [1][1][RTW89_ETSI][36] = 32, - [1][1][RTW89_FCC][38] = -28, - [1][1][RTW89_ETSI][38] = 32, - [1][1][RTW89_FCC][40] = -28, - [1][1][RTW89_ETSI][40] = 32, - [1][1][RTW89_FCC][42] = -28, - [1][1][RTW89_ETSI][42] = 32, - [1][1][RTW89_FCC][44] = -28, - [1][1][RTW89_ETSI][44] = 34, - [1][1][RTW89_FCC][45] = -26, - [1][1][RTW89_ETSI][45] = 127, - [1][1][RTW89_FCC][47] = -28, - [1][1][RTW89_ETSI][47] = 127, - [1][1][RTW89_FCC][49] = -28, - [1][1][RTW89_ETSI][49] = 127, - [1][1][RTW89_FCC][51] = -28, - [1][1][RTW89_ETSI][51] = 127, - [1][1][RTW89_FCC][53] = -26, - [1][1][RTW89_ETSI][53] = 127, - [1][1][RTW89_FCC][55] = -28, - [1][1][RTW89_ETSI][55] = 127, - [1][1][RTW89_FCC][57] = -28, - [1][1][RTW89_ETSI][57] = 127, - [1][1][RTW89_FCC][59] = -28, - [1][1][RTW89_ETSI][59] = 127, - [1][1][RTW89_FCC][60] = -28, - [1][1][RTW89_ETSI][60] = 127, - [1][1][RTW89_FCC][62] = -28, - [1][1][RTW89_ETSI][62] = 127, - [1][1][RTW89_FCC][64] = -28, - [1][1][RTW89_ETSI][64] = 127, - [1][1][RTW89_FCC][66] = -28, - [1][1][RTW89_ETSI][66] = 127, - [1][1][RTW89_FCC][68] = -28, - [1][1][RTW89_ETSI][68] = 127, - [1][1][RTW89_FCC][70] = -26, - [1][1][RTW89_ETSI][70] = 127, - [1][1][RTW89_FCC][72] = -28, - [1][1][RTW89_ETSI][72] = 127, - [1][1][RTW89_FCC][74] = -28, - [1][1][RTW89_ETSI][74] = 127, - [1][1][RTW89_FCC][75] = -28, - [1][1][RTW89_ETSI][75] = 127, - [1][1][RTW89_FCC][77] = -28, - [1][1][RTW89_ETSI][77] = 127, - [1][1][RTW89_FCC][79] = -28, - [1][1][RTW89_ETSI][79] = 127, - [1][1][RTW89_FCC][81] = -28, - [1][1][RTW89_ETSI][81] = 127, - [1][1][RTW89_FCC][83] = -28, - [1][1][RTW89_ETSI][83] = 127, - [1][1][RTW89_FCC][85] = -28, - [1][1][RTW89_ETSI][85] = 127, - [1][1][RTW89_FCC][87] = -28, - [1][1][RTW89_ETSI][87] = 127, - [1][1][RTW89_FCC][89] = -26, - [1][1][RTW89_ETSI][89] = 127, - [1][1][RTW89_FCC][90] = -26, - [1][1][RTW89_ETSI][90] = 127, - [1][1][RTW89_FCC][92] = -26, - [1][1][RTW89_ETSI][92] = 127, - [1][1][RTW89_FCC][94] = -26, - [1][1][RTW89_ETSI][94] = 127, - [1][1][RTW89_FCC][96] = -26, - [1][1][RTW89_ETSI][96] = 127, - [1][1][RTW89_FCC][98] = -26, - [1][1][RTW89_ETSI][98] = 127, - [1][1][RTW89_FCC][100] = -26, - [1][1][RTW89_ETSI][100] = 127, - [1][1][RTW89_FCC][102] = -26, - [1][1][RTW89_ETSI][102] = 127, - [1][1][RTW89_FCC][104] = -26, - [1][1][RTW89_ETSI][104] = 127, - [1][1][RTW89_FCC][105] = -26, - [1][1][RTW89_ETSI][105] = 127, - [1][1][RTW89_FCC][107] = -22, - [1][1][RTW89_ETSI][107] = 127, - [1][1][RTW89_FCC][109] = -22, - [1][1][RTW89_ETSI][109] = 127, - [1][1][RTW89_FCC][111] = 127, - [1][1][RTW89_ETSI][111] = 127, - [1][1][RTW89_FCC][113] = 127, - [1][1][RTW89_ETSI][113] = 127, - [1][1][RTW89_FCC][115] = 127, - [1][1][RTW89_ETSI][115] = 127, - [1][1][RTW89_FCC][117] = 127, - [1][1][RTW89_ETSI][117] = 127, - [1][1][RTW89_FCC][119] = 127, - [1][1][RTW89_ETSI][119] = 127, - [2][0][RTW89_FCC][0] = 8, - [2][0][RTW89_ETSI][0] = 56, - [2][0][RTW89_FCC][2] = 8, - [2][0][RTW89_ETSI][2] = 56, - [2][0][RTW89_FCC][4] = 8, - [2][0][RTW89_ETSI][4] = 56, - [2][0][RTW89_FCC][6] = 8, - [2][0][RTW89_ETSI][6] = 56, - [2][0][RTW89_FCC][8] = 8, - [2][0][RTW89_ETSI][8] = 56, - [2][0][RTW89_FCC][10] = 8, - [2][0][RTW89_ETSI][10] = 56, - [2][0][RTW89_FCC][12] = 8, - [2][0][RTW89_ETSI][12] = 56, - [2][0][RTW89_FCC][14] = 8, - [2][0][RTW89_ETSI][14] = 56, - [2][0][RTW89_FCC][15] = 8, - [2][0][RTW89_ETSI][15] = 56, - [2][0][RTW89_FCC][17] = 8, - [2][0][RTW89_ETSI][17] = 56, - [2][0][RTW89_FCC][19] = 8, - [2][0][RTW89_ETSI][19] = 56, - [2][0][RTW89_FCC][21] = 8, - [2][0][RTW89_ETSI][21] = 56, - [2][0][RTW89_FCC][23] = 8, - [2][0][RTW89_ETSI][23] = 56, - [2][0][RTW89_FCC][25] = 8, - [2][0][RTW89_ETSI][25] = 56, - [2][0][RTW89_FCC][27] = 8, - [2][0][RTW89_ETSI][27] = 56, - [2][0][RTW89_FCC][29] = 8, - [2][0][RTW89_ETSI][29] = 56, - [2][0][RTW89_FCC][30] = 8, - [2][0][RTW89_ETSI][30] = 56, - [2][0][RTW89_FCC][32] = 8, - [2][0][RTW89_ETSI][32] = 56, - [2][0][RTW89_FCC][34] = 8, - [2][0][RTW89_ETSI][34] = 56, - [2][0][RTW89_FCC][36] = 8, - [2][0][RTW89_ETSI][36] = 56, - [2][0][RTW89_FCC][38] = 8, - [2][0][RTW89_ETSI][38] = 56, - [2][0][RTW89_FCC][40] = 8, - [2][0][RTW89_ETSI][40] = 56, - [2][0][RTW89_FCC][42] = 8, - [2][0][RTW89_ETSI][42] = 56, - [2][0][RTW89_FCC][44] = 8, - [2][0][RTW89_ETSI][44] = 56, - [2][0][RTW89_FCC][45] = 8, - [2][0][RTW89_ETSI][45] = 127, - [2][0][RTW89_FCC][47] = 8, - [2][0][RTW89_ETSI][47] = 127, - [2][0][RTW89_FCC][49] = 8, - [2][0][RTW89_ETSI][49] = 127, - [2][0][RTW89_FCC][51] = 8, - [2][0][RTW89_ETSI][51] = 127, - [2][0][RTW89_FCC][53] = 8, - [2][0][RTW89_ETSI][53] = 127, - [2][0][RTW89_FCC][55] = 8, - [2][0][RTW89_ETSI][55] = 127, - [2][0][RTW89_FCC][57] = 8, - [2][0][RTW89_ETSI][57] = 127, - [2][0][RTW89_FCC][59] = 8, - [2][0][RTW89_ETSI][59] = 127, - [2][0][RTW89_FCC][60] = 8, - [2][0][RTW89_ETSI][60] = 127, - [2][0][RTW89_FCC][62] = 8, - [2][0][RTW89_ETSI][62] = 127, - [2][0][RTW89_FCC][64] = 8, - [2][0][RTW89_ETSI][64] = 127, - [2][0][RTW89_FCC][66] = 8, - [2][0][RTW89_ETSI][66] = 127, - [2][0][RTW89_FCC][68] = 8, - [2][0][RTW89_ETSI][68] = 127, - [2][0][RTW89_FCC][70] = 8, - [2][0][RTW89_ETSI][70] = 127, - [2][0][RTW89_FCC][72] = 8, - [2][0][RTW89_ETSI][72] = 127, - [2][0][RTW89_FCC][74] = 8, - [2][0][RTW89_ETSI][74] = 127, - [2][0][RTW89_FCC][75] = 8, - [2][0][RTW89_ETSI][75] = 127, - [2][0][RTW89_FCC][77] = 8, - [2][0][RTW89_ETSI][77] = 127, - [2][0][RTW89_FCC][79] = 8, - [2][0][RTW89_ETSI][79] = 127, - [2][0][RTW89_FCC][81] = 8, - [2][0][RTW89_ETSI][81] = 127, - [2][0][RTW89_FCC][83] = 8, - [2][0][RTW89_ETSI][83] = 127, - [2][0][RTW89_FCC][85] = 8, - [2][0][RTW89_ETSI][85] = 127, - [2][0][RTW89_FCC][87] = 8, - [2][0][RTW89_ETSI][87] = 127, - [2][0][RTW89_FCC][89] = 8, - [2][0][RTW89_ETSI][89] = 127, - [2][0][RTW89_FCC][90] = 8, - [2][0][RTW89_ETSI][90] = 127, - [2][0][RTW89_FCC][92] = 8, - [2][0][RTW89_ETSI][92] = 127, - [2][0][RTW89_FCC][94] = 8, - [2][0][RTW89_ETSI][94] = 127, - [2][0][RTW89_FCC][96] = 8, - [2][0][RTW89_ETSI][96] = 127, - [2][0][RTW89_FCC][98] = 8, - [2][0][RTW89_ETSI][98] = 127, - [2][0][RTW89_FCC][100] = 8, - [2][0][RTW89_ETSI][100] = 127, - [2][0][RTW89_FCC][102] = 8, - [2][0][RTW89_ETSI][102] = 127, - [2][0][RTW89_FCC][104] = 8, - [2][0][RTW89_ETSI][104] = 127, - [2][0][RTW89_FCC][105] = 8, - [2][0][RTW89_ETSI][105] = 127, - [2][0][RTW89_FCC][107] = 10, - [2][0][RTW89_ETSI][107] = 127, - [2][0][RTW89_FCC][109] = 12, - [2][0][RTW89_ETSI][109] = 127, - [2][0][RTW89_FCC][111] = 127, - [2][0][RTW89_ETSI][111] = 127, - [2][0][RTW89_FCC][113] = 127, - [2][0][RTW89_ETSI][113] = 127, - [2][0][RTW89_FCC][115] = 127, - [2][0][RTW89_ETSI][115] = 127, - [2][0][RTW89_FCC][117] = 127, - [2][0][RTW89_ETSI][117] = 127, - [2][0][RTW89_FCC][119] = 127, - [2][0][RTW89_ETSI][119] = 127, - [2][1][RTW89_FCC][0] = -16, - [2][1][RTW89_ETSI][0] = 44, - [2][1][RTW89_FCC][2] = -16, - [2][1][RTW89_ETSI][2] = 44, - [2][1][RTW89_FCC][4] = -16, - [2][1][RTW89_ETSI][4] = 44, - [2][1][RTW89_FCC][6] = -16, - [2][1][RTW89_ETSI][6] = 44, - [2][1][RTW89_FCC][8] = -16, - [2][1][RTW89_ETSI][8] = 44, - [2][1][RTW89_FCC][10] = -16, - [2][1][RTW89_ETSI][10] = 44, - [2][1][RTW89_FCC][12] = -16, - [2][1][RTW89_ETSI][12] = 44, - [2][1][RTW89_FCC][14] = -16, - [2][1][RTW89_ETSI][14] = 44, - [2][1][RTW89_FCC][15] = -16, - [2][1][RTW89_ETSI][15] = 44, - [2][1][RTW89_FCC][17] = -16, - [2][1][RTW89_ETSI][17] = 44, - [2][1][RTW89_FCC][19] = -16, - [2][1][RTW89_ETSI][19] = 44, - [2][1][RTW89_FCC][21] = -16, - [2][1][RTW89_ETSI][21] = 44, - [2][1][RTW89_FCC][23] = -16, - [2][1][RTW89_ETSI][23] = 44, - [2][1][RTW89_FCC][25] = -16, - [2][1][RTW89_ETSI][25] = 44, - [2][1][RTW89_FCC][27] = -16, - [2][1][RTW89_ETSI][27] = 44, - [2][1][RTW89_FCC][29] = -16, - [2][1][RTW89_ETSI][29] = 44, - [2][1][RTW89_FCC][30] = -16, - [2][1][RTW89_ETSI][30] = 44, - [2][1][RTW89_FCC][32] = -16, - [2][1][RTW89_ETSI][32] = 44, - [2][1][RTW89_FCC][34] = -16, - [2][1][RTW89_ETSI][34] = 44, - [2][1][RTW89_FCC][36] = -16, - [2][1][RTW89_ETSI][36] = 44, - [2][1][RTW89_FCC][38] = -16, - [2][1][RTW89_ETSI][38] = 44, - [2][1][RTW89_FCC][40] = -16, - [2][1][RTW89_ETSI][40] = 44, - [2][1][RTW89_FCC][42] = -16, - [2][1][RTW89_ETSI][42] = 44, - [2][1][RTW89_FCC][44] = -16, - [2][1][RTW89_ETSI][44] = 44, - [2][1][RTW89_FCC][45] = -16, - [2][1][RTW89_ETSI][45] = 127, - [2][1][RTW89_FCC][47] = -16, - [2][1][RTW89_ETSI][47] = 127, - [2][1][RTW89_FCC][49] = -16, - [2][1][RTW89_ETSI][49] = 127, - [2][1][RTW89_FCC][51] = -16, - [2][1][RTW89_ETSI][51] = 127, - [2][1][RTW89_FCC][53] = -16, - [2][1][RTW89_ETSI][53] = 127, - [2][1][RTW89_FCC][55] = -16, - [2][1][RTW89_ETSI][55] = 127, - [2][1][RTW89_FCC][57] = -16, - [2][1][RTW89_ETSI][57] = 127, - [2][1][RTW89_FCC][59] = -16, - [2][1][RTW89_ETSI][59] = 127, - [2][1][RTW89_FCC][60] = -16, - [2][1][RTW89_ETSI][60] = 127, - [2][1][RTW89_FCC][62] = -16, - [2][1][RTW89_ETSI][62] = 127, - [2][1][RTW89_FCC][64] = -16, - [2][1][RTW89_ETSI][64] = 127, - [2][1][RTW89_FCC][66] = -16, - [2][1][RTW89_ETSI][66] = 127, - [2][1][RTW89_FCC][68] = -16, - [2][1][RTW89_ETSI][68] = 127, - [2][1][RTW89_FCC][70] = -16, - [2][1][RTW89_ETSI][70] = 127, - [2][1][RTW89_FCC][72] = -16, - [2][1][RTW89_ETSI][72] = 127, - [2][1][RTW89_FCC][74] = -16, - [2][1][RTW89_ETSI][74] = 127, - [2][1][RTW89_FCC][75] = -16, - [2][1][RTW89_ETSI][75] = 127, - [2][1][RTW89_FCC][77] = -16, - [2][1][RTW89_ETSI][77] = 127, - [2][1][RTW89_FCC][79] = -16, - [2][1][RTW89_ETSI][79] = 127, - [2][1][RTW89_FCC][81] = -16, - [2][1][RTW89_ETSI][81] = 127, - [2][1][RTW89_FCC][83] = -16, - [2][1][RTW89_ETSI][83] = 127, - [2][1][RTW89_FCC][85] = -18, - [2][1][RTW89_ETSI][85] = 127, - [2][1][RTW89_FCC][87] = -16, - [2][1][RTW89_ETSI][87] = 127, - [2][1][RTW89_FCC][89] = -16, - [2][1][RTW89_ETSI][89] = 127, - [2][1][RTW89_FCC][90] = -16, - [2][1][RTW89_ETSI][90] = 127, - [2][1][RTW89_FCC][92] = -16, - [2][1][RTW89_ETSI][92] = 127, - [2][1][RTW89_FCC][94] = -16, - [2][1][RTW89_ETSI][94] = 127, - [2][1][RTW89_FCC][96] = -16, - [2][1][RTW89_ETSI][96] = 127, - [2][1][RTW89_FCC][98] = -16, - [2][1][RTW89_ETSI][98] = 127, - [2][1][RTW89_FCC][100] = -16, - [2][1][RTW89_ETSI][100] = 127, - [2][1][RTW89_FCC][102] = -16, - [2][1][RTW89_ETSI][102] = 127, - [2][1][RTW89_FCC][104] = -16, - [2][1][RTW89_ETSI][104] = 127, - [2][1][RTW89_FCC][105] = -16, - [2][1][RTW89_ETSI][105] = 127, - [2][1][RTW89_FCC][107] = -12, - [2][1][RTW89_ETSI][107] = 127, - [2][1][RTW89_FCC][109] = -10, - [2][1][RTW89_ETSI][109] = 127, - [2][1][RTW89_FCC][111] = 127, - [2][1][RTW89_ETSI][111] = 127, - [2][1][RTW89_FCC][113] = 127, - [2][1][RTW89_ETSI][113] = 127, - [2][1][RTW89_FCC][115] = 127, - [2][1][RTW89_ETSI][115] = 127, - [2][1][RTW89_FCC][117] = 127, - [2][1][RTW89_ETSI][117] = 127, - [2][1][RTW89_FCC][119] = 127, - [2][1][RTW89_ETSI][119] = 127, + [RTW89_REGD_NUM][NUM_OF_RTW89_REG_6GHZ_POWER] + [RTW89_6G_CH_NUM] = { + [0][0][RTW89_WW][0][0] = -16, + [0][0][RTW89_WW][1][0] = -16, + [0][0][RTW89_WW][2][0] = 44, + [0][0][RTW89_WW][0][2] = -18, + [0][0][RTW89_WW][1][2] = -18, + [0][0][RTW89_WW][2][2] = 44, + [0][0][RTW89_WW][0][4] = -18, + [0][0][RTW89_WW][1][4] = -18, + [0][0][RTW89_WW][2][4] = 44, + [0][0][RTW89_WW][0][6] = -18, + [0][0][RTW89_WW][1][6] = -18, + [0][0][RTW89_WW][2][6] = 44, + [0][0][RTW89_WW][0][8] = -18, + [0][0][RTW89_WW][1][8] = -18, + [0][0][RTW89_WW][2][8] = 44, + [0][0][RTW89_WW][0][10] = -18, + [0][0][RTW89_WW][1][10] = -18, + [0][0][RTW89_WW][2][10] = 44, + [0][0][RTW89_WW][0][12] = -18, + [0][0][RTW89_WW][1][12] = -18, + [0][0][RTW89_WW][2][12] = 44, + [0][0][RTW89_WW][0][14] = -18, + [0][0][RTW89_WW][1][14] = -18, + [0][0][RTW89_WW][2][14] = 44, + [0][0][RTW89_WW][0][15] = -18, + [0][0][RTW89_WW][1][15] = -18, + [0][0][RTW89_WW][2][15] = 44, + [0][0][RTW89_WW][0][17] = -18, + [0][0][RTW89_WW][1][17] = -18, + [0][0][RTW89_WW][2][17] = 44, + [0][0][RTW89_WW][0][19] = -18, + [0][0][RTW89_WW][1][19] = -18, + [0][0][RTW89_WW][2][19] = 44, + [0][0][RTW89_WW][0][21] = -18, + [0][0][RTW89_WW][1][21] = -18, + [0][0][RTW89_WW][2][21] = 44, + [0][0][RTW89_WW][0][23] = -18, + [0][0][RTW89_WW][1][23] = -18, + [0][0][RTW89_WW][2][23] = 54, + [0][0][RTW89_WW][0][25] = -18, + [0][0][RTW89_WW][1][25] = -18, + [0][0][RTW89_WW][2][25] = 54, + [0][0][RTW89_WW][0][27] = -18, + [0][0][RTW89_WW][1][27] = -18, + [0][0][RTW89_WW][2][27] = 54, + [0][0][RTW89_WW][0][29] = -18, + [0][0][RTW89_WW][1][29] = -18, + [0][0][RTW89_WW][2][29] = 54, + [0][0][RTW89_WW][0][30] = -18, + [0][0][RTW89_WW][1][30] = -18, + [0][0][RTW89_WW][2][30] = 54, + [0][0][RTW89_WW][0][32] = -18, + [0][0][RTW89_WW][1][32] = -18, + [0][0][RTW89_WW][2][32] = 54, + [0][0][RTW89_WW][0][34] = -18, + [0][0][RTW89_WW][1][34] = -18, + [0][0][RTW89_WW][2][34] = 54, + [0][0][RTW89_WW][0][36] = -18, + [0][0][RTW89_WW][1][36] = -18, + [0][0][RTW89_WW][2][36] = 54, + [0][0][RTW89_WW][0][38] = -18, + [0][0][RTW89_WW][1][38] = -18, + [0][0][RTW89_WW][2][38] = 54, + [0][0][RTW89_WW][0][40] = -18, + [0][0][RTW89_WW][1][40] = -18, + [0][0][RTW89_WW][2][40] = 54, + [0][0][RTW89_WW][0][42] = -18, + [0][0][RTW89_WW][1][42] = -18, + [0][0][RTW89_WW][2][42] = 54, + [0][0][RTW89_WW][0][44] = -16, + [0][0][RTW89_WW][1][44] = -16, + [0][0][RTW89_WW][2][44] = 56, + [0][0][RTW89_WW][0][45] = -16, + [0][0][RTW89_WW][1][45] = -16, + [0][0][RTW89_WW][2][45] = 0, + [0][0][RTW89_WW][0][47] = -18, + [0][0][RTW89_WW][1][47] = -18, + [0][0][RTW89_WW][2][47] = 0, + [0][0][RTW89_WW][0][49] = -18, + [0][0][RTW89_WW][1][49] = -18, + [0][0][RTW89_WW][2][49] = 0, + [0][0][RTW89_WW][0][51] = -18, + [0][0][RTW89_WW][1][51] = -18, + [0][0][RTW89_WW][2][51] = 0, + [0][0][RTW89_WW][0][53] = -16, + [0][0][RTW89_WW][1][53] = -16, + [0][0][RTW89_WW][2][53] = 0, + [0][0][RTW89_WW][0][55] = -18, + [0][0][RTW89_WW][1][55] = -18, + [0][0][RTW89_WW][2][55] = 56, + [0][0][RTW89_WW][0][57] = -18, + [0][0][RTW89_WW][1][57] = -18, + [0][0][RTW89_WW][2][57] = 56, + [0][0][RTW89_WW][0][59] = -18, + [0][0][RTW89_WW][1][59] = -18, + [0][0][RTW89_WW][2][59] = 56, + [0][0][RTW89_WW][0][60] = -18, + [0][0][RTW89_WW][1][60] = -18, + [0][0][RTW89_WW][2][60] = 56, + [0][0][RTW89_WW][0][62] = -18, + [0][0][RTW89_WW][1][62] = -18, + [0][0][RTW89_WW][2][62] = 56, + [0][0][RTW89_WW][0][64] = -18, + [0][0][RTW89_WW][1][64] = -18, + [0][0][RTW89_WW][2][64] = 56, + [0][0][RTW89_WW][0][66] = -18, + [0][0][RTW89_WW][1][66] = -18, + [0][0][RTW89_WW][2][66] = 56, + [0][0][RTW89_WW][0][68] = -18, + [0][0][RTW89_WW][1][68] = -18, + [0][0][RTW89_WW][2][68] = 56, + [0][0][RTW89_WW][0][70] = -16, + [0][0][RTW89_WW][1][70] = -16, + [0][0][RTW89_WW][2][70] = 56, + [0][0][RTW89_WW][0][72] = -18, + [0][0][RTW89_WW][1][72] = -18, + [0][0][RTW89_WW][2][72] = 56, + [0][0][RTW89_WW][0][74] = -18, + [0][0][RTW89_WW][1][74] = -18, + [0][0][RTW89_WW][2][74] = 56, + [0][0][RTW89_WW][0][75] = -18, + [0][0][RTW89_WW][1][75] = -18, + [0][0][RTW89_WW][2][75] = 56, + [0][0][RTW89_WW][0][77] = -18, + [0][0][RTW89_WW][1][77] = -18, + [0][0][RTW89_WW][2][77] = 56, + [0][0][RTW89_WW][0][79] = -18, + [0][0][RTW89_WW][1][79] = -18, + [0][0][RTW89_WW][2][79] = 56, + [0][0][RTW89_WW][0][81] = -18, + [0][0][RTW89_WW][1][81] = -18, + [0][0][RTW89_WW][2][81] = 56, + [0][0][RTW89_WW][0][83] = -18, + [0][0][RTW89_WW][1][83] = -18, + [0][0][RTW89_WW][2][83] = 56, + [0][0][RTW89_WW][0][85] = -18, + [0][0][RTW89_WW][1][85] = -18, + [0][0][RTW89_WW][2][85] = 56, + [0][0][RTW89_WW][0][87] = -16, + [0][0][RTW89_WW][1][87] = -16, + [0][0][RTW89_WW][2][87] = 0, + [0][0][RTW89_WW][0][89] = -16, + [0][0][RTW89_WW][1][89] = -16, + [0][0][RTW89_WW][2][89] = 0, + [0][0][RTW89_WW][0][90] = -16, + [0][0][RTW89_WW][1][90] = -16, + [0][0][RTW89_WW][2][90] = 0, + [0][0][RTW89_WW][0][92] = -16, + [0][0][RTW89_WW][1][92] = -16, + [0][0][RTW89_WW][2][92] = 0, + [0][0][RTW89_WW][0][94] = -16, + [0][0][RTW89_WW][1][94] = -16, + [0][0][RTW89_WW][2][94] = 0, + [0][0][RTW89_WW][0][96] = -16, + [0][0][RTW89_WW][1][96] = -16, + [0][0][RTW89_WW][2][96] = 0, + [0][0][RTW89_WW][0][98] = -16, + [0][0][RTW89_WW][1][98] = -16, + [0][0][RTW89_WW][2][98] = 0, + [0][0][RTW89_WW][0][100] = -16, + [0][0][RTW89_WW][1][100] = -16, + [0][0][RTW89_WW][2][100] = 0, + [0][0][RTW89_WW][0][102] = -16, + [0][0][RTW89_WW][1][102] = -16, + [0][0][RTW89_WW][2][102] = 0, + [0][0][RTW89_WW][0][104] = -16, + [0][0][RTW89_WW][1][104] = -16, + [0][0][RTW89_WW][2][104] = 0, + [0][0][RTW89_WW][0][105] = -16, + [0][0][RTW89_WW][1][105] = -16, + [0][0][RTW89_WW][2][105] = 0, + [0][0][RTW89_WW][0][107] = -12, + [0][0][RTW89_WW][1][107] = -12, + [0][0][RTW89_WW][2][107] = 0, + [0][0][RTW89_WW][0][109] = -12, + [0][0][RTW89_WW][1][109] = -12, + [0][0][RTW89_WW][2][109] = 0, + [0][0][RTW89_WW][0][111] = 0, + [0][0][RTW89_WW][1][111] = 0, + [0][0][RTW89_WW][2][111] = 0, + [0][0][RTW89_WW][0][113] = 0, + [0][0][RTW89_WW][1][113] = 0, + [0][0][RTW89_WW][2][113] = 0, + [0][0][RTW89_WW][0][115] = 0, + [0][0][RTW89_WW][1][115] = 0, + [0][0][RTW89_WW][2][115] = 0, + [0][0][RTW89_WW][0][117] = 0, + [0][0][RTW89_WW][1][117] = 0, + [0][0][RTW89_WW][2][117] = 0, + [0][0][RTW89_WW][0][119] = 0, + [0][0][RTW89_WW][1][119] = 0, + [0][0][RTW89_WW][2][119] = 0, + [0][1][RTW89_WW][0][0] = -40, + [0][1][RTW89_WW][1][0] = -40, + [0][1][RTW89_WW][2][0] = 32, + [0][1][RTW89_WW][0][2] = -40, + [0][1][RTW89_WW][1][2] = -40, + [0][1][RTW89_WW][2][2] = 32, + [0][1][RTW89_WW][0][4] = -40, + [0][1][RTW89_WW][1][4] = -40, + [0][1][RTW89_WW][2][4] = 32, + [0][1][RTW89_WW][0][6] = -40, + [0][1][RTW89_WW][1][6] = -40, + [0][1][RTW89_WW][2][6] = 32, + [0][1][RTW89_WW][0][8] = -40, + [0][1][RTW89_WW][1][8] = -40, + [0][1][RTW89_WW][2][8] = 32, + [0][1][RTW89_WW][0][10] = -40, + [0][1][RTW89_WW][1][10] = -40, + [0][1][RTW89_WW][2][10] = 32, + [0][1][RTW89_WW][0][12] = -40, + [0][1][RTW89_WW][1][12] = -40, + [0][1][RTW89_WW][2][12] = 32, + [0][1][RTW89_WW][0][14] = -40, + [0][1][RTW89_WW][1][14] = -40, + [0][1][RTW89_WW][2][14] = 32, + [0][1][RTW89_WW][0][15] = -40, + [0][1][RTW89_WW][1][15] = -40, + [0][1][RTW89_WW][2][15] = 32, + [0][1][RTW89_WW][0][17] = -40, + [0][1][RTW89_WW][1][17] = -40, + [0][1][RTW89_WW][2][17] = 32, + [0][1][RTW89_WW][0][19] = -40, + [0][1][RTW89_WW][1][19] = -40, + [0][1][RTW89_WW][2][19] = 32, + [0][1][RTW89_WW][0][21] = -40, + [0][1][RTW89_WW][1][21] = -40, + [0][1][RTW89_WW][2][21] = 32, + [0][1][RTW89_WW][0][23] = -40, + [0][1][RTW89_WW][1][23] = -40, + [0][1][RTW89_WW][2][23] = 32, + [0][1][RTW89_WW][0][25] = -40, + [0][1][RTW89_WW][1][25] = -40, + [0][1][RTW89_WW][2][25] = 32, + [0][1][RTW89_WW][0][27] = -40, + [0][1][RTW89_WW][1][27] = -40, + [0][1][RTW89_WW][2][27] = 32, + [0][1][RTW89_WW][0][29] = -40, + [0][1][RTW89_WW][1][29] = -40, + [0][1][RTW89_WW][2][29] = 32, + [0][1][RTW89_WW][0][30] = -40, + [0][1][RTW89_WW][1][30] = -40, + [0][1][RTW89_WW][2][30] = 32, + [0][1][RTW89_WW][0][32] = -40, + [0][1][RTW89_WW][1][32] = -40, + [0][1][RTW89_WW][2][32] = 32, + [0][1][RTW89_WW][0][34] = -40, + [0][1][RTW89_WW][1][34] = -40, + [0][1][RTW89_WW][2][34] = 32, + [0][1][RTW89_WW][0][36] = -40, + [0][1][RTW89_WW][1][36] = -40, + [0][1][RTW89_WW][2][36] = 32, + [0][1][RTW89_WW][0][38] = -40, + [0][1][RTW89_WW][1][38] = -40, + [0][1][RTW89_WW][2][38] = 32, + [0][1][RTW89_WW][0][40] = -40, + [0][1][RTW89_WW][1][40] = -40, + [0][1][RTW89_WW][2][40] = 32, + [0][1][RTW89_WW][0][42] = -40, + [0][1][RTW89_WW][1][42] = -40, + [0][1][RTW89_WW][2][42] = 32, + [0][1][RTW89_WW][0][44] = -40, + [0][1][RTW89_WW][1][44] = -40, + [0][1][RTW89_WW][2][44] = 32, + [0][1][RTW89_WW][0][45] = -40, + [0][1][RTW89_WW][1][45] = -40, + [0][1][RTW89_WW][2][45] = 0, + [0][1][RTW89_WW][0][47] = -40, + [0][1][RTW89_WW][1][47] = -40, + [0][1][RTW89_WW][2][47] = 0, + [0][1][RTW89_WW][0][49] = -40, + [0][1][RTW89_WW][1][49] = -40, + [0][1][RTW89_WW][2][49] = 0, + [0][1][RTW89_WW][0][51] = -40, + [0][1][RTW89_WW][1][51] = -40, + [0][1][RTW89_WW][2][51] = 0, + [0][1][RTW89_WW][0][53] = -40, + [0][1][RTW89_WW][1][53] = -40, + [0][1][RTW89_WW][2][53] = 0, + [0][1][RTW89_WW][0][55] = -40, + [0][1][RTW89_WW][1][55] = -40, + [0][1][RTW89_WW][2][55] = 30, + [0][1][RTW89_WW][0][57] = -40, + [0][1][RTW89_WW][1][57] = -40, + [0][1][RTW89_WW][2][57] = 30, + [0][1][RTW89_WW][0][59] = -40, + [0][1][RTW89_WW][1][59] = -40, + [0][1][RTW89_WW][2][59] = 30, + [0][1][RTW89_WW][0][60] = -40, + [0][1][RTW89_WW][1][60] = -40, + [0][1][RTW89_WW][2][60] = 30, + [0][1][RTW89_WW][0][62] = -40, + [0][1][RTW89_WW][1][62] = -40, + [0][1][RTW89_WW][2][62] = 30, + [0][1][RTW89_WW][0][64] = -40, + [0][1][RTW89_WW][1][64] = -40, + [0][1][RTW89_WW][2][64] = 30, + [0][1][RTW89_WW][0][66] = -40, + [0][1][RTW89_WW][1][66] = -40, + [0][1][RTW89_WW][2][66] = 30, + [0][1][RTW89_WW][0][68] = -40, + [0][1][RTW89_WW][1][68] = -40, + [0][1][RTW89_WW][2][68] = 30, + [0][1][RTW89_WW][0][70] = -38, + [0][1][RTW89_WW][1][70] = -38, + [0][1][RTW89_WW][2][70] = 30, + [0][1][RTW89_WW][0][72] = -38, + [0][1][RTW89_WW][1][72] = -38, + [0][1][RTW89_WW][2][72] = 30, + [0][1][RTW89_WW][0][74] = -38, + [0][1][RTW89_WW][1][74] = -38, + [0][1][RTW89_WW][2][74] = 30, + [0][1][RTW89_WW][0][75] = -38, + [0][1][RTW89_WW][1][75] = -38, + [0][1][RTW89_WW][2][75] = 30, + [0][1][RTW89_WW][0][77] = -38, + [0][1][RTW89_WW][1][77] = -38, + [0][1][RTW89_WW][2][77] = 30, + [0][1][RTW89_WW][0][79] = -38, + [0][1][RTW89_WW][1][79] = -38, + [0][1][RTW89_WW][2][79] = 30, + [0][1][RTW89_WW][0][81] = -38, + [0][1][RTW89_WW][1][81] = -38, + [0][1][RTW89_WW][2][81] = 30, + [0][1][RTW89_WW][0][83] = -38, + [0][1][RTW89_WW][1][83] = -38, + [0][1][RTW89_WW][2][83] = 30, + [0][1][RTW89_WW][0][85] = -38, + [0][1][RTW89_WW][1][85] = -38, + [0][1][RTW89_WW][2][85] = 30, + [0][1][RTW89_WW][0][87] = -40, + [0][1][RTW89_WW][1][87] = -40, + [0][1][RTW89_WW][2][87] = 0, + [0][1][RTW89_WW][0][89] = -38, + [0][1][RTW89_WW][1][89] = -38, + [0][1][RTW89_WW][2][89] = 0, + [0][1][RTW89_WW][0][90] = -38, + [0][1][RTW89_WW][1][90] = -38, + [0][1][RTW89_WW][2][90] = 0, + [0][1][RTW89_WW][0][92] = -38, + [0][1][RTW89_WW][1][92] = -38, + [0][1][RTW89_WW][2][92] = 0, + [0][1][RTW89_WW][0][94] = -38, + [0][1][RTW89_WW][1][94] = -38, + [0][1][RTW89_WW][2][94] = 0, + [0][1][RTW89_WW][0][96] = -38, + [0][1][RTW89_WW][1][96] = -38, + [0][1][RTW89_WW][2][96] = 0, + [0][1][RTW89_WW][0][98] = -38, + [0][1][RTW89_WW][1][98] = -38, + [0][1][RTW89_WW][2][98] = 0, + [0][1][RTW89_WW][0][100] = -38, + [0][1][RTW89_WW][1][100] = -38, + [0][1][RTW89_WW][2][100] = 0, + [0][1][RTW89_WW][0][102] = -38, + [0][1][RTW89_WW][1][102] = -38, + [0][1][RTW89_WW][2][102] = 0, + [0][1][RTW89_WW][0][104] = -38, + [0][1][RTW89_WW][1][104] = -38, + [0][1][RTW89_WW][2][104] = 0, + [0][1][RTW89_WW][0][105] = -38, + [0][1][RTW89_WW][1][105] = -38, + [0][1][RTW89_WW][2][105] = 0, + [0][1][RTW89_WW][0][107] = -34, + [0][1][RTW89_WW][1][107] = -34, + [0][1][RTW89_WW][2][107] = 0, + [0][1][RTW89_WW][0][109] = -34, + [0][1][RTW89_WW][1][109] = -34, + [0][1][RTW89_WW][2][109] = 0, + [0][1][RTW89_WW][0][111] = 0, + [0][1][RTW89_WW][1][111] = 0, + [0][1][RTW89_WW][2][111] = 0, + [0][1][RTW89_WW][0][113] = 0, + [0][1][RTW89_WW][1][113] = 0, + [0][1][RTW89_WW][2][113] = 0, + [0][1][RTW89_WW][0][115] = 0, + [0][1][RTW89_WW][1][115] = 0, + [0][1][RTW89_WW][2][115] = 0, + [0][1][RTW89_WW][0][117] = 0, + [0][1][RTW89_WW][1][117] = 0, + [0][1][RTW89_WW][2][117] = 0, + [0][1][RTW89_WW][0][119] = 0, + [0][1][RTW89_WW][1][119] = 0, + [0][1][RTW89_WW][2][119] = 0, + [1][0][RTW89_WW][0][0] = -4, + [1][0][RTW89_WW][1][0] = -4, + [1][0][RTW89_WW][2][0] = 52, + [1][0][RTW89_WW][0][2] = -4, + [1][0][RTW89_WW][1][2] = -4, + [1][0][RTW89_WW][2][2] = 52, + [1][0][RTW89_WW][0][4] = -4, + [1][0][RTW89_WW][1][4] = -4, + [1][0][RTW89_WW][2][4] = 52, + [1][0][RTW89_WW][0][6] = -4, + [1][0][RTW89_WW][1][6] = -4, + [1][0][RTW89_WW][2][6] = 52, + [1][0][RTW89_WW][0][8] = -4, + [1][0][RTW89_WW][1][8] = -4, + [1][0][RTW89_WW][2][8] = 52, + [1][0][RTW89_WW][0][10] = -4, + [1][0][RTW89_WW][1][10] = -4, + [1][0][RTW89_WW][2][10] = 52, + [1][0][RTW89_WW][0][12] = -4, + [1][0][RTW89_WW][1][12] = -4, + [1][0][RTW89_WW][2][12] = 52, + [1][0][RTW89_WW][0][14] = -4, + [1][0][RTW89_WW][1][14] = -4, + [1][0][RTW89_WW][2][14] = 52, + [1][0][RTW89_WW][0][15] = -4, + [1][0][RTW89_WW][1][15] = -4, + [1][0][RTW89_WW][2][15] = 52, + [1][0][RTW89_WW][0][17] = -4, + [1][0][RTW89_WW][1][17] = -4, + [1][0][RTW89_WW][2][17] = 52, + [1][0][RTW89_WW][0][19] = -4, + [1][0][RTW89_WW][1][19] = -4, + [1][0][RTW89_WW][2][19] = 52, + [1][0][RTW89_WW][0][21] = -4, + [1][0][RTW89_WW][1][21] = -4, + [1][0][RTW89_WW][2][21] = 52, + [1][0][RTW89_WW][0][23] = -4, + [1][0][RTW89_WW][1][23] = -4, + [1][0][RTW89_WW][2][23] = 66, + [1][0][RTW89_WW][0][25] = -4, + [1][0][RTW89_WW][1][25] = -4, + [1][0][RTW89_WW][2][25] = 66, + [1][0][RTW89_WW][0][27] = -4, + [1][0][RTW89_WW][1][27] = -4, + [1][0][RTW89_WW][2][27] = 66, + [1][0][RTW89_WW][0][29] = -4, + [1][0][RTW89_WW][1][29] = -4, + [1][0][RTW89_WW][2][29] = 66, + [1][0][RTW89_WW][0][30] = -4, + [1][0][RTW89_WW][1][30] = -4, + [1][0][RTW89_WW][2][30] = 66, + [1][0][RTW89_WW][0][32] = -4, + [1][0][RTW89_WW][1][32] = -4, + [1][0][RTW89_WW][2][32] = 66, + [1][0][RTW89_WW][0][34] = -4, + [1][0][RTW89_WW][1][34] = -4, + [1][0][RTW89_WW][2][34] = 66, + [1][0][RTW89_WW][0][36] = -4, + [1][0][RTW89_WW][1][36] = -4, + [1][0][RTW89_WW][2][36] = 66, + [1][0][RTW89_WW][0][38] = -4, + [1][0][RTW89_WW][1][38] = -4, + [1][0][RTW89_WW][2][38] = 66, + [1][0][RTW89_WW][0][40] = -4, + [1][0][RTW89_WW][1][40] = -4, + [1][0][RTW89_WW][2][40] = 66, + [1][0][RTW89_WW][0][42] = -4, + [1][0][RTW89_WW][1][42] = -4, + [1][0][RTW89_WW][2][42] = 66, + [1][0][RTW89_WW][0][44] = -4, + [1][0][RTW89_WW][1][44] = -4, + [1][0][RTW89_WW][2][44] = 66, + [1][0][RTW89_WW][0][45] = -4, + [1][0][RTW89_WW][1][45] = -4, + [1][0][RTW89_WW][2][45] = 0, + [1][0][RTW89_WW][0][47] = -4, + [1][0][RTW89_WW][1][47] = -4, + [1][0][RTW89_WW][2][47] = 0, + [1][0][RTW89_WW][0][49] = -4, + [1][0][RTW89_WW][1][49] = -4, + [1][0][RTW89_WW][2][49] = 0, + [1][0][RTW89_WW][0][51] = -4, + [1][0][RTW89_WW][1][51] = -4, + [1][0][RTW89_WW][2][51] = 0, + [1][0][RTW89_WW][0][53] = -4, + [1][0][RTW89_WW][1][53] = -4, + [1][0][RTW89_WW][2][53] = 0, + [1][0][RTW89_WW][0][55] = -4, + [1][0][RTW89_WW][1][55] = -4, + [1][0][RTW89_WW][2][55] = 68, + [1][0][RTW89_WW][0][57] = -4, + [1][0][RTW89_WW][1][57] = -4, + [1][0][RTW89_WW][2][57] = 68, + [1][0][RTW89_WW][0][59] = -4, + [1][0][RTW89_WW][1][59] = -4, + [1][0][RTW89_WW][2][59] = 68, + [1][0][RTW89_WW][0][60] = -4, + [1][0][RTW89_WW][1][60] = -4, + [1][0][RTW89_WW][2][60] = 68, + [1][0][RTW89_WW][0][62] = -4, + [1][0][RTW89_WW][1][62] = -4, + [1][0][RTW89_WW][2][62] = 68, + [1][0][RTW89_WW][0][64] = -4, + [1][0][RTW89_WW][1][64] = -4, + [1][0][RTW89_WW][2][64] = 68, + [1][0][RTW89_WW][0][66] = -4, + [1][0][RTW89_WW][1][66] = -4, + [1][0][RTW89_WW][2][66] = 68, + [1][0][RTW89_WW][0][68] = -4, + [1][0][RTW89_WW][1][68] = -4, + [1][0][RTW89_WW][2][68] = 68, + [1][0][RTW89_WW][0][70] = -4, + [1][0][RTW89_WW][1][70] = -4, + [1][0][RTW89_WW][2][70] = 68, + [1][0][RTW89_WW][0][72] = -4, + [1][0][RTW89_WW][1][72] = -4, + [1][0][RTW89_WW][2][72] = 68, + [1][0][RTW89_WW][0][74] = -4, + [1][0][RTW89_WW][1][74] = -4, + [1][0][RTW89_WW][2][74] = 68, + [1][0][RTW89_WW][0][75] = -4, + [1][0][RTW89_WW][1][75] = -4, + [1][0][RTW89_WW][2][75] = 68, + [1][0][RTW89_WW][0][77] = -4, + [1][0][RTW89_WW][1][77] = -4, + [1][0][RTW89_WW][2][77] = 68, + [1][0][RTW89_WW][0][79] = -4, + [1][0][RTW89_WW][1][79] = -4, + [1][0][RTW89_WW][2][79] = 68, + [1][0][RTW89_WW][0][81] = -4, + [1][0][RTW89_WW][1][81] = -4, + [1][0][RTW89_WW][2][81] = 68, + [1][0][RTW89_WW][0][83] = -4, + [1][0][RTW89_WW][1][83] = -4, + [1][0][RTW89_WW][2][83] = 68, + [1][0][RTW89_WW][0][85] = -4, + [1][0][RTW89_WW][1][85] = -4, + [1][0][RTW89_WW][2][85] = 68, + [1][0][RTW89_WW][0][87] = -4, + [1][0][RTW89_WW][1][87] = -4, + [1][0][RTW89_WW][2][87] = 0, + [1][0][RTW89_WW][0][89] = -4, + [1][0][RTW89_WW][1][89] = -4, + [1][0][RTW89_WW][2][89] = 0, + [1][0][RTW89_WW][0][90] = -4, + [1][0][RTW89_WW][1][90] = -4, + [1][0][RTW89_WW][2][90] = 0, + [1][0][RTW89_WW][0][92] = -4, + [1][0][RTW89_WW][1][92] = -4, + [1][0][RTW89_WW][2][92] = 0, + [1][0][RTW89_WW][0][94] = -4, + [1][0][RTW89_WW][1][94] = -4, + [1][0][RTW89_WW][2][94] = 0, + [1][0][RTW89_WW][0][96] = -4, + [1][0][RTW89_WW][1][96] = -4, + [1][0][RTW89_WW][2][96] = 0, + [1][0][RTW89_WW][0][98] = -4, + [1][0][RTW89_WW][1][98] = -4, + [1][0][RTW89_WW][2][98] = 0, + [1][0][RTW89_WW][0][100] = -4, + [1][0][RTW89_WW][1][100] = -4, + [1][0][RTW89_WW][2][100] = 0, + [1][0][RTW89_WW][0][102] = -4, + [1][0][RTW89_WW][1][102] = -4, + [1][0][RTW89_WW][2][102] = 0, + [1][0][RTW89_WW][0][104] = -4, + [1][0][RTW89_WW][1][104] = -4, + [1][0][RTW89_WW][2][104] = 0, + [1][0][RTW89_WW][0][105] = -4, + [1][0][RTW89_WW][1][105] = -4, + [1][0][RTW89_WW][2][105] = 0, + [1][0][RTW89_WW][0][107] = -2, + [1][0][RTW89_WW][1][107] = -2, + [1][0][RTW89_WW][2][107] = 0, + [1][0][RTW89_WW][0][109] = 2, + [1][0][RTW89_WW][1][109] = 2, + [1][0][RTW89_WW][2][109] = 0, + [1][0][RTW89_WW][0][111] = 0, + [1][0][RTW89_WW][1][111] = 0, + [1][0][RTW89_WW][2][111] = 0, + [1][0][RTW89_WW][0][113] = 0, + [1][0][RTW89_WW][1][113] = 0, + [1][0][RTW89_WW][2][113] = 0, + [1][0][RTW89_WW][0][115] = 0, + [1][0][RTW89_WW][1][115] = 0, + [1][0][RTW89_WW][2][115] = 0, + [1][0][RTW89_WW][0][117] = 0, + [1][0][RTW89_WW][1][117] = 0, + [1][0][RTW89_WW][2][117] = 0, + [1][0][RTW89_WW][0][119] = 0, + [1][0][RTW89_WW][1][119] = 0, + [1][0][RTW89_WW][2][119] = 0, + [1][1][RTW89_WW][0][0] = -26, + [1][1][RTW89_WW][1][0] = -26, + [1][1][RTW89_WW][2][0] = 44, + [1][1][RTW89_WW][0][2] = -28, + [1][1][RTW89_WW][1][2] = -28, + [1][1][RTW89_WW][2][2] = 44, + [1][1][RTW89_WW][0][4] = -28, + [1][1][RTW89_WW][1][4] = -28, + [1][1][RTW89_WW][2][4] = 44, + [1][1][RTW89_WW][0][6] = -28, + [1][1][RTW89_WW][1][6] = -28, + [1][1][RTW89_WW][2][6] = 44, + [1][1][RTW89_WW][0][8] = -28, + [1][1][RTW89_WW][1][8] = -28, + [1][1][RTW89_WW][2][8] = 44, + [1][1][RTW89_WW][0][10] = -28, + [1][1][RTW89_WW][1][10] = -28, + [1][1][RTW89_WW][2][10] = 44, + [1][1][RTW89_WW][0][12] = -28, + [1][1][RTW89_WW][1][12] = -28, + [1][1][RTW89_WW][2][12] = 44, + [1][1][RTW89_WW][0][14] = -28, + [1][1][RTW89_WW][1][14] = -28, + [1][1][RTW89_WW][2][14] = 44, + [1][1][RTW89_WW][0][15] = -28, + [1][1][RTW89_WW][1][15] = -28, + [1][1][RTW89_WW][2][15] = 44, + [1][1][RTW89_WW][0][17] = -28, + [1][1][RTW89_WW][1][17] = -28, + [1][1][RTW89_WW][2][17] = 44, + [1][1][RTW89_WW][0][19] = -28, + [1][1][RTW89_WW][1][19] = -28, + [1][1][RTW89_WW][2][19] = 44, + [1][1][RTW89_WW][0][21] = -28, + [1][1][RTW89_WW][1][21] = -28, + [1][1][RTW89_WW][2][21] = 44, + [1][1][RTW89_WW][0][23] = -28, + [1][1][RTW89_WW][1][23] = -28, + [1][1][RTW89_WW][2][23] = 44, + [1][1][RTW89_WW][0][25] = -28, + [1][1][RTW89_WW][1][25] = -28, + [1][1][RTW89_WW][2][25] = 44, + [1][1][RTW89_WW][0][27] = -28, + [1][1][RTW89_WW][1][27] = -28, + [1][1][RTW89_WW][2][27] = 44, + [1][1][RTW89_WW][0][29] = -28, + [1][1][RTW89_WW][1][29] = -28, + [1][1][RTW89_WW][2][29] = 44, + [1][1][RTW89_WW][0][30] = -28, + [1][1][RTW89_WW][1][30] = -28, + [1][1][RTW89_WW][2][30] = 44, + [1][1][RTW89_WW][0][32] = -28, + [1][1][RTW89_WW][1][32] = -28, + [1][1][RTW89_WW][2][32] = 44, + [1][1][RTW89_WW][0][34] = -28, + [1][1][RTW89_WW][1][34] = -28, + [1][1][RTW89_WW][2][34] = 44, + [1][1][RTW89_WW][0][36] = -28, + [1][1][RTW89_WW][1][36] = -28, + [1][1][RTW89_WW][2][36] = 44, + [1][1][RTW89_WW][0][38] = -28, + [1][1][RTW89_WW][1][38] = -28, + [1][1][RTW89_WW][2][38] = 44, + [1][1][RTW89_WW][0][40] = -28, + [1][1][RTW89_WW][1][40] = -28, + [1][1][RTW89_WW][2][40] = 44, + [1][1][RTW89_WW][0][42] = -28, + [1][1][RTW89_WW][1][42] = -28, + [1][1][RTW89_WW][2][42] = 44, + [1][1][RTW89_WW][0][44] = -28, + [1][1][RTW89_WW][1][44] = -28, + [1][1][RTW89_WW][2][44] = 44, + [1][1][RTW89_WW][0][45] = -26, + [1][1][RTW89_WW][1][45] = -26, + [1][1][RTW89_WW][2][45] = 0, + [1][1][RTW89_WW][0][47] = -28, + [1][1][RTW89_WW][1][47] = -28, + [1][1][RTW89_WW][2][47] = 0, + [1][1][RTW89_WW][0][49] = -28, + [1][1][RTW89_WW][1][49] = -28, + [1][1][RTW89_WW][2][49] = 0, + [1][1][RTW89_WW][0][51] = -28, + [1][1][RTW89_WW][1][51] = -28, + [1][1][RTW89_WW][2][51] = 0, + [1][1][RTW89_WW][0][53] = -26, + [1][1][RTW89_WW][1][53] = -26, + [1][1][RTW89_WW][2][53] = 0, + [1][1][RTW89_WW][0][55] = -28, + [1][1][RTW89_WW][1][55] = -28, + [1][1][RTW89_WW][2][55] = 44, + [1][1][RTW89_WW][0][57] = -28, + [1][1][RTW89_WW][1][57] = -28, + [1][1][RTW89_WW][2][57] = 44, + [1][1][RTW89_WW][0][59] = -28, + [1][1][RTW89_WW][1][59] = -28, + [1][1][RTW89_WW][2][59] = 44, + [1][1][RTW89_WW][0][60] = -28, + [1][1][RTW89_WW][1][60] = -28, + [1][1][RTW89_WW][2][60] = 44, + [1][1][RTW89_WW][0][62] = -28, + [1][1][RTW89_WW][1][62] = -28, + [1][1][RTW89_WW][2][62] = 44, + [1][1][RTW89_WW][0][64] = -28, + [1][1][RTW89_WW][1][64] = -28, + [1][1][RTW89_WW][2][64] = 44, + [1][1][RTW89_WW][0][66] = -28, + [1][1][RTW89_WW][1][66] = -28, + [1][1][RTW89_WW][2][66] = 44, + [1][1][RTW89_WW][0][68] = -28, + [1][1][RTW89_WW][1][68] = -28, + [1][1][RTW89_WW][2][68] = 44, + [1][1][RTW89_WW][0][70] = -26, + [1][1][RTW89_WW][1][70] = -26, + [1][1][RTW89_WW][2][70] = 44, + [1][1][RTW89_WW][0][72] = -28, + [1][1][RTW89_WW][1][72] = -28, + [1][1][RTW89_WW][2][72] = 44, + [1][1][RTW89_WW][0][74] = -28, + [1][1][RTW89_WW][1][74] = -28, + [1][1][RTW89_WW][2][74] = 44, + [1][1][RTW89_WW][0][75] = -28, + [1][1][RTW89_WW][1][75] = -28, + [1][1][RTW89_WW][2][75] = 44, + [1][1][RTW89_WW][0][77] = -28, + [1][1][RTW89_WW][1][77] = -28, + [1][1][RTW89_WW][2][77] = 44, + [1][1][RTW89_WW][0][79] = -28, + [1][1][RTW89_WW][1][79] = -28, + [1][1][RTW89_WW][2][79] = 44, + [1][1][RTW89_WW][0][81] = -28, + [1][1][RTW89_WW][1][81] = -28, + [1][1][RTW89_WW][2][81] = 44, + [1][1][RTW89_WW][0][83] = -28, + [1][1][RTW89_WW][1][83] = -28, + [1][1][RTW89_WW][2][83] = 44, + [1][1][RTW89_WW][0][85] = -28, + [1][1][RTW89_WW][1][85] = -28, + [1][1][RTW89_WW][2][85] = 44, + [1][1][RTW89_WW][0][87] = -28, + [1][1][RTW89_WW][1][87] = -28, + [1][1][RTW89_WW][2][87] = 0, + [1][1][RTW89_WW][0][89] = -26, + [1][1][RTW89_WW][1][89] = -26, + [1][1][RTW89_WW][2][89] = 0, + [1][1][RTW89_WW][0][90] = -26, + [1][1][RTW89_WW][1][90] = -26, + [1][1][RTW89_WW][2][90] = 0, + [1][1][RTW89_WW][0][92] = -26, + [1][1][RTW89_WW][1][92] = -26, + [1][1][RTW89_WW][2][92] = 0, + [1][1][RTW89_WW][0][94] = -26, + [1][1][RTW89_WW][1][94] = -26, + [1][1][RTW89_WW][2][94] = 0, + [1][1][RTW89_WW][0][96] = -26, + [1][1][RTW89_WW][1][96] = -26, + [1][1][RTW89_WW][2][96] = 0, + [1][1][RTW89_WW][0][98] = -26, + [1][1][RTW89_WW][1][98] = -26, + [1][1][RTW89_WW][2][98] = 0, + [1][1][RTW89_WW][0][100] = -26, + [1][1][RTW89_WW][1][100] = -26, + [1][1][RTW89_WW][2][100] = 0, + [1][1][RTW89_WW][0][102] = -26, + [1][1][RTW89_WW][1][102] = -26, + [1][1][RTW89_WW][2][102] = 0, + [1][1][RTW89_WW][0][104] = -26, + [1][1][RTW89_WW][1][104] = -26, + [1][1][RTW89_WW][2][104] = 0, + [1][1][RTW89_WW][0][105] = -26, + [1][1][RTW89_WW][1][105] = -26, + [1][1][RTW89_WW][2][105] = 0, + [1][1][RTW89_WW][0][107] = -22, + [1][1][RTW89_WW][1][107] = -22, + [1][1][RTW89_WW][2][107] = 0, + [1][1][RTW89_WW][0][109] = -22, + [1][1][RTW89_WW][1][109] = -22, + [1][1][RTW89_WW][2][109] = 0, + [1][1][RTW89_WW][0][111] = 0, + [1][1][RTW89_WW][1][111] = 0, + [1][1][RTW89_WW][2][111] = 0, + [1][1][RTW89_WW][0][113] = 0, + [1][1][RTW89_WW][1][113] = 0, + [1][1][RTW89_WW][2][113] = 0, + [1][1][RTW89_WW][0][115] = 0, + [1][1][RTW89_WW][1][115] = 0, + [1][1][RTW89_WW][2][115] = 0, + [1][1][RTW89_WW][0][117] = 0, + [1][1][RTW89_WW][1][117] = 0, + [1][1][RTW89_WW][2][117] = 0, + [1][1][RTW89_WW][0][119] = 0, + [1][1][RTW89_WW][1][119] = 0, + [1][1][RTW89_WW][2][119] = 0, + [2][0][RTW89_WW][0][0] = -2, + [2][0][RTW89_WW][1][0] = -2, + [2][0][RTW89_WW][2][0] = 60, + [2][0][RTW89_WW][0][2] = -2, + [2][0][RTW89_WW][1][2] = -2, + [2][0][RTW89_WW][2][2] = 60, + [2][0][RTW89_WW][0][4] = -2, + [2][0][RTW89_WW][1][4] = -2, + [2][0][RTW89_WW][2][4] = 60, + [2][0][RTW89_WW][0][6] = -2, + [2][0][RTW89_WW][1][6] = -2, + [2][0][RTW89_WW][2][6] = 60, + [2][0][RTW89_WW][0][8] = -2, + [2][0][RTW89_WW][1][8] = -2, + [2][0][RTW89_WW][2][8] = 60, + [2][0][RTW89_WW][0][10] = -2, + [2][0][RTW89_WW][1][10] = -2, + [2][0][RTW89_WW][2][10] = 60, + [2][0][RTW89_WW][0][12] = -2, + [2][0][RTW89_WW][1][12] = -2, + [2][0][RTW89_WW][2][12] = 60, + [2][0][RTW89_WW][0][14] = -2, + [2][0][RTW89_WW][1][14] = -2, + [2][0][RTW89_WW][2][14] = 60, + [2][0][RTW89_WW][0][15] = -2, + [2][0][RTW89_WW][1][15] = -2, + [2][0][RTW89_WW][2][15] = 60, + [2][0][RTW89_WW][0][17] = -2, + [2][0][RTW89_WW][1][17] = -2, + [2][0][RTW89_WW][2][17] = 60, + [2][0][RTW89_WW][0][19] = -2, + [2][0][RTW89_WW][1][19] = -2, + [2][0][RTW89_WW][2][19] = 60, + [2][0][RTW89_WW][0][21] = -2, + [2][0][RTW89_WW][1][21] = -2, + [2][0][RTW89_WW][2][21] = 60, + [2][0][RTW89_WW][0][23] = -2, + [2][0][RTW89_WW][1][23] = -2, + [2][0][RTW89_WW][2][23] = 78, + [2][0][RTW89_WW][0][25] = -2, + [2][0][RTW89_WW][1][25] = -2, + [2][0][RTW89_WW][2][25] = 78, + [2][0][RTW89_WW][0][27] = -2, + [2][0][RTW89_WW][1][27] = -2, + [2][0][RTW89_WW][2][27] = 78, + [2][0][RTW89_WW][0][29] = -2, + [2][0][RTW89_WW][1][29] = -2, + [2][0][RTW89_WW][2][29] = 78, + [2][0][RTW89_WW][0][30] = -2, + [2][0][RTW89_WW][1][30] = -2, + [2][0][RTW89_WW][2][30] = 78, + [2][0][RTW89_WW][0][32] = -2, + [2][0][RTW89_WW][1][32] = -2, + [2][0][RTW89_WW][2][32] = 78, + [2][0][RTW89_WW][0][34] = -2, + [2][0][RTW89_WW][1][34] = -2, + [2][0][RTW89_WW][2][34] = 78, + [2][0][RTW89_WW][0][36] = -2, + [2][0][RTW89_WW][1][36] = -2, + [2][0][RTW89_WW][2][36] = 78, + [2][0][RTW89_WW][0][38] = -2, + [2][0][RTW89_WW][1][38] = -2, + [2][0][RTW89_WW][2][38] = 78, + [2][0][RTW89_WW][0][40] = -2, + [2][0][RTW89_WW][1][40] = -2, + [2][0][RTW89_WW][2][40] = 78, + [2][0][RTW89_WW][0][42] = -2, + [2][0][RTW89_WW][1][42] = -2, + [2][0][RTW89_WW][2][42] = 78, + [2][0][RTW89_WW][0][44] = -2, + [2][0][RTW89_WW][1][44] = -2, + [2][0][RTW89_WW][2][44] = 78, + [2][0][RTW89_WW][0][45] = -2, + [2][0][RTW89_WW][1][45] = -2, + [2][0][RTW89_WW][2][45] = 0, + [2][0][RTW89_WW][0][47] = -2, + [2][0][RTW89_WW][1][47] = -2, + [2][0][RTW89_WW][2][47] = 0, + [2][0][RTW89_WW][0][49] = -2, + [2][0][RTW89_WW][1][49] = -2, + [2][0][RTW89_WW][2][49] = 0, + [2][0][RTW89_WW][0][51] = -2, + [2][0][RTW89_WW][1][51] = -2, + [2][0][RTW89_WW][2][51] = 0, + [2][0][RTW89_WW][0][53] = -2, + [2][0][RTW89_WW][1][53] = -2, + [2][0][RTW89_WW][2][53] = 0, + [2][0][RTW89_WW][0][55] = -2, + [2][0][RTW89_WW][1][55] = -2, + [2][0][RTW89_WW][2][55] = 78, + [2][0][RTW89_WW][0][57] = -2, + [2][0][RTW89_WW][1][57] = -2, + [2][0][RTW89_WW][2][57] = 78, + [2][0][RTW89_WW][0][59] = -2, + [2][0][RTW89_WW][1][59] = -2, + [2][0][RTW89_WW][2][59] = 78, + [2][0][RTW89_WW][0][60] = -2, + [2][0][RTW89_WW][1][60] = -2, + [2][0][RTW89_WW][2][60] = 78, + [2][0][RTW89_WW][0][62] = -2, + [2][0][RTW89_WW][1][62] = -2, + [2][0][RTW89_WW][2][62] = 78, + [2][0][RTW89_WW][0][64] = -2, + [2][0][RTW89_WW][1][64] = -2, + [2][0][RTW89_WW][2][64] = 78, + [2][0][RTW89_WW][0][66] = -2, + [2][0][RTW89_WW][1][66] = -2, + [2][0][RTW89_WW][2][66] = 78, + [2][0][RTW89_WW][0][68] = -2, + [2][0][RTW89_WW][1][68] = -2, + [2][0][RTW89_WW][2][68] = 78, + [2][0][RTW89_WW][0][70] = -2, + [2][0][RTW89_WW][1][70] = -2, + [2][0][RTW89_WW][2][70] = 78, + [2][0][RTW89_WW][0][72] = -2, + [2][0][RTW89_WW][1][72] = -2, + [2][0][RTW89_WW][2][72] = 78, + [2][0][RTW89_WW][0][74] = -2, + [2][0][RTW89_WW][1][74] = -2, + [2][0][RTW89_WW][2][74] = 78, + [2][0][RTW89_WW][0][75] = -2, + [2][0][RTW89_WW][1][75] = -2, + [2][0][RTW89_WW][2][75] = 78, + [2][0][RTW89_WW][0][77] = -2, + [2][0][RTW89_WW][1][77] = -2, + [2][0][RTW89_WW][2][77] = 78, + [2][0][RTW89_WW][0][79] = -2, + [2][0][RTW89_WW][1][79] = -2, + [2][0][RTW89_WW][2][79] = 78, + [2][0][RTW89_WW][0][81] = -2, + [2][0][RTW89_WW][1][81] = -2, + [2][0][RTW89_WW][2][81] = 78, + [2][0][RTW89_WW][0][83] = -2, + [2][0][RTW89_WW][1][83] = -2, + [2][0][RTW89_WW][2][83] = 78, + [2][0][RTW89_WW][0][85] = -2, + [2][0][RTW89_WW][1][85] = -2, + [2][0][RTW89_WW][2][85] = 78, + [2][0][RTW89_WW][0][87] = -2, + [2][0][RTW89_WW][1][87] = -2, + [2][0][RTW89_WW][2][87] = 0, + [2][0][RTW89_WW][0][89] = -2, + [2][0][RTW89_WW][1][89] = -2, + [2][0][RTW89_WW][2][89] = 0, + [2][0][RTW89_WW][0][90] = -2, + [2][0][RTW89_WW][1][90] = -2, + [2][0][RTW89_WW][2][90] = 0, + [2][0][RTW89_WW][0][92] = -2, + [2][0][RTW89_WW][1][92] = -2, + [2][0][RTW89_WW][2][92] = 0, + [2][0][RTW89_WW][0][94] = -2, + [2][0][RTW89_WW][1][94] = -2, + [2][0][RTW89_WW][2][94] = 0, + [2][0][RTW89_WW][0][96] = -2, + [2][0][RTW89_WW][1][96] = -2, + [2][0][RTW89_WW][2][96] = 0, + [2][0][RTW89_WW][0][98] = -2, + [2][0][RTW89_WW][1][98] = -2, + [2][0][RTW89_WW][2][98] = 0, + [2][0][RTW89_WW][0][100] = -2, + [2][0][RTW89_WW][1][100] = -2, + [2][0][RTW89_WW][2][100] = 0, + [2][0][RTW89_WW][0][102] = -2, + [2][0][RTW89_WW][1][102] = -2, + [2][0][RTW89_WW][2][102] = 0, + [2][0][RTW89_WW][0][104] = -2, + [2][0][RTW89_WW][1][104] = -2, + [2][0][RTW89_WW][2][104] = 0, + [2][0][RTW89_WW][0][105] = -2, + [2][0][RTW89_WW][1][105] = -2, + [2][0][RTW89_WW][2][105] = 0, + [2][0][RTW89_WW][0][107] = -2, + [2][0][RTW89_WW][1][107] = -2, + [2][0][RTW89_WW][2][107] = 0, + [2][0][RTW89_WW][0][109] = 12, + [2][0][RTW89_WW][1][109] = 12, + [2][0][RTW89_WW][2][109] = 0, + [2][0][RTW89_WW][0][111] = 0, + [2][0][RTW89_WW][1][111] = 0, + [2][0][RTW89_WW][2][111] = 0, + [2][0][RTW89_WW][0][113] = 0, + [2][0][RTW89_WW][1][113] = 0, + [2][0][RTW89_WW][2][113] = 0, + [2][0][RTW89_WW][0][115] = 0, + [2][0][RTW89_WW][1][115] = 0, + [2][0][RTW89_WW][2][115] = 0, + [2][0][RTW89_WW][0][117] = 0, + [2][0][RTW89_WW][1][117] = 0, + [2][0][RTW89_WW][2][117] = 0, + [2][0][RTW89_WW][0][119] = 0, + [2][0][RTW89_WW][1][119] = 0, + [2][0][RTW89_WW][2][119] = 0, + [2][1][RTW89_WW][0][0] = -16, + [2][1][RTW89_WW][1][0] = -16, + [2][1][RTW89_WW][2][0] = 54, + [2][1][RTW89_WW][0][2] = -16, + [2][1][RTW89_WW][1][2] = -16, + [2][1][RTW89_WW][2][2] = 54, + [2][1][RTW89_WW][0][4] = -16, + [2][1][RTW89_WW][1][4] = -16, + [2][1][RTW89_WW][2][4] = 54, + [2][1][RTW89_WW][0][6] = -16, + [2][1][RTW89_WW][1][6] = -16, + [2][1][RTW89_WW][2][6] = 54, + [2][1][RTW89_WW][0][8] = -16, + [2][1][RTW89_WW][1][8] = -16, + [2][1][RTW89_WW][2][8] = 54, + [2][1][RTW89_WW][0][10] = -16, + [2][1][RTW89_WW][1][10] = -16, + [2][1][RTW89_WW][2][10] = 54, + [2][1][RTW89_WW][0][12] = -16, + [2][1][RTW89_WW][1][12] = -16, + [2][1][RTW89_WW][2][12] = 54, + [2][1][RTW89_WW][0][14] = -16, + [2][1][RTW89_WW][1][14] = -16, + [2][1][RTW89_WW][2][14] = 54, + [2][1][RTW89_WW][0][15] = -16, + [2][1][RTW89_WW][1][15] = -16, + [2][1][RTW89_WW][2][15] = 54, + [2][1][RTW89_WW][0][17] = -16, + [2][1][RTW89_WW][1][17] = -16, + [2][1][RTW89_WW][2][17] = 54, + [2][1][RTW89_WW][0][19] = -16, + [2][1][RTW89_WW][1][19] = -16, + [2][1][RTW89_WW][2][19] = 54, + [2][1][RTW89_WW][0][21] = -16, + [2][1][RTW89_WW][1][21] = -16, + [2][1][RTW89_WW][2][21] = 54, + [2][1][RTW89_WW][0][23] = -16, + [2][1][RTW89_WW][1][23] = -16, + [2][1][RTW89_WW][2][23] = 54, + [2][1][RTW89_WW][0][25] = -16, + [2][1][RTW89_WW][1][25] = -16, + [2][1][RTW89_WW][2][25] = 54, + [2][1][RTW89_WW][0][27] = -16, + [2][1][RTW89_WW][1][27] = -16, + [2][1][RTW89_WW][2][27] = 54, + [2][1][RTW89_WW][0][29] = -16, + [2][1][RTW89_WW][1][29] = -16, + [2][1][RTW89_WW][2][29] = 54, + [2][1][RTW89_WW][0][30] = -16, + [2][1][RTW89_WW][1][30] = -16, + [2][1][RTW89_WW][2][30] = 54, + [2][1][RTW89_WW][0][32] = -16, + [2][1][RTW89_WW][1][32] = -16, + [2][1][RTW89_WW][2][32] = 54, + [2][1][RTW89_WW][0][34] = -16, + [2][1][RTW89_WW][1][34] = -16, + [2][1][RTW89_WW][2][34] = 54, + [2][1][RTW89_WW][0][36] = -16, + [2][1][RTW89_WW][1][36] = -16, + [2][1][RTW89_WW][2][36] = 54, + [2][1][RTW89_WW][0][38] = -16, + [2][1][RTW89_WW][1][38] = -16, + [2][1][RTW89_WW][2][38] = 54, + [2][1][RTW89_WW][0][40] = -16, + [2][1][RTW89_WW][1][40] = -16, + [2][1][RTW89_WW][2][40] = 54, + [2][1][RTW89_WW][0][42] = -16, + [2][1][RTW89_WW][1][42] = -16, + [2][1][RTW89_WW][2][42] = 54, + [2][1][RTW89_WW][0][44] = -16, + [2][1][RTW89_WW][1][44] = -16, + [2][1][RTW89_WW][2][44] = 54, + [2][1][RTW89_WW][0][45] = -16, + [2][1][RTW89_WW][1][45] = -16, + [2][1][RTW89_WW][2][45] = 0, + [2][1][RTW89_WW][0][47] = -16, + [2][1][RTW89_WW][1][47] = -16, + [2][1][RTW89_WW][2][47] = 0, + [2][1][RTW89_WW][0][49] = -16, + [2][1][RTW89_WW][1][49] = -16, + [2][1][RTW89_WW][2][49] = 0, + [2][1][RTW89_WW][0][51] = -16, + [2][1][RTW89_WW][1][51] = -16, + [2][1][RTW89_WW][2][51] = 0, + [2][1][RTW89_WW][0][53] = -16, + [2][1][RTW89_WW][1][53] = -16, + [2][1][RTW89_WW][2][53] = 0, + [2][1][RTW89_WW][0][55] = -16, + [2][1][RTW89_WW][1][55] = -16, + [2][1][RTW89_WW][2][55] = 54, + [2][1][RTW89_WW][0][57] = -16, + [2][1][RTW89_WW][1][57] = -16, + [2][1][RTW89_WW][2][57] = 54, + [2][1][RTW89_WW][0][59] = -16, + [2][1][RTW89_WW][1][59] = -16, + [2][1][RTW89_WW][2][59] = 54, + [2][1][RTW89_WW][0][60] = -16, + [2][1][RTW89_WW][1][60] = -16, + [2][1][RTW89_WW][2][60] = 54, + [2][1][RTW89_WW][0][62] = -16, + [2][1][RTW89_WW][1][62] = -16, + [2][1][RTW89_WW][2][62] = 54, + [2][1][RTW89_WW][0][64] = -16, + [2][1][RTW89_WW][1][64] = -16, + [2][1][RTW89_WW][2][64] = 54, + [2][1][RTW89_WW][0][66] = -16, + [2][1][RTW89_WW][1][66] = -16, + [2][1][RTW89_WW][2][66] = 54, + [2][1][RTW89_WW][0][68] = -16, + [2][1][RTW89_WW][1][68] = -16, + [2][1][RTW89_WW][2][68] = 54, + [2][1][RTW89_WW][0][70] = -16, + [2][1][RTW89_WW][1][70] = -16, + [2][1][RTW89_WW][2][70] = 56, + [2][1][RTW89_WW][0][72] = -16, + [2][1][RTW89_WW][1][72] = -16, + [2][1][RTW89_WW][2][72] = 56, + [2][1][RTW89_WW][0][74] = -16, + [2][1][RTW89_WW][1][74] = -16, + [2][1][RTW89_WW][2][74] = 56, + [2][1][RTW89_WW][0][75] = -16, + [2][1][RTW89_WW][1][75] = -16, + [2][1][RTW89_WW][2][75] = 56, + [2][1][RTW89_WW][0][77] = -16, + [2][1][RTW89_WW][1][77] = -16, + [2][1][RTW89_WW][2][77] = 56, + [2][1][RTW89_WW][0][79] = -16, + [2][1][RTW89_WW][1][79] = -16, + [2][1][RTW89_WW][2][79] = 56, + [2][1][RTW89_WW][0][81] = -16, + [2][1][RTW89_WW][1][81] = -16, + [2][1][RTW89_WW][2][81] = 56, + [2][1][RTW89_WW][0][83] = -16, + [2][1][RTW89_WW][1][83] = -16, + [2][1][RTW89_WW][2][83] = 56, + [2][1][RTW89_WW][0][85] = -18, + [2][1][RTW89_WW][1][85] = -18, + [2][1][RTW89_WW][2][85] = 56, + [2][1][RTW89_WW][0][87] = -16, + [2][1][RTW89_WW][1][87] = -16, + [2][1][RTW89_WW][2][87] = 0, + [2][1][RTW89_WW][0][89] = -16, + [2][1][RTW89_WW][1][89] = -16, + [2][1][RTW89_WW][2][89] = 0, + [2][1][RTW89_WW][0][90] = -16, + [2][1][RTW89_WW][1][90] = -16, + [2][1][RTW89_WW][2][90] = 0, + [2][1][RTW89_WW][0][92] = -16, + [2][1][RTW89_WW][1][92] = -16, + [2][1][RTW89_WW][2][92] = 0, + [2][1][RTW89_WW][0][94] = -16, + [2][1][RTW89_WW][1][94] = -16, + [2][1][RTW89_WW][2][94] = 0, + [2][1][RTW89_WW][0][96] = -16, + [2][1][RTW89_WW][1][96] = -16, + [2][1][RTW89_WW][2][96] = 0, + [2][1][RTW89_WW][0][98] = -16, + [2][1][RTW89_WW][1][98] = -16, + [2][1][RTW89_WW][2][98] = 0, + [2][1][RTW89_WW][0][100] = -16, + [2][1][RTW89_WW][1][100] = -16, + [2][1][RTW89_WW][2][100] = 0, + [2][1][RTW89_WW][0][102] = -16, + [2][1][RTW89_WW][1][102] = -16, + [2][1][RTW89_WW][2][102] = 0, + [2][1][RTW89_WW][0][104] = -16, + [2][1][RTW89_WW][1][104] = -16, + [2][1][RTW89_WW][2][104] = 0, + [2][1][RTW89_WW][0][105] = -16, + [2][1][RTW89_WW][1][105] = -16, + [2][1][RTW89_WW][2][105] = 0, + [2][1][RTW89_WW][0][107] = -14, + [2][1][RTW89_WW][1][107] = -14, + [2][1][RTW89_WW][2][107] = 0, + [2][1][RTW89_WW][0][109] = -10, + [2][1][RTW89_WW][1][109] = -10, + [2][1][RTW89_WW][2][109] = 0, + [2][1][RTW89_WW][0][111] = 0, + [2][1][RTW89_WW][1][111] = 0, + [2][1][RTW89_WW][2][111] = 0, + [2][1][RTW89_WW][0][113] = 0, + [2][1][RTW89_WW][1][113] = 0, + [2][1][RTW89_WW][2][113] = 0, + [2][1][RTW89_WW][0][115] = 0, + [2][1][RTW89_WW][1][115] = 0, + [2][1][RTW89_WW][2][115] = 0, + [2][1][RTW89_WW][0][117] = 0, + [2][1][RTW89_WW][1][117] = 0, + [2][1][RTW89_WW][2][117] = 0, + [2][1][RTW89_WW][0][119] = 0, + [2][1][RTW89_WW][1][119] = 0, + [2][1][RTW89_WW][2][119] = 0, + [0][0][RTW89_FCC][1][0] = -16, + [0][0][RTW89_FCC][2][0] = 44, + [0][0][RTW89_ETSI][1][0] = 32, + [0][0][RTW89_ETSI][0][0] = -8, + [0][0][RTW89_MKK][1][0] = 30, + [0][0][RTW89_MKK][0][0] = -8, + [0][0][RTW89_IC][1][0] = -16, + [0][0][RTW89_KCC][1][0] = -2, + [0][0][RTW89_KCC][0][0] = -2, + [0][0][RTW89_ACMA][1][0] = 32, + [0][0][RTW89_ACMA][0][0] = -8, + [0][0][RTW89_CHILE][1][0] = -16, + [0][0][RTW89_QATAR][1][0] = 32, + [0][0][RTW89_QATAR][0][0] = -8, + [0][0][RTW89_UK][1][0] = 32, + [0][0][RTW89_UK][0][0] = -8, + [0][0][RTW89_FCC][1][2] = -18, + [0][0][RTW89_FCC][2][2] = 44, + [0][0][RTW89_ETSI][1][2] = 32, + [0][0][RTW89_ETSI][0][2] = -8, + [0][0][RTW89_MKK][1][2] = 30, + [0][0][RTW89_MKK][0][2] = -8, + [0][0][RTW89_IC][1][2] = -18, + [0][0][RTW89_KCC][1][2] = -2, + [0][0][RTW89_KCC][0][2] = -2, + [0][0][RTW89_ACMA][1][2] = 32, + [0][0][RTW89_ACMA][0][2] = -8, + [0][0][RTW89_CHILE][1][2] = -18, + [0][0][RTW89_QATAR][1][2] = 32, + [0][0][RTW89_QATAR][0][2] = -8, + [0][0][RTW89_UK][1][2] = 32, + [0][0][RTW89_UK][0][2] = -8, + [0][0][RTW89_FCC][1][4] = -18, + [0][0][RTW89_FCC][2][4] = 44, + [0][0][RTW89_ETSI][1][4] = 32, + [0][0][RTW89_ETSI][0][4] = -8, + [0][0][RTW89_MKK][1][4] = 30, + [0][0][RTW89_MKK][0][4] = -8, + [0][0][RTW89_IC][1][4] = -18, + [0][0][RTW89_KCC][1][4] = -2, + [0][0][RTW89_KCC][0][4] = -2, + [0][0][RTW89_ACMA][1][4] = 32, + [0][0][RTW89_ACMA][0][4] = -8, + [0][0][RTW89_CHILE][1][4] = -18, + [0][0][RTW89_QATAR][1][4] = 32, + [0][0][RTW89_QATAR][0][4] = -8, + [0][0][RTW89_UK][1][4] = 32, + [0][0][RTW89_UK][0][4] = -8, + [0][0][RTW89_FCC][1][6] = -18, + [0][0][RTW89_FCC][2][6] = 44, + [0][0][RTW89_ETSI][1][6] = 32, + [0][0][RTW89_ETSI][0][6] = -8, + [0][0][RTW89_MKK][1][6] = 30, + [0][0][RTW89_MKK][0][6] = -8, + [0][0][RTW89_IC][1][6] = -18, + [0][0][RTW89_KCC][1][6] = -2, + [0][0][RTW89_KCC][0][6] = -2, + [0][0][RTW89_ACMA][1][6] = 32, + [0][0][RTW89_ACMA][0][6] = -8, + [0][0][RTW89_CHILE][1][6] = -18, + [0][0][RTW89_QATAR][1][6] = 32, + [0][0][RTW89_QATAR][0][6] = -8, + [0][0][RTW89_UK][1][6] = 32, + [0][0][RTW89_UK][0][6] = -8, + [0][0][RTW89_FCC][1][8] = -18, + [0][0][RTW89_FCC][2][8] = 44, + [0][0][RTW89_ETSI][1][8] = 32, + [0][0][RTW89_ETSI][0][8] = -8, + [0][0][RTW89_MKK][1][8] = 30, + [0][0][RTW89_MKK][0][8] = -8, + [0][0][RTW89_IC][1][8] = -18, + [0][0][RTW89_KCC][1][8] = -2, + [0][0][RTW89_KCC][0][8] = -2, + [0][0][RTW89_ACMA][1][8] = 32, + [0][0][RTW89_ACMA][0][8] = -8, + [0][0][RTW89_CHILE][1][8] = -18, + [0][0][RTW89_QATAR][1][8] = 32, + [0][0][RTW89_QATAR][0][8] = -8, + [0][0][RTW89_UK][1][8] = 32, + [0][0][RTW89_UK][0][8] = -8, + [0][0][RTW89_FCC][1][10] = -18, + [0][0][RTW89_FCC][2][10] = 44, + [0][0][RTW89_ETSI][1][10] = 32, + [0][0][RTW89_ETSI][0][10] = -8, + [0][0][RTW89_MKK][1][10] = 30, + [0][0][RTW89_MKK][0][10] = -8, + [0][0][RTW89_IC][1][10] = -18, + [0][0][RTW89_KCC][1][10] = -2, + [0][0][RTW89_KCC][0][10] = -2, + [0][0][RTW89_ACMA][1][10] = 32, + [0][0][RTW89_ACMA][0][10] = -8, + [0][0][RTW89_CHILE][1][10] = -18, + [0][0][RTW89_QATAR][1][10] = 32, + [0][0][RTW89_QATAR][0][10] = -8, + [0][0][RTW89_UK][1][10] = 32, + [0][0][RTW89_UK][0][10] = -8, + [0][0][RTW89_FCC][1][12] = -18, + [0][0][RTW89_FCC][2][12] = 44, + [0][0][RTW89_ETSI][1][12] = 32, + [0][0][RTW89_ETSI][0][12] = -8, + [0][0][RTW89_MKK][1][12] = 30, + [0][0][RTW89_MKK][0][12] = -8, + [0][0][RTW89_IC][1][12] = -18, + [0][0][RTW89_KCC][1][12] = -2, + [0][0][RTW89_KCC][0][12] = -2, + [0][0][RTW89_ACMA][1][12] = 32, + [0][0][RTW89_ACMA][0][12] = -8, + [0][0][RTW89_CHILE][1][12] = -18, + [0][0][RTW89_QATAR][1][12] = 32, + [0][0][RTW89_QATAR][0][12] = -8, + [0][0][RTW89_UK][1][12] = 32, + [0][0][RTW89_UK][0][12] = -8, + [0][0][RTW89_FCC][1][14] = -18, + [0][0][RTW89_FCC][2][14] = 44, + [0][0][RTW89_ETSI][1][14] = 32, + [0][0][RTW89_ETSI][0][14] = -8, + [0][0][RTW89_MKK][1][14] = 30, + [0][0][RTW89_MKK][0][14] = -8, + [0][0][RTW89_IC][1][14] = -18, + [0][0][RTW89_KCC][1][14] = -2, + [0][0][RTW89_KCC][0][14] = -2, + [0][0][RTW89_ACMA][1][14] = 32, + [0][0][RTW89_ACMA][0][14] = -8, + [0][0][RTW89_CHILE][1][14] = -18, + [0][0][RTW89_QATAR][1][14] = 32, + [0][0][RTW89_QATAR][0][14] = -8, + [0][0][RTW89_UK][1][14] = 32, + [0][0][RTW89_UK][0][14] = -8, + [0][0][RTW89_FCC][1][15] = -18, + [0][0][RTW89_FCC][2][15] = 44, + [0][0][RTW89_ETSI][1][15] = 32, + [0][0][RTW89_ETSI][0][15] = -8, + [0][0][RTW89_MKK][1][15] = 30, + [0][0][RTW89_MKK][0][15] = -8, + [0][0][RTW89_IC][1][15] = -18, + [0][0][RTW89_KCC][1][15] = -2, + [0][0][RTW89_KCC][0][15] = -2, + [0][0][RTW89_ACMA][1][15] = 32, + [0][0][RTW89_ACMA][0][15] = -8, + [0][0][RTW89_CHILE][1][15] = -18, + [0][0][RTW89_QATAR][1][15] = 32, + [0][0][RTW89_QATAR][0][15] = -8, + [0][0][RTW89_UK][1][15] = 32, + [0][0][RTW89_UK][0][15] = -8, + [0][0][RTW89_FCC][1][17] = -18, + [0][0][RTW89_FCC][2][17] = 44, + [0][0][RTW89_ETSI][1][17] = 32, + [0][0][RTW89_ETSI][0][17] = -8, + [0][0][RTW89_MKK][1][17] = 30, + [0][0][RTW89_MKK][0][17] = -8, + [0][0][RTW89_IC][1][17] = -18, + [0][0][RTW89_KCC][1][17] = -2, + [0][0][RTW89_KCC][0][17] = -2, + [0][0][RTW89_ACMA][1][17] = 32, + [0][0][RTW89_ACMA][0][17] = -8, + [0][0][RTW89_CHILE][1][17] = -18, + [0][0][RTW89_QATAR][1][17] = 32, + [0][0][RTW89_QATAR][0][17] = -8, + [0][0][RTW89_UK][1][17] = 32, + [0][0][RTW89_UK][0][17] = -8, + [0][0][RTW89_FCC][1][19] = -18, + [0][0][RTW89_FCC][2][19] = 44, + [0][0][RTW89_ETSI][1][19] = 32, + [0][0][RTW89_ETSI][0][19] = -8, + [0][0][RTW89_MKK][1][19] = 30, + [0][0][RTW89_MKK][0][19] = -8, + [0][0][RTW89_IC][1][19] = -18, + [0][0][RTW89_KCC][1][19] = -2, + [0][0][RTW89_KCC][0][19] = -2, + [0][0][RTW89_ACMA][1][19] = 32, + [0][0][RTW89_ACMA][0][19] = -8, + [0][0][RTW89_CHILE][1][19] = -18, + [0][0][RTW89_QATAR][1][19] = 32, + [0][0][RTW89_QATAR][0][19] = -8, + [0][0][RTW89_UK][1][19] = 32, + [0][0][RTW89_UK][0][19] = -8, + [0][0][RTW89_FCC][1][21] = -18, + [0][0][RTW89_FCC][2][21] = 44, + [0][0][RTW89_ETSI][1][21] = 32, + [0][0][RTW89_ETSI][0][21] = -8, + [0][0][RTW89_MKK][1][21] = 30, + [0][0][RTW89_MKK][0][21] = -8, + [0][0][RTW89_IC][1][21] = -18, + [0][0][RTW89_KCC][1][21] = -2, + [0][0][RTW89_KCC][0][21] = -2, + [0][0][RTW89_ACMA][1][21] = 32, + [0][0][RTW89_ACMA][0][21] = -8, + [0][0][RTW89_CHILE][1][21] = -18, + [0][0][RTW89_QATAR][1][21] = 32, + [0][0][RTW89_QATAR][0][21] = -8, + [0][0][RTW89_UK][1][21] = 32, + [0][0][RTW89_UK][0][21] = -8, + [0][0][RTW89_FCC][1][23] = -18, + [0][0][RTW89_FCC][2][23] = 54, + [0][0][RTW89_ETSI][1][23] = 32, + [0][0][RTW89_ETSI][0][23] = -8, + [0][0][RTW89_MKK][1][23] = 30, + [0][0][RTW89_MKK][0][23] = -8, + [0][0][RTW89_IC][1][23] = -18, + [0][0][RTW89_KCC][1][23] = -2, + [0][0][RTW89_KCC][0][23] = -2, + [0][0][RTW89_ACMA][1][23] = 32, + [0][0][RTW89_ACMA][0][23] = -8, + [0][0][RTW89_CHILE][1][23] = -18, + [0][0][RTW89_QATAR][1][23] = 32, + [0][0][RTW89_QATAR][0][23] = -8, + [0][0][RTW89_UK][1][23] = 32, + [0][0][RTW89_UK][0][23] = -8, + [0][0][RTW89_FCC][1][25] = -18, + [0][0][RTW89_FCC][2][25] = 54, + [0][0][RTW89_ETSI][1][25] = 32, + [0][0][RTW89_ETSI][0][25] = -8, + [0][0][RTW89_MKK][1][25] = 30, + [0][0][RTW89_MKK][0][25] = -8, + [0][0][RTW89_IC][1][25] = -18, + [0][0][RTW89_KCC][1][25] = -2, + [0][0][RTW89_KCC][0][25] = -2, + [0][0][RTW89_ACMA][1][25] = 32, + [0][0][RTW89_ACMA][0][25] = -8, + [0][0][RTW89_CHILE][1][25] = -18, + [0][0][RTW89_QATAR][1][25] = 32, + [0][0][RTW89_QATAR][0][25] = -8, + [0][0][RTW89_UK][1][25] = 32, + [0][0][RTW89_UK][0][25] = -8, + [0][0][RTW89_FCC][1][27] = -18, + [0][0][RTW89_FCC][2][27] = 54, + [0][0][RTW89_ETSI][1][27] = 32, + [0][0][RTW89_ETSI][0][27] = -8, + [0][0][RTW89_MKK][1][27] = 30, + [0][0][RTW89_MKK][0][27] = -8, + [0][0][RTW89_IC][1][27] = -18, + [0][0][RTW89_KCC][1][27] = -2, + [0][0][RTW89_KCC][0][27] = -2, + [0][0][RTW89_ACMA][1][27] = 32, + [0][0][RTW89_ACMA][0][27] = -8, + [0][0][RTW89_CHILE][1][27] = -18, + [0][0][RTW89_QATAR][1][27] = 32, + [0][0][RTW89_QATAR][0][27] = -8, + [0][0][RTW89_UK][1][27] = 32, + [0][0][RTW89_UK][0][27] = -8, + [0][0][RTW89_FCC][1][29] = -18, + [0][0][RTW89_FCC][2][29] = 54, + [0][0][RTW89_ETSI][1][29] = 32, + [0][0][RTW89_ETSI][0][29] = -8, + [0][0][RTW89_MKK][1][29] = 30, + [0][0][RTW89_MKK][0][29] = -8, + [0][0][RTW89_IC][1][29] = -18, + [0][0][RTW89_KCC][1][29] = -2, + [0][0][RTW89_KCC][0][29] = -2, + [0][0][RTW89_ACMA][1][29] = 32, + [0][0][RTW89_ACMA][0][29] = -8, + [0][0][RTW89_CHILE][1][29] = -18, + [0][0][RTW89_QATAR][1][29] = 32, + [0][0][RTW89_QATAR][0][29] = -8, + [0][0][RTW89_UK][1][29] = 32, + [0][0][RTW89_UK][0][29] = -8, + [0][0][RTW89_FCC][1][30] = -18, + [0][0][RTW89_FCC][2][30] = 54, + [0][0][RTW89_ETSI][1][30] = 32, + [0][0][RTW89_ETSI][0][30] = -8, + [0][0][RTW89_MKK][1][30] = 30, + [0][0][RTW89_MKK][0][30] = -8, + [0][0][RTW89_IC][1][30] = -18, + [0][0][RTW89_KCC][1][30] = -2, + [0][0][RTW89_KCC][0][30] = -2, + [0][0][RTW89_ACMA][1][30] = 32, + [0][0][RTW89_ACMA][0][30] = -8, + [0][0][RTW89_CHILE][1][30] = -18, + [0][0][RTW89_QATAR][1][30] = 32, + [0][0][RTW89_QATAR][0][30] = -8, + [0][0][RTW89_UK][1][30] = 32, + [0][0][RTW89_UK][0][30] = -8, + [0][0][RTW89_FCC][1][32] = -18, + [0][0][RTW89_FCC][2][32] = 54, + [0][0][RTW89_ETSI][1][32] = 32, + [0][0][RTW89_ETSI][0][32] = -8, + [0][0][RTW89_MKK][1][32] = 30, + [0][0][RTW89_MKK][0][32] = -8, + [0][0][RTW89_IC][1][32] = -18, + [0][0][RTW89_KCC][1][32] = -2, + [0][0][RTW89_KCC][0][32] = -2, + [0][0][RTW89_ACMA][1][32] = 32, + [0][0][RTW89_ACMA][0][32] = -8, + [0][0][RTW89_CHILE][1][32] = -18, + [0][0][RTW89_QATAR][1][32] = 32, + [0][0][RTW89_QATAR][0][32] = -8, + [0][0][RTW89_UK][1][32] = 32, + [0][0][RTW89_UK][0][32] = -8, + [0][0][RTW89_FCC][1][34] = -18, + [0][0][RTW89_FCC][2][34] = 54, + [0][0][RTW89_ETSI][1][34] = 32, + [0][0][RTW89_ETSI][0][34] = -8, + [0][0][RTW89_MKK][1][34] = 30, + [0][0][RTW89_MKK][0][34] = -8, + [0][0][RTW89_IC][1][34] = -18, + [0][0][RTW89_KCC][1][34] = -2, + [0][0][RTW89_KCC][0][34] = -2, + [0][0][RTW89_ACMA][1][34] = 32, + [0][0][RTW89_ACMA][0][34] = -8, + [0][0][RTW89_CHILE][1][34] = -18, + [0][0][RTW89_QATAR][1][34] = 32, + [0][0][RTW89_QATAR][0][34] = -8, + [0][0][RTW89_UK][1][34] = 32, + [0][0][RTW89_UK][0][34] = -8, + [0][0][RTW89_FCC][1][36] = -18, + [0][0][RTW89_FCC][2][36] = 54, + [0][0][RTW89_ETSI][1][36] = 32, + [0][0][RTW89_ETSI][0][36] = -8, + [0][0][RTW89_MKK][1][36] = 30, + [0][0][RTW89_MKK][0][36] = -8, + [0][0][RTW89_IC][1][36] = -18, + [0][0][RTW89_KCC][1][36] = -2, + [0][0][RTW89_KCC][0][36] = -2, + [0][0][RTW89_ACMA][1][36] = 32, + [0][0][RTW89_ACMA][0][36] = -8, + [0][0][RTW89_CHILE][1][36] = -18, + [0][0][RTW89_QATAR][1][36] = 32, + [0][0][RTW89_QATAR][0][36] = -8, + [0][0][RTW89_UK][1][36] = 32, + [0][0][RTW89_UK][0][36] = -8, + [0][0][RTW89_FCC][1][38] = -18, + [0][0][RTW89_FCC][2][38] = 54, + [0][0][RTW89_ETSI][1][38] = 32, + [0][0][RTW89_ETSI][0][38] = -8, + [0][0][RTW89_MKK][1][38] = 30, + [0][0][RTW89_MKK][0][38] = -8, + [0][0][RTW89_IC][1][38] = -18, + [0][0][RTW89_KCC][1][38] = -2, + [0][0][RTW89_KCC][0][38] = -2, + [0][0][RTW89_ACMA][1][38] = 32, + [0][0][RTW89_ACMA][0][38] = -8, + [0][0][RTW89_CHILE][1][38] = -18, + [0][0][RTW89_QATAR][1][38] = 32, + [0][0][RTW89_QATAR][0][38] = -8, + [0][0][RTW89_UK][1][38] = 32, + [0][0][RTW89_UK][0][38] = -8, + [0][0][RTW89_FCC][1][40] = -18, + [0][0][RTW89_FCC][2][40] = 54, + [0][0][RTW89_ETSI][1][40] = 32, + [0][0][RTW89_ETSI][0][40] = -8, + [0][0][RTW89_MKK][1][40] = 30, + [0][0][RTW89_MKK][0][40] = -8, + [0][0][RTW89_IC][1][40] = -18, + [0][0][RTW89_KCC][1][40] = -2, + [0][0][RTW89_KCC][0][40] = -2, + [0][0][RTW89_ACMA][1][40] = 32, + [0][0][RTW89_ACMA][0][40] = -8, + [0][0][RTW89_CHILE][1][40] = -18, + [0][0][RTW89_QATAR][1][40] = 32, + [0][0][RTW89_QATAR][0][40] = -8, + [0][0][RTW89_UK][1][40] = 32, + [0][0][RTW89_UK][0][40] = -8, + [0][0][RTW89_FCC][1][42] = -18, + [0][0][RTW89_FCC][2][42] = 54, + [0][0][RTW89_ETSI][1][42] = 32, + [0][0][RTW89_ETSI][0][42] = -8, + [0][0][RTW89_MKK][1][42] = 30, + [0][0][RTW89_MKK][0][42] = -8, + [0][0][RTW89_IC][1][42] = -18, + [0][0][RTW89_KCC][1][42] = -2, + [0][0][RTW89_KCC][0][42] = -2, + [0][0][RTW89_ACMA][1][42] = 32, + [0][0][RTW89_ACMA][0][42] = -8, + [0][0][RTW89_CHILE][1][42] = -18, + [0][0][RTW89_QATAR][1][42] = 32, + [0][0][RTW89_QATAR][0][42] = -8, + [0][0][RTW89_UK][1][42] = 32, + [0][0][RTW89_UK][0][42] = -8, + [0][0][RTW89_FCC][1][44] = -16, + [0][0][RTW89_FCC][2][44] = 56, + [0][0][RTW89_ETSI][1][44] = 32, + [0][0][RTW89_ETSI][0][44] = -6, + [0][0][RTW89_MKK][1][44] = 8, + [0][0][RTW89_MKK][0][44] = -10, + [0][0][RTW89_IC][1][44] = -16, + [0][0][RTW89_KCC][1][44] = -2, + [0][0][RTW89_KCC][0][44] = -2, + [0][0][RTW89_ACMA][1][44] = 32, + [0][0][RTW89_ACMA][0][44] = -6, + [0][0][RTW89_CHILE][1][44] = -16, + [0][0][RTW89_QATAR][1][44] = 32, + [0][0][RTW89_QATAR][0][44] = -6, + [0][0][RTW89_UK][1][44] = 32, + [0][0][RTW89_UK][0][44] = -6, + [0][0][RTW89_FCC][1][45] = -16, + [0][0][RTW89_FCC][2][45] = 127, + [0][0][RTW89_ETSI][1][45] = 127, + [0][0][RTW89_ETSI][0][45] = 127, + [0][0][RTW89_MKK][1][45] = 127, + [0][0][RTW89_MKK][0][45] = 127, + [0][0][RTW89_IC][1][45] = -16, + [0][0][RTW89_KCC][1][45] = -2, + [0][0][RTW89_KCC][0][45] = 127, + [0][0][RTW89_ACMA][1][45] = 127, + [0][0][RTW89_ACMA][0][45] = 127, + [0][0][RTW89_CHILE][1][45] = 127, + [0][0][RTW89_QATAR][1][45] = 127, + [0][0][RTW89_QATAR][0][45] = 127, + [0][0][RTW89_UK][1][45] = 127, + [0][0][RTW89_UK][0][45] = 127, + [0][0][RTW89_FCC][1][47] = -18, + [0][0][RTW89_FCC][2][47] = 127, + [0][0][RTW89_ETSI][1][47] = 127, + [0][0][RTW89_ETSI][0][47] = 127, + [0][0][RTW89_MKK][1][47] = 127, + [0][0][RTW89_MKK][0][47] = 127, + [0][0][RTW89_IC][1][47] = -18, + [0][0][RTW89_KCC][1][47] = -2, + [0][0][RTW89_KCC][0][47] = 127, + [0][0][RTW89_ACMA][1][47] = 127, + [0][0][RTW89_ACMA][0][47] = 127, + [0][0][RTW89_CHILE][1][47] = 127, + [0][0][RTW89_QATAR][1][47] = 127, + [0][0][RTW89_QATAR][0][47] = 127, + [0][0][RTW89_UK][1][47] = 127, + [0][0][RTW89_UK][0][47] = 127, + [0][0][RTW89_FCC][1][49] = -18, + [0][0][RTW89_FCC][2][49] = 127, + [0][0][RTW89_ETSI][1][49] = 127, + [0][0][RTW89_ETSI][0][49] = 127, + [0][0][RTW89_MKK][1][49] = 127, + [0][0][RTW89_MKK][0][49] = 127, + [0][0][RTW89_IC][1][49] = -18, + [0][0][RTW89_KCC][1][49] = -2, + [0][0][RTW89_KCC][0][49] = 127, + [0][0][RTW89_ACMA][1][49] = 127, + [0][0][RTW89_ACMA][0][49] = 127, + [0][0][RTW89_CHILE][1][49] = 127, + [0][0][RTW89_QATAR][1][49] = 127, + [0][0][RTW89_QATAR][0][49] = 127, + [0][0][RTW89_UK][1][49] = 127, + [0][0][RTW89_UK][0][49] = 127, + [0][0][RTW89_FCC][1][51] = -18, + [0][0][RTW89_FCC][2][51] = 127, + [0][0][RTW89_ETSI][1][51] = 127, + [0][0][RTW89_ETSI][0][51] = 127, + [0][0][RTW89_MKK][1][51] = 127, + [0][0][RTW89_MKK][0][51] = 127, + [0][0][RTW89_IC][1][51] = -18, + [0][0][RTW89_KCC][1][51] = -2, + [0][0][RTW89_KCC][0][51] = 127, + [0][0][RTW89_ACMA][1][51] = 127, + [0][0][RTW89_ACMA][0][51] = 127, + [0][0][RTW89_CHILE][1][51] = 127, + [0][0][RTW89_QATAR][1][51] = 127, + [0][0][RTW89_QATAR][0][51] = 127, + [0][0][RTW89_UK][1][51] = 127, + [0][0][RTW89_UK][0][51] = 127, + [0][0][RTW89_FCC][1][53] = -16, + [0][0][RTW89_FCC][2][53] = 127, + [0][0][RTW89_ETSI][1][53] = 127, + [0][0][RTW89_ETSI][0][53] = 127, + [0][0][RTW89_MKK][1][53] = 127, + [0][0][RTW89_MKK][0][53] = 127, + [0][0][RTW89_IC][1][53] = -16, + [0][0][RTW89_KCC][1][53] = -2, + [0][0][RTW89_KCC][0][53] = 127, + [0][0][RTW89_ACMA][1][53] = 127, + [0][0][RTW89_ACMA][0][53] = 127, + [0][0][RTW89_CHILE][1][53] = 127, + [0][0][RTW89_QATAR][1][53] = 127, + [0][0][RTW89_QATAR][0][53] = 127, + [0][0][RTW89_UK][1][53] = 127, + [0][0][RTW89_UK][0][53] = 127, + [0][0][RTW89_FCC][1][55] = -18, + [0][0][RTW89_FCC][2][55] = 56, + [0][0][RTW89_ETSI][1][55] = 127, + [0][0][RTW89_ETSI][0][55] = 127, + [0][0][RTW89_MKK][1][55] = 127, + [0][0][RTW89_MKK][0][55] = 127, + [0][0][RTW89_IC][1][55] = -18, + [0][0][RTW89_KCC][1][55] = -2, + [0][0][RTW89_KCC][0][55] = 127, + [0][0][RTW89_ACMA][1][55] = 127, + [0][0][RTW89_ACMA][0][55] = 127, + [0][0][RTW89_CHILE][1][55] = 127, + [0][0][RTW89_QATAR][1][55] = 127, + [0][0][RTW89_QATAR][0][55] = 127, + [0][0][RTW89_UK][1][55] = 127, + [0][0][RTW89_UK][0][55] = 127, + [0][0][RTW89_FCC][1][57] = -18, + [0][0][RTW89_FCC][2][57] = 56, + [0][0][RTW89_ETSI][1][57] = 127, + [0][0][RTW89_ETSI][0][57] = 127, + [0][0][RTW89_MKK][1][57] = 127, + [0][0][RTW89_MKK][0][57] = 127, + [0][0][RTW89_IC][1][57] = -18, + [0][0][RTW89_KCC][1][57] = -2, + [0][0][RTW89_KCC][0][57] = 127, + [0][0][RTW89_ACMA][1][57] = 127, + [0][0][RTW89_ACMA][0][57] = 127, + [0][0][RTW89_CHILE][1][57] = 127, + [0][0][RTW89_QATAR][1][57] = 127, + [0][0][RTW89_QATAR][0][57] = 127, + [0][0][RTW89_UK][1][57] = 127, + [0][0][RTW89_UK][0][57] = 127, + [0][0][RTW89_FCC][1][59] = -18, + [0][0][RTW89_FCC][2][59] = 56, + [0][0][RTW89_ETSI][1][59] = 127, + [0][0][RTW89_ETSI][0][59] = 127, + [0][0][RTW89_MKK][1][59] = 127, + [0][0][RTW89_MKK][0][59] = 127, + [0][0][RTW89_IC][1][59] = -18, + [0][0][RTW89_KCC][1][59] = -2, + [0][0][RTW89_KCC][0][59] = 127, + [0][0][RTW89_ACMA][1][59] = 127, + [0][0][RTW89_ACMA][0][59] = 127, + [0][0][RTW89_CHILE][1][59] = 127, + [0][0][RTW89_QATAR][1][59] = 127, + [0][0][RTW89_QATAR][0][59] = 127, + [0][0][RTW89_UK][1][59] = 127, + [0][0][RTW89_UK][0][59] = 127, + [0][0][RTW89_FCC][1][60] = -18, + [0][0][RTW89_FCC][2][60] = 56, + [0][0][RTW89_ETSI][1][60] = 127, + [0][0][RTW89_ETSI][0][60] = 127, + [0][0][RTW89_MKK][1][60] = 127, + [0][0][RTW89_MKK][0][60] = 127, + [0][0][RTW89_IC][1][60] = -18, + [0][0][RTW89_KCC][1][60] = -2, + [0][0][RTW89_KCC][0][60] = 127, + [0][0][RTW89_ACMA][1][60] = 127, + [0][0][RTW89_ACMA][0][60] = 127, + [0][0][RTW89_CHILE][1][60] = 127, + [0][0][RTW89_QATAR][1][60] = 127, + [0][0][RTW89_QATAR][0][60] = 127, + [0][0][RTW89_UK][1][60] = 127, + [0][0][RTW89_UK][0][60] = 127, + [0][0][RTW89_FCC][1][62] = -18, + [0][0][RTW89_FCC][2][62] = 56, + [0][0][RTW89_ETSI][1][62] = 127, + [0][0][RTW89_ETSI][0][62] = 127, + [0][0][RTW89_MKK][1][62] = 127, + [0][0][RTW89_MKK][0][62] = 127, + [0][0][RTW89_IC][1][62] = -18, + [0][0][RTW89_KCC][1][62] = -2, + [0][0][RTW89_KCC][0][62] = 127, + [0][0][RTW89_ACMA][1][62] = 127, + [0][0][RTW89_ACMA][0][62] = 127, + [0][0][RTW89_CHILE][1][62] = 127, + [0][0][RTW89_QATAR][1][62] = 127, + [0][0][RTW89_QATAR][0][62] = 127, + [0][0][RTW89_UK][1][62] = 127, + [0][0][RTW89_UK][0][62] = 127, + [0][0][RTW89_FCC][1][64] = -18, + [0][0][RTW89_FCC][2][64] = 56, + [0][0][RTW89_ETSI][1][64] = 127, + [0][0][RTW89_ETSI][0][64] = 127, + [0][0][RTW89_MKK][1][64] = 127, + [0][0][RTW89_MKK][0][64] = 127, + [0][0][RTW89_IC][1][64] = -18, + [0][0][RTW89_KCC][1][64] = -2, + [0][0][RTW89_KCC][0][64] = 127, + [0][0][RTW89_ACMA][1][64] = 127, + [0][0][RTW89_ACMA][0][64] = 127, + [0][0][RTW89_CHILE][1][64] = 127, + [0][0][RTW89_QATAR][1][64] = 127, + [0][0][RTW89_QATAR][0][64] = 127, + [0][0][RTW89_UK][1][64] = 127, + [0][0][RTW89_UK][0][64] = 127, + [0][0][RTW89_FCC][1][66] = -18, + [0][0][RTW89_FCC][2][66] = 56, + [0][0][RTW89_ETSI][1][66] = 127, + [0][0][RTW89_ETSI][0][66] = 127, + [0][0][RTW89_MKK][1][66] = 127, + [0][0][RTW89_MKK][0][66] = 127, + [0][0][RTW89_IC][1][66] = -18, + [0][0][RTW89_KCC][1][66] = -2, + [0][0][RTW89_KCC][0][66] = 127, + [0][0][RTW89_ACMA][1][66] = 127, + [0][0][RTW89_ACMA][0][66] = 127, + [0][0][RTW89_CHILE][1][66] = 127, + [0][0][RTW89_QATAR][1][66] = 127, + [0][0][RTW89_QATAR][0][66] = 127, + [0][0][RTW89_UK][1][66] = 127, + [0][0][RTW89_UK][0][66] = 127, + [0][0][RTW89_FCC][1][68] = -18, + [0][0][RTW89_FCC][2][68] = 56, + [0][0][RTW89_ETSI][1][68] = 127, + [0][0][RTW89_ETSI][0][68] = 127, + [0][0][RTW89_MKK][1][68] = 127, + [0][0][RTW89_MKK][0][68] = 127, + [0][0][RTW89_IC][1][68] = -18, + [0][0][RTW89_KCC][1][68] = -2, + [0][0][RTW89_KCC][0][68] = 127, + [0][0][RTW89_ACMA][1][68] = 127, + [0][0][RTW89_ACMA][0][68] = 127, + [0][0][RTW89_CHILE][1][68] = 127, + [0][0][RTW89_QATAR][1][68] = 127, + [0][0][RTW89_QATAR][0][68] = 127, + [0][0][RTW89_UK][1][68] = 127, + [0][0][RTW89_UK][0][68] = 127, + [0][0][RTW89_FCC][1][70] = -16, + [0][0][RTW89_FCC][2][70] = 56, + [0][0][RTW89_ETSI][1][70] = 127, + [0][0][RTW89_ETSI][0][70] = 127, + [0][0][RTW89_MKK][1][70] = 127, + [0][0][RTW89_MKK][0][70] = 127, + [0][0][RTW89_IC][1][70] = -16, + [0][0][RTW89_KCC][1][70] = -2, + [0][0][RTW89_KCC][0][70] = 127, + [0][0][RTW89_ACMA][1][70] = 127, + [0][0][RTW89_ACMA][0][70] = 127, + [0][0][RTW89_CHILE][1][70] = 127, + [0][0][RTW89_QATAR][1][70] = 127, + [0][0][RTW89_QATAR][0][70] = 127, + [0][0][RTW89_UK][1][70] = 127, + [0][0][RTW89_UK][0][70] = 127, + [0][0][RTW89_FCC][1][72] = -18, + [0][0][RTW89_FCC][2][72] = 56, + [0][0][RTW89_ETSI][1][72] = 127, + [0][0][RTW89_ETSI][0][72] = 127, + [0][0][RTW89_MKK][1][72] = 127, + [0][0][RTW89_MKK][0][72] = 127, + [0][0][RTW89_IC][1][72] = -18, + [0][0][RTW89_KCC][1][72] = -2, + [0][0][RTW89_KCC][0][72] = 127, + [0][0][RTW89_ACMA][1][72] = 127, + [0][0][RTW89_ACMA][0][72] = 127, + [0][0][RTW89_CHILE][1][72] = 127, + [0][0][RTW89_QATAR][1][72] = 127, + [0][0][RTW89_QATAR][0][72] = 127, + [0][0][RTW89_UK][1][72] = 127, + [0][0][RTW89_UK][0][72] = 127, + [0][0][RTW89_FCC][1][74] = -18, + [0][0][RTW89_FCC][2][74] = 56, + [0][0][RTW89_ETSI][1][74] = 127, + [0][0][RTW89_ETSI][0][74] = 127, + [0][0][RTW89_MKK][1][74] = 127, + [0][0][RTW89_MKK][0][74] = 127, + [0][0][RTW89_IC][1][74] = -18, + [0][0][RTW89_KCC][1][74] = -2, + [0][0][RTW89_KCC][0][74] = 127, + [0][0][RTW89_ACMA][1][74] = 127, + [0][0][RTW89_ACMA][0][74] = 127, + [0][0][RTW89_CHILE][1][74] = 127, + [0][0][RTW89_QATAR][1][74] = 127, + [0][0][RTW89_QATAR][0][74] = 127, + [0][0][RTW89_UK][1][74] = 127, + [0][0][RTW89_UK][0][74] = 127, + [0][0][RTW89_FCC][1][75] = -18, + [0][0][RTW89_FCC][2][75] = 56, + [0][0][RTW89_ETSI][1][75] = 127, + [0][0][RTW89_ETSI][0][75] = 127, + [0][0][RTW89_MKK][1][75] = 127, + [0][0][RTW89_MKK][0][75] = 127, + [0][0][RTW89_IC][1][75] = -18, + [0][0][RTW89_KCC][1][75] = -2, + [0][0][RTW89_KCC][0][75] = 127, + [0][0][RTW89_ACMA][1][75] = 127, + [0][0][RTW89_ACMA][0][75] = 127, + [0][0][RTW89_CHILE][1][75] = 127, + [0][0][RTW89_QATAR][1][75] = 127, + [0][0][RTW89_QATAR][0][75] = 127, + [0][0][RTW89_UK][1][75] = 127, + [0][0][RTW89_UK][0][75] = 127, + [0][0][RTW89_FCC][1][77] = -18, + [0][0][RTW89_FCC][2][77] = 56, + [0][0][RTW89_ETSI][1][77] = 127, + [0][0][RTW89_ETSI][0][77] = 127, + [0][0][RTW89_MKK][1][77] = 127, + [0][0][RTW89_MKK][0][77] = 127, + [0][0][RTW89_IC][1][77] = -18, + [0][0][RTW89_KCC][1][77] = -2, + [0][0][RTW89_KCC][0][77] = 127, + [0][0][RTW89_ACMA][1][77] = 127, + [0][0][RTW89_ACMA][0][77] = 127, + [0][0][RTW89_CHILE][1][77] = 127, + [0][0][RTW89_QATAR][1][77] = 127, + [0][0][RTW89_QATAR][0][77] = 127, + [0][0][RTW89_UK][1][77] = 127, + [0][0][RTW89_UK][0][77] = 127, + [0][0][RTW89_FCC][1][79] = -18, + [0][0][RTW89_FCC][2][79] = 56, + [0][0][RTW89_ETSI][1][79] = 127, + [0][0][RTW89_ETSI][0][79] = 127, + [0][0][RTW89_MKK][1][79] = 127, + [0][0][RTW89_MKK][0][79] = 127, + [0][0][RTW89_IC][1][79] = -18, + [0][0][RTW89_KCC][1][79] = -2, + [0][0][RTW89_KCC][0][79] = 127, + [0][0][RTW89_ACMA][1][79] = 127, + [0][0][RTW89_ACMA][0][79] = 127, + [0][0][RTW89_CHILE][1][79] = 127, + [0][0][RTW89_QATAR][1][79] = 127, + [0][0][RTW89_QATAR][0][79] = 127, + [0][0][RTW89_UK][1][79] = 127, + [0][0][RTW89_UK][0][79] = 127, + [0][0][RTW89_FCC][1][81] = -18, + [0][0][RTW89_FCC][2][81] = 56, + [0][0][RTW89_ETSI][1][81] = 127, + [0][0][RTW89_ETSI][0][81] = 127, + [0][0][RTW89_MKK][1][81] = 127, + [0][0][RTW89_MKK][0][81] = 127, + [0][0][RTW89_IC][1][81] = -18, + [0][0][RTW89_KCC][1][81] = -2, + [0][0][RTW89_KCC][0][81] = 127, + [0][0][RTW89_ACMA][1][81] = 127, + [0][0][RTW89_ACMA][0][81] = 127, + [0][0][RTW89_CHILE][1][81] = 127, + [0][0][RTW89_QATAR][1][81] = 127, + [0][0][RTW89_QATAR][0][81] = 127, + [0][0][RTW89_UK][1][81] = 127, + [0][0][RTW89_UK][0][81] = 127, + [0][0][RTW89_FCC][1][83] = -18, + [0][0][RTW89_FCC][2][83] = 56, + [0][0][RTW89_ETSI][1][83] = 127, + [0][0][RTW89_ETSI][0][83] = 127, + [0][0][RTW89_MKK][1][83] = 127, + [0][0][RTW89_MKK][0][83] = 127, + [0][0][RTW89_IC][1][83] = -18, + [0][0][RTW89_KCC][1][83] = -2, + [0][0][RTW89_KCC][0][83] = 127, + [0][0][RTW89_ACMA][1][83] = 127, + [0][0][RTW89_ACMA][0][83] = 127, + [0][0][RTW89_CHILE][1][83] = 127, + [0][0][RTW89_QATAR][1][83] = 127, + [0][0][RTW89_QATAR][0][83] = 127, + [0][0][RTW89_UK][1][83] = 127, + [0][0][RTW89_UK][0][83] = 127, + [0][0][RTW89_FCC][1][85] = -18, + [0][0][RTW89_FCC][2][85] = 56, + [0][0][RTW89_ETSI][1][85] = 127, + [0][0][RTW89_ETSI][0][85] = 127, + [0][0][RTW89_MKK][1][85] = 127, + [0][0][RTW89_MKK][0][85] = 127, + [0][0][RTW89_IC][1][85] = -18, + [0][0][RTW89_KCC][1][85] = -2, + [0][0][RTW89_KCC][0][85] = 127, + [0][0][RTW89_ACMA][1][85] = 127, + [0][0][RTW89_ACMA][0][85] = 127, + [0][0][RTW89_CHILE][1][85] = 127, + [0][0][RTW89_QATAR][1][85] = 127, + [0][0][RTW89_QATAR][0][85] = 127, + [0][0][RTW89_UK][1][85] = 127, + [0][0][RTW89_UK][0][85] = 127, + [0][0][RTW89_FCC][1][87] = -16, + [0][0][RTW89_FCC][2][87] = 127, + [0][0][RTW89_ETSI][1][87] = 127, + [0][0][RTW89_ETSI][0][87] = 127, + [0][0][RTW89_MKK][1][87] = 127, + [0][0][RTW89_MKK][0][87] = 127, + [0][0][RTW89_IC][1][87] = -16, + [0][0][RTW89_KCC][1][87] = -2, + [0][0][RTW89_KCC][0][87] = 127, + [0][0][RTW89_ACMA][1][87] = 127, + [0][0][RTW89_ACMA][0][87] = 127, + [0][0][RTW89_CHILE][1][87] = 127, + [0][0][RTW89_QATAR][1][87] = 127, + [0][0][RTW89_QATAR][0][87] = 127, + [0][0][RTW89_UK][1][87] = 127, + [0][0][RTW89_UK][0][87] = 127, + [0][0][RTW89_FCC][1][89] = -16, + [0][0][RTW89_FCC][2][89] = 127, + [0][0][RTW89_ETSI][1][89] = 127, + [0][0][RTW89_ETSI][0][89] = 127, + [0][0][RTW89_MKK][1][89] = 127, + [0][0][RTW89_MKK][0][89] = 127, + [0][0][RTW89_IC][1][89] = -16, + [0][0][RTW89_KCC][1][89] = -2, + [0][0][RTW89_KCC][0][89] = 127, + [0][0][RTW89_ACMA][1][89] = 127, + [0][0][RTW89_ACMA][0][89] = 127, + [0][0][RTW89_CHILE][1][89] = 127, + [0][0][RTW89_QATAR][1][89] = 127, + [0][0][RTW89_QATAR][0][89] = 127, + [0][0][RTW89_UK][1][89] = 127, + [0][0][RTW89_UK][0][89] = 127, + [0][0][RTW89_FCC][1][90] = -16, + [0][0][RTW89_FCC][2][90] = 127, + [0][0][RTW89_ETSI][1][90] = 127, + [0][0][RTW89_ETSI][0][90] = 127, + [0][0][RTW89_MKK][1][90] = 127, + [0][0][RTW89_MKK][0][90] = 127, + [0][0][RTW89_IC][1][90] = -16, + [0][0][RTW89_KCC][1][90] = -2, + [0][0][RTW89_KCC][0][90] = 127, + [0][0][RTW89_ACMA][1][90] = 127, + [0][0][RTW89_ACMA][0][90] = 127, + [0][0][RTW89_CHILE][1][90] = 127, + [0][0][RTW89_QATAR][1][90] = 127, + [0][0][RTW89_QATAR][0][90] = 127, + [0][0][RTW89_UK][1][90] = 127, + [0][0][RTW89_UK][0][90] = 127, + [0][0][RTW89_FCC][1][92] = -16, + [0][0][RTW89_FCC][2][92] = 127, + [0][0][RTW89_ETSI][1][92] = 127, + [0][0][RTW89_ETSI][0][92] = 127, + [0][0][RTW89_MKK][1][92] = 127, + [0][0][RTW89_MKK][0][92] = 127, + [0][0][RTW89_IC][1][92] = -16, + [0][0][RTW89_KCC][1][92] = -2, + [0][0][RTW89_KCC][0][92] = 127, + [0][0][RTW89_ACMA][1][92] = 127, + [0][0][RTW89_ACMA][0][92] = 127, + [0][0][RTW89_CHILE][1][92] = 127, + [0][0][RTW89_QATAR][1][92] = 127, + [0][0][RTW89_QATAR][0][92] = 127, + [0][0][RTW89_UK][1][92] = 127, + [0][0][RTW89_UK][0][92] = 127, + [0][0][RTW89_FCC][1][94] = -16, + [0][0][RTW89_FCC][2][94] = 127, + [0][0][RTW89_ETSI][1][94] = 127, + [0][0][RTW89_ETSI][0][94] = 127, + [0][0][RTW89_MKK][1][94] = 127, + [0][0][RTW89_MKK][0][94] = 127, + [0][0][RTW89_IC][1][94] = -16, + [0][0][RTW89_KCC][1][94] = -2, + [0][0][RTW89_KCC][0][94] = 127, + [0][0][RTW89_ACMA][1][94] = 127, + [0][0][RTW89_ACMA][0][94] = 127, + [0][0][RTW89_CHILE][1][94] = 127, + [0][0][RTW89_QATAR][1][94] = 127, + [0][0][RTW89_QATAR][0][94] = 127, + [0][0][RTW89_UK][1][94] = 127, + [0][0][RTW89_UK][0][94] = 127, + [0][0][RTW89_FCC][1][96] = -16, + [0][0][RTW89_FCC][2][96] = 127, + [0][0][RTW89_ETSI][1][96] = 127, + [0][0][RTW89_ETSI][0][96] = 127, + [0][0][RTW89_MKK][1][96] = 127, + [0][0][RTW89_MKK][0][96] = 127, + [0][0][RTW89_IC][1][96] = -16, + [0][0][RTW89_KCC][1][96] = -2, + [0][0][RTW89_KCC][0][96] = 127, + [0][0][RTW89_ACMA][1][96] = 127, + [0][0][RTW89_ACMA][0][96] = 127, + [0][0][RTW89_CHILE][1][96] = 127, + [0][0][RTW89_QATAR][1][96] = 127, + [0][0][RTW89_QATAR][0][96] = 127, + [0][0][RTW89_UK][1][96] = 127, + [0][0][RTW89_UK][0][96] = 127, + [0][0][RTW89_FCC][1][98] = -16, + [0][0][RTW89_FCC][2][98] = 127, + [0][0][RTW89_ETSI][1][98] = 127, + [0][0][RTW89_ETSI][0][98] = 127, + [0][0][RTW89_MKK][1][98] = 127, + [0][0][RTW89_MKK][0][98] = 127, + [0][0][RTW89_IC][1][98] = -16, + [0][0][RTW89_KCC][1][98] = -2, + [0][0][RTW89_KCC][0][98] = 127, + [0][0][RTW89_ACMA][1][98] = 127, + [0][0][RTW89_ACMA][0][98] = 127, + [0][0][RTW89_CHILE][1][98] = 127, + [0][0][RTW89_QATAR][1][98] = 127, + [0][0][RTW89_QATAR][0][98] = 127, + [0][0][RTW89_UK][1][98] = 127, + [0][0][RTW89_UK][0][98] = 127, + [0][0][RTW89_FCC][1][100] = -16, + [0][0][RTW89_FCC][2][100] = 127, + [0][0][RTW89_ETSI][1][100] = 127, + [0][0][RTW89_ETSI][0][100] = 127, + [0][0][RTW89_MKK][1][100] = 127, + [0][0][RTW89_MKK][0][100] = 127, + [0][0][RTW89_IC][1][100] = -16, + [0][0][RTW89_KCC][1][100] = -2, + [0][0][RTW89_KCC][0][100] = 127, + [0][0][RTW89_ACMA][1][100] = 127, + [0][0][RTW89_ACMA][0][100] = 127, + [0][0][RTW89_CHILE][1][100] = 127, + [0][0][RTW89_QATAR][1][100] = 127, + [0][0][RTW89_QATAR][0][100] = 127, + [0][0][RTW89_UK][1][100] = 127, + [0][0][RTW89_UK][0][100] = 127, + [0][0][RTW89_FCC][1][102] = -16, + [0][0][RTW89_FCC][2][102] = 127, + [0][0][RTW89_ETSI][1][102] = 127, + [0][0][RTW89_ETSI][0][102] = 127, + [0][0][RTW89_MKK][1][102] = 127, + [0][0][RTW89_MKK][0][102] = 127, + [0][0][RTW89_IC][1][102] = -16, + [0][0][RTW89_KCC][1][102] = -2, + [0][0][RTW89_KCC][0][102] = 127, + [0][0][RTW89_ACMA][1][102] = 127, + [0][0][RTW89_ACMA][0][102] = 127, + [0][0][RTW89_CHILE][1][102] = 127, + [0][0][RTW89_QATAR][1][102] = 127, + [0][0][RTW89_QATAR][0][102] = 127, + [0][0][RTW89_UK][1][102] = 127, + [0][0][RTW89_UK][0][102] = 127, + [0][0][RTW89_FCC][1][104] = -16, + [0][0][RTW89_FCC][2][104] = 127, + [0][0][RTW89_ETSI][1][104] = 127, + [0][0][RTW89_ETSI][0][104] = 127, + [0][0][RTW89_MKK][1][104] = 127, + [0][0][RTW89_MKK][0][104] = 127, + [0][0][RTW89_IC][1][104] = -16, + [0][0][RTW89_KCC][1][104] = -2, + [0][0][RTW89_KCC][0][104] = 127, + [0][0][RTW89_ACMA][1][104] = 127, + [0][0][RTW89_ACMA][0][104] = 127, + [0][0][RTW89_CHILE][1][104] = 127, + [0][0][RTW89_QATAR][1][104] = 127, + [0][0][RTW89_QATAR][0][104] = 127, + [0][0][RTW89_UK][1][104] = 127, + [0][0][RTW89_UK][0][104] = 127, + [0][0][RTW89_FCC][1][105] = -16, + [0][0][RTW89_FCC][2][105] = 127, + [0][0][RTW89_ETSI][1][105] = 127, + [0][0][RTW89_ETSI][0][105] = 127, + [0][0][RTW89_MKK][1][105] = 127, + [0][0][RTW89_MKK][0][105] = 127, + [0][0][RTW89_IC][1][105] = -16, + [0][0][RTW89_KCC][1][105] = -2, + [0][0][RTW89_KCC][0][105] = 127, + [0][0][RTW89_ACMA][1][105] = 127, + [0][0][RTW89_ACMA][0][105] = 127, + [0][0][RTW89_CHILE][1][105] = 127, + [0][0][RTW89_QATAR][1][105] = 127, + [0][0][RTW89_QATAR][0][105] = 127, + [0][0][RTW89_UK][1][105] = 127, + [0][0][RTW89_UK][0][105] = 127, + [0][0][RTW89_FCC][1][107] = -12, + [0][0][RTW89_FCC][2][107] = 127, + [0][0][RTW89_ETSI][1][107] = 127, + [0][0][RTW89_ETSI][0][107] = 127, + [0][0][RTW89_MKK][1][107] = 127, + [0][0][RTW89_MKK][0][107] = 127, + [0][0][RTW89_IC][1][107] = -12, + [0][0][RTW89_KCC][1][107] = -2, + [0][0][RTW89_KCC][0][107] = 127, + [0][0][RTW89_ACMA][1][107] = 127, + [0][0][RTW89_ACMA][0][107] = 127, + [0][0][RTW89_CHILE][1][107] = 127, + [0][0][RTW89_QATAR][1][107] = 127, + [0][0][RTW89_QATAR][0][107] = 127, + [0][0][RTW89_UK][1][107] = 127, + [0][0][RTW89_UK][0][107] = 127, + [0][0][RTW89_FCC][1][109] = -12, + [0][0][RTW89_FCC][2][109] = 127, + [0][0][RTW89_ETSI][1][109] = 127, + [0][0][RTW89_ETSI][0][109] = 127, + [0][0][RTW89_MKK][1][109] = 127, + [0][0][RTW89_MKK][0][109] = 127, + [0][0][RTW89_IC][1][109] = -12, + [0][0][RTW89_KCC][1][109] = 127, + [0][0][RTW89_KCC][0][109] = 127, + [0][0][RTW89_ACMA][1][109] = 127, + [0][0][RTW89_ACMA][0][109] = 127, + [0][0][RTW89_CHILE][1][109] = 127, + [0][0][RTW89_QATAR][1][109] = 127, + [0][0][RTW89_QATAR][0][109] = 127, + [0][0][RTW89_UK][1][109] = 127, + [0][0][RTW89_UK][0][109] = 127, + [0][0][RTW89_FCC][1][111] = 127, + [0][0][RTW89_FCC][2][111] = 127, + [0][0][RTW89_ETSI][1][111] = 127, + [0][0][RTW89_ETSI][0][111] = 127, + [0][0][RTW89_MKK][1][111] = 127, + [0][0][RTW89_MKK][0][111] = 127, + [0][0][RTW89_IC][1][111] = 127, + [0][0][RTW89_KCC][1][111] = 127, + [0][0][RTW89_KCC][0][111] = 127, + [0][0][RTW89_ACMA][1][111] = 127, + [0][0][RTW89_ACMA][0][111] = 127, + [0][0][RTW89_CHILE][1][111] = 127, + [0][0][RTW89_QATAR][1][111] = 127, + [0][0][RTW89_QATAR][0][111] = 127, + [0][0][RTW89_UK][1][111] = 127, + [0][0][RTW89_UK][0][111] = 127, + [0][0][RTW89_FCC][1][113] = 127, + [0][0][RTW89_FCC][2][113] = 127, + [0][0][RTW89_ETSI][1][113] = 127, + [0][0][RTW89_ETSI][0][113] = 127, + [0][0][RTW89_MKK][1][113] = 127, + [0][0][RTW89_MKK][0][113] = 127, + [0][0][RTW89_IC][1][113] = 127, + [0][0][RTW89_KCC][1][113] = 127, + [0][0][RTW89_KCC][0][113] = 127, + [0][0][RTW89_ACMA][1][113] = 127, + [0][0][RTW89_ACMA][0][113] = 127, + [0][0][RTW89_CHILE][1][113] = 127, + [0][0][RTW89_QATAR][1][113] = 127, + [0][0][RTW89_QATAR][0][113] = 127, + [0][0][RTW89_UK][1][113] = 127, + [0][0][RTW89_UK][0][113] = 127, + [0][0][RTW89_FCC][1][115] = 127, + [0][0][RTW89_FCC][2][115] = 127, + [0][0][RTW89_ETSI][1][115] = 127, + [0][0][RTW89_ETSI][0][115] = 127, + [0][0][RTW89_MKK][1][115] = 127, + [0][0][RTW89_MKK][0][115] = 127, + [0][0][RTW89_IC][1][115] = 127, + [0][0][RTW89_KCC][1][115] = 127, + [0][0][RTW89_KCC][0][115] = 127, + [0][0][RTW89_ACMA][1][115] = 127, + [0][0][RTW89_ACMA][0][115] = 127, + [0][0][RTW89_CHILE][1][115] = 127, + [0][0][RTW89_QATAR][1][115] = 127, + [0][0][RTW89_QATAR][0][115] = 127, + [0][0][RTW89_UK][1][115] = 127, + [0][0][RTW89_UK][0][115] = 127, + [0][0][RTW89_FCC][1][117] = 127, + [0][0][RTW89_FCC][2][117] = 127, + [0][0][RTW89_ETSI][1][117] = 127, + [0][0][RTW89_ETSI][0][117] = 127, + [0][0][RTW89_MKK][1][117] = 127, + [0][0][RTW89_MKK][0][117] = 127, + [0][0][RTW89_IC][1][117] = 127, + [0][0][RTW89_KCC][1][117] = 127, + [0][0][RTW89_KCC][0][117] = 127, + [0][0][RTW89_ACMA][1][117] = 127, + [0][0][RTW89_ACMA][0][117] = 127, + [0][0][RTW89_CHILE][1][117] = 127, + [0][0][RTW89_QATAR][1][117] = 127, + [0][0][RTW89_QATAR][0][117] = 127, + [0][0][RTW89_UK][1][117] = 127, + [0][0][RTW89_UK][0][117] = 127, + [0][0][RTW89_FCC][1][119] = 127, + [0][0][RTW89_FCC][2][119] = 127, + [0][0][RTW89_ETSI][1][119] = 127, + [0][0][RTW89_ETSI][0][119] = 127, + [0][0][RTW89_MKK][1][119] = 127, + [0][0][RTW89_MKK][0][119] = 127, + [0][0][RTW89_IC][1][119] = 127, + [0][0][RTW89_KCC][1][119] = 127, + [0][0][RTW89_KCC][0][119] = 127, + [0][0][RTW89_ACMA][1][119] = 127, + [0][0][RTW89_ACMA][0][119] = 127, + [0][0][RTW89_CHILE][1][119] = 127, + [0][0][RTW89_QATAR][1][119] = 127, + [0][0][RTW89_QATAR][0][119] = 127, + [0][0][RTW89_UK][1][119] = 127, + [0][0][RTW89_UK][0][119] = 127, + [0][1][RTW89_FCC][1][0] = -40, + [0][1][RTW89_FCC][2][0] = 32, + [0][1][RTW89_ETSI][1][0] = 20, + [0][1][RTW89_ETSI][0][0] = -18, + [0][1][RTW89_MKK][1][0] = 18, + [0][1][RTW89_MKK][0][0] = -20, + [0][1][RTW89_IC][1][0] = -40, + [0][1][RTW89_KCC][1][0] = -14, + [0][1][RTW89_KCC][0][0] = -14, + [0][1][RTW89_ACMA][1][0] = 20, + [0][1][RTW89_ACMA][0][0] = -18, + [0][1][RTW89_CHILE][1][0] = -40, + [0][1][RTW89_QATAR][1][0] = 20, + [0][1][RTW89_QATAR][0][0] = -18, + [0][1][RTW89_UK][1][0] = 20, + [0][1][RTW89_UK][0][0] = -18, + [0][1][RTW89_FCC][1][2] = -40, + [0][1][RTW89_FCC][2][2] = 32, + [0][1][RTW89_ETSI][1][2] = 20, + [0][1][RTW89_ETSI][0][2] = -18, + [0][1][RTW89_MKK][1][2] = 18, + [0][1][RTW89_MKK][0][2] = -22, + [0][1][RTW89_IC][1][2] = -40, + [0][1][RTW89_KCC][1][2] = -14, + [0][1][RTW89_KCC][0][2] = -14, + [0][1][RTW89_ACMA][1][2] = 20, + [0][1][RTW89_ACMA][0][2] = -18, + [0][1][RTW89_CHILE][1][2] = -40, + [0][1][RTW89_QATAR][1][2] = 20, + [0][1][RTW89_QATAR][0][2] = -18, + [0][1][RTW89_UK][1][2] = 20, + [0][1][RTW89_UK][0][2] = -18, + [0][1][RTW89_FCC][1][4] = -40, + [0][1][RTW89_FCC][2][4] = 32, + [0][1][RTW89_ETSI][1][4] = 20, + [0][1][RTW89_ETSI][0][4] = -18, + [0][1][RTW89_MKK][1][4] = 18, + [0][1][RTW89_MKK][0][4] = -22, + [0][1][RTW89_IC][1][4] = -40, + [0][1][RTW89_KCC][1][4] = -14, + [0][1][RTW89_KCC][0][4] = -14, + [0][1][RTW89_ACMA][1][4] = 20, + [0][1][RTW89_ACMA][0][4] = -18, + [0][1][RTW89_CHILE][1][4] = -40, + [0][1][RTW89_QATAR][1][4] = 20, + [0][1][RTW89_QATAR][0][4] = -18, + [0][1][RTW89_UK][1][4] = 20, + [0][1][RTW89_UK][0][4] = -18, + [0][1][RTW89_FCC][1][6] = -40, + [0][1][RTW89_FCC][2][6] = 32, + [0][1][RTW89_ETSI][1][6] = 20, + [0][1][RTW89_ETSI][0][6] = -18, + [0][1][RTW89_MKK][1][6] = 18, + [0][1][RTW89_MKK][0][6] = -22, + [0][1][RTW89_IC][1][6] = -40, + [0][1][RTW89_KCC][1][6] = -14, + [0][1][RTW89_KCC][0][6] = -14, + [0][1][RTW89_ACMA][1][6] = 20, + [0][1][RTW89_ACMA][0][6] = -18, + [0][1][RTW89_CHILE][1][6] = -40, + [0][1][RTW89_QATAR][1][6] = 20, + [0][1][RTW89_QATAR][0][6] = -18, + [0][1][RTW89_UK][1][6] = 20, + [0][1][RTW89_UK][0][6] = -18, + [0][1][RTW89_FCC][1][8] = -40, + [0][1][RTW89_FCC][2][8] = 32, + [0][1][RTW89_ETSI][1][8] = 20, + [0][1][RTW89_ETSI][0][8] = -18, + [0][1][RTW89_MKK][1][8] = 18, + [0][1][RTW89_MKK][0][8] = -22, + [0][1][RTW89_IC][1][8] = -40, + [0][1][RTW89_KCC][1][8] = -14, + [0][1][RTW89_KCC][0][8] = -14, + [0][1][RTW89_ACMA][1][8] = 20, + [0][1][RTW89_ACMA][0][8] = -18, + [0][1][RTW89_CHILE][1][8] = -40, + [0][1][RTW89_QATAR][1][8] = 20, + [0][1][RTW89_QATAR][0][8] = -18, + [0][1][RTW89_UK][1][8] = 20, + [0][1][RTW89_UK][0][8] = -18, + [0][1][RTW89_FCC][1][10] = -40, + [0][1][RTW89_FCC][2][10] = 32, + [0][1][RTW89_ETSI][1][10] = 20, + [0][1][RTW89_ETSI][0][10] = -18, + [0][1][RTW89_MKK][1][10] = 18, + [0][1][RTW89_MKK][0][10] = -22, + [0][1][RTW89_IC][1][10] = -40, + [0][1][RTW89_KCC][1][10] = -14, + [0][1][RTW89_KCC][0][10] = -14, + [0][1][RTW89_ACMA][1][10] = 20, + [0][1][RTW89_ACMA][0][10] = -18, + [0][1][RTW89_CHILE][1][10] = -40, + [0][1][RTW89_QATAR][1][10] = 20, + [0][1][RTW89_QATAR][0][10] = -18, + [0][1][RTW89_UK][1][10] = 20, + [0][1][RTW89_UK][0][10] = -18, + [0][1][RTW89_FCC][1][12] = -40, + [0][1][RTW89_FCC][2][12] = 32, + [0][1][RTW89_ETSI][1][12] = 20, + [0][1][RTW89_ETSI][0][12] = -18, + [0][1][RTW89_MKK][1][12] = 18, + [0][1][RTW89_MKK][0][12] = -22, + [0][1][RTW89_IC][1][12] = -40, + [0][1][RTW89_KCC][1][12] = -14, + [0][1][RTW89_KCC][0][12] = -14, + [0][1][RTW89_ACMA][1][12] = 20, + [0][1][RTW89_ACMA][0][12] = -18, + [0][1][RTW89_CHILE][1][12] = -40, + [0][1][RTW89_QATAR][1][12] = 20, + [0][1][RTW89_QATAR][0][12] = -18, + [0][1][RTW89_UK][1][12] = 20, + [0][1][RTW89_UK][0][12] = -18, + [0][1][RTW89_FCC][1][14] = -40, + [0][1][RTW89_FCC][2][14] = 32, + [0][1][RTW89_ETSI][1][14] = 20, + [0][1][RTW89_ETSI][0][14] = -18, + [0][1][RTW89_MKK][1][14] = 18, + [0][1][RTW89_MKK][0][14] = -22, + [0][1][RTW89_IC][1][14] = -40, + [0][1][RTW89_KCC][1][14] = -14, + [0][1][RTW89_KCC][0][14] = -14, + [0][1][RTW89_ACMA][1][14] = 20, + [0][1][RTW89_ACMA][0][14] = -18, + [0][1][RTW89_CHILE][1][14] = -40, + [0][1][RTW89_QATAR][1][14] = 20, + [0][1][RTW89_QATAR][0][14] = -18, + [0][1][RTW89_UK][1][14] = 20, + [0][1][RTW89_UK][0][14] = -18, + [0][1][RTW89_FCC][1][15] = -40, + [0][1][RTW89_FCC][2][15] = 32, + [0][1][RTW89_ETSI][1][15] = 20, + [0][1][RTW89_ETSI][0][15] = -18, + [0][1][RTW89_MKK][1][15] = 18, + [0][1][RTW89_MKK][0][15] = -22, + [0][1][RTW89_IC][1][15] = -40, + [0][1][RTW89_KCC][1][15] = -14, + [0][1][RTW89_KCC][0][15] = -14, + [0][1][RTW89_ACMA][1][15] = 20, + [0][1][RTW89_ACMA][0][15] = -18, + [0][1][RTW89_CHILE][1][15] = -40, + [0][1][RTW89_QATAR][1][15] = 20, + [0][1][RTW89_QATAR][0][15] = -18, + [0][1][RTW89_UK][1][15] = 20, + [0][1][RTW89_UK][0][15] = -18, + [0][1][RTW89_FCC][1][17] = -40, + [0][1][RTW89_FCC][2][17] = 32, + [0][1][RTW89_ETSI][1][17] = 20, + [0][1][RTW89_ETSI][0][17] = -18, + [0][1][RTW89_MKK][1][17] = 18, + [0][1][RTW89_MKK][0][17] = -22, + [0][1][RTW89_IC][1][17] = -40, + [0][1][RTW89_KCC][1][17] = -14, + [0][1][RTW89_KCC][0][17] = -14, + [0][1][RTW89_ACMA][1][17] = 20, + [0][1][RTW89_ACMA][0][17] = -18, + [0][1][RTW89_CHILE][1][17] = -40, + [0][1][RTW89_QATAR][1][17] = 20, + [0][1][RTW89_QATAR][0][17] = -18, + [0][1][RTW89_UK][1][17] = 20, + [0][1][RTW89_UK][0][17] = -18, + [0][1][RTW89_FCC][1][19] = -40, + [0][1][RTW89_FCC][2][19] = 32, + [0][1][RTW89_ETSI][1][19] = 20, + [0][1][RTW89_ETSI][0][19] = -18, + [0][1][RTW89_MKK][1][19] = 18, + [0][1][RTW89_MKK][0][19] = -22, + [0][1][RTW89_IC][1][19] = -40, + [0][1][RTW89_KCC][1][19] = -14, + [0][1][RTW89_KCC][0][19] = -14, + [0][1][RTW89_ACMA][1][19] = 20, + [0][1][RTW89_ACMA][0][19] = -18, + [0][1][RTW89_CHILE][1][19] = -40, + [0][1][RTW89_QATAR][1][19] = 20, + [0][1][RTW89_QATAR][0][19] = -18, + [0][1][RTW89_UK][1][19] = 20, + [0][1][RTW89_UK][0][19] = -18, + [0][1][RTW89_FCC][1][21] = -40, + [0][1][RTW89_FCC][2][21] = 32, + [0][1][RTW89_ETSI][1][21] = 20, + [0][1][RTW89_ETSI][0][21] = -18, + [0][1][RTW89_MKK][1][21] = 18, + [0][1][RTW89_MKK][0][21] = -22, + [0][1][RTW89_IC][1][21] = -40, + [0][1][RTW89_KCC][1][21] = -14, + [0][1][RTW89_KCC][0][21] = -14, + [0][1][RTW89_ACMA][1][21] = 20, + [0][1][RTW89_ACMA][0][21] = -18, + [0][1][RTW89_CHILE][1][21] = -40, + [0][1][RTW89_QATAR][1][21] = 20, + [0][1][RTW89_QATAR][0][21] = -18, + [0][1][RTW89_UK][1][21] = 20, + [0][1][RTW89_UK][0][21] = -18, + [0][1][RTW89_FCC][1][23] = -40, + [0][1][RTW89_FCC][2][23] = 32, + [0][1][RTW89_ETSI][1][23] = 20, + [0][1][RTW89_ETSI][0][23] = -18, + [0][1][RTW89_MKK][1][23] = 18, + [0][1][RTW89_MKK][0][23] = -22, + [0][1][RTW89_IC][1][23] = -40, + [0][1][RTW89_KCC][1][23] = -14, + [0][1][RTW89_KCC][0][23] = -14, + [0][1][RTW89_ACMA][1][23] = 20, + [0][1][RTW89_ACMA][0][23] = -18, + [0][1][RTW89_CHILE][1][23] = -40, + [0][1][RTW89_QATAR][1][23] = 20, + [0][1][RTW89_QATAR][0][23] = -18, + [0][1][RTW89_UK][1][23] = 20, + [0][1][RTW89_UK][0][23] = -18, + [0][1][RTW89_FCC][1][25] = -40, + [0][1][RTW89_FCC][2][25] = 32, + [0][1][RTW89_ETSI][1][25] = 20, + [0][1][RTW89_ETSI][0][25] = -18, + [0][1][RTW89_MKK][1][25] = -4, + [0][1][RTW89_MKK][0][25] = -22, + [0][1][RTW89_IC][1][25] = -40, + [0][1][RTW89_KCC][1][25] = -14, + [0][1][RTW89_KCC][0][25] = -14, + [0][1][RTW89_ACMA][1][25] = 20, + [0][1][RTW89_ACMA][0][25] = -18, + [0][1][RTW89_CHILE][1][25] = -40, + [0][1][RTW89_QATAR][1][25] = 20, + [0][1][RTW89_QATAR][0][25] = -18, + [0][1][RTW89_UK][1][25] = 20, + [0][1][RTW89_UK][0][25] = -18, + [0][1][RTW89_FCC][1][27] = -40, + [0][1][RTW89_FCC][2][27] = 32, + [0][1][RTW89_ETSI][1][27] = 20, + [0][1][RTW89_ETSI][0][27] = -18, + [0][1][RTW89_MKK][1][27] = -4, + [0][1][RTW89_MKK][0][27] = -22, + [0][1][RTW89_IC][1][27] = -40, + [0][1][RTW89_KCC][1][27] = -14, + [0][1][RTW89_KCC][0][27] = -14, + [0][1][RTW89_ACMA][1][27] = 20, + [0][1][RTW89_ACMA][0][27] = -18, + [0][1][RTW89_CHILE][1][27] = -40, + [0][1][RTW89_QATAR][1][27] = 20, + [0][1][RTW89_QATAR][0][27] = -18, + [0][1][RTW89_UK][1][27] = 20, + [0][1][RTW89_UK][0][27] = -18, + [0][1][RTW89_FCC][1][29] = -40, + [0][1][RTW89_FCC][2][29] = 32, + [0][1][RTW89_ETSI][1][29] = 20, + [0][1][RTW89_ETSI][0][29] = -18, + [0][1][RTW89_MKK][1][29] = -4, + [0][1][RTW89_MKK][0][29] = -22, + [0][1][RTW89_IC][1][29] = -40, + [0][1][RTW89_KCC][1][29] = -14, + [0][1][RTW89_KCC][0][29] = -14, + [0][1][RTW89_ACMA][1][29] = 20, + [0][1][RTW89_ACMA][0][29] = -18, + [0][1][RTW89_CHILE][1][29] = -40, + [0][1][RTW89_QATAR][1][29] = 20, + [0][1][RTW89_QATAR][0][29] = -18, + [0][1][RTW89_UK][1][29] = 20, + [0][1][RTW89_UK][0][29] = -18, + [0][1][RTW89_FCC][1][30] = -40, + [0][1][RTW89_FCC][2][30] = 32, + [0][1][RTW89_ETSI][1][30] = 20, + [0][1][RTW89_ETSI][0][30] = -18, + [0][1][RTW89_MKK][1][30] = -4, + [0][1][RTW89_MKK][0][30] = -22, + [0][1][RTW89_IC][1][30] = -40, + [0][1][RTW89_KCC][1][30] = -14, + [0][1][RTW89_KCC][0][30] = -14, + [0][1][RTW89_ACMA][1][30] = 20, + [0][1][RTW89_ACMA][0][30] = -18, + [0][1][RTW89_CHILE][1][30] = -40, + [0][1][RTW89_QATAR][1][30] = 20, + [0][1][RTW89_QATAR][0][30] = -18, + [0][1][RTW89_UK][1][30] = 20, + [0][1][RTW89_UK][0][30] = -18, + [0][1][RTW89_FCC][1][32] = -40, + [0][1][RTW89_FCC][2][32] = 32, + [0][1][RTW89_ETSI][1][32] = 20, + [0][1][RTW89_ETSI][0][32] = -18, + [0][1][RTW89_MKK][1][32] = -4, + [0][1][RTW89_MKK][0][32] = -22, + [0][1][RTW89_IC][1][32] = -40, + [0][1][RTW89_KCC][1][32] = -14, + [0][1][RTW89_KCC][0][32] = -14, + [0][1][RTW89_ACMA][1][32] = 20, + [0][1][RTW89_ACMA][0][32] = -18, + [0][1][RTW89_CHILE][1][32] = -40, + [0][1][RTW89_QATAR][1][32] = 20, + [0][1][RTW89_QATAR][0][32] = -18, + [0][1][RTW89_UK][1][32] = 20, + [0][1][RTW89_UK][0][32] = -18, + [0][1][RTW89_FCC][1][34] = -40, + [0][1][RTW89_FCC][2][34] = 32, + [0][1][RTW89_ETSI][1][34] = 20, + [0][1][RTW89_ETSI][0][34] = -18, + [0][1][RTW89_MKK][1][34] = -4, + [0][1][RTW89_MKK][0][34] = -22, + [0][1][RTW89_IC][1][34] = -40, + [0][1][RTW89_KCC][1][34] = -14, + [0][1][RTW89_KCC][0][34] = -14, + [0][1][RTW89_ACMA][1][34] = 20, + [0][1][RTW89_ACMA][0][34] = -18, + [0][1][RTW89_CHILE][1][34] = -40, + [0][1][RTW89_QATAR][1][34] = 20, + [0][1][RTW89_QATAR][0][34] = -18, + [0][1][RTW89_UK][1][34] = 20, + [0][1][RTW89_UK][0][34] = -18, + [0][1][RTW89_FCC][1][36] = -40, + [0][1][RTW89_FCC][2][36] = 32, + [0][1][RTW89_ETSI][1][36] = 20, + [0][1][RTW89_ETSI][0][36] = -18, + [0][1][RTW89_MKK][1][36] = -4, + [0][1][RTW89_MKK][0][36] = -22, + [0][1][RTW89_IC][1][36] = -40, + [0][1][RTW89_KCC][1][36] = -14, + [0][1][RTW89_KCC][0][36] = -14, + [0][1][RTW89_ACMA][1][36] = 20, + [0][1][RTW89_ACMA][0][36] = -18, + [0][1][RTW89_CHILE][1][36] = -40, + [0][1][RTW89_QATAR][1][36] = 20, + [0][1][RTW89_QATAR][0][36] = -18, + [0][1][RTW89_UK][1][36] = 20, + [0][1][RTW89_UK][0][36] = -18, + [0][1][RTW89_FCC][1][38] = -40, + [0][1][RTW89_FCC][2][38] = 32, + [0][1][RTW89_ETSI][1][38] = 20, + [0][1][RTW89_ETSI][0][38] = -18, + [0][1][RTW89_MKK][1][38] = -4, + [0][1][RTW89_MKK][0][38] = -22, + [0][1][RTW89_IC][1][38] = -40, + [0][1][RTW89_KCC][1][38] = -14, + [0][1][RTW89_KCC][0][38] = -14, + [0][1][RTW89_ACMA][1][38] = 20, + [0][1][RTW89_ACMA][0][38] = -18, + [0][1][RTW89_CHILE][1][38] = -40, + [0][1][RTW89_QATAR][1][38] = 20, + [0][1][RTW89_QATAR][0][38] = -18, + [0][1][RTW89_UK][1][38] = 20, + [0][1][RTW89_UK][0][38] = -18, + [0][1][RTW89_FCC][1][40] = -40, + [0][1][RTW89_FCC][2][40] = 32, + [0][1][RTW89_ETSI][1][40] = 20, + [0][1][RTW89_ETSI][0][40] = -18, + [0][1][RTW89_MKK][1][40] = -4, + [0][1][RTW89_MKK][0][40] = -22, + [0][1][RTW89_IC][1][40] = -40, + [0][1][RTW89_KCC][1][40] = -14, + [0][1][RTW89_KCC][0][40] = -14, + [0][1][RTW89_ACMA][1][40] = 20, + [0][1][RTW89_ACMA][0][40] = -18, + [0][1][RTW89_CHILE][1][40] = -40, + [0][1][RTW89_QATAR][1][40] = 20, + [0][1][RTW89_QATAR][0][40] = -18, + [0][1][RTW89_UK][1][40] = 20, + [0][1][RTW89_UK][0][40] = -18, + [0][1][RTW89_FCC][1][42] = -40, + [0][1][RTW89_FCC][2][42] = 32, + [0][1][RTW89_ETSI][1][42] = 20, + [0][1][RTW89_ETSI][0][42] = -18, + [0][1][RTW89_MKK][1][42] = -4, + [0][1][RTW89_MKK][0][42] = -22, + [0][1][RTW89_IC][1][42] = -40, + [0][1][RTW89_KCC][1][42] = -14, + [0][1][RTW89_KCC][0][42] = -14, + [0][1][RTW89_ACMA][1][42] = 20, + [0][1][RTW89_ACMA][0][42] = -18, + [0][1][RTW89_CHILE][1][42] = -40, + [0][1][RTW89_QATAR][1][42] = 20, + [0][1][RTW89_QATAR][0][42] = -18, + [0][1][RTW89_UK][1][42] = 20, + [0][1][RTW89_UK][0][42] = -18, + [0][1][RTW89_FCC][1][44] = -40, + [0][1][RTW89_FCC][2][44] = 32, + [0][1][RTW89_ETSI][1][44] = 20, + [0][1][RTW89_ETSI][0][44] = -18, + [0][1][RTW89_MKK][1][44] = -4, + [0][1][RTW89_MKK][0][44] = -22, + [0][1][RTW89_IC][1][44] = -40, + [0][1][RTW89_KCC][1][44] = -14, + [0][1][RTW89_KCC][0][44] = -14, + [0][1][RTW89_ACMA][1][44] = 20, + [0][1][RTW89_ACMA][0][44] = -18, + [0][1][RTW89_CHILE][1][44] = -40, + [0][1][RTW89_QATAR][1][44] = 20, + [0][1][RTW89_QATAR][0][44] = -18, + [0][1][RTW89_UK][1][44] = 20, + [0][1][RTW89_UK][0][44] = -18, + [0][1][RTW89_FCC][1][45] = -40, + [0][1][RTW89_FCC][2][45] = 127, + [0][1][RTW89_ETSI][1][45] = 127, + [0][1][RTW89_ETSI][0][45] = 127, + [0][1][RTW89_MKK][1][45] = 127, + [0][1][RTW89_MKK][0][45] = 127, + [0][1][RTW89_IC][1][45] = -40, + [0][1][RTW89_KCC][1][45] = -14, + [0][1][RTW89_KCC][0][45] = 127, + [0][1][RTW89_ACMA][1][45] = 127, + [0][1][RTW89_ACMA][0][45] = 127, + [0][1][RTW89_CHILE][1][45] = 127, + [0][1][RTW89_QATAR][1][45] = 127, + [0][1][RTW89_QATAR][0][45] = 127, + [0][1][RTW89_UK][1][45] = 127, + [0][1][RTW89_UK][0][45] = 127, + [0][1][RTW89_FCC][1][47] = -40, + [0][1][RTW89_FCC][2][47] = 127, + [0][1][RTW89_ETSI][1][47] = 127, + [0][1][RTW89_ETSI][0][47] = 127, + [0][1][RTW89_MKK][1][47] = 127, + [0][1][RTW89_MKK][0][47] = 127, + [0][1][RTW89_IC][1][47] = -40, + [0][1][RTW89_KCC][1][47] = -14, + [0][1][RTW89_KCC][0][47] = 127, + [0][1][RTW89_ACMA][1][47] = 127, + [0][1][RTW89_ACMA][0][47] = 127, + [0][1][RTW89_CHILE][1][47] = 127, + [0][1][RTW89_QATAR][1][47] = 127, + [0][1][RTW89_QATAR][0][47] = 127, + [0][1][RTW89_UK][1][47] = 127, + [0][1][RTW89_UK][0][47] = 127, + [0][1][RTW89_FCC][1][49] = -40, + [0][1][RTW89_FCC][2][49] = 127, + [0][1][RTW89_ETSI][1][49] = 127, + [0][1][RTW89_ETSI][0][49] = 127, + [0][1][RTW89_MKK][1][49] = 127, + [0][1][RTW89_MKK][0][49] = 127, + [0][1][RTW89_IC][1][49] = -40, + [0][1][RTW89_KCC][1][49] = -14, + [0][1][RTW89_KCC][0][49] = 127, + [0][1][RTW89_ACMA][1][49] = 127, + [0][1][RTW89_ACMA][0][49] = 127, + [0][1][RTW89_CHILE][1][49] = 127, + [0][1][RTW89_QATAR][1][49] = 127, + [0][1][RTW89_QATAR][0][49] = 127, + [0][1][RTW89_UK][1][49] = 127, + [0][1][RTW89_UK][0][49] = 127, + [0][1][RTW89_FCC][1][51] = -40, + [0][1][RTW89_FCC][2][51] = 127, + [0][1][RTW89_ETSI][1][51] = 127, + [0][1][RTW89_ETSI][0][51] = 127, + [0][1][RTW89_MKK][1][51] = 127, + [0][1][RTW89_MKK][0][51] = 127, + [0][1][RTW89_IC][1][51] = -40, + [0][1][RTW89_KCC][1][51] = -14, + [0][1][RTW89_KCC][0][51] = 127, + [0][1][RTW89_ACMA][1][51] = 127, + [0][1][RTW89_ACMA][0][51] = 127, + [0][1][RTW89_CHILE][1][51] = 127, + [0][1][RTW89_QATAR][1][51] = 127, + [0][1][RTW89_QATAR][0][51] = 127, + [0][1][RTW89_UK][1][51] = 127, + [0][1][RTW89_UK][0][51] = 127, + [0][1][RTW89_FCC][1][53] = -40, + [0][1][RTW89_FCC][2][53] = 127, + [0][1][RTW89_ETSI][1][53] = 127, + [0][1][RTW89_ETSI][0][53] = 127, + [0][1][RTW89_MKK][1][53] = 127, + [0][1][RTW89_MKK][0][53] = 127, + [0][1][RTW89_IC][1][53] = -40, + [0][1][RTW89_KCC][1][53] = -14, + [0][1][RTW89_KCC][0][53] = 127, + [0][1][RTW89_ACMA][1][53] = 127, + [0][1][RTW89_ACMA][0][53] = 127, + [0][1][RTW89_CHILE][1][53] = 127, + [0][1][RTW89_QATAR][1][53] = 127, + [0][1][RTW89_QATAR][0][53] = 127, + [0][1][RTW89_UK][1][53] = 127, + [0][1][RTW89_UK][0][53] = 127, + [0][1][RTW89_FCC][1][55] = -40, + [0][1][RTW89_FCC][2][55] = 30, + [0][1][RTW89_ETSI][1][55] = 127, + [0][1][RTW89_ETSI][0][55] = 127, + [0][1][RTW89_MKK][1][55] = 127, + [0][1][RTW89_MKK][0][55] = 127, + [0][1][RTW89_IC][1][55] = -40, + [0][1][RTW89_KCC][1][55] = -14, + [0][1][RTW89_KCC][0][55] = 127, + [0][1][RTW89_ACMA][1][55] = 127, + [0][1][RTW89_ACMA][0][55] = 127, + [0][1][RTW89_CHILE][1][55] = 127, + [0][1][RTW89_QATAR][1][55] = 127, + [0][1][RTW89_QATAR][0][55] = 127, + [0][1][RTW89_UK][1][55] = 127, + [0][1][RTW89_UK][0][55] = 127, + [0][1][RTW89_FCC][1][57] = -40, + [0][1][RTW89_FCC][2][57] = 30, + [0][1][RTW89_ETSI][1][57] = 127, + [0][1][RTW89_ETSI][0][57] = 127, + [0][1][RTW89_MKK][1][57] = 127, + [0][1][RTW89_MKK][0][57] = 127, + [0][1][RTW89_IC][1][57] = -40, + [0][1][RTW89_KCC][1][57] = -14, + [0][1][RTW89_KCC][0][57] = 127, + [0][1][RTW89_ACMA][1][57] = 127, + [0][1][RTW89_ACMA][0][57] = 127, + [0][1][RTW89_CHILE][1][57] = 127, + [0][1][RTW89_QATAR][1][57] = 127, + [0][1][RTW89_QATAR][0][57] = 127, + [0][1][RTW89_UK][1][57] = 127, + [0][1][RTW89_UK][0][57] = 127, + [0][1][RTW89_FCC][1][59] = -40, + [0][1][RTW89_FCC][2][59] = 30, + [0][1][RTW89_ETSI][1][59] = 127, + [0][1][RTW89_ETSI][0][59] = 127, + [0][1][RTW89_MKK][1][59] = 127, + [0][1][RTW89_MKK][0][59] = 127, + [0][1][RTW89_IC][1][59] = -40, + [0][1][RTW89_KCC][1][59] = -14, + [0][1][RTW89_KCC][0][59] = 127, + [0][1][RTW89_ACMA][1][59] = 127, + [0][1][RTW89_ACMA][0][59] = 127, + [0][1][RTW89_CHILE][1][59] = 127, + [0][1][RTW89_QATAR][1][59] = 127, + [0][1][RTW89_QATAR][0][59] = 127, + [0][1][RTW89_UK][1][59] = 127, + [0][1][RTW89_UK][0][59] = 127, + [0][1][RTW89_FCC][1][60] = -40, + [0][1][RTW89_FCC][2][60] = 30, + [0][1][RTW89_ETSI][1][60] = 127, + [0][1][RTW89_ETSI][0][60] = 127, + [0][1][RTW89_MKK][1][60] = 127, + [0][1][RTW89_MKK][0][60] = 127, + [0][1][RTW89_IC][1][60] = -40, + [0][1][RTW89_KCC][1][60] = -14, + [0][1][RTW89_KCC][0][60] = 127, + [0][1][RTW89_ACMA][1][60] = 127, + [0][1][RTW89_ACMA][0][60] = 127, + [0][1][RTW89_CHILE][1][60] = 127, + [0][1][RTW89_QATAR][1][60] = 127, + [0][1][RTW89_QATAR][0][60] = 127, + [0][1][RTW89_UK][1][60] = 127, + [0][1][RTW89_UK][0][60] = 127, + [0][1][RTW89_FCC][1][62] = -40, + [0][1][RTW89_FCC][2][62] = 30, + [0][1][RTW89_ETSI][1][62] = 127, + [0][1][RTW89_ETSI][0][62] = 127, + [0][1][RTW89_MKK][1][62] = 127, + [0][1][RTW89_MKK][0][62] = 127, + [0][1][RTW89_IC][1][62] = -40, + [0][1][RTW89_KCC][1][62] = -14, + [0][1][RTW89_KCC][0][62] = 127, + [0][1][RTW89_ACMA][1][62] = 127, + [0][1][RTW89_ACMA][0][62] = 127, + [0][1][RTW89_CHILE][1][62] = 127, + [0][1][RTW89_QATAR][1][62] = 127, + [0][1][RTW89_QATAR][0][62] = 127, + [0][1][RTW89_UK][1][62] = 127, + [0][1][RTW89_UK][0][62] = 127, + [0][1][RTW89_FCC][1][64] = -40, + [0][1][RTW89_FCC][2][64] = 30, + [0][1][RTW89_ETSI][1][64] = 127, + [0][1][RTW89_ETSI][0][64] = 127, + [0][1][RTW89_MKK][1][64] = 127, + [0][1][RTW89_MKK][0][64] = 127, + [0][1][RTW89_IC][1][64] = -40, + [0][1][RTW89_KCC][1][64] = -14, + [0][1][RTW89_KCC][0][64] = 127, + [0][1][RTW89_ACMA][1][64] = 127, + [0][1][RTW89_ACMA][0][64] = 127, + [0][1][RTW89_CHILE][1][64] = 127, + [0][1][RTW89_QATAR][1][64] = 127, + [0][1][RTW89_QATAR][0][64] = 127, + [0][1][RTW89_UK][1][64] = 127, + [0][1][RTW89_UK][0][64] = 127, + [0][1][RTW89_FCC][1][66] = -40, + [0][1][RTW89_FCC][2][66] = 30, + [0][1][RTW89_ETSI][1][66] = 127, + [0][1][RTW89_ETSI][0][66] = 127, + [0][1][RTW89_MKK][1][66] = 127, + [0][1][RTW89_MKK][0][66] = 127, + [0][1][RTW89_IC][1][66] = -40, + [0][1][RTW89_KCC][1][66] = -14, + [0][1][RTW89_KCC][0][66] = 127, + [0][1][RTW89_ACMA][1][66] = 127, + [0][1][RTW89_ACMA][0][66] = 127, + [0][1][RTW89_CHILE][1][66] = 127, + [0][1][RTW89_QATAR][1][66] = 127, + [0][1][RTW89_QATAR][0][66] = 127, + [0][1][RTW89_UK][1][66] = 127, + [0][1][RTW89_UK][0][66] = 127, + [0][1][RTW89_FCC][1][68] = -40, + [0][1][RTW89_FCC][2][68] = 30, + [0][1][RTW89_ETSI][1][68] = 127, + [0][1][RTW89_ETSI][0][68] = 127, + [0][1][RTW89_MKK][1][68] = 127, + [0][1][RTW89_MKK][0][68] = 127, + [0][1][RTW89_IC][1][68] = -40, + [0][1][RTW89_KCC][1][68] = -14, + [0][1][RTW89_KCC][0][68] = 127, + [0][1][RTW89_ACMA][1][68] = 127, + [0][1][RTW89_ACMA][0][68] = 127, + [0][1][RTW89_CHILE][1][68] = 127, + [0][1][RTW89_QATAR][1][68] = 127, + [0][1][RTW89_QATAR][0][68] = 127, + [0][1][RTW89_UK][1][68] = 127, + [0][1][RTW89_UK][0][68] = 127, + [0][1][RTW89_FCC][1][70] = -38, + [0][1][RTW89_FCC][2][70] = 30, + [0][1][RTW89_ETSI][1][70] = 127, + [0][1][RTW89_ETSI][0][70] = 127, + [0][1][RTW89_MKK][1][70] = 127, + [0][1][RTW89_MKK][0][70] = 127, + [0][1][RTW89_IC][1][70] = -38, + [0][1][RTW89_KCC][1][70] = -14, + [0][1][RTW89_KCC][0][70] = 127, + [0][1][RTW89_ACMA][1][70] = 127, + [0][1][RTW89_ACMA][0][70] = 127, + [0][1][RTW89_CHILE][1][70] = 127, + [0][1][RTW89_QATAR][1][70] = 127, + [0][1][RTW89_QATAR][0][70] = 127, + [0][1][RTW89_UK][1][70] = 127, + [0][1][RTW89_UK][0][70] = 127, + [0][1][RTW89_FCC][1][72] = -38, + [0][1][RTW89_FCC][2][72] = 30, + [0][1][RTW89_ETSI][1][72] = 127, + [0][1][RTW89_ETSI][0][72] = 127, + [0][1][RTW89_MKK][1][72] = 127, + [0][1][RTW89_MKK][0][72] = 127, + [0][1][RTW89_IC][1][72] = -38, + [0][1][RTW89_KCC][1][72] = -14, + [0][1][RTW89_KCC][0][72] = 127, + [0][1][RTW89_ACMA][1][72] = 127, + [0][1][RTW89_ACMA][0][72] = 127, + [0][1][RTW89_CHILE][1][72] = 127, + [0][1][RTW89_QATAR][1][72] = 127, + [0][1][RTW89_QATAR][0][72] = 127, + [0][1][RTW89_UK][1][72] = 127, + [0][1][RTW89_UK][0][72] = 127, + [0][1][RTW89_FCC][1][74] = -38, + [0][1][RTW89_FCC][2][74] = 30, + [0][1][RTW89_ETSI][1][74] = 127, + [0][1][RTW89_ETSI][0][74] = 127, + [0][1][RTW89_MKK][1][74] = 127, + [0][1][RTW89_MKK][0][74] = 127, + [0][1][RTW89_IC][1][74] = -38, + [0][1][RTW89_KCC][1][74] = -14, + [0][1][RTW89_KCC][0][74] = 127, + [0][1][RTW89_ACMA][1][74] = 127, + [0][1][RTW89_ACMA][0][74] = 127, + [0][1][RTW89_CHILE][1][74] = 127, + [0][1][RTW89_QATAR][1][74] = 127, + [0][1][RTW89_QATAR][0][74] = 127, + [0][1][RTW89_UK][1][74] = 127, + [0][1][RTW89_UK][0][74] = 127, + [0][1][RTW89_FCC][1][75] = -38, + [0][1][RTW89_FCC][2][75] = 30, + [0][1][RTW89_ETSI][1][75] = 127, + [0][1][RTW89_ETSI][0][75] = 127, + [0][1][RTW89_MKK][1][75] = 127, + [0][1][RTW89_MKK][0][75] = 127, + [0][1][RTW89_IC][1][75] = -38, + [0][1][RTW89_KCC][1][75] = -14, + [0][1][RTW89_KCC][0][75] = 127, + [0][1][RTW89_ACMA][1][75] = 127, + [0][1][RTW89_ACMA][0][75] = 127, + [0][1][RTW89_CHILE][1][75] = 127, + [0][1][RTW89_QATAR][1][75] = 127, + [0][1][RTW89_QATAR][0][75] = 127, + [0][1][RTW89_UK][1][75] = 127, + [0][1][RTW89_UK][0][75] = 127, + [0][1][RTW89_FCC][1][77] = -38, + [0][1][RTW89_FCC][2][77] = 30, + [0][1][RTW89_ETSI][1][77] = 127, + [0][1][RTW89_ETSI][0][77] = 127, + [0][1][RTW89_MKK][1][77] = 127, + [0][1][RTW89_MKK][0][77] = 127, + [0][1][RTW89_IC][1][77] = -38, + [0][1][RTW89_KCC][1][77] = -14, + [0][1][RTW89_KCC][0][77] = 127, + [0][1][RTW89_ACMA][1][77] = 127, + [0][1][RTW89_ACMA][0][77] = 127, + [0][1][RTW89_CHILE][1][77] = 127, + [0][1][RTW89_QATAR][1][77] = 127, + [0][1][RTW89_QATAR][0][77] = 127, + [0][1][RTW89_UK][1][77] = 127, + [0][1][RTW89_UK][0][77] = 127, + [0][1][RTW89_FCC][1][79] = -38, + [0][1][RTW89_FCC][2][79] = 30, + [0][1][RTW89_ETSI][1][79] = 127, + [0][1][RTW89_ETSI][0][79] = 127, + [0][1][RTW89_MKK][1][79] = 127, + [0][1][RTW89_MKK][0][79] = 127, + [0][1][RTW89_IC][1][79] = -38, + [0][1][RTW89_KCC][1][79] = -14, + [0][1][RTW89_KCC][0][79] = 127, + [0][1][RTW89_ACMA][1][79] = 127, + [0][1][RTW89_ACMA][0][79] = 127, + [0][1][RTW89_CHILE][1][79] = 127, + [0][1][RTW89_QATAR][1][79] = 127, + [0][1][RTW89_QATAR][0][79] = 127, + [0][1][RTW89_UK][1][79] = 127, + [0][1][RTW89_UK][0][79] = 127, + [0][1][RTW89_FCC][1][81] = -38, + [0][1][RTW89_FCC][2][81] = 30, + [0][1][RTW89_ETSI][1][81] = 127, + [0][1][RTW89_ETSI][0][81] = 127, + [0][1][RTW89_MKK][1][81] = 127, + [0][1][RTW89_MKK][0][81] = 127, + [0][1][RTW89_IC][1][81] = -38, + [0][1][RTW89_KCC][1][81] = -14, + [0][1][RTW89_KCC][0][81] = 127, + [0][1][RTW89_ACMA][1][81] = 127, + [0][1][RTW89_ACMA][0][81] = 127, + [0][1][RTW89_CHILE][1][81] = 127, + [0][1][RTW89_QATAR][1][81] = 127, + [0][1][RTW89_QATAR][0][81] = 127, + [0][1][RTW89_UK][1][81] = 127, + [0][1][RTW89_UK][0][81] = 127, + [0][1][RTW89_FCC][1][83] = -38, + [0][1][RTW89_FCC][2][83] = 30, + [0][1][RTW89_ETSI][1][83] = 127, + [0][1][RTW89_ETSI][0][83] = 127, + [0][1][RTW89_MKK][1][83] = 127, + [0][1][RTW89_MKK][0][83] = 127, + [0][1][RTW89_IC][1][83] = -38, + [0][1][RTW89_KCC][1][83] = -14, + [0][1][RTW89_KCC][0][83] = 127, + [0][1][RTW89_ACMA][1][83] = 127, + [0][1][RTW89_ACMA][0][83] = 127, + [0][1][RTW89_CHILE][1][83] = 127, + [0][1][RTW89_QATAR][1][83] = 127, + [0][1][RTW89_QATAR][0][83] = 127, + [0][1][RTW89_UK][1][83] = 127, + [0][1][RTW89_UK][0][83] = 127, + [0][1][RTW89_FCC][1][85] = -38, + [0][1][RTW89_FCC][2][85] = 30, + [0][1][RTW89_ETSI][1][85] = 127, + [0][1][RTW89_ETSI][0][85] = 127, + [0][1][RTW89_MKK][1][85] = 127, + [0][1][RTW89_MKK][0][85] = 127, + [0][1][RTW89_IC][1][85] = -38, + [0][1][RTW89_KCC][1][85] = -14, + [0][1][RTW89_KCC][0][85] = 127, + [0][1][RTW89_ACMA][1][85] = 127, + [0][1][RTW89_ACMA][0][85] = 127, + [0][1][RTW89_CHILE][1][85] = 127, + [0][1][RTW89_QATAR][1][85] = 127, + [0][1][RTW89_QATAR][0][85] = 127, + [0][1][RTW89_UK][1][85] = 127, + [0][1][RTW89_UK][0][85] = 127, + [0][1][RTW89_FCC][1][87] = -40, + [0][1][RTW89_FCC][2][87] = 127, + [0][1][RTW89_ETSI][1][87] = 127, + [0][1][RTW89_ETSI][0][87] = 127, + [0][1][RTW89_MKK][1][87] = 127, + [0][1][RTW89_MKK][0][87] = 127, + [0][1][RTW89_IC][1][87] = -40, + [0][1][RTW89_KCC][1][87] = -14, + [0][1][RTW89_KCC][0][87] = 127, + [0][1][RTW89_ACMA][1][87] = 127, + [0][1][RTW89_ACMA][0][87] = 127, + [0][1][RTW89_CHILE][1][87] = 127, + [0][1][RTW89_QATAR][1][87] = 127, + [0][1][RTW89_QATAR][0][87] = 127, + [0][1][RTW89_UK][1][87] = 127, + [0][1][RTW89_UK][0][87] = 127, + [0][1][RTW89_FCC][1][89] = -38, + [0][1][RTW89_FCC][2][89] = 127, + [0][1][RTW89_ETSI][1][89] = 127, + [0][1][RTW89_ETSI][0][89] = 127, + [0][1][RTW89_MKK][1][89] = 127, + [0][1][RTW89_MKK][0][89] = 127, + [0][1][RTW89_IC][1][89] = -38, + [0][1][RTW89_KCC][1][89] = -14, + [0][1][RTW89_KCC][0][89] = 127, + [0][1][RTW89_ACMA][1][89] = 127, + [0][1][RTW89_ACMA][0][89] = 127, + [0][1][RTW89_CHILE][1][89] = 127, + [0][1][RTW89_QATAR][1][89] = 127, + [0][1][RTW89_QATAR][0][89] = 127, + [0][1][RTW89_UK][1][89] = 127, + [0][1][RTW89_UK][0][89] = 127, + [0][1][RTW89_FCC][1][90] = -38, + [0][1][RTW89_FCC][2][90] = 127, + [0][1][RTW89_ETSI][1][90] = 127, + [0][1][RTW89_ETSI][0][90] = 127, + [0][1][RTW89_MKK][1][90] = 127, + [0][1][RTW89_MKK][0][90] = 127, + [0][1][RTW89_IC][1][90] = -38, + [0][1][RTW89_KCC][1][90] = -14, + [0][1][RTW89_KCC][0][90] = 127, + [0][1][RTW89_ACMA][1][90] = 127, + [0][1][RTW89_ACMA][0][90] = 127, + [0][1][RTW89_CHILE][1][90] = 127, + [0][1][RTW89_QATAR][1][90] = 127, + [0][1][RTW89_QATAR][0][90] = 127, + [0][1][RTW89_UK][1][90] = 127, + [0][1][RTW89_UK][0][90] = 127, + [0][1][RTW89_FCC][1][92] = -38, + [0][1][RTW89_FCC][2][92] = 127, + [0][1][RTW89_ETSI][1][92] = 127, + [0][1][RTW89_ETSI][0][92] = 127, + [0][1][RTW89_MKK][1][92] = 127, + [0][1][RTW89_MKK][0][92] = 127, + [0][1][RTW89_IC][1][92] = -38, + [0][1][RTW89_KCC][1][92] = -14, + [0][1][RTW89_KCC][0][92] = 127, + [0][1][RTW89_ACMA][1][92] = 127, + [0][1][RTW89_ACMA][0][92] = 127, + [0][1][RTW89_CHILE][1][92] = 127, + [0][1][RTW89_QATAR][1][92] = 127, + [0][1][RTW89_QATAR][0][92] = 127, + [0][1][RTW89_UK][1][92] = 127, + [0][1][RTW89_UK][0][92] = 127, + [0][1][RTW89_FCC][1][94] = -38, + [0][1][RTW89_FCC][2][94] = 127, + [0][1][RTW89_ETSI][1][94] = 127, + [0][1][RTW89_ETSI][0][94] = 127, + [0][1][RTW89_MKK][1][94] = 127, + [0][1][RTW89_MKK][0][94] = 127, + [0][1][RTW89_IC][1][94] = -38, + [0][1][RTW89_KCC][1][94] = -14, + [0][1][RTW89_KCC][0][94] = 127, + [0][1][RTW89_ACMA][1][94] = 127, + [0][1][RTW89_ACMA][0][94] = 127, + [0][1][RTW89_CHILE][1][94] = 127, + [0][1][RTW89_QATAR][1][94] = 127, + [0][1][RTW89_QATAR][0][94] = 127, + [0][1][RTW89_UK][1][94] = 127, + [0][1][RTW89_UK][0][94] = 127, + [0][1][RTW89_FCC][1][96] = -38, + [0][1][RTW89_FCC][2][96] = 127, + [0][1][RTW89_ETSI][1][96] = 127, + [0][1][RTW89_ETSI][0][96] = 127, + [0][1][RTW89_MKK][1][96] = 127, + [0][1][RTW89_MKK][0][96] = 127, + [0][1][RTW89_IC][1][96] = -38, + [0][1][RTW89_KCC][1][96] = -14, + [0][1][RTW89_KCC][0][96] = 127, + [0][1][RTW89_ACMA][1][96] = 127, + [0][1][RTW89_ACMA][0][96] = 127, + [0][1][RTW89_CHILE][1][96] = 127, + [0][1][RTW89_QATAR][1][96] = 127, + [0][1][RTW89_QATAR][0][96] = 127, + [0][1][RTW89_UK][1][96] = 127, + [0][1][RTW89_UK][0][96] = 127, + [0][1][RTW89_FCC][1][98] = -38, + [0][1][RTW89_FCC][2][98] = 127, + [0][1][RTW89_ETSI][1][98] = 127, + [0][1][RTW89_ETSI][0][98] = 127, + [0][1][RTW89_MKK][1][98] = 127, + [0][1][RTW89_MKK][0][98] = 127, + [0][1][RTW89_IC][1][98] = -38, + [0][1][RTW89_KCC][1][98] = -14, + [0][1][RTW89_KCC][0][98] = 127, + [0][1][RTW89_ACMA][1][98] = 127, + [0][1][RTW89_ACMA][0][98] = 127, + [0][1][RTW89_CHILE][1][98] = 127, + [0][1][RTW89_QATAR][1][98] = 127, + [0][1][RTW89_QATAR][0][98] = 127, + [0][1][RTW89_UK][1][98] = 127, + [0][1][RTW89_UK][0][98] = 127, + [0][1][RTW89_FCC][1][100] = -38, + [0][1][RTW89_FCC][2][100] = 127, + [0][1][RTW89_ETSI][1][100] = 127, + [0][1][RTW89_ETSI][0][100] = 127, + [0][1][RTW89_MKK][1][100] = 127, + [0][1][RTW89_MKK][0][100] = 127, + [0][1][RTW89_IC][1][100] = -38, + [0][1][RTW89_KCC][1][100] = -14, + [0][1][RTW89_KCC][0][100] = 127, + [0][1][RTW89_ACMA][1][100] = 127, + [0][1][RTW89_ACMA][0][100] = 127, + [0][1][RTW89_CHILE][1][100] = 127, + [0][1][RTW89_QATAR][1][100] = 127, + [0][1][RTW89_QATAR][0][100] = 127, + [0][1][RTW89_UK][1][100] = 127, + [0][1][RTW89_UK][0][100] = 127, + [0][1][RTW89_FCC][1][102] = -38, + [0][1][RTW89_FCC][2][102] = 127, + [0][1][RTW89_ETSI][1][102] = 127, + [0][1][RTW89_ETSI][0][102] = 127, + [0][1][RTW89_MKK][1][102] = 127, + [0][1][RTW89_MKK][0][102] = 127, + [0][1][RTW89_IC][1][102] = -38, + [0][1][RTW89_KCC][1][102] = -14, + [0][1][RTW89_KCC][0][102] = 127, + [0][1][RTW89_ACMA][1][102] = 127, + [0][1][RTW89_ACMA][0][102] = 127, + [0][1][RTW89_CHILE][1][102] = 127, + [0][1][RTW89_QATAR][1][102] = 127, + [0][1][RTW89_QATAR][0][102] = 127, + [0][1][RTW89_UK][1][102] = 127, + [0][1][RTW89_UK][0][102] = 127, + [0][1][RTW89_FCC][1][104] = -38, + [0][1][RTW89_FCC][2][104] = 127, + [0][1][RTW89_ETSI][1][104] = 127, + [0][1][RTW89_ETSI][0][104] = 127, + [0][1][RTW89_MKK][1][104] = 127, + [0][1][RTW89_MKK][0][104] = 127, + [0][1][RTW89_IC][1][104] = -38, + [0][1][RTW89_KCC][1][104] = -14, + [0][1][RTW89_KCC][0][104] = 127, + [0][1][RTW89_ACMA][1][104] = 127, + [0][1][RTW89_ACMA][0][104] = 127, + [0][1][RTW89_CHILE][1][104] = 127, + [0][1][RTW89_QATAR][1][104] = 127, + [0][1][RTW89_QATAR][0][104] = 127, + [0][1][RTW89_UK][1][104] = 127, + [0][1][RTW89_UK][0][104] = 127, + [0][1][RTW89_FCC][1][105] = -38, + [0][1][RTW89_FCC][2][105] = 127, + [0][1][RTW89_ETSI][1][105] = 127, + [0][1][RTW89_ETSI][0][105] = 127, + [0][1][RTW89_MKK][1][105] = 127, + [0][1][RTW89_MKK][0][105] = 127, + [0][1][RTW89_IC][1][105] = -38, + [0][1][RTW89_KCC][1][105] = -14, + [0][1][RTW89_KCC][0][105] = 127, + [0][1][RTW89_ACMA][1][105] = 127, + [0][1][RTW89_ACMA][0][105] = 127, + [0][1][RTW89_CHILE][1][105] = 127, + [0][1][RTW89_QATAR][1][105] = 127, + [0][1][RTW89_QATAR][0][105] = 127, + [0][1][RTW89_UK][1][105] = 127, + [0][1][RTW89_UK][0][105] = 127, + [0][1][RTW89_FCC][1][107] = -34, + [0][1][RTW89_FCC][2][107] = 127, + [0][1][RTW89_ETSI][1][107] = 127, + [0][1][RTW89_ETSI][0][107] = 127, + [0][1][RTW89_MKK][1][107] = 127, + [0][1][RTW89_MKK][0][107] = 127, + [0][1][RTW89_IC][1][107] = -34, + [0][1][RTW89_KCC][1][107] = -14, + [0][1][RTW89_KCC][0][107] = 127, + [0][1][RTW89_ACMA][1][107] = 127, + [0][1][RTW89_ACMA][0][107] = 127, + [0][1][RTW89_CHILE][1][107] = 127, + [0][1][RTW89_QATAR][1][107] = 127, + [0][1][RTW89_QATAR][0][107] = 127, + [0][1][RTW89_UK][1][107] = 127, + [0][1][RTW89_UK][0][107] = 127, + [0][1][RTW89_FCC][1][109] = -34, + [0][1][RTW89_FCC][2][109] = 127, + [0][1][RTW89_ETSI][1][109] = 127, + [0][1][RTW89_ETSI][0][109] = 127, + [0][1][RTW89_MKK][1][109] = 127, + [0][1][RTW89_MKK][0][109] = 127, + [0][1][RTW89_IC][1][109] = -34, + [0][1][RTW89_KCC][1][109] = 127, + [0][1][RTW89_KCC][0][109] = 127, + [0][1][RTW89_ACMA][1][109] = 127, + [0][1][RTW89_ACMA][0][109] = 127, + [0][1][RTW89_CHILE][1][109] = 127, + [0][1][RTW89_QATAR][1][109] = 127, + [0][1][RTW89_QATAR][0][109] = 127, + [0][1][RTW89_UK][1][109] = 127, + [0][1][RTW89_UK][0][109] = 127, + [0][1][RTW89_FCC][1][111] = 127, + [0][1][RTW89_FCC][2][111] = 127, + [0][1][RTW89_ETSI][1][111] = 127, + [0][1][RTW89_ETSI][0][111] = 127, + [0][1][RTW89_MKK][1][111] = 127, + [0][1][RTW89_MKK][0][111] = 127, + [0][1][RTW89_IC][1][111] = 127, + [0][1][RTW89_KCC][1][111] = 127, + [0][1][RTW89_KCC][0][111] = 127, + [0][1][RTW89_ACMA][1][111] = 127, + [0][1][RTW89_ACMA][0][111] = 127, + [0][1][RTW89_CHILE][1][111] = 127, + [0][1][RTW89_QATAR][1][111] = 127, + [0][1][RTW89_QATAR][0][111] = 127, + [0][1][RTW89_UK][1][111] = 127, + [0][1][RTW89_UK][0][111] = 127, + [0][1][RTW89_FCC][1][113] = 127, + [0][1][RTW89_FCC][2][113] = 127, + [0][1][RTW89_ETSI][1][113] = 127, + [0][1][RTW89_ETSI][0][113] = 127, + [0][1][RTW89_MKK][1][113] = 127, + [0][1][RTW89_MKK][0][113] = 127, + [0][1][RTW89_IC][1][113] = 127, + [0][1][RTW89_KCC][1][113] = 127, + [0][1][RTW89_KCC][0][113] = 127, + [0][1][RTW89_ACMA][1][113] = 127, + [0][1][RTW89_ACMA][0][113] = 127, + [0][1][RTW89_CHILE][1][113] = 127, + [0][1][RTW89_QATAR][1][113] = 127, + [0][1][RTW89_QATAR][0][113] = 127, + [0][1][RTW89_UK][1][113] = 127, + [0][1][RTW89_UK][0][113] = 127, + [0][1][RTW89_FCC][1][115] = 127, + [0][1][RTW89_FCC][2][115] = 127, + [0][1][RTW89_ETSI][1][115] = 127, + [0][1][RTW89_ETSI][0][115] = 127, + [0][1][RTW89_MKK][1][115] = 127, + [0][1][RTW89_MKK][0][115] = 127, + [0][1][RTW89_IC][1][115] = 127, + [0][1][RTW89_KCC][1][115] = 127, + [0][1][RTW89_KCC][0][115] = 127, + [0][1][RTW89_ACMA][1][115] = 127, + [0][1][RTW89_ACMA][0][115] = 127, + [0][1][RTW89_CHILE][1][115] = 127, + [0][1][RTW89_QATAR][1][115] = 127, + [0][1][RTW89_QATAR][0][115] = 127, + [0][1][RTW89_UK][1][115] = 127, + [0][1][RTW89_UK][0][115] = 127, + [0][1][RTW89_FCC][1][117] = 127, + [0][1][RTW89_FCC][2][117] = 127, + [0][1][RTW89_ETSI][1][117] = 127, + [0][1][RTW89_ETSI][0][117] = 127, + [0][1][RTW89_MKK][1][117] = 127, + [0][1][RTW89_MKK][0][117] = 127, + [0][1][RTW89_IC][1][117] = 127, + [0][1][RTW89_KCC][1][117] = 127, + [0][1][RTW89_KCC][0][117] = 127, + [0][1][RTW89_ACMA][1][117] = 127, + [0][1][RTW89_ACMA][0][117] = 127, + [0][1][RTW89_CHILE][1][117] = 127, + [0][1][RTW89_QATAR][1][117] = 127, + [0][1][RTW89_QATAR][0][117] = 127, + [0][1][RTW89_UK][1][117] = 127, + [0][1][RTW89_UK][0][117] = 127, + [0][1][RTW89_FCC][1][119] = 127, + [0][1][RTW89_FCC][2][119] = 127, + [0][1][RTW89_ETSI][1][119] = 127, + [0][1][RTW89_ETSI][0][119] = 127, + [0][1][RTW89_MKK][1][119] = 127, + [0][1][RTW89_MKK][0][119] = 127, + [0][1][RTW89_IC][1][119] = 127, + [0][1][RTW89_KCC][1][119] = 127, + [0][1][RTW89_KCC][0][119] = 127, + [0][1][RTW89_ACMA][1][119] = 127, + [0][1][RTW89_ACMA][0][119] = 127, + [0][1][RTW89_CHILE][1][119] = 127, + [0][1][RTW89_QATAR][1][119] = 127, + [0][1][RTW89_QATAR][0][119] = 127, + [0][1][RTW89_UK][1][119] = 127, + [0][1][RTW89_UK][0][119] = 127, + [1][0][RTW89_FCC][1][0] = -4, + [1][0][RTW89_FCC][2][0] = 52, + [1][0][RTW89_ETSI][1][0] = 46, + [1][0][RTW89_ETSI][0][0] = 6, + [1][0][RTW89_MKK][1][0] = 42, + [1][0][RTW89_MKK][0][0] = 2, + [1][0][RTW89_IC][1][0] = -4, + [1][0][RTW89_KCC][1][0] = -2, + [1][0][RTW89_KCC][0][0] = -2, + [1][0][RTW89_ACMA][1][0] = 46, + [1][0][RTW89_ACMA][0][0] = 6, + [1][0][RTW89_CHILE][1][0] = -4, + [1][0][RTW89_QATAR][1][0] = 46, + [1][0][RTW89_QATAR][0][0] = 6, + [1][0][RTW89_UK][1][0] = 46, + [1][0][RTW89_UK][0][0] = 6, + [1][0][RTW89_FCC][1][2] = -4, + [1][0][RTW89_FCC][2][2] = 52, + [1][0][RTW89_ETSI][1][2] = 46, + [1][0][RTW89_ETSI][0][2] = 6, + [1][0][RTW89_MKK][1][2] = 42, + [1][0][RTW89_MKK][0][2] = 2, + [1][0][RTW89_IC][1][2] = -4, + [1][0][RTW89_KCC][1][2] = -2, + [1][0][RTW89_KCC][0][2] = -2, + [1][0][RTW89_ACMA][1][2] = 46, + [1][0][RTW89_ACMA][0][2] = 6, + [1][0][RTW89_CHILE][1][2] = -4, + [1][0][RTW89_QATAR][1][2] = 46, + [1][0][RTW89_QATAR][0][2] = 6, + [1][0][RTW89_UK][1][2] = 46, + [1][0][RTW89_UK][0][2] = 6, + [1][0][RTW89_FCC][1][4] = -4, + [1][0][RTW89_FCC][2][4] = 52, + [1][0][RTW89_ETSI][1][4] = 46, + [1][0][RTW89_ETSI][0][4] = 6, + [1][0][RTW89_MKK][1][4] = 42, + [1][0][RTW89_MKK][0][4] = 2, + [1][0][RTW89_IC][1][4] = -4, + [1][0][RTW89_KCC][1][4] = -2, + [1][0][RTW89_KCC][0][4] = -2, + [1][0][RTW89_ACMA][1][4] = 46, + [1][0][RTW89_ACMA][0][4] = 6, + [1][0][RTW89_CHILE][1][4] = -4, + [1][0][RTW89_QATAR][1][4] = 46, + [1][0][RTW89_QATAR][0][4] = 6, + [1][0][RTW89_UK][1][4] = 46, + [1][0][RTW89_UK][0][4] = 6, + [1][0][RTW89_FCC][1][6] = -4, + [1][0][RTW89_FCC][2][6] = 52, + [1][0][RTW89_ETSI][1][6] = 46, + [1][0][RTW89_ETSI][0][6] = 6, + [1][0][RTW89_MKK][1][6] = 42, + [1][0][RTW89_MKK][0][6] = 2, + [1][0][RTW89_IC][1][6] = -4, + [1][0][RTW89_KCC][1][6] = -2, + [1][0][RTW89_KCC][0][6] = -2, + [1][0][RTW89_ACMA][1][6] = 46, + [1][0][RTW89_ACMA][0][6] = 6, + [1][0][RTW89_CHILE][1][6] = -4, + [1][0][RTW89_QATAR][1][6] = 46, + [1][0][RTW89_QATAR][0][6] = 6, + [1][0][RTW89_UK][1][6] = 46, + [1][0][RTW89_UK][0][6] = 6, + [1][0][RTW89_FCC][1][8] = -4, + [1][0][RTW89_FCC][2][8] = 52, + [1][0][RTW89_ETSI][1][8] = 46, + [1][0][RTW89_ETSI][0][8] = 6, + [1][0][RTW89_MKK][1][8] = 42, + [1][0][RTW89_MKK][0][8] = 2, + [1][0][RTW89_IC][1][8] = -4, + [1][0][RTW89_KCC][1][8] = -2, + [1][0][RTW89_KCC][0][8] = -2, + [1][0][RTW89_ACMA][1][8] = 46, + [1][0][RTW89_ACMA][0][8] = 6, + [1][0][RTW89_CHILE][1][8] = -4, + [1][0][RTW89_QATAR][1][8] = 46, + [1][0][RTW89_QATAR][0][8] = 6, + [1][0][RTW89_UK][1][8] = 46, + [1][0][RTW89_UK][0][8] = 6, + [1][0][RTW89_FCC][1][10] = -4, + [1][0][RTW89_FCC][2][10] = 52, + [1][0][RTW89_ETSI][1][10] = 46, + [1][0][RTW89_ETSI][0][10] = 6, + [1][0][RTW89_MKK][1][10] = 42, + [1][0][RTW89_MKK][0][10] = 2, + [1][0][RTW89_IC][1][10] = -4, + [1][0][RTW89_KCC][1][10] = -2, + [1][0][RTW89_KCC][0][10] = -2, + [1][0][RTW89_ACMA][1][10] = 46, + [1][0][RTW89_ACMA][0][10] = 6, + [1][0][RTW89_CHILE][1][10] = -4, + [1][0][RTW89_QATAR][1][10] = 46, + [1][0][RTW89_QATAR][0][10] = 6, + [1][0][RTW89_UK][1][10] = 46, + [1][0][RTW89_UK][0][10] = 6, + [1][0][RTW89_FCC][1][12] = -4, + [1][0][RTW89_FCC][2][12] = 52, + [1][0][RTW89_ETSI][1][12] = 46, + [1][0][RTW89_ETSI][0][12] = 6, + [1][0][RTW89_MKK][1][12] = 42, + [1][0][RTW89_MKK][0][12] = 2, + [1][0][RTW89_IC][1][12] = -4, + [1][0][RTW89_KCC][1][12] = -2, + [1][0][RTW89_KCC][0][12] = -2, + [1][0][RTW89_ACMA][1][12] = 46, + [1][0][RTW89_ACMA][0][12] = 6, + [1][0][RTW89_CHILE][1][12] = -4, + [1][0][RTW89_QATAR][1][12] = 46, + [1][0][RTW89_QATAR][0][12] = 6, + [1][0][RTW89_UK][1][12] = 46, + [1][0][RTW89_UK][0][12] = 6, + [1][0][RTW89_FCC][1][14] = -4, + [1][0][RTW89_FCC][2][14] = 52, + [1][0][RTW89_ETSI][1][14] = 46, + [1][0][RTW89_ETSI][0][14] = 6, + [1][0][RTW89_MKK][1][14] = 42, + [1][0][RTW89_MKK][0][14] = 2, + [1][0][RTW89_IC][1][14] = -4, + [1][0][RTW89_KCC][1][14] = -2, + [1][0][RTW89_KCC][0][14] = -2, + [1][0][RTW89_ACMA][1][14] = 46, + [1][0][RTW89_ACMA][0][14] = 6, + [1][0][RTW89_CHILE][1][14] = -4, + [1][0][RTW89_QATAR][1][14] = 46, + [1][0][RTW89_QATAR][0][14] = 6, + [1][0][RTW89_UK][1][14] = 46, + [1][0][RTW89_UK][0][14] = 6, + [1][0][RTW89_FCC][1][15] = -4, + [1][0][RTW89_FCC][2][15] = 52, + [1][0][RTW89_ETSI][1][15] = 46, + [1][0][RTW89_ETSI][0][15] = 6, + [1][0][RTW89_MKK][1][15] = 42, + [1][0][RTW89_MKK][0][15] = 2, + [1][0][RTW89_IC][1][15] = -4, + [1][0][RTW89_KCC][1][15] = -2, + [1][0][RTW89_KCC][0][15] = -2, + [1][0][RTW89_ACMA][1][15] = 46, + [1][0][RTW89_ACMA][0][15] = 6, + [1][0][RTW89_CHILE][1][15] = -4, + [1][0][RTW89_QATAR][1][15] = 46, + [1][0][RTW89_QATAR][0][15] = 6, + [1][0][RTW89_UK][1][15] = 46, + [1][0][RTW89_UK][0][15] = 6, + [1][0][RTW89_FCC][1][17] = -4, + [1][0][RTW89_FCC][2][17] = 52, + [1][0][RTW89_ETSI][1][17] = 46, + [1][0][RTW89_ETSI][0][17] = 6, + [1][0][RTW89_MKK][1][17] = 42, + [1][0][RTW89_MKK][0][17] = 2, + [1][0][RTW89_IC][1][17] = -4, + [1][0][RTW89_KCC][1][17] = -2, + [1][0][RTW89_KCC][0][17] = -2, + [1][0][RTW89_ACMA][1][17] = 46, + [1][0][RTW89_ACMA][0][17] = 6, + [1][0][RTW89_CHILE][1][17] = -4, + [1][0][RTW89_QATAR][1][17] = 46, + [1][0][RTW89_QATAR][0][17] = 6, + [1][0][RTW89_UK][1][17] = 46, + [1][0][RTW89_UK][0][17] = 6, + [1][0][RTW89_FCC][1][19] = -4, + [1][0][RTW89_FCC][2][19] = 52, + [1][0][RTW89_ETSI][1][19] = 46, + [1][0][RTW89_ETSI][0][19] = 6, + [1][0][RTW89_MKK][1][19] = 42, + [1][0][RTW89_MKK][0][19] = 2, + [1][0][RTW89_IC][1][19] = -4, + [1][0][RTW89_KCC][1][19] = -2, + [1][0][RTW89_KCC][0][19] = -2, + [1][0][RTW89_ACMA][1][19] = 46, + [1][0][RTW89_ACMA][0][19] = 6, + [1][0][RTW89_CHILE][1][19] = -4, + [1][0][RTW89_QATAR][1][19] = 46, + [1][0][RTW89_QATAR][0][19] = 6, + [1][0][RTW89_UK][1][19] = 46, + [1][0][RTW89_UK][0][19] = 6, + [1][0][RTW89_FCC][1][21] = -4, + [1][0][RTW89_FCC][2][21] = 52, + [1][0][RTW89_ETSI][1][21] = 46, + [1][0][RTW89_ETSI][0][21] = 6, + [1][0][RTW89_MKK][1][21] = 42, + [1][0][RTW89_MKK][0][21] = 2, + [1][0][RTW89_IC][1][21] = -4, + [1][0][RTW89_KCC][1][21] = -2, + [1][0][RTW89_KCC][0][21] = -2, + [1][0][RTW89_ACMA][1][21] = 46, + [1][0][RTW89_ACMA][0][21] = 6, + [1][0][RTW89_CHILE][1][21] = -4, + [1][0][RTW89_QATAR][1][21] = 46, + [1][0][RTW89_QATAR][0][21] = 6, + [1][0][RTW89_UK][1][21] = 46, + [1][0][RTW89_UK][0][21] = 6, + [1][0][RTW89_FCC][1][23] = -4, + [1][0][RTW89_FCC][2][23] = 66, + [1][0][RTW89_ETSI][1][23] = 46, + [1][0][RTW89_ETSI][0][23] = 6, + [1][0][RTW89_MKK][1][23] = 42, + [1][0][RTW89_MKK][0][23] = 2, + [1][0][RTW89_IC][1][23] = -4, + [1][0][RTW89_KCC][1][23] = -2, + [1][0][RTW89_KCC][0][23] = -2, + [1][0][RTW89_ACMA][1][23] = 46, + [1][0][RTW89_ACMA][0][23] = 6, + [1][0][RTW89_CHILE][1][23] = -4, + [1][0][RTW89_QATAR][1][23] = 46, + [1][0][RTW89_QATAR][0][23] = 6, + [1][0][RTW89_UK][1][23] = 46, + [1][0][RTW89_UK][0][23] = 6, + [1][0][RTW89_FCC][1][25] = -4, + [1][0][RTW89_FCC][2][25] = 66, + [1][0][RTW89_ETSI][1][25] = 46, + [1][0][RTW89_ETSI][0][25] = 6, + [1][0][RTW89_MKK][1][25] = 42, + [1][0][RTW89_MKK][0][25] = 2, + [1][0][RTW89_IC][1][25] = -4, + [1][0][RTW89_KCC][1][25] = -2, + [1][0][RTW89_KCC][0][25] = -2, + [1][0][RTW89_ACMA][1][25] = 46, + [1][0][RTW89_ACMA][0][25] = 6, + [1][0][RTW89_CHILE][1][25] = -4, + [1][0][RTW89_QATAR][1][25] = 46, + [1][0][RTW89_QATAR][0][25] = 6, + [1][0][RTW89_UK][1][25] = 46, + [1][0][RTW89_UK][0][25] = 6, + [1][0][RTW89_FCC][1][27] = -4, + [1][0][RTW89_FCC][2][27] = 66, + [1][0][RTW89_ETSI][1][27] = 46, + [1][0][RTW89_ETSI][0][27] = 6, + [1][0][RTW89_MKK][1][27] = 42, + [1][0][RTW89_MKK][0][27] = 2, + [1][0][RTW89_IC][1][27] = -4, + [1][0][RTW89_KCC][1][27] = -2, + [1][0][RTW89_KCC][0][27] = -2, + [1][0][RTW89_ACMA][1][27] = 46, + [1][0][RTW89_ACMA][0][27] = 6, + [1][0][RTW89_CHILE][1][27] = -4, + [1][0][RTW89_QATAR][1][27] = 46, + [1][0][RTW89_QATAR][0][27] = 6, + [1][0][RTW89_UK][1][27] = 46, + [1][0][RTW89_UK][0][27] = 6, + [1][0][RTW89_FCC][1][29] = -4, + [1][0][RTW89_FCC][2][29] = 66, + [1][0][RTW89_ETSI][1][29] = 46, + [1][0][RTW89_ETSI][0][29] = 6, + [1][0][RTW89_MKK][1][29] = 42, + [1][0][RTW89_MKK][0][29] = 2, + [1][0][RTW89_IC][1][29] = -4, + [1][0][RTW89_KCC][1][29] = -2, + [1][0][RTW89_KCC][0][29] = -2, + [1][0][RTW89_ACMA][1][29] = 46, + [1][0][RTW89_ACMA][0][29] = 6, + [1][0][RTW89_CHILE][1][29] = -4, + [1][0][RTW89_QATAR][1][29] = 46, + [1][0][RTW89_QATAR][0][29] = 6, + [1][0][RTW89_UK][1][29] = 46, + [1][0][RTW89_UK][0][29] = 6, + [1][0][RTW89_FCC][1][30] = -4, + [1][0][RTW89_FCC][2][30] = 66, + [1][0][RTW89_ETSI][1][30] = 46, + [1][0][RTW89_ETSI][0][30] = 6, + [1][0][RTW89_MKK][1][30] = 42, + [1][0][RTW89_MKK][0][30] = 2, + [1][0][RTW89_IC][1][30] = -4, + [1][0][RTW89_KCC][1][30] = -2, + [1][0][RTW89_KCC][0][30] = -2, + [1][0][RTW89_ACMA][1][30] = 46, + [1][0][RTW89_ACMA][0][30] = 6, + [1][0][RTW89_CHILE][1][30] = -4, + [1][0][RTW89_QATAR][1][30] = 46, + [1][0][RTW89_QATAR][0][30] = 6, + [1][0][RTW89_UK][1][30] = 46, + [1][0][RTW89_UK][0][30] = 6, + [1][0][RTW89_FCC][1][32] = -4, + [1][0][RTW89_FCC][2][32] = 66, + [1][0][RTW89_ETSI][1][32] = 46, + [1][0][RTW89_ETSI][0][32] = 6, + [1][0][RTW89_MKK][1][32] = 42, + [1][0][RTW89_MKK][0][32] = 2, + [1][0][RTW89_IC][1][32] = -4, + [1][0][RTW89_KCC][1][32] = -2, + [1][0][RTW89_KCC][0][32] = -2, + [1][0][RTW89_ACMA][1][32] = 46, + [1][0][RTW89_ACMA][0][32] = 6, + [1][0][RTW89_CHILE][1][32] = -4, + [1][0][RTW89_QATAR][1][32] = 46, + [1][0][RTW89_QATAR][0][32] = 6, + [1][0][RTW89_UK][1][32] = 46, + [1][0][RTW89_UK][0][32] = 6, + [1][0][RTW89_FCC][1][34] = -4, + [1][0][RTW89_FCC][2][34] = 66, + [1][0][RTW89_ETSI][1][34] = 46, + [1][0][RTW89_ETSI][0][34] = 6, + [1][0][RTW89_MKK][1][34] = 42, + [1][0][RTW89_MKK][0][34] = 2, + [1][0][RTW89_IC][1][34] = -4, + [1][0][RTW89_KCC][1][34] = -2, + [1][0][RTW89_KCC][0][34] = -2, + [1][0][RTW89_ACMA][1][34] = 46, + [1][0][RTW89_ACMA][0][34] = 6, + [1][0][RTW89_CHILE][1][34] = -4, + [1][0][RTW89_QATAR][1][34] = 46, + [1][0][RTW89_QATAR][0][34] = 6, + [1][0][RTW89_UK][1][34] = 46, + [1][0][RTW89_UK][0][34] = 6, + [1][0][RTW89_FCC][1][36] = -4, + [1][0][RTW89_FCC][2][36] = 66, + [1][0][RTW89_ETSI][1][36] = 46, + [1][0][RTW89_ETSI][0][36] = 6, + [1][0][RTW89_MKK][1][36] = 42, + [1][0][RTW89_MKK][0][36] = 2, + [1][0][RTW89_IC][1][36] = -4, + [1][0][RTW89_KCC][1][36] = -2, + [1][0][RTW89_KCC][0][36] = -2, + [1][0][RTW89_ACMA][1][36] = 46, + [1][0][RTW89_ACMA][0][36] = 6, + [1][0][RTW89_CHILE][1][36] = -4, + [1][0][RTW89_QATAR][1][36] = 46, + [1][0][RTW89_QATAR][0][36] = 6, + [1][0][RTW89_UK][1][36] = 46, + [1][0][RTW89_UK][0][36] = 6, + [1][0][RTW89_FCC][1][38] = -4, + [1][0][RTW89_FCC][2][38] = 66, + [1][0][RTW89_ETSI][1][38] = 46, + [1][0][RTW89_ETSI][0][38] = 6, + [1][0][RTW89_MKK][1][38] = 42, + [1][0][RTW89_MKK][0][38] = 2, + [1][0][RTW89_IC][1][38] = -4, + [1][0][RTW89_KCC][1][38] = -2, + [1][0][RTW89_KCC][0][38] = -2, + [1][0][RTW89_ACMA][1][38] = 46, + [1][0][RTW89_ACMA][0][38] = 6, + [1][0][RTW89_CHILE][1][38] = -4, + [1][0][RTW89_QATAR][1][38] = 46, + [1][0][RTW89_QATAR][0][38] = 6, + [1][0][RTW89_UK][1][38] = 46, + [1][0][RTW89_UK][0][38] = 6, + [1][0][RTW89_FCC][1][40] = -4, + [1][0][RTW89_FCC][2][40] = 66, + [1][0][RTW89_ETSI][1][40] = 46, + [1][0][RTW89_ETSI][0][40] = 6, + [1][0][RTW89_MKK][1][40] = 42, + [1][0][RTW89_MKK][0][40] = 2, + [1][0][RTW89_IC][1][40] = -4, + [1][0][RTW89_KCC][1][40] = -2, + [1][0][RTW89_KCC][0][40] = -2, + [1][0][RTW89_ACMA][1][40] = 46, + [1][0][RTW89_ACMA][0][40] = 6, + [1][0][RTW89_CHILE][1][40] = -4, + [1][0][RTW89_QATAR][1][40] = 46, + [1][0][RTW89_QATAR][0][40] = 6, + [1][0][RTW89_UK][1][40] = 46, + [1][0][RTW89_UK][0][40] = 6, + [1][0][RTW89_FCC][1][42] = -4, + [1][0][RTW89_FCC][2][42] = 66, + [1][0][RTW89_ETSI][1][42] = 46, + [1][0][RTW89_ETSI][0][42] = 6, + [1][0][RTW89_MKK][1][42] = 42, + [1][0][RTW89_MKK][0][42] = 2, + [1][0][RTW89_IC][1][42] = -4, + [1][0][RTW89_KCC][1][42] = -2, + [1][0][RTW89_KCC][0][42] = -2, + [1][0][RTW89_ACMA][1][42] = 46, + [1][0][RTW89_ACMA][0][42] = 6, + [1][0][RTW89_CHILE][1][42] = -4, + [1][0][RTW89_QATAR][1][42] = 46, + [1][0][RTW89_QATAR][0][42] = 6, + [1][0][RTW89_UK][1][42] = 46, + [1][0][RTW89_UK][0][42] = 6, + [1][0][RTW89_FCC][1][44] = -4, + [1][0][RTW89_FCC][2][44] = 66, + [1][0][RTW89_ETSI][1][44] = 46, + [1][0][RTW89_ETSI][0][44] = 8, + [1][0][RTW89_MKK][1][44] = 22, + [1][0][RTW89_MKK][0][44] = 4, + [1][0][RTW89_IC][1][44] = -4, + [1][0][RTW89_KCC][1][44] = -2, + [1][0][RTW89_KCC][0][44] = -2, + [1][0][RTW89_ACMA][1][44] = 46, + [1][0][RTW89_ACMA][0][44] = 8, + [1][0][RTW89_CHILE][1][44] = -4, + [1][0][RTW89_QATAR][1][44] = 46, + [1][0][RTW89_QATAR][0][44] = 8, + [1][0][RTW89_UK][1][44] = 46, + [1][0][RTW89_UK][0][44] = 8, + [1][0][RTW89_FCC][1][45] = -4, + [1][0][RTW89_FCC][2][45] = 127, + [1][0][RTW89_ETSI][1][45] = 127, + [1][0][RTW89_ETSI][0][45] = 127, + [1][0][RTW89_MKK][1][45] = 127, + [1][0][RTW89_MKK][0][45] = 127, + [1][0][RTW89_IC][1][45] = -4, + [1][0][RTW89_KCC][1][45] = -2, + [1][0][RTW89_KCC][0][45] = 127, + [1][0][RTW89_ACMA][1][45] = 127, + [1][0][RTW89_ACMA][0][45] = 127, + [1][0][RTW89_CHILE][1][45] = 127, + [1][0][RTW89_QATAR][1][45] = 127, + [1][0][RTW89_QATAR][0][45] = 127, + [1][0][RTW89_UK][1][45] = 127, + [1][0][RTW89_UK][0][45] = 127, + [1][0][RTW89_FCC][1][47] = -4, + [1][0][RTW89_FCC][2][47] = 127, + [1][0][RTW89_ETSI][1][47] = 127, + [1][0][RTW89_ETSI][0][47] = 127, + [1][0][RTW89_MKK][1][47] = 127, + [1][0][RTW89_MKK][0][47] = 127, + [1][0][RTW89_IC][1][47] = -4, + [1][0][RTW89_KCC][1][47] = -2, + [1][0][RTW89_KCC][0][47] = 127, + [1][0][RTW89_ACMA][1][47] = 127, + [1][0][RTW89_ACMA][0][47] = 127, + [1][0][RTW89_CHILE][1][47] = 127, + [1][0][RTW89_QATAR][1][47] = 127, + [1][0][RTW89_QATAR][0][47] = 127, + [1][0][RTW89_UK][1][47] = 127, + [1][0][RTW89_UK][0][47] = 127, + [1][0][RTW89_FCC][1][49] = -4, + [1][0][RTW89_FCC][2][49] = 127, + [1][0][RTW89_ETSI][1][49] = 127, + [1][0][RTW89_ETSI][0][49] = 127, + [1][0][RTW89_MKK][1][49] = 127, + [1][0][RTW89_MKK][0][49] = 127, + [1][0][RTW89_IC][1][49] = -4, + [1][0][RTW89_KCC][1][49] = -2, + [1][0][RTW89_KCC][0][49] = 127, + [1][0][RTW89_ACMA][1][49] = 127, + [1][0][RTW89_ACMA][0][49] = 127, + [1][0][RTW89_CHILE][1][49] = 127, + [1][0][RTW89_QATAR][1][49] = 127, + [1][0][RTW89_QATAR][0][49] = 127, + [1][0][RTW89_UK][1][49] = 127, + [1][0][RTW89_UK][0][49] = 127, + [1][0][RTW89_FCC][1][51] = -4, + [1][0][RTW89_FCC][2][51] = 127, + [1][0][RTW89_ETSI][1][51] = 127, + [1][0][RTW89_ETSI][0][51] = 127, + [1][0][RTW89_MKK][1][51] = 127, + [1][0][RTW89_MKK][0][51] = 127, + [1][0][RTW89_IC][1][51] = -4, + [1][0][RTW89_KCC][1][51] = -2, + [1][0][RTW89_KCC][0][51] = 127, + [1][0][RTW89_ACMA][1][51] = 127, + [1][0][RTW89_ACMA][0][51] = 127, + [1][0][RTW89_CHILE][1][51] = 127, + [1][0][RTW89_QATAR][1][51] = 127, + [1][0][RTW89_QATAR][0][51] = 127, + [1][0][RTW89_UK][1][51] = 127, + [1][0][RTW89_UK][0][51] = 127, + [1][0][RTW89_FCC][1][53] = -4, + [1][0][RTW89_FCC][2][53] = 127, + [1][0][RTW89_ETSI][1][53] = 127, + [1][0][RTW89_ETSI][0][53] = 127, + [1][0][RTW89_MKK][1][53] = 127, + [1][0][RTW89_MKK][0][53] = 127, + [1][0][RTW89_IC][1][53] = -4, + [1][0][RTW89_KCC][1][53] = -2, + [1][0][RTW89_KCC][0][53] = 127, + [1][0][RTW89_ACMA][1][53] = 127, + [1][0][RTW89_ACMA][0][53] = 127, + [1][0][RTW89_CHILE][1][53] = 127, + [1][0][RTW89_QATAR][1][53] = 127, + [1][0][RTW89_QATAR][0][53] = 127, + [1][0][RTW89_UK][1][53] = 127, + [1][0][RTW89_UK][0][53] = 127, + [1][0][RTW89_FCC][1][55] = -4, + [1][0][RTW89_FCC][2][55] = 68, + [1][0][RTW89_ETSI][1][55] = 127, + [1][0][RTW89_ETSI][0][55] = 127, + [1][0][RTW89_MKK][1][55] = 127, + [1][0][RTW89_MKK][0][55] = 127, + [1][0][RTW89_IC][1][55] = -4, + [1][0][RTW89_KCC][1][55] = -2, + [1][0][RTW89_KCC][0][55] = 127, + [1][0][RTW89_ACMA][1][55] = 127, + [1][0][RTW89_ACMA][0][55] = 127, + [1][0][RTW89_CHILE][1][55] = 127, + [1][0][RTW89_QATAR][1][55] = 127, + [1][0][RTW89_QATAR][0][55] = 127, + [1][0][RTW89_UK][1][55] = 127, + [1][0][RTW89_UK][0][55] = 127, + [1][0][RTW89_FCC][1][57] = -4, + [1][0][RTW89_FCC][2][57] = 68, + [1][0][RTW89_ETSI][1][57] = 127, + [1][0][RTW89_ETSI][0][57] = 127, + [1][0][RTW89_MKK][1][57] = 127, + [1][0][RTW89_MKK][0][57] = 127, + [1][0][RTW89_IC][1][57] = -4, + [1][0][RTW89_KCC][1][57] = -2, + [1][0][RTW89_KCC][0][57] = 127, + [1][0][RTW89_ACMA][1][57] = 127, + [1][0][RTW89_ACMA][0][57] = 127, + [1][0][RTW89_CHILE][1][57] = 127, + [1][0][RTW89_QATAR][1][57] = 127, + [1][0][RTW89_QATAR][0][57] = 127, + [1][0][RTW89_UK][1][57] = 127, + [1][0][RTW89_UK][0][57] = 127, + [1][0][RTW89_FCC][1][59] = -4, + [1][0][RTW89_FCC][2][59] = 68, + [1][0][RTW89_ETSI][1][59] = 127, + [1][0][RTW89_ETSI][0][59] = 127, + [1][0][RTW89_MKK][1][59] = 127, + [1][0][RTW89_MKK][0][59] = 127, + [1][0][RTW89_IC][1][59] = -4, + [1][0][RTW89_KCC][1][59] = -2, + [1][0][RTW89_KCC][0][59] = 127, + [1][0][RTW89_ACMA][1][59] = 127, + [1][0][RTW89_ACMA][0][59] = 127, + [1][0][RTW89_CHILE][1][59] = 127, + [1][0][RTW89_QATAR][1][59] = 127, + [1][0][RTW89_QATAR][0][59] = 127, + [1][0][RTW89_UK][1][59] = 127, + [1][0][RTW89_UK][0][59] = 127, + [1][0][RTW89_FCC][1][60] = -4, + [1][0][RTW89_FCC][2][60] = 68, + [1][0][RTW89_ETSI][1][60] = 127, + [1][0][RTW89_ETSI][0][60] = 127, + [1][0][RTW89_MKK][1][60] = 127, + [1][0][RTW89_MKK][0][60] = 127, + [1][0][RTW89_IC][1][60] = -4, + [1][0][RTW89_KCC][1][60] = -2, + [1][0][RTW89_KCC][0][60] = 127, + [1][0][RTW89_ACMA][1][60] = 127, + [1][0][RTW89_ACMA][0][60] = 127, + [1][0][RTW89_CHILE][1][60] = 127, + [1][0][RTW89_QATAR][1][60] = 127, + [1][0][RTW89_QATAR][0][60] = 127, + [1][0][RTW89_UK][1][60] = 127, + [1][0][RTW89_UK][0][60] = 127, + [1][0][RTW89_FCC][1][62] = -4, + [1][0][RTW89_FCC][2][62] = 68, + [1][0][RTW89_ETSI][1][62] = 127, + [1][0][RTW89_ETSI][0][62] = 127, + [1][0][RTW89_MKK][1][62] = 127, + [1][0][RTW89_MKK][0][62] = 127, + [1][0][RTW89_IC][1][62] = -4, + [1][0][RTW89_KCC][1][62] = -2, + [1][0][RTW89_KCC][0][62] = 127, + [1][0][RTW89_ACMA][1][62] = 127, + [1][0][RTW89_ACMA][0][62] = 127, + [1][0][RTW89_CHILE][1][62] = 127, + [1][0][RTW89_QATAR][1][62] = 127, + [1][0][RTW89_QATAR][0][62] = 127, + [1][0][RTW89_UK][1][62] = 127, + [1][0][RTW89_UK][0][62] = 127, + [1][0][RTW89_FCC][1][64] = -4, + [1][0][RTW89_FCC][2][64] = 68, + [1][0][RTW89_ETSI][1][64] = 127, + [1][0][RTW89_ETSI][0][64] = 127, + [1][0][RTW89_MKK][1][64] = 127, + [1][0][RTW89_MKK][0][64] = 127, + [1][0][RTW89_IC][1][64] = -4, + [1][0][RTW89_KCC][1][64] = -2, + [1][0][RTW89_KCC][0][64] = 127, + [1][0][RTW89_ACMA][1][64] = 127, + [1][0][RTW89_ACMA][0][64] = 127, + [1][0][RTW89_CHILE][1][64] = 127, + [1][0][RTW89_QATAR][1][64] = 127, + [1][0][RTW89_QATAR][0][64] = 127, + [1][0][RTW89_UK][1][64] = 127, + [1][0][RTW89_UK][0][64] = 127, + [1][0][RTW89_FCC][1][66] = -4, + [1][0][RTW89_FCC][2][66] = 68, + [1][0][RTW89_ETSI][1][66] = 127, + [1][0][RTW89_ETSI][0][66] = 127, + [1][0][RTW89_MKK][1][66] = 127, + [1][0][RTW89_MKK][0][66] = 127, + [1][0][RTW89_IC][1][66] = -4, + [1][0][RTW89_KCC][1][66] = -2, + [1][0][RTW89_KCC][0][66] = 127, + [1][0][RTW89_ACMA][1][66] = 127, + [1][0][RTW89_ACMA][0][66] = 127, + [1][0][RTW89_CHILE][1][66] = 127, + [1][0][RTW89_QATAR][1][66] = 127, + [1][0][RTW89_QATAR][0][66] = 127, + [1][0][RTW89_UK][1][66] = 127, + [1][0][RTW89_UK][0][66] = 127, + [1][0][RTW89_FCC][1][68] = -4, + [1][0][RTW89_FCC][2][68] = 68, + [1][0][RTW89_ETSI][1][68] = 127, + [1][0][RTW89_ETSI][0][68] = 127, + [1][0][RTW89_MKK][1][68] = 127, + [1][0][RTW89_MKK][0][68] = 127, + [1][0][RTW89_IC][1][68] = -4, + [1][0][RTW89_KCC][1][68] = -2, + [1][0][RTW89_KCC][0][68] = 127, + [1][0][RTW89_ACMA][1][68] = 127, + [1][0][RTW89_ACMA][0][68] = 127, + [1][0][RTW89_CHILE][1][68] = 127, + [1][0][RTW89_QATAR][1][68] = 127, + [1][0][RTW89_QATAR][0][68] = 127, + [1][0][RTW89_UK][1][68] = 127, + [1][0][RTW89_UK][0][68] = 127, + [1][0][RTW89_FCC][1][70] = -4, + [1][0][RTW89_FCC][2][70] = 68, + [1][0][RTW89_ETSI][1][70] = 127, + [1][0][RTW89_ETSI][0][70] = 127, + [1][0][RTW89_MKK][1][70] = 127, + [1][0][RTW89_MKK][0][70] = 127, + [1][0][RTW89_IC][1][70] = -4, + [1][0][RTW89_KCC][1][70] = -2, + [1][0][RTW89_KCC][0][70] = 127, + [1][0][RTW89_ACMA][1][70] = 127, + [1][0][RTW89_ACMA][0][70] = 127, + [1][0][RTW89_CHILE][1][70] = 127, + [1][0][RTW89_QATAR][1][70] = 127, + [1][0][RTW89_QATAR][0][70] = 127, + [1][0][RTW89_UK][1][70] = 127, + [1][0][RTW89_UK][0][70] = 127, + [1][0][RTW89_FCC][1][72] = -4, + [1][0][RTW89_FCC][2][72] = 68, + [1][0][RTW89_ETSI][1][72] = 127, + [1][0][RTW89_ETSI][0][72] = 127, + [1][0][RTW89_MKK][1][72] = 127, + [1][0][RTW89_MKK][0][72] = 127, + [1][0][RTW89_IC][1][72] = -4, + [1][0][RTW89_KCC][1][72] = -2, + [1][0][RTW89_KCC][0][72] = 127, + [1][0][RTW89_ACMA][1][72] = 127, + [1][0][RTW89_ACMA][0][72] = 127, + [1][0][RTW89_CHILE][1][72] = 127, + [1][0][RTW89_QATAR][1][72] = 127, + [1][0][RTW89_QATAR][0][72] = 127, + [1][0][RTW89_UK][1][72] = 127, + [1][0][RTW89_UK][0][72] = 127, + [1][0][RTW89_FCC][1][74] = -4, + [1][0][RTW89_FCC][2][74] = 68, + [1][0][RTW89_ETSI][1][74] = 127, + [1][0][RTW89_ETSI][0][74] = 127, + [1][0][RTW89_MKK][1][74] = 127, + [1][0][RTW89_MKK][0][74] = 127, + [1][0][RTW89_IC][1][74] = -4, + [1][0][RTW89_KCC][1][74] = -2, + [1][0][RTW89_KCC][0][74] = 127, + [1][0][RTW89_ACMA][1][74] = 127, + [1][0][RTW89_ACMA][0][74] = 127, + [1][0][RTW89_CHILE][1][74] = 127, + [1][0][RTW89_QATAR][1][74] = 127, + [1][0][RTW89_QATAR][0][74] = 127, + [1][0][RTW89_UK][1][74] = 127, + [1][0][RTW89_UK][0][74] = 127, + [1][0][RTW89_FCC][1][75] = -4, + [1][0][RTW89_FCC][2][75] = 68, + [1][0][RTW89_ETSI][1][75] = 127, + [1][0][RTW89_ETSI][0][75] = 127, + [1][0][RTW89_MKK][1][75] = 127, + [1][0][RTW89_MKK][0][75] = 127, + [1][0][RTW89_IC][1][75] = -4, + [1][0][RTW89_KCC][1][75] = -2, + [1][0][RTW89_KCC][0][75] = 127, + [1][0][RTW89_ACMA][1][75] = 127, + [1][0][RTW89_ACMA][0][75] = 127, + [1][0][RTW89_CHILE][1][75] = 127, + [1][0][RTW89_QATAR][1][75] = 127, + [1][0][RTW89_QATAR][0][75] = 127, + [1][0][RTW89_UK][1][75] = 127, + [1][0][RTW89_UK][0][75] = 127, + [1][0][RTW89_FCC][1][77] = -4, + [1][0][RTW89_FCC][2][77] = 68, + [1][0][RTW89_ETSI][1][77] = 127, + [1][0][RTW89_ETSI][0][77] = 127, + [1][0][RTW89_MKK][1][77] = 127, + [1][0][RTW89_MKK][0][77] = 127, + [1][0][RTW89_IC][1][77] = -4, + [1][0][RTW89_KCC][1][77] = -2, + [1][0][RTW89_KCC][0][77] = 127, + [1][0][RTW89_ACMA][1][77] = 127, + [1][0][RTW89_ACMA][0][77] = 127, + [1][0][RTW89_CHILE][1][77] = 127, + [1][0][RTW89_QATAR][1][77] = 127, + [1][0][RTW89_QATAR][0][77] = 127, + [1][0][RTW89_UK][1][77] = 127, + [1][0][RTW89_UK][0][77] = 127, + [1][0][RTW89_FCC][1][79] = -4, + [1][0][RTW89_FCC][2][79] = 68, + [1][0][RTW89_ETSI][1][79] = 127, + [1][0][RTW89_ETSI][0][79] = 127, + [1][0][RTW89_MKK][1][79] = 127, + [1][0][RTW89_MKK][0][79] = 127, + [1][0][RTW89_IC][1][79] = -4, + [1][0][RTW89_KCC][1][79] = -2, + [1][0][RTW89_KCC][0][79] = 127, + [1][0][RTW89_ACMA][1][79] = 127, + [1][0][RTW89_ACMA][0][79] = 127, + [1][0][RTW89_CHILE][1][79] = 127, + [1][0][RTW89_QATAR][1][79] = 127, + [1][0][RTW89_QATAR][0][79] = 127, + [1][0][RTW89_UK][1][79] = 127, + [1][0][RTW89_UK][0][79] = 127, + [1][0][RTW89_FCC][1][81] = -4, + [1][0][RTW89_FCC][2][81] = 68, + [1][0][RTW89_ETSI][1][81] = 127, + [1][0][RTW89_ETSI][0][81] = 127, + [1][0][RTW89_MKK][1][81] = 127, + [1][0][RTW89_MKK][0][81] = 127, + [1][0][RTW89_IC][1][81] = -4, + [1][0][RTW89_KCC][1][81] = -2, + [1][0][RTW89_KCC][0][81] = 127, + [1][0][RTW89_ACMA][1][81] = 127, + [1][0][RTW89_ACMA][0][81] = 127, + [1][0][RTW89_CHILE][1][81] = 127, + [1][0][RTW89_QATAR][1][81] = 127, + [1][0][RTW89_QATAR][0][81] = 127, + [1][0][RTW89_UK][1][81] = 127, + [1][0][RTW89_UK][0][81] = 127, + [1][0][RTW89_FCC][1][83] = -4, + [1][0][RTW89_FCC][2][83] = 68, + [1][0][RTW89_ETSI][1][83] = 127, + [1][0][RTW89_ETSI][0][83] = 127, + [1][0][RTW89_MKK][1][83] = 127, + [1][0][RTW89_MKK][0][83] = 127, + [1][0][RTW89_IC][1][83] = -4, + [1][0][RTW89_KCC][1][83] = -2, + [1][0][RTW89_KCC][0][83] = 127, + [1][0][RTW89_ACMA][1][83] = 127, + [1][0][RTW89_ACMA][0][83] = 127, + [1][0][RTW89_CHILE][1][83] = 127, + [1][0][RTW89_QATAR][1][83] = 127, + [1][0][RTW89_QATAR][0][83] = 127, + [1][0][RTW89_UK][1][83] = 127, + [1][0][RTW89_UK][0][83] = 127, + [1][0][RTW89_FCC][1][85] = -4, + [1][0][RTW89_FCC][2][85] = 68, + [1][0][RTW89_ETSI][1][85] = 127, + [1][0][RTW89_ETSI][0][85] = 127, + [1][0][RTW89_MKK][1][85] = 127, + [1][0][RTW89_MKK][0][85] = 127, + [1][0][RTW89_IC][1][85] = -4, + [1][0][RTW89_KCC][1][85] = -2, + [1][0][RTW89_KCC][0][85] = 127, + [1][0][RTW89_ACMA][1][85] = 127, + [1][0][RTW89_ACMA][0][85] = 127, + [1][0][RTW89_CHILE][1][85] = 127, + [1][0][RTW89_QATAR][1][85] = 127, + [1][0][RTW89_QATAR][0][85] = 127, + [1][0][RTW89_UK][1][85] = 127, + [1][0][RTW89_UK][0][85] = 127, + [1][0][RTW89_FCC][1][87] = -4, + [1][0][RTW89_FCC][2][87] = 127, + [1][0][RTW89_ETSI][1][87] = 127, + [1][0][RTW89_ETSI][0][87] = 127, + [1][0][RTW89_MKK][1][87] = 127, + [1][0][RTW89_MKK][0][87] = 127, + [1][0][RTW89_IC][1][87] = -4, + [1][0][RTW89_KCC][1][87] = -2, + [1][0][RTW89_KCC][0][87] = 127, + [1][0][RTW89_ACMA][1][87] = 127, + [1][0][RTW89_ACMA][0][87] = 127, + [1][0][RTW89_CHILE][1][87] = 127, + [1][0][RTW89_QATAR][1][87] = 127, + [1][0][RTW89_QATAR][0][87] = 127, + [1][0][RTW89_UK][1][87] = 127, + [1][0][RTW89_UK][0][87] = 127, + [1][0][RTW89_FCC][1][89] = -4, + [1][0][RTW89_FCC][2][89] = 127, + [1][0][RTW89_ETSI][1][89] = 127, + [1][0][RTW89_ETSI][0][89] = 127, + [1][0][RTW89_MKK][1][89] = 127, + [1][0][RTW89_MKK][0][89] = 127, + [1][0][RTW89_IC][1][89] = -4, + [1][0][RTW89_KCC][1][89] = -2, + [1][0][RTW89_KCC][0][89] = 127, + [1][0][RTW89_ACMA][1][89] = 127, + [1][0][RTW89_ACMA][0][89] = 127, + [1][0][RTW89_CHILE][1][89] = 127, + [1][0][RTW89_QATAR][1][89] = 127, + [1][0][RTW89_QATAR][0][89] = 127, + [1][0][RTW89_UK][1][89] = 127, + [1][0][RTW89_UK][0][89] = 127, + [1][0][RTW89_FCC][1][90] = -4, + [1][0][RTW89_FCC][2][90] = 127, + [1][0][RTW89_ETSI][1][90] = 127, + [1][0][RTW89_ETSI][0][90] = 127, + [1][0][RTW89_MKK][1][90] = 127, + [1][0][RTW89_MKK][0][90] = 127, + [1][0][RTW89_IC][1][90] = -4, + [1][0][RTW89_KCC][1][90] = -2, + [1][0][RTW89_KCC][0][90] = 127, + [1][0][RTW89_ACMA][1][90] = 127, + [1][0][RTW89_ACMA][0][90] = 127, + [1][0][RTW89_CHILE][1][90] = 127, + [1][0][RTW89_QATAR][1][90] = 127, + [1][0][RTW89_QATAR][0][90] = 127, + [1][0][RTW89_UK][1][90] = 127, + [1][0][RTW89_UK][0][90] = 127, + [1][0][RTW89_FCC][1][92] = -4, + [1][0][RTW89_FCC][2][92] = 127, + [1][0][RTW89_ETSI][1][92] = 127, + [1][0][RTW89_ETSI][0][92] = 127, + [1][0][RTW89_MKK][1][92] = 127, + [1][0][RTW89_MKK][0][92] = 127, + [1][0][RTW89_IC][1][92] = -4, + [1][0][RTW89_KCC][1][92] = -2, + [1][0][RTW89_KCC][0][92] = 127, + [1][0][RTW89_ACMA][1][92] = 127, + [1][0][RTW89_ACMA][0][92] = 127, + [1][0][RTW89_CHILE][1][92] = 127, + [1][0][RTW89_QATAR][1][92] = 127, + [1][0][RTW89_QATAR][0][92] = 127, + [1][0][RTW89_UK][1][92] = 127, + [1][0][RTW89_UK][0][92] = 127, + [1][0][RTW89_FCC][1][94] = -4, + [1][0][RTW89_FCC][2][94] = 127, + [1][0][RTW89_ETSI][1][94] = 127, + [1][0][RTW89_ETSI][0][94] = 127, + [1][0][RTW89_MKK][1][94] = 127, + [1][0][RTW89_MKK][0][94] = 127, + [1][0][RTW89_IC][1][94] = -4, + [1][0][RTW89_KCC][1][94] = -2, + [1][0][RTW89_KCC][0][94] = 127, + [1][0][RTW89_ACMA][1][94] = 127, + [1][0][RTW89_ACMA][0][94] = 127, + [1][0][RTW89_CHILE][1][94] = 127, + [1][0][RTW89_QATAR][1][94] = 127, + [1][0][RTW89_QATAR][0][94] = 127, + [1][0][RTW89_UK][1][94] = 127, + [1][0][RTW89_UK][0][94] = 127, + [1][0][RTW89_FCC][1][96] = -4, + [1][0][RTW89_FCC][2][96] = 127, + [1][0][RTW89_ETSI][1][96] = 127, + [1][0][RTW89_ETSI][0][96] = 127, + [1][0][RTW89_MKK][1][96] = 127, + [1][0][RTW89_MKK][0][96] = 127, + [1][0][RTW89_IC][1][96] = -4, + [1][0][RTW89_KCC][1][96] = -2, + [1][0][RTW89_KCC][0][96] = 127, + [1][0][RTW89_ACMA][1][96] = 127, + [1][0][RTW89_ACMA][0][96] = 127, + [1][0][RTW89_CHILE][1][96] = 127, + [1][0][RTW89_QATAR][1][96] = 127, + [1][0][RTW89_QATAR][0][96] = 127, + [1][0][RTW89_UK][1][96] = 127, + [1][0][RTW89_UK][0][96] = 127, + [1][0][RTW89_FCC][1][98] = -4, + [1][0][RTW89_FCC][2][98] = 127, + [1][0][RTW89_ETSI][1][98] = 127, + [1][0][RTW89_ETSI][0][98] = 127, + [1][0][RTW89_MKK][1][98] = 127, + [1][0][RTW89_MKK][0][98] = 127, + [1][0][RTW89_IC][1][98] = -4, + [1][0][RTW89_KCC][1][98] = -2, + [1][0][RTW89_KCC][0][98] = 127, + [1][0][RTW89_ACMA][1][98] = 127, + [1][0][RTW89_ACMA][0][98] = 127, + [1][0][RTW89_CHILE][1][98] = 127, + [1][0][RTW89_QATAR][1][98] = 127, + [1][0][RTW89_QATAR][0][98] = 127, + [1][0][RTW89_UK][1][98] = 127, + [1][0][RTW89_UK][0][98] = 127, + [1][0][RTW89_FCC][1][100] = -4, + [1][0][RTW89_FCC][2][100] = 127, + [1][0][RTW89_ETSI][1][100] = 127, + [1][0][RTW89_ETSI][0][100] = 127, + [1][0][RTW89_MKK][1][100] = 127, + [1][0][RTW89_MKK][0][100] = 127, + [1][0][RTW89_IC][1][100] = -4, + [1][0][RTW89_KCC][1][100] = -2, + [1][0][RTW89_KCC][0][100] = 127, + [1][0][RTW89_ACMA][1][100] = 127, + [1][0][RTW89_ACMA][0][100] = 127, + [1][0][RTW89_CHILE][1][100] = 127, + [1][0][RTW89_QATAR][1][100] = 127, + [1][0][RTW89_QATAR][0][100] = 127, + [1][0][RTW89_UK][1][100] = 127, + [1][0][RTW89_UK][0][100] = 127, + [1][0][RTW89_FCC][1][102] = -4, + [1][0][RTW89_FCC][2][102] = 127, + [1][0][RTW89_ETSI][1][102] = 127, + [1][0][RTW89_ETSI][0][102] = 127, + [1][0][RTW89_MKK][1][102] = 127, + [1][0][RTW89_MKK][0][102] = 127, + [1][0][RTW89_IC][1][102] = -4, + [1][0][RTW89_KCC][1][102] = -2, + [1][0][RTW89_KCC][0][102] = 127, + [1][0][RTW89_ACMA][1][102] = 127, + [1][0][RTW89_ACMA][0][102] = 127, + [1][0][RTW89_CHILE][1][102] = 127, + [1][0][RTW89_QATAR][1][102] = 127, + [1][0][RTW89_QATAR][0][102] = 127, + [1][0][RTW89_UK][1][102] = 127, + [1][0][RTW89_UK][0][102] = 127, + [1][0][RTW89_FCC][1][104] = -4, + [1][0][RTW89_FCC][2][104] = 127, + [1][0][RTW89_ETSI][1][104] = 127, + [1][0][RTW89_ETSI][0][104] = 127, + [1][0][RTW89_MKK][1][104] = 127, + [1][0][RTW89_MKK][0][104] = 127, + [1][0][RTW89_IC][1][104] = -4, + [1][0][RTW89_KCC][1][104] = -2, + [1][0][RTW89_KCC][0][104] = 127, + [1][0][RTW89_ACMA][1][104] = 127, + [1][0][RTW89_ACMA][0][104] = 127, + [1][0][RTW89_CHILE][1][104] = 127, + [1][0][RTW89_QATAR][1][104] = 127, + [1][0][RTW89_QATAR][0][104] = 127, + [1][0][RTW89_UK][1][104] = 127, + [1][0][RTW89_UK][0][104] = 127, + [1][0][RTW89_FCC][1][105] = -4, + [1][0][RTW89_FCC][2][105] = 127, + [1][0][RTW89_ETSI][1][105] = 127, + [1][0][RTW89_ETSI][0][105] = 127, + [1][0][RTW89_MKK][1][105] = 127, + [1][0][RTW89_MKK][0][105] = 127, + [1][0][RTW89_IC][1][105] = -4, + [1][0][RTW89_KCC][1][105] = -2, + [1][0][RTW89_KCC][0][105] = 127, + [1][0][RTW89_ACMA][1][105] = 127, + [1][0][RTW89_ACMA][0][105] = 127, + [1][0][RTW89_CHILE][1][105] = 127, + [1][0][RTW89_QATAR][1][105] = 127, + [1][0][RTW89_QATAR][0][105] = 127, + [1][0][RTW89_UK][1][105] = 127, + [1][0][RTW89_UK][0][105] = 127, + [1][0][RTW89_FCC][1][107] = 1, + [1][0][RTW89_FCC][2][107] = 127, + [1][0][RTW89_ETSI][1][107] = 127, + [1][0][RTW89_ETSI][0][107] = 127, + [1][0][RTW89_MKK][1][107] = 127, + [1][0][RTW89_MKK][0][107] = 127, + [1][0][RTW89_IC][1][107] = 1, + [1][0][RTW89_KCC][1][107] = -2, + [1][0][RTW89_KCC][0][107] = 127, + [1][0][RTW89_ACMA][1][107] = 127, + [1][0][RTW89_ACMA][0][107] = 127, + [1][0][RTW89_CHILE][1][107] = 127, + [1][0][RTW89_QATAR][1][107] = 127, + [1][0][RTW89_QATAR][0][107] = 127, + [1][0][RTW89_UK][1][107] = 127, + [1][0][RTW89_UK][0][107] = 127, + [1][0][RTW89_FCC][1][109] = 2, + [1][0][RTW89_FCC][2][109] = 127, + [1][0][RTW89_ETSI][1][109] = 127, + [1][0][RTW89_ETSI][0][109] = 127, + [1][0][RTW89_MKK][1][109] = 127, + [1][0][RTW89_MKK][0][109] = 127, + [1][0][RTW89_IC][1][109] = 2, + [1][0][RTW89_KCC][1][109] = 127, + [1][0][RTW89_KCC][0][109] = 127, + [1][0][RTW89_ACMA][1][109] = 127, + [1][0][RTW89_ACMA][0][109] = 127, + [1][0][RTW89_CHILE][1][109] = 127, + [1][0][RTW89_QATAR][1][109] = 127, + [1][0][RTW89_QATAR][0][109] = 127, + [1][0][RTW89_UK][1][109] = 127, + [1][0][RTW89_UK][0][109] = 127, + [1][0][RTW89_FCC][1][111] = 127, + [1][0][RTW89_FCC][2][111] = 127, + [1][0][RTW89_ETSI][1][111] = 127, + [1][0][RTW89_ETSI][0][111] = 127, + [1][0][RTW89_MKK][1][111] = 127, + [1][0][RTW89_MKK][0][111] = 127, + [1][0][RTW89_IC][1][111] = 127, + [1][0][RTW89_KCC][1][111] = 127, + [1][0][RTW89_KCC][0][111] = 127, + [1][0][RTW89_ACMA][1][111] = 127, + [1][0][RTW89_ACMA][0][111] = 127, + [1][0][RTW89_CHILE][1][111] = 127, + [1][0][RTW89_QATAR][1][111] = 127, + [1][0][RTW89_QATAR][0][111] = 127, + [1][0][RTW89_UK][1][111] = 127, + [1][0][RTW89_UK][0][111] = 127, + [1][0][RTW89_FCC][1][113] = 127, + [1][0][RTW89_FCC][2][113] = 127, + [1][0][RTW89_ETSI][1][113] = 127, + [1][0][RTW89_ETSI][0][113] = 127, + [1][0][RTW89_MKK][1][113] = 127, + [1][0][RTW89_MKK][0][113] = 127, + [1][0][RTW89_IC][1][113] = 127, + [1][0][RTW89_KCC][1][113] = 127, + [1][0][RTW89_KCC][0][113] = 127, + [1][0][RTW89_ACMA][1][113] = 127, + [1][0][RTW89_ACMA][0][113] = 127, + [1][0][RTW89_CHILE][1][113] = 127, + [1][0][RTW89_QATAR][1][113] = 127, + [1][0][RTW89_QATAR][0][113] = 127, + [1][0][RTW89_UK][1][113] = 127, + [1][0][RTW89_UK][0][113] = 127, + [1][0][RTW89_FCC][1][115] = 127, + [1][0][RTW89_FCC][2][115] = 127, + [1][0][RTW89_ETSI][1][115] = 127, + [1][0][RTW89_ETSI][0][115] = 127, + [1][0][RTW89_MKK][1][115] = 127, + [1][0][RTW89_MKK][0][115] = 127, + [1][0][RTW89_IC][1][115] = 127, + [1][0][RTW89_KCC][1][115] = 127, + [1][0][RTW89_KCC][0][115] = 127, + [1][0][RTW89_ACMA][1][115] = 127, + [1][0][RTW89_ACMA][0][115] = 127, + [1][0][RTW89_CHILE][1][115] = 127, + [1][0][RTW89_QATAR][1][115] = 127, + [1][0][RTW89_QATAR][0][115] = 127, + [1][0][RTW89_UK][1][115] = 127, + [1][0][RTW89_UK][0][115] = 127, + [1][0][RTW89_FCC][1][117] = 127, + [1][0][RTW89_FCC][2][117] = 127, + [1][0][RTW89_ETSI][1][117] = 127, + [1][0][RTW89_ETSI][0][117] = 127, + [1][0][RTW89_MKK][1][117] = 127, + [1][0][RTW89_MKK][0][117] = 127, + [1][0][RTW89_IC][1][117] = 127, + [1][0][RTW89_KCC][1][117] = 127, + [1][0][RTW89_KCC][0][117] = 127, + [1][0][RTW89_ACMA][1][117] = 127, + [1][0][RTW89_ACMA][0][117] = 127, + [1][0][RTW89_CHILE][1][117] = 127, + [1][0][RTW89_QATAR][1][117] = 127, + [1][0][RTW89_QATAR][0][117] = 127, + [1][0][RTW89_UK][1][117] = 127, + [1][0][RTW89_UK][0][117] = 127, + [1][0][RTW89_FCC][1][119] = 127, + [1][0][RTW89_FCC][2][119] = 127, + [1][0][RTW89_ETSI][1][119] = 127, + [1][0][RTW89_ETSI][0][119] = 127, + [1][0][RTW89_MKK][1][119] = 127, + [1][0][RTW89_MKK][0][119] = 127, + [1][0][RTW89_IC][1][119] = 127, + [1][0][RTW89_KCC][1][119] = 127, + [1][0][RTW89_KCC][0][119] = 127, + [1][0][RTW89_ACMA][1][119] = 127, + [1][0][RTW89_ACMA][0][119] = 127, + [1][0][RTW89_CHILE][1][119] = 127, + [1][0][RTW89_QATAR][1][119] = 127, + [1][0][RTW89_QATAR][0][119] = 127, + [1][0][RTW89_UK][1][119] = 127, + [1][0][RTW89_UK][0][119] = 127, + [1][1][RTW89_FCC][1][0] = -26, + [1][1][RTW89_FCC][2][0] = 44, + [1][1][RTW89_ETSI][1][0] = 32, + [1][1][RTW89_ETSI][0][0] = -6, + [1][1][RTW89_MKK][1][0] = 30, + [1][1][RTW89_MKK][0][0] = -10, + [1][1][RTW89_IC][1][0] = -26, + [1][1][RTW89_KCC][1][0] = -14, + [1][1][RTW89_KCC][0][0] = -14, + [1][1][RTW89_ACMA][1][0] = 32, + [1][1][RTW89_ACMA][0][0] = -6, + [1][1][RTW89_CHILE][1][0] = -26, + [1][1][RTW89_QATAR][1][0] = 32, + [1][1][RTW89_QATAR][0][0] = -6, + [1][1][RTW89_UK][1][0] = 32, + [1][1][RTW89_UK][0][0] = -6, + [1][1][RTW89_FCC][1][2] = -28, + [1][1][RTW89_FCC][2][2] = 44, + [1][1][RTW89_ETSI][1][2] = 32, + [1][1][RTW89_ETSI][0][2] = -6, + [1][1][RTW89_MKK][1][2] = 30, + [1][1][RTW89_MKK][0][2] = -10, + [1][1][RTW89_IC][1][2] = -28, + [1][1][RTW89_KCC][1][2] = -14, + [1][1][RTW89_KCC][0][2] = -14, + [1][1][RTW89_ACMA][1][2] = 32, + [1][1][RTW89_ACMA][0][2] = -6, + [1][1][RTW89_CHILE][1][2] = -28, + [1][1][RTW89_QATAR][1][2] = 32, + [1][1][RTW89_QATAR][0][2] = -6, + [1][1][RTW89_UK][1][2] = 32, + [1][1][RTW89_UK][0][2] = -6, + [1][1][RTW89_FCC][1][4] = -28, + [1][1][RTW89_FCC][2][4] = 44, + [1][1][RTW89_ETSI][1][4] = 32, + [1][1][RTW89_ETSI][0][4] = -6, + [1][1][RTW89_MKK][1][4] = 30, + [1][1][RTW89_MKK][0][4] = -10, + [1][1][RTW89_IC][1][4] = -28, + [1][1][RTW89_KCC][1][4] = -14, + [1][1][RTW89_KCC][0][4] = -14, + [1][1][RTW89_ACMA][1][4] = 32, + [1][1][RTW89_ACMA][0][4] = -6, + [1][1][RTW89_CHILE][1][4] = -28, + [1][1][RTW89_QATAR][1][4] = 32, + [1][1][RTW89_QATAR][0][4] = -6, + [1][1][RTW89_UK][1][4] = 32, + [1][1][RTW89_UK][0][4] = -6, + [1][1][RTW89_FCC][1][6] = -28, + [1][1][RTW89_FCC][2][6] = 44, + [1][1][RTW89_ETSI][1][6] = 32, + [1][1][RTW89_ETSI][0][6] = -6, + [1][1][RTW89_MKK][1][6] = 30, + [1][1][RTW89_MKK][0][6] = -10, + [1][1][RTW89_IC][1][6] = -28, + [1][1][RTW89_KCC][1][6] = -14, + [1][1][RTW89_KCC][0][6] = -14, + [1][1][RTW89_ACMA][1][6] = 32, + [1][1][RTW89_ACMA][0][6] = -6, + [1][1][RTW89_CHILE][1][6] = -28, + [1][1][RTW89_QATAR][1][6] = 32, + [1][1][RTW89_QATAR][0][6] = -6, + [1][1][RTW89_UK][1][6] = 32, + [1][1][RTW89_UK][0][6] = -6, + [1][1][RTW89_FCC][1][8] = -28, + [1][1][RTW89_FCC][2][8] = 44, + [1][1][RTW89_ETSI][1][8] = 32, + [1][1][RTW89_ETSI][0][8] = -6, + [1][1][RTW89_MKK][1][8] = 30, + [1][1][RTW89_MKK][0][8] = -10, + [1][1][RTW89_IC][1][8] = -28, + [1][1][RTW89_KCC][1][8] = -14, + [1][1][RTW89_KCC][0][8] = -14, + [1][1][RTW89_ACMA][1][8] = 32, + [1][1][RTW89_ACMA][0][8] = -6, + [1][1][RTW89_CHILE][1][8] = -28, + [1][1][RTW89_QATAR][1][8] = 32, + [1][1][RTW89_QATAR][0][8] = -6, + [1][1][RTW89_UK][1][8] = 32, + [1][1][RTW89_UK][0][8] = -6, + [1][1][RTW89_FCC][1][10] = -28, + [1][1][RTW89_FCC][2][10] = 44, + [1][1][RTW89_ETSI][1][10] = 32, + [1][1][RTW89_ETSI][0][10] = -6, + [1][1][RTW89_MKK][1][10] = 30, + [1][1][RTW89_MKK][0][10] = -10, + [1][1][RTW89_IC][1][10] = -28, + [1][1][RTW89_KCC][1][10] = -14, + [1][1][RTW89_KCC][0][10] = -14, + [1][1][RTW89_ACMA][1][10] = 32, + [1][1][RTW89_ACMA][0][10] = -6, + [1][1][RTW89_CHILE][1][10] = -28, + [1][1][RTW89_QATAR][1][10] = 32, + [1][1][RTW89_QATAR][0][10] = -6, + [1][1][RTW89_UK][1][10] = 32, + [1][1][RTW89_UK][0][10] = -6, + [1][1][RTW89_FCC][1][12] = -28, + [1][1][RTW89_FCC][2][12] = 44, + [1][1][RTW89_ETSI][1][12] = 32, + [1][1][RTW89_ETSI][0][12] = -6, + [1][1][RTW89_MKK][1][12] = 30, + [1][1][RTW89_MKK][0][12] = -10, + [1][1][RTW89_IC][1][12] = -28, + [1][1][RTW89_KCC][1][12] = -14, + [1][1][RTW89_KCC][0][12] = -14, + [1][1][RTW89_ACMA][1][12] = 32, + [1][1][RTW89_ACMA][0][12] = -6, + [1][1][RTW89_CHILE][1][12] = -28, + [1][1][RTW89_QATAR][1][12] = 32, + [1][1][RTW89_QATAR][0][12] = -6, + [1][1][RTW89_UK][1][12] = 32, + [1][1][RTW89_UK][0][12] = -6, + [1][1][RTW89_FCC][1][14] = -28, + [1][1][RTW89_FCC][2][14] = 44, + [1][1][RTW89_ETSI][1][14] = 32, + [1][1][RTW89_ETSI][0][14] = -6, + [1][1][RTW89_MKK][1][14] = 30, + [1][1][RTW89_MKK][0][14] = -10, + [1][1][RTW89_IC][1][14] = -28, + [1][1][RTW89_KCC][1][14] = -14, + [1][1][RTW89_KCC][0][14] = -14, + [1][1][RTW89_ACMA][1][14] = 32, + [1][1][RTW89_ACMA][0][14] = -6, + [1][1][RTW89_CHILE][1][14] = -28, + [1][1][RTW89_QATAR][1][14] = 32, + [1][1][RTW89_QATAR][0][14] = -6, + [1][1][RTW89_UK][1][14] = 32, + [1][1][RTW89_UK][0][14] = -6, + [1][1][RTW89_FCC][1][15] = -28, + [1][1][RTW89_FCC][2][15] = 44, + [1][1][RTW89_ETSI][1][15] = 32, + [1][1][RTW89_ETSI][0][15] = -6, + [1][1][RTW89_MKK][1][15] = 30, + [1][1][RTW89_MKK][0][15] = -10, + [1][1][RTW89_IC][1][15] = -28, + [1][1][RTW89_KCC][1][15] = -14, + [1][1][RTW89_KCC][0][15] = -14, + [1][1][RTW89_ACMA][1][15] = 32, + [1][1][RTW89_ACMA][0][15] = -6, + [1][1][RTW89_CHILE][1][15] = -28, + [1][1][RTW89_QATAR][1][15] = 32, + [1][1][RTW89_QATAR][0][15] = -6, + [1][1][RTW89_UK][1][15] = 32, + [1][1][RTW89_UK][0][15] = -6, + [1][1][RTW89_FCC][1][17] = -28, + [1][1][RTW89_FCC][2][17] = 44, + [1][1][RTW89_ETSI][1][17] = 32, + [1][1][RTW89_ETSI][0][17] = -6, + [1][1][RTW89_MKK][1][17] = 30, + [1][1][RTW89_MKK][0][17] = -10, + [1][1][RTW89_IC][1][17] = -28, + [1][1][RTW89_KCC][1][17] = -14, + [1][1][RTW89_KCC][0][17] = -14, + [1][1][RTW89_ACMA][1][17] = 32, + [1][1][RTW89_ACMA][0][17] = -6, + [1][1][RTW89_CHILE][1][17] = -28, + [1][1][RTW89_QATAR][1][17] = 32, + [1][1][RTW89_QATAR][0][17] = -6, + [1][1][RTW89_UK][1][17] = 32, + [1][1][RTW89_UK][0][17] = -6, + [1][1][RTW89_FCC][1][19] = -28, + [1][1][RTW89_FCC][2][19] = 44, + [1][1][RTW89_ETSI][1][19] = 32, + [1][1][RTW89_ETSI][0][19] = -6, + [1][1][RTW89_MKK][1][19] = 30, + [1][1][RTW89_MKK][0][19] = -10, + [1][1][RTW89_IC][1][19] = -28, + [1][1][RTW89_KCC][1][19] = -14, + [1][1][RTW89_KCC][0][19] = -14, + [1][1][RTW89_ACMA][1][19] = 32, + [1][1][RTW89_ACMA][0][19] = -6, + [1][1][RTW89_CHILE][1][19] = -28, + [1][1][RTW89_QATAR][1][19] = 32, + [1][1][RTW89_QATAR][0][19] = -6, + [1][1][RTW89_UK][1][19] = 32, + [1][1][RTW89_UK][0][19] = -6, + [1][1][RTW89_FCC][1][21] = -28, + [1][1][RTW89_FCC][2][21] = 44, + [1][1][RTW89_ETSI][1][21] = 32, + [1][1][RTW89_ETSI][0][21] = -6, + [1][1][RTW89_MKK][1][21] = 30, + [1][1][RTW89_MKK][0][21] = -10, + [1][1][RTW89_IC][1][21] = -28, + [1][1][RTW89_KCC][1][21] = -14, + [1][1][RTW89_KCC][0][21] = -14, + [1][1][RTW89_ACMA][1][21] = 32, + [1][1][RTW89_ACMA][0][21] = -6, + [1][1][RTW89_CHILE][1][21] = -28, + [1][1][RTW89_QATAR][1][21] = 32, + [1][1][RTW89_QATAR][0][21] = -6, + [1][1][RTW89_UK][1][21] = 32, + [1][1][RTW89_UK][0][21] = -6, + [1][1][RTW89_FCC][1][23] = -28, + [1][1][RTW89_FCC][2][23] = 44, + [1][1][RTW89_ETSI][1][23] = 32, + [1][1][RTW89_ETSI][0][23] = -6, + [1][1][RTW89_MKK][1][23] = 32, + [1][1][RTW89_MKK][0][23] = -10, + [1][1][RTW89_IC][1][23] = -28, + [1][1][RTW89_KCC][1][23] = -14, + [1][1][RTW89_KCC][0][23] = -14, + [1][1][RTW89_ACMA][1][23] = 32, + [1][1][RTW89_ACMA][0][23] = -6, + [1][1][RTW89_CHILE][1][23] = -28, + [1][1][RTW89_QATAR][1][23] = 32, + [1][1][RTW89_QATAR][0][23] = -6, + [1][1][RTW89_UK][1][23] = 32, + [1][1][RTW89_UK][0][23] = -6, + [1][1][RTW89_FCC][1][25] = -28, + [1][1][RTW89_FCC][2][25] = 44, + [1][1][RTW89_ETSI][1][25] = 32, + [1][1][RTW89_ETSI][0][25] = -6, + [1][1][RTW89_MKK][1][25] = 32, + [1][1][RTW89_MKK][0][25] = -10, + [1][1][RTW89_IC][1][25] = -28, + [1][1][RTW89_KCC][1][25] = -14, + [1][1][RTW89_KCC][0][25] = -14, + [1][1][RTW89_ACMA][1][25] = 32, + [1][1][RTW89_ACMA][0][25] = -6, + [1][1][RTW89_CHILE][1][25] = -28, + [1][1][RTW89_QATAR][1][25] = 32, + [1][1][RTW89_QATAR][0][25] = -6, + [1][1][RTW89_UK][1][25] = 32, + [1][1][RTW89_UK][0][25] = -6, + [1][1][RTW89_FCC][1][27] = -28, + [1][1][RTW89_FCC][2][27] = 44, + [1][1][RTW89_ETSI][1][27] = 32, + [1][1][RTW89_ETSI][0][27] = -6, + [1][1][RTW89_MKK][1][27] = 32, + [1][1][RTW89_MKK][0][27] = -10, + [1][1][RTW89_IC][1][27] = -28, + [1][1][RTW89_KCC][1][27] = -14, + [1][1][RTW89_KCC][0][27] = -14, + [1][1][RTW89_ACMA][1][27] = 32, + [1][1][RTW89_ACMA][0][27] = -6, + [1][1][RTW89_CHILE][1][27] = -28, + [1][1][RTW89_QATAR][1][27] = 32, + [1][1][RTW89_QATAR][0][27] = -6, + [1][1][RTW89_UK][1][27] = 32, + [1][1][RTW89_UK][0][27] = -6, + [1][1][RTW89_FCC][1][29] = -28, + [1][1][RTW89_FCC][2][29] = 44, + [1][1][RTW89_ETSI][1][29] = 32, + [1][1][RTW89_ETSI][0][29] = -6, + [1][1][RTW89_MKK][1][29] = 32, + [1][1][RTW89_MKK][0][29] = -10, + [1][1][RTW89_IC][1][29] = -28, + [1][1][RTW89_KCC][1][29] = -14, + [1][1][RTW89_KCC][0][29] = -14, + [1][1][RTW89_ACMA][1][29] = 32, + [1][1][RTW89_ACMA][0][29] = -6, + [1][1][RTW89_CHILE][1][29] = -28, + [1][1][RTW89_QATAR][1][29] = 32, + [1][1][RTW89_QATAR][0][29] = -6, + [1][1][RTW89_UK][1][29] = 32, + [1][1][RTW89_UK][0][29] = -6, + [1][1][RTW89_FCC][1][30] = -28, + [1][1][RTW89_FCC][2][30] = 44, + [1][1][RTW89_ETSI][1][30] = 32, + [1][1][RTW89_ETSI][0][30] = -6, + [1][1][RTW89_MKK][1][30] = 32, + [1][1][RTW89_MKK][0][30] = -10, + [1][1][RTW89_IC][1][30] = -28, + [1][1][RTW89_KCC][1][30] = -14, + [1][1][RTW89_KCC][0][30] = -14, + [1][1][RTW89_ACMA][1][30] = 32, + [1][1][RTW89_ACMA][0][30] = -6, + [1][1][RTW89_CHILE][1][30] = -28, + [1][1][RTW89_QATAR][1][30] = 32, + [1][1][RTW89_QATAR][0][30] = -6, + [1][1][RTW89_UK][1][30] = 32, + [1][1][RTW89_UK][0][30] = -6, + [1][1][RTW89_FCC][1][32] = -28, + [1][1][RTW89_FCC][2][32] = 44, + [1][1][RTW89_ETSI][1][32] = 32, + [1][1][RTW89_ETSI][0][32] = -6, + [1][1][RTW89_MKK][1][32] = 32, + [1][1][RTW89_MKK][0][32] = -10, + [1][1][RTW89_IC][1][32] = -28, + [1][1][RTW89_KCC][1][32] = -14, + [1][1][RTW89_KCC][0][32] = -14, + [1][1][RTW89_ACMA][1][32] = 32, + [1][1][RTW89_ACMA][0][32] = -6, + [1][1][RTW89_CHILE][1][32] = -28, + [1][1][RTW89_QATAR][1][32] = 32, + [1][1][RTW89_QATAR][0][32] = -6, + [1][1][RTW89_UK][1][32] = 32, + [1][1][RTW89_UK][0][32] = -6, + [1][1][RTW89_FCC][1][34] = -28, + [1][1][RTW89_FCC][2][34] = 44, + [1][1][RTW89_ETSI][1][34] = 32, + [1][1][RTW89_ETSI][0][34] = -6, + [1][1][RTW89_MKK][1][34] = 32, + [1][1][RTW89_MKK][0][34] = -10, + [1][1][RTW89_IC][1][34] = -28, + [1][1][RTW89_KCC][1][34] = -14, + [1][1][RTW89_KCC][0][34] = -14, + [1][1][RTW89_ACMA][1][34] = 32, + [1][1][RTW89_ACMA][0][34] = -6, + [1][1][RTW89_CHILE][1][34] = -28, + [1][1][RTW89_QATAR][1][34] = 32, + [1][1][RTW89_QATAR][0][34] = -6, + [1][1][RTW89_UK][1][34] = 32, + [1][1][RTW89_UK][0][34] = -6, + [1][1][RTW89_FCC][1][36] = -28, + [1][1][RTW89_FCC][2][36] = 44, + [1][1][RTW89_ETSI][1][36] = 32, + [1][1][RTW89_ETSI][0][36] = -6, + [1][1][RTW89_MKK][1][36] = 32, + [1][1][RTW89_MKK][0][36] = -10, + [1][1][RTW89_IC][1][36] = -28, + [1][1][RTW89_KCC][1][36] = -14, + [1][1][RTW89_KCC][0][36] = -14, + [1][1][RTW89_ACMA][1][36] = 32, + [1][1][RTW89_ACMA][0][36] = -6, + [1][1][RTW89_CHILE][1][36] = -28, + [1][1][RTW89_QATAR][1][36] = 32, + [1][1][RTW89_QATAR][0][36] = -6, + [1][1][RTW89_UK][1][36] = 32, + [1][1][RTW89_UK][0][36] = -6, + [1][1][RTW89_FCC][1][38] = -28, + [1][1][RTW89_FCC][2][38] = 44, + [1][1][RTW89_ETSI][1][38] = 32, + [1][1][RTW89_ETSI][0][38] = -6, + [1][1][RTW89_MKK][1][38] = 32, + [1][1][RTW89_MKK][0][38] = -10, + [1][1][RTW89_IC][1][38] = -28, + [1][1][RTW89_KCC][1][38] = -14, + [1][1][RTW89_KCC][0][38] = -14, + [1][1][RTW89_ACMA][1][38] = 32, + [1][1][RTW89_ACMA][0][38] = -6, + [1][1][RTW89_CHILE][1][38] = -28, + [1][1][RTW89_QATAR][1][38] = 32, + [1][1][RTW89_QATAR][0][38] = -6, + [1][1][RTW89_UK][1][38] = 32, + [1][1][RTW89_UK][0][38] = -6, + [1][1][RTW89_FCC][1][40] = -28, + [1][1][RTW89_FCC][2][40] = 44, + [1][1][RTW89_ETSI][1][40] = 32, + [1][1][RTW89_ETSI][0][40] = -6, + [1][1][RTW89_MKK][1][40] = 32, + [1][1][RTW89_MKK][0][40] = -10, + [1][1][RTW89_IC][1][40] = -28, + [1][1][RTW89_KCC][1][40] = -14, + [1][1][RTW89_KCC][0][40] = -14, + [1][1][RTW89_ACMA][1][40] = 32, + [1][1][RTW89_ACMA][0][40] = -6, + [1][1][RTW89_CHILE][1][40] = -28, + [1][1][RTW89_QATAR][1][40] = 32, + [1][1][RTW89_QATAR][0][40] = -6, + [1][1][RTW89_UK][1][40] = 32, + [1][1][RTW89_UK][0][40] = -6, + [1][1][RTW89_FCC][1][42] = -28, + [1][1][RTW89_FCC][2][42] = 44, + [1][1][RTW89_ETSI][1][42] = 32, + [1][1][RTW89_ETSI][0][42] = -6, + [1][1][RTW89_MKK][1][42] = 32, + [1][1][RTW89_MKK][0][42] = -10, + [1][1][RTW89_IC][1][42] = -28, + [1][1][RTW89_KCC][1][42] = -14, + [1][1][RTW89_KCC][0][42] = -14, + [1][1][RTW89_ACMA][1][42] = 32, + [1][1][RTW89_ACMA][0][42] = -6, + [1][1][RTW89_CHILE][1][42] = -28, + [1][1][RTW89_QATAR][1][42] = 32, + [1][1][RTW89_QATAR][0][42] = -6, + [1][1][RTW89_UK][1][42] = 32, + [1][1][RTW89_UK][0][42] = -6, + [1][1][RTW89_FCC][1][44] = -28, + [1][1][RTW89_FCC][2][44] = 44, + [1][1][RTW89_ETSI][1][44] = 34, + [1][1][RTW89_ETSI][0][44] = -4, + [1][1][RTW89_MKK][1][44] = 4, + [1][1][RTW89_MKK][0][44] = -8, + [1][1][RTW89_IC][1][44] = -28, + [1][1][RTW89_KCC][1][44] = -14, + [1][1][RTW89_KCC][0][44] = -14, + [1][1][RTW89_ACMA][1][44] = 34, + [1][1][RTW89_ACMA][0][44] = -4, + [1][1][RTW89_CHILE][1][44] = -28, + [1][1][RTW89_QATAR][1][44] = 34, + [1][1][RTW89_QATAR][0][44] = -4, + [1][1][RTW89_UK][1][44] = 34, + [1][1][RTW89_UK][0][44] = -4, + [1][1][RTW89_FCC][1][45] = -26, + [1][1][RTW89_FCC][2][45] = 127, + [1][1][RTW89_ETSI][1][45] = 127, + [1][1][RTW89_ETSI][0][45] = 127, + [1][1][RTW89_MKK][1][45] = 127, + [1][1][RTW89_MKK][0][45] = 127, + [1][1][RTW89_IC][1][45] = -26, + [1][1][RTW89_KCC][1][45] = -14, + [1][1][RTW89_KCC][0][45] = 127, + [1][1][RTW89_ACMA][1][45] = 127, + [1][1][RTW89_ACMA][0][45] = 127, + [1][1][RTW89_CHILE][1][45] = 127, + [1][1][RTW89_QATAR][1][45] = 127, + [1][1][RTW89_QATAR][0][45] = 127, + [1][1][RTW89_UK][1][45] = 127, + [1][1][RTW89_UK][0][45] = 127, + [1][1][RTW89_FCC][1][47] = -28, + [1][1][RTW89_FCC][2][47] = 127, + [1][1][RTW89_ETSI][1][47] = 127, + [1][1][RTW89_ETSI][0][47] = 127, + [1][1][RTW89_MKK][1][47] = 127, + [1][1][RTW89_MKK][0][47] = 127, + [1][1][RTW89_IC][1][47] = -28, + [1][1][RTW89_KCC][1][47] = -14, + [1][1][RTW89_KCC][0][47] = 127, + [1][1][RTW89_ACMA][1][47] = 127, + [1][1][RTW89_ACMA][0][47] = 127, + [1][1][RTW89_CHILE][1][47] = 127, + [1][1][RTW89_QATAR][1][47] = 127, + [1][1][RTW89_QATAR][0][47] = 127, + [1][1][RTW89_UK][1][47] = 127, + [1][1][RTW89_UK][0][47] = 127, + [1][1][RTW89_FCC][1][49] = -28, + [1][1][RTW89_FCC][2][49] = 127, + [1][1][RTW89_ETSI][1][49] = 127, + [1][1][RTW89_ETSI][0][49] = 127, + [1][1][RTW89_MKK][1][49] = 127, + [1][1][RTW89_MKK][0][49] = 127, + [1][1][RTW89_IC][1][49] = -28, + [1][1][RTW89_KCC][1][49] = -14, + [1][1][RTW89_KCC][0][49] = 127, + [1][1][RTW89_ACMA][1][49] = 127, + [1][1][RTW89_ACMA][0][49] = 127, + [1][1][RTW89_CHILE][1][49] = 127, + [1][1][RTW89_QATAR][1][49] = 127, + [1][1][RTW89_QATAR][0][49] = 127, + [1][1][RTW89_UK][1][49] = 127, + [1][1][RTW89_UK][0][49] = 127, + [1][1][RTW89_FCC][1][51] = -28, + [1][1][RTW89_FCC][2][51] = 127, + [1][1][RTW89_ETSI][1][51] = 127, + [1][1][RTW89_ETSI][0][51] = 127, + [1][1][RTW89_MKK][1][51] = 127, + [1][1][RTW89_MKK][0][51] = 127, + [1][1][RTW89_IC][1][51] = -28, + [1][1][RTW89_KCC][1][51] = -14, + [1][1][RTW89_KCC][0][51] = 127, + [1][1][RTW89_ACMA][1][51] = 127, + [1][1][RTW89_ACMA][0][51] = 127, + [1][1][RTW89_CHILE][1][51] = 127, + [1][1][RTW89_QATAR][1][51] = 127, + [1][1][RTW89_QATAR][0][51] = 127, + [1][1][RTW89_UK][1][51] = 127, + [1][1][RTW89_UK][0][51] = 127, + [1][1][RTW89_FCC][1][53] = -26, + [1][1][RTW89_FCC][2][53] = 127, + [1][1][RTW89_ETSI][1][53] = 127, + [1][1][RTW89_ETSI][0][53] = 127, + [1][1][RTW89_MKK][1][53] = 127, + [1][1][RTW89_MKK][0][53] = 127, + [1][1][RTW89_IC][1][53] = -26, + [1][1][RTW89_KCC][1][53] = -14, + [1][1][RTW89_KCC][0][53] = 127, + [1][1][RTW89_ACMA][1][53] = 127, + [1][1][RTW89_ACMA][0][53] = 127, + [1][1][RTW89_CHILE][1][53] = 127, + [1][1][RTW89_QATAR][1][53] = 127, + [1][1][RTW89_QATAR][0][53] = 127, + [1][1][RTW89_UK][1][53] = 127, + [1][1][RTW89_UK][0][53] = 127, + [1][1][RTW89_FCC][1][55] = -28, + [1][1][RTW89_FCC][2][55] = 44, + [1][1][RTW89_ETSI][1][55] = 127, + [1][1][RTW89_ETSI][0][55] = 127, + [1][1][RTW89_MKK][1][55] = 127, + [1][1][RTW89_MKK][0][55] = 127, + [1][1][RTW89_IC][1][55] = -28, + [1][1][RTW89_KCC][1][55] = -14, + [1][1][RTW89_KCC][0][55] = 127, + [1][1][RTW89_ACMA][1][55] = 127, + [1][1][RTW89_ACMA][0][55] = 127, + [1][1][RTW89_CHILE][1][55] = 127, + [1][1][RTW89_QATAR][1][55] = 127, + [1][1][RTW89_QATAR][0][55] = 127, + [1][1][RTW89_UK][1][55] = 127, + [1][1][RTW89_UK][0][55] = 127, + [1][1][RTW89_FCC][1][57] = -28, + [1][1][RTW89_FCC][2][57] = 44, + [1][1][RTW89_ETSI][1][57] = 127, + [1][1][RTW89_ETSI][0][57] = 127, + [1][1][RTW89_MKK][1][57] = 127, + [1][1][RTW89_MKK][0][57] = 127, + [1][1][RTW89_IC][1][57] = -28, + [1][1][RTW89_KCC][1][57] = -14, + [1][1][RTW89_KCC][0][57] = 127, + [1][1][RTW89_ACMA][1][57] = 127, + [1][1][RTW89_ACMA][0][57] = 127, + [1][1][RTW89_CHILE][1][57] = 127, + [1][1][RTW89_QATAR][1][57] = 127, + [1][1][RTW89_QATAR][0][57] = 127, + [1][1][RTW89_UK][1][57] = 127, + [1][1][RTW89_UK][0][57] = 127, + [1][1][RTW89_FCC][1][59] = -28, + [1][1][RTW89_FCC][2][59] = 44, + [1][1][RTW89_ETSI][1][59] = 127, + [1][1][RTW89_ETSI][0][59] = 127, + [1][1][RTW89_MKK][1][59] = 127, + [1][1][RTW89_MKK][0][59] = 127, + [1][1][RTW89_IC][1][59] = -28, + [1][1][RTW89_KCC][1][59] = -14, + [1][1][RTW89_KCC][0][59] = 127, + [1][1][RTW89_ACMA][1][59] = 127, + [1][1][RTW89_ACMA][0][59] = 127, + [1][1][RTW89_CHILE][1][59] = 127, + [1][1][RTW89_QATAR][1][59] = 127, + [1][1][RTW89_QATAR][0][59] = 127, + [1][1][RTW89_UK][1][59] = 127, + [1][1][RTW89_UK][0][59] = 127, + [1][1][RTW89_FCC][1][60] = -28, + [1][1][RTW89_FCC][2][60] = 44, + [1][1][RTW89_ETSI][1][60] = 127, + [1][1][RTW89_ETSI][0][60] = 127, + [1][1][RTW89_MKK][1][60] = 127, + [1][1][RTW89_MKK][0][60] = 127, + [1][1][RTW89_IC][1][60] = -28, + [1][1][RTW89_KCC][1][60] = -14, + [1][1][RTW89_KCC][0][60] = 127, + [1][1][RTW89_ACMA][1][60] = 127, + [1][1][RTW89_ACMA][0][60] = 127, + [1][1][RTW89_CHILE][1][60] = 127, + [1][1][RTW89_QATAR][1][60] = 127, + [1][1][RTW89_QATAR][0][60] = 127, + [1][1][RTW89_UK][1][60] = 127, + [1][1][RTW89_UK][0][60] = 127, + [1][1][RTW89_FCC][1][62] = -28, + [1][1][RTW89_FCC][2][62] = 44, + [1][1][RTW89_ETSI][1][62] = 127, + [1][1][RTW89_ETSI][0][62] = 127, + [1][1][RTW89_MKK][1][62] = 127, + [1][1][RTW89_MKK][0][62] = 127, + [1][1][RTW89_IC][1][62] = -28, + [1][1][RTW89_KCC][1][62] = -14, + [1][1][RTW89_KCC][0][62] = 127, + [1][1][RTW89_ACMA][1][62] = 127, + [1][1][RTW89_ACMA][0][62] = 127, + [1][1][RTW89_CHILE][1][62] = 127, + [1][1][RTW89_QATAR][1][62] = 127, + [1][1][RTW89_QATAR][0][62] = 127, + [1][1][RTW89_UK][1][62] = 127, + [1][1][RTW89_UK][0][62] = 127, + [1][1][RTW89_FCC][1][64] = -28, + [1][1][RTW89_FCC][2][64] = 44, + [1][1][RTW89_ETSI][1][64] = 127, + [1][1][RTW89_ETSI][0][64] = 127, + [1][1][RTW89_MKK][1][64] = 127, + [1][1][RTW89_MKK][0][64] = 127, + [1][1][RTW89_IC][1][64] = -28, + [1][1][RTW89_KCC][1][64] = -14, + [1][1][RTW89_KCC][0][64] = 127, + [1][1][RTW89_ACMA][1][64] = 127, + [1][1][RTW89_ACMA][0][64] = 127, + [1][1][RTW89_CHILE][1][64] = 127, + [1][1][RTW89_QATAR][1][64] = 127, + [1][1][RTW89_QATAR][0][64] = 127, + [1][1][RTW89_UK][1][64] = 127, + [1][1][RTW89_UK][0][64] = 127, + [1][1][RTW89_FCC][1][66] = -28, + [1][1][RTW89_FCC][2][66] = 44, + [1][1][RTW89_ETSI][1][66] = 127, + [1][1][RTW89_ETSI][0][66] = 127, + [1][1][RTW89_MKK][1][66] = 127, + [1][1][RTW89_MKK][0][66] = 127, + [1][1][RTW89_IC][1][66] = -28, + [1][1][RTW89_KCC][1][66] = -14, + [1][1][RTW89_KCC][0][66] = 127, + [1][1][RTW89_ACMA][1][66] = 127, + [1][1][RTW89_ACMA][0][66] = 127, + [1][1][RTW89_CHILE][1][66] = 127, + [1][1][RTW89_QATAR][1][66] = 127, + [1][1][RTW89_QATAR][0][66] = 127, + [1][1][RTW89_UK][1][66] = 127, + [1][1][RTW89_UK][0][66] = 127, + [1][1][RTW89_FCC][1][68] = -28, + [1][1][RTW89_FCC][2][68] = 44, + [1][1][RTW89_ETSI][1][68] = 127, + [1][1][RTW89_ETSI][0][68] = 127, + [1][1][RTW89_MKK][1][68] = 127, + [1][1][RTW89_MKK][0][68] = 127, + [1][1][RTW89_IC][1][68] = -28, + [1][1][RTW89_KCC][1][68] = -14, + [1][1][RTW89_KCC][0][68] = 127, + [1][1][RTW89_ACMA][1][68] = 127, + [1][1][RTW89_ACMA][0][68] = 127, + [1][1][RTW89_CHILE][1][68] = 127, + [1][1][RTW89_QATAR][1][68] = 127, + [1][1][RTW89_QATAR][0][68] = 127, + [1][1][RTW89_UK][1][68] = 127, + [1][1][RTW89_UK][0][68] = 127, + [1][1][RTW89_FCC][1][70] = -26, + [1][1][RTW89_FCC][2][70] = 44, + [1][1][RTW89_ETSI][1][70] = 127, + [1][1][RTW89_ETSI][0][70] = 127, + [1][1][RTW89_MKK][1][70] = 127, + [1][1][RTW89_MKK][0][70] = 127, + [1][1][RTW89_IC][1][70] = -26, + [1][1][RTW89_KCC][1][70] = -14, + [1][1][RTW89_KCC][0][70] = 127, + [1][1][RTW89_ACMA][1][70] = 127, + [1][1][RTW89_ACMA][0][70] = 127, + [1][1][RTW89_CHILE][1][70] = 127, + [1][1][RTW89_QATAR][1][70] = 127, + [1][1][RTW89_QATAR][0][70] = 127, + [1][1][RTW89_UK][1][70] = 127, + [1][1][RTW89_UK][0][70] = 127, + [1][1][RTW89_FCC][1][72] = -28, + [1][1][RTW89_FCC][2][72] = 44, + [1][1][RTW89_ETSI][1][72] = 127, + [1][1][RTW89_ETSI][0][72] = 127, + [1][1][RTW89_MKK][1][72] = 127, + [1][1][RTW89_MKK][0][72] = 127, + [1][1][RTW89_IC][1][72] = -28, + [1][1][RTW89_KCC][1][72] = -14, + [1][1][RTW89_KCC][0][72] = 127, + [1][1][RTW89_ACMA][1][72] = 127, + [1][1][RTW89_ACMA][0][72] = 127, + [1][1][RTW89_CHILE][1][72] = 127, + [1][1][RTW89_QATAR][1][72] = 127, + [1][1][RTW89_QATAR][0][72] = 127, + [1][1][RTW89_UK][1][72] = 127, + [1][1][RTW89_UK][0][72] = 127, + [1][1][RTW89_FCC][1][74] = -28, + [1][1][RTW89_FCC][2][74] = 44, + [1][1][RTW89_ETSI][1][74] = 127, + [1][1][RTW89_ETSI][0][74] = 127, + [1][1][RTW89_MKK][1][74] = 127, + [1][1][RTW89_MKK][0][74] = 127, + [1][1][RTW89_IC][1][74] = -28, + [1][1][RTW89_KCC][1][74] = -14, + [1][1][RTW89_KCC][0][74] = 127, + [1][1][RTW89_ACMA][1][74] = 127, + [1][1][RTW89_ACMA][0][74] = 127, + [1][1][RTW89_CHILE][1][74] = 127, + [1][1][RTW89_QATAR][1][74] = 127, + [1][1][RTW89_QATAR][0][74] = 127, + [1][1][RTW89_UK][1][74] = 127, + [1][1][RTW89_UK][0][74] = 127, + [1][1][RTW89_FCC][1][75] = -28, + [1][1][RTW89_FCC][2][75] = 44, + [1][1][RTW89_ETSI][1][75] = 127, + [1][1][RTW89_ETSI][0][75] = 127, + [1][1][RTW89_MKK][1][75] = 127, + [1][1][RTW89_MKK][0][75] = 127, + [1][1][RTW89_IC][1][75] = -28, + [1][1][RTW89_KCC][1][75] = -14, + [1][1][RTW89_KCC][0][75] = 127, + [1][1][RTW89_ACMA][1][75] = 127, + [1][1][RTW89_ACMA][0][75] = 127, + [1][1][RTW89_CHILE][1][75] = 127, + [1][1][RTW89_QATAR][1][75] = 127, + [1][1][RTW89_QATAR][0][75] = 127, + [1][1][RTW89_UK][1][75] = 127, + [1][1][RTW89_UK][0][75] = 127, + [1][1][RTW89_FCC][1][77] = -28, + [1][1][RTW89_FCC][2][77] = 44, + [1][1][RTW89_ETSI][1][77] = 127, + [1][1][RTW89_ETSI][0][77] = 127, + [1][1][RTW89_MKK][1][77] = 127, + [1][1][RTW89_MKK][0][77] = 127, + [1][1][RTW89_IC][1][77] = -28, + [1][1][RTW89_KCC][1][77] = -14, + [1][1][RTW89_KCC][0][77] = 127, + [1][1][RTW89_ACMA][1][77] = 127, + [1][1][RTW89_ACMA][0][77] = 127, + [1][1][RTW89_CHILE][1][77] = 127, + [1][1][RTW89_QATAR][1][77] = 127, + [1][1][RTW89_QATAR][0][77] = 127, + [1][1][RTW89_UK][1][77] = 127, + [1][1][RTW89_UK][0][77] = 127, + [1][1][RTW89_FCC][1][79] = -28, + [1][1][RTW89_FCC][2][79] = 44, + [1][1][RTW89_ETSI][1][79] = 127, + [1][1][RTW89_ETSI][0][79] = 127, + [1][1][RTW89_MKK][1][79] = 127, + [1][1][RTW89_MKK][0][79] = 127, + [1][1][RTW89_IC][1][79] = -28, + [1][1][RTW89_KCC][1][79] = -14, + [1][1][RTW89_KCC][0][79] = 127, + [1][1][RTW89_ACMA][1][79] = 127, + [1][1][RTW89_ACMA][0][79] = 127, + [1][1][RTW89_CHILE][1][79] = 127, + [1][1][RTW89_QATAR][1][79] = 127, + [1][1][RTW89_QATAR][0][79] = 127, + [1][1][RTW89_UK][1][79] = 127, + [1][1][RTW89_UK][0][79] = 127, + [1][1][RTW89_FCC][1][81] = -28, + [1][1][RTW89_FCC][2][81] = 44, + [1][1][RTW89_ETSI][1][81] = 127, + [1][1][RTW89_ETSI][0][81] = 127, + [1][1][RTW89_MKK][1][81] = 127, + [1][1][RTW89_MKK][0][81] = 127, + [1][1][RTW89_IC][1][81] = -28, + [1][1][RTW89_KCC][1][81] = -14, + [1][1][RTW89_KCC][0][81] = 127, + [1][1][RTW89_ACMA][1][81] = 127, + [1][1][RTW89_ACMA][0][81] = 127, + [1][1][RTW89_CHILE][1][81] = 127, + [1][1][RTW89_QATAR][1][81] = 127, + [1][1][RTW89_QATAR][0][81] = 127, + [1][1][RTW89_UK][1][81] = 127, + [1][1][RTW89_UK][0][81] = 127, + [1][1][RTW89_FCC][1][83] = -28, + [1][1][RTW89_FCC][2][83] = 44, + [1][1][RTW89_ETSI][1][83] = 127, + [1][1][RTW89_ETSI][0][83] = 127, + [1][1][RTW89_MKK][1][83] = 127, + [1][1][RTW89_MKK][0][83] = 127, + [1][1][RTW89_IC][1][83] = -28, + [1][1][RTW89_KCC][1][83] = -14, + [1][1][RTW89_KCC][0][83] = 127, + [1][1][RTW89_ACMA][1][83] = 127, + [1][1][RTW89_ACMA][0][83] = 127, + [1][1][RTW89_CHILE][1][83] = 127, + [1][1][RTW89_QATAR][1][83] = 127, + [1][1][RTW89_QATAR][0][83] = 127, + [1][1][RTW89_UK][1][83] = 127, + [1][1][RTW89_UK][0][83] = 127, + [1][1][RTW89_FCC][1][85] = -28, + [1][1][RTW89_FCC][2][85] = 44, + [1][1][RTW89_ETSI][1][85] = 127, + [1][1][RTW89_ETSI][0][85] = 127, + [1][1][RTW89_MKK][1][85] = 127, + [1][1][RTW89_MKK][0][85] = 127, + [1][1][RTW89_IC][1][85] = -28, + [1][1][RTW89_KCC][1][85] = -14, + [1][1][RTW89_KCC][0][85] = 127, + [1][1][RTW89_ACMA][1][85] = 127, + [1][1][RTW89_ACMA][0][85] = 127, + [1][1][RTW89_CHILE][1][85] = 127, + [1][1][RTW89_QATAR][1][85] = 127, + [1][1][RTW89_QATAR][0][85] = 127, + [1][1][RTW89_UK][1][85] = 127, + [1][1][RTW89_UK][0][85] = 127, + [1][1][RTW89_FCC][1][87] = -28, + [1][1][RTW89_FCC][2][87] = 127, + [1][1][RTW89_ETSI][1][87] = 127, + [1][1][RTW89_ETSI][0][87] = 127, + [1][1][RTW89_MKK][1][87] = 127, + [1][1][RTW89_MKK][0][87] = 127, + [1][1][RTW89_IC][1][87] = -28, + [1][1][RTW89_KCC][1][87] = -14, + [1][1][RTW89_KCC][0][87] = 127, + [1][1][RTW89_ACMA][1][87] = 127, + [1][1][RTW89_ACMA][0][87] = 127, + [1][1][RTW89_CHILE][1][87] = 127, + [1][1][RTW89_QATAR][1][87] = 127, + [1][1][RTW89_QATAR][0][87] = 127, + [1][1][RTW89_UK][1][87] = 127, + [1][1][RTW89_UK][0][87] = 127, + [1][1][RTW89_FCC][1][89] = -26, + [1][1][RTW89_FCC][2][89] = 127, + [1][1][RTW89_ETSI][1][89] = 127, + [1][1][RTW89_ETSI][0][89] = 127, + [1][1][RTW89_MKK][1][89] = 127, + [1][1][RTW89_MKK][0][89] = 127, + [1][1][RTW89_IC][1][89] = -26, + [1][1][RTW89_KCC][1][89] = -14, + [1][1][RTW89_KCC][0][89] = 127, + [1][1][RTW89_ACMA][1][89] = 127, + [1][1][RTW89_ACMA][0][89] = 127, + [1][1][RTW89_CHILE][1][89] = 127, + [1][1][RTW89_QATAR][1][89] = 127, + [1][1][RTW89_QATAR][0][89] = 127, + [1][1][RTW89_UK][1][89] = 127, + [1][1][RTW89_UK][0][89] = 127, + [1][1][RTW89_FCC][1][90] = -26, + [1][1][RTW89_FCC][2][90] = 127, + [1][1][RTW89_ETSI][1][90] = 127, + [1][1][RTW89_ETSI][0][90] = 127, + [1][1][RTW89_MKK][1][90] = 127, + [1][1][RTW89_MKK][0][90] = 127, + [1][1][RTW89_IC][1][90] = -26, + [1][1][RTW89_KCC][1][90] = -14, + [1][1][RTW89_KCC][0][90] = 127, + [1][1][RTW89_ACMA][1][90] = 127, + [1][1][RTW89_ACMA][0][90] = 127, + [1][1][RTW89_CHILE][1][90] = 127, + [1][1][RTW89_QATAR][1][90] = 127, + [1][1][RTW89_QATAR][0][90] = 127, + [1][1][RTW89_UK][1][90] = 127, + [1][1][RTW89_UK][0][90] = 127, + [1][1][RTW89_FCC][1][92] = -26, + [1][1][RTW89_FCC][2][92] = 127, + [1][1][RTW89_ETSI][1][92] = 127, + [1][1][RTW89_ETSI][0][92] = 127, + [1][1][RTW89_MKK][1][92] = 127, + [1][1][RTW89_MKK][0][92] = 127, + [1][1][RTW89_IC][1][92] = -26, + [1][1][RTW89_KCC][1][92] = -14, + [1][1][RTW89_KCC][0][92] = 127, + [1][1][RTW89_ACMA][1][92] = 127, + [1][1][RTW89_ACMA][0][92] = 127, + [1][1][RTW89_CHILE][1][92] = 127, + [1][1][RTW89_QATAR][1][92] = 127, + [1][1][RTW89_QATAR][0][92] = 127, + [1][1][RTW89_UK][1][92] = 127, + [1][1][RTW89_UK][0][92] = 127, + [1][1][RTW89_FCC][1][94] = -26, + [1][1][RTW89_FCC][2][94] = 127, + [1][1][RTW89_ETSI][1][94] = 127, + [1][1][RTW89_ETSI][0][94] = 127, + [1][1][RTW89_MKK][1][94] = 127, + [1][1][RTW89_MKK][0][94] = 127, + [1][1][RTW89_IC][1][94] = -26, + [1][1][RTW89_KCC][1][94] = -14, + [1][1][RTW89_KCC][0][94] = 127, + [1][1][RTW89_ACMA][1][94] = 127, + [1][1][RTW89_ACMA][0][94] = 127, + [1][1][RTW89_CHILE][1][94] = 127, + [1][1][RTW89_QATAR][1][94] = 127, + [1][1][RTW89_QATAR][0][94] = 127, + [1][1][RTW89_UK][1][94] = 127, + [1][1][RTW89_UK][0][94] = 127, + [1][1][RTW89_FCC][1][96] = -26, + [1][1][RTW89_FCC][2][96] = 127, + [1][1][RTW89_ETSI][1][96] = 127, + [1][1][RTW89_ETSI][0][96] = 127, + [1][1][RTW89_MKK][1][96] = 127, + [1][1][RTW89_MKK][0][96] = 127, + [1][1][RTW89_IC][1][96] = -26, + [1][1][RTW89_KCC][1][96] = -14, + [1][1][RTW89_KCC][0][96] = 127, + [1][1][RTW89_ACMA][1][96] = 127, + [1][1][RTW89_ACMA][0][96] = 127, + [1][1][RTW89_CHILE][1][96] = 127, + [1][1][RTW89_QATAR][1][96] = 127, + [1][1][RTW89_QATAR][0][96] = 127, + [1][1][RTW89_UK][1][96] = 127, + [1][1][RTW89_UK][0][96] = 127, + [1][1][RTW89_FCC][1][98] = -26, + [1][1][RTW89_FCC][2][98] = 127, + [1][1][RTW89_ETSI][1][98] = 127, + [1][1][RTW89_ETSI][0][98] = 127, + [1][1][RTW89_MKK][1][98] = 127, + [1][1][RTW89_MKK][0][98] = 127, + [1][1][RTW89_IC][1][98] = -26, + [1][1][RTW89_KCC][1][98] = -14, + [1][1][RTW89_KCC][0][98] = 127, + [1][1][RTW89_ACMA][1][98] = 127, + [1][1][RTW89_ACMA][0][98] = 127, + [1][1][RTW89_CHILE][1][98] = 127, + [1][1][RTW89_QATAR][1][98] = 127, + [1][1][RTW89_QATAR][0][98] = 127, + [1][1][RTW89_UK][1][98] = 127, + [1][1][RTW89_UK][0][98] = 127, + [1][1][RTW89_FCC][1][100] = -26, + [1][1][RTW89_FCC][2][100] = 127, + [1][1][RTW89_ETSI][1][100] = 127, + [1][1][RTW89_ETSI][0][100] = 127, + [1][1][RTW89_MKK][1][100] = 127, + [1][1][RTW89_MKK][0][100] = 127, + [1][1][RTW89_IC][1][100] = -26, + [1][1][RTW89_KCC][1][100] = -14, + [1][1][RTW89_KCC][0][100] = 127, + [1][1][RTW89_ACMA][1][100] = 127, + [1][1][RTW89_ACMA][0][100] = 127, + [1][1][RTW89_CHILE][1][100] = 127, + [1][1][RTW89_QATAR][1][100] = 127, + [1][1][RTW89_QATAR][0][100] = 127, + [1][1][RTW89_UK][1][100] = 127, + [1][1][RTW89_UK][0][100] = 127, + [1][1][RTW89_FCC][1][102] = -26, + [1][1][RTW89_FCC][2][102] = 127, + [1][1][RTW89_ETSI][1][102] = 127, + [1][1][RTW89_ETSI][0][102] = 127, + [1][1][RTW89_MKK][1][102] = 127, + [1][1][RTW89_MKK][0][102] = 127, + [1][1][RTW89_IC][1][102] = -26, + [1][1][RTW89_KCC][1][102] = -14, + [1][1][RTW89_KCC][0][102] = 127, + [1][1][RTW89_ACMA][1][102] = 127, + [1][1][RTW89_ACMA][0][102] = 127, + [1][1][RTW89_CHILE][1][102] = 127, + [1][1][RTW89_QATAR][1][102] = 127, + [1][1][RTW89_QATAR][0][102] = 127, + [1][1][RTW89_UK][1][102] = 127, + [1][1][RTW89_UK][0][102] = 127, + [1][1][RTW89_FCC][1][104] = -26, + [1][1][RTW89_FCC][2][104] = 127, + [1][1][RTW89_ETSI][1][104] = 127, + [1][1][RTW89_ETSI][0][104] = 127, + [1][1][RTW89_MKK][1][104] = 127, + [1][1][RTW89_MKK][0][104] = 127, + [1][1][RTW89_IC][1][104] = -26, + [1][1][RTW89_KCC][1][104] = -14, + [1][1][RTW89_KCC][0][104] = 127, + [1][1][RTW89_ACMA][1][104] = 127, + [1][1][RTW89_ACMA][0][104] = 127, + [1][1][RTW89_CHILE][1][104] = 127, + [1][1][RTW89_QATAR][1][104] = 127, + [1][1][RTW89_QATAR][0][104] = 127, + [1][1][RTW89_UK][1][104] = 127, + [1][1][RTW89_UK][0][104] = 127, + [1][1][RTW89_FCC][1][105] = -26, + [1][1][RTW89_FCC][2][105] = 127, + [1][1][RTW89_ETSI][1][105] = 127, + [1][1][RTW89_ETSI][0][105] = 127, + [1][1][RTW89_MKK][1][105] = 127, + [1][1][RTW89_MKK][0][105] = 127, + [1][1][RTW89_IC][1][105] = -26, + [1][1][RTW89_KCC][1][105] = -14, + [1][1][RTW89_KCC][0][105] = 127, + [1][1][RTW89_ACMA][1][105] = 127, + [1][1][RTW89_ACMA][0][105] = 127, + [1][1][RTW89_CHILE][1][105] = 127, + [1][1][RTW89_QATAR][1][105] = 127, + [1][1][RTW89_QATAR][0][105] = 127, + [1][1][RTW89_UK][1][105] = 127, + [1][1][RTW89_UK][0][105] = 127, + [1][1][RTW89_FCC][1][107] = -22, + [1][1][RTW89_FCC][2][107] = 127, + [1][1][RTW89_ETSI][1][107] = 127, + [1][1][RTW89_ETSI][0][107] = 127, + [1][1][RTW89_MKK][1][107] = 127, + [1][1][RTW89_MKK][0][107] = 127, + [1][1][RTW89_IC][1][107] = -22, + [1][1][RTW89_KCC][1][107] = -14, + [1][1][RTW89_KCC][0][107] = 127, + [1][1][RTW89_ACMA][1][107] = 127, + [1][1][RTW89_ACMA][0][107] = 127, + [1][1][RTW89_CHILE][1][107] = 127, + [1][1][RTW89_QATAR][1][107] = 127, + [1][1][RTW89_QATAR][0][107] = 127, + [1][1][RTW89_UK][1][107] = 127, + [1][1][RTW89_UK][0][107] = 127, + [1][1][RTW89_FCC][1][109] = -22, + [1][1][RTW89_FCC][2][109] = 127, + [1][1][RTW89_ETSI][1][109] = 127, + [1][1][RTW89_ETSI][0][109] = 127, + [1][1][RTW89_MKK][1][109] = 127, + [1][1][RTW89_MKK][0][109] = 127, + [1][1][RTW89_IC][1][109] = -22, + [1][1][RTW89_KCC][1][109] = 127, + [1][1][RTW89_KCC][0][109] = 127, + [1][1][RTW89_ACMA][1][109] = 127, + [1][1][RTW89_ACMA][0][109] = 127, + [1][1][RTW89_CHILE][1][109] = 127, + [1][1][RTW89_QATAR][1][109] = 127, + [1][1][RTW89_QATAR][0][109] = 127, + [1][1][RTW89_UK][1][109] = 127, + [1][1][RTW89_UK][0][109] = 127, + [1][1][RTW89_FCC][1][111] = 127, + [1][1][RTW89_FCC][2][111] = 127, + [1][1][RTW89_ETSI][1][111] = 127, + [1][1][RTW89_ETSI][0][111] = 127, + [1][1][RTW89_MKK][1][111] = 127, + [1][1][RTW89_MKK][0][111] = 127, + [1][1][RTW89_IC][1][111] = 127, + [1][1][RTW89_KCC][1][111] = 127, + [1][1][RTW89_KCC][0][111] = 127, + [1][1][RTW89_ACMA][1][111] = 127, + [1][1][RTW89_ACMA][0][111] = 127, + [1][1][RTW89_CHILE][1][111] = 127, + [1][1][RTW89_QATAR][1][111] = 127, + [1][1][RTW89_QATAR][0][111] = 127, + [1][1][RTW89_UK][1][111] = 127, + [1][1][RTW89_UK][0][111] = 127, + [1][1][RTW89_FCC][1][113] = 127, + [1][1][RTW89_FCC][2][113] = 127, + [1][1][RTW89_ETSI][1][113] = 127, + [1][1][RTW89_ETSI][0][113] = 127, + [1][1][RTW89_MKK][1][113] = 127, + [1][1][RTW89_MKK][0][113] = 127, + [1][1][RTW89_IC][1][113] = 127, + [1][1][RTW89_KCC][1][113] = 127, + [1][1][RTW89_KCC][0][113] = 127, + [1][1][RTW89_ACMA][1][113] = 127, + [1][1][RTW89_ACMA][0][113] = 127, + [1][1][RTW89_CHILE][1][113] = 127, + [1][1][RTW89_QATAR][1][113] = 127, + [1][1][RTW89_QATAR][0][113] = 127, + [1][1][RTW89_UK][1][113] = 127, + [1][1][RTW89_UK][0][113] = 127, + [1][1][RTW89_FCC][1][115] = 127, + [1][1][RTW89_FCC][2][115] = 127, + [1][1][RTW89_ETSI][1][115] = 127, + [1][1][RTW89_ETSI][0][115] = 127, + [1][1][RTW89_MKK][1][115] = 127, + [1][1][RTW89_MKK][0][115] = 127, + [1][1][RTW89_IC][1][115] = 127, + [1][1][RTW89_KCC][1][115] = 127, + [1][1][RTW89_KCC][0][115] = 127, + [1][1][RTW89_ACMA][1][115] = 127, + [1][1][RTW89_ACMA][0][115] = 127, + [1][1][RTW89_CHILE][1][115] = 127, + [1][1][RTW89_QATAR][1][115] = 127, + [1][1][RTW89_QATAR][0][115] = 127, + [1][1][RTW89_UK][1][115] = 127, + [1][1][RTW89_UK][0][115] = 127, + [1][1][RTW89_FCC][1][117] = 127, + [1][1][RTW89_FCC][2][117] = 127, + [1][1][RTW89_ETSI][1][117] = 127, + [1][1][RTW89_ETSI][0][117] = 127, + [1][1][RTW89_MKK][1][117] = 127, + [1][1][RTW89_MKK][0][117] = 127, + [1][1][RTW89_IC][1][117] = 127, + [1][1][RTW89_KCC][1][117] = 127, + [1][1][RTW89_KCC][0][117] = 127, + [1][1][RTW89_ACMA][1][117] = 127, + [1][1][RTW89_ACMA][0][117] = 127, + [1][1][RTW89_CHILE][1][117] = 127, + [1][1][RTW89_QATAR][1][117] = 127, + [1][1][RTW89_QATAR][0][117] = 127, + [1][1][RTW89_UK][1][117] = 127, + [1][1][RTW89_UK][0][117] = 127, + [1][1][RTW89_FCC][1][119] = 127, + [1][1][RTW89_FCC][2][119] = 127, + [1][1][RTW89_ETSI][1][119] = 127, + [1][1][RTW89_ETSI][0][119] = 127, + [1][1][RTW89_MKK][1][119] = 127, + [1][1][RTW89_MKK][0][119] = 127, + [1][1][RTW89_IC][1][119] = 127, + [1][1][RTW89_KCC][1][119] = 127, + [1][1][RTW89_KCC][0][119] = 127, + [1][1][RTW89_ACMA][1][119] = 127, + [1][1][RTW89_ACMA][0][119] = 127, + [1][1][RTW89_CHILE][1][119] = 127, + [1][1][RTW89_QATAR][1][119] = 127, + [1][1][RTW89_QATAR][0][119] = 127, + [1][1][RTW89_UK][1][119] = 127, + [1][1][RTW89_UK][0][119] = 127, + [2][0][RTW89_FCC][1][0] = 8, + [2][0][RTW89_FCC][2][0] = 60, + [2][0][RTW89_ETSI][1][0] = 56, + [2][0][RTW89_ETSI][0][0] = 18, + [2][0][RTW89_MKK][1][0] = 54, + [2][0][RTW89_MKK][0][0] = 14, + [2][0][RTW89_IC][1][0] = 8, + [2][0][RTW89_KCC][1][0] = -2, + [2][0][RTW89_KCC][0][0] = -2, + [2][0][RTW89_ACMA][1][0] = 56, + [2][0][RTW89_ACMA][0][0] = 18, + [2][0][RTW89_CHILE][1][0] = 8, + [2][0][RTW89_QATAR][1][0] = 56, + [2][0][RTW89_QATAR][0][0] = 18, + [2][0][RTW89_UK][1][0] = 56, + [2][0][RTW89_UK][0][0] = 18, + [2][0][RTW89_FCC][1][2] = 8, + [2][0][RTW89_FCC][2][2] = 60, + [2][0][RTW89_ETSI][1][2] = 56, + [2][0][RTW89_ETSI][0][2] = 18, + [2][0][RTW89_MKK][1][2] = 54, + [2][0][RTW89_MKK][0][2] = 14, + [2][0][RTW89_IC][1][2] = 8, + [2][0][RTW89_KCC][1][2] = -2, + [2][0][RTW89_KCC][0][2] = -2, + [2][0][RTW89_ACMA][1][2] = 56, + [2][0][RTW89_ACMA][0][2] = 18, + [2][0][RTW89_CHILE][1][2] = 8, + [2][0][RTW89_QATAR][1][2] = 56, + [2][0][RTW89_QATAR][0][2] = 18, + [2][0][RTW89_UK][1][2] = 56, + [2][0][RTW89_UK][0][2] = 18, + [2][0][RTW89_FCC][1][4] = 8, + [2][0][RTW89_FCC][2][4] = 60, + [2][0][RTW89_ETSI][1][4] = 56, + [2][0][RTW89_ETSI][0][4] = 18, + [2][0][RTW89_MKK][1][4] = 54, + [2][0][RTW89_MKK][0][4] = 14, + [2][0][RTW89_IC][1][4] = 8, + [2][0][RTW89_KCC][1][4] = -2, + [2][0][RTW89_KCC][0][4] = -2, + [2][0][RTW89_ACMA][1][4] = 56, + [2][0][RTW89_ACMA][0][4] = 18, + [2][0][RTW89_CHILE][1][4] = 8, + [2][0][RTW89_QATAR][1][4] = 56, + [2][0][RTW89_QATAR][0][4] = 18, + [2][0][RTW89_UK][1][4] = 56, + [2][0][RTW89_UK][0][4] = 18, + [2][0][RTW89_FCC][1][6] = 8, + [2][0][RTW89_FCC][2][6] = 60, + [2][0][RTW89_ETSI][1][6] = 56, + [2][0][RTW89_ETSI][0][6] = 18, + [2][0][RTW89_MKK][1][6] = 54, + [2][0][RTW89_MKK][0][6] = 14, + [2][0][RTW89_IC][1][6] = 8, + [2][0][RTW89_KCC][1][6] = -2, + [2][0][RTW89_KCC][0][6] = -2, + [2][0][RTW89_ACMA][1][6] = 56, + [2][0][RTW89_ACMA][0][6] = 18, + [2][0][RTW89_CHILE][1][6] = 8, + [2][0][RTW89_QATAR][1][6] = 56, + [2][0][RTW89_QATAR][0][6] = 18, + [2][0][RTW89_UK][1][6] = 56, + [2][0][RTW89_UK][0][6] = 18, + [2][0][RTW89_FCC][1][8] = 8, + [2][0][RTW89_FCC][2][8] = 60, + [2][0][RTW89_ETSI][1][8] = 56, + [2][0][RTW89_ETSI][0][8] = 18, + [2][0][RTW89_MKK][1][8] = 54, + [2][0][RTW89_MKK][0][8] = 14, + [2][0][RTW89_IC][1][8] = 8, + [2][0][RTW89_KCC][1][8] = -2, + [2][0][RTW89_KCC][0][8] = -2, + [2][0][RTW89_ACMA][1][8] = 56, + [2][0][RTW89_ACMA][0][8] = 18, + [2][0][RTW89_CHILE][1][8] = 8, + [2][0][RTW89_QATAR][1][8] = 56, + [2][0][RTW89_QATAR][0][8] = 18, + [2][0][RTW89_UK][1][8] = 56, + [2][0][RTW89_UK][0][8] = 18, + [2][0][RTW89_FCC][1][10] = 8, + [2][0][RTW89_FCC][2][10] = 60, + [2][0][RTW89_ETSI][1][10] = 56, + [2][0][RTW89_ETSI][0][10] = 18, + [2][0][RTW89_MKK][1][10] = 54, + [2][0][RTW89_MKK][0][10] = 14, + [2][0][RTW89_IC][1][10] = 8, + [2][0][RTW89_KCC][1][10] = -2, + [2][0][RTW89_KCC][0][10] = -2, + [2][0][RTW89_ACMA][1][10] = 56, + [2][0][RTW89_ACMA][0][10] = 18, + [2][0][RTW89_CHILE][1][10] = 8, + [2][0][RTW89_QATAR][1][10] = 56, + [2][0][RTW89_QATAR][0][10] = 18, + [2][0][RTW89_UK][1][10] = 56, + [2][0][RTW89_UK][0][10] = 18, + [2][0][RTW89_FCC][1][12] = 8, + [2][0][RTW89_FCC][2][12] = 60, + [2][0][RTW89_ETSI][1][12] = 56, + [2][0][RTW89_ETSI][0][12] = 18, + [2][0][RTW89_MKK][1][12] = 54, + [2][0][RTW89_MKK][0][12] = 14, + [2][0][RTW89_IC][1][12] = 8, + [2][0][RTW89_KCC][1][12] = -2, + [2][0][RTW89_KCC][0][12] = -2, + [2][0][RTW89_ACMA][1][12] = 56, + [2][0][RTW89_ACMA][0][12] = 18, + [2][0][RTW89_CHILE][1][12] = 8, + [2][0][RTW89_QATAR][1][12] = 56, + [2][0][RTW89_QATAR][0][12] = 18, + [2][0][RTW89_UK][1][12] = 56, + [2][0][RTW89_UK][0][12] = 18, + [2][0][RTW89_FCC][1][14] = 8, + [2][0][RTW89_FCC][2][14] = 60, + [2][0][RTW89_ETSI][1][14] = 56, + [2][0][RTW89_ETSI][0][14] = 18, + [2][0][RTW89_MKK][1][14] = 54, + [2][0][RTW89_MKK][0][14] = 14, + [2][0][RTW89_IC][1][14] = 8, + [2][0][RTW89_KCC][1][14] = -2, + [2][0][RTW89_KCC][0][14] = -2, + [2][0][RTW89_ACMA][1][14] = 56, + [2][0][RTW89_ACMA][0][14] = 18, + [2][0][RTW89_CHILE][1][14] = 8, + [2][0][RTW89_QATAR][1][14] = 56, + [2][0][RTW89_QATAR][0][14] = 18, + [2][0][RTW89_UK][1][14] = 56, + [2][0][RTW89_UK][0][14] = 18, + [2][0][RTW89_FCC][1][15] = 8, + [2][0][RTW89_FCC][2][15] = 60, + [2][0][RTW89_ETSI][1][15] = 56, + [2][0][RTW89_ETSI][0][15] = 18, + [2][0][RTW89_MKK][1][15] = 54, + [2][0][RTW89_MKK][0][15] = 14, + [2][0][RTW89_IC][1][15] = 8, + [2][0][RTW89_KCC][1][15] = -2, + [2][0][RTW89_KCC][0][15] = -2, + [2][0][RTW89_ACMA][1][15] = 56, + [2][0][RTW89_ACMA][0][15] = 18, + [2][0][RTW89_CHILE][1][15] = 8, + [2][0][RTW89_QATAR][1][15] = 56, + [2][0][RTW89_QATAR][0][15] = 18, + [2][0][RTW89_UK][1][15] = 56, + [2][0][RTW89_UK][0][15] = 18, + [2][0][RTW89_FCC][1][17] = 8, + [2][0][RTW89_FCC][2][17] = 60, + [2][0][RTW89_ETSI][1][17] = 56, + [2][0][RTW89_ETSI][0][17] = 18, + [2][0][RTW89_MKK][1][17] = 54, + [2][0][RTW89_MKK][0][17] = 14, + [2][0][RTW89_IC][1][17] = 8, + [2][0][RTW89_KCC][1][17] = -2, + [2][0][RTW89_KCC][0][17] = -2, + [2][0][RTW89_ACMA][1][17] = 56, + [2][0][RTW89_ACMA][0][17] = 18, + [2][0][RTW89_CHILE][1][17] = 8, + [2][0][RTW89_QATAR][1][17] = 56, + [2][0][RTW89_QATAR][0][17] = 18, + [2][0][RTW89_UK][1][17] = 56, + [2][0][RTW89_UK][0][17] = 18, + [2][0][RTW89_FCC][1][19] = 8, + [2][0][RTW89_FCC][2][19] = 60, + [2][0][RTW89_ETSI][1][19] = 56, + [2][0][RTW89_ETSI][0][19] = 18, + [2][0][RTW89_MKK][1][19] = 54, + [2][0][RTW89_MKK][0][19] = 14, + [2][0][RTW89_IC][1][19] = 8, + [2][0][RTW89_KCC][1][19] = -2, + [2][0][RTW89_KCC][0][19] = -2, + [2][0][RTW89_ACMA][1][19] = 56, + [2][0][RTW89_ACMA][0][19] = 18, + [2][0][RTW89_CHILE][1][19] = 8, + [2][0][RTW89_QATAR][1][19] = 56, + [2][0][RTW89_QATAR][0][19] = 18, + [2][0][RTW89_UK][1][19] = 56, + [2][0][RTW89_UK][0][19] = 18, + [2][0][RTW89_FCC][1][21] = 8, + [2][0][RTW89_FCC][2][21] = 60, + [2][0][RTW89_ETSI][1][21] = 56, + [2][0][RTW89_ETSI][0][21] = 18, + [2][0][RTW89_MKK][1][21] = 54, + [2][0][RTW89_MKK][0][21] = 14, + [2][0][RTW89_IC][1][21] = 8, + [2][0][RTW89_KCC][1][21] = -2, + [2][0][RTW89_KCC][0][21] = -2, + [2][0][RTW89_ACMA][1][21] = 56, + [2][0][RTW89_ACMA][0][21] = 18, + [2][0][RTW89_CHILE][1][21] = 8, + [2][0][RTW89_QATAR][1][21] = 56, + [2][0][RTW89_QATAR][0][21] = 18, + [2][0][RTW89_UK][1][21] = 56, + [2][0][RTW89_UK][0][21] = 18, + [2][0][RTW89_FCC][1][23] = 8, + [2][0][RTW89_FCC][2][23] = 78, + [2][0][RTW89_ETSI][1][23] = 56, + [2][0][RTW89_ETSI][0][23] = 18, + [2][0][RTW89_MKK][1][23] = 56, + [2][0][RTW89_MKK][0][23] = 14, + [2][0][RTW89_IC][1][23] = 8, + [2][0][RTW89_KCC][1][23] = -2, + [2][0][RTW89_KCC][0][23] = -2, + [2][0][RTW89_ACMA][1][23] = 56, + [2][0][RTW89_ACMA][0][23] = 18, + [2][0][RTW89_CHILE][1][23] = 8, + [2][0][RTW89_QATAR][1][23] = 56, + [2][0][RTW89_QATAR][0][23] = 18, + [2][0][RTW89_UK][1][23] = 56, + [2][0][RTW89_UK][0][23] = 18, + [2][0][RTW89_FCC][1][25] = 8, + [2][0][RTW89_FCC][2][25] = 78, + [2][0][RTW89_ETSI][1][25] = 56, + [2][0][RTW89_ETSI][0][25] = 18, + [2][0][RTW89_MKK][1][25] = 56, + [2][0][RTW89_MKK][0][25] = 14, + [2][0][RTW89_IC][1][25] = 8, + [2][0][RTW89_KCC][1][25] = -2, + [2][0][RTW89_KCC][0][25] = -2, + [2][0][RTW89_ACMA][1][25] = 56, + [2][0][RTW89_ACMA][0][25] = 18, + [2][0][RTW89_CHILE][1][25] = 8, + [2][0][RTW89_QATAR][1][25] = 56, + [2][0][RTW89_QATAR][0][25] = 18, + [2][0][RTW89_UK][1][25] = 56, + [2][0][RTW89_UK][0][25] = 18, + [2][0][RTW89_FCC][1][27] = 8, + [2][0][RTW89_FCC][2][27] = 78, + [2][0][RTW89_ETSI][1][27] = 56, + [2][0][RTW89_ETSI][0][27] = 18, + [2][0][RTW89_MKK][1][27] = 56, + [2][0][RTW89_MKK][0][27] = 14, + [2][0][RTW89_IC][1][27] = 8, + [2][0][RTW89_KCC][1][27] = -2, + [2][0][RTW89_KCC][0][27] = -2, + [2][0][RTW89_ACMA][1][27] = 56, + [2][0][RTW89_ACMA][0][27] = 18, + [2][0][RTW89_CHILE][1][27] = 8, + [2][0][RTW89_QATAR][1][27] = 56, + [2][0][RTW89_QATAR][0][27] = 18, + [2][0][RTW89_UK][1][27] = 56, + [2][0][RTW89_UK][0][27] = 18, + [2][0][RTW89_FCC][1][29] = 8, + [2][0][RTW89_FCC][2][29] = 78, + [2][0][RTW89_ETSI][1][29] = 56, + [2][0][RTW89_ETSI][0][29] = 18, + [2][0][RTW89_MKK][1][29] = 56, + [2][0][RTW89_MKK][0][29] = 14, + [2][0][RTW89_IC][1][29] = 8, + [2][0][RTW89_KCC][1][29] = -2, + [2][0][RTW89_KCC][0][29] = -2, + [2][0][RTW89_ACMA][1][29] = 56, + [2][0][RTW89_ACMA][0][29] = 18, + [2][0][RTW89_CHILE][1][29] = 8, + [2][0][RTW89_QATAR][1][29] = 56, + [2][0][RTW89_QATAR][0][29] = 18, + [2][0][RTW89_UK][1][29] = 56, + [2][0][RTW89_UK][0][29] = 18, + [2][0][RTW89_FCC][1][30] = 8, + [2][0][RTW89_FCC][2][30] = 78, + [2][0][RTW89_ETSI][1][30] = 56, + [2][0][RTW89_ETSI][0][30] = 18, + [2][0][RTW89_MKK][1][30] = 56, + [2][0][RTW89_MKK][0][30] = 14, + [2][0][RTW89_IC][1][30] = 8, + [2][0][RTW89_KCC][1][30] = -2, + [2][0][RTW89_KCC][0][30] = -2, + [2][0][RTW89_ACMA][1][30] = 56, + [2][0][RTW89_ACMA][0][30] = 18, + [2][0][RTW89_CHILE][1][30] = 8, + [2][0][RTW89_QATAR][1][30] = 56, + [2][0][RTW89_QATAR][0][30] = 18, + [2][0][RTW89_UK][1][30] = 56, + [2][0][RTW89_UK][0][30] = 18, + [2][0][RTW89_FCC][1][32] = 8, + [2][0][RTW89_FCC][2][32] = 78, + [2][0][RTW89_ETSI][1][32] = 56, + [2][0][RTW89_ETSI][0][32] = 18, + [2][0][RTW89_MKK][1][32] = 56, + [2][0][RTW89_MKK][0][32] = 14, + [2][0][RTW89_IC][1][32] = 8, + [2][0][RTW89_KCC][1][32] = -2, + [2][0][RTW89_KCC][0][32] = -2, + [2][0][RTW89_ACMA][1][32] = 56, + [2][0][RTW89_ACMA][0][32] = 18, + [2][0][RTW89_CHILE][1][32] = 8, + [2][0][RTW89_QATAR][1][32] = 56, + [2][0][RTW89_QATAR][0][32] = 18, + [2][0][RTW89_UK][1][32] = 56, + [2][0][RTW89_UK][0][32] = 18, + [2][0][RTW89_FCC][1][34] = 8, + [2][0][RTW89_FCC][2][34] = 78, + [2][0][RTW89_ETSI][1][34] = 56, + [2][0][RTW89_ETSI][0][34] = 18, + [2][0][RTW89_MKK][1][34] = 56, + [2][0][RTW89_MKK][0][34] = 14, + [2][0][RTW89_IC][1][34] = 8, + [2][0][RTW89_KCC][1][34] = -2, + [2][0][RTW89_KCC][0][34] = -2, + [2][0][RTW89_ACMA][1][34] = 56, + [2][0][RTW89_ACMA][0][34] = 18, + [2][0][RTW89_CHILE][1][34] = 8, + [2][0][RTW89_QATAR][1][34] = 56, + [2][0][RTW89_QATAR][0][34] = 18, + [2][0][RTW89_UK][1][34] = 56, + [2][0][RTW89_UK][0][34] = 18, + [2][0][RTW89_FCC][1][36] = 8, + [2][0][RTW89_FCC][2][36] = 78, + [2][0][RTW89_ETSI][1][36] = 56, + [2][0][RTW89_ETSI][0][36] = 18, + [2][0][RTW89_MKK][1][36] = 56, + [2][0][RTW89_MKK][0][36] = 14, + [2][0][RTW89_IC][1][36] = 8, + [2][0][RTW89_KCC][1][36] = -2, + [2][0][RTW89_KCC][0][36] = -2, + [2][0][RTW89_ACMA][1][36] = 56, + [2][0][RTW89_ACMA][0][36] = 18, + [2][0][RTW89_CHILE][1][36] = 8, + [2][0][RTW89_QATAR][1][36] = 56, + [2][0][RTW89_QATAR][0][36] = 18, + [2][0][RTW89_UK][1][36] = 56, + [2][0][RTW89_UK][0][36] = 18, + [2][0][RTW89_FCC][1][38] = 8, + [2][0][RTW89_FCC][2][38] = 78, + [2][0][RTW89_ETSI][1][38] = 56, + [2][0][RTW89_ETSI][0][38] = 18, + [2][0][RTW89_MKK][1][38] = 56, + [2][0][RTW89_MKK][0][38] = 14, + [2][0][RTW89_IC][1][38] = 8, + [2][0][RTW89_KCC][1][38] = -2, + [2][0][RTW89_KCC][0][38] = -2, + [2][0][RTW89_ACMA][1][38] = 56, + [2][0][RTW89_ACMA][0][38] = 18, + [2][0][RTW89_CHILE][1][38] = 8, + [2][0][RTW89_QATAR][1][38] = 56, + [2][0][RTW89_QATAR][0][38] = 18, + [2][0][RTW89_UK][1][38] = 56, + [2][0][RTW89_UK][0][38] = 18, + [2][0][RTW89_FCC][1][40] = 8, + [2][0][RTW89_FCC][2][40] = 78, + [2][0][RTW89_ETSI][1][40] = 56, + [2][0][RTW89_ETSI][0][40] = 18, + [2][0][RTW89_MKK][1][40] = 56, + [2][0][RTW89_MKK][0][40] = 14, + [2][0][RTW89_IC][1][40] = 8, + [2][0][RTW89_KCC][1][40] = -2, + [2][0][RTW89_KCC][0][40] = -2, + [2][0][RTW89_ACMA][1][40] = 56, + [2][0][RTW89_ACMA][0][40] = 18, + [2][0][RTW89_CHILE][1][40] = 8, + [2][0][RTW89_QATAR][1][40] = 56, + [2][0][RTW89_QATAR][0][40] = 18, + [2][0][RTW89_UK][1][40] = 56, + [2][0][RTW89_UK][0][40] = 18, + [2][0][RTW89_FCC][1][42] = 8, + [2][0][RTW89_FCC][2][42] = 78, + [2][0][RTW89_ETSI][1][42] = 56, + [2][0][RTW89_ETSI][0][42] = 18, + [2][0][RTW89_MKK][1][42] = 56, + [2][0][RTW89_MKK][0][42] = 14, + [2][0][RTW89_IC][1][42] = 8, + [2][0][RTW89_KCC][1][42] = -2, + [2][0][RTW89_KCC][0][42] = -2, + [2][0][RTW89_ACMA][1][42] = 56, + [2][0][RTW89_ACMA][0][42] = 18, + [2][0][RTW89_CHILE][1][42] = 8, + [2][0][RTW89_QATAR][1][42] = 56, + [2][0][RTW89_QATAR][0][42] = 18, + [2][0][RTW89_UK][1][42] = 56, + [2][0][RTW89_UK][0][42] = 18, + [2][0][RTW89_FCC][1][44] = 8, + [2][0][RTW89_FCC][2][44] = 78, + [2][0][RTW89_ETSI][1][44] = 56, + [2][0][RTW89_ETSI][0][44] = 18, + [2][0][RTW89_MKK][1][44] = 32, + [2][0][RTW89_MKK][0][44] = 14, + [2][0][RTW89_IC][1][44] = 8, + [2][0][RTW89_KCC][1][44] = -2, + [2][0][RTW89_KCC][0][44] = -2, + [2][0][RTW89_ACMA][1][44] = 56, + [2][0][RTW89_ACMA][0][44] = 18, + [2][0][RTW89_CHILE][1][44] = 8, + [2][0][RTW89_QATAR][1][44] = 56, + [2][0][RTW89_QATAR][0][44] = 18, + [2][0][RTW89_UK][1][44] = 56, + [2][0][RTW89_UK][0][44] = 18, + [2][0][RTW89_FCC][1][45] = 8, + [2][0][RTW89_FCC][2][45] = 127, + [2][0][RTW89_ETSI][1][45] = 127, + [2][0][RTW89_ETSI][0][45] = 127, + [2][0][RTW89_MKK][1][45] = 127, + [2][0][RTW89_MKK][0][45] = 127, + [2][0][RTW89_IC][1][45] = 8, + [2][0][RTW89_KCC][1][45] = -2, + [2][0][RTW89_KCC][0][45] = 127, + [2][0][RTW89_ACMA][1][45] = 127, + [2][0][RTW89_ACMA][0][45] = 127, + [2][0][RTW89_CHILE][1][45] = 127, + [2][0][RTW89_QATAR][1][45] = 127, + [2][0][RTW89_QATAR][0][45] = 127, + [2][0][RTW89_UK][1][45] = 127, + [2][0][RTW89_UK][0][45] = 127, + [2][0][RTW89_FCC][1][47] = 8, + [2][0][RTW89_FCC][2][47] = 127, + [2][0][RTW89_ETSI][1][47] = 127, + [2][0][RTW89_ETSI][0][47] = 127, + [2][0][RTW89_MKK][1][47] = 127, + [2][0][RTW89_MKK][0][47] = 127, + [2][0][RTW89_IC][1][47] = 8, + [2][0][RTW89_KCC][1][47] = -2, + [2][0][RTW89_KCC][0][47] = 127, + [2][0][RTW89_ACMA][1][47] = 127, + [2][0][RTW89_ACMA][0][47] = 127, + [2][0][RTW89_CHILE][1][47] = 127, + [2][0][RTW89_QATAR][1][47] = 127, + [2][0][RTW89_QATAR][0][47] = 127, + [2][0][RTW89_UK][1][47] = 127, + [2][0][RTW89_UK][0][47] = 127, + [2][0][RTW89_FCC][1][49] = 8, + [2][0][RTW89_FCC][2][49] = 127, + [2][0][RTW89_ETSI][1][49] = 127, + [2][0][RTW89_ETSI][0][49] = 127, + [2][0][RTW89_MKK][1][49] = 127, + [2][0][RTW89_MKK][0][49] = 127, + [2][0][RTW89_IC][1][49] = 8, + [2][0][RTW89_KCC][1][49] = -2, + [2][0][RTW89_KCC][0][49] = 127, + [2][0][RTW89_ACMA][1][49] = 127, + [2][0][RTW89_ACMA][0][49] = 127, + [2][0][RTW89_CHILE][1][49] = 127, + [2][0][RTW89_QATAR][1][49] = 127, + [2][0][RTW89_QATAR][0][49] = 127, + [2][0][RTW89_UK][1][49] = 127, + [2][0][RTW89_UK][0][49] = 127, + [2][0][RTW89_FCC][1][51] = 8, + [2][0][RTW89_FCC][2][51] = 127, + [2][0][RTW89_ETSI][1][51] = 127, + [2][0][RTW89_ETSI][0][51] = 127, + [2][0][RTW89_MKK][1][51] = 127, + [2][0][RTW89_MKK][0][51] = 127, + [2][0][RTW89_IC][1][51] = 8, + [2][0][RTW89_KCC][1][51] = -2, + [2][0][RTW89_KCC][0][51] = 127, + [2][0][RTW89_ACMA][1][51] = 127, + [2][0][RTW89_ACMA][0][51] = 127, + [2][0][RTW89_CHILE][1][51] = 127, + [2][0][RTW89_QATAR][1][51] = 127, + [2][0][RTW89_QATAR][0][51] = 127, + [2][0][RTW89_UK][1][51] = 127, + [2][0][RTW89_UK][0][51] = 127, + [2][0][RTW89_FCC][1][53] = 8, + [2][0][RTW89_FCC][2][53] = 127, + [2][0][RTW89_ETSI][1][53] = 127, + [2][0][RTW89_ETSI][0][53] = 127, + [2][0][RTW89_MKK][1][53] = 127, + [2][0][RTW89_MKK][0][53] = 127, + [2][0][RTW89_IC][1][53] = 8, + [2][0][RTW89_KCC][1][53] = -2, + [2][0][RTW89_KCC][0][53] = 127, + [2][0][RTW89_ACMA][1][53] = 127, + [2][0][RTW89_ACMA][0][53] = 127, + [2][0][RTW89_CHILE][1][53] = 127, + [2][0][RTW89_QATAR][1][53] = 127, + [2][0][RTW89_QATAR][0][53] = 127, + [2][0][RTW89_UK][1][53] = 127, + [2][0][RTW89_UK][0][53] = 127, + [2][0][RTW89_FCC][1][55] = 8, + [2][0][RTW89_FCC][2][55] = 78, + [2][0][RTW89_ETSI][1][55] = 127, + [2][0][RTW89_ETSI][0][55] = 127, + [2][0][RTW89_MKK][1][55] = 127, + [2][0][RTW89_MKK][0][55] = 127, + [2][0][RTW89_IC][1][55] = 8, + [2][0][RTW89_KCC][1][55] = -2, + [2][0][RTW89_KCC][0][55] = 127, + [2][0][RTW89_ACMA][1][55] = 127, + [2][0][RTW89_ACMA][0][55] = 127, + [2][0][RTW89_CHILE][1][55] = 127, + [2][0][RTW89_QATAR][1][55] = 127, + [2][0][RTW89_QATAR][0][55] = 127, + [2][0][RTW89_UK][1][55] = 127, + [2][0][RTW89_UK][0][55] = 127, + [2][0][RTW89_FCC][1][57] = 8, + [2][0][RTW89_FCC][2][57] = 78, + [2][0][RTW89_ETSI][1][57] = 127, + [2][0][RTW89_ETSI][0][57] = 127, + [2][0][RTW89_MKK][1][57] = 127, + [2][0][RTW89_MKK][0][57] = 127, + [2][0][RTW89_IC][1][57] = 8, + [2][0][RTW89_KCC][1][57] = -2, + [2][0][RTW89_KCC][0][57] = 127, + [2][0][RTW89_ACMA][1][57] = 127, + [2][0][RTW89_ACMA][0][57] = 127, + [2][0][RTW89_CHILE][1][57] = 127, + [2][0][RTW89_QATAR][1][57] = 127, + [2][0][RTW89_QATAR][0][57] = 127, + [2][0][RTW89_UK][1][57] = 127, + [2][0][RTW89_UK][0][57] = 127, + [2][0][RTW89_FCC][1][59] = 8, + [2][0][RTW89_FCC][2][59] = 78, + [2][0][RTW89_ETSI][1][59] = 127, + [2][0][RTW89_ETSI][0][59] = 127, + [2][0][RTW89_MKK][1][59] = 127, + [2][0][RTW89_MKK][0][59] = 127, + [2][0][RTW89_IC][1][59] = 8, + [2][0][RTW89_KCC][1][59] = -2, + [2][0][RTW89_KCC][0][59] = 127, + [2][0][RTW89_ACMA][1][59] = 127, + [2][0][RTW89_ACMA][0][59] = 127, + [2][0][RTW89_CHILE][1][59] = 127, + [2][0][RTW89_QATAR][1][59] = 127, + [2][0][RTW89_QATAR][0][59] = 127, + [2][0][RTW89_UK][1][59] = 127, + [2][0][RTW89_UK][0][59] = 127, + [2][0][RTW89_FCC][1][60] = 8, + [2][0][RTW89_FCC][2][60] = 78, + [2][0][RTW89_ETSI][1][60] = 127, + [2][0][RTW89_ETSI][0][60] = 127, + [2][0][RTW89_MKK][1][60] = 127, + [2][0][RTW89_MKK][0][60] = 127, + [2][0][RTW89_IC][1][60] = 8, + [2][0][RTW89_KCC][1][60] = -2, + [2][0][RTW89_KCC][0][60] = 127, + [2][0][RTW89_ACMA][1][60] = 127, + [2][0][RTW89_ACMA][0][60] = 127, + [2][0][RTW89_CHILE][1][60] = 127, + [2][0][RTW89_QATAR][1][60] = 127, + [2][0][RTW89_QATAR][0][60] = 127, + [2][0][RTW89_UK][1][60] = 127, + [2][0][RTW89_UK][0][60] = 127, + [2][0][RTW89_FCC][1][62] = 8, + [2][0][RTW89_FCC][2][62] = 78, + [2][0][RTW89_ETSI][1][62] = 127, + [2][0][RTW89_ETSI][0][62] = 127, + [2][0][RTW89_MKK][1][62] = 127, + [2][0][RTW89_MKK][0][62] = 127, + [2][0][RTW89_IC][1][62] = 8, + [2][0][RTW89_KCC][1][62] = -2, + [2][0][RTW89_KCC][0][62] = 127, + [2][0][RTW89_ACMA][1][62] = 127, + [2][0][RTW89_ACMA][0][62] = 127, + [2][0][RTW89_CHILE][1][62] = 127, + [2][0][RTW89_QATAR][1][62] = 127, + [2][0][RTW89_QATAR][0][62] = 127, + [2][0][RTW89_UK][1][62] = 127, + [2][0][RTW89_UK][0][62] = 127, + [2][0][RTW89_FCC][1][64] = 8, + [2][0][RTW89_FCC][2][64] = 78, + [2][0][RTW89_ETSI][1][64] = 127, + [2][0][RTW89_ETSI][0][64] = 127, + [2][0][RTW89_MKK][1][64] = 127, + [2][0][RTW89_MKK][0][64] = 127, + [2][0][RTW89_IC][1][64] = 8, + [2][0][RTW89_KCC][1][64] = -2, + [2][0][RTW89_KCC][0][64] = 127, + [2][0][RTW89_ACMA][1][64] = 127, + [2][0][RTW89_ACMA][0][64] = 127, + [2][0][RTW89_CHILE][1][64] = 127, + [2][0][RTW89_QATAR][1][64] = 127, + [2][0][RTW89_QATAR][0][64] = 127, + [2][0][RTW89_UK][1][64] = 127, + [2][0][RTW89_UK][0][64] = 127, + [2][0][RTW89_FCC][1][66] = 8, + [2][0][RTW89_FCC][2][66] = 78, + [2][0][RTW89_ETSI][1][66] = 127, + [2][0][RTW89_ETSI][0][66] = 127, + [2][0][RTW89_MKK][1][66] = 127, + [2][0][RTW89_MKK][0][66] = 127, + [2][0][RTW89_IC][1][66] = 8, + [2][0][RTW89_KCC][1][66] = -2, + [2][0][RTW89_KCC][0][66] = 127, + [2][0][RTW89_ACMA][1][66] = 127, + [2][0][RTW89_ACMA][0][66] = 127, + [2][0][RTW89_CHILE][1][66] = 127, + [2][0][RTW89_QATAR][1][66] = 127, + [2][0][RTW89_QATAR][0][66] = 127, + [2][0][RTW89_UK][1][66] = 127, + [2][0][RTW89_UK][0][66] = 127, + [2][0][RTW89_FCC][1][68] = 8, + [2][0][RTW89_FCC][2][68] = 78, + [2][0][RTW89_ETSI][1][68] = 127, + [2][0][RTW89_ETSI][0][68] = 127, + [2][0][RTW89_MKK][1][68] = 127, + [2][0][RTW89_MKK][0][68] = 127, + [2][0][RTW89_IC][1][68] = 8, + [2][0][RTW89_KCC][1][68] = -2, + [2][0][RTW89_KCC][0][68] = 127, + [2][0][RTW89_ACMA][1][68] = 127, + [2][0][RTW89_ACMA][0][68] = 127, + [2][0][RTW89_CHILE][1][68] = 127, + [2][0][RTW89_QATAR][1][68] = 127, + [2][0][RTW89_QATAR][0][68] = 127, + [2][0][RTW89_UK][1][68] = 127, + [2][0][RTW89_UK][0][68] = 127, + [2][0][RTW89_FCC][1][70] = 8, + [2][0][RTW89_FCC][2][70] = 78, + [2][0][RTW89_ETSI][1][70] = 127, + [2][0][RTW89_ETSI][0][70] = 127, + [2][0][RTW89_MKK][1][70] = 127, + [2][0][RTW89_MKK][0][70] = 127, + [2][0][RTW89_IC][1][70] = 8, + [2][0][RTW89_KCC][1][70] = -2, + [2][0][RTW89_KCC][0][70] = 127, + [2][0][RTW89_ACMA][1][70] = 127, + [2][0][RTW89_ACMA][0][70] = 127, + [2][0][RTW89_CHILE][1][70] = 127, + [2][0][RTW89_QATAR][1][70] = 127, + [2][0][RTW89_QATAR][0][70] = 127, + [2][0][RTW89_UK][1][70] = 127, + [2][0][RTW89_UK][0][70] = 127, + [2][0][RTW89_FCC][1][72] = 8, + [2][0][RTW89_FCC][2][72] = 78, + [2][0][RTW89_ETSI][1][72] = 127, + [2][0][RTW89_ETSI][0][72] = 127, + [2][0][RTW89_MKK][1][72] = 127, + [2][0][RTW89_MKK][0][72] = 127, + [2][0][RTW89_IC][1][72] = 8, + [2][0][RTW89_KCC][1][72] = -2, + [2][0][RTW89_KCC][0][72] = 127, + [2][0][RTW89_ACMA][1][72] = 127, + [2][0][RTW89_ACMA][0][72] = 127, + [2][0][RTW89_CHILE][1][72] = 127, + [2][0][RTW89_QATAR][1][72] = 127, + [2][0][RTW89_QATAR][0][72] = 127, + [2][0][RTW89_UK][1][72] = 127, + [2][0][RTW89_UK][0][72] = 127, + [2][0][RTW89_FCC][1][74] = 8, + [2][0][RTW89_FCC][2][74] = 78, + [2][0][RTW89_ETSI][1][74] = 127, + [2][0][RTW89_ETSI][0][74] = 127, + [2][0][RTW89_MKK][1][74] = 127, + [2][0][RTW89_MKK][0][74] = 127, + [2][0][RTW89_IC][1][74] = 8, + [2][0][RTW89_KCC][1][74] = -2, + [2][0][RTW89_KCC][0][74] = 127, + [2][0][RTW89_ACMA][1][74] = 127, + [2][0][RTW89_ACMA][0][74] = 127, + [2][0][RTW89_CHILE][1][74] = 127, + [2][0][RTW89_QATAR][1][74] = 127, + [2][0][RTW89_QATAR][0][74] = 127, + [2][0][RTW89_UK][1][74] = 127, + [2][0][RTW89_UK][0][74] = 127, + [2][0][RTW89_FCC][1][75] = 8, + [2][0][RTW89_FCC][2][75] = 78, + [2][0][RTW89_ETSI][1][75] = 127, + [2][0][RTW89_ETSI][0][75] = 127, + [2][0][RTW89_MKK][1][75] = 127, + [2][0][RTW89_MKK][0][75] = 127, + [2][0][RTW89_IC][1][75] = 8, + [2][0][RTW89_KCC][1][75] = -2, + [2][0][RTW89_KCC][0][75] = 127, + [2][0][RTW89_ACMA][1][75] = 127, + [2][0][RTW89_ACMA][0][75] = 127, + [2][0][RTW89_CHILE][1][75] = 127, + [2][0][RTW89_QATAR][1][75] = 127, + [2][0][RTW89_QATAR][0][75] = 127, + [2][0][RTW89_UK][1][75] = 127, + [2][0][RTW89_UK][0][75] = 127, + [2][0][RTW89_FCC][1][77] = 8, + [2][0][RTW89_FCC][2][77] = 78, + [2][0][RTW89_ETSI][1][77] = 127, + [2][0][RTW89_ETSI][0][77] = 127, + [2][0][RTW89_MKK][1][77] = 127, + [2][0][RTW89_MKK][0][77] = 127, + [2][0][RTW89_IC][1][77] = 8, + [2][0][RTW89_KCC][1][77] = -2, + [2][0][RTW89_KCC][0][77] = 127, + [2][0][RTW89_ACMA][1][77] = 127, + [2][0][RTW89_ACMA][0][77] = 127, + [2][0][RTW89_CHILE][1][77] = 127, + [2][0][RTW89_QATAR][1][77] = 127, + [2][0][RTW89_QATAR][0][77] = 127, + [2][0][RTW89_UK][1][77] = 127, + [2][0][RTW89_UK][0][77] = 127, + [2][0][RTW89_FCC][1][79] = 8, + [2][0][RTW89_FCC][2][79] = 78, + [2][0][RTW89_ETSI][1][79] = 127, + [2][0][RTW89_ETSI][0][79] = 127, + [2][0][RTW89_MKK][1][79] = 127, + [2][0][RTW89_MKK][0][79] = 127, + [2][0][RTW89_IC][1][79] = 8, + [2][0][RTW89_KCC][1][79] = -2, + [2][0][RTW89_KCC][0][79] = 127, + [2][0][RTW89_ACMA][1][79] = 127, + [2][0][RTW89_ACMA][0][79] = 127, + [2][0][RTW89_CHILE][1][79] = 127, + [2][0][RTW89_QATAR][1][79] = 127, + [2][0][RTW89_QATAR][0][79] = 127, + [2][0][RTW89_UK][1][79] = 127, + [2][0][RTW89_UK][0][79] = 127, + [2][0][RTW89_FCC][1][81] = 8, + [2][0][RTW89_FCC][2][81] = 78, + [2][0][RTW89_ETSI][1][81] = 127, + [2][0][RTW89_ETSI][0][81] = 127, + [2][0][RTW89_MKK][1][81] = 127, + [2][0][RTW89_MKK][0][81] = 127, + [2][0][RTW89_IC][1][81] = 8, + [2][0][RTW89_KCC][1][81] = -2, + [2][0][RTW89_KCC][0][81] = 127, + [2][0][RTW89_ACMA][1][81] = 127, + [2][0][RTW89_ACMA][0][81] = 127, + [2][0][RTW89_CHILE][1][81] = 127, + [2][0][RTW89_QATAR][1][81] = 127, + [2][0][RTW89_QATAR][0][81] = 127, + [2][0][RTW89_UK][1][81] = 127, + [2][0][RTW89_UK][0][81] = 127, + [2][0][RTW89_FCC][1][83] = 8, + [2][0][RTW89_FCC][2][83] = 78, + [2][0][RTW89_ETSI][1][83] = 127, + [2][0][RTW89_ETSI][0][83] = 127, + [2][0][RTW89_MKK][1][83] = 127, + [2][0][RTW89_MKK][0][83] = 127, + [2][0][RTW89_IC][1][83] = 8, + [2][0][RTW89_KCC][1][83] = -2, + [2][0][RTW89_KCC][0][83] = 127, + [2][0][RTW89_ACMA][1][83] = 127, + [2][0][RTW89_ACMA][0][83] = 127, + [2][0][RTW89_CHILE][1][83] = 127, + [2][0][RTW89_QATAR][1][83] = 127, + [2][0][RTW89_QATAR][0][83] = 127, + [2][0][RTW89_UK][1][83] = 127, + [2][0][RTW89_UK][0][83] = 127, + [2][0][RTW89_FCC][1][85] = 8, + [2][0][RTW89_FCC][2][85] = 78, + [2][0][RTW89_ETSI][1][85] = 127, + [2][0][RTW89_ETSI][0][85] = 127, + [2][0][RTW89_MKK][1][85] = 127, + [2][0][RTW89_MKK][0][85] = 127, + [2][0][RTW89_IC][1][85] = 8, + [2][0][RTW89_KCC][1][85] = -2, + [2][0][RTW89_KCC][0][85] = 127, + [2][0][RTW89_ACMA][1][85] = 127, + [2][0][RTW89_ACMA][0][85] = 127, + [2][0][RTW89_CHILE][1][85] = 127, + [2][0][RTW89_QATAR][1][85] = 127, + [2][0][RTW89_QATAR][0][85] = 127, + [2][0][RTW89_UK][1][85] = 127, + [2][0][RTW89_UK][0][85] = 127, + [2][0][RTW89_FCC][1][87] = 8, + [2][0][RTW89_FCC][2][87] = 127, + [2][0][RTW89_ETSI][1][87] = 127, + [2][0][RTW89_ETSI][0][87] = 127, + [2][0][RTW89_MKK][1][87] = 127, + [2][0][RTW89_MKK][0][87] = 127, + [2][0][RTW89_IC][1][87] = 8, + [2][0][RTW89_KCC][1][87] = -2, + [2][0][RTW89_KCC][0][87] = 127, + [2][0][RTW89_ACMA][1][87] = 127, + [2][0][RTW89_ACMA][0][87] = 127, + [2][0][RTW89_CHILE][1][87] = 127, + [2][0][RTW89_QATAR][1][87] = 127, + [2][0][RTW89_QATAR][0][87] = 127, + [2][0][RTW89_UK][1][87] = 127, + [2][0][RTW89_UK][0][87] = 127, + [2][0][RTW89_FCC][1][89] = 8, + [2][0][RTW89_FCC][2][89] = 127, + [2][0][RTW89_ETSI][1][89] = 127, + [2][0][RTW89_ETSI][0][89] = 127, + [2][0][RTW89_MKK][1][89] = 127, + [2][0][RTW89_MKK][0][89] = 127, + [2][0][RTW89_IC][1][89] = 8, + [2][0][RTW89_KCC][1][89] = -2, + [2][0][RTW89_KCC][0][89] = 127, + [2][0][RTW89_ACMA][1][89] = 127, + [2][0][RTW89_ACMA][0][89] = 127, + [2][0][RTW89_CHILE][1][89] = 127, + [2][0][RTW89_QATAR][1][89] = 127, + [2][0][RTW89_QATAR][0][89] = 127, + [2][0][RTW89_UK][1][89] = 127, + [2][0][RTW89_UK][0][89] = 127, + [2][0][RTW89_FCC][1][90] = 8, + [2][0][RTW89_FCC][2][90] = 127, + [2][0][RTW89_ETSI][1][90] = 127, + [2][0][RTW89_ETSI][0][90] = 127, + [2][0][RTW89_MKK][1][90] = 127, + [2][0][RTW89_MKK][0][90] = 127, + [2][0][RTW89_IC][1][90] = 8, + [2][0][RTW89_KCC][1][90] = -2, + [2][0][RTW89_KCC][0][90] = 127, + [2][0][RTW89_ACMA][1][90] = 127, + [2][0][RTW89_ACMA][0][90] = 127, + [2][0][RTW89_CHILE][1][90] = 127, + [2][0][RTW89_QATAR][1][90] = 127, + [2][0][RTW89_QATAR][0][90] = 127, + [2][0][RTW89_UK][1][90] = 127, + [2][0][RTW89_UK][0][90] = 127, + [2][0][RTW89_FCC][1][92] = 8, + [2][0][RTW89_FCC][2][92] = 127, + [2][0][RTW89_ETSI][1][92] = 127, + [2][0][RTW89_ETSI][0][92] = 127, + [2][0][RTW89_MKK][1][92] = 127, + [2][0][RTW89_MKK][0][92] = 127, + [2][0][RTW89_IC][1][92] = 8, + [2][0][RTW89_KCC][1][92] = -2, + [2][0][RTW89_KCC][0][92] = 127, + [2][0][RTW89_ACMA][1][92] = 127, + [2][0][RTW89_ACMA][0][92] = 127, + [2][0][RTW89_CHILE][1][92] = 127, + [2][0][RTW89_QATAR][1][92] = 127, + [2][0][RTW89_QATAR][0][92] = 127, + [2][0][RTW89_UK][1][92] = 127, + [2][0][RTW89_UK][0][92] = 127, + [2][0][RTW89_FCC][1][94] = 8, + [2][0][RTW89_FCC][2][94] = 127, + [2][0][RTW89_ETSI][1][94] = 127, + [2][0][RTW89_ETSI][0][94] = 127, + [2][0][RTW89_MKK][1][94] = 127, + [2][0][RTW89_MKK][0][94] = 127, + [2][0][RTW89_IC][1][94] = 8, + [2][0][RTW89_KCC][1][94] = -2, + [2][0][RTW89_KCC][0][94] = 127, + [2][0][RTW89_ACMA][1][94] = 127, + [2][0][RTW89_ACMA][0][94] = 127, + [2][0][RTW89_CHILE][1][94] = 127, + [2][0][RTW89_QATAR][1][94] = 127, + [2][0][RTW89_QATAR][0][94] = 127, + [2][0][RTW89_UK][1][94] = 127, + [2][0][RTW89_UK][0][94] = 127, + [2][0][RTW89_FCC][1][96] = 8, + [2][0][RTW89_FCC][2][96] = 127, + [2][0][RTW89_ETSI][1][96] = 127, + [2][0][RTW89_ETSI][0][96] = 127, + [2][0][RTW89_MKK][1][96] = 127, + [2][0][RTW89_MKK][0][96] = 127, + [2][0][RTW89_IC][1][96] = 8, + [2][0][RTW89_KCC][1][96] = -2, + [2][0][RTW89_KCC][0][96] = 127, + [2][0][RTW89_ACMA][1][96] = 127, + [2][0][RTW89_ACMA][0][96] = 127, + [2][0][RTW89_CHILE][1][96] = 127, + [2][0][RTW89_QATAR][1][96] = 127, + [2][0][RTW89_QATAR][0][96] = 127, + [2][0][RTW89_UK][1][96] = 127, + [2][0][RTW89_UK][0][96] = 127, + [2][0][RTW89_FCC][1][98] = 8, + [2][0][RTW89_FCC][2][98] = 127, + [2][0][RTW89_ETSI][1][98] = 127, + [2][0][RTW89_ETSI][0][98] = 127, + [2][0][RTW89_MKK][1][98] = 127, + [2][0][RTW89_MKK][0][98] = 127, + [2][0][RTW89_IC][1][98] = 8, + [2][0][RTW89_KCC][1][98] = -2, + [2][0][RTW89_KCC][0][98] = 127, + [2][0][RTW89_ACMA][1][98] = 127, + [2][0][RTW89_ACMA][0][98] = 127, + [2][0][RTW89_CHILE][1][98] = 127, + [2][0][RTW89_QATAR][1][98] = 127, + [2][0][RTW89_QATAR][0][98] = 127, + [2][0][RTW89_UK][1][98] = 127, + [2][0][RTW89_UK][0][98] = 127, + [2][0][RTW89_FCC][1][100] = 8, + [2][0][RTW89_FCC][2][100] = 127, + [2][0][RTW89_ETSI][1][100] = 127, + [2][0][RTW89_ETSI][0][100] = 127, + [2][0][RTW89_MKK][1][100] = 127, + [2][0][RTW89_MKK][0][100] = 127, + [2][0][RTW89_IC][1][100] = 8, + [2][0][RTW89_KCC][1][100] = -2, + [2][0][RTW89_KCC][0][100] = 127, + [2][0][RTW89_ACMA][1][100] = 127, + [2][0][RTW89_ACMA][0][100] = 127, + [2][0][RTW89_CHILE][1][100] = 127, + [2][0][RTW89_QATAR][1][100] = 127, + [2][0][RTW89_QATAR][0][100] = 127, + [2][0][RTW89_UK][1][100] = 127, + [2][0][RTW89_UK][0][100] = 127, + [2][0][RTW89_FCC][1][102] = 8, + [2][0][RTW89_FCC][2][102] = 127, + [2][0][RTW89_ETSI][1][102] = 127, + [2][0][RTW89_ETSI][0][102] = 127, + [2][0][RTW89_MKK][1][102] = 127, + [2][0][RTW89_MKK][0][102] = 127, + [2][0][RTW89_IC][1][102] = 8, + [2][0][RTW89_KCC][1][102] = -2, + [2][0][RTW89_KCC][0][102] = 127, + [2][0][RTW89_ACMA][1][102] = 127, + [2][0][RTW89_ACMA][0][102] = 127, + [2][0][RTW89_CHILE][1][102] = 127, + [2][0][RTW89_QATAR][1][102] = 127, + [2][0][RTW89_QATAR][0][102] = 127, + [2][0][RTW89_UK][1][102] = 127, + [2][0][RTW89_UK][0][102] = 127, + [2][0][RTW89_FCC][1][104] = 8, + [2][0][RTW89_FCC][2][104] = 127, + [2][0][RTW89_ETSI][1][104] = 127, + [2][0][RTW89_ETSI][0][104] = 127, + [2][0][RTW89_MKK][1][104] = 127, + [2][0][RTW89_MKK][0][104] = 127, + [2][0][RTW89_IC][1][104] = 8, + [2][0][RTW89_KCC][1][104] = -2, + [2][0][RTW89_KCC][0][104] = 127, + [2][0][RTW89_ACMA][1][104] = 127, + [2][0][RTW89_ACMA][0][104] = 127, + [2][0][RTW89_CHILE][1][104] = 127, + [2][0][RTW89_QATAR][1][104] = 127, + [2][0][RTW89_QATAR][0][104] = 127, + [2][0][RTW89_UK][1][104] = 127, + [2][0][RTW89_UK][0][104] = 127, + [2][0][RTW89_FCC][1][105] = 8, + [2][0][RTW89_FCC][2][105] = 127, + [2][0][RTW89_ETSI][1][105] = 127, + [2][0][RTW89_ETSI][0][105] = 127, + [2][0][RTW89_MKK][1][105] = 127, + [2][0][RTW89_MKK][0][105] = 127, + [2][0][RTW89_IC][1][105] = 8, + [2][0][RTW89_KCC][1][105] = -2, + [2][0][RTW89_KCC][0][105] = 127, + [2][0][RTW89_ACMA][1][105] = 127, + [2][0][RTW89_ACMA][0][105] = 127, + [2][0][RTW89_CHILE][1][105] = 127, + [2][0][RTW89_QATAR][1][105] = 127, + [2][0][RTW89_QATAR][0][105] = 127, + [2][0][RTW89_UK][1][105] = 127, + [2][0][RTW89_UK][0][105] = 127, + [2][0][RTW89_FCC][1][107] = 10, + [2][0][RTW89_FCC][2][107] = 127, + [2][0][RTW89_ETSI][1][107] = 127, + [2][0][RTW89_ETSI][0][107] = 127, + [2][0][RTW89_MKK][1][107] = 127, + [2][0][RTW89_MKK][0][107] = 127, + [2][0][RTW89_IC][1][107] = 10, + [2][0][RTW89_KCC][1][107] = -2, + [2][0][RTW89_KCC][0][107] = 127, + [2][0][RTW89_ACMA][1][107] = 127, + [2][0][RTW89_ACMA][0][107] = 127, + [2][0][RTW89_CHILE][1][107] = 127, + [2][0][RTW89_QATAR][1][107] = 127, + [2][0][RTW89_QATAR][0][107] = 127, + [2][0][RTW89_UK][1][107] = 127, + [2][0][RTW89_UK][0][107] = 127, + [2][0][RTW89_FCC][1][109] = 12, + [2][0][RTW89_FCC][2][109] = 127, + [2][0][RTW89_ETSI][1][109] = 127, + [2][0][RTW89_ETSI][0][109] = 127, + [2][0][RTW89_MKK][1][109] = 127, + [2][0][RTW89_MKK][0][109] = 127, + [2][0][RTW89_IC][1][109] = 12, + [2][0][RTW89_KCC][1][109] = 127, + [2][0][RTW89_KCC][0][109] = 127, + [2][0][RTW89_ACMA][1][109] = 127, + [2][0][RTW89_ACMA][0][109] = 127, + [2][0][RTW89_CHILE][1][109] = 127, + [2][0][RTW89_QATAR][1][109] = 127, + [2][0][RTW89_QATAR][0][109] = 127, + [2][0][RTW89_UK][1][109] = 127, + [2][0][RTW89_UK][0][109] = 127, + [2][0][RTW89_FCC][1][111] = 127, + [2][0][RTW89_FCC][2][111] = 127, + [2][0][RTW89_ETSI][1][111] = 127, + [2][0][RTW89_ETSI][0][111] = 127, + [2][0][RTW89_MKK][1][111] = 127, + [2][0][RTW89_MKK][0][111] = 127, + [2][0][RTW89_IC][1][111] = 127, + [2][0][RTW89_KCC][1][111] = 127, + [2][0][RTW89_KCC][0][111] = 127, + [2][0][RTW89_ACMA][1][111] = 127, + [2][0][RTW89_ACMA][0][111] = 127, + [2][0][RTW89_CHILE][1][111] = 127, + [2][0][RTW89_QATAR][1][111] = 127, + [2][0][RTW89_QATAR][0][111] = 127, + [2][0][RTW89_UK][1][111] = 127, + [2][0][RTW89_UK][0][111] = 127, + [2][0][RTW89_FCC][1][113] = 127, + [2][0][RTW89_FCC][2][113] = 127, + [2][0][RTW89_ETSI][1][113] = 127, + [2][0][RTW89_ETSI][0][113] = 127, + [2][0][RTW89_MKK][1][113] = 127, + [2][0][RTW89_MKK][0][113] = 127, + [2][0][RTW89_IC][1][113] = 127, + [2][0][RTW89_KCC][1][113] = 127, + [2][0][RTW89_KCC][0][113] = 127, + [2][0][RTW89_ACMA][1][113] = 127, + [2][0][RTW89_ACMA][0][113] = 127, + [2][0][RTW89_CHILE][1][113] = 127, + [2][0][RTW89_QATAR][1][113] = 127, + [2][0][RTW89_QATAR][0][113] = 127, + [2][0][RTW89_UK][1][113] = 127, + [2][0][RTW89_UK][0][113] = 127, + [2][0][RTW89_FCC][1][115] = 127, + [2][0][RTW89_FCC][2][115] = 127, + [2][0][RTW89_ETSI][1][115] = 127, + [2][0][RTW89_ETSI][0][115] = 127, + [2][0][RTW89_MKK][1][115] = 127, + [2][0][RTW89_MKK][0][115] = 127, + [2][0][RTW89_IC][1][115] = 127, + [2][0][RTW89_KCC][1][115] = 127, + [2][0][RTW89_KCC][0][115] = 127, + [2][0][RTW89_ACMA][1][115] = 127, + [2][0][RTW89_ACMA][0][115] = 127, + [2][0][RTW89_CHILE][1][115] = 127, + [2][0][RTW89_QATAR][1][115] = 127, + [2][0][RTW89_QATAR][0][115] = 127, + [2][0][RTW89_UK][1][115] = 127, + [2][0][RTW89_UK][0][115] = 127, + [2][0][RTW89_FCC][1][117] = 127, + [2][0][RTW89_FCC][2][117] = 127, + [2][0][RTW89_ETSI][1][117] = 127, + [2][0][RTW89_ETSI][0][117] = 127, + [2][0][RTW89_MKK][1][117] = 127, + [2][0][RTW89_MKK][0][117] = 127, + [2][0][RTW89_IC][1][117] = 127, + [2][0][RTW89_KCC][1][117] = 127, + [2][0][RTW89_KCC][0][117] = 127, + [2][0][RTW89_ACMA][1][117] = 127, + [2][0][RTW89_ACMA][0][117] = 127, + [2][0][RTW89_CHILE][1][117] = 127, + [2][0][RTW89_QATAR][1][117] = 127, + [2][0][RTW89_QATAR][0][117] = 127, + [2][0][RTW89_UK][1][117] = 127, + [2][0][RTW89_UK][0][117] = 127, + [2][0][RTW89_FCC][1][119] = 127, + [2][0][RTW89_FCC][2][119] = 127, + [2][0][RTW89_ETSI][1][119] = 127, + [2][0][RTW89_ETSI][0][119] = 127, + [2][0][RTW89_MKK][1][119] = 127, + [2][0][RTW89_MKK][0][119] = 127, + [2][0][RTW89_IC][1][119] = 127, + [2][0][RTW89_KCC][1][119] = 127, + [2][0][RTW89_KCC][0][119] = 127, + [2][0][RTW89_ACMA][1][119] = 127, + [2][0][RTW89_ACMA][0][119] = 127, + [2][0][RTW89_CHILE][1][119] = 127, + [2][0][RTW89_QATAR][1][119] = 127, + [2][0][RTW89_QATAR][0][119] = 127, + [2][0][RTW89_UK][1][119] = 127, + [2][0][RTW89_UK][0][119] = 127, + [2][1][RTW89_FCC][1][0] = -16, + [2][1][RTW89_FCC][2][0] = 54, + [2][1][RTW89_ETSI][1][0] = 44, + [2][1][RTW89_ETSI][0][0] = 6, + [2][1][RTW89_MKK][1][0] = 42, + [2][1][RTW89_MKK][0][0] = 2, + [2][1][RTW89_IC][1][0] = -16, + [2][1][RTW89_KCC][1][0] = -14, + [2][1][RTW89_KCC][0][0] = -14, + [2][1][RTW89_ACMA][1][0] = 44, + [2][1][RTW89_ACMA][0][0] = 6, + [2][1][RTW89_CHILE][1][0] = -16, + [2][1][RTW89_QATAR][1][0] = 44, + [2][1][RTW89_QATAR][0][0] = 6, + [2][1][RTW89_UK][1][0] = 44, + [2][1][RTW89_UK][0][0] = 6, + [2][1][RTW89_FCC][1][2] = -16, + [2][1][RTW89_FCC][2][2] = 54, + [2][1][RTW89_ETSI][1][2] = 44, + [2][1][RTW89_ETSI][0][2] = 6, + [2][1][RTW89_MKK][1][2] = 40, + [2][1][RTW89_MKK][0][2] = 2, + [2][1][RTW89_IC][1][2] = -16, + [2][1][RTW89_KCC][1][2] = -14, + [2][1][RTW89_KCC][0][2] = -14, + [2][1][RTW89_ACMA][1][2] = 44, + [2][1][RTW89_ACMA][0][2] = 6, + [2][1][RTW89_CHILE][1][2] = -16, + [2][1][RTW89_QATAR][1][2] = 44, + [2][1][RTW89_QATAR][0][2] = 6, + [2][1][RTW89_UK][1][2] = 44, + [2][1][RTW89_UK][0][2] = 6, + [2][1][RTW89_FCC][1][4] = -16, + [2][1][RTW89_FCC][2][4] = 54, + [2][1][RTW89_ETSI][1][4] = 44, + [2][1][RTW89_ETSI][0][4] = 6, + [2][1][RTW89_MKK][1][4] = 40, + [2][1][RTW89_MKK][0][4] = 2, + [2][1][RTW89_IC][1][4] = -16, + [2][1][RTW89_KCC][1][4] = -14, + [2][1][RTW89_KCC][0][4] = -14, + [2][1][RTW89_ACMA][1][4] = 44, + [2][1][RTW89_ACMA][0][4] = 6, + [2][1][RTW89_CHILE][1][4] = -16, + [2][1][RTW89_QATAR][1][4] = 44, + [2][1][RTW89_QATAR][0][4] = 6, + [2][1][RTW89_UK][1][4] = 44, + [2][1][RTW89_UK][0][4] = 6, + [2][1][RTW89_FCC][1][6] = -16, + [2][1][RTW89_FCC][2][6] = 54, + [2][1][RTW89_ETSI][1][6] = 44, + [2][1][RTW89_ETSI][0][6] = 6, + [2][1][RTW89_MKK][1][6] = 40, + [2][1][RTW89_MKK][0][6] = 2, + [2][1][RTW89_IC][1][6] = -16, + [2][1][RTW89_KCC][1][6] = -14, + [2][1][RTW89_KCC][0][6] = -14, + [2][1][RTW89_ACMA][1][6] = 44, + [2][1][RTW89_ACMA][0][6] = 6, + [2][1][RTW89_CHILE][1][6] = -16, + [2][1][RTW89_QATAR][1][6] = 44, + [2][1][RTW89_QATAR][0][6] = 6, + [2][1][RTW89_UK][1][6] = 44, + [2][1][RTW89_UK][0][6] = 6, + [2][1][RTW89_FCC][1][8] = -16, + [2][1][RTW89_FCC][2][8] = 54, + [2][1][RTW89_ETSI][1][8] = 44, + [2][1][RTW89_ETSI][0][8] = 6, + [2][1][RTW89_MKK][1][8] = 40, + [2][1][RTW89_MKK][0][8] = 2, + [2][1][RTW89_IC][1][8] = -16, + [2][1][RTW89_KCC][1][8] = -14, + [2][1][RTW89_KCC][0][8] = -14, + [2][1][RTW89_ACMA][1][8] = 44, + [2][1][RTW89_ACMA][0][8] = 6, + [2][1][RTW89_CHILE][1][8] = -16, + [2][1][RTW89_QATAR][1][8] = 44, + [2][1][RTW89_QATAR][0][8] = 6, + [2][1][RTW89_UK][1][8] = 44, + [2][1][RTW89_UK][0][8] = 6, + [2][1][RTW89_FCC][1][10] = -16, + [2][1][RTW89_FCC][2][10] = 54, + [2][1][RTW89_ETSI][1][10] = 44, + [2][1][RTW89_ETSI][0][10] = 6, + [2][1][RTW89_MKK][1][10] = 40, + [2][1][RTW89_MKK][0][10] = 2, + [2][1][RTW89_IC][1][10] = -16, + [2][1][RTW89_KCC][1][10] = -14, + [2][1][RTW89_KCC][0][10] = -14, + [2][1][RTW89_ACMA][1][10] = 44, + [2][1][RTW89_ACMA][0][10] = 6, + [2][1][RTW89_CHILE][1][10] = -16, + [2][1][RTW89_QATAR][1][10] = 44, + [2][1][RTW89_QATAR][0][10] = 6, + [2][1][RTW89_UK][1][10] = 44, + [2][1][RTW89_UK][0][10] = 6, + [2][1][RTW89_FCC][1][12] = -16, + [2][1][RTW89_FCC][2][12] = 54, + [2][1][RTW89_ETSI][1][12] = 44, + [2][1][RTW89_ETSI][0][12] = 6, + [2][1][RTW89_MKK][1][12] = 40, + [2][1][RTW89_MKK][0][12] = 2, + [2][1][RTW89_IC][1][12] = -16, + [2][1][RTW89_KCC][1][12] = -14, + [2][1][RTW89_KCC][0][12] = -14, + [2][1][RTW89_ACMA][1][12] = 44, + [2][1][RTW89_ACMA][0][12] = 6, + [2][1][RTW89_CHILE][1][12] = -16, + [2][1][RTW89_QATAR][1][12] = 44, + [2][1][RTW89_QATAR][0][12] = 6, + [2][1][RTW89_UK][1][12] = 44, + [2][1][RTW89_UK][0][12] = 6, + [2][1][RTW89_FCC][1][14] = -16, + [2][1][RTW89_FCC][2][14] = 54, + [2][1][RTW89_ETSI][1][14] = 44, + [2][1][RTW89_ETSI][0][14] = 6, + [2][1][RTW89_MKK][1][14] = 40, + [2][1][RTW89_MKK][0][14] = 2, + [2][1][RTW89_IC][1][14] = -16, + [2][1][RTW89_KCC][1][14] = -14, + [2][1][RTW89_KCC][0][14] = -14, + [2][1][RTW89_ACMA][1][14] = 44, + [2][1][RTW89_ACMA][0][14] = 6, + [2][1][RTW89_CHILE][1][14] = -16, + [2][1][RTW89_QATAR][1][14] = 44, + [2][1][RTW89_QATAR][0][14] = 6, + [2][1][RTW89_UK][1][14] = 44, + [2][1][RTW89_UK][0][14] = 6, + [2][1][RTW89_FCC][1][15] = -16, + [2][1][RTW89_FCC][2][15] = 54, + [2][1][RTW89_ETSI][1][15] = 44, + [2][1][RTW89_ETSI][0][15] = 6, + [2][1][RTW89_MKK][1][15] = 40, + [2][1][RTW89_MKK][0][15] = 2, + [2][1][RTW89_IC][1][15] = -16, + [2][1][RTW89_KCC][1][15] = -14, + [2][1][RTW89_KCC][0][15] = -14, + [2][1][RTW89_ACMA][1][15] = 44, + [2][1][RTW89_ACMA][0][15] = 6, + [2][1][RTW89_CHILE][1][15] = -16, + [2][1][RTW89_QATAR][1][15] = 44, + [2][1][RTW89_QATAR][0][15] = 6, + [2][1][RTW89_UK][1][15] = 44, + [2][1][RTW89_UK][0][15] = 6, + [2][1][RTW89_FCC][1][17] = -16, + [2][1][RTW89_FCC][2][17] = 54, + [2][1][RTW89_ETSI][1][17] = 44, + [2][1][RTW89_ETSI][0][17] = 6, + [2][1][RTW89_MKK][1][17] = 40, + [2][1][RTW89_MKK][0][17] = 2, + [2][1][RTW89_IC][1][17] = -16, + [2][1][RTW89_KCC][1][17] = -14, + [2][1][RTW89_KCC][0][17] = -14, + [2][1][RTW89_ACMA][1][17] = 44, + [2][1][RTW89_ACMA][0][17] = 6, + [2][1][RTW89_CHILE][1][17] = -16, + [2][1][RTW89_QATAR][1][17] = 44, + [2][1][RTW89_QATAR][0][17] = 6, + [2][1][RTW89_UK][1][17] = 44, + [2][1][RTW89_UK][0][17] = 6, + [2][1][RTW89_FCC][1][19] = -16, + [2][1][RTW89_FCC][2][19] = 54, + [2][1][RTW89_ETSI][1][19] = 44, + [2][1][RTW89_ETSI][0][19] = 6, + [2][1][RTW89_MKK][1][19] = 40, + [2][1][RTW89_MKK][0][19] = 2, + [2][1][RTW89_IC][1][19] = -16, + [2][1][RTW89_KCC][1][19] = -14, + [2][1][RTW89_KCC][0][19] = -14, + [2][1][RTW89_ACMA][1][19] = 44, + [2][1][RTW89_ACMA][0][19] = 6, + [2][1][RTW89_CHILE][1][19] = -16, + [2][1][RTW89_QATAR][1][19] = 44, + [2][1][RTW89_QATAR][0][19] = 6, + [2][1][RTW89_UK][1][19] = 44, + [2][1][RTW89_UK][0][19] = 6, + [2][1][RTW89_FCC][1][21] = -16, + [2][1][RTW89_FCC][2][21] = 54, + [2][1][RTW89_ETSI][1][21] = 44, + [2][1][RTW89_ETSI][0][21] = 6, + [2][1][RTW89_MKK][1][21] = 40, + [2][1][RTW89_MKK][0][21] = 2, + [2][1][RTW89_IC][1][21] = -16, + [2][1][RTW89_KCC][1][21] = -14, + [2][1][RTW89_KCC][0][21] = -14, + [2][1][RTW89_ACMA][1][21] = 44, + [2][1][RTW89_ACMA][0][21] = 6, + [2][1][RTW89_CHILE][1][21] = -16, + [2][1][RTW89_QATAR][1][21] = 44, + [2][1][RTW89_QATAR][0][21] = 6, + [2][1][RTW89_UK][1][21] = 44, + [2][1][RTW89_UK][0][21] = 6, + [2][1][RTW89_FCC][1][23] = -16, + [2][1][RTW89_FCC][2][23] = 54, + [2][1][RTW89_ETSI][1][23] = 44, + [2][1][RTW89_ETSI][0][23] = 6, + [2][1][RTW89_MKK][1][23] = 40, + [2][1][RTW89_MKK][0][23] = 2, + [2][1][RTW89_IC][1][23] = -16, + [2][1][RTW89_KCC][1][23] = -14, + [2][1][RTW89_KCC][0][23] = -14, + [2][1][RTW89_ACMA][1][23] = 44, + [2][1][RTW89_ACMA][0][23] = 6, + [2][1][RTW89_CHILE][1][23] = -16, + [2][1][RTW89_QATAR][1][23] = 44, + [2][1][RTW89_QATAR][0][23] = 6, + [2][1][RTW89_UK][1][23] = 44, + [2][1][RTW89_UK][0][23] = 6, + [2][1][RTW89_FCC][1][25] = -16, + [2][1][RTW89_FCC][2][25] = 54, + [2][1][RTW89_ETSI][1][25] = 44, + [2][1][RTW89_ETSI][0][25] = 6, + [2][1][RTW89_MKK][1][25] = 40, + [2][1][RTW89_MKK][0][25] = 2, + [2][1][RTW89_IC][1][25] = -16, + [2][1][RTW89_KCC][1][25] = -14, + [2][1][RTW89_KCC][0][25] = -14, + [2][1][RTW89_ACMA][1][25] = 44, + [2][1][RTW89_ACMA][0][25] = 6, + [2][1][RTW89_CHILE][1][25] = -16, + [2][1][RTW89_QATAR][1][25] = 44, + [2][1][RTW89_QATAR][0][25] = 6, + [2][1][RTW89_UK][1][25] = 44, + [2][1][RTW89_UK][0][25] = 6, + [2][1][RTW89_FCC][1][27] = -16, + [2][1][RTW89_FCC][2][27] = 54, + [2][1][RTW89_ETSI][1][27] = 44, + [2][1][RTW89_ETSI][0][27] = 6, + [2][1][RTW89_MKK][1][27] = 40, + [2][1][RTW89_MKK][0][27] = 2, + [2][1][RTW89_IC][1][27] = -16, + [2][1][RTW89_KCC][1][27] = -14, + [2][1][RTW89_KCC][0][27] = -14, + [2][1][RTW89_ACMA][1][27] = 44, + [2][1][RTW89_ACMA][0][27] = 6, + [2][1][RTW89_CHILE][1][27] = -16, + [2][1][RTW89_QATAR][1][27] = 44, + [2][1][RTW89_QATAR][0][27] = 6, + [2][1][RTW89_UK][1][27] = 44, + [2][1][RTW89_UK][0][27] = 6, + [2][1][RTW89_FCC][1][29] = -16, + [2][1][RTW89_FCC][2][29] = 54, + [2][1][RTW89_ETSI][1][29] = 44, + [2][1][RTW89_ETSI][0][29] = 6, + [2][1][RTW89_MKK][1][29] = 40, + [2][1][RTW89_MKK][0][29] = 2, + [2][1][RTW89_IC][1][29] = -16, + [2][1][RTW89_KCC][1][29] = -14, + [2][1][RTW89_KCC][0][29] = -14, + [2][1][RTW89_ACMA][1][29] = 44, + [2][1][RTW89_ACMA][0][29] = 6, + [2][1][RTW89_CHILE][1][29] = -16, + [2][1][RTW89_QATAR][1][29] = 44, + [2][1][RTW89_QATAR][0][29] = 6, + [2][1][RTW89_UK][1][29] = 44, + [2][1][RTW89_UK][0][29] = 6, + [2][1][RTW89_FCC][1][30] = -16, + [2][1][RTW89_FCC][2][30] = 54, + [2][1][RTW89_ETSI][1][30] = 44, + [2][1][RTW89_ETSI][0][30] = 6, + [2][1][RTW89_MKK][1][30] = 40, + [2][1][RTW89_MKK][0][30] = 2, + [2][1][RTW89_IC][1][30] = -16, + [2][1][RTW89_KCC][1][30] = -14, + [2][1][RTW89_KCC][0][30] = -14, + [2][1][RTW89_ACMA][1][30] = 44, + [2][1][RTW89_ACMA][0][30] = 6, + [2][1][RTW89_CHILE][1][30] = -16, + [2][1][RTW89_QATAR][1][30] = 44, + [2][1][RTW89_QATAR][0][30] = 6, + [2][1][RTW89_UK][1][30] = 44, + [2][1][RTW89_UK][0][30] = 6, + [2][1][RTW89_FCC][1][32] = -16, + [2][1][RTW89_FCC][2][32] = 54, + [2][1][RTW89_ETSI][1][32] = 44, + [2][1][RTW89_ETSI][0][32] = 6, + [2][1][RTW89_MKK][1][32] = 40, + [2][1][RTW89_MKK][0][32] = 2, + [2][1][RTW89_IC][1][32] = -16, + [2][1][RTW89_KCC][1][32] = -14, + [2][1][RTW89_KCC][0][32] = -14, + [2][1][RTW89_ACMA][1][32] = 44, + [2][1][RTW89_ACMA][0][32] = 6, + [2][1][RTW89_CHILE][1][32] = -16, + [2][1][RTW89_QATAR][1][32] = 44, + [2][1][RTW89_QATAR][0][32] = 6, + [2][1][RTW89_UK][1][32] = 44, + [2][1][RTW89_UK][0][32] = 6, + [2][1][RTW89_FCC][1][34] = -16, + [2][1][RTW89_FCC][2][34] = 54, + [2][1][RTW89_ETSI][1][34] = 44, + [2][1][RTW89_ETSI][0][34] = 6, + [2][1][RTW89_MKK][1][34] = 40, + [2][1][RTW89_MKK][0][34] = 2, + [2][1][RTW89_IC][1][34] = -16, + [2][1][RTW89_KCC][1][34] = -14, + [2][1][RTW89_KCC][0][34] = -14, + [2][1][RTW89_ACMA][1][34] = 44, + [2][1][RTW89_ACMA][0][34] = 6, + [2][1][RTW89_CHILE][1][34] = -16, + [2][1][RTW89_QATAR][1][34] = 44, + [2][1][RTW89_QATAR][0][34] = 6, + [2][1][RTW89_UK][1][34] = 44, + [2][1][RTW89_UK][0][34] = 6, + [2][1][RTW89_FCC][1][36] = -16, + [2][1][RTW89_FCC][2][36] = 54, + [2][1][RTW89_ETSI][1][36] = 44, + [2][1][RTW89_ETSI][0][36] = 6, + [2][1][RTW89_MKK][1][36] = 40, + [2][1][RTW89_MKK][0][36] = 2, + [2][1][RTW89_IC][1][36] = -16, + [2][1][RTW89_KCC][1][36] = -14, + [2][1][RTW89_KCC][0][36] = -14, + [2][1][RTW89_ACMA][1][36] = 44, + [2][1][RTW89_ACMA][0][36] = 6, + [2][1][RTW89_CHILE][1][36] = -16, + [2][1][RTW89_QATAR][1][36] = 44, + [2][1][RTW89_QATAR][0][36] = 6, + [2][1][RTW89_UK][1][36] = 44, + [2][1][RTW89_UK][0][36] = 6, + [2][1][RTW89_FCC][1][38] = -16, + [2][1][RTW89_FCC][2][38] = 54, + [2][1][RTW89_ETSI][1][38] = 44, + [2][1][RTW89_ETSI][0][38] = 6, + [2][1][RTW89_MKK][1][38] = 40, + [2][1][RTW89_MKK][0][38] = 2, + [2][1][RTW89_IC][1][38] = -16, + [2][1][RTW89_KCC][1][38] = -14, + [2][1][RTW89_KCC][0][38] = -14, + [2][1][RTW89_ACMA][1][38] = 44, + [2][1][RTW89_ACMA][0][38] = 6, + [2][1][RTW89_CHILE][1][38] = -16, + [2][1][RTW89_QATAR][1][38] = 44, + [2][1][RTW89_QATAR][0][38] = 6, + [2][1][RTW89_UK][1][38] = 44, + [2][1][RTW89_UK][0][38] = 6, + [2][1][RTW89_FCC][1][40] = -16, + [2][1][RTW89_FCC][2][40] = 54, + [2][1][RTW89_ETSI][1][40] = 44, + [2][1][RTW89_ETSI][0][40] = 6, + [2][1][RTW89_MKK][1][40] = 40, + [2][1][RTW89_MKK][0][40] = 2, + [2][1][RTW89_IC][1][40] = -16, + [2][1][RTW89_KCC][1][40] = -14, + [2][1][RTW89_KCC][0][40] = -14, + [2][1][RTW89_ACMA][1][40] = 44, + [2][1][RTW89_ACMA][0][40] = 6, + [2][1][RTW89_CHILE][1][40] = -16, + [2][1][RTW89_QATAR][1][40] = 44, + [2][1][RTW89_QATAR][0][40] = 6, + [2][1][RTW89_UK][1][40] = 44, + [2][1][RTW89_UK][0][40] = 6, + [2][1][RTW89_FCC][1][42] = -16, + [2][1][RTW89_FCC][2][42] = 54, + [2][1][RTW89_ETSI][1][42] = 44, + [2][1][RTW89_ETSI][0][42] = 6, + [2][1][RTW89_MKK][1][42] = 40, + [2][1][RTW89_MKK][0][42] = 2, + [2][1][RTW89_IC][1][42] = -16, + [2][1][RTW89_KCC][1][42] = -14, + [2][1][RTW89_KCC][0][42] = -14, + [2][1][RTW89_ACMA][1][42] = 44, + [2][1][RTW89_ACMA][0][42] = 6, + [2][1][RTW89_CHILE][1][42] = -16, + [2][1][RTW89_QATAR][1][42] = 44, + [2][1][RTW89_QATAR][0][42] = 6, + [2][1][RTW89_UK][1][42] = 44, + [2][1][RTW89_UK][0][42] = 6, + [2][1][RTW89_FCC][1][44] = -16, + [2][1][RTW89_FCC][2][44] = 54, + [2][1][RTW89_ETSI][1][44] = 44, + [2][1][RTW89_ETSI][0][44] = 6, + [2][1][RTW89_MKK][1][44] = 16, + [2][1][RTW89_MKK][0][44] = 2, + [2][1][RTW89_IC][1][44] = -16, + [2][1][RTW89_KCC][1][44] = -14, + [2][1][RTW89_KCC][0][44] = -14, + [2][1][RTW89_ACMA][1][44] = 44, + [2][1][RTW89_ACMA][0][44] = 6, + [2][1][RTW89_CHILE][1][44] = -16, + [2][1][RTW89_QATAR][1][44] = 44, + [2][1][RTW89_QATAR][0][44] = 6, + [2][1][RTW89_UK][1][44] = 44, + [2][1][RTW89_UK][0][44] = 6, + [2][1][RTW89_FCC][1][45] = -16, + [2][1][RTW89_FCC][2][45] = 127, + [2][1][RTW89_ETSI][1][45] = 127, + [2][1][RTW89_ETSI][0][45] = 127, + [2][1][RTW89_MKK][1][45] = 127, + [2][1][RTW89_MKK][0][45] = 127, + [2][1][RTW89_IC][1][45] = -16, + [2][1][RTW89_KCC][1][45] = -14, + [2][1][RTW89_KCC][0][45] = 127, + [2][1][RTW89_ACMA][1][45] = 127, + [2][1][RTW89_ACMA][0][45] = 127, + [2][1][RTW89_CHILE][1][45] = 127, + [2][1][RTW89_QATAR][1][45] = 127, + [2][1][RTW89_QATAR][0][45] = 127, + [2][1][RTW89_UK][1][45] = 127, + [2][1][RTW89_UK][0][45] = 127, + [2][1][RTW89_FCC][1][47] = -16, + [2][1][RTW89_FCC][2][47] = 127, + [2][1][RTW89_ETSI][1][47] = 127, + [2][1][RTW89_ETSI][0][47] = 127, + [2][1][RTW89_MKK][1][47] = 127, + [2][1][RTW89_MKK][0][47] = 127, + [2][1][RTW89_IC][1][47] = -16, + [2][1][RTW89_KCC][1][47] = -14, + [2][1][RTW89_KCC][0][47] = 127, + [2][1][RTW89_ACMA][1][47] = 127, + [2][1][RTW89_ACMA][0][47] = 127, + [2][1][RTW89_CHILE][1][47] = 127, + [2][1][RTW89_QATAR][1][47] = 127, + [2][1][RTW89_QATAR][0][47] = 127, + [2][1][RTW89_UK][1][47] = 127, + [2][1][RTW89_UK][0][47] = 127, + [2][1][RTW89_FCC][1][49] = -16, + [2][1][RTW89_FCC][2][49] = 127, + [2][1][RTW89_ETSI][1][49] = 127, + [2][1][RTW89_ETSI][0][49] = 127, + [2][1][RTW89_MKK][1][49] = 127, + [2][1][RTW89_MKK][0][49] = 127, + [2][1][RTW89_IC][1][49] = -16, + [2][1][RTW89_KCC][1][49] = -14, + [2][1][RTW89_KCC][0][49] = 127, + [2][1][RTW89_ACMA][1][49] = 127, + [2][1][RTW89_ACMA][0][49] = 127, + [2][1][RTW89_CHILE][1][49] = 127, + [2][1][RTW89_QATAR][1][49] = 127, + [2][1][RTW89_QATAR][0][49] = 127, + [2][1][RTW89_UK][1][49] = 127, + [2][1][RTW89_UK][0][49] = 127, + [2][1][RTW89_FCC][1][51] = -16, + [2][1][RTW89_FCC][2][51] = 127, + [2][1][RTW89_ETSI][1][51] = 127, + [2][1][RTW89_ETSI][0][51] = 127, + [2][1][RTW89_MKK][1][51] = 127, + [2][1][RTW89_MKK][0][51] = 127, + [2][1][RTW89_IC][1][51] = -16, + [2][1][RTW89_KCC][1][51] = -14, + [2][1][RTW89_KCC][0][51] = 127, + [2][1][RTW89_ACMA][1][51] = 127, + [2][1][RTW89_ACMA][0][51] = 127, + [2][1][RTW89_CHILE][1][51] = 127, + [2][1][RTW89_QATAR][1][51] = 127, + [2][1][RTW89_QATAR][0][51] = 127, + [2][1][RTW89_UK][1][51] = 127, + [2][1][RTW89_UK][0][51] = 127, + [2][1][RTW89_FCC][1][53] = -16, + [2][1][RTW89_FCC][2][53] = 127, + [2][1][RTW89_ETSI][1][53] = 127, + [2][1][RTW89_ETSI][0][53] = 127, + [2][1][RTW89_MKK][1][53] = 127, + [2][1][RTW89_MKK][0][53] = 127, + [2][1][RTW89_IC][1][53] = -16, + [2][1][RTW89_KCC][1][53] = -14, + [2][1][RTW89_KCC][0][53] = 127, + [2][1][RTW89_ACMA][1][53] = 127, + [2][1][RTW89_ACMA][0][53] = 127, + [2][1][RTW89_CHILE][1][53] = 127, + [2][1][RTW89_QATAR][1][53] = 127, + [2][1][RTW89_QATAR][0][53] = 127, + [2][1][RTW89_UK][1][53] = 127, + [2][1][RTW89_UK][0][53] = 127, + [2][1][RTW89_FCC][1][55] = -16, + [2][1][RTW89_FCC][2][55] = 54, + [2][1][RTW89_ETSI][1][55] = 127, + [2][1][RTW89_ETSI][0][55] = 127, + [2][1][RTW89_MKK][1][55] = 127, + [2][1][RTW89_MKK][0][55] = 127, + [2][1][RTW89_IC][1][55] = -16, + [2][1][RTW89_KCC][1][55] = -14, + [2][1][RTW89_KCC][0][55] = 127, + [2][1][RTW89_ACMA][1][55] = 127, + [2][1][RTW89_ACMA][0][55] = 127, + [2][1][RTW89_CHILE][1][55] = 127, + [2][1][RTW89_QATAR][1][55] = 127, + [2][1][RTW89_QATAR][0][55] = 127, + [2][1][RTW89_UK][1][55] = 127, + [2][1][RTW89_UK][0][55] = 127, + [2][1][RTW89_FCC][1][57] = -16, + [2][1][RTW89_FCC][2][57] = 54, + [2][1][RTW89_ETSI][1][57] = 127, + [2][1][RTW89_ETSI][0][57] = 127, + [2][1][RTW89_MKK][1][57] = 127, + [2][1][RTW89_MKK][0][57] = 127, + [2][1][RTW89_IC][1][57] = -16, + [2][1][RTW89_KCC][1][57] = -14, + [2][1][RTW89_KCC][0][57] = 127, + [2][1][RTW89_ACMA][1][57] = 127, + [2][1][RTW89_ACMA][0][57] = 127, + [2][1][RTW89_CHILE][1][57] = 127, + [2][1][RTW89_QATAR][1][57] = 127, + [2][1][RTW89_QATAR][0][57] = 127, + [2][1][RTW89_UK][1][57] = 127, + [2][1][RTW89_UK][0][57] = 127, + [2][1][RTW89_FCC][1][59] = -16, + [2][1][RTW89_FCC][2][59] = 54, + [2][1][RTW89_ETSI][1][59] = 127, + [2][1][RTW89_ETSI][0][59] = 127, + [2][1][RTW89_MKK][1][59] = 127, + [2][1][RTW89_MKK][0][59] = 127, + [2][1][RTW89_IC][1][59] = -16, + [2][1][RTW89_KCC][1][59] = -14, + [2][1][RTW89_KCC][0][59] = 127, + [2][1][RTW89_ACMA][1][59] = 127, + [2][1][RTW89_ACMA][0][59] = 127, + [2][1][RTW89_CHILE][1][59] = 127, + [2][1][RTW89_QATAR][1][59] = 127, + [2][1][RTW89_QATAR][0][59] = 127, + [2][1][RTW89_UK][1][59] = 127, + [2][1][RTW89_UK][0][59] = 127, + [2][1][RTW89_FCC][1][60] = -16, + [2][1][RTW89_FCC][2][60] = 54, + [2][1][RTW89_ETSI][1][60] = 127, + [2][1][RTW89_ETSI][0][60] = 127, + [2][1][RTW89_MKK][1][60] = 127, + [2][1][RTW89_MKK][0][60] = 127, + [2][1][RTW89_IC][1][60] = -16, + [2][1][RTW89_KCC][1][60] = -14, + [2][1][RTW89_KCC][0][60] = 127, + [2][1][RTW89_ACMA][1][60] = 127, + [2][1][RTW89_ACMA][0][60] = 127, + [2][1][RTW89_CHILE][1][60] = 127, + [2][1][RTW89_QATAR][1][60] = 127, + [2][1][RTW89_QATAR][0][60] = 127, + [2][1][RTW89_UK][1][60] = 127, + [2][1][RTW89_UK][0][60] = 127, + [2][1][RTW89_FCC][1][62] = -16, + [2][1][RTW89_FCC][2][62] = 54, + [2][1][RTW89_ETSI][1][62] = 127, + [2][1][RTW89_ETSI][0][62] = 127, + [2][1][RTW89_MKK][1][62] = 127, + [2][1][RTW89_MKK][0][62] = 127, + [2][1][RTW89_IC][1][62] = -16, + [2][1][RTW89_KCC][1][62] = -14, + [2][1][RTW89_KCC][0][62] = 127, + [2][1][RTW89_ACMA][1][62] = 127, + [2][1][RTW89_ACMA][0][62] = 127, + [2][1][RTW89_CHILE][1][62] = 127, + [2][1][RTW89_QATAR][1][62] = 127, + [2][1][RTW89_QATAR][0][62] = 127, + [2][1][RTW89_UK][1][62] = 127, + [2][1][RTW89_UK][0][62] = 127, + [2][1][RTW89_FCC][1][64] = -16, + [2][1][RTW89_FCC][2][64] = 54, + [2][1][RTW89_ETSI][1][64] = 127, + [2][1][RTW89_ETSI][0][64] = 127, + [2][1][RTW89_MKK][1][64] = 127, + [2][1][RTW89_MKK][0][64] = 127, + [2][1][RTW89_IC][1][64] = -16, + [2][1][RTW89_KCC][1][64] = -14, + [2][1][RTW89_KCC][0][64] = 127, + [2][1][RTW89_ACMA][1][64] = 127, + [2][1][RTW89_ACMA][0][64] = 127, + [2][1][RTW89_CHILE][1][64] = 127, + [2][1][RTW89_QATAR][1][64] = 127, + [2][1][RTW89_QATAR][0][64] = 127, + [2][1][RTW89_UK][1][64] = 127, + [2][1][RTW89_UK][0][64] = 127, + [2][1][RTW89_FCC][1][66] = -16, + [2][1][RTW89_FCC][2][66] = 54, + [2][1][RTW89_ETSI][1][66] = 127, + [2][1][RTW89_ETSI][0][66] = 127, + [2][1][RTW89_MKK][1][66] = 127, + [2][1][RTW89_MKK][0][66] = 127, + [2][1][RTW89_IC][1][66] = -16, + [2][1][RTW89_KCC][1][66] = -14, + [2][1][RTW89_KCC][0][66] = 127, + [2][1][RTW89_ACMA][1][66] = 127, + [2][1][RTW89_ACMA][0][66] = 127, + [2][1][RTW89_CHILE][1][66] = 127, + [2][1][RTW89_QATAR][1][66] = 127, + [2][1][RTW89_QATAR][0][66] = 127, + [2][1][RTW89_UK][1][66] = 127, + [2][1][RTW89_UK][0][66] = 127, + [2][1][RTW89_FCC][1][68] = -16, + [2][1][RTW89_FCC][2][68] = 54, + [2][1][RTW89_ETSI][1][68] = 127, + [2][1][RTW89_ETSI][0][68] = 127, + [2][1][RTW89_MKK][1][68] = 127, + [2][1][RTW89_MKK][0][68] = 127, + [2][1][RTW89_IC][1][68] = -16, + [2][1][RTW89_KCC][1][68] = -14, + [2][1][RTW89_KCC][0][68] = 127, + [2][1][RTW89_ACMA][1][68] = 127, + [2][1][RTW89_ACMA][0][68] = 127, + [2][1][RTW89_CHILE][1][68] = 127, + [2][1][RTW89_QATAR][1][68] = 127, + [2][1][RTW89_QATAR][0][68] = 127, + [2][1][RTW89_UK][1][68] = 127, + [2][1][RTW89_UK][0][68] = 127, + [2][1][RTW89_FCC][1][70] = -16, + [2][1][RTW89_FCC][2][70] = 56, + [2][1][RTW89_ETSI][1][70] = 127, + [2][1][RTW89_ETSI][0][70] = 127, + [2][1][RTW89_MKK][1][70] = 127, + [2][1][RTW89_MKK][0][70] = 127, + [2][1][RTW89_IC][1][70] = -16, + [2][1][RTW89_KCC][1][70] = -14, + [2][1][RTW89_KCC][0][70] = 127, + [2][1][RTW89_ACMA][1][70] = 127, + [2][1][RTW89_ACMA][0][70] = 127, + [2][1][RTW89_CHILE][1][70] = 127, + [2][1][RTW89_QATAR][1][70] = 127, + [2][1][RTW89_QATAR][0][70] = 127, + [2][1][RTW89_UK][1][70] = 127, + [2][1][RTW89_UK][0][70] = 127, + [2][1][RTW89_FCC][1][72] = -16, + [2][1][RTW89_FCC][2][72] = 56, + [2][1][RTW89_ETSI][1][72] = 127, + [2][1][RTW89_ETSI][0][72] = 127, + [2][1][RTW89_MKK][1][72] = 127, + [2][1][RTW89_MKK][0][72] = 127, + [2][1][RTW89_IC][1][72] = -16, + [2][1][RTW89_KCC][1][72] = -14, + [2][1][RTW89_KCC][0][72] = 127, + [2][1][RTW89_ACMA][1][72] = 127, + [2][1][RTW89_ACMA][0][72] = 127, + [2][1][RTW89_CHILE][1][72] = 127, + [2][1][RTW89_QATAR][1][72] = 127, + [2][1][RTW89_QATAR][0][72] = 127, + [2][1][RTW89_UK][1][72] = 127, + [2][1][RTW89_UK][0][72] = 127, + [2][1][RTW89_FCC][1][74] = -16, + [2][1][RTW89_FCC][2][74] = 56, + [2][1][RTW89_ETSI][1][74] = 127, + [2][1][RTW89_ETSI][0][74] = 127, + [2][1][RTW89_MKK][1][74] = 127, + [2][1][RTW89_MKK][0][74] = 127, + [2][1][RTW89_IC][1][74] = -16, + [2][1][RTW89_KCC][1][74] = -14, + [2][1][RTW89_KCC][0][74] = 127, + [2][1][RTW89_ACMA][1][74] = 127, + [2][1][RTW89_ACMA][0][74] = 127, + [2][1][RTW89_CHILE][1][74] = 127, + [2][1][RTW89_QATAR][1][74] = 127, + [2][1][RTW89_QATAR][0][74] = 127, + [2][1][RTW89_UK][1][74] = 127, + [2][1][RTW89_UK][0][74] = 127, + [2][1][RTW89_FCC][1][75] = -16, + [2][1][RTW89_FCC][2][75] = 56, + [2][1][RTW89_ETSI][1][75] = 127, + [2][1][RTW89_ETSI][0][75] = 127, + [2][1][RTW89_MKK][1][75] = 127, + [2][1][RTW89_MKK][0][75] = 127, + [2][1][RTW89_IC][1][75] = -16, + [2][1][RTW89_KCC][1][75] = -14, + [2][1][RTW89_KCC][0][75] = 127, + [2][1][RTW89_ACMA][1][75] = 127, + [2][1][RTW89_ACMA][0][75] = 127, + [2][1][RTW89_CHILE][1][75] = 127, + [2][1][RTW89_QATAR][1][75] = 127, + [2][1][RTW89_QATAR][0][75] = 127, + [2][1][RTW89_UK][1][75] = 127, + [2][1][RTW89_UK][0][75] = 127, + [2][1][RTW89_FCC][1][77] = -16, + [2][1][RTW89_FCC][2][77] = 56, + [2][1][RTW89_ETSI][1][77] = 127, + [2][1][RTW89_ETSI][0][77] = 127, + [2][1][RTW89_MKK][1][77] = 127, + [2][1][RTW89_MKK][0][77] = 127, + [2][1][RTW89_IC][1][77] = -16, + [2][1][RTW89_KCC][1][77] = -14, + [2][1][RTW89_KCC][0][77] = 127, + [2][1][RTW89_ACMA][1][77] = 127, + [2][1][RTW89_ACMA][0][77] = 127, + [2][1][RTW89_CHILE][1][77] = 127, + [2][1][RTW89_QATAR][1][77] = 127, + [2][1][RTW89_QATAR][0][77] = 127, + [2][1][RTW89_UK][1][77] = 127, + [2][1][RTW89_UK][0][77] = 127, + [2][1][RTW89_FCC][1][79] = -16, + [2][1][RTW89_FCC][2][79] = 56, + [2][1][RTW89_ETSI][1][79] = 127, + [2][1][RTW89_ETSI][0][79] = 127, + [2][1][RTW89_MKK][1][79] = 127, + [2][1][RTW89_MKK][0][79] = 127, + [2][1][RTW89_IC][1][79] = -16, + [2][1][RTW89_KCC][1][79] = -14, + [2][1][RTW89_KCC][0][79] = 127, + [2][1][RTW89_ACMA][1][79] = 127, + [2][1][RTW89_ACMA][0][79] = 127, + [2][1][RTW89_CHILE][1][79] = 127, + [2][1][RTW89_QATAR][1][79] = 127, + [2][1][RTW89_QATAR][0][79] = 127, + [2][1][RTW89_UK][1][79] = 127, + [2][1][RTW89_UK][0][79] = 127, + [2][1][RTW89_FCC][1][81] = -16, + [2][1][RTW89_FCC][2][81] = 56, + [2][1][RTW89_ETSI][1][81] = 127, + [2][1][RTW89_ETSI][0][81] = 127, + [2][1][RTW89_MKK][1][81] = 127, + [2][1][RTW89_MKK][0][81] = 127, + [2][1][RTW89_IC][1][81] = -16, + [2][1][RTW89_KCC][1][81] = -14, + [2][1][RTW89_KCC][0][81] = 127, + [2][1][RTW89_ACMA][1][81] = 127, + [2][1][RTW89_ACMA][0][81] = 127, + [2][1][RTW89_CHILE][1][81] = 127, + [2][1][RTW89_QATAR][1][81] = 127, + [2][1][RTW89_QATAR][0][81] = 127, + [2][1][RTW89_UK][1][81] = 127, + [2][1][RTW89_UK][0][81] = 127, + [2][1][RTW89_FCC][1][83] = -16, + [2][1][RTW89_FCC][2][83] = 56, + [2][1][RTW89_ETSI][1][83] = 127, + [2][1][RTW89_ETSI][0][83] = 127, + [2][1][RTW89_MKK][1][83] = 127, + [2][1][RTW89_MKK][0][83] = 127, + [2][1][RTW89_IC][1][83] = -16, + [2][1][RTW89_KCC][1][83] = -14, + [2][1][RTW89_KCC][0][83] = 127, + [2][1][RTW89_ACMA][1][83] = 127, + [2][1][RTW89_ACMA][0][83] = 127, + [2][1][RTW89_CHILE][1][83] = 127, + [2][1][RTW89_QATAR][1][83] = 127, + [2][1][RTW89_QATAR][0][83] = 127, + [2][1][RTW89_UK][1][83] = 127, + [2][1][RTW89_UK][0][83] = 127, + [2][1][RTW89_FCC][1][85] = -18, + [2][1][RTW89_FCC][2][85] = 56, + [2][1][RTW89_ETSI][1][85] = 127, + [2][1][RTW89_ETSI][0][85] = 127, + [2][1][RTW89_MKK][1][85] = 127, + [2][1][RTW89_MKK][0][85] = 127, + [2][1][RTW89_IC][1][85] = -18, + [2][1][RTW89_KCC][1][85] = -14, + [2][1][RTW89_KCC][0][85] = 127, + [2][1][RTW89_ACMA][1][85] = 127, + [2][1][RTW89_ACMA][0][85] = 127, + [2][1][RTW89_CHILE][1][85] = 127, + [2][1][RTW89_QATAR][1][85] = 127, + [2][1][RTW89_QATAR][0][85] = 127, + [2][1][RTW89_UK][1][85] = 127, + [2][1][RTW89_UK][0][85] = 127, + [2][1][RTW89_FCC][1][87] = -16, + [2][1][RTW89_FCC][2][87] = 127, + [2][1][RTW89_ETSI][1][87] = 127, + [2][1][RTW89_ETSI][0][87] = 127, + [2][1][RTW89_MKK][1][87] = 127, + [2][1][RTW89_MKK][0][87] = 127, + [2][1][RTW89_IC][1][87] = -16, + [2][1][RTW89_KCC][1][87] = -14, + [2][1][RTW89_KCC][0][87] = 127, + [2][1][RTW89_ACMA][1][87] = 127, + [2][1][RTW89_ACMA][0][87] = 127, + [2][1][RTW89_CHILE][1][87] = 127, + [2][1][RTW89_QATAR][1][87] = 127, + [2][1][RTW89_QATAR][0][87] = 127, + [2][1][RTW89_UK][1][87] = 127, + [2][1][RTW89_UK][0][87] = 127, + [2][1][RTW89_FCC][1][89] = -16, + [2][1][RTW89_FCC][2][89] = 127, + [2][1][RTW89_ETSI][1][89] = 127, + [2][1][RTW89_ETSI][0][89] = 127, + [2][1][RTW89_MKK][1][89] = 127, + [2][1][RTW89_MKK][0][89] = 127, + [2][1][RTW89_IC][1][89] = -16, + [2][1][RTW89_KCC][1][89] = -14, + [2][1][RTW89_KCC][0][89] = 127, + [2][1][RTW89_ACMA][1][89] = 127, + [2][1][RTW89_ACMA][0][89] = 127, + [2][1][RTW89_CHILE][1][89] = 127, + [2][1][RTW89_QATAR][1][89] = 127, + [2][1][RTW89_QATAR][0][89] = 127, + [2][1][RTW89_UK][1][89] = 127, + [2][1][RTW89_UK][0][89] = 127, + [2][1][RTW89_FCC][1][90] = -16, + [2][1][RTW89_FCC][2][90] = 127, + [2][1][RTW89_ETSI][1][90] = 127, + [2][1][RTW89_ETSI][0][90] = 127, + [2][1][RTW89_MKK][1][90] = 127, + [2][1][RTW89_MKK][0][90] = 127, + [2][1][RTW89_IC][1][90] = -16, + [2][1][RTW89_KCC][1][90] = -14, + [2][1][RTW89_KCC][0][90] = 127, + [2][1][RTW89_ACMA][1][90] = 127, + [2][1][RTW89_ACMA][0][90] = 127, + [2][1][RTW89_CHILE][1][90] = 127, + [2][1][RTW89_QATAR][1][90] = 127, + [2][1][RTW89_QATAR][0][90] = 127, + [2][1][RTW89_UK][1][90] = 127, + [2][1][RTW89_UK][0][90] = 127, + [2][1][RTW89_FCC][1][92] = -16, + [2][1][RTW89_FCC][2][92] = 127, + [2][1][RTW89_ETSI][1][92] = 127, + [2][1][RTW89_ETSI][0][92] = 127, + [2][1][RTW89_MKK][1][92] = 127, + [2][1][RTW89_MKK][0][92] = 127, + [2][1][RTW89_IC][1][92] = -16, + [2][1][RTW89_KCC][1][92] = -14, + [2][1][RTW89_KCC][0][92] = 127, + [2][1][RTW89_ACMA][1][92] = 127, + [2][1][RTW89_ACMA][0][92] = 127, + [2][1][RTW89_CHILE][1][92] = 127, + [2][1][RTW89_QATAR][1][92] = 127, + [2][1][RTW89_QATAR][0][92] = 127, + [2][1][RTW89_UK][1][92] = 127, + [2][1][RTW89_UK][0][92] = 127, + [2][1][RTW89_FCC][1][94] = -16, + [2][1][RTW89_FCC][2][94] = 127, + [2][1][RTW89_ETSI][1][94] = 127, + [2][1][RTW89_ETSI][0][94] = 127, + [2][1][RTW89_MKK][1][94] = 127, + [2][1][RTW89_MKK][0][94] = 127, + [2][1][RTW89_IC][1][94] = -16, + [2][1][RTW89_KCC][1][94] = -14, + [2][1][RTW89_KCC][0][94] = 127, + [2][1][RTW89_ACMA][1][94] = 127, + [2][1][RTW89_ACMA][0][94] = 127, + [2][1][RTW89_CHILE][1][94] = 127, + [2][1][RTW89_QATAR][1][94] = 127, + [2][1][RTW89_QATAR][0][94] = 127, + [2][1][RTW89_UK][1][94] = 127, + [2][1][RTW89_UK][0][94] = 127, + [2][1][RTW89_FCC][1][96] = -16, + [2][1][RTW89_FCC][2][96] = 127, + [2][1][RTW89_ETSI][1][96] = 127, + [2][1][RTW89_ETSI][0][96] = 127, + [2][1][RTW89_MKK][1][96] = 127, + [2][1][RTW89_MKK][0][96] = 127, + [2][1][RTW89_IC][1][96] = -16, + [2][1][RTW89_KCC][1][96] = -14, + [2][1][RTW89_KCC][0][96] = 127, + [2][1][RTW89_ACMA][1][96] = 127, + [2][1][RTW89_ACMA][0][96] = 127, + [2][1][RTW89_CHILE][1][96] = 127, + [2][1][RTW89_QATAR][1][96] = 127, + [2][1][RTW89_QATAR][0][96] = 127, + [2][1][RTW89_UK][1][96] = 127, + [2][1][RTW89_UK][0][96] = 127, + [2][1][RTW89_FCC][1][98] = -16, + [2][1][RTW89_FCC][2][98] = 127, + [2][1][RTW89_ETSI][1][98] = 127, + [2][1][RTW89_ETSI][0][98] = 127, + [2][1][RTW89_MKK][1][98] = 127, + [2][1][RTW89_MKK][0][98] = 127, + [2][1][RTW89_IC][1][98] = -16, + [2][1][RTW89_KCC][1][98] = -14, + [2][1][RTW89_KCC][0][98] = 127, + [2][1][RTW89_ACMA][1][98] = 127, + [2][1][RTW89_ACMA][0][98] = 127, + [2][1][RTW89_CHILE][1][98] = 127, + [2][1][RTW89_QATAR][1][98] = 127, + [2][1][RTW89_QATAR][0][98] = 127, + [2][1][RTW89_UK][1][98] = 127, + [2][1][RTW89_UK][0][98] = 127, + [2][1][RTW89_FCC][1][100] = -16, + [2][1][RTW89_FCC][2][100] = 127, + [2][1][RTW89_ETSI][1][100] = 127, + [2][1][RTW89_ETSI][0][100] = 127, + [2][1][RTW89_MKK][1][100] = 127, + [2][1][RTW89_MKK][0][100] = 127, + [2][1][RTW89_IC][1][100] = -16, + [2][1][RTW89_KCC][1][100] = -14, + [2][1][RTW89_KCC][0][100] = 127, + [2][1][RTW89_ACMA][1][100] = 127, + [2][1][RTW89_ACMA][0][100] = 127, + [2][1][RTW89_CHILE][1][100] = 127, + [2][1][RTW89_QATAR][1][100] = 127, + [2][1][RTW89_QATAR][0][100] = 127, + [2][1][RTW89_UK][1][100] = 127, + [2][1][RTW89_UK][0][100] = 127, + [2][1][RTW89_FCC][1][102] = -16, + [2][1][RTW89_FCC][2][102] = 127, + [2][1][RTW89_ETSI][1][102] = 127, + [2][1][RTW89_ETSI][0][102] = 127, + [2][1][RTW89_MKK][1][102] = 127, + [2][1][RTW89_MKK][0][102] = 127, + [2][1][RTW89_IC][1][102] = -16, + [2][1][RTW89_KCC][1][102] = -14, + [2][1][RTW89_KCC][0][102] = 127, + [2][1][RTW89_ACMA][1][102] = 127, + [2][1][RTW89_ACMA][0][102] = 127, + [2][1][RTW89_CHILE][1][102] = 127, + [2][1][RTW89_QATAR][1][102] = 127, + [2][1][RTW89_QATAR][0][102] = 127, + [2][1][RTW89_UK][1][102] = 127, + [2][1][RTW89_UK][0][102] = 127, + [2][1][RTW89_FCC][1][104] = -16, + [2][1][RTW89_FCC][2][104] = 127, + [2][1][RTW89_ETSI][1][104] = 127, + [2][1][RTW89_ETSI][0][104] = 127, + [2][1][RTW89_MKK][1][104] = 127, + [2][1][RTW89_MKK][0][104] = 127, + [2][1][RTW89_IC][1][104] = -16, + [2][1][RTW89_KCC][1][104] = -14, + [2][1][RTW89_KCC][0][104] = 127, + [2][1][RTW89_ACMA][1][104] = 127, + [2][1][RTW89_ACMA][0][104] = 127, + [2][1][RTW89_CHILE][1][104] = 127, + [2][1][RTW89_QATAR][1][104] = 127, + [2][1][RTW89_QATAR][0][104] = 127, + [2][1][RTW89_UK][1][104] = 127, + [2][1][RTW89_UK][0][104] = 127, + [2][1][RTW89_FCC][1][105] = -16, + [2][1][RTW89_FCC][2][105] = 127, + [2][1][RTW89_ETSI][1][105] = 127, + [2][1][RTW89_ETSI][0][105] = 127, + [2][1][RTW89_MKK][1][105] = 127, + [2][1][RTW89_MKK][0][105] = 127, + [2][1][RTW89_IC][1][105] = -16, + [2][1][RTW89_KCC][1][105] = -14, + [2][1][RTW89_KCC][0][105] = 127, + [2][1][RTW89_ACMA][1][105] = 127, + [2][1][RTW89_ACMA][0][105] = 127, + [2][1][RTW89_CHILE][1][105] = 127, + [2][1][RTW89_QATAR][1][105] = 127, + [2][1][RTW89_QATAR][0][105] = 127, + [2][1][RTW89_UK][1][105] = 127, + [2][1][RTW89_UK][0][105] = 127, + [2][1][RTW89_FCC][1][107] = -12, + [2][1][RTW89_FCC][2][107] = 127, + [2][1][RTW89_ETSI][1][107] = 127, + [2][1][RTW89_ETSI][0][107] = 127, + [2][1][RTW89_MKK][1][107] = 127, + [2][1][RTW89_MKK][0][107] = 127, + [2][1][RTW89_IC][1][107] = -12, + [2][1][RTW89_KCC][1][107] = -14, + [2][1][RTW89_KCC][0][107] = 127, + [2][1][RTW89_ACMA][1][107] = 127, + [2][1][RTW89_ACMA][0][107] = 127, + [2][1][RTW89_CHILE][1][107] = 127, + [2][1][RTW89_QATAR][1][107] = 127, + [2][1][RTW89_QATAR][0][107] = 127, + [2][1][RTW89_UK][1][107] = 127, + [2][1][RTW89_UK][0][107] = 127, + [2][1][RTW89_FCC][1][109] = -10, + [2][1][RTW89_FCC][2][109] = 127, + [2][1][RTW89_ETSI][1][109] = 127, + [2][1][RTW89_ETSI][0][109] = 127, + [2][1][RTW89_MKK][1][109] = 127, + [2][1][RTW89_MKK][0][109] = 127, + [2][1][RTW89_IC][1][109] = -10, + [2][1][RTW89_KCC][1][109] = 127, + [2][1][RTW89_KCC][0][109] = 127, + [2][1][RTW89_ACMA][1][109] = 127, + [2][1][RTW89_ACMA][0][109] = 127, + [2][1][RTW89_CHILE][1][109] = 127, + [2][1][RTW89_QATAR][1][109] = 127, + [2][1][RTW89_QATAR][0][109] = 127, + [2][1][RTW89_UK][1][109] = 127, + [2][1][RTW89_UK][0][109] = 127, + [2][1][RTW89_FCC][1][111] = 127, + [2][1][RTW89_FCC][2][111] = 127, + [2][1][RTW89_ETSI][1][111] = 127, + [2][1][RTW89_ETSI][0][111] = 127, + [2][1][RTW89_MKK][1][111] = 127, + [2][1][RTW89_MKK][0][111] = 127, + [2][1][RTW89_IC][1][111] = 127, + [2][1][RTW89_KCC][1][111] = 127, + [2][1][RTW89_KCC][0][111] = 127, + [2][1][RTW89_ACMA][1][111] = 127, + [2][1][RTW89_ACMA][0][111] = 127, + [2][1][RTW89_CHILE][1][111] = 127, + [2][1][RTW89_QATAR][1][111] = 127, + [2][1][RTW89_QATAR][0][111] = 127, + [2][1][RTW89_UK][1][111] = 127, + [2][1][RTW89_UK][0][111] = 127, + [2][1][RTW89_FCC][1][113] = 127, + [2][1][RTW89_FCC][2][113] = 127, + [2][1][RTW89_ETSI][1][113] = 127, + [2][1][RTW89_ETSI][0][113] = 127, + [2][1][RTW89_MKK][1][113] = 127, + [2][1][RTW89_MKK][0][113] = 127, + [2][1][RTW89_IC][1][113] = 127, + [2][1][RTW89_KCC][1][113] = 127, + [2][1][RTW89_KCC][0][113] = 127, + [2][1][RTW89_ACMA][1][113] = 127, + [2][1][RTW89_ACMA][0][113] = 127, + [2][1][RTW89_CHILE][1][113] = 127, + [2][1][RTW89_QATAR][1][113] = 127, + [2][1][RTW89_QATAR][0][113] = 127, + [2][1][RTW89_UK][1][113] = 127, + [2][1][RTW89_UK][0][113] = 127, + [2][1][RTW89_FCC][1][115] = 127, + [2][1][RTW89_FCC][2][115] = 127, + [2][1][RTW89_ETSI][1][115] = 127, + [2][1][RTW89_ETSI][0][115] = 127, + [2][1][RTW89_MKK][1][115] = 127, + [2][1][RTW89_MKK][0][115] = 127, + [2][1][RTW89_IC][1][115] = 127, + [2][1][RTW89_KCC][1][115] = 127, + [2][1][RTW89_KCC][0][115] = 127, + [2][1][RTW89_ACMA][1][115] = 127, + [2][1][RTW89_ACMA][0][115] = 127, + [2][1][RTW89_CHILE][1][115] = 127, + [2][1][RTW89_QATAR][1][115] = 127, + [2][1][RTW89_QATAR][0][115] = 127, + [2][1][RTW89_UK][1][115] = 127, + [2][1][RTW89_UK][0][115] = 127, + [2][1][RTW89_FCC][1][117] = 127, + [2][1][RTW89_FCC][2][117] = 127, + [2][1][RTW89_ETSI][1][117] = 127, + [2][1][RTW89_ETSI][0][117] = 127, + [2][1][RTW89_MKK][1][117] = 127, + [2][1][RTW89_MKK][0][117] = 127, + [2][1][RTW89_IC][1][117] = 127, + [2][1][RTW89_KCC][1][117] = 127, + [2][1][RTW89_KCC][0][117] = 127, + [2][1][RTW89_ACMA][1][117] = 127, + [2][1][RTW89_ACMA][0][117] = 127, + [2][1][RTW89_CHILE][1][117] = 127, + [2][1][RTW89_QATAR][1][117] = 127, + [2][1][RTW89_QATAR][0][117] = 127, + [2][1][RTW89_UK][1][117] = 127, + [2][1][RTW89_UK][0][117] = 127, + [2][1][RTW89_FCC][1][119] = 127, + [2][1][RTW89_FCC][2][119] = 127, + [2][1][RTW89_ETSI][1][119] = 127, + [2][1][RTW89_ETSI][0][119] = 127, + [2][1][RTW89_MKK][1][119] = 127, + [2][1][RTW89_MKK][0][119] = 127, + [2][1][RTW89_IC][1][119] = 127, + [2][1][RTW89_KCC][1][119] = 127, + [2][1][RTW89_KCC][0][119] = 127, + [2][1][RTW89_ACMA][1][119] = 127, + [2][1][RTW89_ACMA][0][119] = 127, + [2][1][RTW89_CHILE][1][119] = 127, + [2][1][RTW89_QATAR][1][119] = 127, + [2][1][RTW89_QATAR][0][119] = 127, + [2][1][RTW89_UK][1][119] = 127, + [2][1][RTW89_UK][0][119] = 127, }; const struct rtw89_phy_table rtw89_8852c_phy_bb_table = { -- cgit v1.2.3 From 5883fc2ef8573649ee6a63968ae82e679766b878 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 2 Jun 2023 23:05:56 +0800 Subject: wifi: rtw89: 8852c: update RF radio A/B parameters to R63 Update 8852c radio A/B parameters from internal HALRF_029_00_102 R63. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602150556.36777-9-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8852c_table.c | 5138 +++++++++++++++----- 1 file changed, 4052 insertions(+), 1086 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c index 25871a6fddd2..8fda2c2e9833 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c @@ -2551,19 +2551,27 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0xF0040001, 0x0000000A}, {0xF0050001, 0x0000000B}, {0xF0070001, 0x0000000C}, - {0xF0320001, 0x0000000D}, - {0xF0330001, 0x0000000E}, - {0xF0340001, 0x0000000F}, - {0xF0350001, 0x00000010}, - {0xF0360001, 0x00000011}, - {0xF03F0001, 0x00000012}, - {0xF0400001, 0x00000013}, + {0xF0150001, 0x0000000D}, + {0xF0160001, 0x0000000E}, + {0xF0320001, 0x0000000F}, + {0xF0330001, 0x00000010}, + {0xF0340001, 0x00000011}, + {0xF0350001, 0x00000012}, + {0xF0360001, 0x00000013}, + {0xF03F0001, 0x00000014}, + {0xF0400001, 0x00000015}, {0x005, 0x00000000}, {0x10005, 0x00000000}, {0x000, 0x00030001}, {0x10000, 0x00030000}, {0x018, 0x00011124}, {0x10018, 0x00011124}, + {0x0A3, 0x000B9204}, + {0x0AD, 0x00091E0F}, + {0x05D, 0x00001012}, + {0x05C, 0x00061C5C}, + {0x062, 0x00055220}, + {0x0D3, 0x00000103}, {0x0EF, 0x00080000}, {0x033, 0x00000001}, {0x03E, 0x00000620}, @@ -2636,6 +2644,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x067, 0x0000D300}, {0x0DA, 0x000D4000}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x067, 0x0000D300}, + {0x0DA, 0x000D4000}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x067, 0x0000D300}, + {0x0DA, 0x000D4000}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x067, 0x0000D300}, {0x0DA, 0x000D4000}, @@ -2716,6 +2730,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000CC}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000CC}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000CC}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000CC}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000CC}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -2760,6 +2778,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000C4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000C4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000C4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000C4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000C4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -2804,6 +2826,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000BC}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000BC}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000BC}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000BC}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000BC}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -2848,6 +2874,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000B4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000B4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000B4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000B4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000B4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -2892,6 +2922,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000AC}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000AC}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000AC}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000AC}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000AC}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -2936,6 +2970,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -2980,6 +3018,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000009C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000009C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000009C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000009C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000009C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3024,6 +3066,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000094}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000094}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000094}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000094}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000094}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3068,6 +3114,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000008C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000008C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000008C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000008C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000008C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3112,6 +3162,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000084}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000084}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000084}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000084}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000084}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3156,6 +3210,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000BC}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000BC}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000BC}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000BC}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000BC}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3200,6 +3258,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000B4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000B4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000B4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000B4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000B4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3244,6 +3306,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000AC}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000AC}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000AC}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000AC}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000AC}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3288,6 +3354,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000000A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000000A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000000A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3332,6 +3402,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000009C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000009C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000009C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000009C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000009C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3376,6 +3450,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000094}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000094}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000094}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000094}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000094}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3420,6 +3498,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000008C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000008C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000008C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000008C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000008C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3464,6 +3546,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000084}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000084}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000084}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000084}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000084}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3508,6 +3594,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000003C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000003C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000003C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000003C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000003C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3552,6 +3642,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000034}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000034}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000034}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000034}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000034}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3596,6 +3690,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000002C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000002C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000002C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000002C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000002C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3640,6 +3738,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000024}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000024}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000024}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000024}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000024}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3684,6 +3786,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000001C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000001C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000001C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000001C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000001C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3728,6 +3834,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000014}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000014}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000014}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000014}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000014}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3772,6 +3882,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000000C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000000C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000000C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000000C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000000C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3816,6 +3930,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000004}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000004}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000004}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000004}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000004}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3873,6 +3991,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x08F, 0x000D1352}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x08F, 0x000D1352}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x08F, 0x000D1352}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x08F, 0x000D1352}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x08F, 0x000D1352}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -3936,6 +4058,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000007}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000007}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000017}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000017}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000007}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -4472,6 +4598,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000EFFF}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000EFFF}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000EFFF}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000EFFF}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000EFFF}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -4810,6 +4940,32 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x030, 0x00050112}, {0x030, 0x00058101}, {0x030, 0x00060001}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x000085ED}, + {0x030, 0x000105CC}, + {0x030, 0x000184AA}, + {0x030, 0x00020388}, + {0x030, 0x00028377}, + {0x030, 0x00030377}, + {0x030, 0x00038255}, + {0x030, 0x00040244}, + {0x030, 0x00048133}, + {0x030, 0x00050112}, + {0x030, 0x00058101}, + {0x030, 0x00060001}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x000085ED}, + {0x030, 0x000105CC}, + {0x030, 0x000184AA}, + {0x030, 0x00020388}, + {0x030, 0x00028377}, + {0x030, 0x00030377}, + {0x030, 0x00038255}, + {0x030, 0x00040244}, + {0x030, 0x00048133}, + {0x030, 0x00050112}, + {0x030, 0x00058101}, + {0x030, 0x00060001}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x030, 0x000085ED}, {0x030, 0x000105CC}, @@ -5157,6 +5313,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x030, 0x000300FF}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x030, 0x000300FF}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x000300FF}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x000300FF}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x030, 0x000300FF}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5178,96 +5338,568 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x0EF, 0x00000000}, {0x06E, 0x00077A18}, {0x06D, 0x00000C31}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, {0x06A, 0x000E0F8A}, {0x06B, 0x000018A0}, {0x06F, 0x000F81FC}, {0x05E, 0x0000001F}, - {0x0EF, 0x00000200}, - {0x030, 0x0003D407}, - {0x030, 0x00035A87}, - {0x030, 0x0002CF07}, - {0x030, 0x00024F07}, - {0x030, 0x0001CF07}, - {0x030, 0x00014F07}, - {0x030, 0x0000CF07}, - {0x030, 0x00004F07}, - {0x0EF, 0x00000000}, - {0x0EB, 0x00080000}, - {0x030, 0x00008038}, - {0x030, 0x00010038}, - {0x030, 0x00018038}, - {0x030, 0x00020038}, - {0x030, 0x00028038}, - {0x030, 0x00030038}, - {0x030, 0x0003803C}, - {0x030, 0x0004003C}, - {0x030, 0x0004803C}, - {0x030, 0x0005003C}, - {0x030, 0x0005803C}, - {0x030, 0x0006003C}, - {0x030, 0x0006803C}, - {0x030, 0x0007003C}, - {0x0EB, 0x00000000}, - {0x094, 0x000000FC}, - {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000000}, {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0380}, + {0x06B, 0x00003CA0}, + {0x06F, 0x000C01FC}, + {0x05E, 0x0000001F}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0380}, + {0x06B, 0x00003CA0}, + {0x06F, 0x000C01FC}, + {0x05E, 0x0000001F}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x095, 0x00000008}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0xA0000000, 0x00000000}, - {0x095, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x05E, 0x0000001F}, {0xB0000000, 0x00000000}, - {0x0EE, 0x00001000}, - {0x033, 0x00000020}, + {0x0EF, 0x00000200}, {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0xA0000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0xB0000000, 0x00000000}, + {0x0EF, 0x00000000}, + {0x0EB, 0x00080000}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0000803C}, + {0x030, 0x0001003C}, + {0x030, 0x0001803C}, + {0x030, 0x0002003C}, + {0x030, 0x0002803C}, + {0x030, 0x0003003C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0000803C}, + {0x030, 0x0001003C}, + {0x030, 0x0001803C}, + {0x030, 0x0002003C}, + {0x030, 0x0002803C}, + {0x030, 0x0003003C}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0xA0000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0xB0000000, 0x00000000}, + {0x030, 0x0003803C}, + {0x030, 0x0004003C}, + {0x030, 0x0004803C}, + {0x030, 0x0005003C}, + {0x030, 0x0005803C}, + {0x030, 0x0006003C}, + {0x030, 0x0006803C}, + {0x030, 0x0007003C}, + {0x0EB, 0x00000000}, + {0x094, 0x000000FC}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000000}, + {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000000}, + {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000000}, + {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000000}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000000}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000000}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000000}, + {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0xA0000000, 0x00000000}, + {0x095, 0x00000000}, + {0xB0000000, 0x00000000}, + {0x0EE, 0x00001000}, + {0x033, 0x00000020}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000052}, + {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000052}, + {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000052}, + {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000052}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000052}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000052}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000052}, - {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, - {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, - {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5280,6 +5912,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5324,6 +5960,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5368,6 +6008,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5412,6 +6056,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5456,6 +6104,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5500,6 +6152,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5548,6 +6204,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5592,6 +6252,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5636,6 +6300,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5680,6 +6348,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5724,6 +6396,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5768,6 +6444,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5812,6 +6492,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5856,6 +6540,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5900,6 +6588,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5944,6 +6636,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -5988,6 +6684,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -6032,6 +6732,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -6076,6 +6780,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -6120,6 +6828,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -6164,6 +6876,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -6208,6 +6924,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -6252,20 +6972,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0xA0000000, 0x00000000}, {0x03F, 0x00000052}, {0xB0000000, 0x00000000}, @@ -6296,20 +7020,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0xA0000000, 0x00000000}, {0x03F, 0x0000005A}, {0xB0000000, 0x00000000}, @@ -6340,20 +7068,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0xA0000000, 0x00000000}, {0x03F, 0x0000009C}, {0xB0000000, 0x00000000}, @@ -6384,20 +7116,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0xA0000000, 0x00000000}, {0x03F, 0x0000019C}, {0xB0000000, 0x00000000}, @@ -6428,20 +7164,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001A4}, {0xB0000000, 0x00000000}, @@ -6472,20 +7212,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001E6}, {0xB0000000, 0x00000000}, @@ -6516,20 +7260,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000002E6}, {0xB0000000, 0x00000000}, @@ -6560,20 +7308,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000003E6}, {0xB0000000, 0x00000000}, @@ -6604,20 +7356,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0xA0000000, 0x00000000}, {0x03F, 0x00000052}, {0xB0000000, 0x00000000}, @@ -6648,20 +7404,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0xA0000000, 0x00000000}, {0x03F, 0x0000005A}, {0xB0000000, 0x00000000}, @@ -6692,20 +7452,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0xA0000000, 0x00000000}, {0x03F, 0x0000009C}, {0xB0000000, 0x00000000}, @@ -6736,20 +7500,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0xA0000000, 0x00000000}, {0x03F, 0x0000019C}, {0xB0000000, 0x00000000}, @@ -6780,20 +7548,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001A4}, {0xB0000000, 0x00000000}, @@ -6824,20 +7596,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001E6}, {0xB0000000, 0x00000000}, @@ -6868,20 +7644,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000002E6}, {0xB0000000, 0x00000000}, @@ -6912,20 +7692,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000003E6}, {0xB0000000, 0x00000000}, @@ -6956,20 +7740,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0xA0000000, 0x00000000}, {0x03F, 0x00000052}, {0xB0000000, 0x00000000}, @@ -7000,20 +7788,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0xA0000000, 0x00000000}, {0x03F, 0x0000005A}, {0xB0000000, 0x00000000}, @@ -7044,20 +7836,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0xA0000000, 0x00000000}, {0x03F, 0x0000009C}, {0xB0000000, 0x00000000}, @@ -7088,20 +7884,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0xA0000000, 0x00000000}, {0x03F, 0x0000019C}, {0xB0000000, 0x00000000}, @@ -7132,20 +7932,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001A4}, {0xB0000000, 0x00000000}, @@ -7176,20 +7980,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001E6}, {0xB0000000, 0x00000000}, @@ -7220,20 +8028,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000002E6}, {0xB0000000, 0x00000000}, @@ -7264,20 +8076,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000003E6}, {0xB0000000, 0x00000000}, @@ -7308,20 +8124,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0xA0000000, 0x00000000}, {0x03F, 0x00000052}, {0xB0000000, 0x00000000}, @@ -7352,20 +8172,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0xA0000000, 0x00000000}, {0x03F, 0x0000005A}, {0xB0000000, 0x00000000}, @@ -7396,20 +8220,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0xA0000000, 0x00000000}, {0x03F, 0x0000009C}, {0xB0000000, 0x00000000}, @@ -7440,20 +8268,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0xA0000000, 0x00000000}, {0x03F, 0x0000019C}, {0xB0000000, 0x00000000}, @@ -7484,20 +8316,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001A4}, {0xB0000000, 0x00000000}, @@ -7528,20 +8364,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001E6}, {0xB0000000, 0x00000000}, @@ -8711,7 +9551,152 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x000001EF}, + {0x10030, 0x000005E9}, + {0x10030, 0x000009E3}, + {0x10030, 0x00000DDD}, + {0x10030, 0x000011D7}, + {0x10030, 0x0000159F}, + {0x10030, 0x00001999}, + {0x10030, 0x00001D5F}, + {0x10030, 0x00002159}, + {0x10030, 0x0000251F}, + {0x10030, 0x00002919}, + {0x10030, 0x00002CDF}, + {0x10030, 0x000030D9}, + {0x10030, 0x0000349F}, + {0x10030, 0x00003899}, + {0x10030, 0x00003C5F}, + {0x10030, 0x00004059}, + {0x10030, 0x00004453}, + {0x10030, 0x000201EF}, + {0x10030, 0x000205E9}, + {0x10030, 0x000209E3}, + {0x10030, 0x00020DA3}, + {0x10030, 0x00021161}, + {0x10030, 0x0002155B}, + {0x10030, 0x0002191F}, + {0x10030, 0x00021D19}, + {0x10030, 0x000220E1}, + {0x10030, 0x000224DB}, + {0x10030, 0x000228A3}, + {0x10030, 0x00022C9D}, + {0x10030, 0x00023063}, + {0x10030, 0x0002345D}, + {0x10030, 0x00023823}, + {0x10030, 0x00023C1B}, + {0x10030, 0x00024015}, + {0x10030, 0x0002440F}, + {0x10030, 0x000281EF}, + {0x10030, 0x000285E7}, + {0x10030, 0x000289A7}, + {0x10030, 0x00028D65}, + {0x10030, 0x0002915F}, + {0x10030, 0x00029523}, + {0x10030, 0x0002991D}, + {0x10030, 0x00029CE5}, + {0x10030, 0x0002A0DF}, + {0x10030, 0x0002A4A7}, + {0x10030, 0x0002A8A1}, + {0x10030, 0x0002AC67}, + {0x10030, 0x0002B061}, + {0x10030, 0x0002B427}, + {0x10030, 0x0002B821}, + {0x10030, 0x0002BC19}, + {0x10030, 0x0002C013}, + {0x10030, 0x0002C40D}, + {0x10030, 0x000301EF}, + {0x10030, 0x000305E7}, + {0x10030, 0x000309A7}, + {0x10030, 0x00030D65}, + {0x10030, 0x0003115F}, + {0x10030, 0x00031525}, + {0x10030, 0x0003191F}, + {0x10030, 0x00031CE7}, + {0x10030, 0x000320E1}, + {0x10030, 0x000324A9}, + {0x10030, 0x000328A3}, + {0x10030, 0x00032C69}, + {0x10030, 0x00033063}, + {0x10030, 0x00033429}, + {0x10030, 0x00033823}, + {0x10030, 0x00033C1D}, + {0x10030, 0x00034013}, + {0x10030, 0x0003440D}, + {0x10030, 0x000601F1}, + {0x10030, 0x000605E9}, + {0x10030, 0x000609A9}, + {0x10030, 0x00060D65}, + {0x10030, 0x0006115F}, + {0x10030, 0x00061525}, + {0x10030, 0x0006191F}, + {0x10030, 0x00061CE7}, + {0x10030, 0x000620E1}, + {0x10030, 0x000624DB}, + {0x10030, 0x000628A3}, + {0x10030, 0x00062C69}, + {0x10030, 0x00063063}, + {0x10030, 0x00063429}, + {0x10030, 0x00063823}, + {0x10030, 0x00063C1D}, + {0x10030, 0x00064013}, + {0x10030, 0x0006440D}, + {0x10030, 0x000681EF}, + {0x10030, 0x000685E7}, + {0x10030, 0x000689A7}, + {0x10030, 0x00068D61}, + {0x10030, 0x0006915B}, + {0x10030, 0x00069523}, + {0x10030, 0x0006991D}, + {0x10030, 0x00069CE5}, + {0x10030, 0x0006A0DF}, + {0x10030, 0x0006A4A7}, + {0x10030, 0x0006A8A1}, + {0x10030, 0x0006AC67}, + {0x10030, 0x0006B061}, + {0x10030, 0x0006B429}, + {0x10030, 0x0006B823}, + {0x10030, 0x0006BC1D}, + {0x10030, 0x0006C017}, + {0x10030, 0x0006C40D}, + {0x10030, 0x000701EF}, + {0x10030, 0x000705E7}, + {0x10030, 0x000709A7}, + {0x10030, 0x00070D61}, + {0x10030, 0x0007115B}, + {0x10030, 0x00071523}, + {0x10030, 0x0007191D}, + {0x10030, 0x00071D17}, + {0x10030, 0x000720DF}, + {0x10030, 0x000724D9}, + {0x10030, 0x000728A1}, + {0x10030, 0x00072C67}, + {0x10030, 0x00073061}, + {0x10030, 0x00073427}, + {0x10030, 0x00073821}, + {0x10030, 0x00073C1B}, + {0x10030, 0x00074015}, + {0x10030, 0x0007440D}, + {0x10030, 0x000781EF}, + {0x10030, 0x000785E9}, + {0x10030, 0x000789E3}, + {0x10030, 0x00078DA1}, + {0x10030, 0x0007915F}, + {0x10030, 0x00079559}, + {0x10030, 0x00079921}, + {0x10030, 0x00079D1B}, + {0x10030, 0x0007A0E3}, + {0x10030, 0x0007A4DD}, + {0x10030, 0x0007A8D7}, + {0x10030, 0x0007AC9D}, + {0x10030, 0x0007B063}, + {0x10030, 0x0007B45D}, + {0x10030, 0x0007B823}, + {0x10030, 0x0007BC1D}, + {0x10030, 0x0007C017}, + {0x10030, 0x0007C40F}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -8856,7 +9841,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -9001,7 +9986,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -9146,7 +10131,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -9291,7 +10276,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -9436,7 +10421,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -9581,7 +10566,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -9600,60 +10585,60 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x00003C5F}, {0x10030, 0x00004059}, {0x10030, 0x00004453}, - {0x10030, 0x000201A7}, - {0x10030, 0x000205A1}, - {0x10030, 0x0002099B}, - {0x10030, 0x00020D95}, - {0x10030, 0x0002115B}, - {0x10030, 0x00021555}, - {0x10030, 0x00021921}, - {0x10030, 0x00021D1B}, - {0x10030, 0x000220E3}, - {0x10030, 0x000224DD}, + {0x10030, 0x000201EF}, + {0x10030, 0x000205E9}, + {0x10030, 0x000209E3}, + {0x10030, 0x00020DA3}, + {0x10030, 0x00021161}, + {0x10030, 0x0002155B}, + {0x10030, 0x0002191F}, + {0x10030, 0x00021D19}, + {0x10030, 0x000220E1}, + {0x10030, 0x000224DB}, {0x10030, 0x000228A3}, {0x10030, 0x00022C9D}, {0x10030, 0x00023063}, {0x10030, 0x0002345D}, {0x10030, 0x00023823}, - {0x10030, 0x00023C1D}, - {0x10030, 0x00024017}, - {0x10030, 0x00024411}, - {0x10030, 0x000281A9}, - {0x10030, 0x000285A3}, - {0x10030, 0x0002899D}, - {0x10030, 0x00028D97}, - {0x10030, 0x0002915D}, - {0x10030, 0x00029557}, - {0x10030, 0x0002991F}, - {0x10030, 0x00029D19}, - {0x10030, 0x0002A0E1}, - {0x10030, 0x0002A4DB}, + {0x10030, 0x00023C1B}, + {0x10030, 0x00024015}, + {0x10030, 0x0002440F}, + {0x10030, 0x000281EF}, + {0x10030, 0x000285E7}, + {0x10030, 0x000289A7}, + {0x10030, 0x00028D65}, + {0x10030, 0x0002915F}, + {0x10030, 0x00029523}, + {0x10030, 0x0002991D}, + {0x10030, 0x00029CE5}, + {0x10030, 0x0002A0DF}, + {0x10030, 0x0002A4A7}, {0x10030, 0x0002A8A1}, - {0x10030, 0x0002AC9B}, + {0x10030, 0x0002AC67}, {0x10030, 0x0002B061}, - {0x10030, 0x0002B45B}, + {0x10030, 0x0002B427}, {0x10030, 0x0002B821}, - {0x10030, 0x0002BC1B}, - {0x10030, 0x0002C015}, - {0x10030, 0x0002C40F}, - {0x10030, 0x000301A9}, - {0x10030, 0x000305A3}, - {0x10030, 0x0003099D}, - {0x10030, 0x00030D97}, - {0x10030, 0x0003115D}, - {0x10030, 0x00031557}, + {0x10030, 0x0002BC19}, + {0x10030, 0x0002C013}, + {0x10030, 0x0002C40D}, + {0x10030, 0x000301EF}, + {0x10030, 0x000305E7}, + {0x10030, 0x000309A7}, + {0x10030, 0x00030D65}, + {0x10030, 0x0003115F}, + {0x10030, 0x00031525}, {0x10030, 0x0003191F}, - {0x10030, 0x00031D19}, + {0x10030, 0x00031CE7}, {0x10030, 0x000320E1}, - {0x10030, 0x000324DB}, - {0x10030, 0x000328A1}, - {0x10030, 0x00032C9B}, - {0x10030, 0x00033061}, - {0x10030, 0x0003345B}, - {0x10030, 0x00033821}, - {0x10030, 0x00033C1B}, - {0x10030, 0x00034015}, - {0x10030, 0x0003440F}, + {0x10030, 0x000324A9}, + {0x10030, 0x000328A3}, + {0x10030, 0x00032C69}, + {0x10030, 0x00033063}, + {0x10030, 0x00033429}, + {0x10030, 0x00033823}, + {0x10030, 0x00033C1D}, + {0x10030, 0x00034013}, + {0x10030, 0x0003440D}, {0x10030, 0x000601F1}, {0x10030, 0x000605E9}, {0x10030, 0x000609A9}, @@ -9697,7 +10682,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007115B}, {0x10030, 0x00071523}, {0x10030, 0x0007191D}, - {0x10030, 0x00071CE5}, + {0x10030, 0x00071D17}, {0x10030, 0x000720DF}, {0x10030, 0x000724D9}, {0x10030, 0x000728A1}, @@ -9726,7 +10711,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -9804,73 +10789,218 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, + {0x10030, 0x0006B429}, + {0x10030, 0x0006B823}, + {0x10030, 0x0006BC1D}, + {0x10030, 0x0006C017}, + {0x10030, 0x0006C411}, + {0x10030, 0x000701EF}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, + {0x10030, 0x000781EF}, + {0x10030, 0x000785E9}, + {0x10030, 0x000789E3}, + {0x10030, 0x00078DA1}, + {0x10030, 0x0007915F}, + {0x10030, 0x00079559}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x000001EF}, + {0x10030, 0x000005E9}, + {0x10030, 0x000009E3}, + {0x10030, 0x00000DDD}, + {0x10030, 0x000011D7}, + {0x10030, 0x0000159F}, + {0x10030, 0x00001999}, + {0x10030, 0x00001D5F}, + {0x10030, 0x00002159}, + {0x10030, 0x0000251F}, + {0x10030, 0x00002919}, + {0x10030, 0x00002CDF}, + {0x10030, 0x000030D9}, + {0x10030, 0x0000349F}, + {0x10030, 0x00003899}, + {0x10030, 0x00003C5F}, + {0x10030, 0x00004059}, + {0x10030, 0x00004453}, + {0x10030, 0x000201A7}, + {0x10030, 0x000205A1}, + {0x10030, 0x0002099B}, + {0x10030, 0x00020D95}, + {0x10030, 0x0002115B}, + {0x10030, 0x00021555}, + {0x10030, 0x00021921}, + {0x10030, 0x00021D1B}, + {0x10030, 0x000220E3}, + {0x10030, 0x000224DD}, + {0x10030, 0x000228A3}, + {0x10030, 0x00022C9D}, + {0x10030, 0x00023063}, + {0x10030, 0x0002345D}, + {0x10030, 0x00023823}, + {0x10030, 0x00023C1D}, + {0x10030, 0x00024017}, + {0x10030, 0x00024411}, + {0x10030, 0x000281A9}, + {0x10030, 0x000285A3}, + {0x10030, 0x0002899D}, + {0x10030, 0x00028D97}, + {0x10030, 0x0002915D}, + {0x10030, 0x00029557}, + {0x10030, 0x0002991F}, + {0x10030, 0x00029D19}, + {0x10030, 0x0002A0E1}, + {0x10030, 0x0002A4DB}, + {0x10030, 0x0002A8A1}, + {0x10030, 0x0002AC9B}, + {0x10030, 0x0002B061}, + {0x10030, 0x0002B45B}, + {0x10030, 0x0002B821}, + {0x10030, 0x0002BC1B}, + {0x10030, 0x0002C015}, + {0x10030, 0x0002C40F}, + {0x10030, 0x000301A9}, + {0x10030, 0x000305A3}, + {0x10030, 0x0003099D}, + {0x10030, 0x00030D97}, + {0x10030, 0x0003115D}, + {0x10030, 0x00031557}, + {0x10030, 0x0003191F}, + {0x10030, 0x00031D19}, + {0x10030, 0x000320E1}, + {0x10030, 0x000324DB}, + {0x10030, 0x000328A1}, + {0x10030, 0x00032C9B}, + {0x10030, 0x00033061}, + {0x10030, 0x0003345B}, + {0x10030, 0x00033821}, + {0x10030, 0x00033C1B}, + {0x10030, 0x00034015}, + {0x10030, 0x0003440F}, + {0x10030, 0x000601F1}, + {0x10030, 0x000605E9}, + {0x10030, 0x000609A9}, + {0x10030, 0x00060D65}, + {0x10030, 0x0006115F}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, + {0x10030, 0x000681EF}, + {0x10030, 0x000685E7}, + {0x10030, 0x000689A7}, + {0x10030, 0x00068D61}, + {0x10030, 0x0006915B}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, + {0x10030, 0x0006C411}, {0x10030, 0x000701EF}, - {0x10030, 0x000705E7}, - {0x10030, 0x000709A7}, - {0x10030, 0x00070D61}, - {0x10030, 0x0007115B}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071CE5}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728A1}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, {0x10030, 0x000781EF}, {0x10030, 0x000785E9}, {0x10030, 0x000789E3}, {0x10030, 0x00078DA1}, {0x10030, 0x0007915F}, {0x10030, 0x00079559}, - {0x10030, 0x00079921}, - {0x10030, 0x00079D1B}, - {0x10030, 0x0007A0E3}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B823}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -9949,73 +11079,73 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, + {0x10030, 0x0006C411}, {0x10030, 0x000701EF}, - {0x10030, 0x000705E7}, - {0x10030, 0x000709A7}, - {0x10030, 0x00070D61}, - {0x10030, 0x0007115B}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071CE5}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728A1}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, {0x10030, 0x000781EF}, {0x10030, 0x000785E9}, {0x10030, 0x000789E3}, {0x10030, 0x00078DA1}, {0x10030, 0x0007915F}, {0x10030, 0x00079559}, - {0x10030, 0x00079921}, - {0x10030, 0x00079D1B}, - {0x10030, 0x0007A0E3}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B823}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -10094,73 +11224,73 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, + {0x10030, 0x0006C411}, {0x10030, 0x000701EF}, - {0x10030, 0x000705E7}, - {0x10030, 0x000709A7}, - {0x10030, 0x00070D61}, - {0x10030, 0x0007115B}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071CE5}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728A1}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, {0x10030, 0x000781EF}, {0x10030, 0x000785E9}, {0x10030, 0x000789E3}, {0x10030, 0x00078DA1}, {0x10030, 0x0007915F}, {0x10030, 0x00079559}, - {0x10030, 0x00079921}, - {0x10030, 0x00079D1B}, - {0x10030, 0x0007A0E3}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B823}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -10239,73 +11369,73 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, + {0x10030, 0x0006C411}, {0x10030, 0x000701EF}, - {0x10030, 0x000705E7}, - {0x10030, 0x000709A7}, - {0x10030, 0x00070D61}, - {0x10030, 0x0007115B}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071CE5}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728A1}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, {0x10030, 0x000781EF}, {0x10030, 0x000785E9}, {0x10030, 0x000789E3}, {0x10030, 0x00078DA1}, {0x10030, 0x0007915F}, {0x10030, 0x00079559}, - {0x10030, 0x00079921}, - {0x10030, 0x00079D1B}, - {0x10030, 0x0007A0E3}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B823}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -10384,73 +11514,73 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, + {0x10030, 0x0006C411}, {0x10030, 0x000701EF}, - {0x10030, 0x000705E7}, - {0x10030, 0x000709A7}, - {0x10030, 0x00070D61}, - {0x10030, 0x0007115B}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071CE5}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728A1}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, {0x10030, 0x000781EF}, {0x10030, 0x000785E9}, {0x10030, 0x000789E3}, {0x10030, 0x00078DA1}, {0x10030, 0x0007915F}, {0x10030, 0x00079559}, - {0x10030, 0x00079921}, - {0x10030, 0x00079D1B}, - {0x10030, 0x0007A0E3}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B823}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0xA0000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -11294,6 +12424,110 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x000338CC}, {0x10030, 0x00033C09}, {0x10030, 0x00034006}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x000200E8}, + {0x10030, 0x000204E5}, + {0x10030, 0x000208E2}, + {0x10030, 0x00020CDF}, + {0x10030, 0x000210DC}, + {0x10030, 0x000214D9}, + {0x10030, 0x000218D6}, + {0x10030, 0x00021CD3}, + {0x10030, 0x000220D0}, + {0x10030, 0x0002240D}, + {0x10030, 0x0002280A}, + {0x10030, 0x00022C07}, + {0x10030, 0x00023004}, + {0x10030, 0x00023401}, + {0x10030, 0x00023800}, + {0x10030, 0x00023C00}, + {0x10030, 0x00024000}, + {0x10030, 0x000280ED}, + {0x10030, 0x000284EA}, + {0x10030, 0x000288E7}, + {0x10030, 0x00028CE4}, + {0x10030, 0x000290E1}, + {0x10030, 0x000294DE}, + {0x10030, 0x000298DB}, + {0x10030, 0x00029CD8}, + {0x10030, 0x0002A0D5}, + {0x10030, 0x0002A4D2}, + {0x10030, 0x0002A8CF}, + {0x10030, 0x0002AC0C}, + {0x10030, 0x0002B009}, + {0x10030, 0x0002B406}, + {0x10030, 0x0002B803}, + {0x10030, 0x0002BC00}, + {0x10030, 0x0002C000}, + {0x10030, 0x000300EE}, + {0x10030, 0x000304EB}, + {0x10030, 0x000308E8}, + {0x10030, 0x00030CE5}, + {0x10030, 0x000310E2}, + {0x10030, 0x000314DF}, + {0x10030, 0x000318DC}, + {0x10030, 0x00031CD9}, + {0x10030, 0x000320D6}, + {0x10030, 0x000324D3}, + {0x10030, 0x000328D0}, + {0x10030, 0x00032CCD}, + {0x10030, 0x0003300A}, + {0x10030, 0x00033407}, + {0x10030, 0x00033804}, + {0x10030, 0x00033C01}, + {0x10030, 0x00034000}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x000200E8}, + {0x10030, 0x000204E5}, + {0x10030, 0x000208E2}, + {0x10030, 0x00020CDF}, + {0x10030, 0x000210DC}, + {0x10030, 0x000214D9}, + {0x10030, 0x000218D6}, + {0x10030, 0x00021CD3}, + {0x10030, 0x000220D0}, + {0x10030, 0x0002240D}, + {0x10030, 0x0002280A}, + {0x10030, 0x00022C07}, + {0x10030, 0x00023004}, + {0x10030, 0x00023401}, + {0x10030, 0x00023800}, + {0x10030, 0x00023C00}, + {0x10030, 0x00024000}, + {0x10030, 0x000280ED}, + {0x10030, 0x000284EA}, + {0x10030, 0x000288E7}, + {0x10030, 0x00028CE4}, + {0x10030, 0x000290E1}, + {0x10030, 0x000294DE}, + {0x10030, 0x000298DB}, + {0x10030, 0x00029CD8}, + {0x10030, 0x0002A0D5}, + {0x10030, 0x0002A4D2}, + {0x10030, 0x0002A8CF}, + {0x10030, 0x0002AC0C}, + {0x10030, 0x0002B009}, + {0x10030, 0x0002B406}, + {0x10030, 0x0002B803}, + {0x10030, 0x0002BC00}, + {0x10030, 0x0002C000}, + {0x10030, 0x000300EE}, + {0x10030, 0x000304EB}, + {0x10030, 0x000308E8}, + {0x10030, 0x00030CE5}, + {0x10030, 0x000310E2}, + {0x10030, 0x000314DF}, + {0x10030, 0x000318DC}, + {0x10030, 0x00031CD9}, + {0x10030, 0x000320D6}, + {0x10030, 0x000324D3}, + {0x10030, 0x000328D0}, + {0x10030, 0x00032CCD}, + {0x10030, 0x0003300A}, + {0x10030, 0x00033407}, + {0x10030, 0x00033804}, + {0x10030, 0x00033C01}, + {0x10030, 0x00034000}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000200FA}, {0x10030, 0x000204F7}, @@ -11841,6 +13075,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -11885,6 +13123,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -11941,6 +13183,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -11985,6 +13231,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12041,6 +13291,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12085,6 +13339,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12141,6 +13399,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12185,6 +13447,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12241,6 +13507,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12285,6 +13555,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12305,7 +13579,53 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x033, 0x00000070}, {0x03F, 0x00050002}, {0x033, 0x00000071}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0xA0000000, 0x00000000}, {0x03F, 0x00060032}, + {0xB0000000, 0x00000000}, {0x033, 0x00000072}, {0x03F, 0x00050042}, {0x033, 0x00000073}, @@ -12341,6 +13661,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12385,6 +13709,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12405,7 +13733,53 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x033, 0x00000078}, {0x03F, 0x00050002}, {0x033, 0x00000079}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00060032}, + {0xA0000000, 0x00000000}, {0x03F, 0x00060032}, + {0xB0000000, 0x00000000}, {0x033, 0x0000007A}, {0x03F, 0x00050042}, {0x033, 0x0000007B}, @@ -12441,6 +13815,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12485,6 +13863,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12541,6 +13923,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12585,6 +13971,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12641,6 +14031,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12685,6 +14079,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12741,6 +14139,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12785,6 +14187,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12841,6 +14247,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12885,6 +14295,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12941,6 +14355,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -12985,6 +14403,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13041,6 +14463,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13085,6 +14511,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13141,6 +14571,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13185,6 +14619,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13241,6 +14679,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13285,6 +14727,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13341,6 +14787,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13385,6 +14835,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13441,6 +14895,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13485,6 +14943,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13541,6 +15003,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13585,6 +15051,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13641,6 +15111,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13685,6 +15159,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13741,6 +15219,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13785,6 +15267,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13841,6 +15327,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13885,6 +15375,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13941,6 +15435,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -13985,6 +15483,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14041,6 +15543,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14085,6 +15591,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14141,6 +15651,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14185,6 +15699,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14241,6 +15759,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14285,6 +15807,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14341,6 +15867,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14385,6 +15915,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14441,6 +15975,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14485,6 +16023,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14541,6 +16083,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14585,6 +16131,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14669,6 +16219,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x00025003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00025003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00025003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00025003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00025003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14719,6 +16273,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0002D003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0002D003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0002D003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0002D003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0002D003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14769,6 +16327,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x00035003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00035003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00035003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00035003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00035003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14819,6 +16381,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x10030, 0x0003D003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0003D003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0003D003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0003D003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0003D003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -14882,6 +16448,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00065003}, {0x10030, 0x00066003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00065003}, + {0x10030, 0x00066003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00065003}, + {0x10030, 0x00066003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00065003}, {0x10030, 0x00066003}, @@ -14952,6 +16524,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0006D003}, {0x10030, 0x0006E003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0006D003}, + {0x10030, 0x0006E003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0006D003}, + {0x10030, 0x0006E003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0006D003}, {0x10030, 0x0006E003}, @@ -15022,6 +16600,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00075003}, {0x10030, 0x00076003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00075003}, + {0x10030, 0x00076003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00075003}, + {0x10030, 0x00076003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00075003}, {0x10030, 0x00076003}, @@ -15092,6 +16676,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0007D003}, {0x10030, 0x0007E003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0007D003}, + {0x10030, 0x0007E003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0007D003}, + {0x10030, 0x0007E003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0007D003}, {0x10030, 0x0007E003}, @@ -15119,7 +16709,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radioa_regs[] = { {0xB0000000, 0x00000000}, {0x10030, 0x0007F003}, {0x100EE, 0x00000000}, - {0x0FE, 0x00000048}, + {0x0FE, 0x00000063}, }; static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { @@ -15136,13 +16726,15 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0xF0040001, 0x0000000A}, {0xF0050001, 0x0000000B}, {0xF0070001, 0x0000000C}, - {0xF0320001, 0x0000000D}, - {0xF0330001, 0x0000000E}, - {0xF0340001, 0x0000000F}, - {0xF0350001, 0x00000010}, - {0xF0360001, 0x00000011}, - {0xF03F0001, 0x00000012}, - {0xF0400001, 0x00000013}, + {0xF0150001, 0x0000000D}, + {0xF0160001, 0x0000000E}, + {0xF0320001, 0x0000000F}, + {0xF0330001, 0x00000010}, + {0xF0340001, 0x00000011}, + {0xF0350001, 0x00000012}, + {0xF0360001, 0x00000013}, + {0xF03F0001, 0x00000014}, + {0xF0400001, 0x00000015}, {0x005, 0x00000000}, {0x10005, 0x00000000}, {0x0B9, 0x00020440}, @@ -15150,6 +16742,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10000, 0x00030000}, {0x018, 0x00011124}, {0x10018, 0x00011124}, + {0x0A3, 0x000B9204}, + {0x0AD, 0x00091E0F}, + {0x05D, 0x00001012}, + {0x05C, 0x00079C5C}, + {0x062, 0x00055220}, + {0x0D3, 0x00000103}, {0x05F, 0x00000038}, {0x097, 0x00043200}, {0x0A6, 0x00066DB7}, @@ -15253,6 +16851,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x067, 0x0000D300}, {0x0DA, 0x000D4000}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x067, 0x0000D300}, + {0x0DA, 0x000D4000}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x067, 0x0000D300}, + {0x0DA, 0x000D4000}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x067, 0x0000D300}, {0x0DA, 0x000D4000}, @@ -15319,6 +16923,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x08F, 0x000D1352}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x08F, 0x000D1352}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x08F, 0x000D1352}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x08F, 0x000D1352}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x08F, 0x000D1352}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -15382,6 +16990,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000007}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000007}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000017}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000017}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000007}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -15918,6 +17530,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000EFFF}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000EFFF}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000EFFF}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000EFFF}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000EFFF}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16256,6 +17872,32 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x030, 0x00050112}, {0x030, 0x00058101}, {0x030, 0x00060001}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x000085ED}, + {0x030, 0x000105CC}, + {0x030, 0x000184AA}, + {0x030, 0x00020388}, + {0x030, 0x00028377}, + {0x030, 0x00030377}, + {0x030, 0x00038255}, + {0x030, 0x00040244}, + {0x030, 0x00048133}, + {0x030, 0x00050112}, + {0x030, 0x00058101}, + {0x030, 0x00060001}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x000085ED}, + {0x030, 0x000105CC}, + {0x030, 0x000184AA}, + {0x030, 0x00020388}, + {0x030, 0x00028377}, + {0x030, 0x00030377}, + {0x030, 0x00038255}, + {0x030, 0x00040244}, + {0x030, 0x00048133}, + {0x030, 0x00050112}, + {0x030, 0x00058101}, + {0x030, 0x00060001}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x030, 0x000085ED}, {0x030, 0x000105CC}, @@ -16582,11 +18224,300 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x0EF, 0x00000000}, {0x06E, 0x00077A18}, {0x06D, 0x00000C31}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0380}, + {0x06B, 0x00003CA0}, + {0x06F, 0x000C01FC}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0380}, + {0x06B, 0x00003CA0}, + {0x06F, 0x000C01FC}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, + {0x06A, 0x000E0F8A}, + {0x06B, 0x000018A0}, + {0x06F, 0x000F81FC}, + {0xA0000000, 0x00000000}, {0x06A, 0x000E0F8A}, {0x06B, 0x000018A0}, {0x06F, 0x000F81FC}, + {0xB0000000, 0x00000000}, {0x05E, 0x0000001F}, {0x0EF, 0x00000200}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x030, 0x0003E207}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0003D407}, + {0x030, 0x00035A87}, + {0x030, 0x0002CF07}, + {0x030, 0x00024F07}, + {0x030, 0x0001CF07}, + {0x030, 0x00014F07}, + {0x030, 0x0000CF07}, + {0x030, 0x00004F07}, + {0xA0000000, 0x00000000}, {0x030, 0x0003D407}, {0x030, 0x00035A87}, {0x030, 0x0002CF07}, @@ -16595,14 +18526,171 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x030, 0x00014F07}, {0x030, 0x0000CF07}, {0x030, 0x00004F07}, + {0xB0000000, 0x00000000}, {0x0EF, 0x00000000}, {0x0EB, 0x00080000}, + {0x80010000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90020000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90320000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90330000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90340000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90350000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90360000, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90010001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, {0x030, 0x00008038}, {0x030, 0x00010038}, {0x030, 0x00018038}, {0x030, 0x00020038}, {0x030, 0x00028038}, {0x030, 0x00030038}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0000803C}, + {0x030, 0x0001003C}, + {0x030, 0x0001803C}, + {0x030, 0x0002003C}, + {0x030, 0x0002803C}, + {0x030, 0x0003003C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x0000803C}, + {0x030, 0x0001003C}, + {0x030, 0x0001803C}, + {0x030, 0x0002003C}, + {0x030, 0x0002803C}, + {0x030, 0x0003003C}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0xA0000000, 0x00000000}, + {0x030, 0x00008038}, + {0x030, 0x00010038}, + {0x030, 0x00018038}, + {0x030, 0x00020038}, + {0x030, 0x00028038}, + {0x030, 0x00030038}, + {0xB0000000, 0x00000000}, {0x030, 0x0003803C}, {0x030, 0x0004003C}, {0x030, 0x0004803C}, @@ -16639,6 +18727,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x095, 0x00000008}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x095, 0x00000008}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x095, 0x00000008}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x095, 0x00000008}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16684,6 +18776,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16728,6 +18824,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16772,6 +18872,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16816,6 +18920,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16860,6 +18968,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16904,6 +19016,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16948,6 +19064,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -16992,6 +19112,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17036,6 +19160,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17080,6 +19208,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17124,6 +19256,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17168,6 +19304,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17212,6 +19352,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17256,6 +19400,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17300,6 +19448,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17344,6 +19496,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17388,6 +19544,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17432,6 +19592,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17476,6 +19640,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17520,6 +19688,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17564,6 +19736,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17608,6 +19784,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17652,6 +19832,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17696,6 +19880,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -17740,20 +19928,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0xA0000000, 0x00000000}, {0x03F, 0x00000052}, {0xB0000000, 0x00000000}, @@ -17784,20 +19976,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0xA0000000, 0x00000000}, {0x03F, 0x0000005A}, {0xB0000000, 0x00000000}, @@ -17828,20 +20024,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0xA0000000, 0x00000000}, {0x03F, 0x0000009C}, {0xB0000000, 0x00000000}, @@ -17872,20 +20072,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0xA0000000, 0x00000000}, {0x03F, 0x0000019C}, {0xB0000000, 0x00000000}, @@ -17916,20 +20120,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001A4}, {0xB0000000, 0x00000000}, @@ -17960,20 +20168,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001E6}, {0xB0000000, 0x00000000}, @@ -18004,20 +20216,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000002E6}, {0xB0000000, 0x00000000}, @@ -18048,20 +20264,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000003E6}, {0xB0000000, 0x00000000}, @@ -18092,20 +20312,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0xA0000000, 0x00000000}, {0x03F, 0x00000052}, {0xB0000000, 0x00000000}, @@ -18136,20 +20360,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0xA0000000, 0x00000000}, {0x03F, 0x0000005A}, {0xB0000000, 0x00000000}, @@ -18180,20 +20408,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0xA0000000, 0x00000000}, {0x03F, 0x0000009C}, {0xB0000000, 0x00000000}, @@ -18224,20 +20456,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0xA0000000, 0x00000000}, {0x03F, 0x0000019C}, {0xB0000000, 0x00000000}, @@ -18268,20 +20504,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001A4}, {0xB0000000, 0x00000000}, @@ -18312,20 +20552,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001E6}, {0xB0000000, 0x00000000}, @@ -18356,20 +20600,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000002E6}, {0xB0000000, 0x00000000}, @@ -18400,20 +20648,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000003E6}, {0xB0000000, 0x00000000}, @@ -18444,20 +20696,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0xA0000000, 0x00000000}, {0x03F, 0x00000052}, {0xB0000000, 0x00000000}, @@ -18488,20 +20744,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0xA0000000, 0x00000000}, {0x03F, 0x0000005A}, {0xB0000000, 0x00000000}, @@ -18532,20 +20792,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0xA0000000, 0x00000000}, {0x03F, 0x0000009C}, {0xB0000000, 0x00000000}, @@ -18576,20 +20840,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0xA0000000, 0x00000000}, {0x03F, 0x0000019C}, {0xB0000000, 0x00000000}, @@ -18620,20 +20888,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001A4}, {0xB0000000, 0x00000000}, @@ -18664,20 +20936,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001E6}, {0xB0000000, 0x00000000}, @@ -18708,20 +20984,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000002E6}, + {0x03F, 0x000002E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000002E6}, {0xB0000000, 0x00000000}, @@ -18752,20 +21032,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000003E7}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000003E7}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000003E7}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000003E6}, + {0x03F, 0x000003E7}, {0xA0000000, 0x00000000}, {0x03F, 0x000003E6}, {0xB0000000, 0x00000000}, @@ -18796,20 +21080,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000152}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00000152}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000152}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x00000052}, + {0x03F, 0x00000152}, {0xA0000000, 0x00000000}, {0x03F, 0x00000052}, {0xB0000000, 0x00000000}, @@ -18840,20 +21128,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000015A}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000015A}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000015A}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000005A}, + {0x03F, 0x0000015A}, {0xA0000000, 0x00000000}, {0x03F, 0x0000005A}, {0xB0000000, 0x00000000}, @@ -18884,20 +21176,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000019C}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x0000019C}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x0000019C}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000009C}, + {0x03F, 0x0000019C}, {0xA0000000, 0x00000000}, {0x03F, 0x0000009C}, {0xB0000000, 0x00000000}, @@ -18928,20 +21224,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001A4}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001A4}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001A4}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x0000019C}, + {0x03F, 0x000001A4}, {0xA0000000, 0x00000000}, {0x03F, 0x0000019C}, {0xB0000000, 0x00000000}, @@ -18972,20 +21272,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000001E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000001E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000001E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001A4}, + {0x03F, 0x000001E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001A4}, {0xB0000000, 0x00000000}, @@ -19016,20 +21320,24 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x000002E6}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x000002E6}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x000002E6}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, - {0x03F, 0x000001E6}, + {0x03F, 0x000002E6}, {0xA0000000, 0x00000000}, {0x03F, 0x000001E6}, {0xB0000000, 0x00000000}, @@ -20199,7 +22507,152 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90020001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x000001EF}, + {0x10030, 0x000005E9}, + {0x10030, 0x000009E3}, + {0x10030, 0x00000DDD}, + {0x10030, 0x000011D7}, + {0x10030, 0x0000159F}, + {0x10030, 0x00001999}, + {0x10030, 0x00001D5F}, + {0x10030, 0x00002159}, + {0x10030, 0x0000251F}, + {0x10030, 0x00002919}, + {0x10030, 0x00002CDF}, + {0x10030, 0x000030D9}, + {0x10030, 0x0000349F}, + {0x10030, 0x00003899}, + {0x10030, 0x00003C5F}, + {0x10030, 0x00004059}, + {0x10030, 0x00004453}, + {0x10030, 0x000201EF}, + {0x10030, 0x000205E9}, + {0x10030, 0x000209E3}, + {0x10030, 0x00020DA3}, + {0x10030, 0x00021161}, + {0x10030, 0x0002155B}, + {0x10030, 0x0002191F}, + {0x10030, 0x00021D19}, + {0x10030, 0x000220E1}, + {0x10030, 0x000224DB}, + {0x10030, 0x000228A3}, + {0x10030, 0x00022C9D}, + {0x10030, 0x00023063}, + {0x10030, 0x0002345D}, + {0x10030, 0x00023823}, + {0x10030, 0x00023C1B}, + {0x10030, 0x00024015}, + {0x10030, 0x0002440F}, + {0x10030, 0x000281EF}, + {0x10030, 0x000285E7}, + {0x10030, 0x000289A7}, + {0x10030, 0x00028D65}, + {0x10030, 0x0002915F}, + {0x10030, 0x00029523}, + {0x10030, 0x0002991D}, + {0x10030, 0x00029CE5}, + {0x10030, 0x0002A0DF}, + {0x10030, 0x0002A4A7}, + {0x10030, 0x0002A8A1}, + {0x10030, 0x0002AC67}, + {0x10030, 0x0002B061}, + {0x10030, 0x0002B427}, + {0x10030, 0x0002B821}, + {0x10030, 0x0002BC19}, + {0x10030, 0x0002C013}, + {0x10030, 0x0002C40D}, + {0x10030, 0x000301EF}, + {0x10030, 0x000305E7}, + {0x10030, 0x000309A7}, + {0x10030, 0x00030D65}, + {0x10030, 0x0003115F}, + {0x10030, 0x00031525}, + {0x10030, 0x0003191F}, + {0x10030, 0x00031CE7}, + {0x10030, 0x000320E1}, + {0x10030, 0x000324A9}, + {0x10030, 0x000328A3}, + {0x10030, 0x00032C69}, + {0x10030, 0x00033063}, + {0x10030, 0x00033429}, + {0x10030, 0x00033823}, + {0x10030, 0x00033C1D}, + {0x10030, 0x00034013}, + {0x10030, 0x0003440D}, + {0x10030, 0x000601F1}, + {0x10030, 0x000605E9}, + {0x10030, 0x000609A9}, + {0x10030, 0x00060D65}, + {0x10030, 0x0006115F}, + {0x10030, 0x00061525}, + {0x10030, 0x0006191F}, + {0x10030, 0x00061CE7}, + {0x10030, 0x000620E1}, + {0x10030, 0x000624DB}, + {0x10030, 0x000628A3}, + {0x10030, 0x00062C69}, + {0x10030, 0x00063063}, + {0x10030, 0x00063429}, + {0x10030, 0x00063823}, + {0x10030, 0x00063C1D}, + {0x10030, 0x00064013}, + {0x10030, 0x0006440D}, + {0x10030, 0x000681EF}, + {0x10030, 0x000685E7}, + {0x10030, 0x000689A7}, + {0x10030, 0x00068D61}, + {0x10030, 0x0006915B}, + {0x10030, 0x00069523}, + {0x10030, 0x0006991D}, + {0x10030, 0x00069CE5}, + {0x10030, 0x0006A0DF}, + {0x10030, 0x0006A4A7}, + {0x10030, 0x0006A8A1}, + {0x10030, 0x0006AC67}, + {0x10030, 0x0006B061}, + {0x10030, 0x0006B429}, + {0x10030, 0x0006B823}, + {0x10030, 0x0006BC1D}, + {0x10030, 0x0006C017}, + {0x10030, 0x0006C40D}, + {0x10030, 0x000701F1}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071523}, + {0x10030, 0x0007191D}, + {0x10030, 0x00071D17}, + {0x10030, 0x00072111}, + {0x10030, 0x000724D9}, + {0x10030, 0x000728D3}, + {0x10030, 0x00072C67}, + {0x10030, 0x00073061}, + {0x10030, 0x00073427}, + {0x10030, 0x00073821}, + {0x10030, 0x00073C1B}, + {0x10030, 0x00074015}, + {0x10030, 0x0007440D}, + {0x10030, 0x000781F1}, + {0x10030, 0x000785EB}, + {0x10030, 0x000789E5}, + {0x10030, 0x00078DA3}, + {0x10030, 0x00079161}, + {0x10030, 0x0007955B}, + {0x10030, 0x00079923}, + {0x10030, 0x00079D1D}, + {0x10030, 0x0007A117}, + {0x10030, 0x0007A4DD}, + {0x10030, 0x0007A8D7}, + {0x10030, 0x0007AC9D}, + {0x10030, 0x0007B063}, + {0x10030, 0x0007B45D}, + {0x10030, 0x0007B857}, + {0x10030, 0x0007BC1D}, + {0x10030, 0x0007C017}, + {0x10030, 0x0007C40F}, + {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -20344,7 +22797,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90030001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -20489,7 +22942,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90040001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -20634,7 +23087,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90050001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -20779,7 +23232,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -20924,7 +23377,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -21069,7 +23522,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, - {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, {0x10030, 0x000009E3}, @@ -21088,60 +23541,60 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x00003C5F}, {0x10030, 0x00004059}, {0x10030, 0x00004453}, - {0x10030, 0x000201A7}, - {0x10030, 0x000205A1}, - {0x10030, 0x0002099B}, - {0x10030, 0x00020D95}, - {0x10030, 0x0002115B}, - {0x10030, 0x00021555}, - {0x10030, 0x00021921}, - {0x10030, 0x00021D1B}, - {0x10030, 0x000220E3}, - {0x10030, 0x000224DD}, + {0x10030, 0x000201EF}, + {0x10030, 0x000205E9}, + {0x10030, 0x000209E3}, + {0x10030, 0x00020DA3}, + {0x10030, 0x00021161}, + {0x10030, 0x0002155B}, + {0x10030, 0x0002191F}, + {0x10030, 0x00021D19}, + {0x10030, 0x000220E1}, + {0x10030, 0x000224DB}, {0x10030, 0x000228A3}, {0x10030, 0x00022C9D}, {0x10030, 0x00023063}, {0x10030, 0x0002345D}, {0x10030, 0x00023823}, - {0x10030, 0x00023C1D}, - {0x10030, 0x00024017}, - {0x10030, 0x00024411}, - {0x10030, 0x000281A9}, - {0x10030, 0x000285A3}, - {0x10030, 0x0002899D}, - {0x10030, 0x00028D97}, - {0x10030, 0x0002915D}, - {0x10030, 0x00029557}, - {0x10030, 0x0002991F}, - {0x10030, 0x00029D19}, - {0x10030, 0x0002A0E1}, - {0x10030, 0x0002A4DB}, + {0x10030, 0x00023C1B}, + {0x10030, 0x00024015}, + {0x10030, 0x0002440F}, + {0x10030, 0x000281EF}, + {0x10030, 0x000285E7}, + {0x10030, 0x000289A7}, + {0x10030, 0x00028D65}, + {0x10030, 0x0002915F}, + {0x10030, 0x00029523}, + {0x10030, 0x0002991D}, + {0x10030, 0x00029CE5}, + {0x10030, 0x0002A0DF}, + {0x10030, 0x0002A4A7}, {0x10030, 0x0002A8A1}, - {0x10030, 0x0002AC9B}, + {0x10030, 0x0002AC67}, {0x10030, 0x0002B061}, - {0x10030, 0x0002B45B}, + {0x10030, 0x0002B427}, {0x10030, 0x0002B821}, - {0x10030, 0x0002BC1B}, - {0x10030, 0x0002C015}, - {0x10030, 0x0002C40F}, - {0x10030, 0x000301A9}, - {0x10030, 0x000305A3}, - {0x10030, 0x0003099D}, - {0x10030, 0x00030D97}, - {0x10030, 0x0003115D}, - {0x10030, 0x00031557}, + {0x10030, 0x0002BC19}, + {0x10030, 0x0002C013}, + {0x10030, 0x0002C40D}, + {0x10030, 0x000301EF}, + {0x10030, 0x000305E7}, + {0x10030, 0x000309A7}, + {0x10030, 0x00030D65}, + {0x10030, 0x0003115F}, + {0x10030, 0x00031525}, {0x10030, 0x0003191F}, - {0x10030, 0x00031D19}, + {0x10030, 0x00031CE7}, {0x10030, 0x000320E1}, - {0x10030, 0x000324DB}, - {0x10030, 0x000328A1}, - {0x10030, 0x00032C9B}, - {0x10030, 0x00033061}, - {0x10030, 0x0003345B}, - {0x10030, 0x00033821}, - {0x10030, 0x00033C1B}, - {0x10030, 0x00034015}, - {0x10030, 0x0003440F}, + {0x10030, 0x000324A9}, + {0x10030, 0x000328A3}, + {0x10030, 0x00032C69}, + {0x10030, 0x00033063}, + {0x10030, 0x00033429}, + {0x10030, 0x00033823}, + {0x10030, 0x00033C1D}, + {0x10030, 0x00034013}, + {0x10030, 0x0003440D}, {0x10030, 0x000601F1}, {0x10030, 0x000605E9}, {0x10030, 0x000609A9}, @@ -21186,7 +23639,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x00071523}, {0x10030, 0x0007191D}, {0x10030, 0x00071D17}, - {0x10030, 0x000720DF}, + {0x10030, 0x00072111}, {0x10030, 0x000724D9}, {0x10030, 0x000728D3}, {0x10030, 0x00072C67}, @@ -21214,6 +23667,151 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0007BC1D}, {0x10030, 0x0007C017}, {0x10030, 0x0007C40F}, + {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x000001EF}, + {0x10030, 0x000005E9}, + {0x10030, 0x000009E3}, + {0x10030, 0x00000DDD}, + {0x10030, 0x000011D7}, + {0x10030, 0x0000159F}, + {0x10030, 0x00001999}, + {0x10030, 0x00001D5F}, + {0x10030, 0x00002159}, + {0x10030, 0x0000251F}, + {0x10030, 0x00002919}, + {0x10030, 0x00002CDF}, + {0x10030, 0x000030D9}, + {0x10030, 0x0000349F}, + {0x10030, 0x00003899}, + {0x10030, 0x00003C5F}, + {0x10030, 0x00004059}, + {0x10030, 0x00004453}, + {0x10030, 0x000201A7}, + {0x10030, 0x000205A1}, + {0x10030, 0x0002099B}, + {0x10030, 0x00020D95}, + {0x10030, 0x0002115B}, + {0x10030, 0x00021555}, + {0x10030, 0x00021921}, + {0x10030, 0x00021D1B}, + {0x10030, 0x000220E3}, + {0x10030, 0x000224DD}, + {0x10030, 0x000228A3}, + {0x10030, 0x00022C9D}, + {0x10030, 0x00023063}, + {0x10030, 0x0002345D}, + {0x10030, 0x00023823}, + {0x10030, 0x00023C1D}, + {0x10030, 0x00024017}, + {0x10030, 0x00024411}, + {0x10030, 0x000281A9}, + {0x10030, 0x000285A3}, + {0x10030, 0x0002899D}, + {0x10030, 0x00028D97}, + {0x10030, 0x0002915D}, + {0x10030, 0x00029557}, + {0x10030, 0x0002991F}, + {0x10030, 0x00029D19}, + {0x10030, 0x0002A0E1}, + {0x10030, 0x0002A4DB}, + {0x10030, 0x0002A8A1}, + {0x10030, 0x0002AC9B}, + {0x10030, 0x0002B061}, + {0x10030, 0x0002B45B}, + {0x10030, 0x0002B821}, + {0x10030, 0x0002BC1B}, + {0x10030, 0x0002C015}, + {0x10030, 0x0002C40F}, + {0x10030, 0x000301A9}, + {0x10030, 0x000305A3}, + {0x10030, 0x0003099D}, + {0x10030, 0x00030D97}, + {0x10030, 0x0003115D}, + {0x10030, 0x00031557}, + {0x10030, 0x0003191F}, + {0x10030, 0x00031D19}, + {0x10030, 0x000320E1}, + {0x10030, 0x000324DB}, + {0x10030, 0x000328A1}, + {0x10030, 0x00032C9B}, + {0x10030, 0x00033061}, + {0x10030, 0x0003345B}, + {0x10030, 0x00033821}, + {0x10030, 0x00033C1B}, + {0x10030, 0x00034015}, + {0x10030, 0x0003440F}, + {0x10030, 0x000601F1}, + {0x10030, 0x000605E9}, + {0x10030, 0x000609A9}, + {0x10030, 0x00060D65}, + {0x10030, 0x0006115F}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, + {0x10030, 0x000681EF}, + {0x10030, 0x000685E7}, + {0x10030, 0x000689A7}, + {0x10030, 0x00068D61}, + {0x10030, 0x0006915B}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, + {0x10030, 0x0006B429}, + {0x10030, 0x0006B823}, + {0x10030, 0x0006BC1D}, + {0x10030, 0x0006C017}, + {0x10030, 0x0006C411}, + {0x10030, 0x000701EF}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, + {0x10030, 0x000781EF}, + {0x10030, 0x000785E9}, + {0x10030, 0x000789E3}, + {0x10030, 0x00078DA1}, + {0x10030, 0x0007915F}, + {0x10030, 0x00079559}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x90340001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -21292,73 +23890,73 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, - {0x10030, 0x000701F1}, + {0x10030, 0x0006C411}, + {0x10030, 0x000701EF}, {0x10030, 0x000705E9}, {0x10030, 0x000709A9}, {0x10030, 0x00070D63}, {0x10030, 0x0007115D}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071D17}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728D3}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, - {0x10030, 0x000781F1}, - {0x10030, 0x000785EB}, - {0x10030, 0x000789E5}, - {0x10030, 0x00078DA3}, - {0x10030, 0x00079161}, - {0x10030, 0x0007955B}, - {0x10030, 0x00079923}, - {0x10030, 0x00079D1D}, - {0x10030, 0x0007A117}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B857}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, + {0x10030, 0x000781EF}, + {0x10030, 0x000785E9}, + {0x10030, 0x000789E3}, + {0x10030, 0x00078DA1}, + {0x10030, 0x0007915F}, + {0x10030, 0x00079559}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x90350001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -21437,73 +24035,73 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, - {0x10030, 0x000701F1}, + {0x10030, 0x0006C411}, + {0x10030, 0x000701EF}, {0x10030, 0x000705E9}, {0x10030, 0x000709A9}, {0x10030, 0x00070D63}, {0x10030, 0x0007115D}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071D17}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728D3}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, - {0x10030, 0x000781F1}, - {0x10030, 0x000785EB}, - {0x10030, 0x000789E5}, - {0x10030, 0x00078DA3}, - {0x10030, 0x00079161}, - {0x10030, 0x0007955B}, - {0x10030, 0x00079923}, - {0x10030, 0x00079D1D}, - {0x10030, 0x0007A117}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B857}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, + {0x10030, 0x000781EF}, + {0x10030, 0x000785E9}, + {0x10030, 0x000789E3}, + {0x10030, 0x00078DA1}, + {0x10030, 0x0007915F}, + {0x10030, 0x00079559}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x90360001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -21582,73 +24180,73 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, - {0x10030, 0x000701F1}, + {0x10030, 0x0006C411}, + {0x10030, 0x000701EF}, {0x10030, 0x000705E9}, {0x10030, 0x000709A9}, {0x10030, 0x00070D63}, {0x10030, 0x0007115D}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071D17}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728D3}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, - {0x10030, 0x000781F1}, - {0x10030, 0x000785EB}, - {0x10030, 0x000789E5}, - {0x10030, 0x00078DA3}, - {0x10030, 0x00079161}, - {0x10030, 0x0007955B}, - {0x10030, 0x00079923}, - {0x10030, 0x00079D1D}, - {0x10030, 0x0007A117}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B857}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, + {0x10030, 0x000781EF}, + {0x10030, 0x000785E9}, + {0x10030, 0x000789E3}, + {0x10030, 0x00078DA1}, + {0x10030, 0x0007915F}, + {0x10030, 0x00079559}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x903f0001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -21720,80 +24318,80 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0003345B}, {0x10030, 0x00033821}, {0x10030, 0x00033C1B}, - {0x10030, 0x00034015}, - {0x10030, 0x0003440F}, - {0x10030, 0x000601F1}, - {0x10030, 0x000605E9}, - {0x10030, 0x000609A9}, - {0x10030, 0x00060D65}, - {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, - {0x10030, 0x000681EF}, - {0x10030, 0x000685E7}, - {0x10030, 0x000689A7}, - {0x10030, 0x00068D61}, - {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, - {0x10030, 0x0006B429}, - {0x10030, 0x0006B823}, - {0x10030, 0x0006BC1D}, - {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, - {0x10030, 0x000701F1}, - {0x10030, 0x000705E9}, - {0x10030, 0x000709A9}, - {0x10030, 0x00070D63}, - {0x10030, 0x0007115D}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071D17}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728D3}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, - {0x10030, 0x000781F1}, - {0x10030, 0x000785EB}, - {0x10030, 0x000789E5}, - {0x10030, 0x00078DA3}, - {0x10030, 0x00079161}, - {0x10030, 0x0007955B}, - {0x10030, 0x00079923}, - {0x10030, 0x00079D1D}, - {0x10030, 0x0007A117}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B857}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x00034015}, + {0x10030, 0x0003440F}, + {0x10030, 0x000601F1}, + {0x10030, 0x000605E9}, + {0x10030, 0x000609A9}, + {0x10030, 0x00060D65}, + {0x10030, 0x0006115F}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, + {0x10030, 0x000681EF}, + {0x10030, 0x000685E7}, + {0x10030, 0x000689A7}, + {0x10030, 0x00068D61}, + {0x10030, 0x0006915B}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, + {0x10030, 0x0006B429}, + {0x10030, 0x0006B823}, + {0x10030, 0x0006BC1D}, + {0x10030, 0x0006C017}, + {0x10030, 0x0006C411}, + {0x10030, 0x000701EF}, + {0x10030, 0x000705E9}, + {0x10030, 0x000709A9}, + {0x10030, 0x00070D63}, + {0x10030, 0x0007115D}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, + {0x10030, 0x000781EF}, + {0x10030, 0x000785E9}, + {0x10030, 0x000789E3}, + {0x10030, 0x00078DA1}, + {0x10030, 0x0007915F}, + {0x10030, 0x00079559}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0x90400001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -21872,73 +24470,73 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x000609A9}, {0x10030, 0x00060D65}, {0x10030, 0x0006115F}, - {0x10030, 0x00061525}, - {0x10030, 0x0006191F}, - {0x10030, 0x00061CE7}, - {0x10030, 0x000620E1}, - {0x10030, 0x000624DB}, - {0x10030, 0x000628A3}, - {0x10030, 0x00062C69}, - {0x10030, 0x00063063}, - {0x10030, 0x00063429}, - {0x10030, 0x00063823}, - {0x10030, 0x00063C1D}, - {0x10030, 0x00064013}, - {0x10030, 0x0006440D}, + {0x10030, 0x00061527}, + {0x10030, 0x00061921}, + {0x10030, 0x00061CE9}, + {0x10030, 0x000620E3}, + {0x10030, 0x000624DD}, + {0x10030, 0x000628A5}, + {0x10030, 0x00062C6B}, + {0x10030, 0x00063065}, + {0x10030, 0x0006342B}, + {0x10030, 0x00063825}, + {0x10030, 0x00063C1F}, + {0x10030, 0x00064019}, + {0x10030, 0x00064413}, {0x10030, 0x000681EF}, {0x10030, 0x000685E7}, {0x10030, 0x000689A7}, {0x10030, 0x00068D61}, {0x10030, 0x0006915B}, - {0x10030, 0x00069523}, - {0x10030, 0x0006991D}, - {0x10030, 0x00069CE5}, - {0x10030, 0x0006A0DF}, - {0x10030, 0x0006A4A7}, - {0x10030, 0x0006A8A1}, - {0x10030, 0x0006AC67}, - {0x10030, 0x0006B061}, + {0x10030, 0x00069525}, + {0x10030, 0x0006991F}, + {0x10030, 0x00069CE7}, + {0x10030, 0x0006A0E1}, + {0x10030, 0x0006A4A9}, + {0x10030, 0x0006A8A3}, + {0x10030, 0x0006AC69}, + {0x10030, 0x0006B063}, {0x10030, 0x0006B429}, {0x10030, 0x0006B823}, {0x10030, 0x0006BC1D}, {0x10030, 0x0006C017}, - {0x10030, 0x0006C40D}, - {0x10030, 0x000701F1}, + {0x10030, 0x0006C411}, + {0x10030, 0x000701EF}, {0x10030, 0x000705E9}, {0x10030, 0x000709A9}, {0x10030, 0x00070D63}, {0x10030, 0x0007115D}, - {0x10030, 0x00071523}, - {0x10030, 0x0007191D}, - {0x10030, 0x00071D17}, - {0x10030, 0x000720DF}, - {0x10030, 0x000724D9}, - {0x10030, 0x000728D3}, - {0x10030, 0x00072C67}, - {0x10030, 0x00073061}, - {0x10030, 0x00073427}, - {0x10030, 0x00073821}, - {0x10030, 0x00073C1B}, - {0x10030, 0x00074015}, - {0x10030, 0x0007440D}, - {0x10030, 0x000781F1}, - {0x10030, 0x000785EB}, - {0x10030, 0x000789E5}, - {0x10030, 0x00078DA3}, - {0x10030, 0x00079161}, - {0x10030, 0x0007955B}, - {0x10030, 0x00079923}, - {0x10030, 0x00079D1D}, - {0x10030, 0x0007A117}, - {0x10030, 0x0007A4DD}, - {0x10030, 0x0007A8D7}, - {0x10030, 0x0007AC9D}, - {0x10030, 0x0007B063}, - {0x10030, 0x0007B45D}, - {0x10030, 0x0007B857}, - {0x10030, 0x0007BC1D}, - {0x10030, 0x0007C017}, - {0x10030, 0x0007C40F}, + {0x10030, 0x00071525}, + {0x10030, 0x0007191F}, + {0x10030, 0x00071D19}, + {0x10030, 0x000720E1}, + {0x10030, 0x000724DB}, + {0x10030, 0x000728A3}, + {0x10030, 0x00072C69}, + {0x10030, 0x00073063}, + {0x10030, 0x00073429}, + {0x10030, 0x00073823}, + {0x10030, 0x00073C1D}, + {0x10030, 0x00074017}, + {0x10030, 0x00074411}, + {0x10030, 0x000781EF}, + {0x10030, 0x000785E9}, + {0x10030, 0x000789E3}, + {0x10030, 0x00078DA1}, + {0x10030, 0x0007915F}, + {0x10030, 0x00079559}, + {0x10030, 0x0007991F}, + {0x10030, 0x00079D19}, + {0x10030, 0x0007A0DF}, + {0x10030, 0x0007A4D9}, + {0x10030, 0x0007A8D3}, + {0x10030, 0x0007AC99}, + {0x10030, 0x0007B05F}, + {0x10030, 0x0007B459}, + {0x10030, 0x0007B81F}, + {0x10030, 0x0007BC19}, + {0x10030, 0x0007C013}, + {0x10030, 0x0007C40D}, {0xA0000000, 0x00000000}, {0x10030, 0x000001EF}, {0x10030, 0x000005E9}, @@ -22782,6 +25380,110 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x000338CC}, {0x10030, 0x00033C09}, {0x10030, 0x00034006}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x000200E8}, + {0x10030, 0x000204E5}, + {0x10030, 0x000208E2}, + {0x10030, 0x00020CDF}, + {0x10030, 0x000210DC}, + {0x10030, 0x000214D9}, + {0x10030, 0x000218D6}, + {0x10030, 0x00021CD3}, + {0x10030, 0x000220D0}, + {0x10030, 0x0002240D}, + {0x10030, 0x0002280A}, + {0x10030, 0x00022C07}, + {0x10030, 0x00023004}, + {0x10030, 0x00023401}, + {0x10030, 0x00023800}, + {0x10030, 0x00023C00}, + {0x10030, 0x00024000}, + {0x10030, 0x000280E7}, + {0x10030, 0x000284E4}, + {0x10030, 0x000288E1}, + {0x10030, 0x00028CDE}, + {0x10030, 0x000290DB}, + {0x10030, 0x000294D8}, + {0x10030, 0x000298D5}, + {0x10030, 0x00029CD2}, + {0x10030, 0x0002A0CF}, + {0x10030, 0x0002A40C}, + {0x10030, 0x0002A809}, + {0x10030, 0x0002AC06}, + {0x10030, 0x0002B003}, + {0x10030, 0x0002B400}, + {0x10030, 0x0002B800}, + {0x10030, 0x0002BC00}, + {0x10030, 0x0002C000}, + {0x10030, 0x000300E7}, + {0x10030, 0x000304E4}, + {0x10030, 0x000308E1}, + {0x10030, 0x00030CDE}, + {0x10030, 0x000310DB}, + {0x10030, 0x000314D8}, + {0x10030, 0x000318D5}, + {0x10030, 0x00031CD2}, + {0x10030, 0x000320CF}, + {0x10030, 0x000324CC}, + {0x10030, 0x00032809}, + {0x10030, 0x00032C06}, + {0x10030, 0x00033003}, + {0x10030, 0x00033400}, + {0x10030, 0x00033800}, + {0x10030, 0x00033C00}, + {0x10030, 0x00034000}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x000200E8}, + {0x10030, 0x000204E5}, + {0x10030, 0x000208E2}, + {0x10030, 0x00020CDF}, + {0x10030, 0x000210DC}, + {0x10030, 0x000214D9}, + {0x10030, 0x000218D6}, + {0x10030, 0x00021CD3}, + {0x10030, 0x000220D0}, + {0x10030, 0x0002240D}, + {0x10030, 0x0002280A}, + {0x10030, 0x00022C07}, + {0x10030, 0x00023004}, + {0x10030, 0x00023401}, + {0x10030, 0x00023800}, + {0x10030, 0x00023C00}, + {0x10030, 0x00024000}, + {0x10030, 0x000280E7}, + {0x10030, 0x000284E4}, + {0x10030, 0x000288E1}, + {0x10030, 0x00028CDE}, + {0x10030, 0x000290DB}, + {0x10030, 0x000294D8}, + {0x10030, 0x000298D5}, + {0x10030, 0x00029CD2}, + {0x10030, 0x0002A0CF}, + {0x10030, 0x0002A40C}, + {0x10030, 0x0002A809}, + {0x10030, 0x0002AC06}, + {0x10030, 0x0002B003}, + {0x10030, 0x0002B400}, + {0x10030, 0x0002B800}, + {0x10030, 0x0002BC00}, + {0x10030, 0x0002C000}, + {0x10030, 0x000300E7}, + {0x10030, 0x000304E4}, + {0x10030, 0x000308E1}, + {0x10030, 0x00030CDE}, + {0x10030, 0x000310DB}, + {0x10030, 0x000314D8}, + {0x10030, 0x000318D5}, + {0x10030, 0x00031CD2}, + {0x10030, 0x000320CF}, + {0x10030, 0x000324CC}, + {0x10030, 0x00032809}, + {0x10030, 0x00032C06}, + {0x10030, 0x00033003}, + {0x10030, 0x00033400}, + {0x10030, 0x00033800}, + {0x10030, 0x00033C00}, + {0x10030, 0x00034000}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x000200FA}, {0x10030, 0x000204F7}, @@ -23329,6 +26031,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23373,6 +26079,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23429,6 +26139,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23473,6 +26187,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23529,6 +26247,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23573,6 +26295,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23629,6 +26355,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23673,6 +26403,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23729,6 +26463,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23773,6 +26511,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23829,6 +26571,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23873,6 +26619,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23929,6 +26679,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -23973,6 +26727,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24029,6 +26787,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24073,6 +26835,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24129,6 +26895,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24173,6 +26943,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24229,6 +27003,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24273,6 +27051,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24329,6 +27111,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24373,6 +27159,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24429,6 +27219,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24473,6 +27267,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24529,6 +27327,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24573,6 +27375,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24629,6 +27435,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24673,6 +27483,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24729,6 +27543,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24773,6 +27591,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24829,6 +27651,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24873,6 +27699,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24929,6 +27759,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -24973,6 +27807,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25029,6 +27867,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25073,6 +27915,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25129,6 +27975,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25173,6 +28023,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25229,6 +28083,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25273,6 +28131,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25329,6 +28191,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25373,6 +28239,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25429,6 +28299,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25473,6 +28347,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25529,6 +28407,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25573,6 +28455,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25629,6 +28515,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25673,6 +28563,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25729,6 +28623,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25773,6 +28671,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25829,6 +28731,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25873,6 +28779,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25929,6 +28839,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -25973,6 +28887,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -26029,6 +28947,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -26073,6 +28995,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x00000003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x03F, 0x00008002}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x03F, 0x00000003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -26157,6 +29083,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x00025003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00025003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00025003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00025003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00025003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -26207,6 +29137,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0002D003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0002D003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0002D003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0002D003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0002D003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -26257,6 +29191,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x00035003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00035003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00035003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00035003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00035003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -26307,6 +29245,10 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x10030, 0x0003D003}, {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0003D003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0003D003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0003D003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0003D003}, {0x90330001, 0x00000000}, {0x40000000, 0x00000000}, @@ -26370,6 +29312,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00065003}, {0x10030, 0x00066003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00065003}, + {0x10030, 0x00066003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00065003}, + {0x10030, 0x00066003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00065003}, {0x10030, 0x00066003}, @@ -26440,6 +29388,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0006D003}, {0x10030, 0x0006E003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0006D003}, + {0x10030, 0x0006E003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0006D003}, + {0x10030, 0x0006E003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0006D003}, {0x10030, 0x0006E003}, @@ -26510,6 +29464,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00075003}, {0x10030, 0x00076003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00075003}, + {0x10030, 0x00076003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x00075003}, + {0x10030, 0x00076003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x00075003}, {0x10030, 0x00076003}, @@ -26580,6 +29540,12 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x90070001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0007D003}, {0x10030, 0x0007E003}, + {0x90150001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0007D003}, + {0x10030, 0x0007E003}, + {0x90160001, 0x00000000}, {0x40000000, 0x00000000}, + {0x10030, 0x0007D003}, + {0x10030, 0x0007E003}, {0x90320001, 0x00000000}, {0x40000000, 0x00000000}, {0x10030, 0x0007D003}, {0x10030, 0x0007E003}, @@ -26621,7 +29587,7 @@ static const struct rtw89_reg2_def rtw89_8852c_phy_radiob_regs[] = { {0x03F, 0x0000000A}, {0x0ED, 0x00000000}, {0x100EE, 0x00000000}, - {0x0FE, 0x00000048}, + {0x0FE, 0x00000063}, }; static const struct rtw89_reg2_def rtw89_8852c_phy_nctl_regs[] = { -- cgit v1.2.3 From f8f912bf69a021c8cfff23e69e59c7c975a47c1a Mon Sep 17 00:00:00 2001 From: Neal Sidhwaney Date: Sat, 3 Jun 2023 02:00:23 -0400 Subject: wifi: brcmfmac: Detect corner error case earlier with log In brcmf_chip_recognition(), the return value from an MMIO read is interpreted as various fields without checking if it failed, which is harmless today, as the interpreted fields are checked for validity a few lines below. However, in corner cases (on my MacbookPro 14,1, sometimes after waking from sleep or soft reboot), when this happens, it causes the logging to be misleading, because the message indicates an unsupported chip type ("brcmfmac: brcmf_chip_recognition: chip backplane type 15 is not supported"). This patch detects this case slightly earlier and logs an appropriate message, with the same return result as is the case today. Signed-off-by: Neal Sidhwaney Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230603060021.57225-1-nealsid@gmail.com --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 9f9bf08a70bb..2ef92ef25517 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -972,6 +972,7 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) u32 regdata; u32 socitype; int ret; + const u32 READ_FAILED = 0xFFFFFFFF; /* Get CC core rev * Chipid is assume to be at offset 0 from SI_ENUM_BASE @@ -980,6 +981,11 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) */ regdata = ci->ops->read32(ci->ctx, CORE_CC_REG(ci->pub.enum_base, chipid)); + if (regdata == READ_FAILED) { + brcmf_err("MMIO read failed: 0x%08x\n", regdata); + return -ENODEV; + } + ci->pub.chip = regdata & CID_ID_MASK; ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; -- cgit v1.2.3 From b241e260820b68c09586e8a0ae0fc23c0e3215bd Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 28 May 2023 00:28:33 +0200 Subject: wifi: rsi: Do not configure WoWlan in shutdown hook if not enabled In case WoWlan was never configured during the operation of the system, the hw->wiphy->wowlan_config will be NULL. rsi_config_wowlan() checks whether wowlan_config is non-NULL and if it is not, then WARNs about it. The warning is valid, as during normal operation the rsi_config_wowlan() should only ever be called with non-NULL wowlan_config. In shutdown this rsi_config_wowlan() should only ever be called if WoWlan was configured before by the user. Add checks for non-NULL wowlan_config into the shutdown hook. While at it, check whether the wiphy is also non-NULL before accessing wowlan_config . Drop the single-use wowlan_config variable, just inline it into function call. Fixes: 16bbc3eb8372 ("rsi: fix null pointer dereference during rsi_shutdown()") Signed-off-by: Marek Vasut Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230527222833.273741-1-marex@denx.de --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index d09998796ac0..6e33a2563fdb 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1463,10 +1463,8 @@ static void rsi_shutdown(struct device *dev) rsi_dbg(ERR_ZONE, "SDIO Bus shutdown =====>\n"); - if (hw) { - struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config; - - if (rsi_config_wowlan(adapter, wowlan)) + if (hw && hw->wiphy && hw->wiphy->wowlan_config) { + if (rsi_config_wowlan(adapter, hw->wiphy->wowlan_config)) rsi_dbg(ERR_ZONE, "Failed to configure WoWLAN\n"); } -- cgit v1.2.3 From e74f562328b03fbe9cf438f958464dff3a644dfc Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 28 May 2023 00:28:59 +0200 Subject: wifi: rsi: Do not set MMC_PM_KEEP_POWER in shutdown It makes no sense to set MMC_PM_KEEP_POWER in shutdown. The flag indicates to the MMC subsystem to keep the slot powered on during suspend, but in shutdown the slot should actually be powered off. Drop this call. Fixes: 063848c3e155 ("rsi: sdio: Add WOWLAN support for S5 shutdown state") Signed-off-by: Marek Vasut Reviewed-by: Simon Horman Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230527222859.273768-1-marex@denx.de --- drivers/net/wireless/rsi/rsi_91x_sdio.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 6e33a2563fdb..1911fef3bbad 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1479,9 +1479,6 @@ static void rsi_shutdown(struct device *dev) if (sdev->write_fail) rsi_dbg(INFO_ZONE, "###### Device is not ready #######\n"); - if (rsi_set_sdio_pm_caps(adapter)) - rsi_dbg(INFO_ZONE, "Setting power management caps failed\n"); - rsi_dbg(INFO_ZONE, "***** RSI module shut down *****\n"); } -- cgit v1.2.3 From 358b94f0a7cadd2ec7824531d54dadaa8b71de04 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Fri, 2 Jun 2023 09:59:39 +0300 Subject: wifi: rtlwifi: remove unused timer and related code Drop unused 'dualmac_easyconcurrent_retrytimer' of 'struct rtl_works', corresponding 'rtl_easy_concurrent_retrytimer_callback()' handler, 'dualmac_easy_concurrent' function pointer of 'struct rtl_hal_ops' and related call to 'timer_setup()' in '_rtl_init_deferred_work()'. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602065940.149198-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/base.c | 16 +--------------- drivers/net/wireless/realtek/rtlwifi/base.h | 1 - drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 -- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 36ae9ba3ac01..807a53a97325 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -452,8 +452,7 @@ static int _rtl_init_deferred_work(struct ieee80211_hw *hw) /* <1> timer */ timer_setup(&rtlpriv->works.watchdog_timer, rtl_watch_dog_timer_callback, 0); - timer_setup(&rtlpriv->works.dualmac_easyconcurrent_retrytimer, - rtl_easy_concurrent_retrytimer_callback, 0); + /* <2> work queue */ rtlpriv->works.hw = hw; rtlpriv->works.rtl_wq = wq; @@ -2366,19 +2365,6 @@ static void rtl_c2hcmd_wq_callback(struct work_struct *work) rtl_c2hcmd_launcher(hw, 1); } -void rtl_easy_concurrent_retrytimer_callback(struct timer_list *t) -{ - struct rtl_priv *rtlpriv = - from_timer(rtlpriv, t, works.dualmac_easyconcurrent_retrytimer); - struct ieee80211_hw *hw = rtlpriv->hw; - struct rtl_priv *buddy_priv = rtlpriv->buddy_priv; - - if (buddy_priv == NULL) - return; - - rtlpriv->cfg->ops->dualmac_easy_concurrent(hw); -} - /********************************************************* * * frame process functions diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index 0e4f8a8ae3a5..f081a9a90563 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -124,7 +124,6 @@ int rtl_send_smps_action(struct ieee80211_hw *hw, u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); u8 rtl_tid_to_ac(u8 tid); -void rtl_easy_concurrent_retrytimer_callback(struct timer_list *t); extern struct rtl_global_var rtl_global_var; void rtl_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 082af216760f..bc1d68cb9183 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2300,7 +2300,6 @@ struct rtl_hal_ops { u32 regaddr, u32 bitmask, u32 data); void (*linked_set_reg)(struct ieee80211_hw *hw); void (*chk_switch_dmdp)(struct ieee80211_hw *hw); - void (*dualmac_easy_concurrent)(struct ieee80211_hw *hw); void (*dualmac_switch_to_dmdp)(struct ieee80211_hw *hw); bool (*phy_rf6052_config)(struct ieee80211_hw *hw); void (*phy_rf6052_set_cck_txpower)(struct ieee80211_hw *hw, @@ -2465,7 +2464,6 @@ struct rtl_works { /*timer */ struct timer_list watchdog_timer; - struct timer_list dualmac_easyconcurrent_retrytimer; struct timer_list fw_clockoff_timer; struct timer_list fast_antenna_training_timer; /*task */ -- cgit v1.2.3 From 557123259200b30863e1b6a8f24a8c8060b6fc1d Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Fri, 2 Jun 2023 09:59:40 +0300 Subject: wifi: rtlwifi: remove unused dualmac control leftovers Remove 'struct rtl_dualmac_easy_concurrent_ctl' of 'struct rtl_priv' and related code in '_rtl_pci_tx_chk_waitq()'. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230602065940.149198-2-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/pci.c | 5 ----- drivers/net/wireless/realtek/rtlwifi/wifi.h | 9 --------- 2 files changed, 14 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index ca79f652fef3..028a7c97bacf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -482,11 +482,6 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) if (!rtlpriv->rtlhal.earlymode_enable) return; - if (rtlpriv->dm.supp_phymode_switch && - (rtlpriv->easy_concurrent_ctl.switch_in_process || - (rtlpriv->buddy_priv && - rtlpriv->buddy_priv->easy_concurrent_ctl.switch_in_process))) - return; /* we just use em for BE/BK/VI/VO */ for (tid = 7; tid >= 0; tid--) { u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(tid)]; diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index bc1d68cb9183..307e059ec8aa 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -2496,14 +2496,6 @@ struct rtl_debug { #define MIMO_PS_DYNAMIC 1 #define MIMO_PS_NOLIMIT 3 -struct rtl_dualmac_easy_concurrent_ctl { - enum band_type currentbandtype_backfordmdp; - bool close_bbandrf_for_dmsp; - bool change_to_dmdp; - bool change_to_dmsp; - bool switch_in_process; -}; - struct rtl_dmsp_ctl { bool activescan_for_slaveofdmsp; bool scan_for_anothermac_fordmsp; @@ -2744,7 +2736,6 @@ struct rtl_priv { struct list_head list; struct rtl_priv *buddy_priv; struct rtl_global_var *glb_var; - struct rtl_dualmac_easy_concurrent_ctl easy_concurrent_ctl; struct rtl_dmsp_ctl dmsp_ctl; struct rtl_locks locks; struct rtl_works works; -- cgit v1.2.3 From fef0f427f71224442698ea4e052315a894d9de69 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 5 Jun 2023 13:07:00 +0300 Subject: wifi: rtlwifi: remove misused flag from HAL data Always rely on 'driver_is_goingto_unload' of 'struct rtl_hal' and remove (presumably misused) 'driver_going2unload' from it. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230605100700.111644-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c | 6 +++--- drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c index a8b5bf45b1bb..4ae8f69c64f9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c @@ -1302,7 +1302,7 @@ static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); u8 u1btmp; - if (rtlhal->driver_going2unload) + if (rtlhal->driver_is_goingto_unload) rtl_write_byte(rtlpriv, 0x560, 0x0); /* Power save for BB/RF */ @@ -1323,7 +1323,7 @@ static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw) rtl_write_word(rtlpriv, CMDR, 0x57FC); rtl_write_word(rtlpriv, CMDR, 0x0000); - if (rtlhal->driver_going2unload) { + if (rtlhal->driver_is_goingto_unload) { u1btmp = rtl_read_byte(rtlpriv, (REG_SYS_FUNC_EN + 1)); u1btmp &= ~(BIT(0)); rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1btmp); @@ -1345,7 +1345,7 @@ static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw) /* Power save for MAC */ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS && - !rtlhal->driver_going2unload) { + !rtlhal->driver_is_goingto_unload) { /* enable LED function */ rtl_write_byte(rtlpriv, 0x03, 0xF9); /* SW/HW radio off or halt adapter!! For example S3/S4 */ diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 307e059ec8aa..a16b779080cb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1673,8 +1673,6 @@ struct rtl_hal { bool fw_clk_change_in_progress; bool allow_sw_to_change_hwclc; u8 fw_ps_state; - /**/ - bool driver_going2unload; /*AMPDU init min space*/ u8 minspace_cfg; /*For Min spacing configurations */ -- cgit v1.2.3 From 6e8b2c88fc8cf95ed09de25946b20b7536c88cd5 Mon Sep 17 00:00:00 2001 From: Karol Kolacinski Date: Thu, 1 Jun 2023 14:15:03 -0700 Subject: ice: handle extts in the miscellaneous interrupt thread The ice_ptp_extts_work() and ice_ptp_periodic_work() functions are both scheduled on the same kthread worker, pf.ptp.kworker. The ice_ptp_periodic_work() function sends to the firmware to interact with the PHY, and must block to wait for responses. This can cause delay in responding to the PFINT_OICR_TSYN_EVNT interrupt cause, ultimately resulting in disruption to processing an input signal of the frequency is high enough. In our testing, even 100 Hz signals get disrupted. Fix this by instead processing the signal inside the miscellaneous interrupt thread prior to handling Tx timestamps. Use atomic bits in a new pf->misc_thread bitmap in order to safely communicate which tasks require processing within the ice_misc_intr_thread_fn(). This ensures the communication of desired tasks from the ice_misc_intr() are correctly processed without racing even in the event that the interrupt triggers again before the thread function exits. Fixes: 172db5f91d5f ("ice: add support for auxiliary input/output pins") Signed-off-by: Karol Kolacinski Signed-off-by: Jacob Keller Tested-by: Arpana Arland (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 7 +++++++ drivers/net/ethernet/intel/ice/ice_main.c | 29 +++++++++++++++++++++-------- drivers/net/ethernet/intel/ice/ice_ptp.c | 12 +++--------- drivers/net/ethernet/intel/ice/ice_ptp.h | 4 ++-- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index b4bca1d964a9..4ba3d99439a0 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -508,6 +508,12 @@ enum ice_pf_flags { ICE_PF_FLAGS_NBITS /* must be last */ }; +enum ice_misc_thread_tasks { + ICE_MISC_THREAD_EXTTS_EVENT, + ICE_MISC_THREAD_TX_TSTAMP, + ICE_MISC_THREAD_NBITS /* must be last */ +}; + struct ice_switchdev_info { struct ice_vsi *control_vsi; struct ice_vsi *uplink_vsi; @@ -550,6 +556,7 @@ struct ice_pf { DECLARE_BITMAP(features, ICE_F_MAX); DECLARE_BITMAP(state, ICE_STATE_NBITS); DECLARE_BITMAP(flags, ICE_PF_FLAGS_NBITS); + DECLARE_BITMAP(misc_thread, ICE_MISC_THREAD_NBITS); unsigned long *avail_txqs; /* bitmap to track PF Tx queue usage */ unsigned long *avail_rxqs; /* bitmap to track PF Rx queue usage */ unsigned long serv_tmr_period; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 62e91512aeab..314a42808e39 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3139,20 +3139,28 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) if (oicr & PFINT_OICR_TSYN_TX_M) { ena_mask &= ~PFINT_OICR_TSYN_TX_M; - if (!hw->reset_ongoing) + if (!hw->reset_ongoing) { + set_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread); ret = IRQ_WAKE_THREAD; + } } if (oicr & PFINT_OICR_TSYN_EVNT_M) { u8 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; u32 gltsyn_stat = rd32(hw, GLTSYN_STAT(tmr_idx)); - /* Save EVENTs from GTSYN register */ - pf->ptp.ext_ts_irq |= gltsyn_stat & (GLTSYN_STAT_EVENT0_M | - GLTSYN_STAT_EVENT1_M | - GLTSYN_STAT_EVENT2_M); ena_mask &= ~PFINT_OICR_TSYN_EVNT_M; - kthread_queue_work(pf->ptp.kworker, &pf->ptp.extts_work); + + if (hw->func_caps.ts_func_info.src_tmr_owned) { + /* Save EVENTs from GLTSYN register */ + pf->ptp.ext_ts_irq |= gltsyn_stat & + (GLTSYN_STAT_EVENT0_M | + GLTSYN_STAT_EVENT1_M | + GLTSYN_STAT_EVENT2_M); + + set_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread); + ret = IRQ_WAKE_THREAD; + } } #define ICE_AUX_CRIT_ERR (PFINT_OICR_PE_CRITERR_M | PFINT_OICR_HMC_ERR_M | PFINT_OICR_PE_PUSH_M) @@ -3196,8 +3204,13 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data) if (ice_is_reset_in_progress(pf->state)) return IRQ_HANDLED; - while (!ice_ptp_process_ts(pf)) - usleep_range(50, 100); + if (test_and_clear_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread)) + ice_ptp_extts_event(pf); + + if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread)) { + while (!ice_ptp_process_ts(pf)) + usleep_range(50, 100); + } return IRQ_HANDLED; } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index d4b6c997141d..6f51ebaf1d70 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -1458,15 +1458,11 @@ static int ice_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm) } /** - * ice_ptp_extts_work - Workqueue task function - * @work: external timestamp work structure - * - * Service for PTP external clock event + * ice_ptp_extts_event - Process PTP external clock event + * @pf: Board private structure */ -static void ice_ptp_extts_work(struct kthread_work *work) +void ice_ptp_extts_event(struct ice_pf *pf) { - struct ice_ptp *ptp = container_of(work, struct ice_ptp, extts_work); - struct ice_pf *pf = container_of(ptp, struct ice_pf, ptp); struct ptp_clock_event event; struct ice_hw *hw = &pf->hw; u8 chan, tmr_idx; @@ -2558,7 +2554,6 @@ void ice_ptp_prepare_for_reset(struct ice_pf *pf) ice_ptp_cfg_timestamp(pf, false); kthread_cancel_delayed_work_sync(&ptp->work); - kthread_cancel_work_sync(&ptp->extts_work); if (test_bit(ICE_PFR_REQ, pf->state)) return; @@ -2656,7 +2651,6 @@ static int ice_ptp_init_work(struct ice_pf *pf, struct ice_ptp *ptp) /* Initialize work functions */ kthread_init_delayed_work(&ptp->work, ice_ptp_periodic_work); - kthread_init_work(&ptp->extts_work, ice_ptp_extts_work); /* Allocate a kworker for handling work required for the ports * connected to the PTP hardware clock. diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 9cda2f43e0e5..9f8902c1e743 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -169,7 +169,6 @@ struct ice_ptp_port { * struct ice_ptp - data used for integrating with CONFIG_PTP_1588_CLOCK * @port: data for the PHY port initialization procedure * @work: delayed work function for periodic tasks - * @extts_work: work function for handling external Tx timestamps * @cached_phc_time: a cached copy of the PHC time for timestamp extension * @cached_phc_jiffies: jiffies when cached_phc_time was last updated * @ext_ts_chan: the external timestamp channel in use @@ -190,7 +189,6 @@ struct ice_ptp_port { struct ice_ptp { struct ice_ptp_port port; struct kthread_delayed_work work; - struct kthread_work extts_work; u64 cached_phc_time; unsigned long cached_phc_jiffies; u8 ext_ts_chan; @@ -256,6 +254,7 @@ int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr); void ice_ptp_cfg_timestamp(struct ice_pf *pf, bool ena); int ice_get_ptp_clock_index(struct ice_pf *pf); +void ice_ptp_extts_event(struct ice_pf *pf); s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb); bool ice_ptp_process_ts(struct ice_pf *pf); @@ -284,6 +283,7 @@ static inline int ice_get_ptp_clock_index(struct ice_pf *pf) return -1; } +static inline void ice_ptp_extts_event(struct ice_pf *pf) { } static inline s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb) { -- cgit v1.2.3 From d578e618f192f453baf4fd7e32fec88ed7e678b8 Mon Sep 17 00:00:00 2001 From: Karol Kolacinski Date: Thu, 1 Jun 2023 14:15:04 -0700 Subject: ice: always return IRQ_WAKE_THREAD in ice_misc_intr() Refactor the ice_misc_intr() function to always return IRQ_WAKE_THREAD, and schedule the service task during the soft IRQ thread function instead of at the end of the hard IRQ handler. Remove the duplicate call to ice_service_task_schedule() that happened when we got a PCI exception. Signed-off-by: Karol Kolacinski Signed-off-by: Jacob Keller Tested-by: Arpana Arland (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 314a42808e39..45dab7f62198 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3058,7 +3058,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) { struct ice_pf *pf = (struct ice_pf *)data; struct ice_hw *hw = &pf->hw; - irqreturn_t ret = IRQ_NONE; struct device *dev; u32 oicr, ena_mask; @@ -3139,10 +3138,8 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) if (oicr & PFINT_OICR_TSYN_TX_M) { ena_mask &= ~PFINT_OICR_TSYN_TX_M; - if (!hw->reset_ongoing) { + if (!hw->reset_ongoing) set_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread); - ret = IRQ_WAKE_THREAD; - } } if (oicr & PFINT_OICR_TSYN_EVNT_M) { @@ -3159,7 +3156,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) GLTSYN_STAT_EVENT2_M); set_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread); - ret = IRQ_WAKE_THREAD; } } @@ -3180,16 +3176,12 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) if (oicr & (PFINT_OICR_PCI_EXCEPTION_M | PFINT_OICR_ECC_ERR_M)) { set_bit(ICE_PFR_REQ, pf->state); - ice_service_task_schedule(pf); } } - if (!ret) - ret = IRQ_HANDLED; - ice_service_task_schedule(pf); ice_irq_dynamic_ena(hw, NULL, NULL); - return ret; + return IRQ_WAKE_THREAD; } /** @@ -3204,6 +3196,8 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data) if (ice_is_reset_in_progress(pf->state)) return IRQ_HANDLED; + ice_service_task_schedule(pf); + if (test_and_clear_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread)) ice_ptp_extts_event(pf); -- cgit v1.2.3 From ae39eb42dd06e058215d0f782365b84039d686d4 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 1 Jun 2023 14:15:05 -0700 Subject: ice: introduce ICE_TX_TSTAMP_WORK enumeration The ice_ptp_process_ts() function and its various helper functions return a boolean value indicating whether any work is remaining. This use of a boolean has grown confusing as we have multiple helpers that pass status between each other. Readers must be aware of what "true" and "false" mean, and it is very easy to get their meaning inverted. The names of the functions are not standard "yes/no" questions, which is the best practice for boolean returns. Replace this use of an enumeration with a custom type, enum ice_tx_tstamp_work. This enumeration clearly indicates whether all work is done, or if more work is pending. To aid in readability, factor the actual list iteration and processing out into ice_ptp_process_tx_tstamp(), making it void. Then call this in ice_ptp_tx_tstamp() ensuring that we always check the Tracker list at the end when determining the appropriate return value. Now the return value is an explicit name instead of the true or false value. This is easier to follow and makes reading the resulting callers much simpler. In addition, this paves the way for future work to allow E822 hardware to process timestamps for all functions using a single interrupt on the clock owning PF. Signed-off-by: Jacob Keller Tested-by: Arpana Arland (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- drivers/net/ethernet/intel/ice/ice_ptp.c | 50 ++++++++++++++++++------------- drivers/net/ethernet/intel/ice/ice_ptp.h | 12 +++++++- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 45dab7f62198..6811e2a3c154 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3202,7 +3202,7 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data) ice_ptp_extts_event(pf); if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread)) { - while (!ice_ptp_process_ts(pf)) + while (ice_ptp_process_ts(pf) == ICE_TX_TSTAMP_WORK_PENDING) usleep_range(50, 100); } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 6f51ebaf1d70..81d96a40d5a7 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -617,7 +617,7 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx) } /** - * ice_ptp_tx_tstamp - Process Tx timestamps for a port + * ice_ptp_process_tx_tstamp - Process Tx timestamps for a port * @tx: the PTP Tx timestamp tracker * * Process timestamps captured by the PHY associated with this port. To do @@ -633,15 +633,6 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx) * 6) extend the 40 bit timestamp value to get a 64 bit timestamp value * 7) send this 64 bit timestamp to the stack * - * Returns true if all timestamps were handled, and false if any slots remain - * without a timestamp. - * - * After looping, if we still have waiting SKBs, return false. This may cause - * us effectively poll even when not strictly necessary. We do this because - * it's possible a new timestamp was requested around the same time as the - * interrupt. In some cases hardware might not interrupt us again when the - * timestamp is captured. - * * Note that we do not hold the tracking lock while reading the Tx timestamp. * This is because reading the timestamp requires taking a mutex that might * sleep. @@ -673,10 +664,9 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx) * the packet will never be sent by hardware and discard it without reading * the timestamp register. */ -static bool ice_ptp_tx_tstamp(struct ice_ptp_tx *tx) +static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) { struct ice_ptp_port *ptp_port; - bool more_timestamps; struct ice_pf *pf; struct ice_hw *hw; u64 tstamp_ready; @@ -685,7 +675,7 @@ static bool ice_ptp_tx_tstamp(struct ice_ptp_tx *tx) u8 idx; if (!tx->init) - return true; + return; ptp_port = container_of(tx, struct ice_ptp_port, tx); pf = ptp_port_to_pf(ptp_port); @@ -694,7 +684,7 @@ static bool ice_ptp_tx_tstamp(struct ice_ptp_tx *tx) /* Read the Tx ready status first */ err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready); if (err) - return false; + return; /* Drop packets if the link went down */ link_up = ptp_port->link_up; @@ -782,15 +772,34 @@ skip_ts_read: skb_tstamp_tx(skb, &shhwtstamps); dev_kfree_skb_any(skb); } +} - /* Check if we still have work to do. If so, re-queue this task to - * poll for remaining timestamps. - */ +/** + * ice_ptp_tx_tstamp - Process Tx timestamps for this function. + * @tx: Tx tracking structure to initialize + * + * Returns: ICE_TX_TSTAMP_WORK_PENDING if there are any outstanding incomplete + * Tx timestamps, or ICE_TX_TSTAMP_WORK_DONE otherwise. + */ +static enum ice_tx_tstamp_work ice_ptp_tx_tstamp(struct ice_ptp_tx *tx) +{ + bool more_timestamps; + + if (!tx->init) + return ICE_TX_TSTAMP_WORK_DONE; + + /* Process the Tx timestamp tracker */ + ice_ptp_process_tx_tstamp(tx); + + /* Check if there are outstanding Tx timestamps */ spin_lock(&tx->lock); more_timestamps = tx->init && !bitmap_empty(tx->in_use, tx->len); spin_unlock(&tx->lock); - return !more_timestamps; + if (more_timestamps) + return ICE_TX_TSTAMP_WORK_PENDING; + + return ICE_TX_TSTAMP_WORK_DONE; } /** @@ -2426,9 +2435,10 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb) * ice_ptp_process_ts - Process the PTP Tx timestamps * @pf: Board private structure * - * Returns true if timestamps are processed. + * Returns: ICE_TX_TSTAMP_WORK_PENDING if there are any outstanding Tx + * timestamps that need processing, and ICE_TX_TSTAMP_WORK_DONE otherwise. */ -bool ice_ptp_process_ts(struct ice_pf *pf) +enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf) { return ice_ptp_tx_tstamp(&pf->ptp.port.tx); } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 9f8902c1e743..995a57019ba7 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -108,6 +108,16 @@ struct ice_tx_tstamp { u64 cached_tstamp; }; +/** + * enum ice_tx_tstamp_work - Status of Tx timestamp work function + * @ICE_TX_TSTAMP_WORK_DONE: Tx timestamp processing is complete + * @ICE_TX_TSTAMP_WORK_PENDING: More Tx timestamps are pending + */ +enum ice_tx_tstamp_work { + ICE_TX_TSTAMP_WORK_DONE = 0, + ICE_TX_TSTAMP_WORK_PENDING, +}; + /** * struct ice_ptp_tx - Tracking structure for all Tx timestamp requests on a port * @lock: lock to prevent concurrent access to fields of this struct @@ -256,7 +266,7 @@ int ice_get_ptp_clock_index(struct ice_pf *pf); void ice_ptp_extts_event(struct ice_pf *pf); s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb); -bool ice_ptp_process_ts(struct ice_pf *pf); +enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf); void ice_ptp_rx_hwtstamp(struct ice_rx_ring *rx_ring, -- cgit v1.2.3 From 9a8648cce8d8a4a7770b45239912e20edb9736ad Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 1 Jun 2023 14:15:06 -0700 Subject: ice: trigger PFINT_OICR_TSYN_TX interrupt instead of polling In ice_misc_intr_thread_fn(), if we do not complete all Tx timestamp work, the thread function will poll continuously forever. For E822 hardware, this wastes time as the return value from ice_ptp_process_ts() is accurate and always reports correctly that the PHY actually has new timestamp data. In addition, if we receive enough timestamps with the right pacing, we may never exit this polling. Should this occur, other tasks handled by the ice_misc_intr_thread_fn() will never be processed. Fix this by instead writing to PFINT_OICR, causing an emulated interrupt to be triggered immediately. This does take slightly more processing than just re-checking the timestamps. However, it allows all of the other interrupt causes a chance to be processed first in the hard IRQ function. Note that the OICR interrupt is configured to be throttled to no more than once every 124 microseconds. This gives an effective interrupt rate of ~8000 interrupts per second. This should thus not cause a significant increase in overall CPU usage when compared to sleeping. Signed-off-by: Jacob Keller Tested-by: Arpana Arland (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 6811e2a3c154..2665f72b5461 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3202,8 +3202,15 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data) ice_ptp_extts_event(pf); if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread)) { - while (ice_ptp_process_ts(pf) == ICE_TX_TSTAMP_WORK_PENDING) - usleep_range(50, 100); + struct ice_hw *hw = &pf->hw; + + /* Process outstanding Tx timestamps. If there is more work, + * re-arm the interrupt to trigger again. + */ + if (ice_ptp_process_ts(pf) == ICE_TX_TSTAMP_WORK_PENDING) { + wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M); + ice_flush(hw); + } } return IRQ_HANDLED; -- cgit v1.2.3 From 0ec38df36ea1cc4f21bf7cd61a89942b034883c5 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 1 Jun 2023 14:15:07 -0700 Subject: ice: do not re-enable miscellaneous interrupt until thread_fn completes The ice driver uses threaded IRQ for managing Tx timestamps via the devm_request_threaded_irq() interface. The ice_misc_intr() handler function is responsible for processing the hard interrupt context, and can wake the ice_misc_intr_thread_fn() by returning IRQ_WAKE_THREAD. The request_threaded_irq() function comment says: @handler is still called in hard interrupt context and has to check whether the interrupt originates from the device. If yes, it needs to disable the interrupt on the device and return IRQ_WAKE_THREAD which will wake up the handler thread and run the @thread_fn. We currently re-enable the Other Interrupt Cause Register (OCIR) at the end of ice_misc_intr(). In practice, this seems to be ok, but it can make communicating between the handler function and the thread function difficult. This is because the interrupt can trigger again while the thread function is still processing. Move the OICR update to the end of the thread function, leaving the other interrupt cause disabled in hardware until we complete one pass of the thread function. This prevents the miscellaneous interrupt from firing until after we finish the thread function. Signed-off-by: Jacob Keller Tested-by: Arpana Arland (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 2665f72b5461..aa57d26a0ac7 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3179,8 +3179,6 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) } } - ice_irq_dynamic_ena(hw, NULL, NULL); - return IRQ_WAKE_THREAD; } @@ -3192,6 +3190,9 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data) { struct ice_pf *pf = data; + struct ice_hw *hw; + + hw = &pf->hw; if (ice_is_reset_in_progress(pf->state)) return IRQ_HANDLED; @@ -3202,8 +3203,6 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data) ice_ptp_extts_event(pf); if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread)) { - struct ice_hw *hw = &pf->hw; - /* Process outstanding Tx timestamps. If there is more work, * re-arm the interrupt to trigger again. */ @@ -3213,6 +3212,8 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data) } } + ice_irq_dynamic_ena(hw, NULL, NULL); + return IRQ_HANDLED; } -- cgit v1.2.3 From 8947e503737138ff92323f99637d921451fe398a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:23:53 -0700 Subject: netlink: specs: devlink: fill in some details important for C Python YNL is much more forgiving than the C code gen in terms of the spec completeness. Fill in a handful of devlink details to make the spec usable in C. Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/devlink.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml index 90641668232e..5d46ca966979 100644 --- a/Documentation/netlink/specs/devlink.yaml +++ b/Documentation/netlink/specs/devlink.yaml @@ -9,6 +9,7 @@ doc: Partial family for Devlink. attribute-sets: - name: devlink + name-prefix: devlink-attr- attributes: - name: bus-name @@ -95,10 +96,12 @@ attribute-sets: - name: reload-action-info type: nest + multi-attr: true nested-attributes: dl-reload-act-info - name: reload-action-stats type: nest + multi-attr: true nested-attributes: dl-reload-act-stats - name: dl-dev-stats @@ -196,3 +199,8 @@ operations: attributes: - bus-name - dev-name + - info-driver-name + - info-serial-number + - info-version-fixed + - info-version-running + - info-version-stored -- cgit v1.2.3 From 9858bfc271de3cc61307a710044c304e6ec34f8a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:23:54 -0700 Subject: tools: ynl-gen: use enum names in op strmap more carefully In preparation for supporting families which use different msg ids to and from the kernel - make sure the ids in op strmap are correct. The map is expected to be used mostly for notifications, don't generate a separate map for the "to kernel" direction. Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/fou-user.c | 1 - tools/net/ynl/lib/nlspec.py | 4 ++++ tools/net/ynl/ynl-gen-c.py | 6 +++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c index c99b5d438021..a0f33bb882e4 100644 --- a/tools/net/ynl/generated/fou-user.c +++ b/tools/net/ynl/generated/fou-user.c @@ -16,7 +16,6 @@ /* Enums */ static const char * const fou_op_strmap[] = { - [FOU_CMD_UNSPEC] = "unspec", [FOU_CMD_ADD] = "add", [FOU_CMD_DEL] = "del", [FOU_CMD_GET] = "get", diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index ada22b073aa2..bd5da8aaeac7 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -442,6 +442,10 @@ class SpecFamily(SpecElement): else: raise Exception("Can't parse directional ops") + if req_val == req_val_next: + req_val = None + if rsp_val == rsp_val_next: + rsp_val = None op = self.new_operation(elem, req_val, rsp_val) req_val = req_val_next rsp_val = rsp_val_next diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index c07340715601..8a0abf9048db 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1220,7 +1220,11 @@ def put_op_name(family, cw): map_name = f'{family.name}_op_strmap' cw.block_start(line=f"static const char * const {map_name}[] =") for op_name, op in family.msgs.items(): - cw.p(f'[{op.enum_name}] = "{op_name}",') + if op.rsp_value: + if op.req_value == op.rsp_value: + cw.p(f'[{op.enum_name}] = "{op_name}",') + else: + cw.p(f'[{op.rsp_value}] = "{op_name}",') cw.block_end(line=';') cw.nl() -- cgit v1.2.3 From 6f115d4575ab7225fc16ba816b9d25d88976a540 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:23:55 -0700 Subject: tools: ynl-gen: refactor strmap helper generation Move generating strmap lookup function to a helper. No functional changes. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 8a0abf9048db..efcf91675dfa 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1212,6 +1212,21 @@ def put_typol(cw, struct): cw.nl() +def _put_enum_to_str_helper(cw, render_name, map_name, arg_name, enum=None): + args = [f'int {arg_name}'] + if enum and not ('enum-name' in enum and not enum['enum-name']): + args = [f'enum {render_name} {arg_name}'] + cw.write_func_prot('const char *', f'{render_name}_str', args) + cw.block_start() + if enum and enum.type == 'flags': + cw.p(f'{arg_name} = ffs({arg_name}) - 1;') + cw.p(f'if ({arg_name} < 0 || {arg_name} >= (int)MNL_ARRAY_SIZE({map_name}))') + cw.p('return NULL;') + cw.p(f'return {map_name}[{arg_name}];') + cw.block_end() + cw.nl() + + def put_op_name_fwd(family, cw): cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op'], suffix=';') @@ -1228,13 +1243,7 @@ def put_op_name(family, cw): cw.block_end(line=';') cw.nl() - cw.write_func_prot('const char *', f'{family.name}_op_str', ['int op']) - cw.block_start() - cw.p(f'if (op < 0 || op >= (int)MNL_ARRAY_SIZE({map_name}))') - cw.p('return NULL;') - cw.p(f'return {map_name}[op];') - cw.block_end() - cw.nl() + _put_enum_to_str_helper(cw, family.name + '_op', map_name, 'op') def put_enum_to_str_fwd(family, cw, enum): @@ -1252,18 +1261,7 @@ def put_enum_to_str(family, cw, enum): cw.block_end(line=';') cw.nl() - args = [f'enum {enum.render_name} value'] - if 'enum-name' in enum and not enum['enum-name']: - args = ['int value'] - cw.write_func_prot('const char *', f'{enum.render_name}_str', args) - cw.block_start() - if enum.type == 'flags': - cw.p('value = ffs(value) - 1;') - cw.p(f'if (value < 0 || value >= (int)MNL_ARRAY_SIZE({map_name}))') - cw.p('return NULL;') - cw.p(f'return {map_name}[value];') - cw.block_end() - cw.nl() + _put_enum_to_str_helper(cw, enum.render_name, map_name, 'value', enum=enum) def put_req_nested(ri, struct): -- cgit v1.2.3 From ff6db4b58c93eada66f58423aa02363f987679c5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:23:56 -0700 Subject: tools: ynl-gen: enable code gen for directional specs I think that user space code gen for directional specs works after recent changes. Let them through. Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/nlspec.py | 7 ++++--- tools/net/ynl/ynl-gen-c.py | 10 +++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index bd5da8aaeac7..9f7ad87d69af 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -324,6 +324,7 @@ class SpecFamily(SpecElement): Attributes: proto protocol type (e.g. genetlink) + msg_id_model enum-model for operations (unified, directional etc.) license spec license (loaded from an SPDX tag on the spec) attr_sets dict of attribute sets @@ -349,6 +350,7 @@ class SpecFamily(SpecElement): super().__init__(self, spec) self.proto = self.yaml.get('protocol', 'genetlink') + self.msg_id_model = self.yaml['operations'].get('enum-model', 'unified') if schema_path is None: schema_path = os.path.dirname(os.path.dirname(spec_path)) + f'/{self.proto}.yaml' @@ -477,10 +479,9 @@ class SpecFamily(SpecElement): attr_set = self.new_attr_set(elem) self.attr_sets[elem['name']] = attr_set - msg_id_model = self.yaml['operations'].get('enum-model', 'unified') - if msg_id_model == 'unified': + if self.msg_id_model == 'unified': self._dictify_ops_unified() - elif msg_id_model == 'directional': + elif self.msg_id_model == 'directional': self._dictify_ops_directional() for op in self.msgs.values(): diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index efcf91675dfa..7b3e79e17c01 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -709,9 +709,6 @@ class Operation(SpecOperation): def __init__(self, family, yaml, req_value, rsp_value): super().__init__(family, yaml, req_value, rsp_value) - if req_value != rsp_value: - raise Exception("Directional messages not supported by codegen") - self.render_name = family.name + '_' + c_lower(self.name) self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \ @@ -2243,6 +2240,13 @@ def main(): os.sys.exit(1) return + supported_models = ['unified'] + if args.mode == 'user': + supported_models += ['directional'] + if parsed.msg_id_model not in supported_models: + print(f'Message enum-model {parsed.msg_id_model} not supported for {args.mode} generation') + os.sys.exit(1) + cw = CodeWriter(BaseNlLib(), out_file) _, spec_kernel = find_kernel_root(args.spec) -- cgit v1.2.3 From 6afaa0ef9b0e446fde14a1424f2c2858484a3601 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:23:57 -0700 Subject: tools: ynl-gen: try to sort the types more intelligently We need to sort the structures to avoid the need for forward declarations. While at it remove the sort of structs when rendering, it doesn't do anything. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 7b3e79e17c01..d9c74a678df8 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -875,6 +875,28 @@ class Family(SpecFamily): inherit.add('idx') self.pure_nested_structs[nested].set_inherited(inherit) + # Try to reorder according to dependencies + pns_key_list = list(self.pure_nested_structs.keys()) + pns_key_seen = set() + rounds = len(pns_key_list)**2 # it's basically bubble sort + for _ in range(rounds): + if len(pns_key_list) == 0: + break + name = pns_key_list.pop(0) + finished = True + for _, spec in self.attr_sets[name].items(): + if 'nested-attributes' in spec: + if spec['nested-attributes'] not in pns_key_seen: + # Dicts are sorted, this will make struct last + struct = self.pure_nested_structs.pop(name) + self.pure_nested_structs[name] = struct + finished = False + break + if finished: + pns_key_seen.add(name) + else: + pns_key_list.append(name) + def _load_all_notify(self): for op_name, op in self.ops.items(): if not op: @@ -2379,7 +2401,7 @@ def main(): cw.nl() cw.p('/* Common nested types */') - for attr_set, struct in sorted(parsed.pure_nested_structs.items()): + for attr_set, struct in parsed.pure_nested_structs.items(): ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set) print_type_full(ri, struct) @@ -2448,7 +2470,7 @@ def main(): put_typol(cw, struct) cw.p('/* Common nested types */') - for attr_set, struct in sorted(parsed.pure_nested_structs.items()): + for attr_set, struct in parsed.pure_nested_structs.items(): ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set) free_rsp_nested(ri, struct) -- cgit v1.2.3 From 37487f93b12551f82547e04b32d8d285818ea7a0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:23:58 -0700 Subject: tools: ynl-gen: inherit struct use info We only render parse and netlink generation helpers as needed, to avoid generating dead code. Propagate the information from first- and second-layer attribute sets onto all children. Otherwise devlink won't work, it has a lot more levels of nesting. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index d9c74a678df8..1a97cd517116 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -896,6 +896,14 @@ class Family(SpecFamily): pns_key_seen.add(name) else: pns_key_list.append(name) + # Propagate the request / reply + for attr_set, struct in reversed(self.pure_nested_structs.items()): + for _, spec in self.attr_sets[attr_set].items(): + if 'nested-attributes' in spec: + child = self.pure_nested_structs.get(spec['nested-attributes']) + if child: + child.request |= struct.request + child.reply |= struct.reply def _load_all_notify(self): for op_name, op in self.ops.items(): -- cgit v1.2.3 From eae7af21bdb9022bfea7ee96fb4fa6c39bf02f32 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:23:59 -0700 Subject: tools: ynl-gen: walk nested types in depth So far we had only created structures for nested types nested directly in messages (second level of attrs so to speak). Walk types in depth to support deeper nesting. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 1a97cd517116..0cb0f74e714b 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -854,27 +854,44 @@ class Family(SpecFamily): self.root_sets[op['attribute-set']]['reply'].update(rsp_attrs) def _load_nested_sets(self): + attr_set_queue = list(self.root_sets.keys()) + attr_set_seen = set(self.root_sets.keys()) + + while len(attr_set_queue): + a_set = attr_set_queue.pop(0) + for attr, spec in self.attr_sets[a_set].items(): + if 'nested-attributes' not in spec: + continue + + nested = spec['nested-attributes'] + if nested not in attr_set_seen: + attr_set_queue.append(nested) + attr_set_seen.add(nested) + + inherit = set() + if nested not in self.root_sets: + if nested not in self.pure_nested_structs: + self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) + else: + raise Exception(f'Using attr set as root and nested not supported - {nested}') + + if 'type-value' in spec: + if nested in self.root_sets: + raise Exception("Inheriting members to a space used as root not supported") + inherit.update(set(spec['type-value'])) + elif spec['type'] == 'array-nest': + inherit.add('idx') + self.pure_nested_structs[nested].set_inherited(inherit) + for root_set, rs_members in self.root_sets.items(): for attr, spec in self.attr_sets[root_set].items(): if 'nested-attributes' in spec: - inherit = set() nested = spec['nested-attributes'] - if nested not in self.root_sets: - if nested not in self.pure_nested_structs: - self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) if attr in rs_members['request']: self.pure_nested_structs[nested].request = True if attr in rs_members['reply']: self.pure_nested_structs[nested].reply = True - if 'type-value' in spec: - if nested in self.root_sets: - raise Exception("Inheriting members to a space used as root not supported") - inherit.update(set(spec['type-value'])) - elif spec['type'] == 'array-nest': - inherit.add('idx') - self.pure_nested_structs[nested].set_inherited(inherit) - # Try to reorder according to dependencies pns_key_list = list(self.pure_nested_structs.keys()) pns_key_seen = set() -- cgit v1.2.3 From 168dea20ecef59f9e513a8b869da4841775cc49d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:24:00 -0700 Subject: tools: ynl-gen: don't generate forward declarations for policies Now that all nested types have structs and are sorted topologically there should be no need to generate forward declarations for policies. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 0cb0f74e714b..251c5bfffd8d 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1235,10 +1235,6 @@ def print_dump_prototype(ri): print_prototype(ri, "request") -def put_typol_fwd(cw, struct): - cw.p(f'extern struct ynl_policy_nest {struct.render_name}_nest;') - - def put_typol(cw, struct): type_max = struct.attr_set.max_name cw.block_start(line=f'struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =') @@ -2485,12 +2481,10 @@ def main(): cw.nl() cw.p('/* Policies */') - for name, _ in parsed.attr_sets.items(): + for name in parsed.pure_nested_structs: struct = Struct(parsed, name) - put_typol_fwd(cw, struct) - cw.nl() - - for name, _ in parsed.attr_sets.items(): + put_typol(cw, struct) + for name in parsed.root_sets: struct = Struct(parsed, name) put_typol(cw, struct) -- cgit v1.2.3 From 0a9471219672c63b4729f4011a77e017becf8607 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:24:01 -0700 Subject: tools: ynl-gen: don't generate forward declarations for policies - regen Renegerate code after dropping forward declarations for policies. Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/fou-user.c | 2 -- tools/net/ynl/generated/handshake-user.c | 4 ---- tools/net/ynl/generated/netdev-user.c | 2 -- 3 files changed, 8 deletions(-) diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c index a0f33bb882e4..c08c85a6b6c4 100644 --- a/tools/net/ynl/generated/fou-user.c +++ b/tools/net/ynl/generated/fou-user.c @@ -42,8 +42,6 @@ const char *fou_encap_type_str(int value) } /* Policies */ -extern struct ynl_policy_nest fou_nest; - struct ynl_policy_attr fou_policy[FOU_ATTR_MAX + 1] = { [FOU_ATTR_UNSPEC] = { .name = "unspec", .type = YNL_PT_REJECT, }, [FOU_ATTR_PORT] = { .name = "port", .type = YNL_PT_U16, }, diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c index fe99c4ef7373..72eb1c52a8fc 100644 --- a/tools/net/ynl/generated/handshake-user.c +++ b/tools/net/ynl/generated/handshake-user.c @@ -69,10 +69,6 @@ const char *handshake_auth_str(enum handshake_auth value) } /* Policies */ -extern struct ynl_policy_nest handshake_x509_nest; -extern struct ynl_policy_nest handshake_accept_nest; -extern struct ynl_policy_nest handshake_done_nest; - struct ynl_policy_attr handshake_x509_policy[HANDSHAKE_A_X509_MAX + 1] = { [HANDSHAKE_A_X509_CERT] = { .name = "cert", .type = YNL_PT_U32, }, [HANDSHAKE_A_X509_PRIVKEY] = { .name = "privkey", .type = YNL_PT_U32, }, diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index aea5c7cc8ead..3db6921b9fab 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -48,8 +48,6 @@ const char *netdev_xdp_act_str(enum netdev_xdp_act value) } /* Policies */ -extern struct ynl_policy_nest netdev_dev_nest; - struct ynl_policy_attr netdev_dev_policy[NETDEV_A_DEV_MAX + 1] = { [NETDEV_A_DEV_IFINDEX] = { .name = "ifindex", .type = YNL_PT_U32, }, [NETDEV_A_DEV_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, -- cgit v1.2.3 From 5d1a30eb989afb22b60e7d3985984ebcb00bf598 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:24:02 -0700 Subject: tools: ynl: generate code for the devlink family Admittedly the devlink.yaml spec is fairly limitted, it only covers basic device get and info-get ops. That's sufficient to be useful (monitoring FW versions in the fleet). Plus it gives us a chance to exercise deep nesting and directional messaging in YNL. Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/Makefile | 2 +- tools/net/ynl/generated/devlink-user.c | 721 +++++++++++++++++++++++++++++++++ tools/net/ynl/generated/devlink-user.h | 210 ++++++++++ 3 files changed, 932 insertions(+), 1 deletion(-) create mode 100644 tools/net/ynl/generated/devlink-user.c create mode 100644 tools/net/ynl/generated/devlink-user.h diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 916723193b60..8ce610910b8d 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -9,7 +9,7 @@ endif TOOL:=../ynl-gen-c.py -GENS:=handshake fou netdev +GENS:=devlink handshake fou netdev SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c new file mode 100644 index 000000000000..c3204e20b971 --- /dev/null +++ b/tools/net/ynl/generated/devlink-user.c @@ -0,0 +1,721 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/devlink.yaml */ +/* YNL-GEN user source */ + +#include +#include "devlink-user.h" +#include "ynl.h" +#include + +#include +#include +#include +#include +#include + +/* Enums */ +static const char * const devlink_op_strmap[] = { + [3] = "get", + [DEVLINK_CMD_INFO_GET] = "info-get", +}; + +const char *devlink_op_str(int op) +{ + if (op < 0 || op >= (int)MNL_ARRAY_SIZE(devlink_op_strmap)) + return NULL; + return devlink_op_strmap[op]; +} + +/* Policies */ +struct ynl_policy_attr devlink_dl_info_version_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, +}; + +struct ynl_policy_nest devlink_dl_info_version_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_info_version_policy, +}; + +struct ynl_policy_attr devlink_dl_reload_stats_entry_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest devlink_dl_reload_stats_entry_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_reload_stats_entry_policy, +}; + +struct ynl_policy_attr devlink_dl_reload_act_stats_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, +}; + +struct ynl_policy_nest devlink_dl_reload_act_stats_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_reload_act_stats_policy, +}; + +struct ynl_policy_attr devlink_dl_reload_act_info_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, +}; + +struct ynl_policy_nest devlink_dl_reload_act_info_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_reload_act_info_policy, +}; + +struct ynl_policy_attr devlink_dl_reload_stats_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, +}; + +struct ynl_policy_nest devlink_dl_reload_stats_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_reload_stats_policy, +}; + +struct ynl_policy_attr devlink_dl_dev_stats_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, + [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, +}; + +struct ynl_policy_nest devlink_dl_dev_stats_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_dl_dev_stats_policy, +}; + +struct ynl_policy_attr devlink_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .name = "bus-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_PORT_INDEX] = { .name = "port-index", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_INFO_DRIVER_NAME] = { .name = "info-driver-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = { .name = "info-serial-number", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_INFO_VERSION_FIXED] = { .name = "info-version-fixed", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, + [DEVLINK_ATTR_INFO_VERSION_RUNNING] = { .name = "info-version-running", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, + [DEVLINK_ATTR_INFO_VERSION_STORED] = { .name = "info-version-stored", .type = YNL_PT_NEST, .nest = &devlink_dl_info_version_nest, }, + [DEVLINK_ATTR_INFO_VERSION_NAME] = { .name = "info-version-name", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_INFO_VERSION_VALUE] = { .name = "info-version-value", .type = YNL_PT_NUL_STR, }, + [DEVLINK_ATTR_RELOAD_FAILED] = { .name = "reload-failed", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RELOAD_ACTION] = { .name = "reload-action", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_DEV_STATS] = { .name = "dev-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_dev_stats_nest, }, + [DEVLINK_ATTR_RELOAD_STATS] = { .name = "reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, + [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = { .name = "reload-stats-entry", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_entry_nest, }, + [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = { .name = "reload-stats-limit", .type = YNL_PT_U8, }, + [DEVLINK_ATTR_RELOAD_STATS_VALUE] = { .name = "reload-stats-value", .type = YNL_PT_U32, }, + [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = { .name = "remote-reload-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_stats_nest, }, + [DEVLINK_ATTR_RELOAD_ACTION_INFO] = { .name = "reload-action-info", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_info_nest, }, + [DEVLINK_ATTR_RELOAD_ACTION_STATS] = { .name = "reload-action-stats", .type = YNL_PT_NEST, .nest = &devlink_dl_reload_act_stats_nest, }, +}; + +struct ynl_policy_nest devlink_nest = { + .max_attr = DEVLINK_ATTR_MAX, + .table = devlink_policy, +}; + +/* Common nested types */ +void devlink_dl_info_version_free(struct devlink_dl_info_version *obj) +{ + free(obj->info_version_name); + free(obj->info_version_value); +} + +int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_info_version *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.info_version_name_len = len; + dst->info_version_name = malloc(len + 1); + memcpy(dst->info_version_name, mnl_attr_get_str(attr), len); + dst->info_version_name[len] = 0; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_VALUE) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.info_version_value_len = len; + dst->info_version_value = malloc(len + 1); + memcpy(dst->info_version_value, mnl_attr_get_str(attr), len); + dst->info_version_value[len] = 0; + } + } + + return 0; +} + +void +devlink_dl_reload_stats_entry_free(struct devlink_dl_reload_stats_entry *obj) +{ +} + +int devlink_dl_reload_stats_entry_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_reload_stats_entry *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_LIMIT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_stats_limit = 1; + dst->reload_stats_limit = mnl_attr_get_u8(attr); + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_VALUE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_stats_value = 1; + dst->reload_stats_value = mnl_attr_get_u32(attr); + } + } + + return 0; +} + +void devlink_dl_reload_act_stats_free(struct devlink_dl_reload_act_stats *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_reload_stats_entry; i++) + devlink_dl_reload_stats_entry_free(&obj->reload_stats_entry[i]); + free(obj->reload_stats_entry); +} + +int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_reload_act_stats *dst = yarg->data; + unsigned int n_reload_stats_entry = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->reload_stats_entry) + return ynl_error_parse(yarg, "attribute already present (dl-reload-act-stats.reload-stats-entry)"); + + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { + n_reload_stats_entry++; + } + } + + if (n_reload_stats_entry) { + dst->reload_stats_entry = calloc(n_reload_stats_entry, sizeof(*dst->reload_stats_entry)); + dst->n_reload_stats_entry = n_reload_stats_entry; + i = 0; + parg.rsp_policy = &devlink_dl_reload_stats_entry_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { + parg.data = &dst->reload_stats_entry[i]; + if (devlink_dl_reload_stats_entry_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_reload_act_info_free(struct devlink_dl_reload_act_info *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_reload_action_stats; i++) + devlink_dl_reload_act_stats_free(&obj->reload_action_stats[i]); + free(obj->reload_action_stats); +} + +int devlink_dl_reload_act_info_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_reload_act_info *dst = yarg->data; + unsigned int n_reload_action_stats = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->reload_action_stats) + return ynl_error_parse(yarg, "attribute already present (dl-reload-act-info.reload-action-stats)"); + + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_action = 1; + dst->reload_action = mnl_attr_get_u8(attr); + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) { + n_reload_action_stats++; + } + } + + if (n_reload_action_stats) { + dst->reload_action_stats = calloc(n_reload_action_stats, sizeof(*dst->reload_action_stats)); + dst->n_reload_action_stats = n_reload_action_stats; + i = 0; + parg.rsp_policy = &devlink_dl_reload_act_stats_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) { + parg.data = &dst->reload_action_stats[i]; + if (devlink_dl_reload_act_stats_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_reload_stats_free(struct devlink_dl_reload_stats *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_reload_action_info; i++) + devlink_dl_reload_act_info_free(&obj->reload_action_info[i]); + free(obj->reload_action_info); +} + +int devlink_dl_reload_stats_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_reload_stats *dst = yarg->data; + unsigned int n_reload_action_info = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->reload_action_info) + return ynl_error_parse(yarg, "attribute already present (dl-reload-stats.reload-action-info)"); + + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) { + n_reload_action_info++; + } + } + + if (n_reload_action_info) { + dst->reload_action_info = calloc(n_reload_action_info, sizeof(*dst->reload_action_info)); + dst->n_reload_action_info = n_reload_action_info; + i = 0; + parg.rsp_policy = &devlink_dl_reload_act_info_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) { + parg.data = &dst->reload_action_info[i]; + if (devlink_dl_reload_act_info_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void devlink_dl_dev_stats_free(struct devlink_dl_dev_stats *obj) +{ + devlink_dl_reload_stats_free(&obj->reload_stats); + devlink_dl_reload_stats_free(&obj->remote_reload_stats); +} + +int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct devlink_dl_dev_stats *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + parg.ys = yarg->ys; + + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_stats = 1; + + parg.rsp_policy = &devlink_dl_reload_stats_nest; + parg.data = &dst->reload_stats; + if (devlink_dl_reload_stats_parse(&parg, attr)) + return MNL_CB_ERROR; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_REMOTE_RELOAD_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.remote_reload_stats = 1; + + parg.rsp_policy = &devlink_dl_reload_stats_nest; + parg.data = &dst->remote_reload_stats; + if (devlink_dl_reload_stats_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return 0; +} + +/* ============== DEVLINK_CMD_GET ============== */ +/* DEVLINK_CMD_GET - do */ +void devlink_get_req_free(struct devlink_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void devlink_get_rsp_free(struct devlink_get_rsp *rsp) +{ + free(rsp->bus_name); + free(rsp->dev_name); + devlink_dl_dev_stats_free(&rsp->dev_stats); + free(rsp); +} + +int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct devlink_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_FAILED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_failed = 1; + dst->reload_failed = mnl_attr_get_u8(attr); + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reload_action = 1; + dst->reload_action = mnl_attr_get_u8(attr); + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dev_stats = 1; + + parg.rsp_policy = &devlink_dl_dev_stats_nest; + parg.data = &dst->dev_stats; + if (devlink_dl_dev_stats_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct devlink_get_rsp * +devlink_get(struct ynl_sock *ys, struct devlink_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_get_rsp_parse; + yrs.rsp_cmd = 3; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_get_rsp_free(rsp); + return NULL; +} + +/* DEVLINK_CMD_GET - dump */ +void devlink_get_list_free(struct devlink_get_list *rsp) +{ + struct devlink_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + free(rsp->obj.bus_name); + free(rsp->obj.dev_name); + devlink_dl_dev_stats_free(&rsp->obj.dev_stats); + free(rsp); + } +} + +struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct devlink_get_list); + yds.cb = devlink_get_rsp_parse; + yds.rsp_cmd = 3; + yds.rsp_policy = &devlink_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, DEVLINK_CMD_GET, 1); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + devlink_get_list_free(yds.first); + return NULL; +} + +/* ============== DEVLINK_CMD_INFO_GET ============== */ +/* DEVLINK_CMD_INFO_GET - do */ +void devlink_info_get_req_free(struct devlink_info_get_req *req) +{ + free(req->bus_name); + free(req->dev_name); + free(req); +} + +void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp) +{ + unsigned int i; + + free(rsp->bus_name); + free(rsp->dev_name); + free(rsp->info_driver_name); + free(rsp->info_serial_number); + for (i = 0; i < rsp->n_info_version_fixed; i++) + devlink_dl_info_version_free(&rsp->info_version_fixed[i]); + free(rsp->info_version_fixed); + for (i = 0; i < rsp->n_info_version_running; i++) + devlink_dl_info_version_free(&rsp->info_version_running[i]); + free(rsp->info_version_running); + for (i = 0; i < rsp->n_info_version_stored; i++) + devlink_dl_info_version_free(&rsp->info_version_stored[i]); + free(rsp->info_version_stored); + free(rsp); +} + +int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + unsigned int n_info_version_running = 0; + unsigned int n_info_version_stored = 0; + unsigned int n_info_version_fixed = 0; + struct ynl_parse_arg *yarg = data; + struct devlink_info_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + dst = yarg->data; + parg.ys = yarg->ys; + + if (dst->info_version_fixed) + return ynl_error_parse(yarg, "attribute already present (devlink.info-version-fixed)"); + if (dst->info_version_running) + return ynl_error_parse(yarg, "attribute already present (devlink.info-version-running)"); + if (dst->info_version_stored) + return ynl_error_parse(yarg, "attribute already present (devlink.info-version-stored)"); + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_BUS_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.bus_name_len = len; + dst->bus_name = malloc(len + 1); + memcpy(dst->bus_name, mnl_attr_get_str(attr), len); + dst->bus_name[len] = 0; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_DRIVER_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.info_driver_name_len = len; + dst->info_driver_name = malloc(len + 1); + memcpy(dst->info_driver_name, mnl_attr_get_str(attr), len); + dst->info_driver_name[len] = 0; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_SERIAL_NUMBER) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.info_serial_number_len = len; + dst->info_serial_number = malloc(len + 1); + memcpy(dst->info_serial_number, mnl_attr_get_str(attr), len); + dst->info_serial_number[len] = 0; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_FIXED) { + n_info_version_fixed++; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_RUNNING) { + n_info_version_running++; + } + else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_STORED) { + n_info_version_stored++; + } + } + + if (n_info_version_fixed) { + dst->info_version_fixed = calloc(n_info_version_fixed, sizeof(*dst->info_version_fixed)); + dst->n_info_version_fixed = n_info_version_fixed; + i = 0; + parg.rsp_policy = &devlink_dl_info_version_nest; + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_FIXED) { + parg.data = &dst->info_version_fixed[i]; + if (devlink_dl_info_version_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + if (n_info_version_running) { + dst->info_version_running = calloc(n_info_version_running, sizeof(*dst->info_version_running)); + dst->n_info_version_running = n_info_version_running; + i = 0; + parg.rsp_policy = &devlink_dl_info_version_nest; + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_RUNNING) { + parg.data = &dst->info_version_running[i]; + if (devlink_dl_info_version_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + if (n_info_version_stored) { + dst->info_version_stored = calloc(n_info_version_stored, sizeof(*dst->info_version_stored)); + dst->n_info_version_stored = n_info_version_stored; + i = 0; + parg.rsp_policy = &devlink_dl_info_version_nest; + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_STORED) { + parg.data = &dst->info_version_stored[i]; + if (devlink_dl_info_version_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return MNL_CB_OK; +} + +struct devlink_info_get_rsp * +devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct devlink_info_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, DEVLINK_CMD_INFO_GET, 1); + ys->req_policy = &devlink_nest; + yrs.yarg.rsp_policy = &devlink_nest; + + if (req->_present.bus_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, req->bus_name); + if (req->_present.dev_name_len) + mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, req->dev_name); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = devlink_info_get_rsp_parse; + yrs.rsp_cmd = DEVLINK_CMD_INFO_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + devlink_info_get_rsp_free(rsp); + return NULL; +} + +const struct ynl_family ynl_devlink_family = { + .name = "devlink", +}; diff --git a/tools/net/ynl/generated/devlink-user.h b/tools/net/ynl/generated/devlink-user.h new file mode 100644 index 000000000000..a008b99b6e24 --- /dev/null +++ b/tools/net/ynl/generated/devlink-user.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/devlink.yaml */ +/* YNL-GEN user header */ + +#ifndef _LINUX_DEVLINK_GEN_H +#define _LINUX_DEVLINK_GEN_H + +#include +#include +#include +#include + +struct ynl_sock; + +extern const struct ynl_family ynl_devlink_family; + +/* Enums */ +const char *devlink_op_str(int op); + +/* Common nested types */ +struct devlink_dl_info_version { + struct { + __u32 info_version_name_len; + __u32 info_version_value_len; + } _present; + + char *info_version_name; + char *info_version_value; +}; + +struct devlink_dl_reload_stats_entry { + struct { + __u32 reload_stats_limit:1; + __u32 reload_stats_value:1; + } _present; + + __u8 reload_stats_limit; + __u32 reload_stats_value; +}; + +struct devlink_dl_reload_act_stats { + unsigned int n_reload_stats_entry; + struct devlink_dl_reload_stats_entry *reload_stats_entry; +}; + +struct devlink_dl_reload_act_info { + struct { + __u32 reload_action:1; + } _present; + + __u8 reload_action; + unsigned int n_reload_action_stats; + struct devlink_dl_reload_act_stats *reload_action_stats; +}; + +struct devlink_dl_reload_stats { + unsigned int n_reload_action_info; + struct devlink_dl_reload_act_info *reload_action_info; +}; + +struct devlink_dl_dev_stats { + struct { + __u32 reload_stats:1; + __u32 remote_reload_stats:1; + } _present; + + struct devlink_dl_reload_stats reload_stats; + struct devlink_dl_reload_stats remote_reload_stats; +}; + +/* ============== DEVLINK_CMD_GET ============== */ +/* DEVLINK_CMD_GET - do */ +struct devlink_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_get_req *devlink_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_get_req)); +} +void devlink_get_req_free(struct devlink_get_req *req); + +static inline void +devlink_get_req_set_bus_name(struct devlink_get_req *req, const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_get_req_set_dev_name(struct devlink_get_req *req, const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 reload_failed:1; + __u32 reload_action:1; + __u32 dev_stats:1; + } _present; + + char *bus_name; + char *dev_name; + __u8 reload_failed; + __u8 reload_action; + struct devlink_dl_dev_stats dev_stats; +}; + +void devlink_get_rsp_free(struct devlink_get_rsp *rsp); + +/* + * Get devlink instances. + */ +struct devlink_get_rsp * +devlink_get(struct ynl_sock *ys, struct devlink_get_req *req); + +/* DEVLINK_CMD_GET - dump */ +struct devlink_get_list { + struct devlink_get_list *next; + struct devlink_get_rsp obj __attribute__ ((aligned (8))); +}; + +void devlink_get_list_free(struct devlink_get_list *rsp); + +struct devlink_get_list *devlink_get_dump(struct ynl_sock *ys); + +/* ============== DEVLINK_CMD_INFO_GET ============== */ +/* DEVLINK_CMD_INFO_GET - do */ +struct devlink_info_get_req { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + } _present; + + char *bus_name; + char *dev_name; +}; + +static inline struct devlink_info_get_req *devlink_info_get_req_alloc(void) +{ + return calloc(1, sizeof(struct devlink_info_get_req)); +} +void devlink_info_get_req_free(struct devlink_info_get_req *req); + +static inline void +devlink_info_get_req_set_bus_name(struct devlink_info_get_req *req, + const char *bus_name) +{ + free(req->bus_name); + req->_present.bus_name_len = strlen(bus_name); + req->bus_name = malloc(req->_present.bus_name_len + 1); + memcpy(req->bus_name, bus_name, req->_present.bus_name_len); + req->bus_name[req->_present.bus_name_len] = 0; +} +static inline void +devlink_info_get_req_set_dev_name(struct devlink_info_get_req *req, + const char *dev_name) +{ + free(req->dev_name); + req->_present.dev_name_len = strlen(dev_name); + req->dev_name = malloc(req->_present.dev_name_len + 1); + memcpy(req->dev_name, dev_name, req->_present.dev_name_len); + req->dev_name[req->_present.dev_name_len] = 0; +} + +struct devlink_info_get_rsp { + struct { + __u32 bus_name_len; + __u32 dev_name_len; + __u32 info_driver_name_len; + __u32 info_serial_number_len; + } _present; + + char *bus_name; + char *dev_name; + char *info_driver_name; + char *info_serial_number; + unsigned int n_info_version_fixed; + struct devlink_dl_info_version *info_version_fixed; + unsigned int n_info_version_running; + struct devlink_dl_info_version *info_version_running; + unsigned int n_info_version_stored; + struct devlink_dl_info_version *info_version_stored; +}; + +void devlink_info_get_rsp_free(struct devlink_info_get_rsp *rsp); + +/* + * Get device information, like driver name, hardware and firmware versions etc. + */ +struct devlink_info_get_rsp * +devlink_info_get(struct ynl_sock *ys, struct devlink_info_get_req *req); + +#endif /* _LINUX_DEVLINK_GEN_H */ -- cgit v1.2.3 From fff8660b5425bb2f441d67758926df62e61a69aa Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 7 Jun 2023 13:24:03 -0700 Subject: tools: ynl: add sample for devlink Add a sample to show off how to issue basic devlink requests. For added testing issue get requests while walking a dump. $ ./devlink netdevsim/netdevsim1: driver: netdevsim running fw: fw.mgmt: 10.20.30 ... netdevsim/netdevsim2: driver: netdevsim running fw: fw.mgmt: 10.20.30 ... Signed-off-by: Jakub Kicinski --- tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/devlink.c | 60 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tools/net/ynl/samples/devlink.c diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore index 7b1f5179cb54..a24678b67557 100644 --- a/tools/net/ynl/samples/.gitignore +++ b/tools/net/ynl/samples/.gitignore @@ -1 +1,2 @@ +devlink netdev diff --git a/tools/net/ynl/samples/devlink.c b/tools/net/ynl/samples/devlink.c new file mode 100644 index 000000000000..d2611d7ebab4 --- /dev/null +++ b/tools/net/ynl/samples/devlink.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include + +#include "devlink-user.h" + +int main(int argc, char **argv) +{ + struct devlink_get_list *devs; + struct ynl_sock *ys; + + ys = ynl_sock_create(&ynl_devlink_family, NULL); + if (!ys) + return 1; + + devs = devlink_get_dump(ys); + if (!devs) + goto err_close; + + ynl_dump_foreach(devs, d) { + struct devlink_info_get_req *info_req; + struct devlink_info_get_rsp *info_rsp; + + printf("%s/%s:\n", d->bus_name, d->dev_name); + + info_req = devlink_info_get_req_alloc(); + devlink_info_get_req_set_bus_name(info_req, d->bus_name); + devlink_info_get_req_set_dev_name(info_req, d->dev_name); + + info_rsp = devlink_info_get(ys, info_req); + devlink_info_get_req_free(info_req); + if (!info_rsp) + goto err_free_devs; + + if (info_rsp->_present.info_driver_name_len) + printf(" driver: %s\n", info_rsp->info_driver_name); + if (info_rsp->n_info_version_running) + printf(" running fw:\n"); + for (unsigned i = 0; i < info_rsp->n_info_version_running; i++) + printf(" %s: %s\n", + info_rsp->info_version_running[i].info_version_name, + info_rsp->info_version_running[i].info_version_value); + printf(" ...\n"); + devlink_info_get_rsp_free(info_rsp); + } + devlink_get_list_free(devs); + + ynl_sock_destroy(ys); + + return 0; + +err_free_devs: + devlink_get_list_free(devs); +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); + ynl_sock_destroy(ys); + return 2; +} -- cgit v1.2.3 From 37ff78e977f1a4676354a6c6ebbbf293e540abc1 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 7 Jun 2023 14:19:26 +0200 Subject: mlxsw: spectrum_nve_vxlan: Fix unsupported flag regression The recently added 'VXLAN_F_LOCALBYPASS' flag is set by default on VXLAN devices and denotes a behavior that is irrelevant for the hardware data path. Add it to the lists of IPv4 and IPv6 supported flags to avoid rejecting offload of VXLAN devices which have this flag set. Fixes: 69474a8a5837 ("net: vxlan: Add nolocalbypass option to vxlan.") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: Petr Machata Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/5533e63643bf719bbe286fef60f749c9cad35005.1686139716.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c index d309b77a0194..bb8eeb86edf7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c @@ -11,10 +11,12 @@ #include "spectrum_nve.h" #define MLXSW_SP_NVE_VXLAN_IPV4_SUPPORTED_FLAGS (VXLAN_F_UDP_ZERO_CSUM_TX | \ - VXLAN_F_LEARN) + VXLAN_F_LEARN | \ + VXLAN_F_LOCALBYPASS) #define MLXSW_SP_NVE_VXLAN_IPV6_SUPPORTED_FLAGS (VXLAN_F_IPV6 | \ VXLAN_F_UDP_ZERO_CSUM6_TX | \ - VXLAN_F_UDP_ZERO_CSUM6_RX) + VXLAN_F_UDP_ZERO_CSUM6_RX | \ + VXLAN_F_LOCALBYPASS) static bool mlxsw_sp_nve_vxlan_ipv4_flags_check(const struct vxlan_config *cfg, struct netlink_ext_ack *extack) -- cgit v1.2.3 From c8cc2ae229ff0aa9b7e67fd38f5d73bece111e71 Mon Sep 17 00:00:00 2001 From: Jiaxun Yang Date: Wed, 7 Jun 2023 13:59:53 +0800 Subject: net: pch_gbe: Allow build on MIPS_GENERIC kernel MIPS Boston board, which is using MIPS_GENERIC kernel is using EG20T PCH and thus need this driver. Dependency of PCH_GBE, PTP_1588_CLOCK_PCH is also fixed for MIPS_GENERIC. Note that CONFIG_PCH_GBE is selected in arch/mips/configs/generic/ board-boston.config for a while, some how it's never wired up in Kconfig. Signed-off-by: Jiaxun Yang Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230607055953.34110-1-jiaxun.yang@flygoat.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/oki-semi/pch_gbe/Kconfig | 2 +- drivers/ptp/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig index 4e18b64dceb9..9651cc714ef2 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig +++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig @@ -5,7 +5,7 @@ config PCH_GBE tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE" - depends on PCI && (X86_32 || COMPILE_TEST) + depends on PCI && (MIPS_GENERIC || X86_32 || COMPILE_TEST) depends on PTP_1588_CLOCK select MII select PTP_1588_CLOCK_PCH diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index b00201d81313..32dff1b4f891 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -102,7 +102,7 @@ config PTP_1588_CLOCK_INES config PTP_1588_CLOCK_PCH tristate "Intel PCH EG20T as PTP clock" - depends on X86_32 || COMPILE_TEST + depends on MIPS_GENERIC || X86_32 || COMPILE_TEST depends on HAS_IOMEM && PCI depends on NET depends on PTP_1588_CLOCK -- cgit v1.2.3 From 6c79a9c8b1f3eb00b336fc2557fc5e1a5c15bd20 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:13 +0100 Subject: net: dpaa2-mac: allow lynx PCS to manage mdiodev lifetime Put the mdiodev after lynx_pcs_create() so that the Lynx PCS driver can manage the lifetime of the mdiodev its using. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index cb70855e2b9a..c0f7dd3b4ac1 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -271,9 +271,9 @@ static int dpaa2_pcs_create(struct dpaa2_mac *mac, } mac->pcs = lynx_pcs_create(mdiodev); + mdio_device_put(mdiodev); if (!mac->pcs) { netdev_err(mac->net_dev, "lynx_pcs_create() failed\n"); - mdio_device_free(mdiodev); return -ENOMEM; } @@ -285,10 +285,7 @@ static void dpaa2_pcs_destroy(struct dpaa2_mac *mac) struct phylink_pcs *phylink_pcs = mac->pcs; if (phylink_pcs) { - struct mdio_device *mdio = lynx_get_mdio_device(phylink_pcs); - lynx_pcs_destroy(phylink_pcs); - mdio_device_free(mdio); mac->pcs = NULL; } } -- cgit v1.2.3 From d7b6ea1a14e454ae480274a68daed9136409376f Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:18 +0100 Subject: net: fman_memac: allow lynx PCS to handle mdiodev lifetime Put the mdiodev after lynx_pcs_create() so that the Lynx PCS driver can manage the lifetime of the mdiodev its using. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fman/fman_memac.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 625c79d5636f..8f45caf4af12 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -976,14 +976,10 @@ static int memac_init(struct fman_mac *memac) static void pcs_put(struct phylink_pcs *pcs) { - struct mdio_device *mdiodev; - if (IS_ERR_OR_NULL(pcs)) return; - mdiodev = lynx_get_mdio_device(pcs); lynx_pcs_destroy(pcs); - mdio_device_free(mdiodev); } static int memac_free(struct fman_mac *memac) @@ -1055,8 +1051,7 @@ static struct phylink_pcs *memac_pcs_create(struct device_node *mac_node, return ERR_PTR(-EPROBE_DEFER); pcs = lynx_pcs_create(mdiodev); - if (!pcs) - mdio_device_free(mdiodev); + mdio_device_put(mdiodev); return pcs; } -- cgit v1.2.3 From b3b984dc0ba60ce4787f661d8fc7f44e8953b51d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:24 +0100 Subject: net: pcs: lynx: remove lynx_get_mdio_device() lynx_get_mdio_device() is no longer necessary, let's remove it so the lynx PCS code is always managing the lifetime of the mdiodev. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-lynx.c | 8 -------- include/linux/pcs-lynx.h | 2 -- 2 files changed, 10 deletions(-) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index f04dc580ffb8..a90f74172f49 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -34,14 +34,6 @@ enum sgmii_speed { #define phylink_pcs_to_lynx(pl_pcs) container_of((pl_pcs), struct lynx_pcs, pcs) #define lynx_to_phylink_pcs(lynx) (&(lynx)->pcs) -struct mdio_device *lynx_get_mdio_device(struct phylink_pcs *pcs) -{ - struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); - - return lynx->mdio; -} -EXPORT_SYMBOL(lynx_get_mdio_device); - static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs, struct phylink_link_state *state) { diff --git a/include/linux/pcs-lynx.h b/include/linux/pcs-lynx.h index 885b59d10581..25f68a096bfe 100644 --- a/include/linux/pcs-lynx.h +++ b/include/linux/pcs-lynx.h @@ -9,8 +9,6 @@ #include #include -struct mdio_device *lynx_get_mdio_device(struct phylink_pcs *pcs); - struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio); struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr); -- cgit v1.2.3 From 6e1a12821d34ee37b1196872eccc7dc9b5218a87 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:29 +0100 Subject: net: pcs: lynx: add lynx_pcs_create_fwnode() Add a helper to create a lynx PCS from a fwnode handle. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-lynx.c | 29 +++++++++++++++++++++++++++++ include/linux/pcs-lynx.h | 1 + 2 files changed, 30 insertions(+) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index a90f74172f49..b0907c67d469 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -353,6 +353,35 @@ struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr) } EXPORT_SYMBOL(lynx_pcs_create_mdiodev); +struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node) +{ + struct mdio_device *mdio; + struct phylink_pcs *pcs; + + mdio = fwnode_mdio_find_device(node); + if (!mdio) + return ERR_PTR(-EPROBE_DEFER); + + pcs = lynx_pcs_create(mdio); + + /* Convert failure to create the PCS to an error pointer, so this + * function has a consistent return value strategy. + */ + if (!pcs) + pcs = ERR_PTR(-ENOMEM); + + /* lynx_create() has taken a refcount on the mdiodev if it was + * successful. If lynx_create() fails, this will free the mdio + * device here. In any case, we don't need to hold our reference + * anymore, and putting it here will allow mdio_device_put() in + * lynx_destroy() to automatically free the mdio device. + */ + mdio_device_put(mdio); + + return pcs; +} +EXPORT_SYMBOL_GPL(lynx_pcs_create_fwnode); + void lynx_pcs_destroy(struct phylink_pcs *pcs) { struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); diff --git a/include/linux/pcs-lynx.h b/include/linux/pcs-lynx.h index 25f68a096bfe..123e813df771 100644 --- a/include/linux/pcs-lynx.h +++ b/include/linux/pcs-lynx.h @@ -11,6 +11,7 @@ struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio); struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr); +struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node); void lynx_pcs_destroy(struct phylink_pcs *pcs); -- cgit v1.2.3 From 595fa7634d71be88689f61456f38b4dc252366b4 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:34 +0100 Subject: net: dpaa2-mac: use lynx_pcs_create_fwnode() Use lynx_pcs_create_fwnode() to create a lynx PCS from a fwnode handle. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index c0f7dd3b4ac1..38e6208f9e1a 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -247,8 +247,8 @@ static int dpaa2_pcs_create(struct dpaa2_mac *mac, struct fwnode_handle *dpmac_node, int id) { - struct mdio_device *mdiodev; struct fwnode_handle *node; + struct phylink_pcs *pcs; node = fwnode_find_reference(dpmac_node, "pcs-handle", 0); if (IS_ERR(node)) { @@ -263,20 +263,22 @@ static int dpaa2_pcs_create(struct dpaa2_mac *mac, return -ENODEV; } - mdiodev = fwnode_mdio_find_device(node); + pcs = lynx_pcs_create_fwnode(node); fwnode_handle_put(node); - if (!mdiodev) { + + if (pcs == ERR_PTR(-EPROBE_DEFER)) { netdev_dbg(mac->net_dev, "missing PCS device\n"); return -EPROBE_DEFER; } - mac->pcs = lynx_pcs_create(mdiodev); - mdio_device_put(mdiodev); - if (!mac->pcs) { - netdev_err(mac->net_dev, "lynx_pcs_create() failed\n"); - return -ENOMEM; + if (IS_ERR(pcs)) { + netdev_err(mac->net_dev, + "lynx_pcs_create_fwnode() failed: %pe\n", pcs); + return PTR_ERR(pcs); } + mac->pcs = pcs; + return 0; } -- cgit v1.2.3 From 929a629c211f1e6a4be1b941efab595fe6bfaa69 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:39 +0100 Subject: net: fman_memac: use lynx_pcs_create_fwnode() Use lynx_pcs_create_fwnode() to create a lynx PCS from a fwnode handle. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fman/fman_memac.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 8f45caf4af12..4fbdae996d05 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -1039,19 +1039,14 @@ static struct phylink_pcs *memac_pcs_create(struct device_node *mac_node, int index) { struct device_node *node; - struct mdio_device *mdiodev = NULL; struct phylink_pcs *pcs; node = of_parse_phandle(mac_node, "pcsphy-handle", index); - if (node && of_device_is_available(node)) - mdiodev = of_mdio_find_device(node); - of_node_put(node); - - if (!mdiodev) - return ERR_PTR(-EPROBE_DEFER); + if (!node || !of_device_is_available(node)) + return ERR_PTR(-ENODEV); - pcs = lynx_pcs_create(mdiodev); - mdio_device_put(mdiodev); + pcs = lynx_pcs_create_fwnode(of_fwnode_handle(node)); + of_node_put(node); return pcs; } -- cgit v1.2.3 From 84e476b876d9164af4b965c97eee90fa88204b63 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:44 +0100 Subject: net: pcs: lynx: make lynx_pcs_create() static We no longer need to export lynx_pcs_create() for drivers to use as we now have all the functionality we need in the two new creation helpers. Remove the export and prototype, and make it static. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-lynx.c | 3 +-- include/linux/pcs-lynx.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index b0907c67d469..b8c66137e28d 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -307,7 +307,7 @@ static const struct phylink_pcs_ops lynx_pcs_phylink_ops = { .pcs_link_up = lynx_pcs_link_up, }; -struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) +static struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) { struct lynx_pcs *lynx; @@ -322,7 +322,6 @@ struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) return lynx_to_phylink_pcs(lynx); } -EXPORT_SYMBOL(lynx_pcs_create); struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr) { diff --git a/include/linux/pcs-lynx.h b/include/linux/pcs-lynx.h index 123e813df771..7958cccd16f2 100644 --- a/include/linux/pcs-lynx.h +++ b/include/linux/pcs-lynx.h @@ -9,7 +9,6 @@ #include #include -struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio); struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr); struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node); -- cgit v1.2.3 From 05b606b8845213092b50a855ecf7211caa7c82fa Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:49 +0100 Subject: net: pcs: lynx: change lynx_pcs_create() to return error-pointers Change lynx_pcs_create() to return an error-pointer on failure to allocate memory, rather than returning NULL. This allows the removal of the conversion in lynx_pcs_create_fwnode() and lynx_pcs_create_mdiodev(). Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-lynx.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index b8c66137e28d..c2d01da40430 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -313,7 +313,7 @@ static struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) lynx = kzalloc(sizeof(*lynx), GFP_KERNEL); if (!lynx) - return NULL; + return ERR_PTR(-ENOMEM); mdio_device_get(mdio); lynx->mdio = mdio; @@ -334,12 +334,6 @@ struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr) pcs = lynx_pcs_create(mdio); - /* Convert failure to create the PCS to an error pointer, so this - * function has a consistent return value strategy. - */ - if (!pcs) - pcs = ERR_PTR(-ENOMEM); - /* lynx_create() has taken a refcount on the mdiodev if it was * successful. If lynx_create() fails, this will free the mdio * device here. In any case, we don't need to hold our reference @@ -363,12 +357,6 @@ struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node) pcs = lynx_pcs_create(mdio); - /* Convert failure to create the PCS to an error pointer, so this - * function has a consistent return value strategy. - */ - if (!pcs) - pcs = ERR_PTR(-ENOMEM); - /* lynx_create() has taken a refcount on the mdiodev if it was * successful. If lynx_create() fails, this will free the mdio * device here. In any case, we don't need to hold our reference -- cgit v1.2.3 From d143898c6d7b7f9b171ddc76cd9a3d8356bfddd5 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:54 +0100 Subject: net: pcs: lynx: check that the fwnode is available prior to use Check that the fwnode is marked as available prior to trying to lookup the PCS device, and return -ENODEV if unavailable. Document the return codes from lynx_pcs_create_fwnode(). Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-lynx.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index c2d01da40430..fca48ebf0b81 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -6,6 +6,7 @@ #include #include #include +#include #define SGMII_CLOCK_PERIOD_NS 8 /* PCS is clocked at 125 MHz */ #define LINK_TIMER_VAL(ns) ((u32)((ns) / SGMII_CLOCK_PERIOD_NS)) @@ -346,11 +347,24 @@ struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr) } EXPORT_SYMBOL(lynx_pcs_create_mdiodev); +/* + * lynx_pcs_create_fwnode() creates a lynx PCS instance from the fwnode + * device indicated by node. + * + * Returns: + * -ENODEV if the fwnode is marked unavailable + * -EPROBE_DEFER if we fail to find the device + * -ENOMEM if we fail to allocate memory + * pointer to a phylink_pcs on success + */ struct phylink_pcs *lynx_pcs_create_fwnode(struct fwnode_handle *node) { struct mdio_device *mdio; struct phylink_pcs *pcs; + if (!fwnode_device_is_available(node)) + return ERR_PTR(-ENODEV); + mdio = fwnode_mdio_find_device(node); if (!mdio) return ERR_PTR(-EPROBE_DEFER); -- cgit v1.2.3 From 8c1d0b339d675366ad02fe8c571cdeed0dd28435 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:58:59 +0100 Subject: net: dpaa2: use pcs-lynx's check for fwnode availability Use pcs-lynx's check rather than our own when determining if the device is available. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index 38e6208f9e1a..d860d9fe73af 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -257,12 +257,6 @@ static int dpaa2_pcs_create(struct dpaa2_mac *mac, return 0; } - if (!fwnode_device_is_available(node)) { - netdev_err(mac->net_dev, "pcs-handle node not available\n"); - fwnode_handle_put(node); - return -ENODEV; - } - pcs = lynx_pcs_create_fwnode(node); fwnode_handle_put(node); @@ -271,6 +265,11 @@ static int dpaa2_pcs_create(struct dpaa2_mac *mac, return -EPROBE_DEFER; } + if (pcs == ERR_PTR(-ENODEV)) { + netdev_err(mac->net_dev, "pcs-handle node not available\n"); + return PTR_ERR(pcs); + } + if (IS_ERR(pcs)) { netdev_err(mac->net_dev, "lynx_pcs_create_fwnode() failed: %pe\n", pcs); -- cgit v1.2.3 From 32fc30353f7c4d5370acf6ef8fb3be9363dce3c2 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 7 Jun 2023 12:59:04 +0100 Subject: net: fman_memac: use pcs-lynx's check for fwnode availability Use pcs-lynx's check rather than our own when determining if the device is available. This fixes a bug where the reference gained by of_parse_phandle() is not dropped if the device is not available. Signed-off-by: Russell King (Oracle) Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fman/fman_memac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 4fbdae996d05..3b75cc543be9 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -1042,7 +1042,7 @@ static struct phylink_pcs *memac_pcs_create(struct device_node *mac_node, struct phylink_pcs *pcs; node = of_parse_phandle(mac_node, "pcsphy-handle", index); - if (!node || !of_device_is_available(node)) + if (!node) return ERR_PTR(-ENODEV); pcs = lynx_pcs_create_fwnode(of_fwnode_handle(node)); -- cgit v1.2.3 From 55b24334c0f2db55ca059848121939f59133bdb6 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 7 Jun 2023 16:14:11 -0700 Subject: ethtool: ioctl: improve error checking for set_wol The netlink version of set_wol checks for not supported wolopts and avoids setting wol when the correct wolopt is already set. If we do the same with the ioctl version then we can remove these checks from the driver layer. Reviewed-by: Simon Horman Signed-off-by: Justin Chen Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/1686179653-29750-1-git-send-email-justin.chen@broadcom.com Signed-off-by: Jakub Kicinski --- net/ethtool/ioctl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 6bb778e10461..37b582225854 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1436,15 +1436,25 @@ static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) { - struct ethtool_wolinfo wol; + struct ethtool_wolinfo wol, cur_wol; int ret; - if (!dev->ethtool_ops->set_wol) + if (!dev->ethtool_ops->get_wol || !dev->ethtool_ops->set_wol) return -EOPNOTSUPP; + memset(&cur_wol, 0, sizeof(struct ethtool_wolinfo)); + cur_wol.cmd = ETHTOOL_GWOL; + dev->ethtool_ops->get_wol(dev, &cur_wol); + if (copy_from_user(&wol, useraddr, sizeof(wol))) return -EFAULT; + if (wol.wolopts & ~cur_wol.supported) + return -EINVAL; + + if (wol.wolopts == cur_wol.wolopts) + return 0; + ret = dev->ethtool_ops->set_wol(dev, &wol); if (ret) return ret; -- cgit v1.2.3 From 736013292e3ca5ec2aabb32daf72a73b1256ac57 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 7 Jun 2023 21:41:13 +0000 Subject: tcp: let tcp_mtu_probe() build headless packets tcp_mtu_probe() is still copying payload from skbs in the write queue, using skb_copy_bits(), ignoring potential errors. Modern TCP stack wants to only deal with payload found in page frags, as this is a prereq for TCPDirect (host stack might not have access to the payload) Signed-off-by: Eric Dumazet Link: https://lore.kernel.org/r/20230607214113.1992947-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_output.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index cfe128b81a01..f8ce77ce7c3e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2319,6 +2319,57 @@ static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len) return true; } +static int tcp_clone_payload(struct sock *sk, struct sk_buff *to, + int probe_size) +{ + skb_frag_t *lastfrag = NULL, *fragto = skb_shinfo(to)->frags; + int i, todo, len = 0, nr_frags = 0; + const struct sk_buff *skb; + + if (!sk_wmem_schedule(sk, to->truesize + probe_size)) + return -ENOMEM; + + skb_queue_walk(&sk->sk_write_queue, skb) { + const skb_frag_t *fragfrom = skb_shinfo(skb)->frags; + + if (skb_headlen(skb)) + return -EINVAL; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, fragfrom++) { + if (len >= probe_size) + goto commit; + todo = min_t(int, skb_frag_size(fragfrom), + probe_size - len); + len += todo; + if (lastfrag && + skb_frag_page(fragfrom) == skb_frag_page(lastfrag) && + skb_frag_off(fragfrom) == skb_frag_off(lastfrag) + + skb_frag_size(lastfrag)) { + skb_frag_size_add(lastfrag, todo); + continue; + } + if (unlikely(nr_frags == MAX_SKB_FRAGS)) + return -E2BIG; + skb_frag_page_copy(fragto, fragfrom); + skb_frag_off_copy(fragto, fragfrom); + skb_frag_size_set(fragto, todo); + nr_frags++; + lastfrag = fragto++; + } + } +commit: + WARN_ON_ONCE(len != probe_size); + for (i = 0; i < nr_frags; i++) + skb_frag_ref(to, i); + + skb_shinfo(to)->nr_frags = nr_frags; + to->truesize += probe_size; + to->len += probe_size; + to->data_len += probe_size; + __skb_header_release(to); + return 0; +} + /* Create a new MTU probe if we are ready. * MTU probe is regularly attempting to increase the path MTU by * deliberately sending larger packets. This discovers routing @@ -2395,9 +2446,15 @@ static int tcp_mtu_probe(struct sock *sk) return -1; /* We're allowed to probe. Build it now. */ - nskb = tcp_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false); + nskb = tcp_stream_alloc_skb(sk, 0, GFP_ATOMIC, false); if (!nskb) return -1; + + /* build the payload, and be prepared to abort if this fails. */ + if (tcp_clone_payload(sk, nskb, probe_size)) { + consume_skb(nskb); + return -1; + } sk_wmem_queued_add(sk, nskb->truesize); sk_mem_charge(sk, nskb->truesize); @@ -2415,7 +2472,6 @@ static int tcp_mtu_probe(struct sock *sk) len = 0; tcp_for_write_queue_from_safe(skb, next, sk) { copy = min_t(int, skb->len, probe_size - len); - skb_copy_bits(skb, 0, skb_put(nskb, copy), copy); if (skb->len <= copy) { /* We've eaten all the data from this skb. -- cgit v1.2.3 From 4fe38acdac8a71f7cccf347a2e9902bc818ecef7 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:07 +0100 Subject: net: Block MSG_SENDPAGE_* from being passed to sendmsg() by userspace It is necessary to allow MSG_SENDPAGE_* to be passed into ->sendmsg() to allow sendmsg(MSG_SPLICE_PAGES) to replace ->sendpage(). Unblocking them in the network protocol, however, allows these flags to be passed in by userspace too[1]. Fix this by marking MSG_SENDPAGE_NOPOLICY, MSG_SENDPAGE_NOTLAST and MSG_SENDPAGE_DECRYPTED as internal flags, which causes sendmsg() to object if they are passed to sendmsg() by userspace. Network protocol ->sendmsg() implementations can then allow them through. Note that it should be possible to remove MSG_SENDPAGE_NOTLAST once sendpage is removed as a whole slew of pages will be passed in in one go by splice through sendmsg, with MSG_MORE being set if it has more data waiting in the pipe. Signed-off-by: David Howells cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Link: https://lore.kernel.org/r/20230526181338.03a99016@kernel.org/ [1] Signed-off-by: Jakub Kicinski --- include/linux/socket.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/linux/socket.h b/include/linux/socket.h index bd1cc3238851..3fd3436bc09f 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -339,7 +339,9 @@ struct ucred { #endif /* Flags to be cleared on entry by sendmsg and sendmmsg syscalls */ -#define MSG_INTERNAL_SENDMSG_FLAGS (MSG_SPLICE_PAGES) +#define MSG_INTERNAL_SENDMSG_FLAGS \ + (MSG_SPLICE_PAGES | MSG_SENDPAGE_NOPOLICY | MSG_SENDPAGE_NOTLAST | \ + MSG_SENDPAGE_DECRYPTED) /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ #define SOL_IP 0 -- cgit v1.2.3 From 81840b3b91aad06053ad2712f3da5d0448eeb0e8 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:08 +0100 Subject: tls: Allow MSG_SPLICE_PAGES but treat it as normal sendmsg Allow MSG_SPLICE_PAGES to be specified to sendmsg() but treat it as normal sendmsg for now. This means the data will just be copied until MSG_SPLICE_PAGES is handled. Signed-off-by: David Howells cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/tls/tls_device.c | 3 ++- net/tls/tls_sw.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index a959572a816f..9ef766e41c7a 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -447,7 +447,8 @@ static int tls_push_data(struct sock *sk, long timeo; if (flags & - ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SENDPAGE_NOTLAST)) + ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SENDPAGE_NOTLAST | + MSG_SPLICE_PAGES)) return -EOPNOTSUPP; if (unlikely(sk->sk_err)) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 1a53c8f481e9..38acc27a0dd0 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -955,7 +955,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) int pending; if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | - MSG_CMSG_COMPAT)) + MSG_CMSG_COMPAT | MSG_SPLICE_PAGES)) return -EOPNOTSUPP; ret = mutex_lock_interruptible(&tls_ctx->tx_lock); -- cgit v1.2.3 From 2dc334f1a63a8839b88483a3e73c0f27c9c1791c Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:09 +0100 Subject: splice, net: Use sendmsg(MSG_SPLICE_PAGES) rather than ->sendpage() Replace generic_splice_sendpage() + splice_from_pipe + pipe_to_sendpage() with a net-specific handler, splice_to_socket(), that calls sendmsg() with MSG_SPLICE_PAGES set instead of calling ->sendpage(). MSG_MORE is used to indicate if the sendmsg() is expected to be followed with more data. This allows multiple pipe-buffer pages to be passed in a single call in a BVEC iterator, allowing the processing to be pushed down to a loop in the protocol driver. This helps pave the way for passing multipage folios down too. Protocols that haven't been converted to handle MSG_SPLICE_PAGES yet should just ignore it and do a normal sendmsg() for now - although that may be a bit slower as it may copy everything. Signed-off-by: David Howells Reviewed-by: Jakub Kicinski cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- fs/splice.c | 158 +++++++++++++++++++++++++++++++++++++++---------- include/linux/fs.h | 2 - include/linux/splice.h | 2 + net/socket.c | 26 +------- 4 files changed, 131 insertions(+), 57 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 3e06611d19ae..e337630aed64 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -448,30 +449,6 @@ const struct pipe_buf_operations nosteal_pipe_buf_ops = { }; EXPORT_SYMBOL(nosteal_pipe_buf_ops); -/* - * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' - * using sendpage(). Return the number of bytes sent. - */ -static int pipe_to_sendpage(struct pipe_inode_info *pipe, - struct pipe_buffer *buf, struct splice_desc *sd) -{ - struct file *file = sd->u.file; - loff_t pos = sd->pos; - int more; - - if (!likely(file->f_op->sendpage)) - return -EINVAL; - - more = (sd->flags & SPLICE_F_MORE) ? MSG_MORE : 0; - - if (sd->len < sd->total_len && - pipe_occupancy(pipe->head, pipe->tail) > 1) - more |= MSG_SENDPAGE_NOTLAST; - - return file->f_op->sendpage(file, buf->page, buf->offset, - sd->len, &pos, more); -} - static void wakeup_pipe_writers(struct pipe_inode_info *pipe) { smp_mb(); @@ -652,7 +629,7 @@ static void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_des * Description: * This function does little more than loop over the pipe and call * @actor to do the actual moving of a single struct pipe_buffer to - * the desired destination. See pipe_to_file, pipe_to_sendpage, or + * the desired destination. See pipe_to_file, pipe_to_sendmsg, or * pipe_to_user. * */ @@ -833,8 +810,9 @@ done: EXPORT_SYMBOL(iter_file_splice_write); +#ifdef CONFIG_NET /** - * generic_splice_sendpage - splice data from a pipe to a socket + * splice_to_socket - splice data from a pipe to a socket * @pipe: pipe to splice from * @out: socket to write to * @ppos: position in @out @@ -846,13 +824,131 @@ EXPORT_SYMBOL(iter_file_splice_write); * is involved. * */ -ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags) +ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) { - return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage); -} + struct socket *sock = sock_from_file(out); + struct bio_vec bvec[16]; + struct msghdr msg = {}; + ssize_t ret = 0; + size_t spliced = 0; + bool need_wakeup = false; + + pipe_lock(pipe); + + while (len > 0) { + unsigned int head, tail, mask, bc = 0; + size_t remain = len; + + /* + * Check for signal early to make process killable when there + * are always buffers available + */ + ret = -ERESTARTSYS; + if (signal_pending(current)) + break; -EXPORT_SYMBOL(generic_splice_sendpage); + while (pipe_empty(pipe->head, pipe->tail)) { + ret = 0; + if (!pipe->writers) + goto out; + + if (spliced) + goto out; + + ret = -EAGAIN; + if (flags & SPLICE_F_NONBLOCK) + goto out; + + ret = -ERESTARTSYS; + if (signal_pending(current)) + goto out; + + if (need_wakeup) { + wakeup_pipe_writers(pipe); + need_wakeup = false; + } + + pipe_wait_readable(pipe); + } + + head = pipe->head; + tail = pipe->tail; + mask = pipe->ring_size - 1; + + while (!pipe_empty(head, tail)) { + struct pipe_buffer *buf = &pipe->bufs[tail & mask]; + size_t seg; + + if (!buf->len) { + tail++; + continue; + } + + seg = min_t(size_t, remain, buf->len); + seg = min_t(size_t, seg, PAGE_SIZE); + + ret = pipe_buf_confirm(pipe, buf); + if (unlikely(ret)) { + if (ret == -ENODATA) + ret = 0; + break; + } + + bvec_set_page(&bvec[bc++], buf->page, seg, buf->offset); + remain -= seg; + if (seg >= buf->len) + tail++; + if (bc >= ARRAY_SIZE(bvec)) + break; + } + + if (!bc) + break; + + msg.msg_flags = MSG_SPLICE_PAGES; + if (flags & SPLICE_F_MORE) + msg.msg_flags |= MSG_MORE; + if (remain && pipe_occupancy(pipe->head, tail) > 0) + msg.msg_flags |= MSG_MORE; + + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, bvec, bc, + len - remain); + ret = sock_sendmsg(sock, &msg); + if (ret <= 0) + break; + + spliced += ret; + len -= ret; + tail = pipe->tail; + while (ret > 0) { + struct pipe_buffer *buf = &pipe->bufs[tail & mask]; + size_t seg = min_t(size_t, ret, buf->len); + + buf->offset += seg; + buf->len -= seg; + ret -= seg; + + if (!buf->len) { + pipe_buf_release(pipe, buf); + tail++; + } + } + + if (tail != pipe->tail) { + pipe->tail = tail; + if (pipe->files) + need_wakeup = true; + } + } + +out: + pipe_unlock(pipe); + if (need_wakeup) + wakeup_pipe_writers(pipe); + return spliced ?: ret; +} +#endif static int warn_unsupported(struct file *file, const char *op) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 133f0640fb24..df92f4b3d122 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2759,8 +2759,6 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); extern ssize_t iter_file_splice_write(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); -extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, - struct file *out, loff_t *, size_t len, unsigned int flags); extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, loff_t *opos, size_t len, unsigned int flags); diff --git a/include/linux/splice.h b/include/linux/splice.h index a55179fd60fc..991ae318b6eb 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -84,6 +84,8 @@ extern long do_splice(struct file *in, loff_t *off_in, extern long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags); +extern ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags); /* * for dynamic pipe sizing diff --git a/net/socket.c b/net/socket.c index 3df96e9ba4e2..c4d9104418c8 100644 --- a/net/socket.c +++ b/net/socket.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -126,8 +127,6 @@ static long compat_sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #endif static int sock_fasync(int fd, struct file *filp, int on); -static ssize_t sock_sendpage(struct file *file, struct page *page, - int offset, size_t size, loff_t *ppos, int more); static ssize_t sock_splice_read(struct file *file, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); @@ -162,8 +161,7 @@ static const struct file_operations socket_file_ops = { .mmap = sock_mmap, .release = sock_close, .fasync = sock_fasync, - .sendpage = sock_sendpage, - .splice_write = generic_splice_sendpage, + .splice_write = splice_to_socket, .splice_read = sock_splice_read, .show_fdinfo = sock_show_fdinfo, }; @@ -1066,26 +1064,6 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg, } EXPORT_SYMBOL(kernel_recvmsg); -static ssize_t sock_sendpage(struct file *file, struct page *page, - int offset, size_t size, loff_t *ppos, int more) -{ - struct socket *sock; - int flags; - int ret; - - sock = file->private_data; - - flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; - /* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */ - flags |= more; - - ret = kernel_sendpage(sock, page, offset, size, flags); - - if (trace_sock_send_length_enabled()) - call_trace_sock_send_length(sock->sk, ret, 0); - return ret; -} - static ssize_t sock_splice_read(struct file *file, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) -- cgit v1.2.3 From 2bfc66850952b6921b2033b09729ec59eabbc81d Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:10 +0100 Subject: splice, net: Add a splice_eof op to file-ops and socket-ops Add an optional method, ->splice_eof(), to allow splice to indicate the premature termination of a splice to struct file_operations and struct proto_ops. This is called if sendfile() or splice() encounters all of the following conditions inside splice_direct_to_actor(): (1) the user did not set SPLICE_F_MORE (splice only), and (2) an EOF condition occurred (->splice_read() returned 0), and (3) we haven't read enough to fulfill the request (ie. len > 0 still), and (4) we have already spliced at least one byte. A further patch will modify the behaviour of SPLICE_F_MORE to always be passed to the actor if either the user set it or we haven't yet read sufficient data to fulfill the request. Suggested-by: Linus Torvalds Link: https://lore.kernel.org/r/CAHk-=wh=V579PDYvkpnTobCLGczbgxpMgGmmhqiTyE34Cpi5Gg@mail.gmail.com/ Signed-off-by: David Howells Reviewed-by: Jakub Kicinski cc: Jens Axboe cc: Christoph Hellwig cc: Al Viro cc: Matthew Wilcox cc: Jan Kara cc: Jeff Layton cc: David Hildenbrand cc: Christian Brauner cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: linux-mm@kvack.org Signed-off-by: Jakub Kicinski --- fs/splice.c | 31 ++++++++++++++++++++++++++++++- include/linux/fs.h | 1 + include/linux/net.h | 1 + include/linux/splice.h | 1 + include/net/sock.h | 1 + net/socket.c | 10 ++++++++++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/fs/splice.c b/fs/splice.c index e337630aed64..67dbd85db207 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -969,6 +969,17 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, return out->f_op->splice_write(pipe, out, ppos, len, flags); } +/* + * Indicate to the caller that there was a premature EOF when reading from the + * source and the caller didn't indicate they would be sending more data after + * this. + */ +static void do_splice_eof(struct splice_desc *sd) +{ + if (sd->splice_eof) + sd->splice_eof(sd); +} + /* * Attempt to initiate a splice from a file to a pipe. */ @@ -1068,7 +1079,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, ret = do_splice_to(in, &pos, pipe, len, flags); if (unlikely(ret <= 0)) - goto out_release; + goto read_failure; read_len = ret; sd->total_len = read_len; @@ -1108,6 +1119,15 @@ done: file_accessed(in); return bytes; +read_failure: + /* + * If the user did *not* set SPLICE_F_MORE *and* we didn't hit that + * "use all of len" case that cleared SPLICE_F_MORE, *and* we did a + * "->splice_in()" that returned EOF (ie zero) *and* we have sent at + * least 1 byte *then* we will also do the ->splice_eof() call. + */ + if (ret == 0 && !more && len > 0 && bytes) + do_splice_eof(sd); out_release: /* * If we did an incomplete transfer we must release @@ -1136,6 +1156,14 @@ static int direct_splice_actor(struct pipe_inode_info *pipe, sd->flags); } +static void direct_file_splice_eof(struct splice_desc *sd) +{ + struct file *file = sd->u.file; + + if (file->f_op->splice_eof) + file->f_op->splice_eof(file); +} + /** * do_splice_direct - splices data directly between two files * @in: file to splice from @@ -1161,6 +1189,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, .flags = flags, .pos = *ppos, .u.file = out, + .splice_eof = direct_file_splice_eof, .opos = opos, }; long ret; diff --git a/include/linux/fs.h b/include/linux/fs.h index df92f4b3d122..de2cb1132f07 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1796,6 +1796,7 @@ struct file_operations { int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); + void (*splice_eof)(struct file *file); int (*setlease)(struct file *, long, struct file_lock **, void **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); diff --git a/include/linux/net.h b/include/linux/net.h index b73ad8e3c212..8defc8f1d82e 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -210,6 +210,7 @@ struct proto_ops { int offset, size_t size, int flags); ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); + void (*splice_eof)(struct socket *sock); int (*set_peek_off)(struct sock *sk, int val); int (*peek_len)(struct socket *sock); diff --git a/include/linux/splice.h b/include/linux/splice.h index 991ae318b6eb..4fab18a6e371 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -38,6 +38,7 @@ struct splice_desc { struct file *file; /* file to read/write */ void *data; /* cookie */ } u; + void (*splice_eof)(struct splice_desc *sd); /* Unexpected EOF handler */ loff_t pos; /* file position */ loff_t *opos; /* sendfile: output position */ size_t num_spliced; /* number of bytes already spliced */ diff --git a/include/net/sock.h b/include/net/sock.h index 6f428a7f3567..2790133b4b76 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1279,6 +1279,7 @@ struct proto { size_t len, int flags, int *addr_len); int (*sendpage)(struct sock *sk, struct page *page, int offset, size_t size, int flags); + void (*splice_eof)(struct socket *sock); int (*bind)(struct sock *sk, struct sockaddr *addr, int addr_len); int (*bind_add)(struct sock *sk, diff --git a/net/socket.c b/net/socket.c index c4d9104418c8..b778fc03c6e0 100644 --- a/net/socket.c +++ b/net/socket.c @@ -130,6 +130,7 @@ static int sock_fasync(int fd, struct file *filp, int on); static ssize_t sock_splice_read(struct file *file, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); +static void sock_splice_eof(struct file *file); #ifdef CONFIG_PROC_FS static void sock_show_fdinfo(struct seq_file *m, struct file *f) @@ -163,6 +164,7 @@ static const struct file_operations socket_file_ops = { .fasync = sock_fasync, .splice_write = splice_to_socket, .splice_read = sock_splice_read, + .splice_eof = sock_splice_eof, .show_fdinfo = sock_show_fdinfo, }; @@ -1076,6 +1078,14 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, return sock->ops->splice_read(sock, ppos, pipe, len, flags); } +static void sock_splice_eof(struct file *file) +{ + struct socket *sock = file->private_data; + + if (sock->ops->splice_eof) + sock->ops->splice_eof(sock); +} + static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct file *file = iocb->ki_filp; -- cgit v1.2.3 From df720d288dbb1793e82b6ccbfc670ec871e9def4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:11 +0100 Subject: tls/sw: Use splice_eof() to flush Allow splice to end a TLS record after prematurely ending a splice/sendfile due to getting an EOF condition (->splice_read() returned 0) after splice had called TLS with a sendmsg() with MSG_MORE set when the user didn't set MSG_MORE. Suggested-by: Linus Torvalds Link: https://lore.kernel.org/r/CAHk-=wh=V579PDYvkpnTobCLGczbgxpMgGmmhqiTyE34Cpi5Gg@mail.gmail.com/ Signed-off-by: David Howells Reviewed-by: Jakub Kicinski cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/tls/tls.h | 1 + net/tls/tls_main.c | 2 ++ net/tls/tls_sw.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/net/tls/tls.h b/net/tls/tls.h index 0672acab2773..4922668fefaa 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -97,6 +97,7 @@ void tls_update_rx_zc_capable(struct tls_context *tls_ctx); void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx); void tls_sw_strparser_done(struct tls_context *tls_ctx); int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); +void tls_sw_splice_eof(struct socket *sock); int tls_sw_sendpage_locked(struct sock *sk, struct page *page, int offset, size_t size, int flags); int tls_sw_sendpage(struct sock *sk, struct page *page, diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index e02a0d882ed3..82ec5c654f32 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -957,6 +957,7 @@ static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG] ops[TLS_BASE][TLS_BASE] = *base; ops[TLS_SW ][TLS_BASE] = ops[TLS_BASE][TLS_BASE]; + ops[TLS_SW ][TLS_BASE].splice_eof = tls_sw_splice_eof; ops[TLS_SW ][TLS_BASE].sendpage_locked = tls_sw_sendpage_locked; ops[TLS_BASE][TLS_SW ] = ops[TLS_BASE][TLS_BASE]; @@ -1027,6 +1028,7 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], prot[TLS_SW][TLS_BASE] = prot[TLS_BASE][TLS_BASE]; prot[TLS_SW][TLS_BASE].sendmsg = tls_sw_sendmsg; + prot[TLS_SW][TLS_BASE].splice_eof = tls_sw_splice_eof; prot[TLS_SW][TLS_BASE].sendpage = tls_sw_sendpage; prot[TLS_BASE][TLS_SW] = prot[TLS_BASE][TLS_BASE]; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 38acc27a0dd0..a2fb0256ff1c 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1157,6 +1157,80 @@ send_end: return copied > 0 ? copied : ret; } +/* + * Handle unexpected EOF during splice without SPLICE_F_MORE set. + */ +void tls_sw_splice_eof(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct tls_context *tls_ctx = tls_get_ctx(sk); + struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); + struct tls_rec *rec; + struct sk_msg *msg_pl; + ssize_t copied = 0; + bool retrying = false; + int ret = 0; + int pending; + + if (!ctx->open_rec) + return; + + mutex_lock(&tls_ctx->tx_lock); + lock_sock(sk); + +retry: + rec = ctx->open_rec; + if (!rec) + goto unlock; + + msg_pl = &rec->msg_plaintext; + + /* Check the BPF advisor and perform transmission. */ + ret = bpf_exec_tx_verdict(msg_pl, sk, false, TLS_RECORD_TYPE_DATA, + &copied, 0); + switch (ret) { + case 0: + case -EAGAIN: + if (retrying) + goto unlock; + retrying = true; + goto retry; + case -EINPROGRESS: + break; + default: + goto unlock; + } + + /* Wait for pending encryptions to get completed */ + spin_lock_bh(&ctx->encrypt_compl_lock); + ctx->async_notify = true; + + pending = atomic_read(&ctx->encrypt_pending); + spin_unlock_bh(&ctx->encrypt_compl_lock); + if (pending) + crypto_wait_req(-EINPROGRESS, &ctx->async_wait); + else + reinit_completion(&ctx->async_wait.completion); + + /* There can be no concurrent accesses, since we have no pending + * encrypt operations + */ + WRITE_ONCE(ctx->async_notify, false); + + if (ctx->async_wait.err) + goto unlock; + + /* Transmit if any encryptions have completed */ + if (test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) { + cancel_delayed_work(&ctx->tx_work.work); + tls_tx_records(sk, 0); + } + +unlock: + release_sock(sk); + mutex_unlock(&tls_ctx->tx_lock); +} + static int tls_sw_do_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { -- cgit v1.2.3 From d4c1e80b0d1bacbbca5184f122b9893c5920c598 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:12 +0100 Subject: tls/device: Use splice_eof() to flush Allow splice to end a TLS record after prematurely ending a splice/sendfile due to getting an EOF condition (->splice_read() returned 0) after splice had called TLS with a sendmsg() with MSG_MORE set when the user didn't set MSG_MORE. Suggested-by: Linus Torvalds Link: https://lore.kernel.org/r/CAHk-=wh=V579PDYvkpnTobCLGczbgxpMgGmmhqiTyE34Cpi5Gg@mail.gmail.com/ Signed-off-by: David Howells Reviewed-by: Jakub Kicinski cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/tls/tls.h | 1 + net/tls/tls_device.c | 23 +++++++++++++++++++++++ net/tls/tls_main.c | 2 ++ 3 files changed, 26 insertions(+) diff --git a/net/tls/tls.h b/net/tls/tls.h index 4922668fefaa..d002c3af1966 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -116,6 +116,7 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, size_t len, unsigned int flags); int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); +void tls_device_splice_eof(struct socket *sock); int tls_device_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags); int tls_tx_records(struct sock *sk, int flags); diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 9ef766e41c7a..439be833dcf9 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -590,6 +590,29 @@ out: return rc; } +void tls_device_splice_eof(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct tls_context *tls_ctx = tls_get_ctx(sk); + union tls_iter_offset iter; + struct iov_iter iov_iter = {}; + + if (!tls_is_partially_sent_record(tls_ctx)) + return; + + mutex_lock(&tls_ctx->tx_lock); + lock_sock(sk); + + if (tls_is_partially_sent_record(tls_ctx)) { + iov_iter_bvec(&iov_iter, ITER_SOURCE, NULL, 0, 0); + iter.msg_iter = &iov_iter; + tls_push_data(sk, iter, 0, 0, TLS_RECORD_TYPE_DATA, NULL); + } + + release_sock(sk); + mutex_unlock(&tls_ctx->tx_lock); +} + int tls_device_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 82ec5c654f32..7b9c83dd7de2 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -1044,10 +1044,12 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], #ifdef CONFIG_TLS_DEVICE prot[TLS_HW][TLS_BASE] = prot[TLS_BASE][TLS_BASE]; prot[TLS_HW][TLS_BASE].sendmsg = tls_device_sendmsg; + prot[TLS_HW][TLS_BASE].splice_eof = tls_device_splice_eof; prot[TLS_HW][TLS_BASE].sendpage = tls_device_sendpage; prot[TLS_HW][TLS_SW] = prot[TLS_BASE][TLS_SW]; prot[TLS_HW][TLS_SW].sendmsg = tls_device_sendmsg; + prot[TLS_HW][TLS_SW].splice_eof = tls_device_splice_eof; prot[TLS_HW][TLS_SW].sendpage = tls_device_sendpage; prot[TLS_BASE][TLS_HW] = prot[TLS_BASE][TLS_SW]; -- cgit v1.2.3 From 1d7e4538a5463faa0b0e26a7a7b6bd68c7dfdd78 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:13 +0100 Subject: ipv4, ipv6: Use splice_eof() to flush Allow splice to undo the effects of MSG_MORE after prematurely ending a splice/sendfile due to getting an EOF condition (->splice_read() returned 0) after splice had called sendmsg() with MSG_MORE set when the user didn't set MSG_MORE. For UDP, a pending packet will not be emitted if the socket is closed before it is flushed; with this change, it be flushed by ->splice_eof(). For TCP, it's not clear that MSG_MORE is actually effective. Suggested-by: Linus Torvalds Link: https://lore.kernel.org/r/CAHk-=wh=V579PDYvkpnTobCLGczbgxpMgGmmhqiTyE34Cpi5Gg@mail.gmail.com/ Signed-off-by: David Howells cc: Kuniyuki Iwashima cc: Willem de Bruijn cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/net/inet_common.h | 1 + include/net/tcp.h | 1 + include/net/udp.h | 1 + net/ipv4/af_inet.c | 18 ++++++++++++++++++ net/ipv4/tcp.c | 16 ++++++++++++++++ net/ipv4/tcp_ipv4.c | 1 + net/ipv4/udp.c | 16 ++++++++++++++++ net/ipv6/af_inet6.c | 1 + net/ipv6/tcp_ipv6.c | 1 + net/ipv6/udp.c | 15 +++++++++++++++ 10 files changed, 71 insertions(+) diff --git a/include/net/inet_common.h b/include/net/inet_common.h index 77f4b0ef5b92..a75333342c4e 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -35,6 +35,7 @@ void __inet_accept(struct socket *sock, struct socket *newsock, struct sock *newsk); int inet_send_prepare(struct sock *sk); int inet_sendmsg(struct socket *sock, struct msghdr *msg, size_t size); +void inet_splice_eof(struct socket *sock); ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags); int inet_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, diff --git a/include/net/tcp.h b/include/net/tcp.h index 68990a8f556a..49611af31bb7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -327,6 +327,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size); int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied, size_t size, struct ubuf_info *uarg); +void tcp_splice_eof(struct socket *sock); int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags); int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, diff --git a/include/net/udp.h b/include/net/udp.h index 5cad44318d71..4ed0b47c5582 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -278,6 +278,7 @@ int udp_get_port(struct sock *sk, unsigned short snum, int udp_err(struct sk_buff *, u32); int udp_abort(struct sock *sk, int err); int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); +void udp_splice_eof(struct socket *sock); int udp_push_pending_frames(struct sock *sk); void udp_flush_pending_frames(struct sock *sk); int udp_cmsg_send(struct sock *sk, struct msghdr *msg, u16 *gso_size); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index b5735b3551cf..fd233c4195ac 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -831,6 +831,21 @@ int inet_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) } EXPORT_SYMBOL(inet_sendmsg); +void inet_splice_eof(struct socket *sock) +{ + const struct proto *prot; + struct sock *sk = sock->sk; + + if (unlikely(inet_send_prepare(sk))) + return; + + /* IPV6_ADDRFORM can change sk->sk_prot under us. */ + prot = READ_ONCE(sk->sk_prot); + if (prot->splice_eof) + prot->splice_eof(sock); +} +EXPORT_SYMBOL_GPL(inet_splice_eof); + ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) { @@ -1050,6 +1065,7 @@ const struct proto_ops inet_stream_ops = { #ifdef CONFIG_MMU .mmap = tcp_mmap, #endif + .splice_eof = inet_splice_eof, .sendpage = inet_sendpage, .splice_read = tcp_splice_read, .read_sock = tcp_read_sock, @@ -1084,6 +1100,7 @@ const struct proto_ops inet_dgram_ops = { .read_skb = udp_read_skb, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, + .splice_eof = inet_splice_eof, .sendpage = inet_sendpage, .set_peek_off = sk_set_peek_off, #ifdef CONFIG_COMPAT @@ -1115,6 +1132,7 @@ static const struct proto_ops inet_sockraw_ops = { .sendmsg = inet_sendmsg, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, + .splice_eof = inet_splice_eof, .sendpage = inet_sendpage, #ifdef CONFIG_COMPAT .compat_ioctl = inet_compat_ioctl, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 53b7751b68e1..09f03221a6f1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1371,6 +1371,22 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) } EXPORT_SYMBOL(tcp_sendmsg); +void tcp_splice_eof(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct tcp_sock *tp = tcp_sk(sk); + int mss_now, size_goal; + + if (!tcp_write_queue_tail(sk)) + return; + + lock_sock(sk); + mss_now = tcp_send_mss(sk, &size_goal, 0); + tcp_push(sk, 0, mss_now, tp->nonagle, size_goal); + release_sock(sk); +} +EXPORT_SYMBOL_GPL(tcp_splice_eof); + /* * Handle reading urgent data. BSD has very simple semantics for * this, no blocking and very strange errors 8) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 53e9ce2f05bb..84a5d557dc1a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3116,6 +3116,7 @@ struct proto tcp_prot = { .keepalive = tcp_set_keepalive, .recvmsg = tcp_recvmsg, .sendmsg = tcp_sendmsg, + .splice_eof = tcp_splice_eof, .sendpage = tcp_sendpage, .backlog_rcv = tcp_v4_do_rcv, .release_cb = tcp_release_cb, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index fd3dae081f3a..df5e407286d7 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1324,6 +1324,21 @@ do_confirm: } EXPORT_SYMBOL(udp_sendmsg); +void udp_splice_eof(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct udp_sock *up = udp_sk(sk); + + if (!up->pending || READ_ONCE(up->corkflag)) + return; + + lock_sock(sk); + if (up->pending && !READ_ONCE(up->corkflag)) + udp_push_pending_frames(sk); + release_sock(sk); +} +EXPORT_SYMBOL_GPL(udp_splice_eof); + int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { @@ -2918,6 +2933,7 @@ struct proto udp_prot = { .getsockopt = udp_getsockopt, .sendmsg = udp_sendmsg, .recvmsg = udp_recvmsg, + .splice_eof = udp_splice_eof, .sendpage = udp_sendpage, .release_cb = ip4_datagram_release_cb, .hash = udp_lib_hash, diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 2bbf13216a3d..564942bee067 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -695,6 +695,7 @@ const struct proto_ops inet6_stream_ops = { #ifdef CONFIG_MMU .mmap = tcp_mmap, #endif + .splice_eof = inet_splice_eof, .sendpage = inet_sendpage, .sendmsg_locked = tcp_sendmsg_locked, .sendpage_locked = tcp_sendpage_locked, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d657713d1c71..c17c8ff94b79 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2150,6 +2150,7 @@ struct proto tcpv6_prot = { .keepalive = tcp_set_keepalive, .recvmsg = tcp_recvmsg, .sendmsg = tcp_sendmsg, + .splice_eof = tcp_splice_eof, .sendpage = tcp_sendpage, .backlog_rcv = tcp_v6_do_rcv, .release_cb = tcp_release_cb, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index e5a337e6b970..317b01c9bc39 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1653,6 +1653,20 @@ do_confirm: } EXPORT_SYMBOL(udpv6_sendmsg); +static void udpv6_splice_eof(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct udp_sock *up = udp_sk(sk); + + if (!up->pending || READ_ONCE(up->corkflag)) + return; + + lock_sock(sk); + if (up->pending && !READ_ONCE(up->corkflag)) + udp_v6_push_pending_frames(sk); + release_sock(sk); +} + void udpv6_destroy_sock(struct sock *sk) { struct udp_sock *up = udp_sk(sk); @@ -1764,6 +1778,7 @@ struct proto udpv6_prot = { .getsockopt = udpv6_getsockopt, .sendmsg = udpv6_sendmsg, .recvmsg = udpv6_recvmsg, + .splice_eof = udpv6_splice_eof, .release_cb = ip6_datagram_release_cb, .hash = udp_lib_hash, .unhash = udp_lib_unhash, -- cgit v1.2.3 From c289a1601abd7313ef08ec13184df385cfb4d388 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:14 +0100 Subject: chelsio/chtls: Use splice_eof() to flush Allow splice to end a Chelsio TLS record after prematurely ending a splice/sendfile due to getting an EOF condition (->splice_read() returned 0) after splice had called sendmsg() with MSG_MORE set when the user didn't set MSG_MORE. Suggested-by: Linus Torvalds Link: https://lore.kernel.org/r/CAHk-=wh=V579PDYvkpnTobCLGczbgxpMgGmmhqiTyE34Cpi5Gg@mail.gmail.com/ Signed-off-by: David Howells cc: Ayush Sawal cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h | 1 + drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c | 9 +++++++++ drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c | 1 + 3 files changed, 11 insertions(+) diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h index 41714203ace8..da4818d2c856 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h @@ -568,6 +568,7 @@ void chtls_destroy_sock(struct sock *sk); int chtls_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); int chtls_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len); +void chtls_splice_eof(struct socket *sock); int chtls_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags); int send_tx_flowc_wr(struct sock *sk, int compl, diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c index 5724bbbb6ee0..e08ac960c967 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c @@ -1237,6 +1237,15 @@ out_err: goto done; } +void chtls_splice_eof(struct socket *sock) +{ + struct sock *sk = sock->sk; + + lock_sock(sk); + chtls_tcp_push(sk, 0); + release_sock(sk); +} + int chtls_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c index 1e55b12fee51..6b6787eafd2f 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c @@ -606,6 +606,7 @@ static void __init chtls_init_ulp_ops(void) chtls_cpl_prot.destroy = chtls_destroy_sock; chtls_cpl_prot.shutdown = chtls_shutdown; chtls_cpl_prot.sendmsg = chtls_sendmsg; + chtls_cpl_prot.splice_eof = chtls_splice_eof; chtls_cpl_prot.sendpage = chtls_sendpage; chtls_cpl_prot.recvmsg = chtls_recvmsg; chtls_cpl_prot.setsockopt = chtls_setsockopt; -- cgit v1.2.3 From 951ace9951382a90a56e98590e0b9b651e7579b4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:15 +0100 Subject: kcm: Use splice_eof() to flush Allow splice to undo the effects of MSG_MORE after prematurely ending a splice/sendfile due to getting an EOF condition (->splice_read() returned 0) after splice had called sendmsg() with MSG_MORE set when the user didn't set MSG_MORE. Suggested-by: Linus Torvalds Link: https://lore.kernel.org/r/CAHk-=wh=V579PDYvkpnTobCLGczbgxpMgGmmhqiTyE34Cpi5Gg@mail.gmail.com/ Signed-off-by: David Howells cc: Tom Herbert cc: Tom Herbert cc: Cong Wang cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/kcm/kcmsock.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index ba22af16b96d..7dee74430b59 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -968,6 +968,19 @@ out_error: return err; } +static void kcm_splice_eof(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct kcm_sock *kcm = kcm_sk(sk); + + if (skb_queue_empty_lockless(&sk->sk_write_queue)) + return; + + lock_sock(sk); + kcm_write_msgs(kcm); + release_sock(sk); +} + static ssize_t kcm_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) @@ -1773,6 +1786,7 @@ static const struct proto_ops kcm_dgram_ops = { .sendmsg = kcm_sendmsg, .recvmsg = kcm_recvmsg, .mmap = sock_no_mmap, + .splice_eof = kcm_splice_eof, .sendpage = kcm_sendpage, }; @@ -1794,6 +1808,7 @@ static const struct proto_ops kcm_seqpacket_ops = { .sendmsg = kcm_sendmsg, .recvmsg = kcm_recvmsg, .mmap = sock_no_mmap, + .splice_eof = kcm_splice_eof, .sendpage = kcm_sendpage, .splice_read = kcm_splice_read, }; -- cgit v1.2.3 From 219d92056ba36ca9f79a72e8544874d1bf35b21d Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:16 +0100 Subject: splice, net: Fix SPLICE_F_MORE signalling in splice_direct_to_actor() splice_direct_to_actor() doesn't manage SPLICE_F_MORE correctly[1] - and, as a result, it incorrectly signals/fails to signal MSG_MORE when splicing to a socket. The problem I'm seeing happens when a short splice occurs because we got a short read due to hitting the EOF on a file: as the length read (read_len) is less than the remaining size to be spliced (len), SPLICE_F_MORE (and thus MSG_MORE) is set. The issue is that, for the moment, we have no way to know *why* the short read occurred and so can't make a good decision on whether we *should* keep MSG_MORE set. MSG_SENDPAGE_NOTLAST was added to work around this, but that is also set incorrectly under some circumstances - for example if a short read fills a single pipe_buffer, but the next read would return more (seqfile can do this). This was observed with the multi_chunk_sendfile tests in the tls kselftest program. Some of those tests would hang and time out when the last chunk of file was less than the sendfile request size: build/kselftest/net/tls -r tls.12_aes_gcm.multi_chunk_sendfile This has been observed before[2] and worked around in AF_TLS[3]. Fix this by making splice_direct_to_actor() always signal SPLICE_F_MORE if we haven't yet hit the requested operation size. SPLICE_F_MORE remains signalled if the user passed it in to splice() but otherwise gets cleared when we've read sufficient data to fulfill the request. If, however, we get a premature EOF from ->splice_read(), have sent at least one byte and SPLICE_F_MORE was not set by the caller, ->splice_eof() will be invoked. Signed-off-by: David Howells cc: Linus Torvalds cc: Jens Axboe cc: Christoph Hellwig cc: Al Viro cc: Matthew Wilcox cc: Jan Kara cc: Jeff Layton cc: David Hildenbrand cc: Christian Brauner cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: linux-mm@kvack.org Link: https://lore.kernel.org/r/499791.1685485603@warthog.procyon.org.uk/ [1] Link: https://lore.kernel.org/r/1591392508-14592-1-git-send-email-pooja.trivedi@stackpath.com/ [2] Link: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=d452d48b9f8b1a7f8152d33ef52cfd7fe1735b0a [3] Signed-off-by: Jakub Kicinski --- fs/splice.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 67dbd85db207..67ddaac1f5c5 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1063,13 +1063,17 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, */ bytes = 0; len = sd->total_len; + + /* Don't block on output, we have to drain the direct pipe. */ flags = sd->flags; + sd->flags &= ~SPLICE_F_NONBLOCK; /* - * Don't block on output, we have to drain the direct pipe. + * We signal MORE until we've read sufficient data to fulfill the + * request and we keep signalling it if the caller set it. */ - sd->flags &= ~SPLICE_F_NONBLOCK; more = sd->flags & SPLICE_F_MORE; + sd->flags |= SPLICE_F_MORE; WARN_ON_ONCE(!pipe_empty(pipe->head, pipe->tail)); @@ -1085,14 +1089,12 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, sd->total_len = read_len; /* - * If more data is pending, set SPLICE_F_MORE - * If this is the last data and SPLICE_F_MORE was not set - * initially, clears it. + * If we now have sufficient data to fulfill the request then + * we clear SPLICE_F_MORE if it was not set initially. */ - if (read_len < len) - sd->flags |= SPLICE_F_MORE; - else if (!more) + if (read_len >= len && !more) sd->flags &= ~SPLICE_F_MORE; + /* * NOTE: nonblocking mode only applies to the input. We * must not do the output in nonblocking mode as then we -- cgit v1.2.3 From fe1e81d4f73b6cbaed4fcc476960d26770642842 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:17 +0100 Subject: tls/sw: Support MSG_SPLICE_PAGES Make TLS's sendmsg() support MSG_SPLICE_PAGES. This causes pages to be spliced from the source iterator if possible. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/tls/tls_sw.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index a2fb0256ff1c..2d2bb933d2a6 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -931,6 +931,35 @@ static int tls_sw_push_pending_record(struct sock *sk, int flags) &copied, flags); } +static int tls_sw_sendmsg_splice(struct sock *sk, struct msghdr *msg, + struct sk_msg *msg_pl, size_t try_to_copy, + ssize_t *copied) +{ + struct page *page = NULL, **pages = &page; + + do { + ssize_t part; + size_t off; + + part = iov_iter_extract_pages(&msg->msg_iter, &pages, + try_to_copy, 1, 0, &off); + if (part <= 0) + return part ?: -EIO; + + if (WARN_ON_ONCE(!sendpage_ok(page))) { + iov_iter_revert(&msg->msg_iter, part); + return -EIO; + } + + sk_msg_page_add(msg_pl, page, part, off); + sk_mem_charge(sk, part); + *copied += part; + try_to_copy -= part; + } while (try_to_copy && !sk_msg_full(msg_pl)); + + return 0; +} + int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) { long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); @@ -1020,6 +1049,17 @@ alloc_encrypted: full_record = true; } + if (try_to_copy && (msg->msg_flags & MSG_SPLICE_PAGES)) { + ret = tls_sw_sendmsg_splice(sk, msg, msg_pl, + try_to_copy, &copied); + if (ret < 0) + goto send_end; + tls_ctx->pending_open_record_frags = true; + if (full_record || eor || sk_msg_full(msg_pl)) + goto copied; + continue; + } + if (!is_kvec && (full_record || eor) && !async_capable) { u32 first = msg_pl->sg.end; @@ -1084,6 +1124,7 @@ fallback_to_reg_send: */ tls_ctx->pending_open_record_frags = true; copied += try_to_copy; +copied: if (full_record || eor) { ret = bpf_exec_tx_verdict(msg_pl, sk, full_record, record_type, &copied, -- cgit v1.2.3 From 45e5be844ab6b2845b6d2935b61278c5ecae7d38 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:18 +0100 Subject: tls/sw: Convert tls_sw_sendpage() to use MSG_SPLICE_PAGES Convert tls_sw_sendpage() and tls_sw_sendpage_locked() to use sendmsg() with MSG_SPLICE_PAGES rather than directly splicing in the pages itself. [!] Note that tls_sw_sendpage_locked() appears to have the wrong locking upstream. I think the caller will only hold the socket lock, but it should hold tls_ctx->tx_lock too. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells Reviewed-by: Jakub Kicinski cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/tls/tls_sw.c | 173 +++++++++++-------------------------------------------- 1 file changed, 35 insertions(+), 138 deletions(-) diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 2d2bb933d2a6..319f61590d2c 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -960,7 +960,8 @@ static int tls_sw_sendmsg_splice(struct sock *sk, struct msghdr *msg, return 0; } -int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) +static int tls_sw_sendmsg_locked(struct sock *sk, struct msghdr *msg, + size_t size) { long timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); struct tls_context *tls_ctx = tls_get_ctx(sk); @@ -983,15 +984,6 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) int ret = 0; int pending; - if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | - MSG_CMSG_COMPAT | MSG_SPLICE_PAGES)) - return -EOPNOTSUPP; - - ret = mutex_lock_interruptible(&tls_ctx->tx_lock); - if (ret) - return ret; - lock_sock(sk); - if (unlikely(msg->msg_controllen)) { ret = tls_process_cmsg(sk, msg, &record_type); if (ret) { @@ -1192,10 +1184,27 @@ trim_sgl: send_end: ret = sk_stream_error(sk, msg->msg_flags, ret); + return copied > 0 ? copied : ret; +} +int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) +{ + struct tls_context *tls_ctx = tls_get_ctx(sk); + int ret; + + if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | + MSG_CMSG_COMPAT | MSG_SPLICE_PAGES | + MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY)) + return -EOPNOTSUPP; + + ret = mutex_lock_interruptible(&tls_ctx->tx_lock); + if (ret) + return ret; + lock_sock(sk); + ret = tls_sw_sendmsg_locked(sk, msg, size); release_sock(sk); mutex_unlock(&tls_ctx->tx_lock); - return copied > 0 ? copied : ret; + return ret; } /* @@ -1272,151 +1281,39 @@ unlock: mutex_unlock(&tls_ctx->tx_lock); } -static int tls_sw_do_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags) -{ - long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); - struct tls_context *tls_ctx = tls_get_ctx(sk); - struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); - struct tls_prot_info *prot = &tls_ctx->prot_info; - unsigned char record_type = TLS_RECORD_TYPE_DATA; - struct sk_msg *msg_pl; - struct tls_rec *rec; - int num_async = 0; - ssize_t copied = 0; - bool full_record; - int record_room; - int ret = 0; - bool eor; - - eor = !(flags & MSG_SENDPAGE_NOTLAST); - sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); - - /* Call the sk_stream functions to manage the sndbuf mem. */ - while (size > 0) { - size_t copy, required_size; - - if (sk->sk_err) { - ret = -sk->sk_err; - goto sendpage_end; - } - - if (ctx->open_rec) - rec = ctx->open_rec; - else - rec = ctx->open_rec = tls_get_rec(sk); - if (!rec) { - ret = -ENOMEM; - goto sendpage_end; - } - - msg_pl = &rec->msg_plaintext; - - full_record = false; - record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size; - copy = size; - if (copy >= record_room) { - copy = record_room; - full_record = true; - } - - required_size = msg_pl->sg.size + copy + prot->overhead_size; - - if (!sk_stream_memory_free(sk)) - goto wait_for_sndbuf; -alloc_payload: - ret = tls_alloc_encrypted_msg(sk, required_size); - if (ret) { - if (ret != -ENOSPC) - goto wait_for_memory; - - /* Adjust copy according to the amount that was - * actually allocated. The difference is due - * to max sg elements limit - */ - copy -= required_size - msg_pl->sg.size; - full_record = true; - } - - sk_msg_page_add(msg_pl, page, copy, offset); - sk_mem_charge(sk, copy); - - offset += copy; - size -= copy; - copied += copy; - - tls_ctx->pending_open_record_frags = true; - if (full_record || eor || sk_msg_full(msg_pl)) { - ret = bpf_exec_tx_verdict(msg_pl, sk, full_record, - record_type, &copied, flags); - if (ret) { - if (ret == -EINPROGRESS) - num_async++; - else if (ret == -ENOMEM) - goto wait_for_memory; - else if (ret != -EAGAIN) { - if (ret == -ENOSPC) - ret = 0; - goto sendpage_end; - } - } - } - continue; -wait_for_sndbuf: - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); -wait_for_memory: - ret = sk_stream_wait_memory(sk, &timeo); - if (ret) { - if (ctx->open_rec) - tls_trim_both_msgs(sk, msg_pl->sg.size); - goto sendpage_end; - } - - if (ctx->open_rec) - goto alloc_payload; - } - - if (num_async) { - /* Transmit if any encryptions have completed */ - if (test_and_clear_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) { - cancel_delayed_work(&ctx->tx_work.work); - tls_tx_records(sk, flags); - } - } -sendpage_end: - ret = sk_stream_error(sk, flags, ret); - return copied > 0 ? copied : ret; -} - int tls_sw_sendpage_locked(struct sock *sk, struct page *page, int offset, size_t size, int flags) { + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; + if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY | MSG_NO_SHARED_FRAGS)) return -EOPNOTSUPP; + if (flags & MSG_SENDPAGE_NOTLAST) + msg.msg_flags |= MSG_MORE; - return tls_sw_do_sendpage(sk, page, offset, size, flags); + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + return tls_sw_sendmsg_locked(sk, &msg, size); } int tls_sw_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { - struct tls_context *tls_ctx = tls_get_ctx(sk); - int ret; + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY)) return -EOPNOTSUPP; + if (flags & MSG_SENDPAGE_NOTLAST) + msg.msg_flags |= MSG_MORE; - ret = mutex_lock_interruptible(&tls_ctx->tx_lock); - if (ret) - return ret; - lock_sock(sk); - ret = tls_sw_do_sendpage(sk, page, offset, size, flags); - release_sock(sk); - mutex_unlock(&tls_ctx->tx_lock); - return ret; + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + return tls_sw_sendmsg(sk, &msg, size); } static int -- cgit v1.2.3 From 24763c9c09804db9b178f41358034144b87a937a Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:19 +0100 Subject: tls/device: Support MSG_SPLICE_PAGES Make TLS's device sendmsg() support MSG_SPLICE_PAGES. This causes pages to be spliced from the source iterator if possible. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells Reviewed-by: Jakub Kicinski cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/tls/tls_device.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 439be833dcf9..bb3bb523544e 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -509,6 +509,29 @@ handle_error: tls_append_frag(record, &zc_pfrag, copy); iter_offset.offset += copy; + } else if (copy && (flags & MSG_SPLICE_PAGES)) { + struct page_frag zc_pfrag; + struct page **pages = &zc_pfrag.page; + size_t off; + + rc = iov_iter_extract_pages(iter_offset.msg_iter, + &pages, copy, 1, 0, &off); + if (rc <= 0) { + if (rc == 0) + rc = -EIO; + goto handle_error; + } + copy = rc; + + if (WARN_ON_ONCE(!sendpage_ok(zc_pfrag.page))) { + iov_iter_revert(iter_offset.msg_iter, copy); + rc = -EIO; + goto handle_error; + } + + zc_pfrag.offset = off; + zc_pfrag.size = copy; + tls_append_frag(record, &zc_pfrag, copy); } else if (copy) { copy = min_t(size_t, copy, pfrag->size - pfrag->offset); @@ -572,6 +595,9 @@ int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) union tls_iter_offset iter; int rc; + if (!tls_ctx->zerocopy_sendfile) + msg->msg_flags &= ~MSG_SPLICE_PAGES; + mutex_lock(&tls_ctx->tx_lock); lock_sock(sk); -- cgit v1.2.3 From 3dc8976c7ad6ec46954eb99076551e2a2c4114da Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 7 Jun 2023 19:19:20 +0100 Subject: tls/device: Convert tls_device_sendpage() to use MSG_SPLICE_PAGES Convert tls_device_sendpage() to use sendmsg() with MSG_SPLICE_PAGES rather than directly splicing in the pages itself. With that, the tls_iter_offset union is no longer necessary and can be replaced with an iov_iter pointer and the zc_page argument to tls_push_data() can also be removed. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells Acked-by: Jakub Kicinski cc: Chuck Lever cc: Boris Pismenny cc: John Fastabend cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/tls/tls_device.c | 92 +++++++++++++--------------------------------------- 1 file changed, 23 insertions(+), 69 deletions(-) diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index bb3bb523544e..b4864d55900f 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -422,16 +422,10 @@ static int tls_device_copy_data(void *addr, size_t bytes, struct iov_iter *i) return 0; } -union tls_iter_offset { - struct iov_iter *msg_iter; - int offset; -}; - static int tls_push_data(struct sock *sk, - union tls_iter_offset iter_offset, + struct iov_iter *iter, size_t size, int flags, - unsigned char record_type, - struct page *zc_page) + unsigned char record_type) { struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_prot_info *prot = &tls_ctx->prot_info; @@ -500,22 +494,13 @@ handle_error: record = ctx->open_record; copy = min_t(size_t, size, max_open_record_len - record->len); - if (copy && zc_page) { - struct page_frag zc_pfrag; - - zc_pfrag.page = zc_page; - zc_pfrag.offset = iter_offset.offset; - zc_pfrag.size = copy; - tls_append_frag(record, &zc_pfrag, copy); - - iter_offset.offset += copy; - } else if (copy && (flags & MSG_SPLICE_PAGES)) { + if (copy && (flags & MSG_SPLICE_PAGES)) { struct page_frag zc_pfrag; struct page **pages = &zc_pfrag.page; size_t off; - rc = iov_iter_extract_pages(iter_offset.msg_iter, - &pages, copy, 1, 0, &off); + rc = iov_iter_extract_pages(iter, &pages, + copy, 1, 0, &off); if (rc <= 0) { if (rc == 0) rc = -EIO; @@ -524,7 +509,7 @@ handle_error: copy = rc; if (WARN_ON_ONCE(!sendpage_ok(zc_pfrag.page))) { - iov_iter_revert(iter_offset.msg_iter, copy); + iov_iter_revert(iter, copy); rc = -EIO; goto handle_error; } @@ -537,7 +522,7 @@ handle_error: rc = tls_device_copy_data(page_address(pfrag->page) + pfrag->offset, copy, - iter_offset.msg_iter); + iter); if (rc) goto handle_error; tls_append_frag(record, pfrag, copy); @@ -592,7 +577,6 @@ int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) { unsigned char record_type = TLS_RECORD_TYPE_DATA; struct tls_context *tls_ctx = tls_get_ctx(sk); - union tls_iter_offset iter; int rc; if (!tls_ctx->zerocopy_sendfile) @@ -607,8 +591,8 @@ int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) goto out; } - iter.msg_iter = &msg->msg_iter; - rc = tls_push_data(sk, iter, size, msg->msg_flags, record_type, NULL); + rc = tls_push_data(sk, &msg->msg_iter, size, msg->msg_flags, + record_type); out: release_sock(sk); @@ -620,8 +604,7 @@ void tls_device_splice_eof(struct socket *sock) { struct sock *sk = sock->sk; struct tls_context *tls_ctx = tls_get_ctx(sk); - union tls_iter_offset iter; - struct iov_iter iov_iter = {}; + struct iov_iter iter = {}; if (!tls_is_partially_sent_record(tls_ctx)) return; @@ -630,9 +613,8 @@ void tls_device_splice_eof(struct socket *sock) lock_sock(sk); if (tls_is_partially_sent_record(tls_ctx)) { - iov_iter_bvec(&iov_iter, ITER_SOURCE, NULL, 0, 0); - iter.msg_iter = &iov_iter; - tls_push_data(sk, iter, 0, 0, TLS_RECORD_TYPE_DATA, NULL); + iov_iter_bvec(&iter, ITER_SOURCE, NULL, 0, 0); + tls_push_data(sk, &iter, 0, 0, TLS_RECORD_TYPE_DATA); } release_sock(sk); @@ -642,44 +624,18 @@ void tls_device_splice_eof(struct socket *sock) int tls_device_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { - struct tls_context *tls_ctx = tls_get_ctx(sk); - union tls_iter_offset iter_offset; - struct iov_iter msg_iter; - char *kaddr; - struct kvec iov; - int rc; + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; if (flags & MSG_SENDPAGE_NOTLAST) - flags |= MSG_MORE; - - mutex_lock(&tls_ctx->tx_lock); - lock_sock(sk); + msg.msg_flags |= MSG_MORE; - if (flags & MSG_OOB) { - rc = -EOPNOTSUPP; - goto out; - } - - if (tls_ctx->zerocopy_sendfile) { - iter_offset.offset = offset; - rc = tls_push_data(sk, iter_offset, size, - flags, TLS_RECORD_TYPE_DATA, page); - goto out; - } - - kaddr = kmap(page); - iov.iov_base = kaddr + offset; - iov.iov_len = size; - iov_iter_kvec(&msg_iter, ITER_SOURCE, &iov, 1, size); - iter_offset.msg_iter = &msg_iter; - rc = tls_push_data(sk, iter_offset, size, flags, TLS_RECORD_TYPE_DATA, - NULL); - kunmap(page); + if (flags & MSG_OOB) + return -EOPNOTSUPP; -out: - release_sock(sk); - mutex_unlock(&tls_ctx->tx_lock); - return rc; + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + return tls_device_sendmsg(sk, &msg, size); } struct tls_record_info *tls_get_record(struct tls_offload_context_tx *context, @@ -744,12 +700,10 @@ EXPORT_SYMBOL(tls_get_record); static int tls_device_push_pending_record(struct sock *sk, int flags) { - union tls_iter_offset iter; - struct iov_iter msg_iter; + struct iov_iter iter; - iov_iter_kvec(&msg_iter, ITER_SOURCE, NULL, 0, 0); - iter.msg_iter = &msg_iter; - return tls_push_data(sk, iter, 0, flags, TLS_RECORD_TYPE_DATA, NULL); + iov_iter_kvec(&iter, ITER_SOURCE, NULL, 0, 0); + return tls_push_data(sk, &iter, 0, flags, TLS_RECORD_TYPE_DATA); } void tls_device_write_space(struct sock *sk, struct tls_context *ctx) -- cgit v1.2.3 From 2203718c2f59ffdd6c78d54e5add594aebb4461e Mon Sep 17 00:00:00 2001 From: Georgi Valkov Date: Wed, 7 Jun 2023 15:56:59 +0200 Subject: usbnet: ipheth: fix risk of NULL pointer deallocation The cleanup precedure in ipheth_probe will attempt to free a NULL pointer in dev->ctrl_buf if the memory allocation for this buffer is not successful. While kfree ignores NULL pointers, and the existing code is safe, it is a better design to rearrange the goto labels and avoid this. Signed-off-by: Georgi Valkov Signed-off-by: Foster Snowhill Signed-off-by: David S. Miller --- drivers/net/usb/ipheth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 6a769df0b421..8875a3d0e6d9 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -510,8 +510,8 @@ err_register_netdev: ipheth_free_urbs(dev); err_alloc_urbs: err_get_macaddr: -err_alloc_ctrl_buf: kfree(dev->ctrl_buf); +err_alloc_ctrl_buf: err_endpoints: free_netdev(netdev); return retval; -- cgit v1.2.3 From 3e65efcca87a9bb5f3b864e0a43d167bc0a8688c Mon Sep 17 00:00:00 2001 From: Foster Snowhill Date: Wed, 7 Jun 2023 15:57:00 +0200 Subject: usbnet: ipheth: transmit URBs without trailing padding The behaviour of the official iOS tethering driver on macOS is to not transmit any trailing padding at the end of URBs. This is applicable to both NCM and legacy modes, including older devices. Adapt the driver to not include trailing padding in TX URBs, matching the behaviour of the official macOS driver. Signed-off-by: Foster Snowhill Tested-by: Georgi Valkov Signed-off-by: David S. Miller --- drivers/net/usb/ipheth.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 8875a3d0e6d9..dd809e247521 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -373,12 +373,10 @@ static netdev_tx_t ipheth_tx(struct sk_buff *skb, struct net_device *net) } memcpy(dev->tx_buf, skb->data, skb->len); - if (skb->len < IPHETH_BUF_SIZE) - memset(dev->tx_buf + skb->len, 0, IPHETH_BUF_SIZE - skb->len); usb_fill_bulk_urb(dev->tx_urb, udev, usb_sndbulkpipe(udev, dev->bulk_out), - dev->tx_buf, IPHETH_BUF_SIZE, + dev->tx_buf, skb->len, ipheth_sndbulk_callback, dev); dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -- cgit v1.2.3 From a2d274c62e44b1995c170595db3865c6fe701226 Mon Sep 17 00:00:00 2001 From: Foster Snowhill Date: Wed, 7 Jun 2023 15:57:01 +0200 Subject: usbnet: ipheth: add CDC NCM support Recent iOS releases support CDC NCM encapsulation on RX. This mode is the default on macOS and Windows. In this mode, an iOS device may include one or more Ethernet frames inside a single URB. Freshly booted iOS devices start in legacy mode, but are put into NCM mode by the official Apple driver. When reconnecting such a device from a macOS/Windows machine to a Linux host, the device stays in NCM mode, making it unusable with the legacy ipheth driver code. To correctly support such a device, the driver has to either support the NCM mode too, or put the device back into legacy mode. To match the behaviour of the macOS/Windows driver, and since there is no documented control command to revert to legacy mode, implement NCM support. The device is attempted to be put into NCM mode by default, and falls back to legacy mode if the attempt fails. Signed-off-by: Foster Snowhill Tested-by: Georgi Valkov Signed-off-by: David S. Miller --- drivers/net/usb/ipheth.c | 180 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 155 insertions(+), 25 deletions(-) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index dd809e247521..687d70cfc556 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -52,6 +52,7 @@ #include #include #include +#include #define USB_VENDOR_APPLE 0x05ac @@ -59,8 +60,12 @@ #define IPHETH_USBINTF_SUBCLASS 253 #define IPHETH_USBINTF_PROTO 1 -#define IPHETH_BUF_SIZE 1514 #define IPHETH_IP_ALIGN 2 /* padding at front of URB */ +#define IPHETH_NCM_HEADER_SIZE (12 + 96) /* NCMH + NCM0 */ +#define IPHETH_TX_BUF_SIZE ETH_FRAME_LEN +#define IPHETH_RX_BUF_SIZE_LEGACY (IPHETH_IP_ALIGN + ETH_FRAME_LEN) +#define IPHETH_RX_BUF_SIZE_NCM 65536 + #define IPHETH_TX_TIMEOUT (5 * HZ) #define IPHETH_INTFNUM 2 @@ -71,6 +76,7 @@ #define IPHETH_CTRL_TIMEOUT (5 * HZ) #define IPHETH_CMD_GET_MACADDR 0x00 +#define IPHETH_CMD_ENABLE_NCM 0x04 #define IPHETH_CMD_CARRIER_CHECK 0x45 #define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ) @@ -97,6 +103,8 @@ struct ipheth_device { u8 bulk_out; struct delayed_work carrier_work; bool confirmed_pairing; + int (*rcvbulk_callback)(struct urb *urb); + size_t rx_buf_len; }; static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); @@ -116,12 +124,12 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone) if (rx_urb == NULL) goto free_tx_urb; - tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE, + tx_buf = usb_alloc_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, GFP_KERNEL, &tx_urb->transfer_dma); if (tx_buf == NULL) goto free_rx_urb; - rx_buf = usb_alloc_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, + rx_buf = usb_alloc_coherent(iphone->udev, iphone->rx_buf_len, GFP_KERNEL, &rx_urb->transfer_dma); if (rx_buf == NULL) goto free_tx_buf; @@ -134,7 +142,7 @@ static int ipheth_alloc_urbs(struct ipheth_device *iphone) return 0; free_tx_buf: - usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, tx_buf, + usb_free_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, tx_buf, tx_urb->transfer_dma); free_rx_urb: usb_free_urb(rx_urb); @@ -146,9 +154,9 @@ error_nomem: static void ipheth_free_urbs(struct ipheth_device *iphone) { - usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, iphone->rx_buf, + usb_free_coherent(iphone->udev, iphone->rx_buf_len, iphone->rx_buf, iphone->rx_urb->transfer_dma); - usb_free_coherent(iphone->udev, IPHETH_BUF_SIZE, iphone->tx_buf, + usb_free_coherent(iphone->udev, IPHETH_TX_BUF_SIZE, iphone->tx_buf, iphone->tx_urb->transfer_dma); usb_free_urb(iphone->rx_urb); usb_free_urb(iphone->tx_urb); @@ -160,14 +168,105 @@ static void ipheth_kill_urbs(struct ipheth_device *dev) usb_kill_urb(dev->rx_urb); } -static void ipheth_rcvbulk_callback(struct urb *urb) +static int ipheth_consume_skb(char *buf, int len, struct ipheth_device *dev) { - struct ipheth_device *dev; struct sk_buff *skb; - int status; + + skb = dev_alloc_skb(len); + if (!skb) { + dev->net->stats.rx_dropped++; + return -ENOMEM; + } + + skb_put_data(skb, buf, len); + skb->dev = dev->net; + skb->protocol = eth_type_trans(skb, dev->net); + + dev->net->stats.rx_packets++; + dev->net->stats.rx_bytes += len; + netif_rx(skb); + + return 0; +} + +static int ipheth_rcvbulk_callback_legacy(struct urb *urb) +{ + struct ipheth_device *dev; char *buf; int len; + dev = urb->context; + + if (urb->actual_length <= IPHETH_IP_ALIGN) { + dev->net->stats.rx_length_errors++; + return -EINVAL; + } + len = urb->actual_length - IPHETH_IP_ALIGN; + buf = urb->transfer_buffer + IPHETH_IP_ALIGN; + + return ipheth_consume_skb(buf, len, dev); +} + +static int ipheth_rcvbulk_callback_ncm(struct urb *urb) +{ + struct usb_cdc_ncm_nth16 *ncmh; + struct usb_cdc_ncm_ndp16 *ncm0; + struct usb_cdc_ncm_dpe16 *dpe; + struct ipheth_device *dev; + int retval = -EINVAL; + char *buf; + int len; + + dev = urb->context; + + if (urb->actual_length < IPHETH_NCM_HEADER_SIZE) { + dev->net->stats.rx_length_errors++; + return retval; + } + + ncmh = urb->transfer_buffer; + if (ncmh->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH16_SIGN) || + le16_to_cpu(ncmh->wNdpIndex) >= urb->actual_length) { + dev->net->stats.rx_errors++; + return retval; + } + + ncm0 = urb->transfer_buffer + le16_to_cpu(ncmh->wNdpIndex); + if (ncm0->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN) || + le16_to_cpu(ncmh->wHeaderLength) + le16_to_cpu(ncm0->wLength) >= + urb->actual_length) { + dev->net->stats.rx_errors++; + return retval; + } + + dpe = ncm0->dpe16; + while (le16_to_cpu(dpe->wDatagramIndex) != 0 && + le16_to_cpu(dpe->wDatagramLength) != 0) { + if (le16_to_cpu(dpe->wDatagramIndex) >= urb->actual_length || + le16_to_cpu(dpe->wDatagramIndex) + + le16_to_cpu(dpe->wDatagramLength) > urb->actual_length) { + dev->net->stats.rx_length_errors++; + return retval; + } + + buf = urb->transfer_buffer + le16_to_cpu(dpe->wDatagramIndex); + len = le16_to_cpu(dpe->wDatagramLength); + + retval = ipheth_consume_skb(buf, len, dev); + if (retval != 0) + return retval; + + dpe++; + } + + return 0; +} + +static void ipheth_rcvbulk_callback(struct urb *urb) +{ + struct ipheth_device *dev; + int retval, status; + dev = urb->context; if (dev == NULL) return; @@ -191,25 +290,27 @@ static void ipheth_rcvbulk_callback(struct urb *urb) dev->net->stats.rx_length_errors++; return; } - len = urb->actual_length - IPHETH_IP_ALIGN; - buf = urb->transfer_buffer + IPHETH_IP_ALIGN; - skb = dev_alloc_skb(len); - if (!skb) { - dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n", - __func__); - dev->net->stats.rx_dropped++; + /* RX URBs starting with 0x00 0x01 do not encapsulate Ethernet frames, + * but rather are control frames. Their purpose is not documented, and + * they don't affect driver functionality, okay to drop them. + * There is usually just one 4-byte control frame as the very first + * URB received from the bulk IN endpoint. + */ + if (unlikely + (((char *)urb->transfer_buffer)[0] == 0 && + ((char *)urb->transfer_buffer)[1] == 1)) + goto rx_submit; + + retval = dev->rcvbulk_callback(urb); + if (retval != 0) { + dev_err(&dev->intf->dev, "%s: callback retval: %d\n", + __func__, retval); return; } - skb_put_data(skb, buf, len); - skb->dev = dev->net; - skb->protocol = eth_type_trans(skb, dev->net); - - dev->net->stats.rx_packets++; - dev->net->stats.rx_bytes += len; +rx_submit: dev->confirmed_pairing = true; - netif_rx(skb); ipheth_rx_submit(dev, GFP_ATOMIC); } @@ -310,6 +411,27 @@ static int ipheth_get_macaddr(struct ipheth_device *dev) return retval; } +static int ipheth_enable_ncm(struct ipheth_device *dev) +{ + struct usb_device *udev = dev->udev; + int retval; + + retval = usb_control_msg(udev, + usb_sndctrlpipe(udev, IPHETH_CTRL_ENDP), + IPHETH_CMD_ENABLE_NCM, /* request */ + 0x41, /* request type */ + 0x00, /* value */ + 0x02, /* index */ + NULL, + 0, + IPHETH_CTRL_TIMEOUT); + + dev_info(&dev->intf->dev, "%s: usb_control_msg: %d\n", + __func__, retval); + + return retval; +} + static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) { struct usb_device *udev = dev->udev; @@ -317,7 +439,7 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) usb_fill_bulk_urb(dev->rx_urb, udev, usb_rcvbulkpipe(udev, dev->bulk_in), - dev->rx_buf, IPHETH_BUF_SIZE + IPHETH_IP_ALIGN, + dev->rx_buf, dev->rx_buf_len, ipheth_rcvbulk_callback, dev); dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -365,7 +487,7 @@ static netdev_tx_t ipheth_tx(struct sk_buff *skb, struct net_device *net) int retval; /* Paranoid */ - if (skb->len > IPHETH_BUF_SIZE) { + if (skb->len > IPHETH_TX_BUF_SIZE) { WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len); dev->net->stats.tx_dropped++; dev_kfree_skb_any(skb); @@ -448,6 +570,8 @@ static int ipheth_probe(struct usb_interface *intf, dev->net = netdev; dev->intf = intf; dev->confirmed_pairing = false; + dev->rx_buf_len = IPHETH_RX_BUF_SIZE_LEGACY; + dev->rcvbulk_callback = ipheth_rcvbulk_callback_legacy; /* Set up endpoints */ hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); if (hintf == NULL) { @@ -479,6 +603,12 @@ static int ipheth_probe(struct usb_interface *intf, if (retval) goto err_get_macaddr; + retval = ipheth_enable_ncm(dev); + if (!retval) { + dev->rx_buf_len = IPHETH_RX_BUF_SIZE_NCM; + dev->rcvbulk_callback = ipheth_rcvbulk_callback_ncm; + } + INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work); retval = ipheth_alloc_urbs(dev); -- cgit v1.2.3 From 0c6e9d32ef0ccfcf2d875cbcff23bf345a54d585 Mon Sep 17 00:00:00 2001 From: Foster Snowhill Date: Wed, 7 Jun 2023 15:57:02 +0200 Subject: usbnet: ipheth: update Kconfig description This module has for a long time not been limited to iPhone <= 3GS. Update description to match the actual state of the driver. Remove dead link from 2010, instead reference an existing userspace iOS device pairing implementation as part of libimobiledevice. Signed-off-by: Foster Snowhill Signed-off-by: David S. Miller --- drivers/net/usb/Kconfig | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 4402eedb3d1a..3fd7dccf0f9c 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -583,12 +583,10 @@ config USB_IPHETH default n help Module used to share Internet connection (tethering) from your - iPhone (Original, 3G and 3GS) to your system. - Note that you need userspace libraries and programs that are needed - to pair your device with your system and that understand the iPhone - protocol. - - For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver + iPhone to your system. + Note that you need a corresponding userspace library/program + to pair your device with your system, for example usbmuxd + . config USB_SIERRA_NET tristate "USB-to-WWAN Driver for Sierra Wireless modems" -- cgit v1.2.3 From 74b449b98dccdf24288d562f9d207fa066da793d Mon Sep 17 00:00:00 2001 From: Ivan Mikhaylov Date: Wed, 7 Jun 2023 18:17:41 +0300 Subject: net/ncsi: make one oem_gma function for all mfr id Make the one Get Mac Address function for all manufacturers and change this call in handlers accordingly. Reviewed-by: Simon Horman Signed-off-by: Ivan Mikhaylov Signed-off-by: David S. Miller --- net/ncsi/ncsi-rsp.c | 88 ++++++++++++----------------------------------------- 1 file changed, 19 insertions(+), 69 deletions(-) diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index 6447a09932f5..91c42253a711 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@ -611,14 +611,15 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr) return 0; } -/* Response handler for Mellanox command Get Mac Address */ -static int ncsi_rsp_handler_oem_mlx_gma(struct ncsi_request *nr) +/* Response handler for Get Mac Address command */ +static int ncsi_rsp_handler_oem_gma(struct ncsi_request *nr, int mfr_id) { struct ncsi_dev_priv *ndp = nr->ndp; struct net_device *ndev = ndp->ndev.dev; const struct net_device_ops *ops = ndev->netdev_ops; struct ncsi_rsp_oem_pkt *rsp; struct sockaddr saddr; + u32 mac_addr_off = 0; int ret = 0; /* Get the response header */ @@ -626,7 +627,19 @@ static int ncsi_rsp_handler_oem_mlx_gma(struct ncsi_request *nr) saddr.sa_family = ndev->type; ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; - memcpy(saddr.sa_data, &rsp->data[MLX_MAC_ADDR_OFFSET], ETH_ALEN); + if (mfr_id == NCSI_OEM_MFR_BCM_ID) + mac_addr_off = BCM_MAC_ADDR_OFFSET; + else if (mfr_id == NCSI_OEM_MFR_MLX_ID) + mac_addr_off = MLX_MAC_ADDR_OFFSET; + else if (mfr_id == NCSI_OEM_MFR_INTEL_ID) + mac_addr_off = INTEL_MAC_ADDR_OFFSET; + + memcpy(saddr.sa_data, &rsp->data[mac_addr_off], ETH_ALEN); + if (mfr_id == NCSI_OEM_MFR_BCM_ID || mfr_id == NCSI_OEM_MFR_INTEL_ID) + eth_addr_inc((u8 *)saddr.sa_data); + if (!is_valid_ether_addr((const u8 *)saddr.sa_data)) + return -ENXIO; + /* Set the flag for GMA command which should only be called once */ ndp->gma_flag = 1; @@ -649,41 +662,10 @@ static int ncsi_rsp_handler_oem_mlx(struct ncsi_request *nr) if (mlx->cmd == NCSI_OEM_MLX_CMD_GMA && mlx->param == NCSI_OEM_MLX_CMD_GMA_PARAM) - return ncsi_rsp_handler_oem_mlx_gma(nr); + return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_MLX_ID); return 0; } -/* Response handler for Broadcom command Get Mac Address */ -static int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr) -{ - struct ncsi_dev_priv *ndp = nr->ndp; - struct net_device *ndev = ndp->ndev.dev; - const struct net_device_ops *ops = ndev->netdev_ops; - struct ncsi_rsp_oem_pkt *rsp; - struct sockaddr saddr; - int ret = 0; - - /* Get the response header */ - rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); - - saddr.sa_family = ndev->type; - ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; - memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN); - /* Increase mac address by 1 for BMC's address */ - eth_addr_inc((u8 *)saddr.sa_data); - if (!is_valid_ether_addr((const u8 *)saddr.sa_data)) - return -ENXIO; - - /* Set the flag for GMA command which should only be called once */ - ndp->gma_flag = 1; - - ret = ops->ndo_set_mac_address(ndev, &saddr); - if (ret < 0) - netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n"); - - return ret; -} - /* Response handler for Broadcom card */ static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr) { @@ -695,42 +677,10 @@ static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr) bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data); if (bcm->type == NCSI_OEM_BCM_CMD_GMA) - return ncsi_rsp_handler_oem_bcm_gma(nr); + return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_BCM_ID); return 0; } -/* Response handler for Intel command Get Mac Address */ -static int ncsi_rsp_handler_oem_intel_gma(struct ncsi_request *nr) -{ - struct ncsi_dev_priv *ndp = nr->ndp; - struct net_device *ndev = ndp->ndev.dev; - const struct net_device_ops *ops = ndev->netdev_ops; - struct ncsi_rsp_oem_pkt *rsp; - struct sockaddr saddr; - int ret = 0; - - /* Get the response header */ - rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); - - saddr.sa_family = ndev->type; - ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; - memcpy(saddr.sa_data, &rsp->data[INTEL_MAC_ADDR_OFFSET], ETH_ALEN); - /* Increase mac address by 1 for BMC's address */ - eth_addr_inc((u8 *)saddr.sa_data); - if (!is_valid_ether_addr((const u8 *)saddr.sa_data)) - return -ENXIO; - - /* Set the flag for GMA command which should only be called once */ - ndp->gma_flag = 1; - - ret = ops->ndo_set_mac_address(ndev, &saddr); - if (ret < 0) - netdev_warn(ndev, - "NCSI: 'Writing mac address to device failed\n"); - - return ret; -} - /* Response handler for Intel card */ static int ncsi_rsp_handler_oem_intel(struct ncsi_request *nr) { @@ -742,7 +692,7 @@ static int ncsi_rsp_handler_oem_intel(struct ncsi_request *nr) intel = (struct ncsi_rsp_oem_intel_pkt *)(rsp->data); if (intel->cmd == NCSI_OEM_INTEL_CMD_GMA) - return ncsi_rsp_handler_oem_intel_gma(nr); + return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_INTEL_ID); return 0; } -- cgit v1.2.3 From 790071347a0a1a89e618eedcd51c687ea783aeb3 Mon Sep 17 00:00:00 2001 From: Ivan Mikhaylov Date: Wed, 7 Jun 2023 18:17:42 +0300 Subject: net/ncsi: change from ndo_set_mac_address to dev_set_mac_address Change ndo_set_mac_address to dev_set_mac_address because dev_set_mac_address provides a way to notify network layer about MAC change. In other case, services may not aware about MAC change and keep using old one which set from network adapter driver. As example, DHCP client from systemd do not update MAC address without notification from net subsystem which leads to the problem with acquiring the right address from DHCP server. Fixes: cb10c7c0dfd9e ("net/ncsi: Add NCSI Broadcom OEM command") Cc: stable@vger.kernel.org # v6.0+ 2f38e84 net/ncsi: make one oem_gma function for all mfr id Signed-off-by: Paul Fertser Signed-off-by: Ivan Mikhaylov Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/ncsi/ncsi-rsp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c index 91c42253a711..069c2659074b 100644 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@ -616,7 +616,6 @@ static int ncsi_rsp_handler_oem_gma(struct ncsi_request *nr, int mfr_id) { struct ncsi_dev_priv *ndp = nr->ndp; struct net_device *ndev = ndp->ndev.dev; - const struct net_device_ops *ops = ndev->netdev_ops; struct ncsi_rsp_oem_pkt *rsp; struct sockaddr saddr; u32 mac_addr_off = 0; @@ -643,7 +642,9 @@ static int ncsi_rsp_handler_oem_gma(struct ncsi_request *nr, int mfr_id) /* Set the flag for GMA command which should only be called once */ ndp->gma_flag = 1; - ret = ops->ndo_set_mac_address(ndev, &saddr); + rtnl_lock(); + ret = dev_set_mac_address(ndev, &saddr, NULL); + rtnl_unlock(); if (ret < 0) netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n"); -- cgit v1.2.3 From 57fd7d59b1c7d6f6a1c34863a2bc4ff1f6c92d40 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 7 Jun 2023 11:34:52 -0700 Subject: net: phy: broadcom: Rename LED registers These registers are common to most PHYs and are not specific to the BCM5482, renamed the constants accordingly, no functional change. Signed-off-by: Florian Fainelli Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 10 +++++----- include/linux/brcmphy.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 822c8b01dc53..57a865aa1fe5 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -414,13 +414,13 @@ static int bcm54xx_config_init(struct phy_device *phydev) * these settings will cause LOS to malfunction. */ if (!phy_on_sfp(phydev)) { - val = BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | - BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); - bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, val); + val = BCM54XX_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) | + BCM54XX_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1); + bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDS1, val); val = BCM_LED_MULTICOLOR_IN_PHASE | - BCM5482_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | - BCM5482_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); + BCM54XX_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) | + BCM54XX_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT); bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val); } diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index 251833ab271f..ab21b8a1b2c8 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -206,11 +206,11 @@ #define BCM_NO_ANEG_APD_EN 0x0060 /* bits 5 & 6 */ #define BCM_APD_SINGLELP_EN 0x0100 /* Bit 8 */ -#define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ +#define BCM54XX_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ /* LED3 / ~LINKSPD[2] selector */ -#define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) +#define BCM54XX_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) /* LED1 / ~LINKSPD[1] selector */ -#define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) +#define BCM54XX_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) #define BCM54XX_SHD_RGMII_MODE 0x0b /* 01011: RGMII Mode Selector */ #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ -- cgit v1.2.3 From bd5736e146e35f9eabe8c1bfc0ab00979ae62930 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 7 Jun 2023 11:34:53 -0700 Subject: net: phy: broadcom: Add support for setting LED brightness Broadcom PHYs have two LEDs selector registers which allow us to control the LED assignment, including how to turn them on/off. Signed-off-by: Florian Fainelli Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/phy/bcm-phy-lib.c | 27 +++++++++++++++++++++++++++ drivers/net/phy/bcm-phy-lib.h | 3 +++ drivers/net/phy/broadcom.c | 15 +++++++++++++++ include/linux/brcmphy.h | 3 +++ 4 files changed, 48 insertions(+) diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c index c6e2e5f636d4..876f28fd8256 100644 --- a/drivers/net/phy/bcm-phy-lib.c +++ b/drivers/net/phy/bcm-phy-lib.c @@ -1039,6 +1039,33 @@ irqreturn_t bcm_phy_wol_isr(int irq, void *dev_id) } EXPORT_SYMBOL_GPL(bcm_phy_wol_isr); +int bcm_phy_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + u8 led_num; + int ret; + u16 reg; + + if (index >= 4) + return -EINVAL; + + /* Two LEDS per register */ + led_num = index % 2; + reg = index >= 2 ? BCM54XX_SHD_LEDS2 : BCM54XX_SHD_LEDS1; + + ret = bcm_phy_read_shadow(phydev, reg); + if (ret < 0) + return ret; + + ret &= ~(BCM_LED_SRC_MASK << BCM54XX_SHD_LEDS_SHIFT(led_num)); + if (value == LED_OFF) + ret |= BCM_LED_SRC_OFF << BCM54XX_SHD_LEDS_SHIFT(led_num); + else + ret |= BCM_LED_SRC_ON << BCM54XX_SHD_LEDS_SHIFT(led_num); + return bcm_phy_write_shadow(phydev, reg, ret); +} +EXPORT_SYMBOL_GPL(bcm_phy_led_brightness_set); + MODULE_DESCRIPTION("Broadcom PHY Library"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Broadcom Corporation"); diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index 2f30ce0cab0e..b52189e45a84 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -118,4 +118,7 @@ int bcm_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); irqreturn_t bcm_phy_wol_isr(int irq, void *dev_id); +int bcm_phy_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value); + #endif /* _LINUX_BCM_PHY_LIB_H */ diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 57a865aa1fe5..9f0a9c575bd7 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -1031,6 +1031,7 @@ static struct phy_driver broadcom_drivers[] = { .resume = bcm54xx_resume, .get_wol = bcm54xx_phy_get_wol, .set_wol = bcm54xx_phy_set_wol, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM5461, .phy_id_mask = 0xfffffff0, @@ -1044,6 +1045,7 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM54612E, .phy_id_mask = 0xfffffff0, @@ -1057,6 +1059,7 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM54616S, .phy_id_mask = 0xfffffff0, @@ -1070,6 +1073,7 @@ static struct phy_driver broadcom_drivers[] = { .read_status = bcm54616s_read_status, .probe = bcm54616s_probe, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM5464, .phy_id_mask = 0xfffffff0, @@ -1085,6 +1089,7 @@ static struct phy_driver broadcom_drivers[] = { .suspend = genphy_suspend, .resume = genphy_resume, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM5481, .phy_id_mask = 0xfffffff0, @@ -1099,6 +1104,7 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM54810, .phy_id_mask = 0xfffffff0, @@ -1115,6 +1121,7 @@ static struct phy_driver broadcom_drivers[] = { .suspend = bcm54xx_suspend, .resume = bcm54xx_resume, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM54811, .phy_id_mask = 0xfffffff0, @@ -1131,6 +1138,7 @@ static struct phy_driver broadcom_drivers[] = { .suspend = bcm54xx_suspend, .resume = bcm54xx_resume, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM5482, .phy_id_mask = 0xfffffff0, @@ -1144,6 +1152,7 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM50610, .phy_id_mask = 0xfffffff0, @@ -1159,6 +1168,7 @@ static struct phy_driver broadcom_drivers[] = { .link_change_notify = bcm54xx_link_change_notify, .suspend = bcm54xx_suspend, .resume = bcm54xx_resume, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM50610M, .phy_id_mask = 0xfffffff0, @@ -1174,6 +1184,7 @@ static struct phy_driver broadcom_drivers[] = { .link_change_notify = bcm54xx_link_change_notify, .suspend = bcm54xx_suspend, .resume = bcm54xx_resume, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM57780, .phy_id_mask = 0xfffffff0, @@ -1187,6 +1198,7 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCMAC131, .phy_id_mask = 0xfffffff0, @@ -1218,6 +1230,7 @@ static struct phy_driver broadcom_drivers[] = { .get_stats = bcm54xx_get_stats, .probe = bcm54xx_phy_probe, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM53125, .phy_id_mask = 0xfffffff0, @@ -1232,6 +1245,7 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM53128, .phy_id_mask = 0xfffffff0, @@ -1246,6 +1260,7 @@ static struct phy_driver broadcom_drivers[] = { .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, .link_change_notify = bcm54xx_link_change_notify, + .led_brightness_set = bcm_phy_led_brightness_set, }, { .phy_id = PHY_ID_BCM89610, .phy_id_mask = 0xfffffff0, diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index ab21b8a1b2c8..5d732f48f787 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -161,6 +161,7 @@ #define BCM_LED_SRC_OPENSHORT 0xb #define BCM_LED_SRC_OFF 0xe /* Tied high */ #define BCM_LED_SRC_ON 0xf /* Tied low */ +#define BCM_LED_SRC_MASK GENMASK(3, 0) /* * Broadcom Multicolor LED configurations (expansion register 4) @@ -208,9 +209,11 @@ #define BCM54XX_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ /* LED3 / ~LINKSPD[2] selector */ +#define BCM54XX_SHD_LEDS_SHIFT(led) (4 * (led)) #define BCM54XX_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) /* LED1 / ~LINKSPD[1] selector */ #define BCM54XX_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) +#define BCM54XX_SHD_LEDS2 0x0e /* 01110: LED Selector 2 */ #define BCM54XX_SHD_RGMII_MODE 0x0b /* 01011: RGMII Mode Selector */ #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ -- cgit v1.2.3 From e7c5433c5aaab52ddd5448967a9a5db94a3939cc Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 8 Jun 2023 16:31:48 +0800 Subject: tools: ynl: Remove duplicated include in handshake-user.c ./tools/net/ynl/generated/handshake-user.c: stdlib.h is included more than once. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5464 Signed-off-by: Yang Li Signed-off-by: David S. Miller --- tools/net/ynl/generated/handshake-user.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c index 72eb1c52a8fc..9ffe9fc58e51 100644 --- a/tools/net/ynl/generated/handshake-user.c +++ b/tools/net/ynl/generated/handshake-user.c @@ -8,7 +8,6 @@ #include "ynl.h" #include -#include #include #include #include -- cgit v1.2.3 From ec3b1ce2ca347b4b0a7cd5d1b69c316840202df3 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 1 Jun 2023 10:25:53 +0200 Subject: wifi: ath10k: Drop cleaning of driver data from probe error path and remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver core cares for resetting driver data if probe fails and after remove. So drop the explicit and duplicate cleanup in the driver's functions. Signed-off-by: Uwe Kleine-König Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230601082556.2738446-2-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/ath10k/ahb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index f0c615fa5614..7bb45c66cff7 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -816,7 +816,6 @@ err_resource_deinit: err_core_destroy: ath10k_core_destroy(ar); - platform_set_drvdata(pdev, NULL); return ret; } @@ -845,8 +844,6 @@ static int ath10k_ahb_remove(struct platform_device *pdev) ath10k_ahb_resource_deinit(ar); ath10k_core_destroy(ar); - platform_set_drvdata(pdev, NULL); - return 0; } -- cgit v1.2.3 From fad5ac80dfa5010d44c24d59d9e8e1552a447911 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 1 Jun 2023 10:25:54 +0200 Subject: wifi: ath10k: Drop checks that are always false MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit platform_get_drvdata() cannot return NULL as the probe function calls platform_set_drvdata() with a non-NULL argument or returns with a failure. In the first case, platform_get_drvdata() returns this non-NULL value and in the second the remove callback isn't called at all. ath10k_ahb_priv() cannot return NULL and ar_ahb is unused after the check anyhow. Signed-off-by: Uwe Kleine-König Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230601082556.2738446-3-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/ath10k/ahb.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 7bb45c66cff7..fffdbad75074 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -823,15 +823,6 @@ err_core_destroy: static int ath10k_ahb_remove(struct platform_device *pdev) { struct ath10k *ar = platform_get_drvdata(pdev); - struct ath10k_ahb *ar_ahb; - - if (!ar) - return -EINVAL; - - ar_ahb = ath10k_ahb_priv(ar); - - if (!ar_ahb) - return -EINVAL; ath10k_dbg(ar, ATH10K_DBG_AHB, "ahb remove\n"); -- cgit v1.2.3 From d457bff2763366513bce36c2fc51fcba12a2f912 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 1 Jun 2023 10:25:55 +0200 Subject: wifi: ath10k: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 (mostly) ignored 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. Both ath10k platform drivers return zero unconditionally in their remove callback, so they can be trivially converted to use .remove_new(). Also fix on of the more offending whitespace issues in the definition of ath10k_snoc_driver. Signed-off-by: Uwe Kleine-König Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230601082556.2738446-4-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/ath10k/ahb.c | 6 ++---- drivers/net/wireless/ath/ath10k/snoc.c | 8 +++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index fffdbad75074..632da4c5e5da 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -820,7 +820,7 @@ err_core_destroy: return ret; } -static int ath10k_ahb_remove(struct platform_device *pdev) +static void ath10k_ahb_remove(struct platform_device *pdev) { struct ath10k *ar = platform_get_drvdata(pdev); @@ -834,8 +834,6 @@ static int ath10k_ahb_remove(struct platform_device *pdev) ath10k_ahb_clock_disable(ar); ath10k_ahb_resource_deinit(ar); ath10k_core_destroy(ar); - - return 0; } static struct platform_driver ath10k_ahb_driver = { @@ -844,7 +842,7 @@ static struct platform_driver ath10k_ahb_driver = { .of_match_table = ath10k_ahb_of_match, }, .probe = ath10k_ahb_probe, - .remove = ath10k_ahb_remove, + .remove_new = ath10k_ahb_remove, }; int ath10k_ahb_init(void) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 5128a452c65f..26214c00cd0d 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1848,7 +1848,7 @@ static int ath10k_snoc_free_resources(struct ath10k *ar) return 0; } -static int ath10k_snoc_remove(struct platform_device *pdev) +static void ath10k_snoc_remove(struct platform_device *pdev) { struct ath10k *ar = platform_get_drvdata(pdev); struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -1861,8 +1861,6 @@ static int ath10k_snoc_remove(struct platform_device *pdev) wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ); ath10k_snoc_free_resources(ar); - - return 0; } static void ath10k_snoc_shutdown(struct platform_device *pdev) @@ -1875,8 +1873,8 @@ static void ath10k_snoc_shutdown(struct platform_device *pdev) static struct platform_driver ath10k_snoc_driver = { .probe = ath10k_snoc_probe, - .remove = ath10k_snoc_remove, - .shutdown = ath10k_snoc_shutdown, + .remove_new = ath10k_snoc_remove, + .shutdown = ath10k_snoc_shutdown, .driver = { .name = "ath10k_snoc", .of_match_table = ath10k_snoc_dt_match, -- cgit v1.2.3 From 6358b10371579e1068b6f236a3ccd5c2fef995e6 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 1 Jun 2023 10:25:56 +0200 Subject: wifi: atk10k: Don't opencode ath10k_pci_priv() in ath10k_ahb_priv() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces no changes in the compiled result (tested for an ARCH=arm allmodconfig build). Signed-off-by: Uwe Kleine-König Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230601082556.2738446-5-u.kleine-koenig@pengutronix.de --- drivers/net/wireless/ath/ath10k/ahb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index 632da4c5e5da..4a006fb4d424 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -27,7 +27,7 @@ MODULE_DEVICE_TABLE(of, ath10k_ahb_of_match); static inline struct ath10k_ahb *ath10k_ahb_priv(struct ath10k *ar) { - return &((struct ath10k_pci *)ar->drv_priv)->ahb[0]; + return &ath10k_pci_priv(ar)->ahb[0]; } static void ath10k_ahb_write32(struct ath10k *ar, u32 offset, u32 value) -- cgit v1.2.3 From 37fdb33c87c2fa9f83f0f3f0ae5a007c1e917052 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Thu, 1 Jun 2023 20:02:14 +0530 Subject: wifi: ath11k: update proper pdev/vdev id for testmode command User can extend test mode command support to set vdev and pdev params for debug purpose at run time by sending vdev/pdev param set command through the testmode command interface. Fill the proper pdev/vdev id in driver since, pdev/vdev id details may not be available at user space. It will make sure that the proper vdev/pdev ids are sent to firmware. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: Venkateswara Naralasetty Signed-off-by: Raj Kumar Bhagat Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230601143214.13006-1-quic_rajkbhag@quicinc.com --- drivers/net/wireless/ath/ath11k/testmode.c | 37 +++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c index 3611b6ec39c6..8fc5cddb28bd 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.c +++ b/drivers/net/wireless/ath/ath11k/testmode.c @@ -297,13 +297,16 @@ err: return ret; } -static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[]) +static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[], + struct ieee80211_vif *vif) { struct ath11k_pdev_wmi *wmi = ar->wmi; struct sk_buff *skb; + struct ath11k_vif *arvif; u32 cmd_id, buf_len; - int ret; + int ret, tag; void *buf; + u32 *ptr; mutex_lock(&ar->conf_mutex); @@ -327,6 +330,34 @@ static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[]) cmd_id = nla_get_u32(tb[ATH11K_TM_ATTR_WMI_CMDID]); + /* Make sure that the buffer length is long enough to + * hold TLV and pdev/vdev id. + */ + if (buf_len < sizeof(struct wmi_tlv) + sizeof(u32)) { + ret = -EINVAL; + goto out; + } + + ptr = buf; + tag = FIELD_GET(WMI_TLV_TAG, *ptr); + + /* pdev/vdev id start after TLV header */ + ptr++; + + if (tag == WMI_TAG_PDEV_SET_PARAM_CMD) + *ptr = ar->pdev->pdev_id; + + if (ar->ab->fw_mode != ATH11K_FIRMWARE_MODE_FTM && + (tag == WMI_TAG_VDEV_SET_PARAM_CMD || tag == WMI_TAG_UNIT_TEST_CMD)) { + if (vif) { + arvif = (struct ath11k_vif *)vif->drv_priv; + *ptr = arvif->vdev_id; + } else { + ret = -EINVAL; + goto out; + } + } + ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, "cmd wmi cmd_id %d buf length %d\n", cmd_id, buf_len); @@ -460,7 +491,7 @@ int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case ATH11K_TM_CMD_GET_VERSION: return ath11k_tm_cmd_get_version(ar, tb); case ATH11K_TM_CMD_WMI: - return ath11k_tm_cmd_wmi(ar, tb); + return ath11k_tm_cmd_wmi(ar, tb, vif); case ATH11K_TM_CMD_TESTMODE_START: return ath11k_tm_cmd_testmode_start(ar, tb); case ATH11K_TM_CMD_WMI_FTM: -- cgit v1.2.3 From 054b5580a36e435692c203c19abdcb9f7734320e Mon Sep 17 00:00:00 2001 From: Balamurugan S Date: Thu, 1 Jun 2023 13:35:15 +0300 Subject: wifi: ath12k: Avoid NULL pointer access during management transmit cleanup Currently 'ar' reference is not added in skb_cb. Though this is generally not used during transmit completion callbacks, on interface removal the remaining idr cleanup callback uses the ar pointer from skb_cb from management txmgmt_idr. Hence fill them during transmit call for proper usage to avoid NULL pointer dereference. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Balamurugan S Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230518071046.14337-1-quic_bselvara@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d814d74bc168..a344211f5b53 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -4443,6 +4443,7 @@ static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_vif *arvif, int buf_id; int ret; + ATH12K_SKB_CB(skb)->ar = ar; spin_lock_bh(&ar->txmgmt_idr_lock); buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0, ATH12K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC); -- cgit v1.2.3 From 3394b51c7d3f5239459ceac7e535e45836d78bd4 Mon Sep 17 00:00:00 2001 From: Carl Huang Date: Thu, 1 Jun 2023 13:35:15 +0300 Subject: wifi: ath12k: check hardware major version for WCN7850 This is to check the hardware major version for WCN7850 so only supported hardware is initialized. Now only WCN7850 with major version 2 is supported. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Carl Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230518105741.1281424-1-quic_cjhuang@quicinc.com --- drivers/net/wireless/ath/ath12k/pci.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 9f174daf324c..5990a55801f0 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1227,8 +1227,20 @@ static int ath12k_pci_probe(struct pci_dev *pdev, case WCN7850_DEVICE_ID: ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = false; - ab->hw_rev = ATH12K_HW_WCN7850_HW20; ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; + ath12k_pci_read_hw_version(ab, &soc_hw_version_major, + &soc_hw_version_minor); + switch (soc_hw_version_major) { + case ATH12K_PCI_SOC_HW_VERSION_2: + ab->hw_rev = ATH12K_HW_WCN7850_HW20; + break; + default: + dev_err(&pdev->dev, + "Unknown hardware version found for WCN7850: 0x%x\n", + soc_hw_version_major); + ret = -EOPNOTSUPP; + goto err_pci_free_region; + } break; default: -- cgit v1.2.3 From 8f04852e90cbed8e12c13d75a87adbad313d365e Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Mon, 29 May 2023 16:16:09 +0800 Subject: wifi: ath12k: Use msdu_end to check MCBC We are seeing a very low TCP throughput testing with some specific tools. This is because for sub-frames of an AMSDU, MCBC flag in mpdu_start may be not valid, and as a result those frames would be dropped by kernel. Add a new helper to get it from msdu_end. Also clean up original helper since it is not needed any more. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Baochen Qiang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230529081609.34567-1-quic_bqiang@quicinc.com --- drivers/net/wireless/ath/ath12k/dp_rx.c | 8 ++++---- drivers/net/wireless/ath/ath12k/hal.c | 16 ++++++++-------- drivers/net/wireless/ath/ath12k/hal.h | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 8c8162fbe5c6..ffd9a2018610 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -193,11 +193,11 @@ static void ath12k_dp_rxdesc_set_msdu_len(struct ath12k_base *ab, ab->hw_params->hal_ops->rx_desc_set_msdu_len(desc, len); } -static bool ath12k_dp_rx_h_is_mcbc(struct ath12k_base *ab, - struct hal_rx_desc *desc) +static bool ath12k_dp_rx_h_is_da_mcbc(struct ath12k_base *ab, + struct hal_rx_desc *desc) { return (ath12k_dp_rx_h_first_msdu(ab, desc) && - ab->hw_params->hal_ops->rx_desc_is_mcbc(desc)); + ab->hw_params->hal_ops->rx_desc_is_da_mcbc(desc)); } static bool ath12k_dp_rxdesc_mac_addr2_valid(struct ath12k_base *ab, @@ -2208,7 +2208,7 @@ static void ath12k_dp_rx_h_mpdu(struct ath12k *ar, /* PN for multicast packets will be checked in mac80211 */ rxcb = ATH12K_SKB_RXCB(msdu); - fill_crypto_hdr = ath12k_dp_rx_h_is_mcbc(ar->ab, rx_desc); + fill_crypto_hdr = ath12k_dp_rx_h_is_da_mcbc(ar->ab, rx_desc); rxcb->is_mcbc = fill_crypto_hdr; if (rxcb->is_mcbc) diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 0ec53afe9915..e7a150e7158e 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -447,10 +447,10 @@ static u8 *ath12k_hw_qcn9274_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) return desc->u.qcn9274.mpdu_start.addr2; } -static bool ath12k_hw_qcn9274_rx_desc_is_mcbc(struct hal_rx_desc *desc) +static bool ath12k_hw_qcn9274_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) { - return __le32_to_cpu(desc->u.qcn9274.mpdu_start.info6) & - RX_MPDU_START_INFO6_MCAST_BCAST; + return __le16_to_cpu(desc->u.qcn9274.msdu_end.info5) & + RX_MSDU_END_INFO5_DA_IS_MCBC; } static void ath12k_hw_qcn9274_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, @@ -708,7 +708,7 @@ const struct hal_ops hal_qcn9274_ops = { .rx_desc_get_msdu_end_offset = ath12k_hw_qcn9274_rx_desc_get_msdu_end_offset, .rx_desc_mac_addr2_valid = ath12k_hw_qcn9274_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath12k_hw_qcn9274_rx_desc_mpdu_start_addr2, - .rx_desc_is_mcbc = ath12k_hw_qcn9274_rx_desc_is_mcbc, + .rx_desc_is_da_mcbc = ath12k_hw_qcn9274_rx_desc_is_da_mcbc, .rx_desc_get_dot11_hdr = ath12k_hw_qcn9274_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_qcn9274_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_qcn9274_rx_desc_get_mpdu_frame_ctl, @@ -887,10 +887,10 @@ static u8 *ath12k_hw_wcn7850_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) return desc->u.wcn7850.mpdu_start.addr2; } -static bool ath12k_hw_wcn7850_rx_desc_is_mcbc(struct hal_rx_desc *desc) +static bool ath12k_hw_wcn7850_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) { - return __le32_to_cpu(desc->u.wcn7850.mpdu_start.info6) & - RX_MPDU_START_INFO6_MCAST_BCAST; + return __le16_to_cpu(desc->u.wcn7850.msdu_end.info5) & + RX_MSDU_END_INFO5_DA_IS_MCBC; } static void ath12k_hw_wcn7850_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, @@ -1163,7 +1163,7 @@ const struct hal_ops hal_wcn7850_ops = { .rx_desc_get_msdu_end_offset = ath12k_hw_wcn7850_rx_desc_get_msdu_end_offset, .rx_desc_mac_addr2_valid = ath12k_hw_wcn7850_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath12k_hw_wcn7850_rx_desc_mpdu_start_addr2, - .rx_desc_is_mcbc = ath12k_hw_wcn7850_rx_desc_is_mcbc, + .rx_desc_is_da_mcbc = ath12k_hw_wcn7850_rx_desc_is_da_mcbc, .rx_desc_get_dot11_hdr = ath12k_hw_wcn7850_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_wcn7850_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_wcn7850_rx_desc_get_mpdu_frame_ctl, diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 0d4fa12ea622..66035a787c72 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -1063,7 +1063,7 @@ struct hal_ops { u32 (*rx_desc_get_msdu_end_offset)(void); bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc); u8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc); - bool (*rx_desc_is_mcbc)(struct hal_rx_desc *desc); + bool (*rx_desc_is_da_mcbc)(struct hal_rx_desc *desc); void (*rx_desc_get_dot11_hdr)(struct hal_rx_desc *desc, struct ieee80211_hdr *hdr); u16 (*rx_desc_get_mpdu_frame_ctl)(struct hal_rx_desc *desc); -- cgit v1.2.3 From e2d1f005d3fbaea14ddea1a24db924406e55f6c3 Mon Sep 17 00:00:00 2001 From: Hari Chandrakanthan Date: Mon, 29 May 2023 15:43:58 +0530 Subject: wifi: ath12k: delete the timer rx_replenish_retry during rmmod The rx_replenish_retry timer is initialized in ath12k_core_alloc() when ath12k module is loaded. But rx_replenish_retry timer is not deleted anywhere in the code. It is supposed to be deleted when ath12k module is removed/unloaded. Delete the timer rx_replenish_retry in ath12k_core_free(). Found during code review. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0-02903-QCAHKSWPL_SILICONZ-1 Signed-off-by: Hari Chandrakanthan Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/1685355238-3282-1-git-send-email-quic_haric@quicinc.com --- drivers/net/wireless/ath/ath12k/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 499b81cd938e..3df8059d5512 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -886,6 +886,7 @@ void ath12k_core_deinit(struct ath12k_base *ab) void ath12k_core_free(struct ath12k_base *ab) { + timer_delete_sync(&ab->rx_replenish_retry); destroy_workqueue(ab->workqueue_aux); destroy_workqueue(ab->workqueue); kfree(ab); -- cgit v1.2.3 From 7ec5d48fdb78260a51122bd8d0cee4a0e2b7b089 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 11:00:59 -0700 Subject: Revert "tools: ynl: Remove duplicated include in handshake-user.c" This reverts commit e7c5433c5aaab52ddd5448967a9a5db94a3939cc. Commit e7c5433c5aaa ("tools: ynl: Remove duplicated include in handshake-user.c") was applied too hastily. It changes an auto-generated file, and there's already a proper fix on the list. Link: https://lore.kernel.org/all/ZIMPLYi%2FxRih+DlC@nanopsycho/ Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/handshake-user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c index 9ffe9fc58e51..72eb1c52a8fc 100644 --- a/tools/net/ynl/generated/handshake-user.c +++ b/tools/net/ynl/generated/handshake-user.c @@ -8,6 +8,7 @@ #include "ynl.h" #include +#include #include #include #include -- cgit v1.2.3 From 30b5c720e1a90c9709187871c9f2152192078519 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:49 -0700 Subject: tools: ynl-gen: cleanup user space header includes Bots started screaming that we're including stdlib.h twice. While at it move string.h into a common spot and drop stdio.h which we don't need. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5464 Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5466 Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5467 Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 251c5bfffd8d..e1b86b1fba66 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -2323,8 +2323,8 @@ def main(): headers = ['uapi/' + parsed.uapi_header] else: cw.p('#include ') + cw.p('#include ') if args.header: - cw.p('#include ') cw.p('#include ') else: cw.p(f'#include "{parsed.name}-user.h"') @@ -2339,9 +2339,6 @@ def main(): if args.mode == "user": if not args.header: - cw.p("#include ") - cw.p("#include ") - cw.p("#include ") cw.p("#include ") cw.p("#include ") cw.nl() -- cgit v1.2.3 From 9b52fd4b630526aa78bde8f9c6217954c71dc6a5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:50 -0700 Subject: tools: ynl: regen: cleanup user space header includes Remove unnecessary includes. Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/devlink-user.c | 4 +--- tools/net/ynl/generated/fou-user.c | 4 +--- tools/net/ynl/generated/handshake-user.c | 4 +--- tools/net/ynl/generated/netdev-user.c | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c index c3204e20b971..4604b6829fd0 100644 --- a/tools/net/ynl/generated/devlink-user.c +++ b/tools/net/ynl/generated/devlink-user.c @@ -4,13 +4,11 @@ /* YNL-GEN user source */ #include +#include #include "devlink-user.h" #include "ynl.h" #include -#include -#include -#include #include #include diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c index c08c85a6b6c4..23c8f347547e 100644 --- a/tools/net/ynl/generated/fou-user.c +++ b/tools/net/ynl/generated/fou-user.c @@ -4,13 +4,11 @@ /* YNL-GEN user source */ #include +#include #include "fou-user.h" #include "ynl.h" #include -#include -#include -#include #include #include diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c index 72eb1c52a8fc..7c204bf4c7cb 100644 --- a/tools/net/ynl/generated/handshake-user.c +++ b/tools/net/ynl/generated/handshake-user.c @@ -4,13 +4,11 @@ /* YNL-GEN user source */ #include +#include #include "handshake-user.h" #include "ynl.h" #include -#include -#include -#include #include #include diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index 3db6921b9fab..fe0da71f653c 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -4,13 +4,11 @@ /* YNL-GEN user source */ #include +#include #include "netdev-user.h" #include "ynl.h" #include -#include -#include -#include #include #include -- cgit v1.2.3 From 820343ccbb2e11a6579a33a856dcc2a10bb3c7a6 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:51 -0700 Subject: tools: ynl-gen: complete the C keyword list C keywords need to be avoided when naming things. Complete the list (ethtool has at least one thing called "auto"). Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index e1b86b1fba66..9b6ff256f80e 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1172,7 +1172,40 @@ op_mode_to_wrapper = { } _C_KW = { - 'do' + 'auto', + 'bool', + 'break', + 'case', + 'char', + 'const', + 'continue', + 'default', + 'do', + 'double', + 'else', + 'enum', + 'extern', + 'float', + 'for', + 'goto', + 'if', + 'inline', + 'int', + 'long', + 'register', + 'return', + 'short', + 'signed', + 'sizeof', + 'static', + 'struct', + 'switch', + 'typedef', + 'union', + 'unsigned', + 'void', + 'volatile', + 'while' } -- cgit v1.2.3 From 2c0f1466867c8405224b97d978b67f35d76b1dc1 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:52 -0700 Subject: tools: ynl-gen: combine else with closing bracket Code gen currently prints: } else if (... This is really ugly. Fix it by delaying printing of closing brackets in anticipation of else coming along. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 9b6ff256f80e..d2edded5f747 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1017,6 +1017,7 @@ class CodeWriter: self.nlib = nlib self._nl = False + self._block_end = False self._silent_block = False self._ind = 0 self._out = out_file @@ -1025,11 +1026,18 @@ class CodeWriter: def _is_cond(cls, line): return line.startswith('if') or line.startswith('while') or line.startswith('for') - def p(self, line, add_ind=0, eat_nl=False): + def p(self, line, add_ind=0): + if self._block_end: + self._block_end = False + if line.startswith('else'): + line = '} ' + line + else: + self._out.write('\t' * self._ind + '}\n') + if self._nl: - if not eat_nl: - self._out.write('\n') + self._out.write('\n') self._nl = False + ind = self._ind if line[-1] == ':': ind -= 1 @@ -1053,7 +1061,14 @@ class CodeWriter: if line and line[0] not in {';', ','}: line = ' ' + line self._ind -= 1 - self.p('}' + line, eat_nl=True) + self._nl = False + if not line: + # Delay printing closing bracket in case "else" comes next + if self._block_end: + self._out.write('\t' * (self._ind + 1) + '}\n') + self._block_end = True + else: + self.p('}' + line) def write_doc_line(self, doc, indent=True): words = doc.split() -- cgit v1.2.3 From e4ea3cc68472b1cc0b68a1adf145ee39fb90a506 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:53 -0700 Subject: tools: ynl-gen: get attr type outside of if() Reading attr type with mnl_attr_get_type() for each condition leads to most conditions being longer than 80 chars. Avoid this by reading the type to a variable on the stack. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index d2edded5f747..ecd8beba7e0d 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -153,7 +153,7 @@ class Type(SpecAttr): init_lines = [init_lines] kw = 'if' if first else 'else if' - ri.cw.block_start(line=f"{kw} (mnl_attr_get_type(attr) == {self.enum_name})") + ri.cw.block_start(line=f"{kw} (type == {self.enum_name})") if local_vars: for local in local_vars: ri.cw.p(local) @@ -1418,6 +1418,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.nl() ri.cw.block_start(line=iter_line) + ri.cw.p('unsigned int type = mnl_attr_get_type(attr);') + ri.cw.nl() first = True for _, arg in struct.member_list(): -- cgit v1.2.3 From 7234415b8f86c496fec2d62a48f136cde530ad95 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:54 -0700 Subject: tools: ynl: regen: regenerate the if ladders Renegate the code to combine } and else and use tmp variable to store type. Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/devlink-user.c | 74 ++++++++++++++++---------------- tools/net/ynl/generated/fou-user.c | 31 ++++++------- tools/net/ynl/generated/handshake-user.c | 29 ++++++------- tools/net/ynl/generated/netdev-user.c | 7 +-- 4 files changed, 67 insertions(+), 74 deletions(-) diff --git a/tools/net/ynl/generated/devlink-user.c b/tools/net/ynl/generated/devlink-user.c index 4604b6829fd0..939bd45feaca 100644 --- a/tools/net/ynl/generated/devlink-user.c +++ b/tools/net/ynl/generated/devlink-user.c @@ -126,7 +126,9 @@ int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, const struct nlattr *attr; mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_NAME) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_INFO_VERSION_NAME) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -137,8 +139,7 @@ int devlink_dl_info_version_parse(struct ynl_parse_arg *yarg, dst->info_version_name = malloc(len + 1); memcpy(dst->info_version_name, mnl_attr_get_str(attr), len); dst->info_version_name[len] = 0; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_VALUE) { + } else if (type == DEVLINK_ATTR_INFO_VERSION_VALUE) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -167,13 +168,14 @@ int devlink_dl_reload_stats_entry_parse(struct ynl_parse_arg *yarg, const struct nlattr *attr; mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_LIMIT) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_STATS_LIMIT) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.reload_stats_limit = 1; dst->reload_stats_limit = mnl_attr_get_u8(attr); - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_VALUE) { + } else if (type == DEVLINK_ATTR_RELOAD_STATS_VALUE) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.reload_stats_value = 1; @@ -208,7 +210,9 @@ int devlink_dl_reload_act_stats_parse(struct ynl_parse_arg *yarg, return ynl_error_parse(yarg, "attribute already present (dl-reload-act-stats.reload-stats-entry)"); mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_STATS_ENTRY) { n_reload_stats_entry++; } } @@ -255,13 +259,14 @@ int devlink_dl_reload_act_info_parse(struct ynl_parse_arg *yarg, return ynl_error_parse(yarg, "attribute already present (dl-reload-act-info.reload-action-stats)"); mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_ACTION) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.reload_action = 1; dst->reload_action = mnl_attr_get_u8(attr); - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_STATS) { + } else if (type == DEVLINK_ATTR_RELOAD_ACTION_STATS) { n_reload_action_stats++; } } @@ -308,7 +313,9 @@ int devlink_dl_reload_stats_parse(struct ynl_parse_arg *yarg, return ynl_error_parse(yarg, "attribute already present (dl-reload-stats.reload-action-info)"); mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION_INFO) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_ACTION_INFO) { n_reload_action_info++; } } @@ -347,7 +354,9 @@ int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg, parg.ys = yarg->ys; mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_STATS) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_RELOAD_STATS) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.reload_stats = 1; @@ -356,8 +365,7 @@ int devlink_dl_dev_stats_parse(struct ynl_parse_arg *yarg, parg.data = &dst->reload_stats; if (devlink_dl_reload_stats_parse(&parg, attr)) return MNL_CB_ERROR; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_REMOTE_RELOAD_STATS) { + } else if (type == DEVLINK_ATTR_REMOTE_RELOAD_STATS) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.remote_reload_stats = 1; @@ -400,7 +408,9 @@ int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) parg.ys = yarg->ys; mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_BUS_NAME) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -411,8 +421,7 @@ int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->bus_name = malloc(len + 1); memcpy(dst->bus_name, mnl_attr_get_str(attr), len); dst->bus_name[len] = 0; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_NAME) { + } else if (type == DEVLINK_ATTR_DEV_NAME) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -423,20 +432,17 @@ int devlink_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->dev_name = malloc(len + 1); memcpy(dst->dev_name, mnl_attr_get_str(attr), len); dst->dev_name[len] = 0; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_FAILED) { + } else if (type == DEVLINK_ATTR_RELOAD_FAILED) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.reload_failed = 1; dst->reload_failed = mnl_attr_get_u8(attr); - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_RELOAD_ACTION) { + } else if (type == DEVLINK_ATTR_RELOAD_ACTION) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.reload_action = 1; dst->reload_action = mnl_attr_get_u8(attr); - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_STATS) { + } else if (type == DEVLINK_ATTR_DEV_STATS) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.dev_stats = 1; @@ -576,7 +582,9 @@ int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) return ynl_error_parse(yarg, "attribute already present (devlink.info-version-stored)"); mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == DEVLINK_ATTR_BUS_NAME) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == DEVLINK_ATTR_BUS_NAME) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -587,8 +595,7 @@ int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->bus_name = malloc(len + 1); memcpy(dst->bus_name, mnl_attr_get_str(attr), len); dst->bus_name[len] = 0; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_DEV_NAME) { + } else if (type == DEVLINK_ATTR_DEV_NAME) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -599,8 +606,7 @@ int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->dev_name = malloc(len + 1); memcpy(dst->dev_name, mnl_attr_get_str(attr), len); dst->dev_name[len] = 0; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_DRIVER_NAME) { + } else if (type == DEVLINK_ATTR_INFO_DRIVER_NAME) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -611,8 +617,7 @@ int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->info_driver_name = malloc(len + 1); memcpy(dst->info_driver_name, mnl_attr_get_str(attr), len); dst->info_driver_name[len] = 0; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_SERIAL_NUMBER) { + } else if (type == DEVLINK_ATTR_INFO_SERIAL_NUMBER) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -623,14 +628,11 @@ int devlink_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->info_serial_number = malloc(len + 1); memcpy(dst->info_serial_number, mnl_attr_get_str(attr), len); dst->info_serial_number[len] = 0; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_FIXED) { + } else if (type == DEVLINK_ATTR_INFO_VERSION_FIXED) { n_info_version_fixed++; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_RUNNING) { + } else if (type == DEVLINK_ATTR_INFO_VERSION_RUNNING) { n_info_version_running++; - } - else if (mnl_attr_get_type(attr) == DEVLINK_ATTR_INFO_VERSION_STORED) { + } else if (type == DEVLINK_ATTR_INFO_VERSION_STORED) { n_info_version_stored++; } } diff --git a/tools/net/ynl/generated/fou-user.c b/tools/net/ynl/generated/fou-user.c index 23c8f347547e..4271b5d43c58 100644 --- a/tools/net/ynl/generated/fou-user.c +++ b/tools/net/ynl/generated/fou-user.c @@ -172,42 +172,38 @@ int fou_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst = yarg->data; mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == FOU_ATTR_PORT) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == FOU_ATTR_PORT) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.port = 1; dst->port = mnl_attr_get_u16(attr); - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_IPPROTO) { + } else if (type == FOU_ATTR_IPPROTO) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.ipproto = 1; dst->ipproto = mnl_attr_get_u8(attr); - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_TYPE) { + } else if (type == FOU_ATTR_TYPE) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.type = 1; dst->type = mnl_attr_get_u8(attr); - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_REMCSUM_NOPARTIAL) { + } else if (type == FOU_ATTR_REMCSUM_NOPARTIAL) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.remcsum_nopartial = 1; - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_LOCAL_V4) { + } else if (type == FOU_ATTR_LOCAL_V4) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.local_v4 = 1; dst->local_v4 = mnl_attr_get_u32(attr); - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_PEER_V4) { + } else if (type == FOU_ATTR_PEER_V4) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.peer_v4 = 1; dst->peer_v4 = mnl_attr_get_u32(attr); - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_LOCAL_V6) { + } else if (type == FOU_ATTR_LOCAL_V6) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -217,8 +213,7 @@ int fou_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->_present.local_v6_len = len; dst->local_v6 = malloc(len); memcpy(dst->local_v6, mnl_attr_get_payload(attr), len); - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_PEER_V6) { + } else if (type == FOU_ATTR_PEER_V6) { unsigned int len; if (ynl_attr_validate(yarg, attr)) @@ -228,14 +223,12 @@ int fou_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst->_present.peer_v6_len = len; dst->peer_v6 = malloc(len); memcpy(dst->peer_v6, mnl_attr_get_payload(attr), len); - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_PEER_PORT) { + } else if (type == FOU_ATTR_PEER_PORT) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.peer_port = 1; dst->peer_port = mnl_attr_get_u16(attr); - } - else if (mnl_attr_get_type(attr) == FOU_ATTR_IFINDEX) { + } else if (type == FOU_ATTR_IFINDEX) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.ifindex = 1; diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c index 7c204bf4c7cb..3a0392b3355e 100644 --- a/tools/net/ynl/generated/handshake-user.c +++ b/tools/net/ynl/generated/handshake-user.c @@ -116,13 +116,14 @@ int handshake_x509_parse(struct ynl_parse_arg *yarg, const struct nlattr *attr; mnl_attr_for_each_nested(attr, nested) { - if (mnl_attr_get_type(attr) == HANDSHAKE_A_X509_CERT) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == HANDSHAKE_A_X509_CERT) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.cert = 1; dst->cert = mnl_attr_get_u32(attr); - } - else if (mnl_attr_get_type(attr) == HANDSHAKE_A_X509_PRIVKEY) { + } else if (type == HANDSHAKE_A_X509_PRIVKEY) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.privkey = 1; @@ -171,37 +172,33 @@ int handshake_accept_rsp_parse(const struct nlmsghdr *nlh, void *data) return ynl_error_parse(yarg, "attribute already present (accept.peer-identity)"); mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_SOCKFD) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == HANDSHAKE_A_ACCEPT_SOCKFD) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.sockfd = 1; dst->sockfd = mnl_attr_get_u32(attr); - } - else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_MESSAGE_TYPE) { + } else if (type == HANDSHAKE_A_ACCEPT_MESSAGE_TYPE) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.message_type = 1; dst->message_type = mnl_attr_get_u32(attr); - } - else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_TIMEOUT) { + } else if (type == HANDSHAKE_A_ACCEPT_TIMEOUT) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.timeout = 1; dst->timeout = mnl_attr_get_u32(attr); - } - else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_AUTH_MODE) { + } else if (type == HANDSHAKE_A_ACCEPT_AUTH_MODE) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.auth_mode = 1; dst->auth_mode = mnl_attr_get_u32(attr); - } - else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { + } else if (type == HANDSHAKE_A_ACCEPT_PEER_IDENTITY) { n_peer_identity++; - } - else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_CERTIFICATE) { + } else if (type == HANDSHAKE_A_ACCEPT_CERTIFICATE) { n_certificate++; - } - else if (mnl_attr_get_type(attr) == HANDSHAKE_A_ACCEPT_PEERNAME) { + } else if (type == HANDSHAKE_A_ACCEPT_PEERNAME) { unsigned int len; if (ynl_attr_validate(yarg, attr)) diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index fe0da71f653c..12069784637e 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -79,13 +79,14 @@ int netdev_dev_get_rsp_parse(const struct nlmsghdr *nlh, void *data) dst = yarg->data; mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { - if (mnl_attr_get_type(attr) == NETDEV_A_DEV_IFINDEX) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == NETDEV_A_DEV_IFINDEX) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.ifindex = 1; dst->ifindex = mnl_attr_get_u32(attr); - } - else if (mnl_attr_get_type(attr) == NETDEV_A_DEV_XDP_FEATURES) { + } else if (type == NETDEV_A_DEV_XDP_FEATURES) { if (ynl_attr_validate(yarg, attr)) return MNL_CB_ERROR; dst->_present.xdp_features = 1; -- cgit v1.2.3 From f2ba1e5e22081e3279fd248677f53ce719fdc23d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:55 -0700 Subject: tools: ynl-gen: stop generating common notification handlers Common notification handler was supposed to be a way for the user to parse the notifications from a socket synchronously. I don't think we'll end up using it, ynl_ntf_check() works for all known use cases. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 73 ---------------------------------------------- 1 file changed, 73 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index ecd8beba7e0d..f88417947e60 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -1810,70 +1810,6 @@ def print_ntf_type_free(ri): ri.cw.nl() -def print_ntf_parse_prototype(family, cw, suffix=';'): - cw.write_func_prot('struct ynl_ntf_base_type *', f"{family['name']}_ntf_parse", - ['struct ynl_sock *ys'], suffix=suffix) - - -def print_ntf_type_parse(family, cw, ku_mode): - print_ntf_parse_prototype(family, cw, suffix='') - cw.block_start() - cw.write_func_lvar(['struct genlmsghdr *genlh;', - 'struct nlmsghdr *nlh;', - 'struct ynl_parse_arg yarg = { .ys = ys, };', - 'struct ynl_ntf_base_type *rsp;', - 'int len, err;', - 'mnl_cb_t parse;']) - cw.p('len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE);') - cw.p('if (len < (ssize_t)(sizeof(*nlh) + sizeof(*genlh)))') - cw.p('return NULL;') - cw.nl() - cw.p('nlh = (struct nlmsghdr *)ys->rx_buf;') - cw.p('genlh = mnl_nlmsg_get_payload(nlh);') - cw.nl() - cw.block_start(line='switch (genlh->cmd)') - for ntf_op in sorted(family.all_notify.keys()): - op = family.ops[ntf_op] - ri = RenderInfo(cw, family, ku_mode, op, ntf_op, "notify") - for ntf in op['notify']['cmds']: - cw.p(f"case {ntf.enum_name}:") - cw.p(f"rsp = calloc(1, sizeof({type_name(ri, 'notify')}));") - cw.p(f"parse = {op_prefix(ri, 'reply', deref=True)}_parse;") - cw.p(f"yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") - cw.p(f"rsp->free = (void *){op_prefix(ri, 'notify')}_free;") - cw.p('break;') - for op_name, op in family.ops.items(): - if 'event' not in op: - continue - ri = RenderInfo(cw, family, ku_mode, op, op_name, "event") - cw.p(f"case {op.enum_name}:") - cw.p(f"rsp = calloc(1, sizeof({type_name(ri, 'event')}));") - cw.p(f"parse = {op_prefix(ri, 'reply', deref=True)}_parse;") - cw.p(f"yarg.rsp_policy = &{ri.struct['reply'].render_name}_nest;") - cw.p(f"rsp->free = (void *){op_prefix(ri, 'notify')}_free;") - cw.p('break;') - cw.p('default:') - cw.p('ynl_error_unknown_notification(ys, genlh->cmd);') - cw.p('return NULL;') - cw.block_end() - cw.nl() - cw.p('yarg.data = rsp->data;') - cw.nl() - cw.p(f"err = {cw.nlib.parse_cb_run('parse', '&yarg', True)};") - cw.p('if (err < 0)') - cw.p('goto err_free;') - cw.nl() - cw.p('rsp->family = nlh->nlmsg_type;') - cw.p('rsp->cmd = genlh->cmd;') - cw.p('return rsp;') - cw.nl() - cw.p('err_free:') - cw.p('free(rsp);') - cw.p('return NULL;') - cw.block_end() - cw.nl() - - def print_req_policy_fwd(cw, struct, ri=None, terminate=True): if terminate and ri and kernel_can_gen_family_struct(struct.family): return @@ -2513,10 +2449,6 @@ def main(): print_rsp_type(ri) cw.nl() print_wrapped_type(ri) - - if parsed.has_notifications(): - cw.p('/* --------------- Common notification parsing --------------- */') - print_ntf_parse_prototype(parsed, cw) cw.nl() else: cw.p('/* Enums */') @@ -2580,11 +2512,6 @@ def main(): ri = RenderInfo(cw, parsed, args.mode, op, op_name, "event") print_ntf_type_free(ri) - - if parsed.has_notifications(): - cw.p('/* --------------- Common notification parsing --------------- */') - print_ntf_type_parse(parsed, cw, args.mode) - cw.nl() render_user_family(parsed, cw, False) -- cgit v1.2.3 From d0915d64c3a636f73065dbb7e5aab78eb7e75f0d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:56 -0700 Subject: tools: ynl: regen: stop generating common notification handlers Remove unused notification handlers. Signed-off-by: Jakub Kicinski --- tools/net/ynl/generated/handshake-user.c | 45 ------------------------------ tools/net/ynl/generated/handshake-user.h | 3 -- tools/net/ynl/generated/netdev-user.c | 47 -------------------------------- tools/net/ynl/generated/netdev-user.h | 3 -- 4 files changed, 98 deletions(-) diff --git a/tools/net/ynl/generated/handshake-user.c b/tools/net/ynl/generated/handshake-user.c index 3a0392b3355e..7c67765daf90 100644 --- a/tools/net/ynl/generated/handshake-user.c +++ b/tools/net/ynl/generated/handshake-user.c @@ -315,51 +315,6 @@ int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req) return 0; } -/* --------------- Common notification parsing --------------- */ -struct ynl_ntf_base_type *handshake_ntf_parse(struct ynl_sock *ys) -{ - struct ynl_parse_arg yarg = { .ys = ys, }; - struct ynl_ntf_base_type *rsp; - struct genlmsghdr *genlh; - struct nlmsghdr *nlh; - mnl_cb_t parse; - int len, err; - - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); - if (len < (ssize_t)(sizeof(*nlh) + sizeof(*genlh))) - return NULL; - - nlh = (struct nlmsghdr *)ys->rx_buf; - genlh = mnl_nlmsg_get_payload(nlh); - - switch (genlh->cmd) { - case HANDSHAKE_CMD_READY: - rsp = calloc(1, sizeof(struct handshake_accept_ntf)); - parse = handshake_accept_rsp_parse; - yarg.rsp_policy = &handshake_accept_nest; - rsp->free = (void *)handshake_accept_ntf_free; - break; - default: - ynl_error_unknown_notification(ys, genlh->cmd); - return NULL; - } - - yarg.data = rsp->data; - - err = mnl_cb_run2(ys->rx_buf, len, 0, 0, parse, &yarg, - ynl_cb_array, NLMSG_MIN_TYPE); - if (err < 0) - goto err_free; - - rsp->family = nlh->nlmsg_type; - rsp->cmd = genlh->cmd; - return rsp; - -err_free: - free(rsp); - return NULL; -} - static const struct ynl_ntf_info handshake_ntf_info[] = { [HANDSHAKE_CMD_READY] = { .alloc_sz = sizeof(struct handshake_accept_ntf), diff --git a/tools/net/ynl/generated/handshake-user.h b/tools/net/ynl/generated/handshake-user.h index 38e0844f2efd..47646bb91cea 100644 --- a/tools/net/ynl/generated/handshake-user.h +++ b/tools/net/ynl/generated/handshake-user.h @@ -142,7 +142,4 @@ __handshake_done_req_set_remote_auth(struct handshake_done_req *req, */ int handshake_done(struct ynl_sock *ys, struct handshake_done_req *req); -/* --------------- Common notification parsing --------------- */ -struct ynl_ntf_base_type *handshake_ntf_parse(struct ynl_sock *ys); - #endif /* _LINUX_HANDSHAKE_GEN_H */ diff --git a/tools/net/ynl/generated/netdev-user.c b/tools/net/ynl/generated/netdev-user.c index 12069784637e..4eb8aefef0cd 100644 --- a/tools/net/ynl/generated/netdev-user.c +++ b/tools/net/ynl/generated/netdev-user.c @@ -172,53 +172,6 @@ void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp) free(rsp); } -/* --------------- Common notification parsing --------------- */ -struct ynl_ntf_base_type *netdev_ntf_parse(struct ynl_sock *ys) -{ - struct ynl_parse_arg yarg = { .ys = ys, }; - struct ynl_ntf_base_type *rsp; - struct genlmsghdr *genlh; - struct nlmsghdr *nlh; - mnl_cb_t parse; - int len, err; - - len = mnl_socket_recvfrom(ys->sock, ys->rx_buf, MNL_SOCKET_BUFFER_SIZE); - if (len < (ssize_t)(sizeof(*nlh) + sizeof(*genlh))) - return NULL; - - nlh = (struct nlmsghdr *)ys->rx_buf; - genlh = mnl_nlmsg_get_payload(nlh); - - switch (genlh->cmd) { - case NETDEV_CMD_DEV_ADD_NTF: - case NETDEV_CMD_DEV_DEL_NTF: - case NETDEV_CMD_DEV_CHANGE_NTF: - rsp = calloc(1, sizeof(struct netdev_dev_get_ntf)); - parse = netdev_dev_get_rsp_parse; - yarg.rsp_policy = &netdev_dev_nest; - rsp->free = (void *)netdev_dev_get_ntf_free; - break; - default: - ynl_error_unknown_notification(ys, genlh->cmd); - return NULL; - } - - yarg.data = rsp->data; - - err = mnl_cb_run2(ys->rx_buf, len, 0, 0, parse, &yarg, - ynl_cb_array, NLMSG_MIN_TYPE); - if (err < 0) - goto err_free; - - rsp->family = nlh->nlmsg_type; - rsp->cmd = genlh->cmd; - return rsp; - -err_free: - free(rsp); - return NULL; -} - static const struct ynl_ntf_info netdev_ntf_info[] = { [NETDEV_CMD_DEV_ADD_NTF] = { .alloc_sz = sizeof(struct netdev_dev_get_ntf), diff --git a/tools/net/ynl/generated/netdev-user.h b/tools/net/ynl/generated/netdev-user.h index d146bc4b2112..5554dc69bb9c 100644 --- a/tools/net/ynl/generated/netdev-user.h +++ b/tools/net/ynl/generated/netdev-user.h @@ -82,7 +82,4 @@ struct netdev_dev_get_ntf { void netdev_dev_get_ntf_free(struct netdev_dev_get_ntf *rsp); -/* --------------- Common notification parsing --------------- */ -struct ynl_ntf_base_type *netdev_ntf_parse(struct ynl_sock *ys); - #endif /* _LINUX_NETDEV_GEN_H */ -- cgit v1.2.3 From ced1568862bdb985eb4e5ca854cc7734a4ad3543 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:57 -0700 Subject: tools: ynl-gen: sanitize notification tracking Don't modify the raw dicts (as loaded from YAML) to pretend that the notify attributes also exist on the ops. This makes the code easier to follow. Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/nlspec.py | 5 +++- tools/net/ynl/ynl-gen-c.py | 65 ++++++++++++++++----------------------------- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 9f7ad87d69af..623c5702bd10 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -329,8 +329,8 @@ class SpecFamily(SpecElement): attr_sets dict of attribute sets msgs dict of all messages (index by name) - msgs_by_value dict of all messages (indexed by name) ops dict of all valid requests / responses + ntfs dict of all async events consts dict of all constants/enums fixed_header string, optional name of family default fixed header struct """ @@ -370,6 +370,7 @@ class SpecFamily(SpecElement): self.req_by_value = collections.OrderedDict() self.rsp_by_value = collections.OrderedDict() self.ops = collections.OrderedDict() + self.ntfs = collections.OrderedDict() self.consts = collections.OrderedDict() last_exception = None @@ -491,3 +492,5 @@ class SpecFamily(SpecElement): self.rsp_by_value[op.rsp_value] = op if not op.is_async and 'attribute-set' in op: self.ops[op.name] = op + elif op.is_async: + self.ntfs[op.name] = op diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index f88417947e60..a230598d216f 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -714,6 +714,8 @@ class Operation(SpecOperation): self.dual_policy = ('do' in yaml and 'request' in yaml['do']) and \ ('dump' in yaml and 'request' in yaml['dump']) + self.has_ntf = False + # Added by resolve: self.enum_name = None delattr(self, "enum_name") @@ -726,12 +728,8 @@ class Operation(SpecOperation): else: self.enum_name = self.family.async_op_prefix + c_upper(self.name) - def add_notification(self, op): - if 'notify' not in self.yaml: - self.yaml['notify'] = dict() - self.yaml['notify']['reply'] = self.yaml['do']['reply'] - self.yaml['notify']['cmds'] = [] - self.yaml['notify']['cmds'].append(op) + def mark_has_ntf(self): + self.has_ntf = True class Family(SpecFamily): @@ -793,14 +791,12 @@ class Family(SpecFamily): self.root_sets = dict() # dict space-name -> set('request', 'reply') self.pure_nested_structs = dict() - self.all_notify = dict() + self._mark_notify() self._mock_up_events() - self._dictify() self._load_root_sets() self._load_nested_sets() - self._load_all_notify() self._load_hooks() self.kernel_policy = self.yaml.get('kernel-policy', 'split') @@ -816,6 +812,11 @@ class Family(SpecFamily): def new_operation(self, elem, req_value, rsp_value): return Operation(self, elem, req_value, rsp_value) + def _mark_notify(self): + for op in self.msgs.values(): + if 'notify' in op: + self.ops[op['notify']].mark_has_ntf() + # Fake a 'do' equivalent of all events, so that we can render their response parsing def _mock_up_events(self): for op in self.yaml['operations']['list']: @@ -826,14 +827,6 @@ class Family(SpecFamily): } } - def _dictify(self): - ntf = [] - for msg in self.msgs.values(): - if 'notify' in msg: - ntf.append(msg) - for n in ntf: - self.ops[n['notify']].add_notification(n) - def _load_root_sets(self): for op_name, op in self.ops.items(): if 'attribute-set' not in op: @@ -922,14 +915,6 @@ class Family(SpecFamily): child.request |= struct.request child.reply |= struct.reply - def _load_all_notify(self): - for op_name, op in self.ops.items(): - if not op: - continue - - if 'notify' in op: - self.all_notify[op_name] = op['notify']['cmds'] - def _load_global_policy(self): global_set = set() attr_set_name = None @@ -968,21 +953,15 @@ class Family(SpecFamily): self.hooks[when][op_mode]['set'].add(name) self.hooks[when][op_mode]['list'].append(name) - def has_notifications(self): - for op in self.ops.values(): - if 'notify' in op or 'event' in op: - return True - return False - class RenderInfo: def __init__(self, cw, family, ku_space, op, op_name, op_mode, attr_set=None): self.family = family self.nl = cw.nlib self.ku_space = ku_space + self.op_mode = op_mode self.op = op self.op_name = op_name - self.op_mode = op_mode # 'do' and 'dump' response parsing is identical self.type_consistent = True @@ -1004,6 +983,8 @@ class RenderInfo: self.cw = cw self.struct = dict() + if op_mode == 'notify': + op_mode = 'do' for op_dir in ['request', 'reply']: if op and op_dir in op[op_mode]: self.struct[op_dir] = Struct(family, self.attr_set, @@ -2209,14 +2190,14 @@ def render_user_family(family, cw, prototype): cw.p(f'extern {symbol};') return - ntf = family.has_notifications() - if ntf: + if family.ntfs: cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ") - for ntf_op in sorted(family.all_notify.keys()): - op = family.ops[ntf_op] - ri = RenderInfo(cw, family, "user", op, ntf_op, "notify") - for ntf in op['notify']['cmds']: - _render_user_ntf_entry(ri, ntf) + for ntf_op_name, ntf_op in family.ntfs.items(): + if 'notify' not in ntf_op: + continue + op = family.ops[ntf_op['notify']] + ri = RenderInfo(cw, family, "user", op, op.name, "notify") + _render_user_ntf_entry(ri, ntf_op) for op_name, op in family.ops.items(): if 'event' not in op: continue @@ -2227,7 +2208,7 @@ def render_user_family(family, cw, prototype): cw.block_start(f'{symbol} = ') cw.p(f'.name\t\t= "{family.name}",') - if ntf: + if family.ntfs: cw.p(f".ntf_info\t= {family['name']}_ntf_info,") cw.p(f".ntf_info_size\t= MNL_ARRAY_SIZE({family['name']}_ntf_info),") cw.block_end(line=';') @@ -2436,7 +2417,7 @@ def main(): print_dump_prototype(ri) cw.nl() - if 'notify' in op: + if op.has_ntf: cw.p(f"/* {op.enum_name} - notify */") ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify') if not ri.type_consistent: @@ -2497,7 +2478,7 @@ def main(): print_dump(ri) cw.nl() - if 'notify' in op: + if op.has_ntf: cw.p(f"/* {op.enum_name} - notify */") ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify') if not ri.type_consistent: -- cgit v1.2.3 From 6da3424fd629570b5e3b5e9484ffc752a325f9f5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:58 -0700 Subject: tools: ynl-gen: support code gen for events Netlink specs support both events and notifications (former can define their own message contents). Plug in missing code to generate types, parsers and include events into notification tables. Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/nlspec.py | 2 +- tools/net/ynl/ynl-gen-c.py | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 623c5702bd10..c5d4a6d476a0 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -423,7 +423,7 @@ class SpecFamily(SpecElement): self.fixed_header = self.yaml['operations'].get('fixed-header') req_val = rsp_val = 1 for elem in self.yaml['operations']['list']: - if 'notify' in elem: + if 'notify' in elem or 'event' in elem: if 'value' in elem: rsp_val = elem['value'] req_val_next = req_val diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index a230598d216f..ccd73f10384c 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -828,7 +828,7 @@ class Family(SpecFamily): } def _load_root_sets(self): - for op_name, op in self.ops.items(): + for op_name, op in self.msgs.items(): if 'attribute-set' not in op: continue @@ -839,6 +839,8 @@ class Family(SpecFamily): req_attrs.update(set(op[op_mode]['request']['attributes'])) if op_mode in op and 'reply' in op[op_mode]: rsp_attrs.update(set(op[op_mode]['reply']['attributes'])) + if 'event' in op: + rsp_attrs.update(set(op['event']['attributes'])) if op['attribute-set'] not in self.root_sets: self.root_sets[op['attribute-set']] = {'request': req_attrs, 'reply': rsp_attrs} @@ -2193,10 +2195,13 @@ def render_user_family(family, cw, prototype): if family.ntfs: cw.block_start(line=f"static const struct ynl_ntf_info {family['name']}_ntf_info[] = ") for ntf_op_name, ntf_op in family.ntfs.items(): - if 'notify' not in ntf_op: - continue - op = family.ops[ntf_op['notify']] - ri = RenderInfo(cw, family, "user", op, op.name, "notify") + if 'notify' in ntf_op: + op = family.ops[ntf_op['notify']] + ri = RenderInfo(cw, family, "user", op, op.name, "notify") + elif 'event' in ntf_op: + ri = RenderInfo(cw, family, "user", ntf_op, ntf_op_name, "event") + else: + raise Exception('Invalid notification ' + ntf_op_name) _render_user_ntf_entry(ri, ntf_op) for op_name, op in family.ops.items(): if 'event' not in op: @@ -2424,6 +2429,7 @@ def main(): raise Exception(f'Only notifications with consistent types supported ({op.name})') print_wrapped_type(ri) + for op_name, op in parsed.ntfs.items(): if 'event' in op: ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'event') cw.p(f"/* {op.enum_name} - event */") @@ -2485,6 +2491,7 @@ def main(): raise Exception(f'Only notifications with consistent types supported ({op.name})') print_ntf_type_free(ri) + for op_name, op in parsed.ntfs.items(): if 'event' in op: cw.p(f"/* {op.enum_name} - event */") -- cgit v1.2.3 From 6f96ec73cb5a87f438fa20c585e72b2918885df3 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:11:59 -0700 Subject: tools: ynl-gen: don't pass op_name to RenderInfo The op_name argument is barely used and identical to op.name in all cases. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index ccd73f10384c..be860dee7239 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -957,13 +957,12 @@ class Family(SpecFamily): class RenderInfo: - def __init__(self, cw, family, ku_space, op, op_name, op_mode, attr_set=None): + def __init__(self, cw, family, ku_space, op, op_mode, attr_set=None): self.family = family self.nl = cw.nlib self.ku_space = ku_space self.op_mode = op_mode self.op = op - self.op_name = op_name # 'do' and 'dump' response parsing is identical self.type_consistent = True @@ -978,7 +977,7 @@ class RenderInfo: self.attr_set = op['attribute-set'] if op: - self.type_name = c_lower(op_name) + self.type_name = c_lower(op.name) else: self.type_name = c_lower(attr_set) @@ -2197,16 +2196,16 @@ def render_user_family(family, cw, prototype): for ntf_op_name, ntf_op in family.ntfs.items(): if 'notify' in ntf_op: op = family.ops[ntf_op['notify']] - ri = RenderInfo(cw, family, "user", op, op.name, "notify") + ri = RenderInfo(cw, family, "user", op, "notify") elif 'event' in ntf_op: - ri = RenderInfo(cw, family, "user", ntf_op, ntf_op_name, "event") + ri = RenderInfo(cw, family, "user", ntf_op, "event") else: raise Exception('Invalid notification ' + ntf_op_name) _render_user_ntf_entry(ri, ntf_op) for op_name, op in family.ops.items(): if 'event' not in op: continue - ri = RenderInfo(cw, family, "user", op, op_name, "event") + ri = RenderInfo(cw, family, "user", op, "event") _render_user_ntf_entry(ri, op) cw.block_end(line=";") cw.nl() @@ -2343,7 +2342,7 @@ def main(): if parsed.kernel_policy in {'per-op', 'split'}: for op_name, op in parsed.ops.items(): if 'do' in op and 'event' not in op: - ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do") + ri = RenderInfo(cw, parsed, args.mode, op, "do") print_req_policy_fwd(cw, ri.struct['request'], ri=ri) cw.nl() @@ -2372,7 +2371,7 @@ def main(): for op_mode in ['do', 'dump']: if op_mode in op and 'request' in op[op_mode]: cw.p(f"/* {op.enum_name} - {op_mode} */") - ri = RenderInfo(cw, parsed, args.mode, op, op_name, op_mode) + ri = RenderInfo(cw, parsed, args.mode, op, op_mode) print_req_policy(cw, ri.struct['request'], ri=ri) cw.nl() @@ -2392,7 +2391,7 @@ def main(): cw.p('/* Common nested types */') for attr_set, struct in parsed.pure_nested_structs.items(): - ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set) + ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set) print_type_full(ri, struct) for op_name, op in parsed.ops.items(): @@ -2400,7 +2399,7 @@ def main(): if 'do' in op and 'event' not in op: cw.p(f"/* {op.enum_name} - do */") - ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do") + ri = RenderInfo(cw, parsed, args.mode, op, "do") print_req_type(ri) print_req_type_helpers(ri) cw.nl() @@ -2412,7 +2411,7 @@ def main(): if 'dump' in op: cw.p(f"/* {op.enum_name} - dump */") - ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'dump') + ri = RenderInfo(cw, parsed, args.mode, op, 'dump') if 'request' in op['dump']: print_req_type(ri) print_req_type_helpers(ri) @@ -2424,14 +2423,14 @@ def main(): if op.has_ntf: cw.p(f"/* {op.enum_name} - notify */") - ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify') + ri = RenderInfo(cw, parsed, args.mode, op, 'notify') if not ri.type_consistent: raise Exception(f'Only notifications with consistent types supported ({op.name})') print_wrapped_type(ri) for op_name, op in parsed.ntfs.items(): if 'event' in op: - ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'event') + ri = RenderInfo(cw, parsed, args.mode, op, 'event') cw.p(f"/* {op.enum_name} - event */") print_rsp_type(ri) cw.nl() @@ -2456,7 +2455,7 @@ def main(): cw.p('/* Common nested types */') for attr_set, struct in parsed.pure_nested_structs.items(): - ri = RenderInfo(cw, parsed, args.mode, "", "", "", attr_set) + ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set) free_rsp_nested(ri, struct) if struct.request: @@ -2468,7 +2467,7 @@ def main(): cw.p(f"/* ============== {op.enum_name} ============== */") if 'do' in op and 'event' not in op: cw.p(f"/* {op.enum_name} - do */") - ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do") + ri = RenderInfo(cw, parsed, args.mode, op, "do") print_req_free(ri) print_rsp_free(ri) parse_rsp_msg(ri) @@ -2477,7 +2476,7 @@ def main(): if 'dump' in op: cw.p(f"/* {op.enum_name} - dump */") - ri = RenderInfo(cw, parsed, args.mode, op, op_name, "dump") + ri = RenderInfo(cw, parsed, args.mode, op, "dump") if not ri.type_consistent: parse_rsp_msg(ri, deref=True) print_dump_type_free(ri) @@ -2486,7 +2485,7 @@ def main(): if op.has_ntf: cw.p(f"/* {op.enum_name} - notify */") - ri = RenderInfo(cw, parsed, args.mode, op, op_name, 'notify') + ri = RenderInfo(cw, parsed, args.mode, op, 'notify') if not ri.type_consistent: raise Exception(f'Only notifications with consistent types supported ({op.name})') print_ntf_type_free(ri) @@ -2495,10 +2494,10 @@ def main(): if 'event' in op: cw.p(f"/* {op.enum_name} - event */") - ri = RenderInfo(cw, parsed, args.mode, op, op_name, "do") + ri = RenderInfo(cw, parsed, args.mode, op, "do") parse_rsp_msg(ri) - ri = RenderInfo(cw, parsed, args.mode, op, op_name, "event") + ri = RenderInfo(cw, parsed, args.mode, op, "event") print_ntf_type_free(ri) cw.nl() render_user_family(parsed, cw, False) -- cgit v1.2.3 From 76abff37f0d70066503747a76deb40b752fb23be Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 8 Jun 2023 14:12:00 -0700 Subject: tools: ynl-gen: support / skip pads on the way to kernel Kernel does not have padding requirements for 64b attrs. We can ignore pad attrs. Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index be860dee7239..7b051c00cfc3 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -227,12 +227,18 @@ class TypePad(Type): def _attr_typol(self): return '.type = YNL_PT_IGNORE, ' + def attr_put(self, ri, var): + pass + def attr_get(self, ri, var, first): pass def attr_policy(self, cw): pass + def setter(self, ri, space, direction, deref=False, ref=None): + pass + class TypeScalar(Type): def __init__(self, family, attr_set, attr, value): -- cgit v1.2.3 From 18a92b05425493c3d131c47689443d7ae860c986 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Wed, 8 Mar 2023 00:02:12 +0200 Subject: net/mlx5: Simplify unload all rep code Instead of using type specific iterators which are only used in one place just traverse the xarray. It will provide suitable ordering based on the vport numbers. This will also eliminate the need for changes here when new types are added. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Reviewed-by: Parav Pandit Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 48 +--------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index eafb098db6b0..625982454575 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -55,13 +55,6 @@ #define mlx5_esw_for_each_rep(esw, i, rep) \ xa_for_each(&((esw)->offloads.vport_reps), i, rep) -#define mlx5_esw_for_each_sf_rep(esw, i, rep) \ - xa_for_each_marked(&((esw)->offloads.vport_reps), i, rep, MLX5_ESW_VPT_SF) - -#define mlx5_esw_for_each_vf_rep(esw, index, rep) \ - mlx5_esw_for_each_entry_marked(&((esw)->offloads.vport_reps), index, \ - rep, (esw)->esw_funcs.num_vfs, MLX5_ESW_VPT_VF) - /* There are two match-all miss flows, one for unicast dst mac and * one for multicast. */ @@ -2191,18 +2184,6 @@ static int esw_offloads_start(struct mlx5_eswitch *esw, return 0; } -static void mlx5_esw_offloads_rep_mark_set(struct mlx5_eswitch *esw, - struct mlx5_eswitch_rep *rep, - xa_mark_t mark) -{ - bool mark_set; - - /* Copy the mark from vport to its rep */ - mark_set = xa_get_mark(&esw->vports, rep->vport, mark); - if (mark_set) - xa_set_mark(&esw->offloads.vport_reps, rep->vport, mark); -} - static int mlx5_esw_offloads_rep_init(struct mlx5_eswitch *esw, const struct mlx5_vport *vport) { struct mlx5_eswitch_rep *rep; @@ -2222,9 +2203,6 @@ static int mlx5_esw_offloads_rep_init(struct mlx5_eswitch *esw, const struct mlx if (err) goto insert_err; - mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_HOST_FN); - mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_VF); - mlx5_esw_offloads_rep_mark_set(esw, rep, MLX5_ESW_VPT_SF); return 0; insert_err: @@ -2365,37 +2343,13 @@ static void __esw_offloads_unload_rep(struct mlx5_eswitch *esw, esw->offloads.rep_ops[rep_type]->unload(rep); } -static void __unload_reps_sf_vport(struct mlx5_eswitch *esw, u8 rep_type) -{ - struct mlx5_eswitch_rep *rep; - unsigned long i; - - mlx5_esw_for_each_sf_rep(esw, i, rep) - __esw_offloads_unload_rep(esw, rep, rep_type); -} - static void __unload_reps_all_vport(struct mlx5_eswitch *esw, u8 rep_type) { struct mlx5_eswitch_rep *rep; unsigned long i; - __unload_reps_sf_vport(esw, rep_type); - - mlx5_esw_for_each_vf_rep(esw, i, rep) - __esw_offloads_unload_rep(esw, rep, rep_type); - - if (mlx5_ecpf_vport_exists(esw->dev)) { - rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_ECPF); - __esw_offloads_unload_rep(esw, rep, rep_type); - } - - if (mlx5_core_is_ecpf_esw_manager(esw->dev)) { - rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_PF); + mlx5_esw_for_each_rep(esw, i, rep) __esw_offloads_unload_rep(esw, rep, rep_type); - } - - rep = mlx5_eswitch_get_rep(esw, MLX5_VPORT_UPLINK); - __esw_offloads_unload_rep(esw, rep, rep_type); } int mlx5_esw_offloads_rep_load(struct mlx5_eswitch *esw, u16 vport_num) -- cgit v1.2.3 From 93b36d0f2892357906f1058778c9188ff857baa1 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 00:27:21 +0200 Subject: net/mlx5: mlx5_ifc updates for embedded CPU SRIOV Add ec_vf_vport_base to HCA Capabilities 2. This indicates the base vport of embedded CPU virtual functions that are connected to the eswitch. Add ec_vf_function to query/set_hca_caps. If set this indicates accessing a virtual function on the embedded CPU by function ID. This should only be used with other_function set to 1. Signed-off-by: Daniel Jurgens Reviewed-by: Bodong Wang Reviewed-by: William Tu Signed-off-by: Saeed Mahameed --- include/linux/mlx5/mlx5_ifc.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index af3a92ad2e6b..1f4f62cb9f34 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1992,7 +1992,10 @@ struct mlx5_ifc_cmd_hca_cap_2_bits { u8 ts_cqe_metadata_size2wqe_counter[0x5]; u8 reserved_at_250[0x10]; - u8 reserved_at_260[0x5a0]; + u8 reserved_at_260[0x120]; + u8 reserved_at_380[0x10]; + u8 ec_vf_vport_base[0x10]; + u8 reserved_at_3a0[0x460]; }; enum mlx5_ifc_flow_destination_type { @@ -4805,7 +4808,8 @@ struct mlx5_ifc_set_hca_cap_in_bits { u8 op_mod[0x10]; u8 other_function[0x1]; - u8 reserved_at_41[0xf]; + u8 ec_vf_function[0x1]; + u8 reserved_at_42[0xe]; u8 function_id[0x10]; u8 reserved_at_60[0x20]; @@ -5956,7 +5960,8 @@ struct mlx5_ifc_query_hca_cap_in_bits { u8 op_mod[0x10]; u8 other_function[0x1]; - u8 reserved_at_41[0xf]; + u8 ec_vf_function[0x1]; + u8 reserved_at_42[0xe]; u8 function_id[0x10]; u8 reserved_at_60[0x20]; -- cgit v1.2.3 From dc13180824b78e1e4e7ae1ce22160ae8e5fb858e Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 19:36:14 +0200 Subject: net/mlx5: Enable devlink port for embedded cpu VF vports Enable creation of a devlink port for EC VF vports. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/esw/devlink_port.c | 8 +++++++- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 20 ++++++++++++++++++++ include/linux/mlx5/driver.h | 6 ++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c index f370f67d9e33..af779c700278 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/devlink_port.c @@ -18,7 +18,8 @@ static bool mlx5_esw_devlink_port_supported(struct mlx5_eswitch *esw, u16 vport_ { return vport_num == MLX5_VPORT_UPLINK || (mlx5_core_is_ecpf(esw->dev) && vport_num == MLX5_VPORT_PF) || - mlx5_eswitch_is_vf_vport(esw, vport_num); + mlx5_eswitch_is_vf_vport(esw, vport_num) || + mlx5_core_is_ec_vf_vport(esw->dev, vport_num); } static struct devlink_port *mlx5_esw_dl_port_alloc(struct mlx5_eswitch *esw, u16 vport_num) @@ -56,6 +57,11 @@ static struct devlink_port *mlx5_esw_dl_port_alloc(struct mlx5_eswitch *esw, u16 dl_port->attrs.switch_id.id_len = ppid.id_len; devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum, vport_num - 1, external); + } else if (mlx5_core_is_ec_vf_vport(esw->dev, vport_num)) { + memcpy(dl_port->attrs.switch_id.id, ppid.id, ppid.id_len); + dl_port->attrs.switch_id.id_len = ppid.id_len; + devlink_port_attrs_pci_vf_set(dl_port, controller_num, pfnum, + vport_num - 1, false); } return dl_port; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 1d879374acaa..0e7b5c6e4020 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -343,4 +343,24 @@ bool mlx5_rdma_supported(struct mlx5_core_dev *dev); bool mlx5_vnet_supported(struct mlx5_core_dev *dev); bool mlx5_same_hw_devs(struct mlx5_core_dev *dev, struct mlx5_core_dev *peer_dev); +static inline u16 mlx5_core_ec_vf_vport_base(const struct mlx5_core_dev *dev) +{ + return MLX5_CAP_GEN_2(dev, ec_vf_vport_base); +} + +static inline u16 mlx5_core_ec_sriov_enabled(const struct mlx5_core_dev *dev) +{ + return mlx5_core_is_ecpf(dev) && mlx5_core_ec_vf_vport_base(dev); +} + +static inline bool mlx5_core_is_ec_vf_vport(const struct mlx5_core_dev *dev, u16 vport_num) +{ + int base_vport = mlx5_core_ec_vf_vport_base(dev); + int max_vport = base_vport + mlx5_core_max_ec_vfs(dev); + + if (!mlx5_core_ec_sriov_enabled(dev)) + return false; + + return (vport_num >= base_vport && vport_num < max_vport); +} #endif /* __MLX5_CORE_H__ */ diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 9a744c48eec2..252b6a6965b8 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -474,6 +474,7 @@ struct mlx5_core_sriov { struct mlx5_vf_context *vfs_ctx; int num_vfs; u16 max_vfs; + u16 max_ec_vfs; }; struct mlx5_fc_pool { @@ -1244,6 +1245,11 @@ static inline u16 mlx5_core_max_vfs(const struct mlx5_core_dev *dev) return dev->priv.sriov.max_vfs; } +static inline u16 mlx5_core_max_ec_vfs(const struct mlx5_core_dev *dev) +{ + return dev->priv.sriov.max_ec_vfs; +} + static inline int mlx5_get_gid_table_len(u16 param) { if (param > 4) { -- cgit v1.2.3 From 9ac0b128248e19d06475f4592fe87f6ce18bc554 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 19:51:22 +0200 Subject: net/mlx5: Update vport caps query/set for EC VFs These functions are for query/set by vport, there was an underlying assumption that vport was equal to function ID. That's not the case for EC VF functions. Set the ec_vf_function bit accordingly. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 6 +++--- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 19 +++++++++++++++---- include/linux/mlx5/vport.h | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 0e7b5c6e4020..7ca0c7a547aa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -325,10 +325,10 @@ void mlx5_unload_one_devl_locked(struct mlx5_core_dev *dev, bool suspend); int mlx5_load_one(struct mlx5_core_dev *dev, bool recovery); int mlx5_load_one_devl_locked(struct mlx5_core_dev *dev, bool recovery); -int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap, u16 function_id, +int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap, u16 vport, u16 opmod); -#define mlx5_vport_get_other_func_general_cap(dev, fid, out) \ - mlx5_vport_get_other_func_cap(dev, fid, out, MLX5_CAP_GENERAL) +#define mlx5_vport_get_other_func_general_cap(dev, vport, out) \ + mlx5_vport_get_other_func_cap(dev, vport, out, MLX5_CAP_GENERAL) void mlx5_events_work_enqueue(struct mlx5_core_dev *dev, struct work_struct *work); static inline u32 mlx5_sriov_get_vf_total_msix(struct pci_dev *pdev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index bc66b078a8a1..6d3984dd5b21 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -1161,23 +1161,32 @@ u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev) } EXPORT_SYMBOL_GPL(mlx5_query_nic_system_image_guid); -int mlx5_vport_get_other_func_cap(struct mlx5_core_dev *dev, u16 function_id, void *out, +static int mlx5_vport_to_func_id(const struct mlx5_core_dev *dev, u16 vport, bool ec_vf_func) +{ + return ec_vf_func ? vport - mlx5_core_ec_vf_vport_base(dev) + : vport; +} + +int mlx5_vport_get_other_func_cap(struct mlx5_core_dev *dev, u16 vport, void *out, u16 opmod) { + bool ec_vf_func = mlx5_core_is_ec_vf_vport(dev, vport); u8 in[MLX5_ST_SZ_BYTES(query_hca_cap_in)] = {}; opmod = (opmod << 1) | (HCA_CAP_OPMOD_GET_MAX & 0x01); MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); MLX5_SET(query_hca_cap_in, in, op_mod, opmod); - MLX5_SET(query_hca_cap_in, in, function_id, function_id); + MLX5_SET(query_hca_cap_in, in, function_id, mlx5_vport_to_func_id(dev, vport, ec_vf_func)); MLX5_SET(query_hca_cap_in, in, other_function, true); + MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); return mlx5_cmd_exec_inout(dev, query_hca_cap, in, out); } EXPORT_SYMBOL_GPL(mlx5_vport_get_other_func_cap); int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap, - u16 function_id, u16 opmod) + u16 vport, u16 opmod) { + bool ec_vf_func = mlx5_core_is_ec_vf_vport(dev, vport); int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in); void *set_hca_cap; void *set_ctx; @@ -1191,8 +1200,10 @@ int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap MLX5_SET(set_hca_cap_in, set_ctx, op_mod, opmod << 1); set_hca_cap = MLX5_ADDR_OF(set_hca_cap_in, set_ctx, capability); memcpy(set_hca_cap, hca_cap, MLX5_ST_SZ_BYTES(cmd_hca_cap)); - MLX5_SET(set_hca_cap_in, set_ctx, function_id, function_id); + MLX5_SET(set_hca_cap_in, set_ctx, function_id, + mlx5_vport_to_func_id(dev, vport, ec_vf_func)); MLX5_SET(set_hca_cap_in, set_ctx, other_function, true); + MLX5_SET(set_hca_cap_in, set_ctx, ec_vf_function, ec_vf_func); ret = mlx5_cmd_exec_in(dev, set_hca_cap, set_ctx); kfree(set_ctx); diff --git a/include/linux/mlx5/vport.h b/include/linux/mlx5/vport.h index 7f31432f44c2..fbb9bf447889 100644 --- a/include/linux/mlx5/vport.h +++ b/include/linux/mlx5/vport.h @@ -132,6 +132,6 @@ int mlx5_nic_vport_affiliate_multiport(struct mlx5_core_dev *master_mdev, int mlx5_nic_vport_unaffiliate_multiport(struct mlx5_core_dev *port_mdev); u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev); -int mlx5_vport_get_other_func_cap(struct mlx5_core_dev *dev, u16 function_id, void *out, +int mlx5_vport_get_other_func_cap(struct mlx5_core_dev *dev, u16 vport, void *out, u16 opmod); #endif /* __MLX5_VPORT_H__ */ -- cgit v1.2.3 From a7719b29a82199b90ebbf355d3332e0fbfbf6045 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 21:24:55 +0200 Subject: net/mlx5: Add management of EC VF vports Add init, load, unload, and cleanup of the EC VF vports. This includes changes in how eswitch SRIOV is managed. Previous on an embedded CPU platform the number of VFs provided when enabling the eswitch was always 0, host VFs vports are handled in the eswitch functions change event handler. Now track the number of EC VFs as well, so they can be handled properly in the enable/disable flows. There are only 3 marks available for use in xarrays, all 3 were already in use for this use case. EC VF vports are in a known range so we can access them by index instead of marks. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 125 ++++++++++++++++++--- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 13 +++ .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 22 ++++ 3 files changed, 143 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index ecd8864d5d11..b33d852aae34 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1051,6 +1051,18 @@ static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw) } } +static void mlx5_eswitch_clear_ec_vf_vports_info(struct mlx5_eswitch *esw) +{ + struct mlx5_vport *vport; + unsigned long i; + + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, esw->esw_funcs.num_ec_vfs) { + memset(&vport->qos, 0, sizeof(vport->qos)); + memset(&vport->info, 0, sizeof(vport->info)); + vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO; + } +} + /* Public E-Switch API */ int mlx5_eswitch_load_vport(struct mlx5_eswitch *esw, u16 vport_num, enum mlx5_eswitch_vport_event enabled_events) @@ -1090,6 +1102,19 @@ void mlx5_eswitch_unload_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs) } } +static void mlx5_eswitch_unload_ec_vf_vports(struct mlx5_eswitch *esw, + u16 num_ec_vfs) +{ + struct mlx5_vport *vport; + unsigned long i; + + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, num_ec_vfs) { + if (!vport->enabled) + continue; + mlx5_eswitch_unload_vport(esw, vport->vport); + } +} + int mlx5_eswitch_load_vf_vports(struct mlx5_eswitch *esw, u16 num_vfs, enum mlx5_eswitch_vport_event enabled_events) { @@ -1110,6 +1135,26 @@ vf_err: return err; } +static int mlx5_eswitch_load_ec_vf_vports(struct mlx5_eswitch *esw, u16 num_ec_vfs, + enum mlx5_eswitch_vport_event enabled_events) +{ + struct mlx5_vport *vport; + unsigned long i; + int err; + + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, num_ec_vfs) { + err = mlx5_eswitch_load_vport(esw, vport->vport, enabled_events); + if (err) + goto vf_err; + } + + return 0; + +vf_err: + mlx5_eswitch_unload_ec_vf_vports(esw, num_ec_vfs); + return err; +} + static int host_pf_enable_hca(struct mlx5_core_dev *dev) { if (!mlx5_core_is_ecpf(dev)) @@ -1154,6 +1199,12 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, ret = mlx5_eswitch_load_vport(esw, MLX5_VPORT_ECPF, enabled_events); if (ret) goto ecpf_err; + if (mlx5_core_ec_sriov_enabled(esw->dev)) { + ret = mlx5_eswitch_load_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs, + enabled_events); + if (ret) + goto ec_vf_err; + } } /* Enable VF vports */ @@ -1164,6 +1215,9 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, return 0; vf_err: + if (mlx5_core_ec_sriov_enabled(esw->dev)) + mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs); +ec_vf_err: if (mlx5_ecpf_vport_exists(esw->dev)) mlx5_eswitch_unload_vport(esw, MLX5_VPORT_ECPF); ecpf_err: @@ -1180,8 +1234,11 @@ void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw) { mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs); - if (mlx5_ecpf_vport_exists(esw->dev)) + if (mlx5_ecpf_vport_exists(esw->dev)) { + if (mlx5_core_ec_sriov_enabled(esw->dev)) + mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_vfs); mlx5_eswitch_unload_vport(esw, MLX5_VPORT_ECPF); + } host_pf_disable_hca(esw->dev); mlx5_eswitch_unload_vport(esw, MLX5_VPORT_PF); @@ -1225,6 +1282,9 @@ mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, int num_vfs) esw->esw_funcs.num_vfs = MLX5_GET(query_esw_functions_out, out, host_params_context.host_num_of_vfs); + if (mlx5_core_ec_sriov_enabled(esw->dev)) + esw->esw_funcs.num_ec_vfs = num_vfs; + kvfree(out); } @@ -1332,9 +1392,9 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs) mlx5_eswitch_event_handlers_register(esw); - esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), active vports(%d)\n", + esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n", esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS", - esw->esw_funcs.num_vfs, esw->enabled_vports); + esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports); mlx5_esw_mode_change_notify(esw, esw->mode); @@ -1356,7 +1416,7 @@ abort: int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs) { bool toggle_lag; - int ret; + int ret = 0; if (!mlx5_esw_allowed(esw)) return 0; @@ -1376,10 +1436,21 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs) vport_events = (esw->mode == MLX5_ESWITCH_LEGACY) ? MLX5_LEGACY_SRIOV_VPORT_EVENTS : MLX5_VPORT_UC_ADDR_CHANGE; - ret = mlx5_eswitch_load_vf_vports(esw, num_vfs, vport_events); - if (!ret) - esw->esw_funcs.num_vfs = num_vfs; + /* If this is the ECPF the number of host VFs is managed via the + * eswitch function change event handler, and any num_vfs provided + * here are intended to be EC VFs. + */ + if (!mlx5_core_is_ecpf(esw->dev)) { + ret = mlx5_eswitch_load_vf_vports(esw, num_vfs, vport_events); + if (!ret) + esw->esw_funcs.num_vfs = num_vfs; + } else if (mlx5_core_ec_sriov_enabled(esw->dev)) { + ret = mlx5_eswitch_load_ec_vf_vports(esw, num_vfs, vport_events); + if (!ret) + esw->esw_funcs.num_ec_vfs = num_vfs; + } } + up_write(&esw->mode_lock); if (toggle_lag) @@ -1399,16 +1470,22 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) /* If driver is unloaded, this function is called twice by remove_one() * and mlx5_unload(). Prevent the second call. */ - if (!esw->esw_funcs.num_vfs && !clear_vf) + if (!esw->esw_funcs.num_vfs && !esw->esw_funcs.num_ec_vfs && !clear_vf) goto unlock; - esw_info(esw->dev, "Unload vfs: mode(%s), nvfs(%d), active vports(%d)\n", + esw_info(esw->dev, "Unload vfs: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n", esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS", - esw->esw_funcs.num_vfs, esw->enabled_vports); - - mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs); - if (clear_vf) - mlx5_eswitch_clear_vf_vports_info(esw); + esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports); + + if (!mlx5_core_is_ecpf(esw->dev)) { + mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs); + if (clear_vf) + mlx5_eswitch_clear_vf_vports_info(esw); + } else if (mlx5_core_ec_sriov_enabled(esw->dev)) { + mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs); + if (clear_vf) + mlx5_eswitch_clear_ec_vf_vports_info(esw); + } if (esw->mode == MLX5_ESWITCH_OFFLOADS) { struct devlink *devlink = priv_to_devlink(esw->dev); @@ -1419,7 +1496,10 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) if (esw->mode == MLX5_ESWITCH_LEGACY) mlx5_eswitch_disable_locked(esw); - esw->esw_funcs.num_vfs = 0; + if (!mlx5_core_is_ecpf(esw->dev)) + esw->esw_funcs.num_vfs = 0; + else + esw->esw_funcs.num_ec_vfs = 0; unlock: up_write(&esw->mode_lock); @@ -1439,9 +1519,9 @@ void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw) mlx5_eswitch_event_handlers_unregister(esw); - esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n", + esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), necvfs(%d), active vports(%d)\n", esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS", - esw->esw_funcs.num_vfs, esw->enabled_vports); + esw->esw_funcs.num_vfs, esw->esw_funcs.num_ec_vfs, esw->enabled_vports); if (esw->fdb_table.flags & MLX5_ESW_FDB_CREATED) { esw->fdb_table.flags &= ~MLX5_ESW_FDB_CREATED; @@ -1601,6 +1681,17 @@ static int mlx5_esw_vports_init(struct mlx5_eswitch *esw) idx++; } + if (mlx5_core_ec_sriov_enabled(esw->dev)) { + int ec_vf_base_num = mlx5_core_ec_vf_vport_base(dev); + + for (i = 0; i < mlx5_core_max_ec_vfs(esw->dev); i++) { + err = mlx5_esw_vport_alloc(esw, idx, ec_vf_base_num + i); + if (err) + goto err; + idx++; + } + } + if (mlx5_ecpf_vport_exists(dev) || mlx5_core_is_ecpf_esw_manager(dev)) { err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_ECPF); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index d3608f198e0a..266b60fefe25 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -289,6 +289,7 @@ struct mlx5_host_work { struct mlx5_esw_functions { struct mlx5_nb nb; u16 num_vfs; + u16 num_ec_vfs; }; enum { @@ -654,6 +655,18 @@ void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw); #define mlx5_esw_for_each_host_func_vport(esw, index, vport, last) \ mlx5_esw_for_each_vport_marked(esw, index, vport, last, MLX5_ESW_VPT_HOST_FN) +/* This macro should only be used if EC SRIOV is enabled. + * + * Because there were no more marks available on the xarray this uses a + * for_each_range approach. The range is only valid when EC SRIOV is enabled + */ +#define mlx5_esw_for_each_ec_vf_vport(esw, index, vport, last) \ + xa_for_each_range(&((esw)->vports), \ + index, \ + vport, \ + MLX5_CAP_GEN_2((esw->dev), ec_vf_vport_base), \ + (last) - 1) + struct mlx5_eswitch *mlx5_devlink_eswitch_get(struct devlink *devlink); struct mlx5_vport *__must_check mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 625982454575..68798aed792f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -3287,6 +3287,9 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) /* Representor will control the vport link state */ mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) vport->info.link_state = MLX5_VPORT_ADMIN_STATE_DOWN; + if (mlx5_core_ec_sriov_enabled(esw->dev)) + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, esw->esw_funcs.num_ec_vfs) + vport->info.link_state = MLX5_VPORT_ADMIN_STATE_DOWN; /* Uplink vport rep must load first. */ err = esw_offloads_load_rep(esw, MLX5_VPORT_UPLINK); @@ -3524,8 +3527,27 @@ static int mlx5_esw_vports_inline_set(struct mlx5_eswitch *esw, u8 mlx5_mode, goto revert_inline_mode; } } + if (mlx5_core_ec_sriov_enabled(esw->dev)) { + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, esw->esw_funcs.num_ec_vfs) { + err = mlx5_modify_nic_vport_min_inline(dev, vport->vport, mlx5_mode); + if (err) { + err_vport_num = vport->vport; + NL_SET_ERR_MSG_MOD(extack, + "Failed to set min inline on vport"); + goto revert_ec_vf_inline_mode; + } + } + } return 0; +revert_ec_vf_inline_mode: + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, esw->esw_funcs.num_ec_vfs) { + if (vport->vport == err_vport_num) + break; + mlx5_modify_nic_vport_min_inline(dev, + vport->vport, + esw->offloads.inline_mode); + } revert_inline_mode: mlx5_esw_for_each_host_func_vport(esw, i, vport, esw->esw_funcs.num_vfs) { if (vport->vport == err_vport_num) -- cgit v1.2.3 From fa3c73eee641cf76bc232373303aa51a1cad8b8e Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 21:36:39 +0200 Subject: net/mlx5: Add/remove peer miss rules for EC VFs Add and remove the peer miss rules for EC VFs. It's possible that there are different amounts of total VFs per function so only create rules for the minimum number of max VFs. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 68798aed792f..fdf482f6fb34 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1125,11 +1125,32 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw, flows[vport->index] = flow; } + if (mlx5_core_ec_sriov_enabled(esw->dev)) { + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, mlx5_core_max_ec_vfs(esw->dev)) { + if (i >= mlx5_core_max_ec_vfs(peer_dev)) + break; + esw_set_peer_miss_rule_source_port(esw, peer_dev->priv.eswitch, + spec, vport->vport); + flow = mlx5_add_flow_rules(esw->fdb_table.offloads.slow_fdb, + spec, &flow_act, &dest, 1); + if (IS_ERR(flow)) { + err = PTR_ERR(flow); + goto add_ec_vf_flow_err; + } + flows[vport->index] = flow; + } + } esw->fdb_table.offloads.peer_miss_rules[mlx5_get_dev_index(peer_dev)] = flows; kvfree(spec); return 0; +add_ec_vf_flow_err: + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, mlx5_core_max_ec_vfs(esw->dev)) { + if (!flows[vport->index]) + continue; + mlx5_del_flow_rules(flows[vport->index]); + } add_vf_flow_err: mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev)) { if (!flows[vport->index]) @@ -1162,6 +1183,17 @@ static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw, flows = esw->fdb_table.offloads.peer_miss_rules[mlx5_get_dev_index(peer_dev)]; + if (mlx5_core_ec_sriov_enabled(esw->dev)) { + mlx5_esw_for_each_ec_vf_vport(esw, i, vport, mlx5_core_max_ec_vfs(esw->dev)) { + /* The flow for a particular vport could be NULL if the other ECPF + * has fewer or no VFs enabled + */ + if (!flows[vport->index]) + continue; + mlx5_del_flow_rules(flows[vport->index]); + } + } + mlx5_esw_for_each_vf_vport(esw, i, vport, mlx5_core_max_vfs(esw->dev)) mlx5_del_flow_rules(flows[vport->index]); -- cgit v1.2.3 From 395ccd6eb49a12b021ac5deaa56e6b0b8f93241b Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 00:53:21 +0200 Subject: net/mlx5: Add new page type for EC VF pages When the embedded cpu supports SRIOV it can be enabled and disabled independently from the host SRIOV. Track the pages separately so we can properly wait for returned VF pages. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/debugfs.c | 1 + drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c | 11 ++++++++++- include/linux/mlx5/driver.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c index bb95b40d25eb..fc13b41cc9b2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c @@ -246,6 +246,7 @@ void mlx5_pages_debugfs_init(struct mlx5_core_dev *dev) debugfs_create_u32("fw_pages_total", 0400, pages, &dev->priv.fw_pages); debugfs_create_u32("fw_pages_vfs", 0400, pages, &dev->priv.page_counters[MLX5_VF]); + debugfs_create_u32("fw_pages_ec_vfs", 0400, pages, &dev->priv.page_counters[MLX5_EC_VF]); debugfs_create_u32("fw_pages_sfs", 0400, pages, &dev->priv.page_counters[MLX5_SF]); debugfs_create_u32("fw_pages_host_pf", 0400, pages, &dev->priv.page_counters[MLX5_HOST_PF]); debugfs_create_u32("fw_pages_alloc_failed", 0400, pages, &dev->priv.fw_pages_alloc_failed); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index 95dc67fb3001..dcf58efac159 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -79,7 +79,13 @@ static u16 func_id_to_type(struct mlx5_core_dev *dev, u16 func_id, bool ec_funct if (!func_id) return mlx5_core_is_ecpf(dev) && !ec_function ? MLX5_HOST_PF : MLX5_PF; - return func_id <= mlx5_core_max_vfs(dev) ? MLX5_VF : MLX5_SF; + if (func_id <= max(mlx5_core_max_vfs(dev), mlx5_core_max_ec_vfs(dev))) { + if (ec_function) + return MLX5_EC_VF; + else + return MLX5_VF; + } + return MLX5_SF; } static u32 mlx5_get_ec_function(u32 function) @@ -730,6 +736,9 @@ int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev) WARN(dev->priv.page_counters[MLX5_HOST_PF], "External host PF FW pages counter is %d after reclaiming all pages\n", dev->priv.page_counters[MLX5_HOST_PF]); + WARN(dev->priv.page_counters[MLX5_EC_VF], + "EC VFs FW pages counter is %d after reclaiming all pages\n", + dev->priv.page_counters[MLX5_EC_VF]); return 0; } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 252b6a6965b8..18a608a1f567 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -581,6 +581,7 @@ enum mlx5_func_type { MLX5_VF, MLX5_SF, MLX5_HOST_PF, + MLX5_EC_VF, MLX5_FUNC_TYPE_NUM, }; -- cgit v1.2.3 From 2ee3db806e851b9f3bfc46a1004a1ccee180b0a8 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 19:06:58 +0200 Subject: net/mlx5: Use correct vport when restoring GUIDs Prior to enabling EC VF functionality the vport number and function ID were always the same. That's not the case now. Use the correct vport number to modify the HCA vport context. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index f07d00929162..c2463a1d7035 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -37,7 +37,7 @@ #include "mlx5_irq.h" #include "eswitch.h" -static int sriov_restore_guids(struct mlx5_core_dev *dev, int vf) +static int sriov_restore_guids(struct mlx5_core_dev *dev, int vf, u16 func_id) { struct mlx5_core_sriov *sriov = &dev->priv.sriov; struct mlx5_hca_vport_context *in; @@ -59,7 +59,7 @@ static int sriov_restore_guids(struct mlx5_core_dev *dev, int vf) !!(in->node_guid) * MLX5_HCA_VPORT_SEL_NODE_GUID | !!(in->policy) * MLX5_HCA_VPORT_SEL_STATE_POLICY; - err = mlx5_core_modify_hca_vport_context(dev, 1, 1, vf + 1, in); + err = mlx5_core_modify_hca_vport_context(dev, 1, 1, func_id, in); if (err) mlx5_core_warn(dev, "modify vport context failed, unable to restore VF %d settings\n", vf); @@ -73,6 +73,7 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) { struct mlx5_core_sriov *sriov = &dev->priv.sriov; int err, vf, num_msix_count; + int vport_num; err = mlx5_eswitch_enable(dev->priv.eswitch, num_vfs); if (err) { @@ -104,7 +105,10 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) sriov->vfs_ctx[vf].enabled = 1; if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_IB) { - err = sriov_restore_guids(dev, vf); + vport_num = mlx5_core_ec_sriov_enabled(dev) ? + mlx5_core_ec_vf_vport_base(dev) + vf + : vf + 1; + err = sriov_restore_guids(dev, vf, vport_num); if (err) { mlx5_core_warn(dev, "failed to restore VF %d settings, err %d\n", -- cgit v1.2.3 From 42a84a430931afe2ccf31a6910dec86e87de5d2a Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 19:13:43 +0200 Subject: net/mlx5: Query correct caps for min msix vectors The VFs on the host and the embedded CPU platform share function numbers. Set the ec_vf_function field to query the caps for the correct function. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c index 843da89a9035..b2dbae763ca6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c @@ -41,6 +41,15 @@ struct mlx5_irq_table { struct mlx5_irq_pool *sf_comp_pool; }; +static int mlx5_core_func_to_vport(const struct mlx5_core_dev *dev, + int func, + bool ec_vf_func) +{ + if (!ec_vf_func) + return func; + return mlx5_core_ec_vf_vport_base(dev) + func - 1; +} + /** * mlx5_get_default_msix_vec_count - Get the default number of MSI-X vectors * to be ssigned to each VF. @@ -79,6 +88,8 @@ int mlx5_set_msix_vec_count(struct mlx5_core_dev *dev, int function_id, int set_sz = MLX5_ST_SZ_BYTES(set_hca_cap_in); void *hca_cap = NULL, *query_cap = NULL, *cap; int num_vf_msix, min_msix, max_msix; + bool ec_vf_function; + int vport; int ret; num_vf_msix = MLX5_CAP_GEN_MAX(dev, num_total_dynamic_vf_msix); @@ -104,7 +115,9 @@ int mlx5_set_msix_vec_count(struct mlx5_core_dev *dev, int function_id, goto out; } - ret = mlx5_vport_get_other_func_general_cap(dev, function_id, query_cap); + ec_vf_function = mlx5_core_ec_sriov_enabled(dev); + vport = mlx5_core_func_to_vport(dev, function_id, ec_vf_function); + ret = mlx5_vport_get_other_func_general_cap(dev, vport, query_cap); if (ret) goto out; @@ -115,6 +128,7 @@ int mlx5_set_msix_vec_count(struct mlx5_core_dev *dev, int function_id, MLX5_SET(set_hca_cap_in, hca_cap, opcode, MLX5_CMD_OP_SET_HCA_CAP); MLX5_SET(set_hca_cap_in, hca_cap, other_function, 1); + MLX5_SET(set_hca_cap_in, hca_cap, ec_vf_function, ec_vf_function); MLX5_SET(set_hca_cap_in, hca_cap, function_id, function_id); MLX5_SET(set_hca_cap_in, hca_cap, op_mod, -- cgit v1.2.3 From 6d98f314bfca10cebf66e42573c4b362ed2ee17c Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 7 Mar 2023 18:52:29 +0200 Subject: net/mlx5: Update SRIOV enable/disable to handle EC/VFs Previously on the embedded CPU platform SRIOV was never enabled/disabled via mlx5_core_sriov_configure. Host VF updates are provided by an event handler. Now in the disable flow it must be known if this is a disable due to driver unload or SRIOV detach, or if the user updated the number of VFs. If due to change in the number of VFs only wait for the pages of ECVFs. Signed-off-by: Daniel Jurgens Reviewed-by: William Tu Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 2 +- .../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 35 +++++++++++++++++----- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index d6ee016deae1..fed8b48a5b20 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1809,7 +1809,7 @@ static void remove_one(struct pci_dev *pdev) mlx5_drain_fw_reset(dev); mlx5_drain_health_wq(dev); devlink_unregister(devlink); - mlx5_sriov_disable(pdev); + mlx5_sriov_disable(pdev, false); mlx5_thermal_uninit(dev); mlx5_crdump_disable(dev); mlx5_uninit_one(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 7ca0c7a547aa..7a5f04082058 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -195,7 +195,7 @@ void mlx5_sriov_cleanup(struct mlx5_core_dev *dev); int mlx5_sriov_attach(struct mlx5_core_dev *dev); void mlx5_sriov_detach(struct mlx5_core_dev *dev); int mlx5_core_sriov_configure(struct pci_dev *dev, int num_vfs); -void mlx5_sriov_disable(struct pci_dev *pdev); +void mlx5_sriov_disable(struct pci_dev *pdev, bool num_vf_change); int mlx5_core_sriov_set_msix_vec_count(struct pci_dev *vf, int msix_vec_count); int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id); int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index c2463a1d7035..b73583b0a0fe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -123,9 +123,11 @@ static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs) } static void -mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf) +mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf, bool num_vf_change) { struct mlx5_core_sriov *sriov = &dev->priv.sriov; + bool wait_for_ec_vf_pages = true; + bool wait_for_vf_pages = true; int err; int vf; @@ -147,11 +149,30 @@ mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf) mlx5_eswitch_disable_sriov(dev->priv.eswitch, clear_vf); + /* There are a number of scenarios when SRIOV is being disabled: + * 1. VFs or ECVFs had been created, and now set back to 0 (num_vf_change == true). + * - If EC SRIOV is enabled then this flow is happening on the + * embedded platform, wait for only EC VF pages. + * - If EC SRIOV is not enabled this flow is happening on non-embedded + * platform, wait for the VF pages. + * + * 2. The driver is being unloaded. In this case wait for all pages. + */ + if (num_vf_change) { + if (mlx5_core_ec_sriov_enabled(dev)) + wait_for_vf_pages = false; + else + wait_for_ec_vf_pages = false; + } + + if (wait_for_ec_vf_pages && mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_EC_VF])) + mlx5_core_warn(dev, "timeout reclaiming EC VFs pages\n"); + /* For ECPFs, skip waiting for host VF pages until ECPF is destroyed */ if (mlx5_core_is_ecpf(dev)) return; - if (mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_VF])) + if (wait_for_vf_pages && mlx5_wait_for_pages(dev, &dev->priv.page_counters[MLX5_VF])) mlx5_core_warn(dev, "timeout reclaiming VFs pages\n"); } @@ -172,12 +193,12 @@ static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs) err = pci_enable_sriov(pdev, num_vfs); if (err) { mlx5_core_warn(dev, "pci_enable_sriov failed : %d\n", err); - mlx5_device_disable_sriov(dev, num_vfs, true); + mlx5_device_disable_sriov(dev, num_vfs, true, true); } return err; } -void mlx5_sriov_disable(struct pci_dev *pdev) +void mlx5_sriov_disable(struct pci_dev *pdev, bool num_vf_change) { struct mlx5_core_dev *dev = pci_get_drvdata(pdev); struct devlink *devlink = priv_to_devlink(dev); @@ -185,7 +206,7 @@ void mlx5_sriov_disable(struct pci_dev *pdev) pci_disable_sriov(pdev); devl_lock(devlink); - mlx5_device_disable_sriov(dev, num_vfs, true); + mlx5_device_disable_sriov(dev, num_vfs, true, num_vf_change); devl_unlock(devlink); } @@ -200,7 +221,7 @@ int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs) if (num_vfs) err = mlx5_sriov_enable(pdev, num_vfs); else - mlx5_sriov_disable(pdev); + mlx5_sriov_disable(pdev, true); if (!err) sriov->num_vfs = num_vfs; @@ -245,7 +266,7 @@ void mlx5_sriov_detach(struct mlx5_core_dev *dev) if (!mlx5_core_is_pf(dev)) return; - mlx5_device_disable_sriov(dev, pci_num_vf(dev->pdev), false); + mlx5_device_disable_sriov(dev, pci_num_vf(dev->pdev), false, false); } static u16 mlx5_get_max_vfs(struct mlx5_core_dev *dev) -- cgit v1.2.3 From 7057fe561988effa0b044b99262bb3712a5892c0 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Wed, 15 Mar 2023 17:29:13 +0200 Subject: net/mlx5: Set max number of embedded CPU VFs Set the maximum number of embedded cpu VF functions available. Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index b73583b0a0fe..4e42a3b9b8ee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -305,6 +305,7 @@ int mlx5_sriov_init(struct mlx5_core_dev *dev) total_vfs = pci_sriov_get_totalvfs(pdev); sriov->max_vfs = mlx5_get_max_vfs(dev); sriov->num_vfs = pci_num_vf(pdev); + sriov->max_ec_vfs = mlx5_core_ec_sriov_enabled(dev) ? pci_sriov_get_totalvfs(dev->pdev) : 0; sriov->vfs_ctx = kcalloc(total_vfs, sizeof(*sriov->vfs_ctx), GFP_KERNEL); if (!sriov->vfs_ctx) return -ENOMEM; -- cgit v1.2.3 From 2059cf51f318681a4cdd3eb1a01a2d62b6a9c442 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Wed, 3 May 2023 12:08:48 +0300 Subject: net/mlx5: Split function_setup() to enable and open functions mlx5_cmd_init_hca() is taking ~0.2 seconds. In case of a user who desire to disable some of the SF aux devices, and with large scale-1K SFs for example, this user will waste more than 3 minutes on mlx5_cmd_init_hca() which isn't needed at this stage. Downstream patch will change SFs which are probe over the E-switch, local SFs, to be probed without any aux dev. In order to support this, split function_setup() to avoid executing mlx5_cmd_init_hca(). Signed-off-by: Shay Drory Reviewed-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 83 ++++++++++++++++++-------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index fed8b48a5b20..0faae77d84e6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1118,7 +1118,7 @@ static void mlx5_cleanup_once(struct mlx5_core_dev *dev) mlx5_devcom_unregister_device(dev->priv.devcom); } -static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot, u64 timeout) +static int mlx5_function_enable(struct mlx5_core_dev *dev, bool boot, u64 timeout) { int err; @@ -1183,28 +1183,56 @@ static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot, u64 timeout goto reclaim_boot_pages; } + return 0; + +reclaim_boot_pages: + mlx5_reclaim_startup_pages(dev); +err_disable_hca: + mlx5_core_disable_hca(dev, 0); +stop_health_poll: + mlx5_stop_health_poll(dev, boot); +err_cmd_cleanup: + mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_DOWN); + mlx5_cmd_cleanup(dev); + + return err; +} + +static void mlx5_function_disable(struct mlx5_core_dev *dev, bool boot) +{ + mlx5_reclaim_startup_pages(dev); + mlx5_core_disable_hca(dev, 0); + mlx5_stop_health_poll(dev, boot); + mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_DOWN); + mlx5_cmd_cleanup(dev); +} + +static int mlx5_function_open(struct mlx5_core_dev *dev) +{ + int err; + err = set_hca_ctrl(dev); if (err) { mlx5_core_err(dev, "set_hca_ctrl failed\n"); - goto reclaim_boot_pages; + return err; } err = set_hca_cap(dev); if (err) { mlx5_core_err(dev, "set_hca_cap failed\n"); - goto reclaim_boot_pages; + return err; } err = mlx5_satisfy_startup_pages(dev, 0); if (err) { mlx5_core_err(dev, "failed to allocate init pages\n"); - goto reclaim_boot_pages; + return err; } err = mlx5_cmd_init_hca(dev, sw_owner_id); if (err) { mlx5_core_err(dev, "init hca failed\n"); - goto reclaim_boot_pages; + return err; } mlx5_set_driver_version(dev); @@ -1212,26 +1240,13 @@ static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot, u64 timeout err = mlx5_query_hca_caps(dev); if (err) { mlx5_core_err(dev, "query hca failed\n"); - goto reclaim_boot_pages; + return err; } mlx5_start_health_fw_log_up(dev); - return 0; - -reclaim_boot_pages: - mlx5_reclaim_startup_pages(dev); -err_disable_hca: - mlx5_core_disable_hca(dev, 0); -stop_health_poll: - mlx5_stop_health_poll(dev, boot); -err_cmd_cleanup: - mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_DOWN); - mlx5_cmd_cleanup(dev); - - return err; } -static int mlx5_function_teardown(struct mlx5_core_dev *dev, bool boot) +static int mlx5_function_close(struct mlx5_core_dev *dev) { int err; @@ -1240,15 +1255,33 @@ static int mlx5_function_teardown(struct mlx5_core_dev *dev, bool boot) mlx5_core_err(dev, "tear_down_hca failed, skip cleanup\n"); return err; } - mlx5_reclaim_startup_pages(dev); - mlx5_core_disable_hca(dev, 0); - mlx5_stop_health_poll(dev, boot); - mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_DOWN); - mlx5_cmd_cleanup(dev); return 0; } +static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot, u64 timeout) +{ + int err; + + err = mlx5_function_enable(dev, boot, timeout); + if (err) + return err; + + err = mlx5_function_open(dev); + if (err) + mlx5_function_disable(dev, boot); + return err; +} + +static int mlx5_function_teardown(struct mlx5_core_dev *dev, bool boot) +{ + int err = mlx5_function_close(dev); + + if (!err) + mlx5_function_disable(dev, boot); + return err; +} + static int mlx5_load(struct mlx5_core_dev *dev) { int err; -- cgit v1.2.3 From 3f90840305e2b240749aec7dde23f5262e513641 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Wed, 17 May 2023 17:39:54 +0300 Subject: net/mlx5: Move esw multiport devlink param to eswitch code Move the param registration and handling code into the eswitch code as they are related to each other. No point in having the devlink param registration done in separate file. Signed-off-by: Shay Drory Reviewed-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 34 ---------------- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 49 ++++++++++++++++++++++- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 63635cc44479..27197acdb4d8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -7,7 +7,6 @@ #include "fw_reset.h" #include "fs_core.h" #include "eswitch.h" -#include "lag/lag.h" #include "esw/qos.h" #include "sf/dev/dev.h" #include "sf/sf.h" @@ -427,33 +426,6 @@ static int mlx5_devlink_large_group_num_validate(struct devlink *devlink, u32 id return 0; } - -static int mlx5_devlink_esw_multiport_set(struct devlink *devlink, u32 id, - struct devlink_param_gset_ctx *ctx) -{ - struct mlx5_core_dev *dev = devlink_priv(devlink); - - if (!MLX5_ESWITCH_MANAGER(dev)) - return -EOPNOTSUPP; - - if (ctx->val.vbool) - return mlx5_lag_mpesw_enable(dev); - - mlx5_lag_mpesw_disable(dev); - return 0; -} - -static int mlx5_devlink_esw_multiport_get(struct devlink *devlink, u32 id, - struct devlink_param_gset_ctx *ctx) -{ - struct mlx5_core_dev *dev = devlink_priv(devlink); - - if (!MLX5_ESWITCH_MANAGER(dev)) - return -EOPNOTSUPP; - - ctx->val.vbool = mlx5_lag_is_mpesw(dev); - return 0; -} #endif static int mlx5_devlink_eq_depth_validate(struct devlink *devlink, u32 id, @@ -527,12 +499,6 @@ static const struct devlink_param mlx5_devlink_params[] = { BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL, mlx5_devlink_large_group_num_validate), - DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_ESW_MULTIPORT, - "esw_multiport", DEVLINK_PARAM_TYPE_BOOL, - BIT(DEVLINK_PARAM_CMODE_RUNTIME), - mlx5_devlink_esw_multiport_get, - mlx5_devlink_esw_multiport_set, - NULL), #endif DEVLINK_PARAM_GENERIC(IO_EQ_SIZE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL, mlx5_devlink_eq_depth_validate), diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index b33d852aae34..2af9c4646bc7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -41,6 +41,7 @@ #include "esw/qos.h" #include "mlx5_core.h" #include "lib/eq.h" +#include "lag/lag.h" #include "eswitch.h" #include "fs_core.h" #include "devlink.h" @@ -1709,6 +1710,38 @@ err: return err; } +static int mlx5_devlink_esw_multiport_set(struct devlink *devlink, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct mlx5_core_dev *dev = devlink_priv(devlink); + + if (!MLX5_ESWITCH_MANAGER(dev)) + return -EOPNOTSUPP; + + if (ctx->val.vbool) + return mlx5_lag_mpesw_enable(dev); + + mlx5_lag_mpesw_disable(dev); + return 0; +} + +static int mlx5_devlink_esw_multiport_get(struct devlink *devlink, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct mlx5_core_dev *dev = devlink_priv(devlink); + + ctx->val.vbool = mlx5_lag_is_mpesw(dev); + return 0; +} + +static const struct devlink_param mlx5_eswitch_params[] = { + DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_ID_ESW_MULTIPORT, + "esw_multiport", DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + mlx5_devlink_esw_multiport_get, + mlx5_devlink_esw_multiport_set, NULL), +}; + int mlx5_eswitch_init(struct mlx5_core_dev *dev) { struct mlx5_eswitch *esw; @@ -1717,9 +1750,16 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) if (!MLX5_VPORT_MANAGER(dev) && !MLX5_ESWITCH_MANAGER(dev)) return 0; + err = devl_params_register(priv_to_devlink(dev), mlx5_eswitch_params, + ARRAY_SIZE(mlx5_eswitch_params)); + if (err) + return err; + esw = kzalloc(sizeof(*esw), GFP_KERNEL); - if (!esw) - return -ENOMEM; + if (!esw) { + err = -ENOMEM; + goto unregister_param; + } esw->dev = dev; esw->manager_vport = mlx5_eswitch_manager_vport(dev); @@ -1779,6 +1819,9 @@ abort: if (esw->work_queue) destroy_workqueue(esw->work_queue); kfree(esw); +unregister_param: + devl_params_unregister(priv_to_devlink(dev), mlx5_eswitch_params, + ARRAY_SIZE(mlx5_eswitch_params)); return err; } @@ -1802,6 +1845,8 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) esw_offloads_cleanup(esw); mlx5_esw_vports_cleanup(esw); kfree(esw); + devl_params_unregister(priv_to_devlink(esw->dev), mlx5_eswitch_params, + ARRAY_SIZE(mlx5_eswitch_params)); } /* Vport Administration */ -- cgit v1.2.3 From e71383fb9cd15a28d6c01d2c165a96f1c0bcf418 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Wed, 3 May 2023 14:18:23 +0300 Subject: net/mlx5: Light probe local SFs In case user wants to configure the SFs, for example: to use only vdpa functionality, he needs to fully probe a SF, configure what he wants, and afterward reload the SF. In order to save the time of the reload, local SFs will probe without any auxiliary sub-device, so that the SFs can be configured prior to its full probe. The defaults of the enable_* devlink params of these SFs are set to false. Usage example: Create SF: $ devlink port add pci/0000:08:00.0 flavour pcisf pfnum 0 sfnum 11 $ devlink port function set pci/0000:08:00.0/32768 \ hw_addr 00:00:00:00:00:11 state active Enable ETH auxiliary device: $ devlink dev param set auxiliary/mlx5_core.sf.1 \ name enable_eth value true cmode driverinit Now, in order to fully probe the SF, use devlink reload: $ devlink dev reload auxiliary/mlx5_core.sf.1 At this point the user have SF devlink instance with auxiliary device for the Ethernet functionality only. Signed-off-by: Shay Drory Reviewed-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/switchdev.rst | 20 ++++ drivers/net/ethernet/mellanox/mlx5/core/dev.c | 16 +++ drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 20 +++- drivers/net/ethernet/mellanox/mlx5/core/health.c | 24 ++-- drivers/net/ethernet/mellanox/mlx5/core/main.c | 124 +++++++++++++++++++-- .../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 7 ++ .../ethernet/mellanox/mlx5/core/sf/dev/driver.c | 15 ++- 7 files changed, 203 insertions(+), 23 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst index 01deedb71597..db62187eebce 100644 --- a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst +++ b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst @@ -45,6 +45,26 @@ Following bridge VLAN functions are supported by mlx5: Subfunction =========== +Subfunction which are spawned over the E-switch are created only with devlink +device, and by default all the SF auxiliary devices are disabled. +This will allow user to configure the SF before the SF have been fully probed, +which will save time. + +Usage example: +Create SF: +$ devlink port add pci/0000:08:00.0 flavour pcisf pfnum 0 sfnum 11 +$ devlink port function set pci/0000:08:00.0/32768 \ + hw_addr 00:00:00:00:00:11 state active + +Enable ETH auxiliary device: +$ devlink dev param set auxiliary/mlx5_core.sf.1 \ + name enable_eth value true cmode driverinit + +Now, in order to fully probe the SF, use devlink reload: +$ devlink dev reload auxiliary/mlx5_core.sf.1 + +mlx5 supports ETH,rdma and vdpa (vnet) auxiliary devices devlink params (see :ref:`Documentation/networking/devlink/devlink-params.rst`) + mlx5 supports subfunction management using devlink port (see :ref:`Documentation/networking/devlink/devlink-port.rst `) interface. A subfunction has its own function capabilities and its own resources. This diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index 1b33533b15de..617ac7e5d75c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -323,6 +323,18 @@ static void del_adev(struct auxiliary_device *adev) auxiliary_device_uninit(adev); } +void mlx5_dev_set_lightweight(struct mlx5_core_dev *dev) +{ + mutex_lock(&mlx5_intf_mutex); + dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV; + mutex_unlock(&mlx5_intf_mutex); +} + +bool mlx5_dev_is_lightweight(struct mlx5_core_dev *dev) +{ + return dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_ALL_ADEV; +} + int mlx5_attach_device(struct mlx5_core_dev *dev) { struct mlx5_priv *priv = &dev->priv; @@ -457,6 +469,10 @@ static int add_drivers(struct mlx5_core_dev *dev) if (priv->adev[i]) continue; + if (mlx5_adev_devices[i].is_enabled && + !(mlx5_adev_devices[i].is_enabled(dev))) + continue; + if (mlx5_adev_devices[i].is_supported) is_supported = mlx5_adev_devices[i].is_supported(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 27197acdb4d8..3d82ec890666 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -141,6 +141,13 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, bool sf_dev_allocated; int ret = 0; + if (mlx5_dev_is_lightweight(dev)) { + if (action != DEVLINK_RELOAD_ACTION_DRIVER_REINIT) + return -EOPNOTSUPP; + mlx5_unload_one_light(dev); + return 0; + } + sf_dev_allocated = mlx5_sf_dev_allocated(dev); if (sf_dev_allocated) { /* Reload results in deleting SF device which further results in @@ -193,6 +200,10 @@ static int mlx5_devlink_reload_up(struct devlink *devlink, enum devlink_reload_a *actions_performed = BIT(action); switch (action) { case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: + if (mlx5_dev_is_lightweight(dev)) { + mlx5_fw_reporters_create(dev); + return mlx5_init_one_devl_locked(dev); + } ret = mlx5_load_one_devl_locked(dev, false); break; case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: @@ -511,7 +522,7 @@ static void mlx5_devlink_set_params_init_values(struct devlink *devlink) struct mlx5_core_dev *dev = devlink_priv(devlink); union devlink_param_value value; - value.vbool = MLX5_CAP_GEN(dev, roce); + value.vbool = MLX5_CAP_GEN(dev, roce) && !mlx5_dev_is_lightweight(dev); devl_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, value); @@ -561,7 +572,7 @@ static int mlx5_devlink_eth_params_register(struct devlink *devlink) if (err) return err; - value.vbool = true; + value.vbool = !mlx5_dev_is_lightweight(dev); devl_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH, value); @@ -601,6 +612,7 @@ static const struct devlink_param mlx5_devlink_rdma_params[] = { static int mlx5_devlink_rdma_params_register(struct devlink *devlink) { + struct mlx5_core_dev *dev = devlink_priv(devlink); union devlink_param_value value; int err; @@ -612,7 +624,7 @@ static int mlx5_devlink_rdma_params_register(struct devlink *devlink) if (err) return err; - value.vbool = true; + value.vbool = !mlx5_dev_is_lightweight(dev); devl_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA, value); @@ -647,7 +659,7 @@ static int mlx5_devlink_vnet_params_register(struct devlink *devlink) if (err) return err; - value.vbool = true; + value.vbool = !mlx5_dev_is_lightweight(dev); devl_param_driverinit_value_set(devlink, DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET, value); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 871c32dda66e..210100a4064a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -719,7 +719,7 @@ static const struct devlink_health_reporter_ops mlx5_fw_fatal_reporter_ops = { #define MLX5_FW_REPORTER_VF_GRACEFUL_PERIOD 30000 #define MLX5_FW_REPORTER_DEFAULT_GRACEFUL_PERIOD MLX5_FW_REPORTER_VF_GRACEFUL_PERIOD -static void mlx5_fw_reporters_create(struct mlx5_core_dev *dev) +void mlx5_fw_reporters_create(struct mlx5_core_dev *dev) { struct mlx5_core_health *health = &dev->priv.health; struct devlink *devlink = priv_to_devlink(dev); @@ -735,17 +735,17 @@ static void mlx5_fw_reporters_create(struct mlx5_core_dev *dev) } health->fw_reporter = - devlink_health_reporter_create(devlink, &mlx5_fw_reporter_ops, - 0, dev); + devl_health_reporter_create(devlink, &mlx5_fw_reporter_ops, + 0, dev); if (IS_ERR(health->fw_reporter)) mlx5_core_warn(dev, "Failed to create fw reporter, err = %ld\n", PTR_ERR(health->fw_reporter)); health->fw_fatal_reporter = - devlink_health_reporter_create(devlink, - &mlx5_fw_fatal_reporter_ops, - grace_period, - dev); + devl_health_reporter_create(devlink, + &mlx5_fw_fatal_reporter_ops, + grace_period, + dev); if (IS_ERR(health->fw_fatal_reporter)) mlx5_core_warn(dev, "Failed to create fw fatal reporter, err = %ld\n", PTR_ERR(health->fw_fatal_reporter)); @@ -777,7 +777,8 @@ void mlx5_trigger_health_work(struct mlx5_core_dev *dev) { struct mlx5_core_health *health = &dev->priv.health; - queue_work(health->wq, &health->fatal_report_work); + if (!mlx5_dev_is_lightweight(dev)) + queue_work(health->wq, &health->fatal_report_work); } #define MLX5_MSEC_PER_HOUR (MSEC_PER_SEC * 60 * 60) @@ -905,10 +906,15 @@ void mlx5_health_cleanup(struct mlx5_core_dev *dev) int mlx5_health_init(struct mlx5_core_dev *dev) { + struct devlink *devlink = priv_to_devlink(dev); struct mlx5_core_health *health; char *name; - mlx5_fw_reporters_create(dev); + if (!mlx5_dev_is_lightweight(dev)) { + devl_lock(devlink); + mlx5_fw_reporters_create(dev); + devl_unlock(devlink); + } mlx5_reporter_vnic_create(dev); health = &dev->priv.health; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 0faae77d84e6..6fa314f8e5ee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1424,12 +1424,11 @@ static void mlx5_unload(struct mlx5_core_dev *dev) mlx5_put_uars_page(dev, dev->priv.uar); } -int mlx5_init_one(struct mlx5_core_dev *dev) +int mlx5_init_one_devl_locked(struct mlx5_core_dev *dev) { - struct devlink *devlink = priv_to_devlink(dev); + bool light_probe = mlx5_dev_is_lightweight(dev); int err = 0; - devl_lock(devlink); mutex_lock(&dev->intf_state_mutex); dev->state = MLX5_DEVICE_STATE_UP; @@ -1443,9 +1442,14 @@ int mlx5_init_one(struct mlx5_core_dev *dev) goto function_teardown; } - err = mlx5_devlink_params_register(priv_to_devlink(dev)); - if (err) - goto err_devlink_params_reg; + /* In case of light_probe, mlx5_devlink is already registered. + * Hence, don't register devlink again. + */ + if (!light_probe) { + err = mlx5_devlink_params_register(priv_to_devlink(dev)); + if (err) + goto err_devlink_params_reg; + } err = mlx5_load(dev); if (err) @@ -1458,14 +1462,14 @@ int mlx5_init_one(struct mlx5_core_dev *dev) goto err_register; mutex_unlock(&dev->intf_state_mutex); - devl_unlock(devlink); return 0; err_register: clear_bit(MLX5_INTERFACE_STATE_UP, &dev->intf_state); mlx5_unload(dev); err_load: - mlx5_devlink_params_unregister(priv_to_devlink(dev)); + if (!light_probe) + mlx5_devlink_params_unregister(priv_to_devlink(dev)); err_devlink_params_reg: mlx5_cleanup_once(dev); function_teardown: @@ -1473,6 +1477,16 @@ function_teardown: err_function: dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; mutex_unlock(&dev->intf_state_mutex); + return err; +} + +int mlx5_init_one(struct mlx5_core_dev *dev) +{ + struct devlink *devlink = priv_to_devlink(dev); + int err; + + devl_lock(devlink); + err = mlx5_init_one_devl_locked(dev); devl_unlock(devlink); return err; } @@ -1590,6 +1604,100 @@ void mlx5_unload_one(struct mlx5_core_dev *dev, bool suspend) devl_unlock(devlink); } +/* In case of light probe, we don't need a full query of hca_caps, but only the bellow caps. + * A full query of hca_caps will be done when the device will reload. + */ +static int mlx5_query_hca_caps_light(struct mlx5_core_dev *dev) +{ + int err; + + err = mlx5_core_get_caps(dev, MLX5_CAP_GENERAL); + if (err) + return err; + + if (MLX5_CAP_GEN(dev, eth_net_offloads)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_ETHERNET_OFFLOADS); + if (err) + return err; + } + + if (MLX5_CAP_GEN(dev, nic_flow_table) || + MLX5_CAP_GEN(dev, ipoib_enhanced_offloads)) { + err = mlx5_core_get_caps(dev, MLX5_CAP_FLOW_TABLE); + if (err) + return err; + } + + if (MLX5_CAP_GEN_64(dev, general_obj_types) & + MLX5_GENERAL_OBJ_TYPES_CAP_VIRTIO_NET_Q) { + err = mlx5_core_get_caps(dev, MLX5_CAP_VDPA_EMULATION); + if (err) + return err; + } + + return 0; +} + +int mlx5_init_one_light(struct mlx5_core_dev *dev) +{ + struct devlink *devlink = priv_to_devlink(dev); + int err; + + dev->state = MLX5_DEVICE_STATE_UP; + err = mlx5_function_enable(dev, true, mlx5_tout_ms(dev, FW_PRE_INIT_TIMEOUT)); + if (err) { + mlx5_core_warn(dev, "mlx5_function_enable err=%d\n", err); + goto out; + } + + err = mlx5_query_hca_caps_light(dev); + if (err) { + mlx5_core_warn(dev, "mlx5_query_hca_caps_light err=%d\n", err); + goto query_hca_caps_err; + } + + devl_lock(devlink); + err = mlx5_devlink_params_register(priv_to_devlink(dev)); + devl_unlock(devlink); + if (err) { + mlx5_core_warn(dev, "mlx5_devlink_param_reg err = %d\n", err); + goto query_hca_caps_err; + } + + return 0; + +query_hca_caps_err: + mlx5_function_disable(dev, true); +out: + dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; + return err; +} + +void mlx5_uninit_one_light(struct mlx5_core_dev *dev) +{ + struct devlink *devlink = priv_to_devlink(dev); + + devl_lock(devlink); + mlx5_devlink_params_unregister(priv_to_devlink(dev)); + devl_unlock(devlink); + if (dev->state != MLX5_DEVICE_STATE_UP) + return; + mlx5_function_disable(dev, true); +} + +/* xxx_light() function are used in order to configure the device without full + * init (light init). e.g.: There isn't a point in reload a device to light state. + * Hence, mlx5_load_one_light() isn't needed. + */ + +void mlx5_unload_one_light(struct mlx5_core_dev *dev) +{ + if (dev->state != MLX5_DEVICE_STATE_UP) + return; + mlx5_function_disable(dev, false); + dev->state = MLX5_DEVICE_STATE_INTERNAL_ERROR; +} + static const int types[] = { MLX5_CAP_GENERAL, MLX5_CAP_GENERAL_2, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 7a5f04082058..464c6885a01c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -240,11 +240,14 @@ int mlx5_attach_device(struct mlx5_core_dev *dev); void mlx5_detach_device(struct mlx5_core_dev *dev, bool suspend); int mlx5_register_device(struct mlx5_core_dev *dev); void mlx5_unregister_device(struct mlx5_core_dev *dev); +void mlx5_dev_set_lightweight(struct mlx5_core_dev *dev); +bool mlx5_dev_is_lightweight(struct mlx5_core_dev *dev); struct mlx5_core_dev *mlx5_get_next_phys_dev_lag(struct mlx5_core_dev *dev); void mlx5_dev_list_lock(void); void mlx5_dev_list_unlock(void); int mlx5_dev_list_trylock(void); +void mlx5_fw_reporters_create(struct mlx5_core_dev *dev); int mlx5_query_mtpps(struct mlx5_core_dev *dev, u32 *mtpps, u32 mtpps_size); int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size); int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode); @@ -319,11 +322,15 @@ static inline bool mlx5_core_is_sf(const struct mlx5_core_dev *dev) int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx); void mlx5_mdev_uninit(struct mlx5_core_dev *dev); int mlx5_init_one(struct mlx5_core_dev *dev); +int mlx5_init_one_devl_locked(struct mlx5_core_dev *dev); void mlx5_uninit_one(struct mlx5_core_dev *dev); void mlx5_unload_one(struct mlx5_core_dev *dev, bool suspend); void mlx5_unload_one_devl_locked(struct mlx5_core_dev *dev, bool suspend); int mlx5_load_one(struct mlx5_core_dev *dev, bool recovery); int mlx5_load_one_devl_locked(struct mlx5_core_dev *dev, bool recovery); +int mlx5_init_one_light(struct mlx5_core_dev *dev); +void mlx5_uninit_one_light(struct mlx5_core_dev *dev); +void mlx5_unload_one_light(struct mlx5_core_dev *dev); int mlx5_vport_set_other_func_cap(struct mlx5_core_dev *dev, const void *hca_cap, u16 vport, u16 opmod); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c index 0692363cf80e..8fe82f1191bb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c @@ -3,6 +3,7 @@ #include #include +#include #include "mlx5_core.h" #include "dev.h" #include "devlink.h" @@ -28,6 +29,10 @@ static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxilia mdev->priv.adev_idx = adev->id; sf_dev->mdev = mdev; + /* Only local SFs do light probe */ + if (MLX5_ESWITCH_MANAGER(sf_dev->parent_mdev)) + mlx5_dev_set_lightweight(mdev); + err = mlx5_mdev_init(mdev, MLX5_SF_PROF); if (err) { mlx5_core_warn(mdev, "mlx5_mdev_init on err=%d\n", err); @@ -41,7 +46,10 @@ static int mlx5_sf_dev_probe(struct auxiliary_device *adev, const struct auxilia goto remap_err; } - err = mlx5_init_one(mdev); + if (MLX5_ESWITCH_MANAGER(sf_dev->parent_mdev)) + err = mlx5_init_one_light(mdev); + else + err = mlx5_init_one(mdev); if (err) { mlx5_core_warn(mdev, "mlx5_init_one err=%d\n", err); goto init_one_err; @@ -65,7 +73,10 @@ static void mlx5_sf_dev_remove(struct auxiliary_device *adev) mlx5_drain_health_wq(sf_dev->mdev); devlink_unregister(devlink); - mlx5_uninit_one(sf_dev->mdev); + if (mlx5_dev_is_lightweight(sf_dev->mdev)) + mlx5_uninit_one_light(sf_dev->mdev); + else + mlx5_uninit_one(sf_dev->mdev); iounmap(sf_dev->mdev->iseg); mlx5_mdev_uninit(sf_dev->mdev); mlx5_devlink_free(devlink); -- cgit v1.2.3 From 978015f7ef9240acfb078f4c1c0d79459b42f951 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 29 May 2023 10:34:59 +0200 Subject: net/mlx5e: Remove a useless function call 'handle' is known to be NULL here. There is no need to kfree() it. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c index 0290e0dea539..4e923a2874ae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c @@ -112,10 +112,8 @@ mlx5e_tc_post_act_add(struct mlx5e_post_act *post_act, struct mlx5_flow_attr *po int err; handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (!handle) { - kfree(handle); + if (!handle) return ERR_PTR(-ENOMEM); - } post_attr->chain = 0; post_attr->prio = 0; -- cgit v1.2.3 From dc886bce753cc2cf3c88ec5c7a6880a4e17d65ba Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 8 Jun 2023 15:20:49 +0200 Subject: mptcp: export local_address Rename local_address() with "mptcp_" prefix and export it in protocol.h. This function will be re-used in the common PM code (pm.c) in the following commit. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Reviewed-by: Larysa Zaremba Signed-off-by: Jakub Kicinski --- net/mptcp/pm_netlink.c | 17 ++++++++--------- net/mptcp/protocol.h | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 59f8f3124855..0bf09c45febd 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -86,8 +86,7 @@ bool mptcp_addresses_equal(const struct mptcp_addr_info *a, return a->port == b->port; } -static void local_address(const struct sock_common *skc, - struct mptcp_addr_info *addr) +void mptcp_local_address(const struct sock_common *skc, struct mptcp_addr_info *addr) { addr->family = skc->skc_family; addr->port = htons(skc->skc_num); @@ -122,7 +121,7 @@ static bool lookup_subflow_by_saddr(const struct list_head *list, list_for_each_entry(subflow, list, node) { skc = (struct sock_common *)mptcp_subflow_tcp_sock(subflow); - local_address(skc, &cur); + mptcp_local_address(skc, &cur); if (mptcp_addresses_equal(&cur, saddr, saddr->port)) return true; } @@ -263,7 +262,7 @@ bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk) struct mptcp_addr_info saddr; bool ret = false; - local_address((struct sock_common *)sk, &saddr); + mptcp_local_address((struct sock_common *)sk, &saddr); spin_lock_bh(&msk->pm.lock); list_for_each_entry(entry, &msk->pm.anno_list, list) { @@ -541,7 +540,7 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) struct mptcp_addr_info mpc_addr; bool backup = false; - local_address((struct sock_common *)msk->first, &mpc_addr); + mptcp_local_address((struct sock_common *)msk->first, &mpc_addr); rcu_read_lock(); entry = __lookup_addr(pernet, &mpc_addr, false); if (entry) { @@ -752,7 +751,7 @@ int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk, struct sock *ssk = mptcp_subflow_tcp_sock(subflow); struct mptcp_addr_info local, remote; - local_address((struct sock_common *)ssk, &local); + mptcp_local_address((struct sock_common *)ssk, &local); if (!mptcp_addresses_equal(&local, addr, addr->port)) continue; @@ -1070,8 +1069,8 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) /* The 0 ID mapping is defined by the first subflow, copied into the msk * addr */ - local_address((struct sock_common *)msk, &msk_local); - local_address((struct sock_common *)skc, &skc_local); + mptcp_local_address((struct sock_common *)msk, &msk_local); + mptcp_local_address((struct sock_common *)skc, &skc_local); if (mptcp_addresses_equal(&msk_local, &skc_local, false)) return 0; @@ -1491,7 +1490,7 @@ static int mptcp_nl_remove_id_zero_address(struct net *net, if (list_empty(&msk->conn_list) || mptcp_pm_is_userspace(msk)) goto next; - local_address((struct sock_common *)msk, &msk_local); + mptcp_local_address((struct sock_common *)msk, &msk_local); if (!mptcp_addresses_equal(&msk_local, addr, addr->port)) goto next; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 70c957bc56a8..3580c7fc39c3 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -638,6 +638,7 @@ void mptcp_set_owner_r(struct sk_buff *skb, struct sock *sk); bool mptcp_addresses_equal(const struct mptcp_addr_info *a, const struct mptcp_addr_info *b, bool use_port); +void mptcp_local_address(const struct sock_common *skc, struct mptcp_addr_info *addr); /* called with sk socket lock held */ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc, -- cgit v1.2.3 From 9bbec87ecfe8a5c06710100a93e6b7e66f2cbbaf Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 8 Jun 2023 15:20:50 +0200 Subject: mptcp: unify pm get_local_id interfaces This patch unifies the three PM get_local_id() interfaces: mptcp_pm_nl_get_local_id() in mptcp/pm_netlink.c for the in-kernel PM and mptcp_userspace_pm_get_local_id() in mptcp/pm_userspace.c for the userspace PM. They'll be switched in the common PM infterface mptcp_pm_get_local_id() in mptcp/pm.c based on whether mptcp_pm_is_userspace() or not. Also put together the declarations of these three functions in protocol.h. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Reviewed-by: Larysa Zaremba Signed-off-by: Jakub Kicinski --- net/mptcp/pm.c | 18 +++++++++++++++++- net/mptcp/pm_netlink.c | 22 +++------------------- net/mptcp/protocol.h | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 92d540e527a2..300fa9bea047 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -415,7 +415,23 @@ out_unlock: int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) { - return mptcp_pm_nl_get_local_id(msk, skc); + struct mptcp_addr_info skc_local; + struct mptcp_addr_info msk_local; + + if (WARN_ON_ONCE(!msk)) + return -1; + + /* The 0 ID mapping is defined by the first subflow, copied into the msk + * addr + */ + mptcp_local_address((struct sock_common *)msk, &msk_local); + mptcp_local_address((struct sock_common *)skc, &skc_local); + if (mptcp_addresses_equal(&msk_local, &skc_local, false)) + return 0; + + if (mptcp_pm_is_userspace(msk)) + return mptcp_userspace_pm_get_local_id(msk, &skc_local); + return mptcp_pm_nl_get_local_id(msk, &skc_local); } void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk) diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 0bf09c45febd..e51d98877485 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -1055,33 +1055,17 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk, return 0; } -int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) +int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc) { struct mptcp_pm_addr_entry *entry; - struct mptcp_addr_info skc_local; - struct mptcp_addr_info msk_local; struct pm_nl_pernet *pernet; int ret = -1; - if (WARN_ON_ONCE(!msk)) - return -1; - - /* The 0 ID mapping is defined by the first subflow, copied into the msk - * addr - */ - mptcp_local_address((struct sock_common *)msk, &msk_local); - mptcp_local_address((struct sock_common *)skc, &skc_local); - if (mptcp_addresses_equal(&msk_local, &skc_local, false)) - return 0; - - if (mptcp_pm_is_userspace(msk)) - return mptcp_userspace_pm_get_local_id(msk, &skc_local); - pernet = pm_nl_get_pernet_from_msk(msk); rcu_read_lock(); list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) { - if (mptcp_addresses_equal(&entry->addr, &skc_local, entry->addr.port)) { + if (mptcp_addresses_equal(&entry->addr, skc, entry->addr.port)) { ret = entry->addr.id; break; } @@ -1095,7 +1079,7 @@ int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) if (!entry) return -ENOMEM; - entry->addr = skc_local; + entry->addr = *skc; entry->addr.id = 0; entry->addr.port = 0; entry->ifindex = 0; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 3580c7fc39c3..1ac799a6b959 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -917,13 +917,13 @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, const struct sk_buff *skb, bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining, struct mptcp_rm_list *rm_list); int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); +int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc); int mptcp_userspace_pm_get_local_id(struct mptcp_sock *msk, struct mptcp_addr_info *skc); void __init mptcp_pm_nl_init(void); void mptcp_pm_nl_work(struct mptcp_sock *msk); void mptcp_pm_nl_rm_subflow_received(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list); -int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc); unsigned int mptcp_pm_get_add_addr_signal_max(const struct mptcp_sock *msk); unsigned int mptcp_pm_get_add_addr_accept_max(const struct mptcp_sock *msk); unsigned int mptcp_pm_get_subflows_max(const struct mptcp_sock *msk); -- cgit v1.2.3 From f40be0db0b7680c2e9f0b1289788542813ba0f00 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 8 Jun 2023 15:20:51 +0200 Subject: mptcp: unify pm get_flags_and_ifindex_by_id This patch unifies the three PM get_flags_and_ifindex_by_id() interfaces: mptcp_pm_nl_get_flags_and_ifindex_by_id() in mptcp/pm_netlink.c for the in-kernel PM and mptcp_userspace_pm_get_flags_and_ifindex_by_id() in mptcp/pm_userspace.c for the userspace PM. They'll be switched in the common PM infterface mptcp_pm_get_flags_and_ifindex_by_id() in mptcp/pm.c based on whether mptcp_pm_is_userspace() or not. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Reviewed-by: Larysa Zaremba Signed-off-by: Jakub Kicinski --- net/mptcp/pm.c | 14 ++++++++++++++ net/mptcp/pm_netlink.c | 27 ++++++++------------------- net/mptcp/pm_userspace.c | 3 --- net/mptcp/protocol.h | 2 ++ 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 300fa9bea047..b4a1277b4bb5 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -434,6 +434,20 @@ int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc) return mptcp_pm_nl_get_local_id(msk, &skc_local); } +int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id, + u8 *flags, int *ifindex) +{ + *flags = 0; + *ifindex = 0; + + if (!id) + return 0; + + if (mptcp_pm_is_userspace(msk)) + return mptcp_userspace_pm_get_flags_and_ifindex_by_id(msk, id, flags, ifindex); + return mptcp_pm_nl_get_flags_and_ifindex_by_id(msk, id, flags, ifindex); +} + void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index e51d98877485..0fd938933373 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -1356,31 +1356,20 @@ out_free: return ret; } -int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id, - u8 *flags, int *ifindex) +int mptcp_pm_nl_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id, + u8 *flags, int *ifindex) { struct mptcp_pm_addr_entry *entry; struct sock *sk = (struct sock *)msk; struct net *net = sock_net(sk); - *flags = 0; - *ifindex = 0; - - if (id) { - if (mptcp_pm_is_userspace(msk)) - return mptcp_userspace_pm_get_flags_and_ifindex_by_id(msk, - id, - flags, - ifindex); - - rcu_read_lock(); - entry = __lookup_addr_by_id(pm_nl_get_pernet(net), id); - if (entry) { - *flags = entry->flags; - *ifindex = entry->ifindex; - } - rcu_read_unlock(); + rcu_read_lock(); + entry = __lookup_addr_by_id(pm_nl_get_pernet(net), id); + if (entry) { + *flags = entry->flags; + *ifindex = entry->ifindex; } + rcu_read_unlock(); return 0; } diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index b06aa58dfcf2..47a883a16c11 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -111,9 +111,6 @@ int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, { struct mptcp_pm_addr_entry *entry, *match = NULL; - *flags = 0; - *ifindex = 0; - spin_lock_bh(&msk->pm.lock); list_for_each_entry(entry, &msk->pm.userspace_pm_local_addr_list, list) { if (id == entry->addr.id) { diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 1ac799a6b959..0a0a36fd0310 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -822,6 +822,8 @@ mptcp_lookup_anno_list_by_saddr(const struct mptcp_sock *msk, int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id, u8 *flags, int *ifindex); +int mptcp_pm_nl_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id, + u8 *flags, int *ifindex); int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id, u8 *flags, int *ifindex); -- cgit v1.2.3 From 6ba7ce89905c5d5cdb4ff9ff7c763a6a1d31f48d Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Thu, 8 Jun 2023 15:20:52 +0200 Subject: mptcp: unify pm set_flags interfaces This patch unifies the three PM set_flags() interfaces: mptcp_pm_nl_set_flags() in mptcp/pm_netlink.c for the in-kernel PM and mptcp_userspace_pm_set_flags() in mptcp/pm_userspace.c for the userspace PM. They'll be switched in the common PM infterface mptcp_pm_set_flags() in mptcp/pm.c based on whether token is NULL or not. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Reviewed-by: Larysa Zaremba Signed-off-by: Jakub Kicinski --- net/mptcp/pm.c | 9 +++++++ net/mptcp/pm_netlink.c | 70 +++++++++++++++++++++++++++----------------------- net/mptcp/protocol.h | 4 +++ 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index b4a1277b4bb5..7dbbad1e4f55 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -448,6 +448,15 @@ int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id return mptcp_pm_nl_get_flags_and_ifindex_by_id(msk, id, flags, ifindex); } +int mptcp_pm_set_flags(struct net *net, struct nlattr *token, + struct mptcp_pm_addr_entry *loc, + struct mptcp_pm_addr_entry *rem, u8 bkup) +{ + if (token) + return mptcp_userspace_pm_set_flags(net, token, loc, rem, bkup); + return mptcp_pm_nl_set_flags(net, loc, bkup); +} + void mptcp_pm_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ssk) { struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk); diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 0fd938933373..a12a87b780f6 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -1882,18 +1882,50 @@ next: return ret; } +int mptcp_pm_nl_set_flags(struct net *net, struct mptcp_pm_addr_entry *addr, u8 bkup) +{ + struct pm_nl_pernet *pernet = pm_nl_get_pernet(net); + u8 changed, mask = MPTCP_PM_ADDR_FLAG_BACKUP | + MPTCP_PM_ADDR_FLAG_FULLMESH; + struct mptcp_pm_addr_entry *entry; + u8 lookup_by_id = 0; + + if (addr->addr.family == AF_UNSPEC) { + lookup_by_id = 1; + if (!addr->addr.id) + return -EOPNOTSUPP; + } + + spin_lock_bh(&pernet->lock); + entry = __lookup_addr(pernet, &addr->addr, lookup_by_id); + if (!entry) { + spin_unlock_bh(&pernet->lock); + return -EINVAL; + } + if ((addr->flags & MPTCP_PM_ADDR_FLAG_FULLMESH) && + (entry->flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) { + spin_unlock_bh(&pernet->lock); + return -EINVAL; + } + + changed = (addr->flags ^ entry->flags) & mask; + entry->flags = (entry->flags & ~mask) | (addr->flags & mask); + *addr = *entry; + spin_unlock_bh(&pernet->lock); + + mptcp_nl_set_flags(net, &addr->addr, bkup, changed); + return 0; +} + static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info) { - struct mptcp_pm_addr_entry addr = { .addr = { .family = AF_UNSPEC }, }, *entry; struct mptcp_pm_addr_entry remote = { .addr = { .family = AF_UNSPEC }, }; + struct mptcp_pm_addr_entry addr = { .addr = { .family = AF_UNSPEC }, }; struct nlattr *attr_rem = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE]; struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN]; struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR]; - struct pm_nl_pernet *pernet = genl_info_pm_nl(info); - u8 changed, mask = MPTCP_PM_ADDR_FLAG_BACKUP | - MPTCP_PM_ADDR_FLAG_FULLMESH; struct net *net = sock_net(skb->sk); - u8 bkup = 0, lookup_by_id = 0; + u8 bkup = 0; int ret; ret = mptcp_pm_parse_entry(attr, info, false, &addr); @@ -1908,34 +1940,8 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info) if (addr.flags & MPTCP_PM_ADDR_FLAG_BACKUP) bkup = 1; - if (addr.addr.family == AF_UNSPEC) { - lookup_by_id = 1; - if (!addr.addr.id) - return -EOPNOTSUPP; - } - - if (token) - return mptcp_userspace_pm_set_flags(net, token, &addr, &remote, bkup); - - spin_lock_bh(&pernet->lock); - entry = __lookup_addr(pernet, &addr.addr, lookup_by_id); - if (!entry) { - spin_unlock_bh(&pernet->lock); - return -EINVAL; - } - if ((addr.flags & MPTCP_PM_ADDR_FLAG_FULLMESH) && - (entry->flags & MPTCP_PM_ADDR_FLAG_SIGNAL)) { - spin_unlock_bh(&pernet->lock); - return -EINVAL; - } - changed = (addr.flags ^ entry->flags) & mask; - entry->flags = (entry->flags & ~mask) | (addr.flags & mask); - addr = *entry; - spin_unlock_bh(&pernet->lock); - - mptcp_nl_set_flags(net, &addr.addr, bkup, changed); - return 0; + return mptcp_pm_set_flags(net, token, &addr, &remote, bkup); } static void mptcp_nl_mcast_send(struct net *net, struct sk_buff *nlskb, gfp_t gfp) diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 0a0a36fd0310..47b46602870e 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -827,6 +827,10 @@ int mptcp_pm_nl_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk, unsigned int id, u8 *flags, int *ifindex); +int mptcp_pm_set_flags(struct net *net, struct nlattr *token, + struct mptcp_pm_addr_entry *loc, + struct mptcp_pm_addr_entry *rem, u8 bkup); +int mptcp_pm_nl_set_flags(struct net *net, struct mptcp_pm_addr_entry *addr, u8 bkup); int mptcp_userspace_pm_set_flags(struct net *net, struct nlattr *token, struct mptcp_pm_addr_entry *loc, struct mptcp_pm_addr_entry *rem, u8 bkup); -- cgit v1.2.3 From d457a0e329b0bfd3a1450e0b1a18cd2b47a25a08 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 8 Jun 2023 19:17:37 +0000 Subject: net: move gso declarations and functions to their own files Move declarations into include/net/gso.h and code into net/core/gso.c Signed-off-by: Eric Dumazet Cc: Stanislav Fomichev Reviewed-by: Simon Horman Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230608191738.3947077-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/tg3.c | 1 + drivers/net/ethernet/myricom/myri10ge/myri10ge.c | 1 + drivers/net/ethernet/sfc/siena/tx_common.c | 1 + drivers/net/ethernet/sfc/tx_common.c | 1 + drivers/net/tap.c | 1 + drivers/net/usb/r8152.c | 1 + drivers/net/wireguard/device.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 1 + include/linux/netdevice.h | 26 +-- include/linux/skbuff.h | 71 ------ include/net/gro.h | 1 + include/net/gso.h | 109 +++++++++ include/net/udp.h | 1 + net/core/Makefile | 2 +- net/core/dev.c | 70 +----- net/core/gro.c | 59 +---- net/core/gso.c | 273 +++++++++++++++++++++++ net/core/skbuff.c | 142 +----------- net/ipv4/af_inet.c | 1 + net/ipv4/esp4_offload.c | 1 + net/ipv4/gre_offload.c | 1 + net/ipv4/ip_output.c | 1 + net/ipv4/tcp_offload.c | 1 + net/ipv4/udp.c | 1 + net/ipv4/udp_offload.c | 1 + net/ipv6/esp6_offload.c | 1 + net/ipv6/ip6_offload.c | 1 + net/ipv6/ip6_output.c | 1 + net/ipv6/udp_offload.c | 1 + net/mac80211/tx.c | 1 + net/mpls/af_mpls.c | 1 + net/mpls/mpls_gso.c | 1 + net/netfilter/nf_flow_table_ip.c | 1 + net/netfilter/nfnetlink_queue.c | 1 + net/nsh/nsh.c | 1 + net/openvswitch/actions.c | 1 + net/openvswitch/datapath.c | 1 + net/sched/act_police.c | 1 + net/sched/sch_cake.c | 1 + net/sched/sch_netem.c | 1 + net/sched/sch_taprio.c | 1 + net/sched/sch_tbf.c | 1 + net/sctp/offload.c | 1 + net/xfrm/xfrm_device.c | 1 + net/xfrm/xfrm_interface_core.c | 1 + net/xfrm/xfrm_output.c | 1 + 46 files changed, 425 insertions(+), 365 deletions(-) create mode 100644 include/net/gso.h create mode 100644 net/core/gso.c diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 58747292521d..5e68a6a4b2af 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -57,6 +57,7 @@ #include #include +#include #include #include diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index c5687d94ea88..7b7e1c5b00f4 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/ethernet/sfc/siena/tx_common.c b/drivers/net/ethernet/sfc/siena/tx_common.c index 93a32d61944f..a7a9ab304e13 100644 --- a/drivers/net/ethernet/sfc/siena/tx_common.c +++ b/drivers/net/ethernet/sfc/siena/tx_common.c @@ -12,6 +12,7 @@ #include "efx.h" #include "nic_common.h" #include "tx_common.h" +#include static unsigned int efx_tx_cb_page_count(struct efx_tx_queue *tx_queue) { diff --git a/drivers/net/ethernet/sfc/tx_common.c b/drivers/net/ethernet/sfc/tx_common.c index 67e789b96c43..4ce7d00e697d 100644 --- a/drivers/net/ethernet/sfc/tx_common.c +++ b/drivers/net/ethernet/sfc/tx_common.c @@ -12,6 +12,7 @@ #include "efx.h" #include "nic_common.h" #include "tx_common.h" +#include static unsigned int efx_tx_cb_page_count(struct efx_tx_queue *tx_queue) { diff --git a/drivers/net/tap.c b/drivers/net/tap.c index d30d730ed5a7..9137fb8c1c42 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0999a58ca9d2..0738baa5b82e 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Information for net-next */ #define NETNEXT_VERSION "12" diff --git a/drivers/net/wireguard/device.c b/drivers/net/wireguard/device.c index d58e9f818d3b..258dcc103921 100644 --- a/drivers/net/wireguard/device.c +++ b/drivers/net/wireguard/device.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 5fa6f98b8e55..ef0f53b3b89f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c2f0c6002a84..2d6cb2bf2f05 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4827,13 +4827,6 @@ int skb_crc32c_csum_help(struct sk_buff *skb); int skb_csum_hwoffload_help(struct sk_buff *skb, const netdev_features_t features); -struct sk_buff *__skb_gso_segment(struct sk_buff *skb, - netdev_features_t features, bool tx_path); -struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb, - netdev_features_t features, __be16 type); -struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, - netdev_features_t features); - struct netdev_bonding_info { ifslave slave; ifbond master; @@ -4856,11 +4849,6 @@ static inline void ethtool_notify(struct net_device *dev, unsigned int cmd, } #endif -static inline -struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features) -{ - return __skb_gso_segment(skb, features, true); -} __be16 skb_network_protocol(struct sk_buff *skb, int *depth); static inline bool can_checksum_protocol(netdev_features_t features, @@ -4987,6 +4975,7 @@ netdev_features_t passthru_features_check(struct sk_buff *skb, struct net_device *dev, netdev_features_t features); netdev_features_t netif_skb_features(struct sk_buff *skb); +void skb_warn_bad_offload(const struct sk_buff *skb); static inline bool net_gso_ok(netdev_features_t features, int gso_type) { @@ -5035,19 +5024,6 @@ void netif_set_tso_max_segs(struct net_device *dev, unsigned int segs); void netif_inherit_tso_max(struct net_device *to, const struct net_device *from); -static inline void skb_gso_error_unwind(struct sk_buff *skb, __be16 protocol, - int pulled_hlen, u16 mac_offset, - int mac_len) -{ - skb->protocol = protocol; - skb->encapsulation = 1; - skb_push(skb, pulled_hlen); - skb_reset_transport_header(skb); - skb->mac_header = mac_offset; - skb->network_header = skb->mac_header + mac_len; - skb->mac_len = mac_len; -} - static inline bool netif_is_macsec(const struct net_device *dev) { return dev->priv_flags & IFF_MACSEC; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e2f48ddb2f7c..91ed66952580 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3974,8 +3974,6 @@ int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); void skb_scrub_packet(struct sk_buff *skb, bool xnet); -bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu); -bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len); struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); struct sk_buff *skb_segment_list(struct sk_buff *skb, netdev_features_t features, unsigned int offset); @@ -4841,75 +4839,6 @@ static inline struct sec_path *skb_sec_path(const struct sk_buff *skb) #endif } -/* Keeps track of mac header offset relative to skb->head. - * It is useful for TSO of Tunneling protocol. e.g. GRE. - * For non-tunnel skb it points to skb_mac_header() and for - * tunnel skb it points to outer mac header. - * Keeps track of level of encapsulation of network headers. - */ -struct skb_gso_cb { - union { - int mac_offset; - int data_offset; - }; - int encap_level; - __wsum csum; - __u16 csum_start; -}; -#define SKB_GSO_CB_OFFSET 32 -#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_GSO_CB_OFFSET)) - -static inline int skb_tnl_header_len(const struct sk_buff *inner_skb) -{ - return (skb_mac_header(inner_skb) - inner_skb->head) - - SKB_GSO_CB(inner_skb)->mac_offset; -} - -static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra) -{ - int new_headroom, headroom; - int ret; - - headroom = skb_headroom(skb); - ret = pskb_expand_head(skb, extra, 0, GFP_ATOMIC); - if (ret) - return ret; - - new_headroom = skb_headroom(skb); - SKB_GSO_CB(skb)->mac_offset += (new_headroom - headroom); - return 0; -} - -static inline void gso_reset_checksum(struct sk_buff *skb, __wsum res) -{ - /* Do not update partial checksums if remote checksum is enabled. */ - if (skb->remcsum_offload) - return; - - SKB_GSO_CB(skb)->csum = res; - SKB_GSO_CB(skb)->csum_start = skb_checksum_start(skb) - skb->head; -} - -/* Compute the checksum for a gso segment. First compute the checksum value - * from the start of transport header to SKB_GSO_CB(skb)->csum_start, and - * then add in skb->csum (checksum from csum_start to end of packet). - * skb->csum and csum_start are then updated to reflect the checksum of the - * resultant packet starting from the transport header-- the resultant checksum - * is in the res argument (i.e. normally zero or ~ of checksum of a pseudo - * header. - */ -static inline __sum16 gso_make_checksum(struct sk_buff *skb, __wsum res) -{ - unsigned char *csum_start = skb_transport_header(skb); - int plen = (skb->head + SKB_GSO_CB(skb)->csum_start) - csum_start; - __wsum partial = SKB_GSO_CB(skb)->csum; - - SKB_GSO_CB(skb)->csum = res; - SKB_GSO_CB(skb)->csum_start = csum_start - skb->head; - - return csum_fold(csum_partial(csum_start, plen, partial)); -} - static inline bool skb_is_gso(const struct sk_buff *skb) { return skb_shinfo(skb)->gso_size; diff --git a/include/net/gro.h b/include/net/gro.h index 7b47dd6ce94f..75efa6fb8441 100644 --- a/include/net/gro.h +++ b/include/net/gro.h @@ -452,5 +452,6 @@ static inline void gro_normal_one(struct napi_struct *napi, struct sk_buff *skb, gro_normal_list(napi); } +extern struct list_head offload_base; #endif /* _NET_IPV6_GRO_H */ diff --git a/include/net/gso.h b/include/net/gso.h new file mode 100644 index 000000000000..29975440cad5 --- /dev/null +++ b/include/net/gso.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _NET_GSO_H +#define _NET_GSO_H + +#include + +/* Keeps track of mac header offset relative to skb->head. + * It is useful for TSO of Tunneling protocol. e.g. GRE. + * For non-tunnel skb it points to skb_mac_header() and for + * tunnel skb it points to outer mac header. + * Keeps track of level of encapsulation of network headers. + */ +struct skb_gso_cb { + union { + int mac_offset; + int data_offset; + }; + int encap_level; + __wsum csum; + __u16 csum_start; +}; +#define SKB_GSO_CB_OFFSET 32 +#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_GSO_CB_OFFSET)) + +static inline int skb_tnl_header_len(const struct sk_buff *inner_skb) +{ + return (skb_mac_header(inner_skb) - inner_skb->head) - + SKB_GSO_CB(inner_skb)->mac_offset; +} + +static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra) +{ + int new_headroom, headroom; + int ret; + + headroom = skb_headroom(skb); + ret = pskb_expand_head(skb, extra, 0, GFP_ATOMIC); + if (ret) + return ret; + + new_headroom = skb_headroom(skb); + SKB_GSO_CB(skb)->mac_offset += (new_headroom - headroom); + return 0; +} + +static inline void gso_reset_checksum(struct sk_buff *skb, __wsum res) +{ + /* Do not update partial checksums if remote checksum is enabled. */ + if (skb->remcsum_offload) + return; + + SKB_GSO_CB(skb)->csum = res; + SKB_GSO_CB(skb)->csum_start = skb_checksum_start(skb) - skb->head; +} + +/* Compute the checksum for a gso segment. First compute the checksum value + * from the start of transport header to SKB_GSO_CB(skb)->csum_start, and + * then add in skb->csum (checksum from csum_start to end of packet). + * skb->csum and csum_start are then updated to reflect the checksum of the + * resultant packet starting from the transport header-- the resultant checksum + * is in the res argument (i.e. normally zero or ~ of checksum of a pseudo + * header. + */ +static inline __sum16 gso_make_checksum(struct sk_buff *skb, __wsum res) +{ + unsigned char *csum_start = skb_transport_header(skb); + int plen = (skb->head + SKB_GSO_CB(skb)->csum_start) - csum_start; + __wsum partial = SKB_GSO_CB(skb)->csum; + + SKB_GSO_CB(skb)->csum = res; + SKB_GSO_CB(skb)->csum_start = csum_start - skb->head; + + return csum_fold(csum_partial(csum_start, plen, partial)); +} + +struct sk_buff *__skb_gso_segment(struct sk_buff *skb, + netdev_features_t features, bool tx_path); + +static inline struct sk_buff *skb_gso_segment(struct sk_buff *skb, + netdev_features_t features) +{ + return __skb_gso_segment(skb, features, true); +} + +struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb, + netdev_features_t features, __be16 type); + +struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, + netdev_features_t features); + +bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu); + +bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len); + +static inline void skb_gso_error_unwind(struct sk_buff *skb, __be16 protocol, + int pulled_hlen, u16 mac_offset, + int mac_len) +{ + skb->protocol = protocol; + skb->encapsulation = 1; + skb_push(skb, pulled_hlen); + skb_reset_transport_header(skb); + skb->mac_header = mac_offset; + skb->network_header = skb->mac_header + mac_len; + skb->mac_len = mac_len; +} + +#endif /* _NET_GSO_H */ diff --git a/include/net/udp.h b/include/net/udp.h index 4ed0b47c5582..e01340a27155 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/net/core/Makefile b/net/core/Makefile index 8f367813bc68..731db2eaa610 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -13,7 +13,7 @@ obj-y += dev.o dev_addr_lists.o dst.o netevent.o \ neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ fib_notifier.o xdp.o flow_offload.o gro.o \ - netdev-genl.o netdev-genl-gen.o + netdev-genl.o netdev-genl-gen.o gso.o obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o diff --git a/net/core/dev.c b/net/core/dev.c index 6d6f8a7fe6b4..c2456b3667fe 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3209,7 +3209,7 @@ static u16 skb_tx_hash(const struct net_device *dev, return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset; } -static void skb_warn_bad_offload(const struct sk_buff *skb) +void skb_warn_bad_offload(const struct sk_buff *skb) { static const netdev_features_t null_features; struct net_device *dev = skb->dev; @@ -3338,74 +3338,6 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth) return vlan_get_protocol_and_depth(skb, type, depth); } -/* openvswitch calls this on rx path, so we need a different check. - */ -static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path) -{ - if (tx_path) - return skb->ip_summed != CHECKSUM_PARTIAL && - skb->ip_summed != CHECKSUM_UNNECESSARY; - - return skb->ip_summed == CHECKSUM_NONE; -} - -/** - * __skb_gso_segment - Perform segmentation on skb. - * @skb: buffer to segment - * @features: features for the output path (see dev->features) - * @tx_path: whether it is called in TX path - * - * This function segments the given skb and returns a list of segments. - * - * It may return NULL if the skb requires no segmentation. This is - * only possible when GSO is used for verifying header integrity. - * - * Segmentation preserves SKB_GSO_CB_OFFSET bytes of previous skb cb. - */ -struct sk_buff *__skb_gso_segment(struct sk_buff *skb, - netdev_features_t features, bool tx_path) -{ - struct sk_buff *segs; - - if (unlikely(skb_needs_check(skb, tx_path))) { - int err; - - /* We're going to init ->check field in TCP or UDP header */ - err = skb_cow_head(skb, 0); - if (err < 0) - return ERR_PTR(err); - } - - /* Only report GSO partial support if it will enable us to - * support segmentation on this frame without needing additional - * work. - */ - if (features & NETIF_F_GSO_PARTIAL) { - netdev_features_t partial_features = NETIF_F_GSO_ROBUST; - struct net_device *dev = skb->dev; - - partial_features |= dev->features & dev->gso_partial_features; - if (!skb_gso_ok(skb, features | partial_features)) - features &= ~NETIF_F_GSO_PARTIAL; - } - - BUILD_BUG_ON(SKB_GSO_CB_OFFSET + - sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb)); - - SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb); - SKB_GSO_CB(skb)->encap_level = 0; - - skb_reset_mac_header(skb); - skb_reset_mac_len(skb); - - segs = skb_mac_gso_segment(skb, features); - - if (segs != skb && unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs))) - skb_warn_bad_offload(skb); - - return segs; -} -EXPORT_SYMBOL(__skb_gso_segment); /* Take action when hardware reception checksum errors are detected. */ #ifdef CONFIG_BUG diff --git a/net/core/gro.c b/net/core/gro.c index 4d45f78e2fac..dca800068e41 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -10,7 +10,7 @@ #define GRO_MAX_HEAD (MAX_HEADER + 128) static DEFINE_SPINLOCK(offload_lock); -static struct list_head offload_base __read_mostly = LIST_HEAD_INIT(offload_base); +struct list_head offload_base __read_mostly = LIST_HEAD_INIT(offload_base); /* Maximum number of GRO_NORMAL skbs to batch up for list-RX */ int gro_normal_batch __read_mostly = 8; @@ -92,63 +92,6 @@ void dev_remove_offload(struct packet_offload *po) } EXPORT_SYMBOL(dev_remove_offload); -/** - * skb_eth_gso_segment - segmentation handler for ethernet protocols. - * @skb: buffer to segment - * @features: features for the output path (see dev->features) - * @type: Ethernet Protocol ID - */ -struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb, - netdev_features_t features, __be16 type) -{ - struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); - struct packet_offload *ptype; - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, &offload_base, list) { - if (ptype->type == type && ptype->callbacks.gso_segment) { - segs = ptype->callbacks.gso_segment(skb, features); - break; - } - } - rcu_read_unlock(); - - return segs; -} -EXPORT_SYMBOL(skb_eth_gso_segment); - -/** - * skb_mac_gso_segment - mac layer segmentation handler. - * @skb: buffer to segment - * @features: features for the output path (see dev->features) - */ -struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, - netdev_features_t features) -{ - struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); - struct packet_offload *ptype; - int vlan_depth = skb->mac_len; - __be16 type = skb_network_protocol(skb, &vlan_depth); - - if (unlikely(!type)) - return ERR_PTR(-EINVAL); - - __skb_pull(skb, vlan_depth); - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, &offload_base, list) { - if (ptype->type == type && ptype->callbacks.gso_segment) { - segs = ptype->callbacks.gso_segment(skb, features); - break; - } - } - rcu_read_unlock(); - - __skb_push(skb, skb->data - skb_mac_header(skb)); - - return segs; -} -EXPORT_SYMBOL(skb_mac_gso_segment); int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb) { diff --git a/net/core/gso.c b/net/core/gso.c new file mode 100644 index 000000000000..9e1803bfc9c6 --- /dev/null +++ b/net/core/gso.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include +#include + +/** + * skb_eth_gso_segment - segmentation handler for ethernet protocols. + * @skb: buffer to segment + * @features: features for the output path (see dev->features) + * @type: Ethernet Protocol ID + */ +struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb, + netdev_features_t features, __be16 type) +{ + struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); + struct packet_offload *ptype; + + rcu_read_lock(); + list_for_each_entry_rcu(ptype, &offload_base, list) { + if (ptype->type == type && ptype->callbacks.gso_segment) { + segs = ptype->callbacks.gso_segment(skb, features); + break; + } + } + rcu_read_unlock(); + + return segs; +} +EXPORT_SYMBOL(skb_eth_gso_segment); + +/** + * skb_mac_gso_segment - mac layer segmentation handler. + * @skb: buffer to segment + * @features: features for the output path (see dev->features) + */ +struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, + netdev_features_t features) +{ + struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); + struct packet_offload *ptype; + int vlan_depth = skb->mac_len; + __be16 type = skb_network_protocol(skb, &vlan_depth); + + if (unlikely(!type)) + return ERR_PTR(-EINVAL); + + __skb_pull(skb, vlan_depth); + + rcu_read_lock(); + list_for_each_entry_rcu(ptype, &offload_base, list) { + if (ptype->type == type && ptype->callbacks.gso_segment) { + segs = ptype->callbacks.gso_segment(skb, features); + break; + } + } + rcu_read_unlock(); + + __skb_push(skb, skb->data - skb_mac_header(skb)); + + return segs; +} +EXPORT_SYMBOL(skb_mac_gso_segment); +/* openvswitch calls this on rx path, so we need a different check. + */ +static bool skb_needs_check(const struct sk_buff *skb, bool tx_path) +{ + if (tx_path) + return skb->ip_summed != CHECKSUM_PARTIAL && + skb->ip_summed != CHECKSUM_UNNECESSARY; + + return skb->ip_summed == CHECKSUM_NONE; +} + +/** + * __skb_gso_segment - Perform segmentation on skb. + * @skb: buffer to segment + * @features: features for the output path (see dev->features) + * @tx_path: whether it is called in TX path + * + * This function segments the given skb and returns a list of segments. + * + * It may return NULL if the skb requires no segmentation. This is + * only possible when GSO is used for verifying header integrity. + * + * Segmentation preserves SKB_GSO_CB_OFFSET bytes of previous skb cb. + */ +struct sk_buff *__skb_gso_segment(struct sk_buff *skb, + netdev_features_t features, bool tx_path) +{ + struct sk_buff *segs; + + if (unlikely(skb_needs_check(skb, tx_path))) { + int err; + + /* We're going to init ->check field in TCP or UDP header */ + err = skb_cow_head(skb, 0); + if (err < 0) + return ERR_PTR(err); + } + + /* Only report GSO partial support if it will enable us to + * support segmentation on this frame without needing additional + * work. + */ + if (features & NETIF_F_GSO_PARTIAL) { + netdev_features_t partial_features = NETIF_F_GSO_ROBUST; + struct net_device *dev = skb->dev; + + partial_features |= dev->features & dev->gso_partial_features; + if (!skb_gso_ok(skb, features | partial_features)) + features &= ~NETIF_F_GSO_PARTIAL; + } + + BUILD_BUG_ON(SKB_GSO_CB_OFFSET + + sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb)); + + SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb); + SKB_GSO_CB(skb)->encap_level = 0; + + skb_reset_mac_header(skb); + skb_reset_mac_len(skb); + + segs = skb_mac_gso_segment(skb, features); + + if (segs != skb && unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs))) + skb_warn_bad_offload(skb); + + return segs; +} +EXPORT_SYMBOL(__skb_gso_segment); + +/** + * skb_gso_transport_seglen - Return length of individual segments of a gso packet + * + * @skb: GSO skb + * + * skb_gso_transport_seglen is used to determine the real size of the + * individual segments, including Layer4 headers (TCP/UDP). + * + * The MAC/L2 or network (IP, IPv6) headers are not accounted for. + */ +static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) +{ + const struct skb_shared_info *shinfo = skb_shinfo(skb); + unsigned int thlen = 0; + + if (skb->encapsulation) { + thlen = skb_inner_transport_header(skb) - + skb_transport_header(skb); + + if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) + thlen += inner_tcp_hdrlen(skb); + } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { + thlen = tcp_hdrlen(skb); + } else if (unlikely(skb_is_gso_sctp(skb))) { + thlen = sizeof(struct sctphdr); + } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { + thlen = sizeof(struct udphdr); + } + /* UFO sets gso_size to the size of the fragmentation + * payload, i.e. the size of the L4 (UDP) header is already + * accounted for. + */ + return thlen + shinfo->gso_size; +} + +/** + * skb_gso_network_seglen - Return length of individual segments of a gso packet + * + * @skb: GSO skb + * + * skb_gso_network_seglen is used to determine the real size of the + * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). + * + * The MAC/L2 header is not accounted for. + */ +static unsigned int skb_gso_network_seglen(const struct sk_buff *skb) +{ + unsigned int hdr_len = skb_transport_header(skb) - + skb_network_header(skb); + + return hdr_len + skb_gso_transport_seglen(skb); +} + +/** + * skb_gso_mac_seglen - Return length of individual segments of a gso packet + * + * @skb: GSO skb + * + * skb_gso_mac_seglen is used to determine the real size of the + * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4 + * headers (TCP/UDP). + */ +static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) +{ + unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); + + return hdr_len + skb_gso_transport_seglen(skb); +} + +/** + * skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS + * + * There are a couple of instances where we have a GSO skb, and we + * want to determine what size it would be after it is segmented. + * + * We might want to check: + * - L3+L4+payload size (e.g. IP forwarding) + * - L2+L3+L4+payload size (e.g. sanity check before passing to driver) + * + * This is a helper to do that correctly considering GSO_BY_FRAGS. + * + * @skb: GSO skb + * + * @seg_len: The segmented length (from skb_gso_*_seglen). In the + * GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS]. + * + * @max_len: The maximum permissible length. + * + * Returns true if the segmented length <= max length. + */ +static inline bool skb_gso_size_check(const struct sk_buff *skb, + unsigned int seg_len, + unsigned int max_len) { + const struct skb_shared_info *shinfo = skb_shinfo(skb); + const struct sk_buff *iter; + + if (shinfo->gso_size != GSO_BY_FRAGS) + return seg_len <= max_len; + + /* Undo this so we can re-use header sizes */ + seg_len -= GSO_BY_FRAGS; + + skb_walk_frags(skb, iter) { + if (seg_len + skb_headlen(iter) > max_len) + return false; + } + + return true; +} + +/** + * skb_gso_validate_network_len - Will a split GSO skb fit into a given MTU? + * + * @skb: GSO skb + * @mtu: MTU to validate against + * + * skb_gso_validate_network_len validates if a given skb will fit a + * wanted MTU once split. It considers L3 headers, L4 headers, and the + * payload. + */ +bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu) +{ + return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu); +} +EXPORT_SYMBOL_GPL(skb_gso_validate_network_len); + +/** + * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length? + * + * @skb: GSO skb + * @len: length to validate against + * + * skb_gso_validate_mac_len validates if a given skb will fit a wanted + * length once split, including L2, L3 and L4 headers and the payload. + */ +bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len) +{ + return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len); +} +EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len); + diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7c4338221b17..fee2b1c105fe 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -5766,147 +5767,6 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet) } EXPORT_SYMBOL_GPL(skb_scrub_packet); -/** - * skb_gso_transport_seglen - Return length of individual segments of a gso packet - * - * @skb: GSO skb - * - * skb_gso_transport_seglen is used to determine the real size of the - * individual segments, including Layer4 headers (TCP/UDP). - * - * The MAC/L2 or network (IP, IPv6) headers are not accounted for. - */ -static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) -{ - const struct skb_shared_info *shinfo = skb_shinfo(skb); - unsigned int thlen = 0; - - if (skb->encapsulation) { - thlen = skb_inner_transport_header(skb) - - skb_transport_header(skb); - - if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) - thlen += inner_tcp_hdrlen(skb); - } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { - thlen = tcp_hdrlen(skb); - } else if (unlikely(skb_is_gso_sctp(skb))) { - thlen = sizeof(struct sctphdr); - } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { - thlen = sizeof(struct udphdr); - } - /* UFO sets gso_size to the size of the fragmentation - * payload, i.e. the size of the L4 (UDP) header is already - * accounted for. - */ - return thlen + shinfo->gso_size; -} - -/** - * skb_gso_network_seglen - Return length of individual segments of a gso packet - * - * @skb: GSO skb - * - * skb_gso_network_seglen is used to determine the real size of the - * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). - * - * The MAC/L2 header is not accounted for. - */ -static unsigned int skb_gso_network_seglen(const struct sk_buff *skb) -{ - unsigned int hdr_len = skb_transport_header(skb) - - skb_network_header(skb); - - return hdr_len + skb_gso_transport_seglen(skb); -} - -/** - * skb_gso_mac_seglen - Return length of individual segments of a gso packet - * - * @skb: GSO skb - * - * skb_gso_mac_seglen is used to determine the real size of the - * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4 - * headers (TCP/UDP). - */ -static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) -{ - unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); - - return hdr_len + skb_gso_transport_seglen(skb); -} - -/** - * skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS - * - * There are a couple of instances where we have a GSO skb, and we - * want to determine what size it would be after it is segmented. - * - * We might want to check: - * - L3+L4+payload size (e.g. IP forwarding) - * - L2+L3+L4+payload size (e.g. sanity check before passing to driver) - * - * This is a helper to do that correctly considering GSO_BY_FRAGS. - * - * @skb: GSO skb - * - * @seg_len: The segmented length (from skb_gso_*_seglen). In the - * GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS]. - * - * @max_len: The maximum permissible length. - * - * Returns true if the segmented length <= max length. - */ -static inline bool skb_gso_size_check(const struct sk_buff *skb, - unsigned int seg_len, - unsigned int max_len) { - const struct skb_shared_info *shinfo = skb_shinfo(skb); - const struct sk_buff *iter; - - if (shinfo->gso_size != GSO_BY_FRAGS) - return seg_len <= max_len; - - /* Undo this so we can re-use header sizes */ - seg_len -= GSO_BY_FRAGS; - - skb_walk_frags(skb, iter) { - if (seg_len + skb_headlen(iter) > max_len) - return false; - } - - return true; -} - -/** - * skb_gso_validate_network_len - Will a split GSO skb fit into a given MTU? - * - * @skb: GSO skb - * @mtu: MTU to validate against - * - * skb_gso_validate_network_len validates if a given skb will fit a - * wanted MTU once split. It considers L3 headers, L4 headers, and the - * payload. - */ -bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu) -{ - return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu); -} -EXPORT_SYMBOL_GPL(skb_gso_validate_network_len); - -/** - * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length? - * - * @skb: GSO skb - * @len: length to validate against - * - * skb_gso_validate_mac_len validates if a given skb will fit a wanted - * length once split, including L2, L3 and L4 headers and the payload. - */ -bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len) -{ - return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len); -} -EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len); - static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) { int mac_len, meta_len; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index fd233c4195ac..0e16ac8282c5 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c index 3969fa805679..12c5fb3c6e1e 100644 --- a/net/ipv4/esp4_offload.c +++ b/net/ipv4/esp4_offload.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 2b9cb5398335..311e70bfce40 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c @@ -11,6 +11,7 @@ #include #include #include +#include static struct sk_buff *gre_gso_segment(struct sk_buff *skb, netdev_features_t features) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 244fb9365d87..457598dfa128 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 05b38f58b404..8311c38267b5 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index df5e407286d7..7e0542c10471 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -103,6 +103,7 @@ #include #include #include +#include #include #include #include diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index 1f01e15ca24f..75aa4de5b731 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c index 75c02992c520..b33c7de5bdbc 100644 --- a/net/ipv6/esp6_offload.c +++ b/net/ipv6/esp6_offload.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 00dc2e3b0184..d6314287338d 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "ip6_offload.h" diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c722cb881b2d..c06ff7519f19 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index c39c1e32f980..ad3b8726873e 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -14,6 +14,7 @@ #include #include "ip6_offload.h" #include +#include static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, netdev_features_t features) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 148a0e2aa740..cfbe4beb8f1c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "ieee80211_i.h" #include "driver-ops.h" diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index dc5165d3eec4..bf6e81d56263 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c index 1482259de9b5..533d082f0701 100644 --- a/net/mpls/mpls_gso.c +++ b/net/mpls/mpls_gso.c @@ -14,6 +14,7 @@ #include #include #include +#include #include static struct sk_buff *mpls_gso_segment(struct sk_buff *skb, diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c index d248763917ad..d885d34edfe1 100644 --- a/net/netfilter/nf_flow_table_ip.c +++ b/net/netfilter/nf_flow_table_ip.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index e311462f6d98..556bc902af00 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/net/nsh/nsh.c b/net/nsh/nsh.c index 0f23e5e8e03e..f4a38bd6a7e0 100644 --- a/net/nsh/nsh.c +++ b/net/nsh/nsh.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index a8cf9a88758e..8074ea00d577 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 58f530f60172..a6d2a0b1aa21 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 2e9dce03d1ec..f3121c5a85e9 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 891e007d5c0b..9cff99558694 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 6ef3021e1169..0c9e93d66c50 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 5076da103f63..4a4e6ff894c1 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 277ad11f4d61..17d2d00ddb18 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/net/sctp/offload.c b/net/sctp/offload.c index eb874e3c399a..502095173d88 100644 --- a/net/sctp/offload.c +++ b/net/sctp/offload.c @@ -22,6 +22,7 @@ #include #include #include +#include static __le32 sctp_gso_make_checksum(struct sk_buff *skb) { diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c index 408f5e55744e..533697e2488f 100644 --- a/net/xfrm/xfrm_device.c +++ b/net/xfrm/xfrm_device.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/net/xfrm/xfrm_interface_core.c b/net/xfrm/xfrm_interface_core.c index 1f99dc469027..0ee864a76579 100644 --- a/net/xfrm/xfrm_interface_core.c +++ b/net/xfrm/xfrm_interface_core.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 369e5de8558f..662c83beb345 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From e16ca7fb9ffb0d51ddf01e450a1043ea65b5be3f Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 8 Jun 2023 17:42:30 +0100 Subject: sfc: add fallback action-set-lists for TC offload When offloading a TC encap action, the action information for the hardware might not be "ready": if there's currently no neighbour entry available for the destination address, we can't construct the Ethernet header to prepend to the packet. In this case, we still offload the flow rule, but with its action-set-list ID pointing at a "fallback" action which simply delivers the packet to its default destination (as though no flow rule had matched), thus allowing software TC to handle it. Later, when we receive a neighbouring update that allows us to construct the encap header, the rule will become "ready" and we will update its action-set-list ID in hardware to point at the actual offloaded actions. This patch sets up these fallback ASLs, but does not yet use them. Reviewed-by: Pieter Jansen van Vuuren Signed-off-by: Edward Cree Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/tc.c | 68 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/tc.h | 9 ++++++ 2 files changed, 77 insertions(+) diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index bb9ec1e761d3..24c67a163910 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -1391,6 +1391,58 @@ void efx_tc_deconfigure_default_rule(struct efx_nic *efx, rule->fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; } +static int efx_tc_configure_fallback_acts(struct efx_nic *efx, u32 eg_port, + struct efx_tc_action_set_list *acts) +{ + struct efx_tc_action_set *act; + int rc; + + act = kzalloc(sizeof(*act), GFP_KERNEL); + if (!act) + return -ENOMEM; + act->deliver = 1; + act->dest_mport = eg_port; + rc = efx_mae_alloc_action_set(efx, act); + if (rc) + goto fail1; + EFX_WARN_ON_PARANOID(!list_empty(&acts->list)); + list_add_tail(&act->list, &acts->list); + rc = efx_mae_alloc_action_set_list(efx, acts); + if (rc) + goto fail2; + return 0; +fail2: + list_del(&act->list); + efx_mae_free_action_set(efx, act->fw_id); +fail1: + kfree(act); + return rc; +} + +static int efx_tc_configure_fallback_acts_pf(struct efx_nic *efx) +{ + struct efx_tc_action_set_list *acts = &efx->tc->facts.pf; + u32 eg_port; + + efx_mae_mport_uplink(efx, &eg_port); + return efx_tc_configure_fallback_acts(efx, eg_port, acts); +} + +static int efx_tc_configure_fallback_acts_reps(struct efx_nic *efx) +{ + struct efx_tc_action_set_list *acts = &efx->tc->facts.reps; + u32 eg_port; + + efx_mae_mport_mport(efx, efx->tc->reps_mport_id, &eg_port); + return efx_tc_configure_fallback_acts(efx, eg_port, acts); +} + +static void efx_tc_deconfigure_fallback_acts(struct efx_nic *efx, + struct efx_tc_action_set_list *acts) +{ + efx_tc_free_action_set_list(efx, acts, true); +} + static int efx_tc_configure_rep_mport(struct efx_nic *efx) { u32 rep_mport_label; @@ -1481,6 +1533,12 @@ int efx_init_tc(struct efx_nic *efx) if (rc) return rc; rc = efx_tc_configure_rep_mport(efx); + if (rc) + return rc; + rc = efx_tc_configure_fallback_acts_pf(efx); + if (rc) + return rc; + rc = efx_tc_configure_fallback_acts_reps(efx); if (rc) return rc; efx->tc->up = true; @@ -1500,6 +1558,8 @@ void efx_fini_tc(struct efx_nic *efx) efx_tc_deconfigure_rep_mport(efx); efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.pf); efx_tc_deconfigure_default_rule(efx, &efx->tc->dflt.wire); + efx_tc_deconfigure_fallback_acts(efx, &efx->tc->facts.pf); + efx_tc_deconfigure_fallback_acts(efx, &efx->tc->facts.reps); efx->tc->up = false; } @@ -1564,6 +1624,10 @@ int efx_init_struct_tc(struct efx_nic *efx) efx->tc->dflt.pf.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; INIT_LIST_HEAD(&efx->tc->dflt.wire.acts.list); efx->tc->dflt.wire.fw_id = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL; + INIT_LIST_HEAD(&efx->tc->facts.pf.list); + efx->tc->facts.pf.fw_id = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL; + INIT_LIST_HEAD(&efx->tc->facts.reps.list); + efx->tc->facts.reps.fw_id = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL; efx->extra_channel_type[EFX_EXTRA_CHANNEL_TC] = &efx_tc_channel_type; return 0; fail_match_action_ht: @@ -1589,6 +1653,10 @@ void efx_fini_struct_tc(struct efx_nic *efx) MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); EFX_WARN_ON_PARANOID(efx->tc->dflt.wire.fw_id != MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); + EFX_WARN_ON_PARANOID(efx->tc->facts.pf.fw_id != + MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); + EFX_WARN_ON_PARANOID(efx->tc->facts.reps.fw_id != + MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); rhashtable_free_and_destroy(&efx->tc->match_action_ht, efx_tc_flow_free, efx); rhashtable_free_and_destroy(&efx->tc->encap_match_ht, diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h index 24e9640c74e9..ae182553514d 100644 --- a/drivers/net/ethernet/sfc/tc.h +++ b/drivers/net/ethernet/sfc/tc.h @@ -160,6 +160,11 @@ enum efx_tc_rule_prios { * %EFX_TC_PRIO_DFLT. Named by *ingress* port * @dflt.pf: rule for traffic ingressing from PF (egresses to wire) * @dflt.wire: rule for traffic ingressing from wire (egresses to PF) + * @facts: Fallback action-set-lists for unready rules. Named by *egress* port + * @facts.pf: action-set-list for unready rules on PF netdev, hence applying to + * traffic from wire, and egressing to PF + * @facts.reps: action-set-list for unready rules on representors, hence + * applying to traffic from representees, and egressing to the reps mport * @up: have TC datastructures been set up? */ struct efx_tc_state { @@ -180,6 +185,10 @@ struct efx_tc_state { struct efx_tc_flow_rule pf; struct efx_tc_flow_rule wire; } dflt; + struct { + struct efx_tc_action_set_list pf; + struct efx_tc_action_set_list reps; + } facts; bool up; }; -- cgit v1.2.3 From b4da4235dc69427fbdb66c9fbdf094ac76cdf745 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 8 Jun 2023 17:42:31 +0100 Subject: sfc: some plumbing towards TC encap action offload Create software objects to manage the metadata for encap actions that can be attached to TC rules. However, since we don't yet have the neighbouring information (needed to generate the Ethernet header), all rules with encap actions are marked as "unready" and thus insert the fallback action into hardware rather than actually offloading the encapsulation action. Reviewed-by: Pieter Jansen van Vuuren Signed-off-by: Edward Cree Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/Makefile | 3 +- drivers/net/ethernet/sfc/tc.c | 104 ++++++++++++++++++++++- drivers/net/ethernet/sfc/tc.h | 7 ++ drivers/net/ethernet/sfc/tc_encap_actions.c | 126 ++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/tc_encap_actions.h | 47 +++++++++++ 5 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 drivers/net/ethernet/sfc/tc_encap_actions.c create mode 100644 drivers/net/ethernet/sfc/tc_encap_actions.h diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile index 55b9c73cd8ef..16293b58e0a8 100644 --- a/drivers/net/ethernet/sfc/Makefile +++ b/drivers/net/ethernet/sfc/Makefile @@ -10,7 +10,8 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \ efx_devlink.o sfc-$(CONFIG_SFC_MTD) += mtd.o sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \ - mae.o tc.o tc_bindings.o tc_counters.o + mae.o tc.o tc_bindings.o tc_counters.o \ + tc_encap_actions.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 24c67a163910..4177feced3e6 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -14,11 +14,12 @@ #include #include "tc.h" #include "tc_bindings.h" +#include "tc_encap_actions.h" #include "mae.h" #include "ef100_rep.h" #include "efx.h" -static enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev) +enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev) { if (netif_is_vxlan(net_dev)) return EFX_ENCAP_TYPE_VXLAN; @@ -111,6 +112,8 @@ static void efx_tc_free_action_set(struct efx_nic *efx, } if (act->count) efx_tc_flower_put_counter_index(efx, act->count); + if (act->encap_md) + efx_tc_flower_release_encap_md(efx, act->encap_md); kfree(act); } @@ -594,6 +597,7 @@ enum efx_tc_action_order { EFX_TC_AO_VLAN_POP, EFX_TC_AO_VLAN_PUSH, EFX_TC_AO_COUNT, + EFX_TC_AO_ENCAP, EFX_TC_AO_DELIVER }; /* Determine whether we can add @new action without violating order */ @@ -623,6 +627,10 @@ static bool efx_tc_flower_action_order_ok(const struct efx_tc_action_set *act, if (act->count) return false; fallthrough; + case EFX_TC_AO_ENCAP: + if (act->encap_md) + return false; + fallthrough; case EFX_TC_AO_DELIVER: return !act->deliver; default: @@ -918,11 +926,13 @@ static int efx_tc_flower_replace(struct efx_nic *efx, { struct flow_rule *fr = flow_cls_offload_flow_rule(tc); struct netlink_ext_ack *extack = tc->common.extack; + const struct ip_tunnel_info *encap_info = NULL; struct efx_tc_flow_rule *rule = NULL, *old; struct efx_tc_action_set *act = NULL; const struct flow_action_entry *fa; struct efx_rep *from_efv, *to_efv; struct efx_tc_match match; + u32 acts_id; s64 rc; int i; @@ -1087,6 +1097,46 @@ static int efx_tc_flower_replace(struct efx_nic *efx, case FLOW_ACTION_MIRRED: save = *act; + if (encap_info) { + struct efx_tc_encap_action *encap; + + if (!efx_tc_flower_action_order_ok(act, + EFX_TC_AO_ENCAP)) { + rc = -EOPNOTSUPP; + NL_SET_ERR_MSG_MOD(extack, "Encap action violates action order"); + goto release; + } + encap = efx_tc_flower_create_encap_md( + efx, encap_info, fa->dev, extack); + if (IS_ERR_OR_NULL(encap)) { + rc = PTR_ERR(encap); + if (!rc) + rc = -EIO; /* arbitrary */ + goto release; + } + act->encap_md = encap; + act->dest_mport = encap->dest_mport; + act->deliver = 1; + rc = efx_mae_alloc_action_set(efx, act); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Failed to write action set to hw (encap)"); + goto release; + } + list_add_tail(&act->list, &rule->acts.list); + act = NULL; + if (fa->id == FLOW_ACTION_REDIRECT) + break; /* end of the line */ + /* Mirror, so continue on with saved act */ + save.count = NULL; + act = kzalloc(sizeof(*act), GFP_USER); + if (!act) { + rc = -ENOMEM; + goto release; + } + *act = save; + break; + } + if (!efx_tc_flower_action_order_ok(act, EFX_TC_AO_DELIVER)) { /* can't happen */ rc = -EOPNOTSUPP; @@ -1150,6 +1200,37 @@ static int efx_tc_flower_replace(struct efx_nic *efx, act->vlan_proto[act->vlan_push] = fa->vlan.proto; act->vlan_push++; break; + case FLOW_ACTION_TUNNEL_ENCAP: + if (encap_info) { + /* Can't specify encap multiple times. + * If you want to overwrite an existing + * encap_info, use an intervening + * FLOW_ACTION_TUNNEL_DECAP to clear it. + */ + NL_SET_ERR_MSG_MOD(extack, "Tunnel key set when already set"); + rc = -EINVAL; + goto release; + } + if (!fa->tunnel) { + NL_SET_ERR_MSG_MOD(extack, "Tunnel key set is missing key"); + rc = -EOPNOTSUPP; + goto release; + } + encap_info = fa->tunnel; + break; + case FLOW_ACTION_TUNNEL_DECAP: + if (encap_info) { + encap_info = NULL; + break; + } + /* Since we don't support enc_key matches on ingress + * (and if we did there'd be no tunnel-device to give + * us a type), we can't offload a decap that's not + * just undoing a previous encap action. + */ + NL_SET_ERR_MSG_MOD(extack, "Cannot offload tunnel decap action without tunnel device"); + rc = -EOPNOTSUPP; + goto release; default: NL_SET_ERR_MSG_FMT_MOD(extack, "Unhandled action %u", fa->id); @@ -1193,8 +1274,21 @@ static int efx_tc_flower_replace(struct efx_nic *efx, NL_SET_ERR_MSG_MOD(extack, "Failed to write action set list to hw"); goto release; } + if (from_efv == EFX_EFV_PF) + /* PF netdev, so rule applies to traffic from wire */ + rule->fallback = &efx->tc->facts.pf; + else + /* repdev, so rule applies to traffic from representee */ + rule->fallback = &efx->tc->facts.reps; + if (!efx_tc_check_ready(efx, rule)) { + netif_dbg(efx, drv, efx->net_dev, "action not ready for hw\n"); + acts_id = rule->fallback->fw_id; + } else { + netif_dbg(efx, drv, efx->net_dev, "ready for hw\n"); + acts_id = rule->acts.fw_id; + } rc = efx_mae_insert_rule(efx, &rule->match, EFX_TC_PRIO_TC, - rule->acts.fw_id, &rule->fw_id); + acts_id, &rule->fw_id); if (rc) { NL_SET_ERR_MSG_MOD(extack, "Failed to insert rule in hw"); goto release_acts; @@ -1609,6 +1703,9 @@ int efx_init_struct_tc(struct efx_nic *efx) mutex_init(&efx->tc->mutex); init_waitqueue_head(&efx->tc->flush_wq); + rc = efx_tc_init_encap_actions(efx); + if (rc < 0) + goto fail_encap_actions; rc = efx_tc_init_counters(efx); if (rc < 0) goto fail_counters; @@ -1635,6 +1732,8 @@ fail_match_action_ht: fail_encap_match_ht: efx_tc_destroy_counters(efx); fail_counters: + efx_tc_destroy_encap_actions(efx); +fail_encap_actions: mutex_destroy(&efx->tc->mutex); kfree(efx->tc->caps); fail_alloc_caps: @@ -1662,6 +1761,7 @@ void efx_fini_struct_tc(struct efx_nic *efx) rhashtable_free_and_destroy(&efx->tc->encap_match_ht, efx_tc_encap_match_free, NULL); efx_tc_fini_counters(efx); + efx_tc_fini_encap_actions(efx); mutex_unlock(&efx->tc->mutex); mutex_destroy(&efx->tc->mutex); kfree(efx->tc->caps); diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h index ae182553514d..5a8f701b05c5 100644 --- a/drivers/net/ethernet/sfc/tc.h +++ b/drivers/net/ethernet/sfc/tc.h @@ -25,6 +25,8 @@ static inline bool efx_ipv6_addr_all_ones(struct in6_addr *addr) } #endif +struct efx_tc_encap_action; /* see tc_encap_actions.h */ + struct efx_tc_action_set { u16 vlan_push:2; u16 vlan_pop:2; @@ -33,6 +35,7 @@ struct efx_tc_action_set { __be16 vlan_tci[2]; /* TCIs for vlan_push */ __be16 vlan_proto[2]; /* Ethertypes for vlan_push */ struct efx_tc_counter_index *count; + struct efx_tc_encap_action *encap_md; /* entry in tc_encap_ht table */ u32 dest_mport; u32 fw_id; /* index of this entry in firmware actions table */ struct list_head list; @@ -127,6 +130,7 @@ struct efx_tc_flow_rule { struct rhash_head linkage; struct efx_tc_match match; struct efx_tc_action_set_list acts; + struct efx_tc_action_set_list *fallback; /* what to use when unready? */ u32 fw_id; }; @@ -144,6 +148,7 @@ enum efx_tc_rule_prios { * @mutex: Used to serialise operations on TC hashtables * @counter_ht: Hashtable of TC counters (FW IDs and counter values) * @counter_id_ht: Hashtable mapping TC counter cookies to counters + * @encap_ht: Hashtable of TC encap actions * @encap_match_ht: Hashtable of TC encap matches * @match_action_ht: Hashtable of TC match-action rules * @reps_mport_id: MAE port allocated for representor RX @@ -173,6 +178,7 @@ struct efx_tc_state { struct mutex mutex; struct rhashtable counter_ht; struct rhashtable counter_id_ht; + struct rhashtable encap_ht; struct rhashtable encap_match_ht; struct rhashtable match_action_ht; u32 reps_mport_id, reps_mport_vport_id; @@ -194,6 +200,7 @@ struct efx_tc_state { struct efx_rep; +enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev); int efx_tc_configure_default_rule_rep(struct efx_rep *efv); void efx_tc_deconfigure_default_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rule); diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c new file mode 100644 index 000000000000..c41493e659a3 --- /dev/null +++ b/drivers/net/ethernet/sfc/tc_encap_actions.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-only +/**************************************************************************** + * Driver for Solarflare network controllers and boards + * Copyright 2023, Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include "tc_encap_actions.h" +#include "tc.h" +#include "mae.h" +#include +#include + +static const struct rhashtable_params efx_tc_encap_ht_params = { + .key_len = offsetofend(struct efx_tc_encap_action, key), + .key_offset = 0, + .head_offset = offsetof(struct efx_tc_encap_action, linkage), +}; + +static void efx_tc_encap_free(void *ptr, void *__unused) +{ + struct efx_tc_encap_action *enc = ptr; + + WARN_ON(refcount_read(&enc->ref)); + kfree(enc); +} + +int efx_tc_init_encap_actions(struct efx_nic *efx) +{ + return rhashtable_init(&efx->tc->encap_ht, &efx_tc_encap_ht_params); +} + +/* Only call this in init failure teardown. + * Normal exit should fini instead as there may be entries in the table. + */ +void efx_tc_destroy_encap_actions(struct efx_nic *efx) +{ + rhashtable_destroy(&efx->tc->encap_ht); +} + +void efx_tc_fini_encap_actions(struct efx_nic *efx) +{ + rhashtable_free_and_destroy(&efx->tc->encap_ht, efx_tc_encap_free, NULL); +} + +bool efx_tc_check_ready(struct efx_nic *efx, struct efx_tc_flow_rule *rule) +{ + struct efx_tc_action_set *act; + + /* Encap actions can only be offloaded if they have valid + * neighbour info for the outer Ethernet header. + */ + list_for_each_entry(act, &rule->acts.list, list) + if (act->encap_md) /* neigh bindings not implemented yet */ + return false; + return true; +} + +struct efx_tc_encap_action *efx_tc_flower_create_encap_md( + struct efx_nic *efx, const struct ip_tunnel_info *info, + struct net_device *egdev, struct netlink_ext_ack *extack) +{ + enum efx_encap_type type = efx_tc_indr_netdev_type(egdev); + struct efx_tc_encap_action *encap, *old; + s64 rc; + + if (type == EFX_ENCAP_TYPE_NONE) { + /* dest is not an encap device */ + NL_SET_ERR_MSG_MOD(extack, "Not a (supported) tunnel device but tunnel_key is set"); + return ERR_PTR(-EOPNOTSUPP); + } + rc = efx_mae_check_encap_type_supported(efx, type); + if (rc < 0) { + NL_SET_ERR_MSG_MOD(extack, "Firmware reports no support for this tunnel type"); + return ERR_PTR(rc); + } + /* No support yet for Geneve options */ + if (info->options_len) { + NL_SET_ERR_MSG_MOD(extack, "Unsupported tunnel options"); + return ERR_PTR(-EOPNOTSUPP); + } + switch (info->mode) { + case IP_TUNNEL_INFO_TX: + break; + case IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6: + type |= EFX_ENCAP_FLAG_IPV6; + break; + default: + NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported tunnel mode %u", + info->mode); + return ERR_PTR(-EOPNOTSUPP); + } + encap = kzalloc(sizeof(*encap), GFP_KERNEL_ACCOUNT); + if (!encap) + return ERR_PTR(-ENOMEM); + encap->type = type; + encap->key = info->key; + old = rhashtable_lookup_get_insert_fast(&efx->tc->encap_ht, + &encap->linkage, + efx_tc_encap_ht_params); + if (old) { + /* don't need our new entry */ + kfree(encap); + if (!refcount_inc_not_zero(&old->ref)) + return ERR_PTR(-EAGAIN); + /* existing entry found, ref taken */ + return old; + } + + /* ref and return */ + refcount_set(&encap->ref, 1); + return encap; +} + +void efx_tc_flower_release_encap_md(struct efx_nic *efx, + struct efx_tc_encap_action *encap) +{ + if (!refcount_dec_and_test(&encap->ref)) + return; /* still in use */ + rhashtable_remove_fast(&efx->tc->encap_ht, &encap->linkage, + efx_tc_encap_ht_params); + kfree(encap); +} diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.h b/drivers/net/ethernet/sfc/tc_encap_actions.h new file mode 100644 index 000000000000..1a3679e81f09 --- /dev/null +++ b/drivers/net/ethernet/sfc/tc_encap_actions.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/**************************************************************************** + * Driver for Solarflare network controllers and boards + * Copyright 2023, Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef EFX_TC_ENCAP_ACTIONS_H +#define EFX_TC_ENCAP_ACTIONS_H +#include "net_driver.h" + +#include +#include + +/* This limit is arbitrary; current hardware (SN1022) handles encap headers + * of up to 126 bytes, but that limit is not enshrined in the MCDI protocol. + */ +#define EFX_TC_MAX_ENCAP_HDR 126 +struct efx_tc_encap_action { + enum efx_encap_type type; + struct ip_tunnel_key key; /* 52 bytes */ + u32 dest_mport; /* is copied into struct efx_tc_action_set */ + u8 encap_hdr_len; + u8 encap_hdr[EFX_TC_MAX_ENCAP_HDR]; + struct rhash_head linkage; /* efx->tc_encap_ht */ + refcount_t ref; + u32 fw_id; /* index of this entry in firmware encap table */ +}; + +/* create/uncreate/teardown hashtables */ +int efx_tc_init_encap_actions(struct efx_nic *efx); +void efx_tc_destroy_encap_actions(struct efx_nic *efx); +void efx_tc_fini_encap_actions(struct efx_nic *efx); + +struct efx_tc_flow_rule; +bool efx_tc_check_ready(struct efx_nic *efx, struct efx_tc_flow_rule *rule); + +struct efx_tc_encap_action *efx_tc_flower_create_encap_md( + struct efx_nic *efx, const struct ip_tunnel_info *info, + struct net_device *egdev, struct netlink_ext_ack *extack); +void efx_tc_flower_release_encap_md(struct efx_nic *efx, + struct efx_tc_encap_action *encap); + +#endif /* EFX_TC_ENCAP_ACTIONS_H */ -- cgit v1.2.3 From 69819d3bc4086dd5a268600d1cbd65c39eda1672 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 8 Jun 2023 17:42:32 +0100 Subject: sfc: add function to atomically update a rule in the MAE efx_mae_update_rule() changes the action-set-list attached to an MAE flow rule in the Action Rule Table. We will use this when neighbouring updates change encap actions. Reviewed-by: Pieter Jansen van Vuuren Signed-off-by: Edward Cree Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/mae.c | 23 +++++++++++++++++++++++ drivers/net/ethernet/sfc/mae.h | 1 + 2 files changed, 24 insertions(+) diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c index 37a4c6925ad4..4eef5d18817a 100644 --- a/drivers/net/ethernet/sfc/mae.c +++ b/drivers/net/ethernet/sfc/mae.c @@ -1229,6 +1229,29 @@ int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, return 0; } +int efx_mae_update_rule(struct efx_nic *efx, u32 acts_id, u32 id) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_UPDATE_IN_LEN); + MCDI_DECLARE_STRUCT_PTR(response); + + BUILD_BUG_ON(MC_CMD_MAE_ACTION_RULE_UPDATE_OUT_LEN); + response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_RESPONSE); + + MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_AR_ID, id); + if (efx_mae_asl_id(acts_id)) { + MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); + MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, + MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); + } else { + /* We only had one AS, so we didn't wrap it in an ASL */ + MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, + MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); + MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); + } + return efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_UPDATE, inbuf, sizeof(inbuf), + NULL, 0, NULL); +} + int efx_mae_delete_rule(struct efx_nic *efx, u32 id) { MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h index 1cf8dfeb0c28..c542aab43ea1 100644 --- a/drivers/net/ethernet/sfc/mae.h +++ b/drivers/net/ethernet/sfc/mae.h @@ -105,6 +105,7 @@ int efx_mae_unregister_encap_match(struct efx_nic *efx, int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, u32 prio, u32 acts_id, u32 *id); +int efx_mae_update_rule(struct efx_nic *efx, u32 acts_id, u32 id); int efx_mae_delete_rule(struct efx_nic *efx, u32 id); int efx_init_mae(struct efx_nic *efx); -- cgit v1.2.3 From f1363154c47468725611f264fc2e50833800dc3b Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 8 Jun 2023 17:42:33 +0100 Subject: sfc: MAE functions to create/update/delete encap headers Besides the raw header data, also pass the tunnel type, so that the hardware knows it needs to update the IP Total Length and UDP Length fields (and corresponding checksums) for each packet. Also, populate the ENCAP_HEADER_ID field in efx_mae_alloc_action_set() with the fw_id returned from efx_mae_allocate_encap_md(). Reviewed-by: Pieter Jansen van Vuuren Signed-off-by: Edward Cree Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/mae.c | 90 +++++++++++++++++++++++++++++++++++++++++- drivers/net/ethernet/sfc/mae.h | 7 ++++ 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c index 4eef5d18817a..0cab508f2f9d 100644 --- a/drivers/net/ethernet/sfc/mae.c +++ b/drivers/net/ethernet/sfc/mae.c @@ -15,6 +15,7 @@ #include "mcdi.h" #include "mcdi_pcol.h" #include "mcdi_pcol_mae.h" +#include "tc_encap_actions.h" int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label) { @@ -610,6 +611,87 @@ static int efx_mae_encap_type_to_mae_type(enum efx_encap_type type) } } +int efx_mae_allocate_encap_md(struct efx_nic *efx, + struct efx_tc_encap_action *encap) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(EFX_TC_MAX_ENCAP_HDR)); + MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN); + size_t inlen, outlen; + int rc; + + rc = efx_mae_encap_type_to_mae_type(encap->type); + if (rc < 0) + return rc; + MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, rc); + inlen = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(encap->encap_hdr_len); + if (WARN_ON(inlen > sizeof(inbuf))) /* can't happen */ + return -EINVAL; + memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA), + encap->encap_hdr, + encap->encap_hdr_len); + rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_ALLOC, inbuf, + inlen, outbuf, sizeof(outbuf), &outlen); + if (rc) + return rc; + if (outlen < sizeof(outbuf)) + return -EIO; + encap->fw_id = MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID); + return 0; +} + +int efx_mae_update_encap_md(struct efx_nic *efx, + struct efx_tc_encap_action *encap) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(EFX_TC_MAX_ENCAP_HDR)); + size_t inlen; + int rc; + + rc = efx_mae_encap_type_to_mae_type(encap->type); + if (rc < 0) + return rc; + MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_ENCAP_TYPE, rc); + MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_EH_ID, + encap->fw_id); + inlen = MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(encap->encap_hdr_len); + if (WARN_ON(inlen > sizeof(inbuf))) /* can't happen */ + return -EINVAL; + memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_HDR_DATA), + encap->encap_hdr, + encap->encap_hdr_len); + + BUILD_BUG_ON(MC_CMD_MAE_ENCAP_HEADER_UPDATE_OUT_LEN != 0); + return efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_UPDATE, inbuf, + inlen, NULL, 0, NULL); +} + +int efx_mae_free_encap_md(struct efx_nic *efx, + struct efx_tc_encap_action *encap) +{ + MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1)); + MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1)); + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_FREE_IN_EH_ID, encap->fw_id); + rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_FREE, inbuf, + sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); + if (rc) + return rc; + if (outlen < sizeof(outbuf)) + return -EIO; + /* FW freed a different ID than we asked for, should also never happen. + * Warn because it means we've now got a different idea to the FW of + * what encap_mds exist, which could cause mayhem later. + */ + if (WARN_ON(MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) != encap->fw_id)) + return -EIO; + /* We're probably about to free @encap, but let's just make sure its + * fw_id is blatted so that it won't look valid if it leaks out. + */ + encap->fw_id = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL; + return 0; +} + int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id) { struct ef100_nic_data *nic_data = efx->nic_data; @@ -833,8 +915,12 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE, act->vlan_proto[1]); } - MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, - MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); + if (act->encap_md) + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, + act->encap_md->fw_id); + else + MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, + MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); if (act->deliver) MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER, act->dest_mport); diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h index c542aab43ea1..24abfe509690 100644 --- a/drivers/net/ethernet/sfc/mae.h +++ b/drivers/net/ethernet/sfc/mae.h @@ -90,6 +90,13 @@ int efx_mae_check_encap_type_supported(struct efx_nic *efx, int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt); int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt); +int efx_mae_allocate_encap_md(struct efx_nic *efx, + struct efx_tc_encap_action *encap); +int efx_mae_update_encap_md(struct efx_nic *efx, + struct efx_tc_encap_action *encap); +int efx_mae_free_encap_md(struct efx_nic *efx, + struct efx_tc_encap_action *encap); + int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act); int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id); -- cgit v1.2.3 From 7e5e7d800011adf4aeda615f8a1bc31c0c1e2bb9 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 8 Jun 2023 17:42:34 +0100 Subject: sfc: neighbour lookup for TC encap action offload For each neighbour we're interested in, create a struct efx_neigh_binder object which has a list of all the encap_actions using it. When we receive a neighbouring update (through the netevent notifier), find the corresponding efx_neigh_binder and update all its users. Since the actual generation of encap headers is still only a stub, the resulting rules still get left on fallback actions. Signed-off-by: Edward Cree Reviewed-by: Simon Horman Reviewed-by: Pieter Jansen van Vuuren Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/ef100_netdev.c | 34 +++ drivers/net/ethernet/sfc/net_driver.h | 3 + drivers/net/ethernet/sfc/tc.c | 12 +- drivers/net/ethernet/sfc/tc.h | 7 + drivers/net/ethernet/sfc/tc_bindings.c | 13 + drivers/net/ethernet/sfc/tc_bindings.h | 2 + drivers/net/ethernet/sfc/tc_encap_actions.c | 448 +++++++++++++++++++++++++++- drivers/net/ethernet/sfc/tc_encap_actions.h | 56 ++++ 8 files changed, 569 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c index 274f3a2562ad..7f7d560cb2b4 100644 --- a/drivers/net/ethernet/sfc/ef100_netdev.c +++ b/drivers/net/ethernet/sfc/ef100_netdev.c @@ -24,6 +24,7 @@ #include "rx_common.h" #include "ef100_sriov.h" #include "tc_bindings.h" +#include "tc_encap_actions.h" #include "efx_devlink.h" static void ef100_update_name(struct efx_nic *efx) @@ -300,14 +301,38 @@ int ef100_netdev_event(struct notifier_block *this, { struct efx_nic *efx = container_of(this, struct efx_nic, netdev_notifier); struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); + struct ef100_nic_data *nic_data = efx->nic_data; + int err; if (efx->net_dev == net_dev && (event == NETDEV_CHANGENAME || event == NETDEV_REGISTER)) ef100_update_name(efx); + if (!nic_data->grp_mae) + return NOTIFY_DONE; + err = efx_tc_netdev_event(efx, event, net_dev); + if (err & NOTIFY_STOP_MASK) + return err; + return NOTIFY_DONE; } +static int ef100_netevent_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct efx_nic *efx = container_of(this, struct efx_nic, netevent_notifier); + struct ef100_nic_data *nic_data = efx->nic_data; + int err; + + if (!nic_data->grp_mae) + return NOTIFY_DONE; + err = efx_tc_netevent_event(efx, event, ptr); + if (err & NOTIFY_STOP_MASK) + return err; + + return NOTIFY_DONE; +}; + static int ef100_register_netdev(struct efx_nic *efx) { struct net_device *net_dev = efx->net_dev; @@ -367,6 +392,7 @@ void ef100_remove_netdev(struct efx_probe_data *probe_data) rtnl_unlock(); unregister_netdevice_notifier(&efx->netdev_notifier); + unregister_netevent_notifier(&efx->netevent_notifier); #if defined(CONFIG_SFC_SRIOV) if (!efx->type->is_vf) efx_ef100_pci_sriov_disable(efx, true); @@ -487,6 +513,14 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data) goto fail; } + efx->netevent_notifier.notifier_call = ef100_netevent_event; + rc = register_netevent_notifier(&efx->netevent_notifier); + if (rc) { + netif_err(efx, probe, efx->net_dev, + "Failed to register netevent notifier, rc=%d\n", rc); + goto fail; + } + efx_probe_devlink_unlock(efx); return rc; fail: diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index fcd51d3992fa..a7a22b019794 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "enum.h" #include "bitfield.h" @@ -996,6 +997,7 @@ struct efx_mae; * @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their * xdp_rxq_info structures? * @netdev_notifier: Netdevice notifier. + * @netevent_notifier: Netevent notifier (for neighbour updates). * @tc: state for TC offload (EF100). * @devlink: reference to devlink structure owned by this device * @dl_port: devlink port associated with the PF @@ -1183,6 +1185,7 @@ struct efx_nic { bool xdp_rxq_info_failed; struct notifier_block netdev_notifier; + struct notifier_block netevent_notifier; struct efx_tc_state *tc; struct devlink *devlink; diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 4177feced3e6..77acdb60381e 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -34,8 +34,8 @@ enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev) * May return NULL for the PF (us), or an error pointer for a device that * isn't supported as a TC offload endpoint */ -static struct efx_rep *efx_tc_flower_lookup_efv(struct efx_nic *efx, - struct net_device *dev) +struct efx_rep *efx_tc_flower_lookup_efv(struct efx_nic *efx, + struct net_device *dev) { struct efx_rep *efv; @@ -71,7 +71,7 @@ static s64 efx_tc_flower_internal_mport(struct efx_nic *efx, struct efx_rep *efv } /* Convert a driver-internal vport ID into an external device (wire or VF) */ -static s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv) +s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv) { u32 mport; @@ -112,8 +112,10 @@ static void efx_tc_free_action_set(struct efx_nic *efx, } if (act->count) efx_tc_flower_put_counter_index(efx, act->count); - if (act->encap_md) + if (act->encap_md) { + list_del(&act->encap_user); efx_tc_flower_release_encap_md(efx, act->encap_md); + } kfree(act); } @@ -1115,6 +1117,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, goto release; } act->encap_md = encap; + list_add_tail(&act->encap_user, &encap->users); act->dest_mport = encap->dest_mport; act->deliver = 1; rc = efx_mae_alloc_action_set(efx, act); @@ -1123,6 +1126,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, goto release; } list_add_tail(&act->list, &rule->acts.list); + act->user = &rule->acts; act = NULL; if (fa->id == FLOW_ACTION_REDIRECT) break; /* end of the line */ diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h index 5a8f701b05c5..607429f8bb28 100644 --- a/drivers/net/ethernet/sfc/tc.h +++ b/drivers/net/ethernet/sfc/tc.h @@ -36,6 +36,8 @@ struct efx_tc_action_set { __be16 vlan_proto[2]; /* Ethertypes for vlan_push */ struct efx_tc_counter_index *count; struct efx_tc_encap_action *encap_md; /* entry in tc_encap_ht table */ + struct list_head encap_user; /* entry on encap_md->users list */ + struct efx_tc_action_set_list *user; /* Only populated if encap_md */ u32 dest_mport; u32 fw_id; /* index of this entry in firmware actions table */ struct list_head list; @@ -151,6 +153,7 @@ enum efx_tc_rule_prios { * @encap_ht: Hashtable of TC encap actions * @encap_match_ht: Hashtable of TC encap matches * @match_action_ht: Hashtable of TC match-action rules + * @neigh_ht: Hashtable of neighbour watches (&struct efx_neigh_binder) * @reps_mport_id: MAE port allocated for representor RX * @reps_filter_uc: VNIC filter for representor unicast RX (promisc) * @reps_filter_mc: VNIC filter for representor multicast RX (allmulti) @@ -181,6 +184,7 @@ struct efx_tc_state { struct rhashtable encap_ht; struct rhashtable encap_match_ht; struct rhashtable match_action_ht; + struct rhashtable neigh_ht; u32 reps_mport_id, reps_mport_vport_id; s32 reps_filter_uc, reps_filter_mc; bool flush_counters; @@ -201,6 +205,9 @@ struct efx_tc_state { struct efx_rep; enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev); +struct efx_rep *efx_tc_flower_lookup_efv(struct efx_nic *efx, + struct net_device *dev); +s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv); int efx_tc_configure_default_rule_rep(struct efx_rep *efv); void efx_tc_deconfigure_default_rule(struct efx_nic *efx, struct efx_tc_flow_rule *rule); diff --git a/drivers/net/ethernet/sfc/tc_bindings.c b/drivers/net/ethernet/sfc/tc_bindings.c index c18d64519c2d..1b79c535c54e 100644 --- a/drivers/net/ethernet/sfc/tc_bindings.c +++ b/drivers/net/ethernet/sfc/tc_bindings.c @@ -10,6 +10,7 @@ #include "tc_bindings.h" #include "tc.h" +#include "tc_encap_actions.h" struct efx_tc_block_binding { struct list_head list; @@ -226,3 +227,15 @@ int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type, return -EOPNOTSUPP; } + +int efx_tc_netdev_event(struct efx_nic *efx, unsigned long event, + struct net_device *net_dev) +{ + if (efx->type->is_vf) + return NOTIFY_DONE; + + if (event == NETDEV_UNREGISTER) + efx_tc_unregister_egdev(efx, net_dev); + + return NOTIFY_OK; +} diff --git a/drivers/net/ethernet/sfc/tc_bindings.h b/drivers/net/ethernet/sfc/tc_bindings.h index c210bb09150e..095ddeb59eb3 100644 --- a/drivers/net/ethernet/sfc/tc_bindings.h +++ b/drivers/net/ethernet/sfc/tc_bindings.h @@ -26,4 +26,6 @@ int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch, void *cb_priv, enum tc_setup_type type, void *type_data, void *data, void (*cleanup)(struct flow_block_cb *block_cb)); +int efx_tc_netdev_event(struct efx_nic *efx, unsigned long event, + struct net_device *net_dev); #endif /* EFX_TC_BINDINGS_H */ diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c index c41493e659a3..c1bd7d468343 100644 --- a/drivers/net/ethernet/sfc/tc_encap_actions.c +++ b/drivers/net/ethernet/sfc/tc_encap_actions.c @@ -13,6 +13,14 @@ #include "mae.h" #include #include +#include +#include + +static const struct rhashtable_params efx_neigh_ht_params = { + .key_len = offsetof(struct efx_neigh_binder, ha), + .key_offset = 0, + .head_offset = offsetof(struct efx_neigh_binder, linkage), +}; static const struct rhashtable_params efx_tc_encap_ht_params = { .key_len = offsetofend(struct efx_tc_encap_action, key), @@ -28,9 +36,32 @@ static void efx_tc_encap_free(void *ptr, void *__unused) kfree(enc); } +static void efx_neigh_free(void *ptr, void *__unused) +{ + struct efx_neigh_binder *neigh = ptr; + + WARN_ON(refcount_read(&neigh->ref)); + WARN_ON(!list_empty(&neigh->users)); + put_net_track(neigh->net, &neigh->ns_tracker); + netdev_put(neigh->egdev, &neigh->dev_tracker); + kfree(neigh); +} + int efx_tc_init_encap_actions(struct efx_nic *efx) { - return rhashtable_init(&efx->tc->encap_ht, &efx_tc_encap_ht_params); + int rc; + + rc = rhashtable_init(&efx->tc->neigh_ht, &efx_neigh_ht_params); + if (rc < 0) + goto fail_neigh_ht; + rc = rhashtable_init(&efx->tc->encap_ht, &efx_tc_encap_ht_params); + if (rc < 0) + goto fail_encap_ht; + return 0; +fail_encap_ht: + rhashtable_destroy(&efx->tc->neigh_ht); +fail_neigh_ht: + return rc; } /* Only call this in init failure teardown. @@ -39,11 +70,337 @@ int efx_tc_init_encap_actions(struct efx_nic *efx) void efx_tc_destroy_encap_actions(struct efx_nic *efx) { rhashtable_destroy(&efx->tc->encap_ht); + rhashtable_destroy(&efx->tc->neigh_ht); } void efx_tc_fini_encap_actions(struct efx_nic *efx) { rhashtable_free_and_destroy(&efx->tc->encap_ht, efx_tc_encap_free, NULL); + rhashtable_free_and_destroy(&efx->tc->neigh_ht, efx_neigh_free, NULL); +} + +static void efx_neigh_update(struct work_struct *work); + +static int efx_bind_neigh(struct efx_nic *efx, + struct efx_tc_encap_action *encap, struct net *net, + struct netlink_ext_ack *extack) +{ + struct efx_neigh_binder *neigh, *old; + struct flowi6 flow6 = {}; + struct flowi4 flow4 = {}; + int rc; + + /* GCC stupidly thinks that only values explicitly listed in the enum + * definition can _possibly_ be sensible case values, so without this + * cast it complains about the IPv6 versions. + */ + switch ((int)encap->type) { + case EFX_ENCAP_TYPE_VXLAN: + case EFX_ENCAP_TYPE_GENEVE: + flow4.flowi4_proto = IPPROTO_UDP; + flow4.fl4_dport = encap->key.tp_dst; + flow4.flowi4_tos = encap->key.tos; + flow4.daddr = encap->key.u.ipv4.dst; + flow4.saddr = encap->key.u.ipv4.src; + break; + case EFX_ENCAP_TYPE_VXLAN | EFX_ENCAP_FLAG_IPV6: + case EFX_ENCAP_TYPE_GENEVE | EFX_ENCAP_FLAG_IPV6: + flow6.flowi6_proto = IPPROTO_UDP; + flow6.fl6_dport = encap->key.tp_dst; + flow6.flowlabel = ip6_make_flowinfo(encap->key.tos, + encap->key.label); + flow6.daddr = encap->key.u.ipv6.dst; + flow6.saddr = encap->key.u.ipv6.src; + break; + default: + NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported encap type %d", + (int)encap->type); + return -EOPNOTSUPP; + } + + neigh = kzalloc(sizeof(*neigh), GFP_KERNEL_ACCOUNT); + if (!neigh) + return -ENOMEM; + neigh->net = get_net_track(net, &neigh->ns_tracker, GFP_KERNEL_ACCOUNT); + neigh->dst_ip = flow4.daddr; + neigh->dst_ip6 = flow6.daddr; + + old = rhashtable_lookup_get_insert_fast(&efx->tc->neigh_ht, + &neigh->linkage, + efx_neigh_ht_params); + if (old) { + /* don't need our new entry */ + put_net_track(neigh->net, &neigh->ns_tracker); + kfree(neigh); + if (!refcount_inc_not_zero(&old->ref)) + return -EAGAIN; + /* existing entry found, ref taken */ + neigh = old; + } else { + /* New entry. We need to initiate a lookup */ + struct neighbour *n; + struct rtable *rt; + + if (encap->type & EFX_ENCAP_FLAG_IPV6) { +#if IS_ENABLED(CONFIG_IPV6) + struct dst_entry *dst; + + dst = ipv6_stub->ipv6_dst_lookup_flow(net, NULL, &flow6, + NULL); + rc = PTR_ERR_OR_ZERO(dst); + if (rc) { + NL_SET_ERR_MSG_MOD(extack, "Failed to lookup route for IPv6 encap"); + goto out_free; + } + neigh->egdev = dst->dev; + netdev_hold(neigh->egdev, &neigh->dev_tracker, + GFP_KERNEL_ACCOUNT); + neigh->ttl = ip6_dst_hoplimit(dst); + n = dst_neigh_lookup(dst, &flow6.daddr); + dst_release(dst); +#else + /* We shouldn't ever get here, because if IPv6 isn't + * enabled how did someone create an IPv6 tunnel_key? + */ + rc = -EOPNOTSUPP; + NL_SET_ERR_MSG_MOD(extack, "No IPv6 support (neigh bind)"); +#endif + } else { + rt = ip_route_output_key(net, &flow4); + if (IS_ERR_OR_NULL(rt)) { + rc = PTR_ERR_OR_ZERO(rt); + if (!rc) + rc = -EIO; + NL_SET_ERR_MSG_MOD(extack, "Failed to lookup route for encap"); + goto out_free; + } + neigh->egdev = rt->dst.dev; + netdev_hold(neigh->egdev, &neigh->dev_tracker, + GFP_KERNEL_ACCOUNT); + neigh->ttl = ip4_dst_hoplimit(&rt->dst); + n = dst_neigh_lookup(&rt->dst, &flow4.daddr); + ip_rt_put(rt); + } + if (!n) { + rc = -ENETUNREACH; + NL_SET_ERR_MSG_MOD(extack, "Failed to lookup neighbour for encap"); + netdev_put(neigh->egdev, &neigh->dev_tracker); + goto out_free; + } + refcount_set(&neigh->ref, 1); + INIT_LIST_HEAD(&neigh->users); + read_lock_bh(&n->lock); + ether_addr_copy(neigh->ha, n->ha); + neigh->n_valid = n->nud_state & NUD_VALID; + read_unlock_bh(&n->lock); + rwlock_init(&neigh->lock); + INIT_WORK(&neigh->work, efx_neigh_update); + neigh->efx = efx; + neigh->used = jiffies; + if (!neigh->n_valid) + /* Prod ARP to find us a neighbour */ + neigh_event_send(n, NULL); + neigh_release(n); + } + /* Add us to this neigh */ + encap->neigh = neigh; + list_add_tail(&encap->list, &neigh->users); + return 0; + +out_free: + /* cleanup common to several error paths */ + rhashtable_remove_fast(&efx->tc->neigh_ht, &neigh->linkage, + efx_neigh_ht_params); + synchronize_rcu(); + put_net_track(net, &neigh->ns_tracker); + kfree(neigh); + return rc; +} + +static void efx_free_neigh(struct efx_neigh_binder *neigh) +{ + struct efx_nic *efx = neigh->efx; + + rhashtable_remove_fast(&efx->tc->neigh_ht, &neigh->linkage, + efx_neigh_ht_params); + synchronize_rcu(); + netdev_put(neigh->egdev, &neigh->dev_tracker); + put_net_track(neigh->net, &neigh->ns_tracker); + kfree(neigh); +} + +static void efx_release_neigh(struct efx_nic *efx, + struct efx_tc_encap_action *encap) +{ + struct efx_neigh_binder *neigh = encap->neigh; + + if (!neigh) + return; + list_del(&encap->list); + encap->neigh = NULL; + if (!refcount_dec_and_test(&neigh->ref)) + return; /* still in use */ + efx_free_neigh(neigh); +} + +static void efx_gen_encap_header(struct efx_tc_encap_action *encap) +{ + /* stub for now */ + encap->n_valid = false; + memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr)); + encap->encap_hdr_len = ETH_HLEN; +} + +static void efx_tc_update_encap(struct efx_nic *efx, + struct efx_tc_encap_action *encap) +{ + struct efx_tc_action_set_list *acts, *fallback; + struct efx_tc_flow_rule *rule; + struct efx_tc_action_set *act; + int rc; + + if (encap->n_valid) { + /* Make sure no rules are using this encap while we change it */ + list_for_each_entry(act, &encap->users, encap_user) { + acts = act->user; + if (WARN_ON(!acts)) /* can't happen */ + continue; + rule = container_of(acts, struct efx_tc_flow_rule, acts); + if (rule->fallback) + fallback = rule->fallback; + else /* fallback fallback: deliver to PF */ + fallback = &efx->tc->facts.pf; + rc = efx_mae_update_rule(efx, fallback->fw_id, + rule->fw_id); + if (rc) + netif_err(efx, drv, efx->net_dev, + "Failed to update (f) rule %08x rc %d\n", + rule->fw_id, rc); + else + netif_dbg(efx, drv, efx->net_dev, "Updated (f) rule %08x\n", + rule->fw_id); + } + } + + if (encap->neigh) { + read_lock_bh(&encap->neigh->lock); + efx_gen_encap_header(encap); + read_unlock_bh(&encap->neigh->lock); + } else { + encap->n_valid = false; + memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr)); + encap->encap_hdr_len = ETH_HLEN; + } + + rc = efx_mae_update_encap_md(efx, encap); + if (rc) { + netif_err(efx, drv, efx->net_dev, + "Failed to update encap hdr %08x rc %d\n", + encap->fw_id, rc); + return; + } + netif_dbg(efx, drv, efx->net_dev, "Updated encap hdr %08x\n", + encap->fw_id); + if (!encap->n_valid) + return; + /* Update rule users: use the action if they are now ready */ + list_for_each_entry(act, &encap->users, encap_user) { + acts = act->user; + if (WARN_ON(!acts)) /* can't happen */ + continue; + rule = container_of(acts, struct efx_tc_flow_rule, acts); + if (!efx_tc_check_ready(efx, rule)) + continue; + rc = efx_mae_update_rule(efx, acts->fw_id, rule->fw_id); + if (rc) + netif_err(efx, drv, efx->net_dev, + "Failed to update rule %08x rc %d\n", + rule->fw_id, rc); + else + netif_dbg(efx, drv, efx->net_dev, "Updated rule %08x\n", + rule->fw_id); + } +} + +static void efx_neigh_update(struct work_struct *work) +{ + struct efx_neigh_binder *neigh = container_of(work, struct efx_neigh_binder, work); + struct efx_tc_encap_action *encap; + struct efx_nic *efx = neigh->efx; + + mutex_lock(&efx->tc->mutex); + list_for_each_entry(encap, &neigh->users, list) + efx_tc_update_encap(neigh->efx, encap); + /* release ref taken in efx_neigh_event() */ + if (refcount_dec_and_test(&neigh->ref)) + efx_free_neigh(neigh); + mutex_unlock(&efx->tc->mutex); +} + +static int efx_neigh_event(struct efx_nic *efx, struct neighbour *n) +{ + struct efx_neigh_binder keys = {NULL}, *neigh; + bool n_valid, ipv6 = false; + char ha[ETH_ALEN]; + size_t keysize; + + if (WARN_ON(!efx->tc)) + return NOTIFY_DONE; + + if (n->tbl == &arp_tbl) { + keysize = sizeof(keys.dst_ip); +#if IS_ENABLED(CONFIG_IPV6) + } else if (n->tbl == ipv6_stub->nd_tbl) { + ipv6 = true; + keysize = sizeof(keys.dst_ip6); +#endif + } else { + return NOTIFY_DONE; + } + if (!n->parms) { + netif_warn(efx, drv, efx->net_dev, "neigh_event with no parms!\n"); + return NOTIFY_DONE; + } + keys.net = read_pnet(&n->parms->net); + if (n->tbl->key_len != keysize) { + netif_warn(efx, drv, efx->net_dev, "neigh_event with bad key_len %u\n", + n->tbl->key_len); + return NOTIFY_DONE; + } + read_lock_bh(&n->lock); /* Get a consistent view */ + memcpy(ha, n->ha, ETH_ALEN); + n_valid = (n->nud_state & NUD_VALID) && !n->dead; + read_unlock_bh(&n->lock); + if (ipv6) + memcpy(&keys.dst_ip6, n->primary_key, n->tbl->key_len); + else + memcpy(&keys.dst_ip, n->primary_key, n->tbl->key_len); + rcu_read_lock(); + neigh = rhashtable_lookup_fast(&efx->tc->neigh_ht, &keys, + efx_neigh_ht_params); + if (!neigh || neigh->dying) + /* We're not interested in this neighbour */ + goto done; + write_lock_bh(&neigh->lock); + if (n_valid == neigh->n_valid && !memcmp(ha, neigh->ha, ETH_ALEN)) { + write_unlock_bh(&neigh->lock); + /* Nothing has changed; no work to do */ + goto done; + } + neigh->n_valid = n_valid; + memcpy(neigh->ha, ha, ETH_ALEN); + write_unlock_bh(&neigh->lock); + if (refcount_inc_not_zero(&neigh->ref)) { + rcu_read_unlock(); + if (!schedule_work(&neigh->work)) + /* failed to schedule, release the ref we just took */ + if (refcount_dec_and_test(&neigh->ref)) + efx_free_neigh(neigh); + } else { +done: + rcu_read_unlock(); + } + return NOTIFY_DONE; } bool efx_tc_check_ready(struct efx_nic *efx, struct efx_tc_flow_rule *rule) @@ -54,7 +411,7 @@ bool efx_tc_check_ready(struct efx_nic *efx, struct efx_tc_flow_rule *rule) * neighbour info for the outer Ethernet header. */ list_for_each_entry(act, &rule->acts.list, list) - if (act->encap_md) /* neigh bindings not implemented yet */ + if (act->encap_md && !act->encap_md->n_valid) return false; return true; } @@ -65,6 +422,7 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md( { enum efx_encap_type type = efx_tc_indr_netdev_type(egdev); struct efx_tc_encap_action *encap, *old; + struct efx_rep *to_efv; s64 rc; if (type == EFX_ENCAP_TYPE_NONE) { @@ -98,6 +456,7 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md( return ERR_PTR(-ENOMEM); encap->type = type; encap->key = info->key; + INIT_LIST_HEAD(&encap->users); old = rhashtable_lookup_get_insert_fast(&efx->tc->encap_ht, &encap->linkage, efx_tc_encap_ht_params); @@ -110,9 +469,42 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md( return old; } + rc = efx_bind_neigh(efx, encap, dev_net(egdev), extack); + if (rc < 0) + goto out_remove; + to_efv = efx_tc_flower_lookup_efv(efx, encap->neigh->egdev); + if (IS_ERR(to_efv)) { + /* neigh->egdev isn't ours */ + NL_SET_ERR_MSG_MOD(extack, "Tunnel egress device not on switch"); + rc = PTR_ERR(to_efv); + goto out_release; + } + rc = efx_tc_flower_external_mport(efx, to_efv); + if (rc < 0) { + NL_SET_ERR_MSG_MOD(extack, "Failed to identify tunnel egress m-port"); + goto out_release; + } + encap->dest_mport = rc; + read_lock_bh(&encap->neigh->lock); + efx_gen_encap_header(encap); + read_unlock_bh(&encap->neigh->lock); + + rc = efx_mae_allocate_encap_md(efx, encap); + if (rc < 0) { + NL_SET_ERR_MSG_MOD(extack, "Failed to write tunnel header to hw"); + goto out_release; + } + /* ref and return */ refcount_set(&encap->ref, 1); return encap; +out_release: + efx_release_neigh(efx, encap); +out_remove: + rhashtable_remove_fast(&efx->tc->encap_ht, &encap->linkage, + efx_tc_encap_ht_params); + kfree(encap); + return ERR_PTR(rc); } void efx_tc_flower_release_encap_md(struct efx_nic *efx, @@ -120,7 +512,59 @@ void efx_tc_flower_release_encap_md(struct efx_nic *efx, { if (!refcount_dec_and_test(&encap->ref)) return; /* still in use */ + efx_release_neigh(efx, encap); rhashtable_remove_fast(&efx->tc->encap_ht, &encap->linkage, efx_tc_encap_ht_params); + efx_mae_free_encap_md(efx, encap); kfree(encap); } + +static void efx_tc_remove_neigh_users(struct efx_nic *efx, struct efx_neigh_binder *neigh) +{ + struct efx_tc_encap_action *encap, *next; + + list_for_each_entry_safe(encap, next, &neigh->users, list) { + /* Should cause neigh usage count to fall to zero, freeing it */ + efx_release_neigh(efx, encap); + /* The encap has lost its neigh, so it's now unready */ + efx_tc_update_encap(efx, encap); + } +} + +void efx_tc_unregister_egdev(struct efx_nic *efx, struct net_device *net_dev) +{ + struct efx_neigh_binder *neigh; + struct rhashtable_iter walk; + + mutex_lock(&efx->tc->mutex); + rhashtable_walk_enter(&efx->tc->neigh_ht, &walk); + rhashtable_walk_start(&walk); + while ((neigh = rhashtable_walk_next(&walk)) != NULL) { + if (IS_ERR(neigh)) + continue; + if (neigh->egdev != net_dev) + continue; + neigh->dying = true; + rhashtable_walk_stop(&walk); + synchronize_rcu(); /* Make sure any updates see dying flag */ + efx_tc_remove_neigh_users(efx, neigh); /* might sleep */ + rhashtable_walk_start(&walk); + } + rhashtable_walk_stop(&walk); + rhashtable_walk_exit(&walk); + mutex_unlock(&efx->tc->mutex); +} + +int efx_tc_netevent_event(struct efx_nic *efx, unsigned long event, + void *ptr) +{ + if (efx->type->is_vf) + return NOTIFY_DONE; + + switch (event) { + case NETEVENT_NEIGH_UPDATE: + return efx_neigh_event(efx, ptr); + default: + return NOTIFY_DONE; + } +} diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.h b/drivers/net/ethernet/sfc/tc_encap_actions.h index 1a3679e81f09..4d755fb92daf 100644 --- a/drivers/net/ethernet/sfc/tc_encap_actions.h +++ b/drivers/net/ethernet/sfc/tc_encap_actions.h @@ -15,6 +15,54 @@ #include #include +/** + * struct efx_neigh_binder - driver state for a neighbour entry + * @net: the network namespace in which this neigh resides + * @dst_ip: the IPv4 destination address resolved by this neigh + * @dst_ip6: the IPv6 destination address resolved by this neigh + * @ha: the hardware (Ethernet) address of the neighbour + * @n_valid: true if the neighbour is in NUD_VALID state + * @lock: protects @ha and @n_valid + * @ttl: Time To Live associated with the route used + * @dying: set when egdev is going away, to skip further updates + * @egdev: egress device from the route lookup. Holds a reference + * @dev_tracker: reference tracker entry for @egdev + * @ns_tracker: reference tracker entry for @ns + * @ref: counts encap actions referencing this entry + * @used: jiffies of last time traffic hit any encap action using this. + * When counter reads update this, a new neighbour event is sent to + * indicate that the neighbour entry is still in use. + * @users: list of &struct efx_tc_encap_action + * @linkage: entry in efx->neigh_ht (keys are @net, @dst_ip, @dst_ip6). + * @work: processes neighbour state changes, updates the encap actions + * @efx: owning NIC instance. + * + * Associates a neighbour entry with the encap actions that are + * interested in it, allowing the latter to be updated when the + * neighbour details change. + * Whichever of @dst_ip and @dst_ip6 is not in use will be all-zeroes, + * this distinguishes IPv4 from IPv6 entries. + */ +struct efx_neigh_binder { + struct net *net; + __be32 dst_ip; + struct in6_addr dst_ip6; + char ha[ETH_ALEN]; + bool n_valid; + rwlock_t lock; + u8 ttl; + bool dying; + struct net_device *egdev; + netdevice_tracker dev_tracker; + netns_tracker ns_tracker; + refcount_t ref; + unsigned long used; + struct list_head users; + struct rhash_head linkage; + struct work_struct work; + struct efx_nic *efx; +}; + /* This limit is arbitrary; current hardware (SN1022) handles encap headers * of up to 126 bytes, but that limit is not enshrined in the MCDI protocol. */ @@ -24,7 +72,11 @@ struct efx_tc_encap_action { struct ip_tunnel_key key; /* 52 bytes */ u32 dest_mport; /* is copied into struct efx_tc_action_set */ u8 encap_hdr_len; + bool n_valid; u8 encap_hdr[EFX_TC_MAX_ENCAP_HDR]; + struct efx_neigh_binder *neigh; + struct list_head list; /* entry on neigh->users list */ + struct list_head users; /* action sets using this encap_md */ struct rhash_head linkage; /* efx->tc_encap_ht */ refcount_t ref; u32 fw_id; /* index of this entry in firmware encap table */ @@ -44,4 +96,8 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md( void efx_tc_flower_release_encap_md(struct efx_nic *efx, struct efx_tc_encap_action *encap); +void efx_tc_unregister_egdev(struct efx_nic *efx, struct net_device *net_dev); +int efx_tc_netevent_event(struct efx_nic *efx, unsigned long event, + void *ptr); + #endif /* EFX_TC_ENCAP_ACTIONS_H */ -- cgit v1.2.3 From a1e82162af0b8ae9e65320ca405c6327edb99648 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 8 Jun 2023 17:42:35 +0100 Subject: sfc: generate encap headers for TC offload Support constructing VxLAN and GENEVE headers, on either IPv4 or IPv6, using the neighbouring information obtained in encap->neigh to populate the Ethernet header. Note that the ef100 hardware does not insert UDP checksums when performing encap, so for IPv6 the remote endpoint will need to be configured with udp6zerocsumrx or equivalent. Signed-off-by: Edward Cree Reviewed-by: Simon Horman Reviewed-by: Pieter Jansen van Vuuren Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/tc_encap_actions.c | 194 ++++++++++++++++++++++++++-- 1 file changed, 185 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c index c1bd7d468343..aac259528e73 100644 --- a/drivers/net/ethernet/sfc/tc_encap_actions.c +++ b/drivers/net/ethernet/sfc/tc_encap_actions.c @@ -243,12 +243,183 @@ static void efx_release_neigh(struct efx_nic *efx, efx_free_neigh(neigh); } -static void efx_gen_encap_header(struct efx_tc_encap_action *encap) +static void efx_gen_tun_header_eth(struct efx_tc_encap_action *encap, u16 proto) { - /* stub for now */ - encap->n_valid = false; - memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr)); - encap->encap_hdr_len = ETH_HLEN; + struct efx_neigh_binder *neigh = encap->neigh; + struct ethhdr *eth; + + encap->encap_hdr_len = sizeof(*eth); + eth = (struct ethhdr *)encap->encap_hdr; + + if (encap->neigh->n_valid) + ether_addr_copy(eth->h_dest, neigh->ha); + else + eth_zero_addr(eth->h_dest); + ether_addr_copy(eth->h_source, neigh->egdev->dev_addr); + eth->h_proto = htons(proto); +} + +static void efx_gen_tun_header_ipv4(struct efx_tc_encap_action *encap, u8 ipproto, u8 len) +{ + struct efx_neigh_binder *neigh = encap->neigh; + struct ip_tunnel_key *key = &encap->key; + struct iphdr *ip; + + ip = (struct iphdr *)(encap->encap_hdr + encap->encap_hdr_len); + encap->encap_hdr_len += sizeof(*ip); + + ip->daddr = key->u.ipv4.dst; + ip->saddr = key->u.ipv4.src; + ip->ttl = neigh->ttl; + ip->protocol = ipproto; + ip->version = 0x4; + ip->ihl = 0x5; + ip->tot_len = cpu_to_be16(ip->ihl * 4 + len); + ip_send_check(ip); +} + +#ifdef CONFIG_IPV6 +static void efx_gen_tun_header_ipv6(struct efx_tc_encap_action *encap, u8 ipproto, u8 len) +{ + struct efx_neigh_binder *neigh = encap->neigh; + struct ip_tunnel_key *key = &encap->key; + struct ipv6hdr *ip; + + ip = (struct ipv6hdr *)(encap->encap_hdr + encap->encap_hdr_len); + encap->encap_hdr_len += sizeof(*ip); + + ip6_flow_hdr(ip, key->tos, key->label); + ip->daddr = key->u.ipv6.dst; + ip->saddr = key->u.ipv6.src; + ip->hop_limit = neigh->ttl; + ip->nexthdr = ipproto; + ip->version = 0x6; + ip->payload_len = cpu_to_be16(len); +} +#endif + +static void efx_gen_tun_header_udp(struct efx_tc_encap_action *encap, u8 len) +{ + struct ip_tunnel_key *key = &encap->key; + struct udphdr *udp; + + udp = (struct udphdr *)(encap->encap_hdr + encap->encap_hdr_len); + encap->encap_hdr_len += sizeof(*udp); + + udp->dest = key->tp_dst; + udp->len = cpu_to_be16(sizeof(*udp) + len); +} + +static void efx_gen_tun_header_vxlan(struct efx_tc_encap_action *encap) +{ + struct ip_tunnel_key *key = &encap->key; + struct vxlanhdr *vxlan; + + vxlan = (struct vxlanhdr *)(encap->encap_hdr + encap->encap_hdr_len); + encap->encap_hdr_len += sizeof(*vxlan); + + vxlan->vx_flags = VXLAN_HF_VNI; + vxlan->vx_vni = vxlan_vni_field(tunnel_id_to_key32(key->tun_id)); +} + +static void efx_gen_tun_header_geneve(struct efx_tc_encap_action *encap) +{ + struct ip_tunnel_key *key = &encap->key; + struct genevehdr *geneve; + u32 vni; + + geneve = (struct genevehdr *)(encap->encap_hdr + encap->encap_hdr_len); + encap->encap_hdr_len += sizeof(*geneve); + + geneve->proto_type = htons(ETH_P_TEB); + /* convert tun_id to host-endian so we can use host arithmetic to + * extract individual bytes. + */ + vni = ntohl(tunnel_id_to_key32(key->tun_id)); + geneve->vni[0] = vni >> 16; + geneve->vni[1] = vni >> 8; + geneve->vni[2] = vni; +} + +#define vxlan_header_l4_len (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) +#define vxlan4_header_len (sizeof(struct ethhdr) + sizeof(struct iphdr) + vxlan_header_l4_len) +static void efx_gen_vxlan_header_ipv4(struct efx_tc_encap_action *encap) +{ + BUILD_BUG_ON(sizeof(encap->encap_hdr) < vxlan4_header_len); + efx_gen_tun_header_eth(encap, ETH_P_IP); + efx_gen_tun_header_ipv4(encap, IPPROTO_UDP, vxlan_header_l4_len); + efx_gen_tun_header_udp(encap, sizeof(struct vxlanhdr)); + efx_gen_tun_header_vxlan(encap); +} + +#define geneve_header_l4_len (sizeof(struct udphdr) + sizeof(struct genevehdr)) +#define geneve4_header_len (sizeof(struct ethhdr) + sizeof(struct iphdr) + geneve_header_l4_len) +static void efx_gen_geneve_header_ipv4(struct efx_tc_encap_action *encap) +{ + BUILD_BUG_ON(sizeof(encap->encap_hdr) < geneve4_header_len); + efx_gen_tun_header_eth(encap, ETH_P_IP); + efx_gen_tun_header_ipv4(encap, IPPROTO_UDP, geneve_header_l4_len); + efx_gen_tun_header_udp(encap, sizeof(struct genevehdr)); + efx_gen_tun_header_geneve(encap); +} + +#ifdef CONFIG_IPV6 +#define vxlan6_header_len (sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + vxlan_header_l4_len) +static void efx_gen_vxlan_header_ipv6(struct efx_tc_encap_action *encap) +{ + BUILD_BUG_ON(sizeof(encap->encap_hdr) < vxlan6_header_len); + efx_gen_tun_header_eth(encap, ETH_P_IPV6); + efx_gen_tun_header_ipv6(encap, IPPROTO_UDP, vxlan_header_l4_len); + efx_gen_tun_header_udp(encap, sizeof(struct vxlanhdr)); + efx_gen_tun_header_vxlan(encap); +} + +#define geneve6_header_len (sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + geneve_header_l4_len) +static void efx_gen_geneve_header_ipv6(struct efx_tc_encap_action *encap) +{ + BUILD_BUG_ON(sizeof(encap->encap_hdr) < geneve6_header_len); + efx_gen_tun_header_eth(encap, ETH_P_IPV6); + efx_gen_tun_header_ipv6(encap, IPPROTO_UDP, geneve_header_l4_len); + efx_gen_tun_header_udp(encap, sizeof(struct genevehdr)); + efx_gen_tun_header_geneve(encap); +} +#endif + +static void efx_gen_encap_header(struct efx_nic *efx, + struct efx_tc_encap_action *encap) +{ + encap->n_valid = encap->neigh->n_valid; + + /* GCC stupidly thinks that only values explicitly listed in the enum + * definition can _possibly_ be sensible case values, so without this + * cast it complains about the IPv6 versions. + */ + switch ((int)encap->type) { + case EFX_ENCAP_TYPE_VXLAN: + efx_gen_vxlan_header_ipv4(encap); + break; + case EFX_ENCAP_TYPE_GENEVE: + efx_gen_geneve_header_ipv4(encap); + break; +#ifdef CONFIG_IPV6 + case EFX_ENCAP_TYPE_VXLAN | EFX_ENCAP_FLAG_IPV6: + efx_gen_vxlan_header_ipv6(encap); + break; + case EFX_ENCAP_TYPE_GENEVE | EFX_ENCAP_FLAG_IPV6: + efx_gen_geneve_header_ipv6(encap); + break; +#endif + default: + /* unhandled encap type, can't happen */ + if (net_ratelimit()) + netif_err(efx, drv, efx->net_dev, + "Bogus encap type %d, can't generate\n", + encap->type); + + /* Use fallback action. */ + encap->n_valid = false; + break; + } } static void efx_tc_update_encap(struct efx_nic *efx, @@ -282,14 +453,19 @@ static void efx_tc_update_encap(struct efx_nic *efx, } } + /* Make sure we don't leak arbitrary bytes on the wire; + * set an all-0s ethernet header. A successful call to + * efx_gen_encap_header() will overwrite this. + */ + memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr)); + encap->encap_hdr_len = ETH_HLEN; + if (encap->neigh) { read_lock_bh(&encap->neigh->lock); - efx_gen_encap_header(encap); + efx_gen_encap_header(efx, encap); read_unlock_bh(&encap->neigh->lock); } else { encap->n_valid = false; - memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr)); - encap->encap_hdr_len = ETH_HLEN; } rc = efx_mae_update_encap_md(efx, encap); @@ -486,7 +662,7 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md( } encap->dest_mport = rc; read_lock_bh(&encap->neigh->lock); - efx_gen_encap_header(encap); + efx_gen_encap_header(efx, encap); read_unlock_bh(&encap->neigh->lock); rc = efx_mae_allocate_encap_md(efx, encap); -- cgit v1.2.3 From dc510c6d2ecfff1faaf95b642c5fc01c86d6fdff Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 8 Jun 2023 11:20:06 +0900 Subject: net: renesas: rswitch: Use napi_gro_receive() in RX This hardware can receive multiple frames so that using napi_gro_receive() instead of netif_receive_skb() gets good performance of RX. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Maciej Fijalkowski Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index aace87139cea..7bb0a6d594a0 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -729,7 +729,7 @@ static bool rswitch_rx(struct net_device *ndev, int *quota) } skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, ndev); - netif_receive_skb(skb); + napi_gro_receive(&rdev->napi, skb); rdev->ndev->stats.rx_packets++; rdev->ndev->stats.rx_bytes += pkt_len; -- cgit v1.2.3 From c87bd91e34e1593584c3b309e8fead833c985855 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 8 Jun 2023 11:20:07 +0900 Subject: net: renesas: rswitch: Use hardware pause features Since this driver used the "global rate limiter" feature of GWCA, the TX performance of each port was reduced when multiple ports transmitted frames simultaneously. To improve performance, remove the use of the "global rate limiter" feature and use "hardware pause" features of the following: - "per priority pause" of GWCA - "global pause" of COMA Note that these features are not related to the ethernet PAUSE frame. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Maciej Fijalkowski Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/rswitch.c | 36 +++++++++++++--------------------- drivers/net/ethernet/renesas/rswitch.h | 7 +++++++ 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 7bb0a6d594a0..84f62c77eb8f 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -90,6 +90,11 @@ static int rswitch_bpool_config(struct rswitch_private *priv) return rswitch_reg_wait(priv->addr, CABPIRM, CABPIRM_BPR, CABPIRM_BPR); } +static void rswitch_coma_init(struct rswitch_private *priv) +{ + iowrite32(CABPPFLC_INIT_VALUE, priv->addr + CABPPFLC0); +} + /* R-Switch-2 block (TOP) */ static void rswitch_top_init(struct rswitch_private *priv) { @@ -156,24 +161,6 @@ static int rswitch_gwca_axi_ram_reset(struct rswitch_private *priv) return rswitch_reg_wait(priv->addr, GWARIRM, GWARIRM_ARR, GWARIRM_ARR); } -static void rswitch_gwca_set_rate_limit(struct rswitch_private *priv, int rate) -{ - u32 gwgrlulc, gwgrlc; - - switch (rate) { - case 1000: - gwgrlulc = 0x0000005f; - gwgrlc = 0x00010260; - break; - default: - dev_err(&priv->pdev->dev, "%s: This rate is not supported (%d)\n", __func__, rate); - return; - } - - iowrite32(gwgrlulc, priv->addr + GWGRLULC); - iowrite32(gwgrlc, priv->addr + GWGRLC); -} - static bool rswitch_is_any_data_irq(struct rswitch_private *priv, u32 *dis, bool tx) { u32 *mask = tx ? priv->gwca.tx_irq_bits : priv->gwca.rx_irq_bits; @@ -402,7 +389,7 @@ static int rswitch_gwca_queue_format(struct net_device *ndev, linkfix->die_dt = DT_LINKFIX; rswitch_desc_set_dptr(linkfix, gq->ring_dma); - iowrite32(GWDCC_BALR | (gq->dir_tx ? GWDCC_DQT : 0) | GWDCC_EDE, + iowrite32(GWDCC_BALR | (gq->dir_tx ? GWDCC_DCP(GWCA_IPV_NUM) | GWDCC_DQT : 0) | GWDCC_EDE, priv->addr + GWDCC_OFFS(gq->index)); return 0; @@ -500,7 +487,8 @@ static int rswitch_gwca_queue_ext_ts_format(struct net_device *ndev, linkfix->die_dt = DT_LINKFIX; rswitch_desc_set_dptr(linkfix, gq->ring_dma); - iowrite32(GWDCC_BALR | (gq->dir_tx ? GWDCC_DQT : 0) | GWDCC_ETS | GWDCC_EDE, + iowrite32(GWDCC_BALR | (gq->dir_tx ? GWDCC_DCP(GWCA_IPV_NUM) | GWDCC_DQT : 0) | + GWDCC_ETS | GWDCC_EDE, priv->addr + GWDCC_OFFS(gq->index)); return 0; @@ -649,7 +637,8 @@ static int rswitch_gwca_hw_init(struct rswitch_private *priv) iowrite32(lower_32_bits(priv->gwca.ts_queue.ring_dma), priv->addr + GWTDCAC10); iowrite32(upper_32_bits(priv->gwca.ts_queue.ring_dma), priv->addr + GWTDCAC00); iowrite32(GWCA_TS_IRQ_BIT, priv->addr + GWTSDCC0); - rswitch_gwca_set_rate_limit(priv, priv->gwca.speed); + + iowrite32(GWTPC_PPPL(GWCA_IPV_NUM), priv->addr + GWTPC0); for (i = 0; i < RSWITCH_NUM_PORTS; i++) { err = rswitch_rxdmac_init(priv, i); @@ -1502,7 +1491,8 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd rswitch_desc_set_dptr(&desc->desc, dma_addr); desc->desc.info_ds = cpu_to_le16(skb->len); - desc->info1 = cpu_to_le64(INFO1_DV(BIT(rdev->etha->index)) | INFO1_FMT); + desc->info1 = cpu_to_le64(INFO1_DV(BIT(rdev->etha->index)) | + INFO1_IPV(GWCA_IPV_NUM) | INFO1_FMT); if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { struct rswitch_gwca_ts_info *ts_info; @@ -1772,6 +1762,8 @@ static int rswitch_init(struct rswitch_private *priv) if (err < 0) return err; + rswitch_coma_init(priv); + err = rswitch_gwca_linkfix_alloc(priv); if (err < 0) return -ENOMEM; diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index b3e0411b408e..bb9ed971a97c 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -48,6 +48,7 @@ #define GWCA_NUM_IRQS 8 #define GWCA_INDEX 0 #define AGENT_INDEX_GWCA 3 +#define GWCA_IPV_NUM 0 #define GWRO RSWITCH_GWCA0_OFFSET #define GWCA_TS_IRQ_RESOURCE_NAME "gwca0_rxts0" @@ -768,11 +769,14 @@ enum rswitch_gwca_mode { #define GWARIRM_ARR BIT(1) #define GWDCC_BALR BIT(24) +#define GWDCC_DCP_MASK GENMASK(18, 16) +#define GWDCC_DCP(prio) FIELD_PREP(GWDCC_DCP_MASK, (prio)) #define GWDCC_DQT BIT(11) #define GWDCC_ETS BIT(9) #define GWDCC_EDE BIT(8) #define GWTRC(queue) (GWTRC0 + (queue) / 32 * 4) +#define GWTPC_PPPL(ipv) BIT(ipv) #define GWDCC_OFFS(queue) (GWDCC0 + (queue) * 4) #define GWDIS(i) (GWDIS0 + (i) * 0x10) @@ -789,6 +793,8 @@ enum rswitch_gwca_mode { #define CABPIRM_BPIOG BIT(0) #define CABPIRM_BPR BIT(1) +#define CABPPFLC_INIT_VALUE 0x00800080 + /* MFWD */ #define FWPC0_LTHTA BIT(0) #define FWPC0_IP4UE BIT(3) @@ -863,6 +869,7 @@ enum DIE_DT { /* For transmission */ #define INFO1_TSUN(val) ((u64)(val) << 8ULL) +#define INFO1_IPV(prio) ((u64)(prio) << 28ULL) #define INFO1_CSD0(index) ((u64)(index) << 32ULL) #define INFO1_CSD1(index) ((u64)(index) << 40ULL) #define INFO1_DV(port_vector) ((u64)(port_vector) << 48ULL) -- cgit v1.2.3 From 26a4dd839eeba3638df8441223903baa49c6f0da Mon Sep 17 00:00:00 2001 From: Vladimir Nikishkin Date: Thu, 8 Jun 2023 14:44:48 +0800 Subject: selftests: net: vxlan: Fix selftest regression after changes in iproute2. The iproute2 output that eventually landed upstream is different than the one used in this test, resulting in failures. Fix by adjusting the test to use iproute2's JSON output, which is more stable than regular output. Fixes: 305c04189997 ("selftests: net: vxlan: Add tests for vxlan nolocalbypass option.") Signed-off-by: Vladimir Nikishkin Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/test_vxlan_nolocalbypass.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh index 46067db53068..f75212bf142c 100755 --- a/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh +++ b/tools/testing/selftests/net/test_vxlan_nolocalbypass.sh @@ -130,7 +130,7 @@ nolocalbypass() run_cmd "tc -n ns1 qdisc add dev lo clsact" run_cmd "tc -n ns1 filter add dev lo ingress pref 1 handle 101 proto ip flower ip_proto udp dst_port 4790 action drop" - run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'" + run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'" log_test $? 0 "localbypass enabled" run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" @@ -140,7 +140,7 @@ nolocalbypass() run_cmd "ip -n ns1 link set dev vx0 type vxlan nolocalbypass" - run_cmd "ip -n ns1 -d link show dev vx0 | grep 'nolocalbypass'" + run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == false'" log_test $? 0 "localbypass disabled" run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" @@ -150,7 +150,7 @@ nolocalbypass() run_cmd "ip -n ns1 link set dev vx0 type vxlan localbypass" - run_cmd "ip -n ns1 -d link show dev vx0 | grep ' localbypass'" + run_cmd "ip -n ns1 -d -j link show dev vx0 | jq -e '.[][\"linkinfo\"][\"info_data\"][\"localbypass\"] == true'" log_test $? 0 "localbypass enabled" run_cmd "ip netns exec ns1 mausezahn vx0 -a $smac -b $dmac -c 1 -p 100 -q" -- cgit v1.2.3 From cbb1ca6d5f9a5a4972c4466a4b61e5bed1f4690f Mon Sep 17 00:00:00 2001 From: Radhey Shyam Pandey Date: Thu, 8 Jun 2023 13:54:58 +0530 Subject: dt-bindings: net: xlnx,axi-ethernet: convert bindings document to yaml Convert the bindings document for Xilinx AXI Ethernet Subsystem from txt to yaml. No changes to existing binding description. Signed-off-by: Radhey Shyam Pandey Signed-off-by: Sarath Babu Naidu Gaddam Signed-off-by: David S. Miller --- .../devicetree/bindings/net/xilinx_axienet.txt | 101 ------------ .../devicetree/bindings/net/xlnx,axi-ethernet.yaml | 183 +++++++++++++++++++++ MAINTAINERS | 1 + 3 files changed, 184 insertions(+), 101 deletions(-) delete mode 100644 Documentation/devicetree/bindings/net/xilinx_axienet.txt create mode 100644 Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml diff --git a/Documentation/devicetree/bindings/net/xilinx_axienet.txt b/Documentation/devicetree/bindings/net/xilinx_axienet.txt deleted file mode 100644 index 80e505a2fda1..000000000000 --- a/Documentation/devicetree/bindings/net/xilinx_axienet.txt +++ /dev/null @@ -1,101 +0,0 @@ -XILINX AXI ETHERNET Device Tree Bindings --------------------------------------------------------- - -Also called AXI 1G/2.5G Ethernet Subsystem, the xilinx axi ethernet IP core -provides connectivity to an external ethernet PHY supporting different -interfaces: MII, GMII, RGMII, SGMII, 1000BaseX. It also includes two -segments of memory for buffering TX and RX, as well as the capability of -offloading TX/RX checksum calculation off the processor. - -Management configuration is done through the AXI interface, while payload is -sent and received through means of an AXI DMA controller. This driver -includes the DMA driver code, so this driver is incompatible with AXI DMA -driver. - -For more details about mdio please refer phy.txt file in the same directory. - -Required properties: -- compatible : Must be one of "xlnx,axi-ethernet-1.00.a", - "xlnx,axi-ethernet-1.01.a", "xlnx,axi-ethernet-2.01.a" -- reg : Address and length of the IO space, as well as the address - and length of the AXI DMA controller IO space, unless - axistream-connected is specified, in which case the reg - attribute of the node referenced by it is used. -- interrupts : Should be a list of 2 or 3 interrupts: TX DMA, RX DMA, - and optionally Ethernet core. If axistream-connected is - specified, the TX/RX DMA interrupts should be on that node - instead, and only the Ethernet core interrupt is optionally - specified here. -- phy-handle : Should point to the external phy device if exists. Pointing - this to the PCS/PMA PHY is deprecated and should be avoided. - See ethernet.txt file in the same directory. -- xlnx,rxmem : Set to allocated memory buffer for Rx/Tx in the hardware - -Optional properties: -- phy-mode : See ethernet.txt -- xlnx,phy-type : Deprecated, do not use, but still accepted in preference - to phy-mode. -- xlnx,txcsum : 0 or empty for disabling TX checksum offload, - 1 to enable partial TX checksum offload, - 2 to enable full TX checksum offload -- xlnx,rxcsum : Same values as xlnx,txcsum but for RX checksum offload -- xlnx,switch-x-sgmii : Boolean to indicate the Ethernet core is configured to - support both 1000BaseX and SGMII modes. If set, the phy-mode - should be set to match the mode selected on core reset (i.e. - by the basex_or_sgmii core input line). -- clock-names: Tuple listing input clock names. Possible clocks: - s_axi_lite_clk: Clock for AXI register slave interface - axis_clk: AXI4-Stream clock for TXD RXD TXC and RXS interfaces - ref_clk: Ethernet reference clock, used by signal delay - primitives and transceivers - mgt_clk: MGT reference clock (used by optional internal - PCS/PMA PHY) - - Note that if s_axi_lite_clk is not specified by name, the - first clock of any name is used for this. If that is also not - specified, the clock rate is auto-detected from the CPU clock - (but only on platforms where this is possible). New device - trees should specify all applicable clocks by name - the - fallbacks to an unnamed clock or to CPU clock are only for - backward compatibility. -- clocks: Phandles to input clocks matching clock-names. Refer to common - clock bindings. -- axistream-connected: Reference to another node which contains the resources - for the AXI DMA controller used by this device. - If this is specified, the DMA-related resources from that - device (DMA registers and DMA TX/RX interrupts) rather - than this one will be used. - - mdio : Child node for MDIO bus. Must be defined if PHY access is - required through the core's MDIO interface (i.e. always, - unless the PHY is accessed through a different bus). - Non-standard MDIO bus frequency is supported via - "clock-frequency", see mdio.yaml. - - - pcs-handle: Phandle to the internal PCS/PMA PHY in SGMII or 1000Base-X - modes, where "pcs-handle" should be used to point - to the PCS/PMA PHY, and "phy-handle" should point to an - external PHY if exists. - -Example: - axi_ethernet_eth: ethernet@40c00000 { - compatible = "xlnx,axi-ethernet-1.00.a"; - device_type = "network"; - interrupt-parent = <µblaze_0_axi_intc>; - interrupts = <2 0 1>; - clock-names = "s_axi_lite_clk", "axis_clk", "ref_clk", "mgt_clk"; - clocks = <&axi_clk>, <&axi_clk>, <&pl_enet_ref_clk>, <&mgt_clk>; - phy-mode = "mii"; - reg = <0x40c00000 0x40000 0x50c00000 0x40000>; - xlnx,rxcsum = <0x2>; - xlnx,rxmem = <0x800>; - xlnx,txcsum = <0x2>; - phy-handle = <&phy0>; - axi_ethernetlite_0_mdio: mdio { - #address-cells = <1>; - #size-cells = <0>; - phy0: phy@0 { - device_type = "ethernet-phy"; - reg = <1>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml new file mode 100644 index 000000000000..1d33d80af11c --- /dev/null +++ b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml @@ -0,0 +1,183 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/xlnx,axi-ethernet.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AXI 1G/2.5G Ethernet Subsystem + +description: | + Also called AXI 1G/2.5G Ethernet Subsystem, the xilinx axi ethernet IP core + provides connectivity to an external ethernet PHY supporting different + interfaces: MII, GMII, RGMII, SGMII, 1000BaseX. It also includes two + segments of memory for buffering TX and RX, as well as the capability of + offloading TX/RX checksum calculation off the processor. + + Management configuration is done through the AXI interface, while payload is + sent and received through means of an AXI DMA controller. This driver + includes the DMA driver code, so this driver is incompatible with AXI DMA + driver. + +maintainers: + - Radhey Shyam Pandey + +properties: + compatible: + enum: + - xlnx,axi-ethernet-1.00.a + - xlnx,axi-ethernet-1.01.a + - xlnx,axi-ethernet-2.01.a + + reg: + description: + Address and length of the IO space, as well as the address + and length of the AXI DMA controller IO space, unless + axistream-connected is specified, in which case the reg + attribute of the node referenced by it is used. + maxItems: 2 + + interrupts: + items: + - description: Ethernet core interrupt + - description: Tx DMA interrupt + - description: Rx DMA interrupt + description: + Ethernet core interrupt is optional. If axistream-connected property is + present DMA node should contains TX/RX DMA interrupts else DMA interrupt + resources are mentioned on ethernet node. + minItems: 1 + + phy-handle: true + + xlnx,rxmem: + description: + Set to allocated memory buffer for Rx/Tx in the hardware. + $ref: /schemas/types.yaml#/definitions/uint32 + + phy-mode: + enum: + - mii + - gmii + - rgmii + - sgmii + - 1000BaseX + + xlnx,phy-type: + description: + Do not use, but still accepted in preference to phy-mode. + deprecated: true + $ref: /schemas/types.yaml#/definitions/uint32 + + xlnx,txcsum: + description: + TX checksum offload. 0 or empty for disabling TX checksum offload, + 1 to enable partial TX checksum offload and 2 to enable full TX + checksum offload. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + + xlnx,rxcsum: + description: + RX checksum offload. 0 or empty for disabling RX checksum offload, + 1 to enable partial RX checksum offload and 2 to enable full RX + checksum offload. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + + xlnx,switch-x-sgmii: + type: boolean + description: + Indicate the Ethernet core is configured to support both 1000BaseX and + SGMII modes. If set, the phy-mode should be set to match the mode + selected on core reset (i.e. by the basex_or_sgmii core input line). + + clocks: + items: + - description: Clock for AXI register slave interface. + - description: AXI4-Stream clock for TXD RXD TXC and RXS interfaces. + - description: Ethernet reference clock, used by signal delay primitives + and transceivers. + - description: MGT reference clock (used by optional internal PCS/PMA PHY) + + clock-names: + items: + - const: s_axi_lite_clk + - const: axis_clk + - const: ref_clk + - const: mgt_clk + + axistream-connected: + $ref: /schemas/types.yaml#/definitions/phandle + description: Phandle of AXI DMA controller which contains the resources + used by this device. If this is specified, the DMA-related resources + from that device (DMA registers and DMA TX/RX interrupts) rather than + this one will be used. + + mdio: + type: object + + pcs-handle: + description: Phandle to the internal PCS/PMA PHY in SGMII or 1000Base-X + modes, where "pcs-handle" should be used to point to the PCS/PMA PHY, + and "phy-handle" should point to an external PHY if exists. + maxItems: 1 + +required: + - compatible + - interrupts + - reg + - xlnx,rxmem + - phy-handle + +allOf: + - $ref: /schemas/net/ethernet-controller.yaml# + +additionalProperties: false + +examples: + - | + axi_ethernet_eth: ethernet@40c00000 { + compatible = "xlnx,axi-ethernet-1.00.a"; + interrupts = <2 0 1>; + clock-names = "s_axi_lite_clk", "axis_clk", "ref_clk", "mgt_clk"; + clocks = <&axi_clk>, <&axi_clk>, <&pl_enet_ref_clk>, <&mgt_clk>; + phy-mode = "mii"; + reg = <0x40c00000 0x40000>,<0x50c00000 0x40000>; + xlnx,rxcsum = <0x2>; + xlnx,rxmem = <0x800>; + xlnx,txcsum = <0x2>; + phy-handle = <&phy0>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@1 { + device_type = "ethernet-phy"; + reg = <1>; + }; + }; + }; + + - | + axi_ethernet_eth1: ethernet@40000000 { + compatible = "xlnx,axi-ethernet-1.00.a"; + interrupts = <0>; + clock-names = "s_axi_lite_clk", "axis_clk", "ref_clk", "mgt_clk"; + clocks = <&axi_clk>, <&axi_clk>, <&pl_enet_ref_clk>, <&mgt_clk>; + phy-mode = "mii"; + reg = <0x00 0x40000000 0x00 0x40000>; + xlnx,rxcsum = <0x2>; + xlnx,rxmem = <0x800>; + xlnx,txcsum = <0x2>; + phy-handle = <&phy1>; + axistream-connected = <&dma>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy1: ethernet-phy@1 { + device_type = "ethernet-phy"; + reg = <1>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 0971854323a7..ecac69046d30 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23144,6 +23144,7 @@ F: drivers/iio/adc/xilinx-ams.c XILINX AXI ETHERNET DRIVER M: Radhey Shyam Pandey S: Maintained +F: Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml F: drivers/net/ethernet/xilinx/xilinx_axienet* XILINX CAN DRIVER -- cgit v1.2.3 From e4f5073d53be6cec0c654fac98372047efb66947 Mon Sep 17 00:00:00 2001 From: M Chetan Kumar Date: Thu, 8 Jun 2023 15:38:03 +0530 Subject: net: wwan: iosm: enable runtime pm support for 7560 Adds runtime pm support for 7560. As part of probe procedure auto suspend is enabled and auto suspend delay is set to 5000 ms for runtime pm use. Later auto flag is set to power manage the device at run time. On successful communication establishment between host and device the device usage counter is dropped and request to put the device into sleep state (suspend). In TX path, the device usage counter is raised and device is moved out of sleep(resume) for data transmission. In RX path, if the device has some data to be sent it request host platform to change the power state by giving PCI PME message. Signed-off-by: M Chetan Kumar Signed-off-by: David S. Miller --- drivers/net/wwan/iosm/iosm_ipc_imem.c | 17 +++++++++++++++++ drivers/net/wwan/iosm/iosm_ipc_imem.h | 2 ++ drivers/net/wwan/iosm/iosm_ipc_pcie.c | 4 +++- drivers/net/wwan/iosm/iosm_ipc_port.c | 17 ++++++++++++++++- drivers/net/wwan/iosm/iosm_ipc_trace.c | 8 ++++++++ drivers/net/wwan/iosm/iosm_ipc_wwan.c | 21 +++++++++++++++++++-- 6 files changed, 65 insertions(+), 4 deletions(-) diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem.c b/drivers/net/wwan/iosm/iosm_ipc_imem.c index 829515a601b3..635301d677e1 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem.c +++ b/drivers/net/wwan/iosm/iosm_ipc_imem.c @@ -4,6 +4,7 @@ */ #include +#include #include "iosm_ipc_chnl_cfg.h" #include "iosm_ipc_devlink.h" @@ -631,6 +632,11 @@ static void ipc_imem_run_state_worker(struct work_struct *instance) /* Complete all memory stores after setting bit */ smp_mb__after_atomic(); + if (ipc_imem->pcie->pci->device == INTEL_CP_DEVICE_7560_ID) { + pm_runtime_mark_last_busy(ipc_imem->dev); + pm_runtime_put_autosuspend(ipc_imem->dev); + } + return; err_ipc_mux_deinit: @@ -1234,6 +1240,7 @@ void ipc_imem_cleanup(struct iosm_imem *ipc_imem) /* forward MDM_NOT_READY to listeners */ ipc_uevent_send(ipc_imem->dev, UEVENT_MDM_NOT_READY); + pm_runtime_get_sync(ipc_imem->dev); hrtimer_cancel(&ipc_imem->td_alloc_timer); hrtimer_cancel(&ipc_imem->tdupdate_timer); @@ -1419,6 +1426,16 @@ struct iosm_imem *ipc_imem_init(struct iosm_pcie *pcie, unsigned int device_id, set_bit(IOSM_DEVLINK_INIT, &ipc_imem->flag); } + + if (!pm_runtime_enabled(ipc_imem->dev)) + pm_runtime_enable(ipc_imem->dev); + + pm_runtime_set_autosuspend_delay(ipc_imem->dev, + IPC_MEM_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(ipc_imem->dev); + pm_runtime_allow(ipc_imem->dev); + pm_runtime_mark_last_busy(ipc_imem->dev); + return ipc_imem; devlink_channel_fail: ipc_devlink_deinit(ipc_imem->ipc_devlink); diff --git a/drivers/net/wwan/iosm/iosm_ipc_imem.h b/drivers/net/wwan/iosm/iosm_ipc_imem.h index 5664ac507c90..0144b45e2afb 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_imem.h +++ b/drivers/net/wwan/iosm/iosm_ipc_imem.h @@ -103,6 +103,8 @@ struct ipc_chnl_cfg; #define FULLY_FUNCTIONAL 0 #define IOSM_DEVLINK_INIT 1 +#define IPC_MEM_AUTO_SUSPEND_DELAY_MS 5000 + /* List of the supported UL/DL pipes. */ enum ipc_mem_pipes { IPC_MEM_PIPE_0 = 0, diff --git a/drivers/net/wwan/iosm/iosm_ipc_pcie.c b/drivers/net/wwan/iosm/iosm_ipc_pcie.c index 04517bd3325a..3a259c9abefd 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_pcie.c +++ b/drivers/net/wwan/iosm/iosm_ipc_pcie.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "iosm_ipc_imem.h" @@ -437,7 +438,8 @@ static int __maybe_unused ipc_pcie_resume_cb(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(iosm_ipc_pm, ipc_pcie_suspend_cb, ipc_pcie_resume_cb); +static DEFINE_RUNTIME_DEV_PM_OPS(iosm_ipc_pm, ipc_pcie_suspend_cb, + ipc_pcie_resume_cb, NULL); static struct pci_driver iosm_ipc_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wwan/iosm/iosm_ipc_port.c b/drivers/net/wwan/iosm/iosm_ipc_port.c index 5d5b4183e14a..2ba1ddca3945 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_port.c +++ b/drivers/net/wwan/iosm/iosm_ipc_port.c @@ -3,6 +3,8 @@ * Copyright (C) 2020-21 Intel Corporation. */ +#include + #include "iosm_ipc_chnl_cfg.h" #include "iosm_ipc_imem_ops.h" #include "iosm_ipc_port.h" @@ -13,12 +15,16 @@ static int ipc_port_ctrl_start(struct wwan_port *port) struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port); int ret = 0; + pm_runtime_get_sync(ipc_port->ipc_imem->dev); ipc_port->channel = ipc_imem_sys_port_open(ipc_port->ipc_imem, ipc_port->chl_id, IPC_HP_CDEV_OPEN); if (!ipc_port->channel) ret = -EIO; + pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev); + pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev); + return ret; } @@ -27,15 +33,24 @@ static void ipc_port_ctrl_stop(struct wwan_port *port) { struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port); + pm_runtime_get_sync(ipc_port->ipc_imem->dev); ipc_imem_sys_port_close(ipc_port->ipc_imem, ipc_port->channel); + pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev); + pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev); } /* transfer control data to modem */ static int ipc_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb) { struct iosm_cdev *ipc_port = wwan_port_get_drvdata(port); + int ret; - return ipc_imem_sys_cdev_write(ipc_port, skb); + pm_runtime_get_sync(ipc_port->ipc_imem->dev); + ret = ipc_imem_sys_cdev_write(ipc_port, skb); + pm_runtime_mark_last_busy(ipc_port->ipc_imem->dev); + pm_runtime_put_autosuspend(ipc_port->ipc_imem->dev); + + return ret; } static const struct wwan_port_ops ipc_wwan_ctrl_ops = { diff --git a/drivers/net/wwan/iosm/iosm_ipc_trace.c b/drivers/net/wwan/iosm/iosm_ipc_trace.c index eeecfa3d10c5..4368373797b6 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_trace.c +++ b/drivers/net/wwan/iosm/iosm_ipc_trace.c @@ -3,7 +3,9 @@ * Copyright (C) 2020-2021 Intel Corporation. */ +#include #include + #include "iosm_ipc_trace.h" /* sub buffer size and number of sub buffer */ @@ -97,6 +99,8 @@ static ssize_t ipc_trace_ctrl_file_write(struct file *filp, if (ret) return ret; + pm_runtime_get_sync(ipc_trace->ipc_imem->dev); + mutex_lock(&ipc_trace->trc_mutex); if (val == TRACE_ENABLE && ipc_trace->mode != TRACE_ENABLE) { ipc_trace->channel = ipc_imem_sys_port_open(ipc_trace->ipc_imem, @@ -117,6 +121,10 @@ static ssize_t ipc_trace_ctrl_file_write(struct file *filp, ret = count; unlock: mutex_unlock(&ipc_trace->trc_mutex); + + pm_runtime_mark_last_busy(ipc_trace->ipc_imem->dev); + pm_runtime_put_autosuspend(ipc_trace->ipc_imem->dev); + return ret; } diff --git a/drivers/net/wwan/iosm/iosm_ipc_wwan.c b/drivers/net/wwan/iosm/iosm_ipc_wwan.c index ff747fc79aaf..93d17de08786 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_wwan.c +++ b/drivers/net/wwan/iosm/iosm_ipc_wwan.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -51,11 +52,13 @@ static int ipc_wwan_link_open(struct net_device *netdev) struct iosm_netdev_priv *priv = wwan_netdev_drvpriv(netdev); struct iosm_wwan *ipc_wwan = priv->ipc_wwan; int if_id = priv->if_id; + int ret = 0; if (if_id < IP_MUX_SESSION_START || if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)) return -EINVAL; + pm_runtime_get_sync(ipc_wwan->ipc_imem->dev); /* get channel id */ priv->ch_id = ipc_imem_sys_wwan_open(ipc_wwan->ipc_imem, if_id); @@ -63,7 +66,8 @@ static int ipc_wwan_link_open(struct net_device *netdev) dev_err(ipc_wwan->dev, "cannot connect wwan0 & id %d to the IPC mem layer", if_id); - return -ENODEV; + ret = -ENODEV; + goto err_out; } /* enable tx path, DL data may follow */ @@ -72,7 +76,11 @@ static int ipc_wwan_link_open(struct net_device *netdev) dev_dbg(ipc_wwan->dev, "Channel id %d allocated to if_id %d", priv->ch_id, priv->if_id); - return 0; +err_out: + pm_runtime_mark_last_busy(ipc_wwan->ipc_imem->dev); + pm_runtime_put_autosuspend(ipc_wwan->ipc_imem->dev); + + return ret; } /* Bring-down the wwan net link */ @@ -82,9 +90,12 @@ static int ipc_wwan_link_stop(struct net_device *netdev) netif_stop_queue(netdev); + pm_runtime_get_sync(priv->ipc_wwan->ipc_imem->dev); ipc_imem_sys_wwan_close(priv->ipc_wwan->ipc_imem, priv->if_id, priv->ch_id); priv->ch_id = -1; + pm_runtime_mark_last_busy(priv->ipc_wwan->ipc_imem->dev); + pm_runtime_put_autosuspend(priv->ipc_wwan->ipc_imem->dev); return 0; } @@ -106,6 +117,7 @@ static netdev_tx_t ipc_wwan_link_transmit(struct sk_buff *skb, if_id >= ARRAY_SIZE(ipc_wwan->sub_netlist)) return -EINVAL; + pm_runtime_get(ipc_wwan->ipc_imem->dev); /* Send the SKB to device for transmission */ ret = ipc_imem_sys_wwan_transmit(ipc_wwan->ipc_imem, if_id, priv->ch_id, skb); @@ -119,9 +131,14 @@ static netdev_tx_t ipc_wwan_link_transmit(struct sk_buff *skb, ret = NETDEV_TX_BUSY; dev_err(ipc_wwan->dev, "unable to push packets"); } else { + pm_runtime_mark_last_busy(ipc_wwan->ipc_imem->dev); + pm_runtime_put_autosuspend(ipc_wwan->ipc_imem->dev); goto exit; } + pm_runtime_mark_last_busy(ipc_wwan->ipc_imem->dev); + pm_runtime_put_autosuspend(ipc_wwan->ipc_imem->dev); + return ret; exit: -- cgit v1.2.3 From 132b4ebfa090492663f84144a1e7afaca54cd58a Mon Sep 17 00:00:00 2001 From: Nitya Sunkad Date: Thu, 8 Jun 2023 22:50:16 -0700 Subject: ionic: add support for ethtool extended stat link_down_count Following the example of 'commit 9a0f830f8026 ("ethtool: linkstate: add a statistic for PHY down events")', added support for link down events. Add callback ionic_get_link_ext_stats to ionic_ethtool.c to support link_down_count, a property of netdev that gets reported exclusively on physical link down events. Run ethtool -I to display the device link down count. Signed-off-by: Nitya Sunkad Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 10 ++++++++++ drivers/net/ethernet/pensando/ionic/ionic_lif.c | 1 + drivers/net/ethernet/pensando/ionic/ionic_lif.h | 1 + 3 files changed, 12 insertions(+) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index 9b2b96fa36af..3a6b0a9bc241 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -104,6 +104,15 @@ static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs, memcpy_fromio(p + offset, lif->ionic->idev.dev_cmd_regs->words, size); } +static void ionic_get_link_ext_stats(struct net_device *netdev, + struct ethtool_link_ext_stats *stats) +{ + struct ionic_lif *lif = netdev_priv(netdev); + + if (lif->ionic->pdev->is_physfn) + stats->link_down_events = lif->link_down_count; +} + static int ionic_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *ks) { @@ -1074,6 +1083,7 @@ static const struct ethtool_ops ionic_ethtool_ops = { .get_regs_len = ionic_get_regs_len, .get_regs = ionic_get_regs, .get_link = ethtool_op_get_link, + .get_link_ext_stats = ionic_get_link_ext_stats, .get_link_ksettings = ionic_get_link_ksettings, .set_link_ksettings = ionic_set_link_ksettings, .get_coalesce = ionic_get_coalesce, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 957027e546b3..6ccc1ea91992 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -168,6 +168,7 @@ static void ionic_link_status_check(struct ionic_lif *lif) } } else { if (netif_carrier_ok(netdev)) { + lif->link_down_count++; netdev_info(netdev, "Link down\n"); netif_carrier_off(netdev); } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index c9c4c46d5a16..fd2ea670e7d8 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -201,6 +201,7 @@ struct ionic_lif { u64 hw_features; bool registered; u16 lif_type; + unsigned int link_down_count; unsigned int nmcast; unsigned int nucast; unsigned int nvlans; -- cgit v1.2.3 From 26e35370b9766914364409626035fda2c63fef05 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Fri, 9 Jun 2023 15:01:17 +0800 Subject: net/sched: act_pedit: Use kmemdup() to replace kmalloc + memcpy ./net/sched/act_pedit.c:245:21-28: WARNING opportunity for kmemdup. Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=5478 Signed-off-by: Jiapeng Chong Reviewed-by: Pedro Tammela Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/act_pedit.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index fc945c7e4123..8c4e7fddddbf 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -242,14 +242,12 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, nparms->tcfp_flags = parm->flags; nparms->tcfp_nkeys = parm->nkeys; - nparms->tcfp_keys = kmalloc(ksize, GFP_KERNEL); + nparms->tcfp_keys = kmemdup(parm->keys, ksize, GFP_KERNEL); if (!nparms->tcfp_keys) { ret = -ENOMEM; goto put_chain; } - memcpy(nparms->tcfp_keys, parm->keys, ksize); - for (i = 0; i < nparms->tcfp_nkeys; ++i) { u32 offmask = nparms->tcfp_keys[i].offmask; u32 cur = nparms->tcfp_keys[i].off; -- cgit v1.2.3 From 998b85f0468f0b4784da69c087f52149ae7ded13 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Fri, 9 Jun 2023 08:57:36 +0100 Subject: sfc: Add devlink dev info support for EF10 Reuse the work done for EF100 to add devlink support for EF10. There is no devlink port support for EF10. Signed-off-by: Martin Habets Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index a4f22d8e6ac7..d670a319b379 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -32,6 +32,7 @@ #include "io.h" #include "selftest.h" #include "sriov.h" +#include "efx_devlink.h" #include "mcdi_port_common.h" #include "mcdi_pcol.h" @@ -877,6 +878,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev) if (efx->type->sriov_fini) efx->type->sriov_fini(efx); + efx_fini_devlink_lock(efx); efx_unregister_netdev(efx); efx_mtd_remove(efx); @@ -886,6 +888,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev) efx_fini_io(efx); pci_dbg(efx->pci_dev, "shutdown successful\n"); + efx_fini_devlink_and_unlock(efx); efx_fini_struct(efx); free_netdev(efx->net_dev); probe_data = container_of(efx, struct efx_probe_data, efx); @@ -1025,7 +1028,13 @@ static int efx_pci_probe_post_io(struct efx_nic *efx) NETDEV_XDP_ACT_REDIRECT | NETDEV_XDP_ACT_NDO_XMIT; + /* devlink creation, registration and lock */ + rc = efx_probe_devlink_and_lock(efx); + if (rc) + pci_err(efx->pci_dev, "devlink registration failed"); + rc = efx_register_netdev(efx); + efx_probe_devlink_unlock(efx); if (!rc) return 0; -- cgit v1.2.3 From b803d1fded4085d268507a432dac8077ead68971 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 9 Jun 2023 05:47:17 -0700 Subject: net: mana: Add support for vlan tagging To support vlan, use MANA_LONG_PKT_FMT if vlan tag is present in TX skb. Then extract the vlan tag from the skb struct, and save it to tx_oob for the NIC to transmit. For vlan tags on the payload, they are accepted by the NIC too. For RX, extract the vlan tag from CQE and put it into skb. Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/ethernet/microsoft/mana/mana_en.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index d907727c7b7a..cd4d5ceb9f2d 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -179,6 +179,14 @@ netdev_tx_t mana_start_xmit(struct sk_buff *skb, struct net_device *ndev) pkg.tx_oob.s_oob.short_vp_offset = txq->vp_offset; } + if (skb_vlan_tag_present(skb)) { + pkt_fmt = MANA_LONG_PKT_FMT; + pkg.tx_oob.l_oob.inject_vlan_pri_tag = 1; + pkg.tx_oob.l_oob.pcp = skb_vlan_tag_get_prio(skb); + pkg.tx_oob.l_oob.dei = skb_vlan_tag_get_cfi(skb); + pkg.tx_oob.l_oob.vlan_id = skb_vlan_tag_get_id(skb); + } + pkg.tx_oob.s_oob.pkt_fmt = pkt_fmt; if (pkt_fmt == MANA_SHORT_PKT_FMT) { @@ -1457,6 +1465,12 @@ static void mana_rx_skb(void *buf_va, struct mana_rxcomp_oob *cqe, skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L3); } + if (cqe->rx_vlantag_present) { + u16 vlan_tci = cqe->rx_vlan_id; + + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); + } + u64_stats_update_begin(&rx_stats->syncp); rx_stats->packets++; rx_stats->bytes += pkt_len; @@ -2451,8 +2465,9 @@ static int mana_probe_port(struct mana_context *ac, int port_idx, ndev->hw_features |= NETIF_F_RXCSUM; ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; ndev->hw_features |= NETIF_F_RXHASH; - ndev->features = ndev->hw_features; - ndev->vlan_features = 0; + ndev->features = ndev->hw_features | NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX; + ndev->vlan_features = ndev->features; ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | NETDEV_XDP_ACT_NDO_XMIT; -- cgit v1.2.3 From f2ea0c3582abc721ce9e090cf496b96e6b204e2c Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 9 Jun 2023 15:31:57 +0200 Subject: nfc: nxp-nci: store __be16 value in __be16 variable Use a __be16 variable to store the big endian value of header in nxp_nci_i2c_fw_read(). Flagged by Sparse as: .../i2c.c:113:22: warning: cast to restricted __be16 No functional changes intended. Compile tested only. Signed-off-by: Simon Horman Reviewed-by: Sridhar Samudrala Reviewed-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- drivers/nfc/nxp-nci/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c index baddaf242d18..dca25a0c2f33 100644 --- a/drivers/nfc/nxp-nci/i2c.c +++ b/drivers/nfc/nxp-nci/i2c.c @@ -97,8 +97,8 @@ static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy, struct sk_buff **skb) { struct i2c_client *client = phy->i2c_dev; - u16 header; size_t frame_len; + __be16 header; int r; r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN); -- cgit v1.2.3 From 2b84960fc5dd38a19241388fb33f20936cb217e2 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 9 Jun 2023 16:59:16 +0300 Subject: net/sched: taprio: report class offload stats per TXQ, not per TC The taprio Qdisc creates child classes per netdev TX queue, but taprio_dump_class_stats() currently reports offload statistics per traffic class. Traffic classes are groups of TXQs sharing the same dequeue priority, so this is incorrect and we shouldn't be bundling up the TXQ stats when reporting them, as we currently do in enetc. Modify the API from taprio to drivers such that they report TXQ offload stats and not TC offload stats. There is no change in the UAPI or in the global Qdisc stats. Fixes: 6c1adb650c8d ("net/sched: taprio: add netlink reporting for offload statistics counters") Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc_qos.c | 20 +++++++------------- include/net/pkt_sched.h | 10 +++++----- net/sched/sch_taprio.c | 8 ++++---- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 71157eba1fbe..58cdd67bb573 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -160,20 +160,14 @@ static void enetc_taprio_stats(struct net_device *ndev, stats->window_drops = window_drops; } -static void enetc_taprio_tc_stats(struct net_device *ndev, - struct tc_taprio_qopt_tc_stats *tc_stats) +static void enetc_taprio_queue_stats(struct net_device *ndev, + struct tc_taprio_qopt_queue_stats *queue_stats) { - struct tc_taprio_qopt_stats *stats = &tc_stats->stats; + struct tc_taprio_qopt_stats *stats = &queue_stats->stats; struct enetc_ndev_priv *priv = netdev_priv(ndev); - int tc = tc_stats->tc; - u64 window_drops = 0; - int i; + int queue = queue_stats->queue; - for (i = 0; i < priv->num_tx_rings; i++) - if (priv->tx_ring[i]->prio == tc) - window_drops += priv->tx_ring[i]->stats.win_drop; - - stats->window_drops = window_drops; + stats->window_drops = priv->tx_ring[queue]->stats.win_drop; } static int enetc_taprio_replace(struct net_device *ndev, @@ -208,8 +202,8 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) case TAPRIO_CMD_STATS: enetc_taprio_stats(ndev, &offload->stats); break; - case TAPRIO_CMD_TC_STATS: - enetc_taprio_tc_stats(ndev, &offload->tc_stats); + case TAPRIO_CMD_QUEUE_STATS: + enetc_taprio_queue_stats(ndev, &offload->queue_stats); break; default: err = -EOPNOTSUPP; diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 518febb91c9f..e98aac9d5ad5 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -191,7 +191,7 @@ enum tc_taprio_qopt_cmd { TAPRIO_CMD_REPLACE, TAPRIO_CMD_DESTROY, TAPRIO_CMD_STATS, - TAPRIO_CMD_TC_STATS, + TAPRIO_CMD_QUEUE_STATS, }; /** @@ -208,8 +208,8 @@ struct tc_taprio_qopt_stats { u64 tx_overruns; }; -struct tc_taprio_qopt_tc_stats { - int tc; +struct tc_taprio_qopt_queue_stats { + int queue; struct tc_taprio_qopt_stats stats; }; @@ -227,8 +227,8 @@ struct tc_taprio_qopt_offload { union { /* TAPRIO_CMD_STATS */ struct tc_taprio_qopt_stats stats; - /* TAPRIO_CMD_TC_STATS */ - struct tc_taprio_qopt_tc_stats tc_stats; + /* TAPRIO_CMD_QUEUE_STATS */ + struct tc_taprio_qopt_queue_stats queue_stats; /* TAPRIO_CMD_REPLACE */ struct { struct tc_mqprio_qopt_offload mqprio; diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 4a4e6ff894c1..c6627f5abdfa 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -2458,9 +2458,9 @@ static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, { struct netdev_queue *dev_queue = taprio_queue_get(sch, cl); struct tc_taprio_qopt_offload offload = { - .cmd = TAPRIO_CMD_TC_STATS, - .tc_stats = { - .tc = cl - 1, + .cmd = TAPRIO_CMD_QUEUE_STATS, + .queue_stats = { + .queue = cl - 1, }, }; struct Qdisc *child; @@ -2470,7 +2470,7 @@ static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl, qdisc_qstats_copy(d, child) < 0) return -1; - return taprio_dump_xstats(sch, d, &offload, &offload.tc_stats.stats); + return taprio_dump_xstats(sch, d, &offload, &offload.queue_stats.stats); } static void taprio_walk(struct Qdisc *sch, struct qdisc_walker *arg) -- cgit v1.2.3 From f1e668d29c57499f734a291bfb96a82142322f41 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 9 Jun 2023 16:59:17 +0300 Subject: net: enetc: reset taprio stats when taprio is deleted Currently, the window_drop stats persist even if an incorrect Qdisc was removed from the interface and a new one is installed. This is because the enetc driver keeps the state, and that is persistent across multiple Qdiscs. To resolve the issue, clear all win_drop counters from all TX queues when the currently active Qdisc is removed. These counters are zero by default. The counters visible in ethtool -S are also affected, but I don't care very much about preserving those enough to keep them monotonically incrementing. Fixes: 4802fca8d1af ("net: enetc: report statistics counters for taprio") Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc_qos.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 58cdd67bb573..9d74104df7c8 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -127,6 +127,14 @@ static int enetc_setup_taprio(struct enetc_ndev_priv *priv, return 0; } +static void enetc_reset_taprio_stats(struct enetc_ndev_priv *priv) +{ + int i; + + for (i = 0; i < priv->num_tx_rings; i++) + priv->tx_ring[i]->stats.win_drop = 0; +} + static void enetc_reset_taprio(struct enetc_ndev_priv *priv) { struct enetc_hw *hw = &priv->si->hw; @@ -145,6 +153,7 @@ static void enetc_taprio_destroy(struct net_device *ndev) enetc_reset_taprio(priv); enetc_reset_tc_mqprio(ndev); + enetc_reset_taprio_stats(priv); } static void enetc_taprio_stats(struct net_device *ndev, -- cgit v1.2.3 From e069ba07e6c7af69e119316bc87ff44869095f49 Mon Sep 17 00:00:00 2001 From: Aaron Conole Date: Fri, 9 Jun 2023 09:59:55 -0400 Subject: net: openvswitch: add support for l4 symmetric hashing Since its introduction, the ovs module execute_hash action allowed hash algorithms other than the skb->l4_hash to be used. However, additional hash algorithms were not implemented. This means flows requiring different hash distributions weren't able to use the kernel datapath. Now, introduce support for symmetric hashing algorithm as an alternative hash supported by the ovs module using the flow dissector. Output of flow using l4_sym hash: recirc_id(0),in_port(3),eth(),eth_type(0x0800), ipv4(dst=64.0.0.0/192.0.0.0,proto=6,frag=no), packets:30473425, bytes:45902883702, used:0.000s, flags:SP., actions:hash(sym_l4(0)),recirc(0xd) Some performance testing with no GRO/GSO, two veths, single flow: hash(l4(0)): 4.35 GBits/s hash(l4_sym(0)): 4.24 GBits/s Signed-off-by: Aaron Conole Signed-off-by: David S. Miller --- include/uapi/linux/openvswitch.h | 1 + net/openvswitch/actions.c | 12 ++++++++++-- net/openvswitch/flow_netlink.c | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index c5d62ee82567..e94870e77ee9 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -765,6 +765,7 @@ struct ovs_action_push_vlan { */ enum ovs_hash_alg { OVS_HASH_ALG_L4, + OVS_HASH_ALG_SYM_L4, }; /* diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 8074ea00d577..cab1e02b63e0 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -1073,8 +1073,16 @@ static void execute_hash(struct sk_buff *skb, struct sw_flow_key *key, struct ovs_action_hash *hash_act = nla_data(attr); u32 hash = 0; - /* OVS_HASH_ALG_L4 is the only possible hash algorithm. */ - hash = skb_get_hash(skb); + if (hash_act->hash_alg == OVS_HASH_ALG_L4) { + /* OVS_HASH_ALG_L4 hasing type. */ + hash = skb_get_hash(skb); + } else if (hash_act->hash_alg == OVS_HASH_ALG_SYM_L4) { + /* OVS_HASH_ALG_SYM_L4 hashing type. NOTE: this doesn't + * extend past an encapsulated header. + */ + hash = __skb_get_hash_symmetric(skb); + } + hash = jhash_1word(hash, hash_act->hash_basis); if (!hash) hash = 0x1; diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index ead5418c126e..41116361433d 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -3221,6 +3221,8 @@ static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, switch (act_hash->hash_alg) { case OVS_HASH_ALG_L4: + fallthrough; + case OVS_HASH_ALG_SYM_L4: break; default: return -EINVAL; -- cgit v1.2.3 From 50f6c3d57e9a7d11ff935198c1d55d37975c2fa4 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 9 Jun 2023 19:32:06 +0200 Subject: mlxsw: spectrum_router: mlxsw_sp_router_fini(): Extract a helper variable Make mlxsw_sp_router_fini() more similar to the _init() function (and more concise) by extracting the `router' handle to a named variable and using that throughout. The availability of a dedicated `router' variable will come in handy in following patches. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 25 +++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 7304e8a29cf9..583d0b717e25 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -10664,15 +10664,16 @@ err_router_ops_init: void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) { + struct mlxsw_sp_router *router = mlxsw_sp->router; + unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), - &mlxsw_sp->router->netdevice_nb); - unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), - &mlxsw_sp->router->fib_nb); + &router->netdevice_nb); + unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), &router->fib_nb); unregister_nexthop_notifier(mlxsw_sp_net(mlxsw_sp), - &mlxsw_sp->router->nexthop_nb); - unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); - unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb); - unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb); + &router->nexthop_nb); + unregister_netevent_notifier(&router->netevent_nb); + unregister_inet6addr_notifier(&router->inet6addr_nb); + unregister_inetaddr_notifier(&router->inetaddr_nb); mlxsw_core_flush_owq(); mlxsw_sp_mp_hash_fini(mlxsw_sp); mlxsw_sp_neigh_fini(mlxsw_sp); @@ -10680,12 +10681,12 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_sp_vrs_fini(mlxsw_sp); mlxsw_sp_mr_fini(mlxsw_sp); mlxsw_sp_lpm_fini(mlxsw_sp); - rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht); - rhashtable_destroy(&mlxsw_sp->router->nexthop_ht); + rhashtable_destroy(&router->nexthop_group_ht); + rhashtable_destroy(&router->nexthop_ht); mlxsw_sp_ipips_fini(mlxsw_sp); mlxsw_sp_rifs_fini(mlxsw_sp); __mlxsw_sp_router_fini(mlxsw_sp); - cancel_delayed_work_sync(&mlxsw_sp->router->nh_grp_activity_dw); - mutex_destroy(&mlxsw_sp->router->lock); - kfree(mlxsw_sp->router); + cancel_delayed_work_sync(&router->nh_grp_activity_dw); + mutex_destroy(&router->lock); + kfree(router); } -- cgit v1.2.3 From 41b2bd208e8acf0f453e258f342a593332e3d2c8 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 9 Jun 2023 19:32:07 +0200 Subject: mlxsw: spectrum_router: Move here inetaddr validator notifiers The validation logic is already in the router code. Move there the notifier blocks themselves as well. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 18 +-------------- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 ---- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 26 ++++++++++++++++++---- .../net/ethernet/mellanox/mlxsw/spectrum_router.h | 2 ++ 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 02a327744a61..4609b13bda02 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -5139,14 +5139,6 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb, return notifier_from_errno(err); } -static struct notifier_block mlxsw_sp_inetaddr_valid_nb __read_mostly = { - .notifier_call = mlxsw_sp_inetaddr_valid_event, -}; - -static struct notifier_block mlxsw_sp_inet6addr_valid_nb __read_mostly = { - .notifier_call = mlxsw_sp_inet6addr_valid_event, -}; - static const struct pci_device_id mlxsw_sp1_pci_id_table[] = { {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SPECTRUM), 0}, {0, }, @@ -5191,12 +5183,9 @@ static int __init mlxsw_sp_module_init(void) { int err; - register_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb); - register_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); - err = mlxsw_core_driver_register(&mlxsw_sp1_driver); if (err) - goto err_sp1_core_driver_register; + return err; err = mlxsw_core_driver_register(&mlxsw_sp2_driver); if (err) @@ -5242,9 +5231,6 @@ err_sp3_core_driver_register: mlxsw_core_driver_unregister(&mlxsw_sp2_driver); err_sp2_core_driver_register: mlxsw_core_driver_unregister(&mlxsw_sp1_driver); -err_sp1_core_driver_register: - unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); - unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb); return err; } @@ -5258,8 +5244,6 @@ static void __exit mlxsw_sp_module_exit(void) mlxsw_core_driver_unregister(&mlxsw_sp3_driver); mlxsw_core_driver_unregister(&mlxsw_sp2_driver); mlxsw_core_driver_unregister(&mlxsw_sp1_driver); - unregister_inet6addr_validator_notifier(&mlxsw_sp_inet6addr_valid_nb); - unregister_inetaddr_validator_notifier(&mlxsw_sp_inetaddr_valid_nb); } module_init(mlxsw_sp_module_init); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 4c22f8004514..0b57c8d0cce0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -755,10 +755,6 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, const struct net_device *macvlan_dev); -int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused, - unsigned long event, void *ptr); -int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused, - unsigned long event, void *ptr); int mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct net_device *l3_dev, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 583d0b717e25..edfc42230285 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8879,8 +8879,8 @@ out: return notifier_from_errno(err); } -int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused, - unsigned long event, void *ptr) +static int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused, + unsigned long event, void *ptr) { struct in_validator_info *ivi = (struct in_validator_info *) ptr; struct net_device *dev = ivi->ivi_dev->dev; @@ -8962,8 +8962,8 @@ static int mlxsw_sp_inet6addr_event(struct notifier_block *nb, return NOTIFY_DONE; } -int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused, - unsigned long event, void *ptr) +static int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused, + unsigned long event, void *ptr) { struct in6_validator_info *i6vi = (struct in6_validator_info *) ptr; struct net_device *dev = i6vi->i6vi_dev->dev; @@ -10510,6 +10510,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, struct netlink_ext_ack *extack) { struct mlxsw_sp_router *router; + struct notifier_block *nb; int err; router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL); @@ -10588,6 +10589,17 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, if (err) goto err_register_inet6addr_notifier; + router->inetaddr_valid_nb.notifier_call = mlxsw_sp_inetaddr_valid_event; + err = register_inetaddr_validator_notifier(&router->inetaddr_valid_nb); + if (err) + goto err_register_inetaddr_valid_notifier; + + nb = &router->inet6addr_valid_nb; + nb->notifier_call = mlxsw_sp_inet6addr_valid_event; + err = register_inet6addr_validator_notifier(nb); + if (err) + goto err_register_inet6addr_valid_notifier; + mlxsw_sp->router->netevent_nb.notifier_call = mlxsw_sp_router_netevent_event; err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb); @@ -10627,6 +10639,10 @@ err_register_fib_notifier: err_register_nexthop_notifier: unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); err_register_netevent_notifier: + unregister_inet6addr_validator_notifier(&router->inet6addr_valid_nb); +err_register_inet6addr_valid_notifier: + unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb); +err_register_inetaddr_valid_notifier: unregister_inet6addr_notifier(&router->inet6addr_nb); err_register_inet6addr_notifier: unregister_inetaddr_notifier(&router->inetaddr_nb); @@ -10672,6 +10688,8 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) unregister_nexthop_notifier(mlxsw_sp_net(mlxsw_sp), &router->nexthop_nb); unregister_netevent_notifier(&router->netevent_nb); + unregister_inet6addr_validator_notifier(&router->inet6addr_valid_nb); + unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb); unregister_inet6addr_notifier(&router->inet6addr_nb); unregister_inetaddr_notifier(&router->inetaddr_nb); mlxsw_core_flush_owq(); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index 37d6e4c80e6a..229d38c514b9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -52,6 +52,8 @@ struct mlxsw_sp_router { struct notifier_block inetaddr_nb; struct notifier_block inet6addr_nb; struct notifier_block netdevice_nb; + struct notifier_block inetaddr_valid_nb; + struct notifier_block inet6addr_valid_nb; const struct mlxsw_sp_rif_ops **rif_ops_arr; const struct mlxsw_sp_ipip_ops **ipip_ops_arr; struct mlxsw_sp_router_nve_decap nve_decap_config; -- cgit v1.2.3 From 48dde35ea157b4b17bcccb8cd6fed3dfd9627a7a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 9 Jun 2023 19:32:08 +0200 Subject: mlxsw: spectrum_router: Pass router to mlxsw_sp_router_schedule_work() directly Instead of passing a notifier block and deducing the router pointer from that in the helper, do that in the caller, and pass the result. In the following patches, the pointer will also be made useful in the caller. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index edfc42230285..7b1877c116ed 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2748,13 +2748,11 @@ static void mlxsw_sp_router_update_priority_work(struct work_struct *work) } static int mlxsw_sp_router_schedule_work(struct net *net, - struct notifier_block *nb, + struct mlxsw_sp_router *router, void (*cb)(struct work_struct *)) { struct mlxsw_sp_netevent_work *net_work; - struct mlxsw_sp_router *router; - router = container_of(nb, struct mlxsw_sp_router, netevent_nb); if (!net_eq(net, mlxsw_sp_net(router->mlxsw_sp))) return NOTIFY_DONE; @@ -2773,11 +2771,14 @@ static int mlxsw_sp_router_netevent_event(struct notifier_block *nb, { struct mlxsw_sp_netevent_work *net_work; struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp_router *router; struct mlxsw_sp *mlxsw_sp; unsigned long interval; struct neigh_parms *p; struct neighbour *n; + router = container_of(nb, struct mlxsw_sp_router, netevent_nb); + switch (event) { case NETEVENT_DELAY_PROBE_TIME_UPDATE: p = ptr; @@ -2830,11 +2831,11 @@ static int mlxsw_sp_router_netevent_event(struct notifier_block *nb, break; case NETEVENT_IPV4_MPATH_HASH_UPDATE: case NETEVENT_IPV6_MPATH_HASH_UPDATE: - return mlxsw_sp_router_schedule_work(ptr, nb, + return mlxsw_sp_router_schedule_work(ptr, router, mlxsw_sp_router_mp_hash_event_work); case NETEVENT_IPV4_FWD_UPDATE_PRIORITY_UPDATE: - return mlxsw_sp_router_schedule_work(ptr, nb, + return mlxsw_sp_router_schedule_work(ptr, router, mlxsw_sp_router_update_priority_work); } -- cgit v1.2.3 From 14304e70634cb03913ec11b7f418df752d9ee3f8 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 9 Jun 2023 19:32:09 +0200 Subject: mlxsw: spectrum_router: Use the available router pointer for netevent handling This code handles NETEVENT_DELAY_PROBE_TIME_UPDATE, which is invoked every time the delay_probe_time changes. mlxsw router currently only maintains one timer, so the last delay_probe_time set wins. Currently, mlxsw uses mlxsw_sp_port_lower_dev_hold() to find a reference to the router. This is no longer necessary. But as a side effect, this makes sure that only updates to "interesting netdevices" (ones that have a physical netdevice lower) are projected. Retain that side effect by calling mlxsw_sp_port_dev_lower_find_rcu() and punting if there is none. Then just proceed using the router pointer that's already at hand in the helper. Note that previously, the code took and put a reference of the netdevice. Because the mlxsw_sp pointer is now obtained from the notifier block, the port pointer (non-) NULL-ness is all that's relevant, and the reference does not need to be taken anymore. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 7b1877c116ed..9d34fc846b93 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2766,13 +2766,22 @@ static int mlxsw_sp_router_schedule_work(struct net *net, return NOTIFY_DONE; } +static bool mlxsw_sp_dev_lower_is_port(struct net_device *dev) +{ + struct mlxsw_sp_port *mlxsw_sp_port; + + rcu_read_lock(); + mlxsw_sp_port = mlxsw_sp_port_dev_lower_find_rcu(dev); + rcu_read_unlock(); + return !!mlxsw_sp_port; +} + static int mlxsw_sp_router_netevent_event(struct notifier_block *nb, unsigned long event, void *ptr) { struct mlxsw_sp_netevent_work *net_work; struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_router *router; - struct mlxsw_sp *mlxsw_sp; unsigned long interval; struct neigh_parms *p; struct neighbour *n; @@ -2791,15 +2800,11 @@ static int mlxsw_sp_router_netevent_event(struct notifier_block *nb, /* We are in atomic context and can't take RTNL mutex, * so use RCU variant to walk the device chain. */ - mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(p->dev); - if (!mlxsw_sp_port) + if (!mlxsw_sp_dev_lower_is_port(p->dev)) return NOTIFY_DONE; - mlxsw_sp = mlxsw_sp_port->mlxsw_sp; interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME)); - mlxsw_sp->router->neighs_update.interval = interval; - - mlxsw_sp_port_dev_put(mlxsw_sp_port); + router->neighs_update.interval = interval; break; case NETEVENT_NEIGH_UPDATE: n = ptr; -- cgit v1.2.3 From 151b89f6025a95dd8083d5844f2746a9450653ca Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 9 Jun 2023 19:32:10 +0200 Subject: mlxsw: spectrum_router: Reuse work neighbor initialization in work scheduler After the struct mlxsw_sp_netevent_work.n field initialization is moved here, the body of code that handles NETEVENT_NEIGH_UPDATE is almost identical to the one in the helper function. Therefore defer to the helper instead of inlining the equivalent. Note that previously, the code took and put a reference of the netdevice. The new code defers to mlxsw_sp_dev_lower_is_port() to obviate the need for taking the reference. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 29 ++++++++-------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 9d34fc846b93..a0598aa4cb5d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2749,6 +2749,7 @@ static void mlxsw_sp_router_update_priority_work(struct work_struct *work) static int mlxsw_sp_router_schedule_work(struct net *net, struct mlxsw_sp_router *router, + struct neighbour *n, void (*cb)(struct work_struct *)) { struct mlxsw_sp_netevent_work *net_work; @@ -2762,6 +2763,7 @@ static int mlxsw_sp_router_schedule_work(struct net *net, INIT_WORK(&net_work->work, cb); net_work->mlxsw_sp = router->mlxsw_sp; + net_work->n = n; mlxsw_core_schedule_work(&net_work->work); return NOTIFY_DONE; } @@ -2779,12 +2781,11 @@ static bool mlxsw_sp_dev_lower_is_port(struct net_device *dev) static int mlxsw_sp_router_netevent_event(struct notifier_block *nb, unsigned long event, void *ptr) { - struct mlxsw_sp_netevent_work *net_work; - struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_router *router; unsigned long interval; struct neigh_parms *p; struct neighbour *n; + struct net *net; router = container_of(nb, struct mlxsw_sp_router, netevent_nb); @@ -2808,39 +2809,29 @@ static int mlxsw_sp_router_netevent_event(struct notifier_block *nb, break; case NETEVENT_NEIGH_UPDATE: n = ptr; + net = neigh_parms_net(n->parms); if (n->tbl->family != AF_INET && n->tbl->family != AF_INET6) return NOTIFY_DONE; - mlxsw_sp_port = mlxsw_sp_port_lower_dev_hold(n->dev); - if (!mlxsw_sp_port) + if (!mlxsw_sp_dev_lower_is_port(n->dev)) return NOTIFY_DONE; - net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC); - if (!net_work) { - mlxsw_sp_port_dev_put(mlxsw_sp_port); - return NOTIFY_BAD; - } - - INIT_WORK(&net_work->work, mlxsw_sp_router_neigh_event_work); - net_work->mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - net_work->n = n; - /* Take a reference to ensure the neighbour won't be * destructed until we drop the reference in delayed * work. */ neigh_clone(n); - mlxsw_core_schedule_work(&net_work->work); - mlxsw_sp_port_dev_put(mlxsw_sp_port); - break; + return mlxsw_sp_router_schedule_work(net, router, n, + mlxsw_sp_router_neigh_event_work); + case NETEVENT_IPV4_MPATH_HASH_UPDATE: case NETEVENT_IPV6_MPATH_HASH_UPDATE: - return mlxsw_sp_router_schedule_work(ptr, router, + return mlxsw_sp_router_schedule_work(ptr, router, NULL, mlxsw_sp_router_mp_hash_event_work); case NETEVENT_IPV4_FWD_UPDATE_PRIORITY_UPDATE: - return mlxsw_sp_router_schedule_work(ptr, router, + return mlxsw_sp_router_schedule_work(ptr, router, NULL, mlxsw_sp_router_update_priority_work); } -- cgit v1.2.3 From 0255f74845c0035d918697b7abff1fcf45ed2789 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 9 Jun 2023 19:32:11 +0200 Subject: mlxsw: Convert RIF-has-netdevice queries to a dedicated helper In a number of places, a netdevice underlying a RIF is obtained only to check if it a NULL pointer. In order to clean up the interface between the router and the other modules, add a new helper to specifically answer this question, and convert the relevant uses to this new interface. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c | 6 +++--- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 5 +++++ drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c index 5416093c0e35..c8a356accdf8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dpipe.c @@ -221,7 +221,7 @@ start_again: for (; i < rif_count; i++) { struct mlxsw_sp_rif *rif = mlxsw_sp_rif_by_index(mlxsw_sp, i); - if (!rif || !mlxsw_sp_rif_dev(rif)) + if (!rif || !mlxsw_sp_rif_has_dev(rif)) continue; err = mlxsw_sp_erif_entry_get(mlxsw_sp, &entry, rif, counters_enabled); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c index 1f6bc0c7e91d..b0f03009c130 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c @@ -720,7 +720,7 @@ int mlxsw_sp_mr_rif_add(struct mlxsw_sp_mr_table *mr_table, const struct net_device *rif_dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp_mr_vif *mr_vif; - if (!rif_dev) + if (!mlxsw_sp_rif_has_dev(rif)) return 0; mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif_dev); @@ -736,7 +736,7 @@ void mlxsw_sp_mr_rif_del(struct mlxsw_sp_mr_table *mr_table, const struct net_device *rif_dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp_mr_vif *mr_vif; - if (!rif_dev) + if (!mlxsw_sp_rif_has_dev(rif)) return; mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif_dev); @@ -754,7 +754,7 @@ void mlxsw_sp_mr_rif_mtu_update(struct mlxsw_sp_mr_table *mr_table, struct mlxsw_sp_mr *mr = mlxsw_sp->mr; struct mlxsw_sp_mr_vif *mr_vif; - if (!rif_dev) + if (!mlxsw_sp_rif_has_dev(rif)) return; /* Search for a VIF that use that RIF */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index a0598aa4cb5d..3259aede09ec 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8080,6 +8080,11 @@ const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif) return rif->dev; } +bool mlxsw_sp_rif_has_dev(const struct mlxsw_sp_rif *rif) +{ + return !!mlxsw_sp_rif_dev(rif); +} + static void mlxsw_sp_rif_push_l3_stats(struct mlxsw_sp_rif *rif) { struct rtnl_hw_stats64 stats = {}; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index 229d38c514b9..a6a8cf0b4500 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -94,6 +94,7 @@ u16 mlxsw_sp_ipip_lb_ul_rif_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif); u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev); int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif); const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif); +bool mlxsw_sp_rif_has_dev(const struct mlxsw_sp_rif *rif); int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif, enum mlxsw_sp_rif_counter_dir dir, -- cgit v1.2.3 From 5374a50f2eb617022cdd1aab6b1b7d4d2a952d56 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 9 Jun 2023 19:32:12 +0200 Subject: mlxsw: Convert does-RIF-have-this-netdev queries to a dedicated helper In a number of places, a netdevice underlying a RIF is obtained only to compare it to another pointer. In order to clean up the interface between the router and the other modules, add a new helper to specifically answer this question, and convert the relevant uses to this new interface. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c | 13 +++++-------- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 8 +++++++- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 2 ++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c index b0f03009c130..69cd689dbc83 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c @@ -704,12 +704,12 @@ void mlxsw_sp_mr_vif_del(struct mlxsw_sp_mr_table *mr_table, vifi_t vif_index) static struct mlxsw_sp_mr_vif * mlxsw_sp_mr_dev_vif_lookup(struct mlxsw_sp_mr_table *mr_table, - const struct net_device *dev) + const struct mlxsw_sp_rif *rif) { vifi_t vif_index; for (vif_index = 0; vif_index < MAXVIFS; vif_index++) - if (mr_table->vifs[vif_index].dev == dev) + if (mlxsw_sp_rif_dev_is(rif, mr_table->vifs[vif_index].dev)) return &mr_table->vifs[vif_index]; return NULL; } @@ -717,13 +717,12 @@ mlxsw_sp_mr_dev_vif_lookup(struct mlxsw_sp_mr_table *mr_table, int mlxsw_sp_mr_rif_add(struct mlxsw_sp_mr_table *mr_table, const struct mlxsw_sp_rif *rif) { - const struct net_device *rif_dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp_mr_vif *mr_vif; if (!mlxsw_sp_rif_has_dev(rif)) return 0; - mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif_dev); + mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif); if (!mr_vif) return 0; return mlxsw_sp_mr_vif_resolve(mr_table, mr_vif->dev, mr_vif, @@ -733,13 +732,12 @@ int mlxsw_sp_mr_rif_add(struct mlxsw_sp_mr_table *mr_table, void mlxsw_sp_mr_rif_del(struct mlxsw_sp_mr_table *mr_table, const struct mlxsw_sp_rif *rif) { - const struct net_device *rif_dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp_mr_vif *mr_vif; if (!mlxsw_sp_rif_has_dev(rif)) return; - mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif_dev); + mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif); if (!mr_vif) return; mlxsw_sp_mr_vif_unresolve(mr_table, mr_vif->dev, mr_vif); @@ -748,7 +746,6 @@ void mlxsw_sp_mr_rif_del(struct mlxsw_sp_mr_table *mr_table, void mlxsw_sp_mr_rif_mtu_update(struct mlxsw_sp_mr_table *mr_table, const struct mlxsw_sp_rif *rif, int mtu) { - const struct net_device *rif_dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp *mlxsw_sp = mr_table->mlxsw_sp; struct mlxsw_sp_mr_route_vif_entry *rve; struct mlxsw_sp_mr *mr = mlxsw_sp->mr; @@ -758,7 +755,7 @@ void mlxsw_sp_mr_rif_mtu_update(struct mlxsw_sp_mr_table *mr_table, return; /* Search for a VIF that use that RIF */ - mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif_dev); + mr_vif = mlxsw_sp_mr_dev_vif_lookup(mr_table, rif); if (!mr_vif) return; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 3259aede09ec..537730b22c7a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -7705,7 +7705,7 @@ mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp, for (i = 0; i < max_rifs; i++) if (mlxsw_sp->router->rifs[i] && - mlxsw_sp->router->rifs[i]->dev == dev) + mlxsw_sp_rif_dev_is(mlxsw_sp->router->rifs[i], dev)) return mlxsw_sp->router->rifs[i]; return NULL; @@ -8085,6 +8085,12 @@ bool mlxsw_sp_rif_has_dev(const struct mlxsw_sp_rif *rif) return !!mlxsw_sp_rif_dev(rif); } +bool mlxsw_sp_rif_dev_is(const struct mlxsw_sp_rif *rif, + const struct net_device *dev) +{ + return mlxsw_sp_rif_dev(rif) == dev; +} + static void mlxsw_sp_rif_push_l3_stats(struct mlxsw_sp_rif *rif) { struct rtnl_hw_stats64 stats = {}; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index a6a8cf0b4500..b941e781e476 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -95,6 +95,8 @@ u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev); int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif); const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif); bool mlxsw_sp_rif_has_dev(const struct mlxsw_sp_rif *rif); +bool mlxsw_sp_rif_dev_is(const struct mlxsw_sp_rif *rif, + const struct net_device *dev); int mlxsw_sp_rif_counter_value_get(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif, enum mlxsw_sp_rif_counter_dir dir, -- cgit v1.2.3 From df95ae66cc0a1606278677b1be4f2170c73876a9 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 9 Jun 2023 19:32:13 +0200 Subject: mlxsw: spectrum_router: Privatize mlxsw_sp_rif_dev() Now that the external users of mlxsw_sp_rif_dev() have been converted in the preceding patches, make the function static. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 537730b22c7a..f9328e8410f5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8075,7 +8075,7 @@ int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif) return rif->dev->ifindex; } -const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif) +static const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif) { return rif->dev; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index b941e781e476..5ff443f27136 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -93,7 +93,6 @@ u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *rif); u16 mlxsw_sp_ipip_lb_ul_rif_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif); u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev); int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif); -const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif); bool mlxsw_sp_rif_has_dev(const struct mlxsw_sp_rif *rif); bool mlxsw_sp_rif_dev_is(const struct mlxsw_sp_rif *rif, const struct net_device *dev); -- cgit v1.2.3 From 5e2ff6704a275be009be8979af17c52361b79b89 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 8 Jun 2023 22:26:25 +0200 Subject: scm: add SO_PASSPIDFD and SCM_PIDFD Implement SCM_PIDFD, a new type of CMSG type analogical to SCM_CREDENTIALS, but it contains pidfd instead of plain pid, which allows programmers not to care about PID reuse problem. We mask SO_PASSPIDFD feature if CONFIG_UNIX is not builtin because it depends on a pidfd_prepare() API which is not exported to the kernel modules. Idea comes from UAPI kernel group: https://uapi-group.org/kernel-features/ Big thanks to Christian Brauner and Lennart Poettering for productive discussions about this. Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: Lennart Poettering Cc: Luca Boccassi Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Tested-by: Luca Boccassi Reviewed-by: Kuniyuki Iwashima Reviewed-by: Christian Brauner Signed-off-by: Alexander Mikhalitsyn Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- arch/alpha/include/uapi/asm/socket.h | 2 ++ arch/mips/include/uapi/asm/socket.h | 2 ++ arch/parisc/include/uapi/asm/socket.h | 2 ++ arch/sparc/include/uapi/asm/socket.h | 2 ++ include/linux/net.h | 1 + include/linux/socket.h | 1 + include/net/scm.h | 39 +++++++++++++++++++++++++++++++-- include/uapi/asm-generic/socket.h | 2 ++ net/core/sock.c | 11 ++++++++++ net/mptcp/sockopt.c | 1 + net/unix/af_unix.c | 18 ++++++++++----- tools/include/uapi/asm-generic/socket.h | 2 ++ 12 files changed, 76 insertions(+), 7 deletions(-) diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index 739891b94136..ff310613ae64 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -137,6 +137,8 @@ #define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h index 18f3d95ecfec..762dcb80e4ec 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -148,6 +148,8 @@ #define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index f486d3dfb6bb..df16a3e16d64 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -129,6 +129,8 @@ #define SO_RCVMARK 0x4049 +#define SO_PASSPIDFD 0x404A + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h index 2fda57a3ea86..6e2847804fea 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -130,6 +130,8 @@ #define SO_RCVMARK 0x0054 +#define SO_PASSPIDFD 0x0055 + #if !defined(__KERNEL__) diff --git a/include/linux/net.h b/include/linux/net.h index 8defc8f1d82e..23324e9a2b3d 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -43,6 +43,7 @@ struct net; #define SOCK_PASSSEC 4 #define SOCK_SUPPORT_ZC 5 #define SOCK_CUSTOM_SOCKOPT 6 +#define SOCK_PASSPIDFD 7 #ifndef ARCH_HAS_SOCKET_TYPES /** diff --git a/include/linux/socket.h b/include/linux/socket.h index 3fd3436bc09f..58204700018a 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -177,6 +177,7 @@ static inline size_t msg_data_left(struct msghdr *msg) #define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ #define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ #define SCM_SECURITY 0x03 /* rw: security label */ +#define SCM_PIDFD 0x04 /* ro: pidfd (int) */ struct ucred { __u32 pid; diff --git a/include/net/scm.h b/include/net/scm.h index 585adc1346bd..c67f765a165b 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -120,12 +120,44 @@ static inline bool scm_has_secdata(struct socket *sock) } #endif /* CONFIG_SECURITY_NETWORK */ +static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm) +{ + struct file *pidfd_file = NULL; + int pidfd; + + /* + * put_cmsg() doesn't return an error if CMSG is truncated, + * that's why we need to opencode these checks here. + */ + if ((msg->msg_controllen <= sizeof(struct cmsghdr)) || + (msg->msg_controllen - sizeof(struct cmsghdr)) < sizeof(int)) { + msg->msg_flags |= MSG_CTRUNC; + return; + } + + WARN_ON_ONCE(!scm->pid); + pidfd = pidfd_prepare(scm->pid, 0, &pidfd_file); + + if (put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd)) { + if (pidfd_file) { + put_unused_fd(pidfd); + fput(pidfd_file); + } + + return; + } + + if (pidfd_file) + fd_install(pidfd, pidfd_file); +} + static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm, int flags) { if (!msg->msg_control) { - if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp || - scm_has_secdata(sock)) + if (test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags) || + scm->fp || scm_has_secdata(sock)) msg->msg_flags |= MSG_CTRUNC; scm_destroy(scm); return; @@ -141,6 +173,9 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); } + if (test_bit(SOCK_PASSPIDFD, &sock->flags)) + scm_pidfd_recv(msg, scm); + scm_destroy_cred(scm); scm_passec(sock, msg, scm); diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h index 638230899e98..b76169fdb80b 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -132,6 +132,8 @@ #define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) diff --git a/net/core/sock.c b/net/core/sock.c index 24f2761bdb1d..ed4eb4ba738b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1246,6 +1246,13 @@ set_sndbuf: clear_bit(SOCK_PASSCRED, &sock->flags); break; + case SO_PASSPIDFD: + if (valbool) + set_bit(SOCK_PASSPIDFD, &sock->flags); + else + clear_bit(SOCK_PASSPIDFD, &sock->flags); + break; + case SO_TIMESTAMP_OLD: case SO_TIMESTAMP_NEW: case SO_TIMESTAMPNS_OLD: @@ -1732,6 +1739,10 @@ int sk_getsockopt(struct sock *sk, int level, int optname, v.val = !!test_bit(SOCK_PASSCRED, &sock->flags); break; + case SO_PASSPIDFD: + v.val = !!test_bit(SOCK_PASSPIDFD, &sock->flags); + break; + case SO_PEERCRED: { struct ucred peercred; diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index d4258869ac48..e172a5848b0d 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -355,6 +355,7 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, case SO_BROADCAST: case SO_BSDCOMPAT: case SO_PASSCRED: + case SO_PASSPIDFD: case SO_PASSSEC: case SO_RXQ_OVFL: case SO_WIFI_STATUS: diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 653136d68b32..c46c2f5d860c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1361,7 +1361,8 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, if (err) goto out; - if (test_bit(SOCK_PASSCRED, &sock->flags) && + if ((test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) && !unix_sk(sk)->addr) { err = unix_autobind(sk); if (err) @@ -1469,7 +1470,8 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, if (err) goto out; - if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr) { + if ((test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { err = unix_autobind(sk); if (err) goto out; @@ -1670,6 +1672,8 @@ static void unix_sock_inherit_flags(const struct socket *old, { if (test_bit(SOCK_PASSCRED, &old->flags)) set_bit(SOCK_PASSCRED, &new->flags); + if (test_bit(SOCK_PASSPIDFD, &old->flags)) + set_bit(SOCK_PASSPIDFD, &new->flags); if (test_bit(SOCK_PASSSEC, &old->flags)) set_bit(SOCK_PASSSEC, &new->flags); } @@ -1819,8 +1823,10 @@ static bool unix_passcred_enabled(const struct socket *sock, const struct sock *other) { return test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags) || !other->sk_socket || - test_bit(SOCK_PASSCRED, &other->sk_socket->flags); + test_bit(SOCK_PASSCRED, &other->sk_socket->flags) || + test_bit(SOCK_PASSPIDFD, &other->sk_socket->flags); } /* @@ -1904,7 +1910,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, goto out; } - if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr) { + if ((test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { err = unix_autobind(sk); if (err) goto out; @@ -2718,7 +2725,8 @@ unlock: /* Never glue messages from different writers */ if (!unix_skb_scm_eq(skb, &scm)) break; - } else if (test_bit(SOCK_PASSCRED, &sock->flags)) { + } else if (test_bit(SOCK_PASSCRED, &sock->flags) || + test_bit(SOCK_PASSPIDFD, &sock->flags)) { /* Copy credentials */ scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); unix_set_secdata(&scm, skb); diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h index 8756df13be50..fbbc4bf53ee3 100644 --- a/tools/include/uapi/asm-generic/socket.h +++ b/tools/include/uapi/asm-generic/socket.h @@ -121,6 +121,8 @@ #define SO_RCVMARK 75 +#define SO_PASSPIDFD 76 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) -- cgit v1.2.3 From 7b26952a91cf65ff1cc867a2382a8964d8c0ee7d Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 8 Jun 2023 22:26:26 +0200 Subject: net: core: add getsockopt SO_PEERPIDFD Add SO_PEERPIDFD which allows to get pidfd of peer socket holder pidfd. This thing is direct analog of SO_PEERCRED which allows to get plain PID. Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: Lennart Poettering Cc: Luca Boccassi Cc: Daniel Borkmann Cc: Stanislav Fomichev Cc: bpf@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Reviewed-by: Christian Brauner Acked-by: Stanislav Fomichev Tested-by: Luca Boccassi Signed-off-by: Alexander Mikhalitsyn Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- arch/alpha/include/uapi/asm/socket.h | 1 + arch/mips/include/uapi/asm/socket.h | 1 + arch/parisc/include/uapi/asm/socket.h | 1 + arch/sparc/include/uapi/asm/socket.h | 1 + include/uapi/asm-generic/socket.h | 1 + net/core/sock.c | 33 +++++++++++++++++++++++++++++++++ net/unix/af_unix.c | 16 ++++++++++++++++ tools/include/uapi/asm-generic/socket.h | 1 + 8 files changed, 55 insertions(+) diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index ff310613ae64..e94f621903fe 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -138,6 +138,7 @@ #define SO_RCVMARK 75 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 #if !defined(__KERNEL__) diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h index 762dcb80e4ec..60ebaed28a4c 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -149,6 +149,7 @@ #define SO_RCVMARK 75 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 #if !defined(__KERNEL__) diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index df16a3e16d64..be264c2b1a11 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -130,6 +130,7 @@ #define SO_RCVMARK 0x4049 #define SO_PASSPIDFD 0x404A +#define SO_PEERPIDFD 0x404B #if !defined(__KERNEL__) diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h index 6e2847804fea..682da3714686 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -131,6 +131,7 @@ #define SO_RCVMARK 0x0054 #define SO_PASSPIDFD 0x0055 +#define SO_PEERPIDFD 0x0056 #if !defined(__KERNEL__) diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h index b76169fdb80b..8ce8a39a1e5f 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -133,6 +133,7 @@ #define SO_RCVMARK 75 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 #if !defined(__KERNEL__) diff --git a/net/core/sock.c b/net/core/sock.c index ed4eb4ba738b..ea66b1afadd0 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1758,6 +1758,39 @@ int sk_getsockopt(struct sock *sk, int level, int optname, goto lenout; } + case SO_PEERPIDFD: + { + struct pid *peer_pid; + struct file *pidfd_file = NULL; + int pidfd; + + if (len > sizeof(pidfd)) + len = sizeof(pidfd); + + spin_lock(&sk->sk_peer_lock); + peer_pid = get_pid(sk->sk_peer_pid); + spin_unlock(&sk->sk_peer_lock); + + if (!peer_pid) + return -ESRCH; + + pidfd = pidfd_prepare(peer_pid, 0, &pidfd_file); + put_pid(peer_pid); + if (pidfd < 0) + return pidfd; + + if (copy_to_sockptr(optval, &pidfd, len) || + copy_to_sockptr(optlen, &len, sizeof(int))) { + put_unused_fd(pidfd); + fput(pidfd_file); + + return -EFAULT; + } + + fd_install(pidfd, pidfd_file); + return 0; + } + case SO_PEERGROUPS: { const struct cred *cred; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index c46c2f5d860c..73c61a010b01 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -921,11 +921,26 @@ static void unix_unhash(struct sock *sk) */ } +static bool unix_bpf_bypass_getsockopt(int level, int optname) +{ + if (level == SOL_SOCKET) { + switch (optname) { + case SO_PEERPIDFD: + return true; + default: + return false; + } + } + + return false; +} + struct proto unix_dgram_proto = { .name = "UNIX", .owner = THIS_MODULE, .obj_size = sizeof(struct unix_sock), .close = unix_close, + .bpf_bypass_getsockopt = unix_bpf_bypass_getsockopt, #ifdef CONFIG_BPF_SYSCALL .psock_update_sk_prot = unix_dgram_bpf_update_proto, #endif @@ -937,6 +952,7 @@ struct proto unix_stream_proto = { .obj_size = sizeof(struct unix_sock), .close = unix_close, .unhash = unix_unhash, + .bpf_bypass_getsockopt = unix_bpf_bypass_getsockopt, #ifdef CONFIG_BPF_SYSCALL .psock_update_sk_prot = unix_stream_bpf_update_proto, #endif diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h index fbbc4bf53ee3..54d9c8bf7c55 100644 --- a/tools/include/uapi/asm-generic/socket.h +++ b/tools/include/uapi/asm-generic/socket.h @@ -122,6 +122,7 @@ #define SO_RCVMARK 75 #define SO_PASSPIDFD 76 +#define SO_PEERPIDFD 77 #if !defined(__KERNEL__) -- cgit v1.2.3 From ec80f488252b9ce0536c397364dd2c9cc820c1e1 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 8 Jun 2023 22:26:27 +0200 Subject: selftests: net: add SCM_PIDFD / SO_PEERPIDFD test Basic test to check consistency between: - SCM_CREDENTIALS and SCM_PIDFD - SO_PEERCRED and SO_PEERPIDFD Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Cc: linux-kselftest@vger.kernel.org Signed-off-by: Alexander Mikhalitsyn Signed-off-by: David S. Miller --- tools/testing/selftests/net/.gitignore | 1 + tools/testing/selftests/net/af_unix/Makefile | 3 +- tools/testing/selftests/net/af_unix/scm_pidfd.c | 430 ++++++++++++++++++++++++ 3 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/net/af_unix/scm_pidfd.c diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index f27a7338b60e..501854a89cc0 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -29,6 +29,7 @@ reuseport_bpf_numa reuseport_dualstack rxtimestamp sctp_hello +scm_pidfd sk_bind_sendto_listen sk_connect_zero_addr socket diff --git a/tools/testing/selftests/net/af_unix/Makefile b/tools/testing/selftests/net/af_unix/Makefile index 1e4b397cece6..221c387a7d7f 100644 --- a/tools/testing/selftests/net/af_unix/Makefile +++ b/tools/testing/selftests/net/af_unix/Makefile @@ -1,3 +1,4 @@ -TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect +CFLAGS += $(KHDR_INCLUDES) +TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect scm_pidfd include ../../lib.mk diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/selftests/net/af_unix/scm_pidfd.c new file mode 100644 index 000000000000..a86222143d79 --- /dev/null +++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest_harness.h" + +#define clean_errno() (errno == 0 ? "None" : strerror(errno)) +#define log_err(MSG, ...) \ + fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", __FILE__, __LINE__, \ + clean_errno(), ##__VA_ARGS__) + +#ifndef SCM_PIDFD +#define SCM_PIDFD 0x04 +#endif + +static void child_die() +{ + exit(1); +} + +static int safe_int(const char *numstr, int *converted) +{ + char *err = NULL; + long sli; + + errno = 0; + sli = strtol(numstr, &err, 0); + if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) + return -ERANGE; + + if (errno != 0 && sli == 0) + return -EINVAL; + + if (err == numstr || *err != '\0') + return -EINVAL; + + if (sli > INT_MAX || sli < INT_MIN) + return -ERANGE; + + *converted = (int)sli; + return 0; +} + +static int char_left_gc(const char *buffer, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (buffer[i] == ' ' || buffer[i] == '\t') + continue; + + return i; + } + + return 0; +} + +static int char_right_gc(const char *buffer, size_t len) +{ + int i; + + for (i = len - 1; i >= 0; i--) { + if (buffer[i] == ' ' || buffer[i] == '\t' || + buffer[i] == '\n' || buffer[i] == '\0') + continue; + + return i + 1; + } + + return 0; +} + +static char *trim_whitespace_in_place(char *buffer) +{ + buffer += char_left_gc(buffer, strlen(buffer)); + buffer[char_right_gc(buffer, strlen(buffer))] = '\0'; + return buffer; +} + +/* borrowed (with all helpers) from pidfd/pidfd_open_test.c */ +static pid_t get_pid_from_fdinfo_file(int pidfd, const char *key, size_t keylen) +{ + int ret; + char path[512]; + FILE *f; + size_t n = 0; + pid_t result = -1; + char *line = NULL; + + snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", pidfd); + + f = fopen(path, "re"); + if (!f) + return -1; + + while (getline(&line, &n, f) != -1) { + char *numstr; + + if (strncmp(line, key, keylen)) + continue; + + numstr = trim_whitespace_in_place(line + 4); + ret = safe_int(numstr, &result); + if (ret < 0) + goto out; + + break; + } + +out: + free(line); + fclose(f); + return result; +} + +static int cmsg_check(int fd) +{ + struct msghdr msg = { 0 }; + struct cmsghdr *cmsg; + struct iovec iov; + struct ucred *ucred = NULL; + int data = 0; + char control[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int))] = { 0 }; + int *pidfd = NULL; + pid_t parent_pid; + int err; + + iov.iov_base = &data; + iov.iov_len = sizeof(data); + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = control; + msg.msg_controllen = sizeof(control); + + err = recvmsg(fd, &msg, 0); + if (err < 0) { + log_err("recvmsg"); + return 1; + } + + if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { + log_err("recvmsg: truncated"); + return 1; + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_PIDFD) { + if (cmsg->cmsg_len < sizeof(*pidfd)) { + log_err("CMSG parse: SCM_PIDFD wrong len"); + return 1; + } + + pidfd = (void *)CMSG_DATA(cmsg); + } + + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS) { + if (cmsg->cmsg_len < sizeof(*ucred)) { + log_err("CMSG parse: SCM_CREDENTIALS wrong len"); + return 1; + } + + ucred = (void *)CMSG_DATA(cmsg); + } + } + + /* send(pfd, "x", sizeof(char), 0) */ + if (data != 'x') { + log_err("recvmsg: data corruption"); + return 1; + } + + if (!pidfd) { + log_err("CMSG parse: SCM_PIDFD not found"); + return 1; + } + + if (!ucred) { + log_err("CMSG parse: SCM_CREDENTIALS not found"); + return 1; + } + + /* pidfd from SCM_PIDFD should point to the parent process PID */ + parent_pid = + get_pid_from_fdinfo_file(*pidfd, "Pid:", sizeof("Pid:") - 1); + if (parent_pid != getppid()) { + log_err("wrong SCM_PIDFD %d != %d", parent_pid, getppid()); + return 1; + } + + return 0; +} + +struct sock_addr { + char sock_name[32]; + struct sockaddr_un listen_addr; + socklen_t addrlen; +}; + +FIXTURE(scm_pidfd) +{ + int server; + pid_t client_pid; + int startup_pipe[2]; + struct sock_addr server_addr; + struct sock_addr *client_addr; +}; + +FIXTURE_VARIANT(scm_pidfd) +{ + int type; + bool abstract; +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, stream_pathname) +{ + .type = SOCK_STREAM, + .abstract = 0, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, stream_abstract) +{ + .type = SOCK_STREAM, + .abstract = 1, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, dgram_pathname) +{ + .type = SOCK_DGRAM, + .abstract = 0, +}; + +FIXTURE_VARIANT_ADD(scm_pidfd, dgram_abstract) +{ + .type = SOCK_DGRAM, + .abstract = 1, +}; + +FIXTURE_SETUP(scm_pidfd) +{ + self->client_addr = mmap(NULL, sizeof(*self->client_addr), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + ASSERT_NE(MAP_FAILED, self->client_addr); +} + +FIXTURE_TEARDOWN(scm_pidfd) +{ + close(self->server); + + kill(self->client_pid, SIGKILL); + waitpid(self->client_pid, NULL, 0); + + if (!variant->abstract) { + unlink(self->server_addr.sock_name); + unlink(self->client_addr->sock_name); + } +} + +static void fill_sockaddr(struct sock_addr *addr, bool abstract) +{ + char *sun_path_buf = (char *)&addr->listen_addr.sun_path; + + addr->listen_addr.sun_family = AF_UNIX; + addr->addrlen = offsetof(struct sockaddr_un, sun_path); + snprintf(addr->sock_name, sizeof(addr->sock_name), "scm_pidfd_%d", getpid()); + addr->addrlen += strlen(addr->sock_name); + if (abstract) { + *sun_path_buf = '\0'; + addr->addrlen++; + sun_path_buf++; + } else { + unlink(addr->sock_name); + } + memcpy(sun_path_buf, addr->sock_name, strlen(addr->sock_name)); +} + +static void client(FIXTURE_DATA(scm_pidfd) *self, + const FIXTURE_VARIANT(scm_pidfd) *variant) +{ + int err; + int cfd; + socklen_t len; + struct ucred peer_cred; + int peer_pidfd; + pid_t peer_pid; + int on = 0; + + cfd = socket(AF_UNIX, variant->type, 0); + if (cfd < 0) { + log_err("socket"); + child_die(); + } + + if (variant->type == SOCK_DGRAM) { + fill_sockaddr(self->client_addr, variant->abstract); + + if (bind(cfd, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen)) { + log_err("bind"); + child_die(); + } + } + + if (connect(cfd, (struct sockaddr *)&self->server_addr.listen_addr, + self->server_addr.addrlen) != 0) { + log_err("connect"); + child_die(); + } + + on = 1; + if (setsockopt(cfd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) { + log_err("Failed to set SO_PASSCRED"); + child_die(); + } + + if (setsockopt(cfd, SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) { + log_err("Failed to set SO_PASSPIDFD"); + child_die(); + } + + close(self->startup_pipe[1]); + + if (cmsg_check(cfd)) { + log_err("cmsg_check failed"); + child_die(); + } + + /* skip further for SOCK_DGRAM as it's not applicable */ + if (variant->type == SOCK_DGRAM) + return; + + len = sizeof(peer_cred); + if (getsockopt(cfd, SOL_SOCKET, SO_PEERCRED, &peer_cred, &len)) { + log_err("Failed to get SO_PEERCRED"); + child_die(); + } + + len = sizeof(peer_pidfd); + if (getsockopt(cfd, SOL_SOCKET, SO_PEERPIDFD, &peer_pidfd, &len)) { + log_err("Failed to get SO_PEERPIDFD"); + child_die(); + } + + /* pid from SO_PEERCRED should point to the parent process PID */ + if (peer_cred.pid != getppid()) { + log_err("peer_cred.pid != getppid(): %d != %d", peer_cred.pid, getppid()); + child_die(); + } + + peer_pid = get_pid_from_fdinfo_file(peer_pidfd, + "Pid:", sizeof("Pid:") - 1); + if (peer_pid != peer_cred.pid) { + log_err("peer_pid != peer_cred.pid: %d != %d", peer_pid, peer_cred.pid); + child_die(); + } +} + +TEST_F(scm_pidfd, test) +{ + int err; + int pfd; + int child_status = 0; + + self->server = socket(AF_UNIX, variant->type, 0); + ASSERT_NE(-1, self->server); + + fill_sockaddr(&self->server_addr, variant->abstract); + + err = bind(self->server, (struct sockaddr *)&self->server_addr.listen_addr, self->server_addr.addrlen); + ASSERT_EQ(0, err); + + if (variant->type == SOCK_STREAM) { + err = listen(self->server, 1); + ASSERT_EQ(0, err); + } + + err = pipe(self->startup_pipe); + ASSERT_NE(-1, err); + + self->client_pid = fork(); + ASSERT_NE(-1, self->client_pid); + if (self->client_pid == 0) { + close(self->server); + close(self->startup_pipe[0]); + client(self, variant); + exit(0); + } + close(self->startup_pipe[1]); + + if (variant->type == SOCK_STREAM) { + pfd = accept(self->server, NULL, NULL); + ASSERT_NE(-1, pfd); + } else { + pfd = self->server; + } + + /* wait until the child arrives at checkpoint */ + read(self->startup_pipe[0], &err, sizeof(int)); + close(self->startup_pipe[0]); + + if (variant->type == SOCK_DGRAM) { + err = sendto(pfd, "x", sizeof(char), 0, (struct sockaddr *)&self->client_addr->listen_addr, self->client_addr->addrlen); + ASSERT_NE(-1, err); + } else { + err = send(pfd, "x", sizeof(char), 0); + ASSERT_NE(-1, err); + } + + close(pfd); + waitpid(self->client_pid, &child_status, 0); + ASSERT_EQ(0, WIFEXITED(child_status) ? WEXITSTATUS(child_status) : 1); +} + +TEST_HARNESS_MAIN -- cgit v1.2.3 From 97154bcf4d1b7cabefec8a72cff5fbb91d5afb7b Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Thu, 8 Jun 2023 22:26:28 +0200 Subject: af_unix: Kconfig: make CONFIG_UNIX bool Let's make CONFIG_UNIX a bool instead of a tristate. We've decided to do that during discussion about SCM_PIDFD patchset [1]. [1] https://lore.kernel.org/lkml/20230524081933.44dc8bea@kernel.org/ Cc: "David S. Miller" Cc: Eric Dumazet Cc: Jakub Kicinski Cc: Paolo Abeni Cc: Leon Romanovsky Cc: David Ahern Cc: Arnd Bergmann Cc: Kees Cook Cc: Christian Brauner Cc: Kuniyuki Iwashima Cc: Lennart Poettering Cc: Luca Boccassi Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-arch@vger.kernel.org Suggested-by: Jakub Kicinski Signed-off-by: Alexander Mikhalitsyn Acked-by: Christian Brauner Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- net/unix/Kconfig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/unix/Kconfig b/net/unix/Kconfig index b7f811216820..28b232f281ab 100644 --- a/net/unix/Kconfig +++ b/net/unix/Kconfig @@ -4,7 +4,7 @@ # config UNIX - tristate "Unix domain sockets" + bool "Unix domain sockets" help If you say Y here, you will include support for Unix domain sockets; sockets are the standard Unix mechanism for establishing and @@ -14,10 +14,6 @@ config UNIX an embedded system or something similar, you therefore definitely want to say Y here. - To compile this driver as a module, choose M here: the module will be - called unix. Note that several important services won't work - correctly if you say M here and then neglect to load the module. - Say Y unless you know what you are doing. config UNIX_SCM -- cgit v1.2.3 From 61ab5a060a57d7aa77cfbc860c84a25d7d1ac3cf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 9 Jun 2023 16:07:12 +0200 Subject: dt-bindings: net: drop unneeded quotes Cleanup bindings dropping unneeded quotes. Once all these are fixed, checking for this can be enabled in yamllint. Signed-off-by: Krzysztof Kozlowski Acked-by: Jernej Skrabec Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml | 2 +- Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml | 2 +- Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml | 2 +- Documentation/devicetree/bindings/net/brcm,bcmgenet.yaml | 2 +- Documentation/devicetree/bindings/net/intel,dwmac-plat.yaml | 2 +- Documentation/devicetree/bindings/net/mediatek-dwmac.yaml | 2 +- Documentation/devicetree/bindings/net/nxp,dwmac-imx.yaml | 2 +- Documentation/devicetree/bindings/net/rockchip-dwmac.yaml | 2 +- Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml | 4 ++-- Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml index 3bd912ed7c7e..23e92be33ac8 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun7i-a20-gmac.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Allwinner A20 GMAC allOf: - - $ref: "snps,dwmac.yaml#" + - $ref: snps,dwmac.yaml# maintainers: - Chen-Yu Tsai diff --git a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml index 47bc2057e629..4bfac9186886 100644 --- a/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml +++ b/Documentation/devicetree/bindings/net/allwinner,sun8i-a83t-emac.yaml @@ -63,7 +63,7 @@ required: - syscon allOf: - - $ref: "snps,dwmac.yaml#" + - $ref: snps,dwmac.yaml# - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml b/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml index a2c51a84efa5..ee7a65b528cd 100644 --- a/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml +++ b/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml @@ -27,7 +27,7 @@ select: - compatible allOf: - - $ref: "snps,dwmac.yaml#" + - $ref: snps,dwmac.yaml# - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/net/brcm,bcmgenet.yaml b/Documentation/devicetree/bindings/net/brcm,bcmgenet.yaml index 0e5e5db32faf..7c90a4390531 100644 --- a/Documentation/devicetree/bindings/net/brcm,bcmgenet.yaml +++ b/Documentation/devicetree/bindings/net/brcm,bcmgenet.yaml @@ -55,7 +55,7 @@ properties: patternProperties: "^mdio@[0-9a-f]+$": type: object - $ref: "brcm,unimac-mdio.yaml" + $ref: brcm,unimac-mdio.yaml description: GENET internal UniMAC MDIO bus diff --git a/Documentation/devicetree/bindings/net/intel,dwmac-plat.yaml b/Documentation/devicetree/bindings/net/intel,dwmac-plat.yaml index d23fa3771210..42a0bc94312c 100644 --- a/Documentation/devicetree/bindings/net/intel,dwmac-plat.yaml +++ b/Documentation/devicetree/bindings/net/intel,dwmac-plat.yaml @@ -19,7 +19,7 @@ select: - compatible allOf: - - $ref: "snps,dwmac.yaml#" + - $ref: snps,dwmac.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/net/mediatek-dwmac.yaml b/Documentation/devicetree/bindings/net/mediatek-dwmac.yaml index 0fa2132fa4f4..08d74ca0769c 100644 --- a/Documentation/devicetree/bindings/net/mediatek-dwmac.yaml +++ b/Documentation/devicetree/bindings/net/mediatek-dwmac.yaml @@ -25,7 +25,7 @@ select: - compatible allOf: - - $ref: "snps,dwmac.yaml#" + - $ref: snps,dwmac.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/net/nxp,dwmac-imx.yaml b/Documentation/devicetree/bindings/net/nxp,dwmac-imx.yaml index 63409cbff5ad..4c01cae7c93a 100644 --- a/Documentation/devicetree/bindings/net/nxp,dwmac-imx.yaml +++ b/Documentation/devicetree/bindings/net/nxp,dwmac-imx.yaml @@ -24,7 +24,7 @@ select: - compatible allOf: - - $ref: "snps,dwmac.yaml#" + - $ref: snps,dwmac.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml index 2a21bbe02892..176ea5f90251 100644 --- a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml +++ b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml @@ -32,7 +32,7 @@ select: - compatible allOf: - - $ref: "snps,dwmac.yaml#" + - $ref: snps,dwmac.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml b/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml index 395a4650e285..c9c25132d154 100644 --- a/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml +++ b/Documentation/devicetree/bindings/net/ti,k3-am654-cpsw-nuss.yaml @@ -168,14 +168,14 @@ properties: patternProperties: "^mdio@[0-9a-f]+$": type: object - $ref: "ti,davinci-mdio.yaml#" + $ref: ti,davinci-mdio.yaml# description: CPSW MDIO bus. "^cpts@[0-9a-f]+": type: object - $ref: "ti,k3-am654-cpts.yaml#" + $ref: ti,k3-am654-cpts.yaml# description: CPSW Common Platform Time Sync (CPTS) module. diff --git a/Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml b/Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml index 474fa8bcf302..052f636158b3 100644 --- a/Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml +++ b/Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml @@ -19,7 +19,7 @@ select: - compatible allOf: - - $ref: "snps,dwmac.yaml#" + - $ref: snps,dwmac.yaml# properties: compatible: -- cgit v1.2.3 From b30a1f305b7bfde19c2ddbb053b51705eef65553 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 9 Jun 2023 12:26:16 -0600 Subject: mdio: mdio-mux-mmioreg: Use of_property_read_reg() to parse "reg" Use the recently added of_property_read_reg() helper to get the untranslated "reg" address value. Signed-off-by: Rob Herring Signed-off-by: David S. Miller --- drivers/net/mdio/mdio-mux-mmioreg.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/mdio/mdio-mux-mmioreg.c b/drivers/net/mdio/mdio-mux-mmioreg.c index c02c9c660016..09af150ed774 100644 --- a/drivers/net/mdio/mdio-mux-mmioreg.c +++ b/drivers/net/mdio/mdio-mux-mmioreg.c @@ -140,14 +140,15 @@ static int mdio_mux_mmioreg_probe(struct platform_device *pdev) * set any bits outside of the 'mask'. */ for_each_available_child_of_node(np, np2) { - iprop = of_get_property(np2, "reg", &len); - if (!iprop || len != sizeof(uint32_t)) { + u64 reg; + + if (of_property_read_reg(np2, 0, ®, NULL)) { dev_err(&pdev->dev, "mdio-mux child node %pOF is " "missing a 'reg' property\n", np2); of_node_put(np2); return -ENODEV; } - if (be32_to_cpup(iprop) & ~s->mask) { + if ((u32)reg & ~s->mask) { dev_err(&pdev->dev, "mdio-mux child node %pOF has " "a 'reg' value with unmasked bits\n", np2); -- cgit v1.2.3 From 008bcd6835a2f00a46bc91cad32de50d57d1b196 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:35 -0700 Subject: tools: ynl-gen: support excluding tricky ops The ethtool family has a small handful of quite tricky ops and a lot of simple very useful ops. Teach ynl-gen to skip ops so that we can bypass the tricky ones. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/lib/nlspec.py | 12 ++++++++++-- tools/net/ynl/ynl-gen-c.py | 10 +++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index c5d4a6d476a0..1ba572cae27b 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -334,7 +334,7 @@ class SpecFamily(SpecElement): consts dict of all constants/enums fixed_header string, optional name of family default fixed header struct """ - def __init__(self, spec_path, schema_path=None): + def __init__(self, spec_path, schema_path=None, exclude_ops=None): with open(spec_path, "r") as stream: prefix = '# SPDX-License-Identifier: ' first = stream.readline().strip() @@ -349,6 +349,8 @@ class SpecFamily(SpecElement): super().__init__(self, spec) + self._exclude_ops = exclude_ops if exclude_ops else [] + self.proto = self.yaml.get('protocol', 'genetlink') self.msg_id_model = self.yaml['operations'].get('enum-model', 'unified') @@ -449,7 +451,13 @@ class SpecFamily(SpecElement): req_val = None if rsp_val == rsp_val_next: rsp_val = None - op = self.new_operation(elem, req_val, rsp_val) + + skip = False + for exclude in self._exclude_ops: + skip |= bool(exclude.match(elem['name'])) + if not skip: + op = self.new_operation(elem, req_val, rsp_val) + req_val = req_val_next rsp_val = rsp_val_next diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 7b051c00cfc3..a55c4cec2529 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -4,6 +4,7 @@ import argparse import collections import os +import re import yaml from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry @@ -739,7 +740,7 @@ class Operation(SpecOperation): class Family(SpecFamily): - def __init__(self, file_name): + def __init__(self, file_name, exclude_ops): # Added by resolve: self.c_name = None delattr(self, "c_name") @@ -754,7 +755,7 @@ class Family(SpecFamily): self.hooks = None delattr(self, "hooks") - super().__init__(file_name) + super().__init__(file_name, exclude_ops=exclude_ops) self.fam_key = c_upper(self.yaml.get('c-family-name', self.yaml["name"] + '_FAMILY_NAME')) self.ver_key = c_upper(self.yaml.get('c-version-name', self.yaml["name"] + '_FAMILY_VERSION')) @@ -2241,6 +2242,7 @@ def main(): parser.add_argument('--header', dest='header', action='store_true', default=None) parser.add_argument('--source', dest='header', action='store_false') parser.add_argument('--user-header', nargs='+', default=[]) + parser.add_argument('--exclude-op', action='append', default=[]) parser.add_argument('-o', dest='out_file', type=str) args = parser.parse_args() @@ -2249,8 +2251,10 @@ def main(): if args.header is None: parser.error("--header or --source is required") + exclude_ops = [re.compile(expr) for expr in args.exclude_op] + try: - parsed = Family(args.spec) + parsed = Family(args.spec, exclude_ops) if parsed.license != '((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)': print('Spec license:', parsed.license) print('License must be: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)') -- cgit v1.2.3 From 33eedb0071c84ee47ab329a90e8e7b0653bcba33 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:36 -0700 Subject: tools: ynl-gen: record extra args for regen ynl-regen needs to know the arguments used to generate a file. Record excluded ops and, while at it, user headers. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/ynl-gen-c.py | 5 +++++ tools/net/ynl/ynl-regen.sh | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index a55c4cec2529..89d9471e9c2b 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -2281,6 +2281,11 @@ def main(): cw.p("/* Do not edit directly, auto-generated from: */") cw.p(f"/*\t{spec_kernel} */") cw.p(f"/* YNL-GEN {args.mode} {'header' if args.header else 'source'} */") + if args.exclude_op or args.user_header: + line = '' + line += ' --user-header '.join([''] + args.user_header) + line += ' --exclude-op '.join([''] + args.exclude_op) + cw.p(f'/* YNL-ARG{line} */') cw.nl() if args.mode == 'uapi': diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh index 2a4525e2aa17..8d4ca6a50582 100755 --- a/tools/net/ynl/ynl-regen.sh +++ b/tools/net/ynl/ynl-regen.sh @@ -19,6 +19,7 @@ for f in $files; do # params: 0 1 2 3 # $YAML YNL-GEN kernel $mode params=( $(git grep -B1 -h '/\* YNL-GEN' $f | sed 's@/\*\(.*\)\*/@\1@') ) + args=$(sed -n 's@/\* YNL-ARG \(.*\) \*/@\1@p' $f) if [ $f -nt ${params[0]} -a -z "$force" ]; then echo -e "\tSKIP $f" @@ -26,5 +27,6 @@ for f in $files; do fi echo -e "\tGEN ${params[2]}\t$f" - $TOOL --mode ${params[2]} --${params[3]} --spec $KDIR/${params[0]} -o $f + $TOOL --mode ${params[2]} --${params[3]} --spec $KDIR/${params[0]} \ + $args -o $f done -- cgit v1.2.3 From ed2042cc77f1cef4850a891dc93d80fb1aa6c955 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:37 -0700 Subject: netlink: specs: support setting prefix-name per attribute Ethtool's PSE PoDL has a attr nest with different prefixes: /* Power Sourcing Equipment */ enum { ETHTOOL_A_PSE_UNSPEC, ETHTOOL_A_PSE_HEADER, /* nest - _A_HEADER_* */ ETHTOOL_A_PODL_PSE_ADMIN_STATE, /* u32 */ ETHTOOL_A_PODL_PSE_ADMIN_CONTROL, /* u32 */ ETHTOOL_A_PODL_PSE_PW_D_STATUS, /* u32 */ Header has a prefix of ETHTOOL_A_PSE_ and other attrs prefix of ETHTOOL_A_PODL_PSE_ we can't cover them uniformly. If PODL was after PSE life would be easy. Now we either need to add prefixes to attr names which is yucky or support setting prefix name per attr. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/netlink/genetlink-c.yaml | 4 ++++ Documentation/netlink/genetlink-legacy.yaml | 4 ++++ tools/net/ynl/ynl-gen-c.py | 7 +++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index 8e8c17b0a6c6..0519c257ecf4 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -195,6 +195,10 @@ properties: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' sub-type: *attr-type + # Start genetlink-c + name-prefix: + type: string + # End genetlink-c # Make sure name-prefix does not appear in subsets (subsets inherit naming) dependencies: diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index ac4350498f5e..b474889b49ff 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -226,6 +226,10 @@ properties: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' sub-type: *attr-type + # Start genetlink-c + name-prefix: + type: string + # End genetlink-c # Start genetlink-legacy struct: description: Name of the struct type used for the attribute. diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 89d9471e9c2b..05b49aa459a7 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -58,8 +58,11 @@ class Type(SpecAttr): delattr(self, "enum_name") def resolve(self): - self.enum_name = f"{self.attr_set.name_prefix}{self.name}" - self.enum_name = c_upper(self.enum_name) + if 'name-prefix' in self.attr: + enum_name = f"{self.attr['name-prefix']}{self.name}" + else: + enum_name = f"{self.attr_set.name_prefix}{self.name}" + self.enum_name = c_upper(enum_name) def is_multi_val(self): return None -- cgit v1.2.3 From d4813b11d679c80d4c3e20d27dafcd6d3317a69c Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:38 -0700 Subject: netlink: specs: ethtool: add C render hints Most of the C enum names are guessed correctly, but there is a handful of corner cases we need to name explicitly. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/netlink/specs/ethtool.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 4846345bade4..b0e4147d0890 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -9,6 +9,7 @@ doc: Partial family for Ethtool Netlink. definitions: - name: udp-tunnel-type + enum-name: type: enum entries: [ vxlan, geneve, vxlan-gpe ] @@ -836,12 +837,15 @@ attribute-sets: - name: admin-state type: u32 + name-prefix: ethtool-a-podl-pse- - name: admin-control type: u32 + name-prefix: ethtool-a-podl-pse- - name: pw-d-status type: u32 + name-prefix: ethtool-a-podl-pse- - name: rss attributes: @@ -895,6 +899,7 @@ attribute-sets: operations: enum-model: directional + name-prefix: ethtool-msg- list: - name: strset-get -- cgit v1.2.3 From dddc9f53da3e1e359e56edc8da301e145e3b97df Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:39 -0700 Subject: tools: ynl-gen: don't generate enum types if unnamed If attr set or enum has empty enum name we need to use u32 or int as function arguments and struct members. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/ynl-gen-c.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 05b49aa459a7..82ee6c7fa22d 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -268,7 +268,8 @@ class TypeScalar(Type): else: self.is_bitfield = False - if 'enum' in self.attr and not self.is_bitfield: + maybe_enum = not self.is_bitfield and 'enum' in self.attr + if maybe_enum and self.family.consts[self.attr['enum']].enum_name: self.type_name = f"enum {self.family.name}_{c_lower(self.attr['enum'])}" else: self.type_name = '__' + self.type @@ -652,7 +653,14 @@ class EnumEntry(SpecEnumEntry): class EnumSet(SpecEnumSet): def __init__(self, family, yaml): self.render_name = c_lower(family.name + '-' + yaml['name']) - self.enum_name = 'enum ' + self.render_name + + if 'enum-name' in yaml: + if yaml['enum-name']: + self.enum_name = 'enum ' + c_lower(yaml['enum-name']) + else: + self.enum_name = None + else: + self.enum_name = 'enum ' + self.render_name self.value_pfx = yaml.get('name-prefix', f"{family.name}-{yaml['name']}-") -- cgit v1.2.3 From 2c9d47a095f7d0380e35064121bc8838dbf136cb Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:40 -0700 Subject: tools: ynl-gen: resolve enum vs struct name conflicts Ethtool has an attribute set called stringset, from which we'll generate struct ethtool_stringset. Unfortunately, the old ethtool header declares enum ethtool_stringset (the same name), to which compilers object. This seems unavoidable. Check struct names against known constants and append an underscore if conflict is detected. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/ynl-gen-c.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 82ee6c7fa22d..870f98d0e12c 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -49,6 +49,11 @@ class Type(SpecAttr): else: self.nested_render_name = f"{family.name}_{c_lower(self.nested_attrs)}" + if self.nested_attrs in self.family.consts: + self.nested_struct_type = 'struct ' + self.nested_render_name + '_' + else: + self.nested_struct_type = 'struct ' + self.nested_render_name + self.c_name = c_lower(self.name) if self.c_name in _C_KW: self.c_name += '_' @@ -425,7 +430,7 @@ class TypeBinary(Type): class TypeNest(Type): def _complex_member_type(self, ri): - return f"struct {self.nested_render_name}" + return self.nested_struct_type def free(self, ri, var, ref): ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name});') @@ -470,7 +475,7 @@ class TypeMultiAttr(Type): def _complex_member_type(self, ri): if 'type' not in self.attr or self.attr['type'] == 'nest': - return f"struct {self.nested_render_name}" + return self.nested_struct_type elif self.attr['type'] in scalars: scalar_pfx = '__' if ri.ku_space == 'user' else '' return scalar_pfx + self.attr['type'] @@ -530,7 +535,7 @@ class TypeArrayNest(Type): def _complex_member_type(self, ri): if 'sub-type' not in self.attr or self.attr['sub-type'] == 'nest': - return f"struct {self.nested_render_name}" + return self.nested_struct_type elif self.attr['sub-type'] in scalars: scalar_pfx = '__' if ri.ku_space == 'user' else '' return scalar_pfx + self.attr['sub-type'] @@ -550,7 +555,7 @@ class TypeArrayNest(Type): class TypeNestTypeValue(Type): def _complex_member_type(self, ri): - return f"struct {self.nested_render_name}" + return self.nested_struct_type def _attr_typol(self): return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' @@ -593,6 +598,8 @@ class Struct: else: self.render_name = f"{family.name}_{c_lower(space_name)}" self.struct_name = 'struct ' + self.render_name + if self.nested and space_name in family.consts: + self.struct_name += '_' self.ptr_name = self.struct_name + ' *' self.request = False @@ -994,10 +1001,13 @@ class RenderInfo: if not self.attr_set: self.attr_set = op['attribute-set'] + self.type_name_conflict = False if op: self.type_name = c_lower(op.name) else: self.type_name = c_lower(attr_set) + if attr_set in family.consts: + self.type_name_conflict = True self.cw = cw @@ -1634,12 +1644,17 @@ def print_alloc_wrapper(ri, direction): def print_free_prototype(ri, direction, suffix=';'): name = op_prefix(ri, direction) + struct_name = name + if ri.type_name_conflict: + struct_name += '_' arg = free_arg_name(direction) - ri.cw.write_func_prot('void', f"{name}_free", [f"struct {name} *{arg}"], suffix=suffix) + ri.cw.write_func_prot('void', f"{name}_free", [f"struct {struct_name} *{arg}"], suffix=suffix) def _print_type(ri, direction, struct): suffix = f'_{ri.type_name}{direction_to_suffix[direction]}' + if not direction and ri.type_name_conflict: + suffix += '_' if ri.op_mode == 'dump': suffix += '_dump' -- cgit v1.2.3 From 180ad455273a7d3ba95ec21d28c1fee6766f166d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:41 -0700 Subject: netlink: specs: ethtool: add empty enum stringset C does not allow defining structures and enums with the same name. Since enum ethtool_stringset exists in the uAPI we need to include at least a stub of it in the spec. This will trigger name collision avoidance in the code gen. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/netlink/specs/ethtool.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index b0e4147d0890..d674731629c4 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -12,6 +12,10 @@ definitions: enum-name: type: enum entries: [ vxlan, geneve, vxlan-gpe ] + - + name: stringset + type: enum + entries: [] attribute-sets: - -- cgit v1.2.3 From 37c852222712e1968da858961709a179150acd41 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:42 -0700 Subject: netlink: specs: ethtool: untangle UDP tunnels and cable test a bit UDP tunnel and cable test messages have a lot of nests, which do not match the names of the enum entries in C uAPI. Some of the structure / nesting also looks wrong. Untangle this a little bit based on the names, comments and educated guesses, I haven't actually tested the results. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/netlink/specs/ethtool.yaml | 82 ++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index d674731629c4..17b7b5028e2b 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -582,7 +582,7 @@ attribute-sets: name: phc-index type: u32 - - name: cable-test-ntf-nest-result + name: cable-result attributes: - name: pair @@ -591,7 +591,7 @@ attribute-sets: name: code type: u8 - - name: cable-test-ntf-nest-fault-length + name: cable-fault-length attributes: - name: pair @@ -600,18 +600,25 @@ attribute-sets: name: cm type: u32 - - name: cable-test-ntf-nest + name: cable-nest attributes: - name: result type: nest - nested-attributes: cable-test-ntf-nest-result + nested-attributes: cable-result - name: fault-length type: nest - nested-attributes: cable-test-ntf-nest-fault-length + nested-attributes: cable-fault-length - name: cable-test + attributes: + - + name: header + type: nest + nested-attributes: header + - + name: cable-test-ntf attributes: - name: header @@ -623,7 +630,7 @@ attribute-sets: - name: nest type: nest - nested-attributes: cable-test-ntf-nest + nested-attributes: cable-nest - name: cable-test-tdr-cfg attributes: @@ -637,8 +644,22 @@ attribute-sets: name: step type: u32 - - name: pari + name: pair type: u8 + - + name: cable-test-tdr-ntf + attributes: + - + name: header + type: nest + nested-attributes: header + - + name: status + type: u8 + - + name: nest + type: nest + nested-attributes: cable-nest - name: cable-test-tdr attributes: @@ -651,7 +672,7 @@ attribute-sets: type: nest nested-attributes: cable-test-tdr-cfg - - name: tunnel-info-udp-entry + name: tunnel-udp-entry attributes: - name: port @@ -662,7 +683,7 @@ attribute-sets: type: u32 enum: udp-tunnel-type - - name: tunnel-info-udp-table + name: tunnel-udp-table attributes: - name: size @@ -672,9 +693,17 @@ attribute-sets: type: nest nested-attributes: bitset - - name: udp-ports + name: entry type: nest - nested-attributes: tunnel-info-udp-entry + multi-attr: true + nested-attributes: tunnel-udp-entry + - + name: tunnel-udp + attributes: + - + name: table + type: nest + nested-attributes: tunnel-udp-table - name: tunnel-info attributes: @@ -685,7 +714,7 @@ attribute-sets: - name: udp-ports type: nest - nested-attributes: tunnel-info-udp-table + nested-attributes: tunnel-udp - name: fec-stat attributes: @@ -1357,10 +1386,16 @@ operations: request: attributes: - header - reply: - attributes: - - header - - cable-test-ntf-nest + - + name: cable-test-ntf + doc: Cable test notification. + + attribute-set: cable-test-ntf + + event: + attributes: + - header + - status - name: cable-test-tdr-act doc: Cable test TDR. @@ -1371,10 +1406,17 @@ operations: request: attributes: - header - reply: - attributes: - - header - - cable-test-tdr-cfg + - + name: cable-test-tdr-ntf + doc: Cable test TDR notification. + + attribute-set: cable-test-tdr-ntf + + event: + attributes: + - header + - status + - nest - name: tunnel-info-get doc: Get tsinfo params. -- cgit v1.2.3 From 709d0c3b3d4c385793fd12cc57e400c8e036e744 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:43 -0700 Subject: netlink: specs: ethtool: untangle stats-get Code gen for stats is a bit of a challenge, but from looking at the attrs I think that the format isn't quite right. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/netlink/specs/ethtool.yaml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 17b7b5028e2b..00c1ab04b857 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -793,16 +793,29 @@ attribute-sets: type: u32 - name: stat - type: nest - nested-attributes: u64 + type: u64 + type-value: [ id ] - name: hist-rx type: nest - nested-attributes: u64 + nested-attributes: stats-grp-hist - name: hist-tx type: nest - nested-attributes: u64 + nested-attributes: stats-grp-hist + - + name: hist-bkt-low + type: u32 + - + name: hist-bkt-hi + type: u32 + - + name: hist-val + type: u64 + - + name: stats-grp-hist + subset-of: stats-grp + attributes: - name: hist-bkt-low type: u32 -- cgit v1.2.3 From 68335713d2eaf8e3e064c584b39da45fdee6e365 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:44 -0700 Subject: netlink: specs: ethtool: mark pads as pads Pad is a separate type. Even though in practice they can only be a u32 the value should be discarded. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- Documentation/netlink/specs/ethtool.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 00c1ab04b857..837b565577ca 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -502,7 +502,7 @@ attribute-sets: attributes: - name: pad - type: u32 + type: pad - name: tx-frames type: u64 @@ -720,7 +720,7 @@ attribute-sets: attributes: - name: pad - type: u8 + type: pad - name: corrected type: binary @@ -784,7 +784,7 @@ attribute-sets: attributes: - name: pad - type: u32 + type: pad - name: id type: u32 @@ -830,7 +830,7 @@ attribute-sets: attributes: - name: pad - type: u32 + type: pad - name: header type: nest -- cgit v1.2.3 From 2d7be507d65e90099c76631bf0448d0b30f7f203 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:45 -0700 Subject: tools: ynl: generate code for the ethtool family Generate the protocol code for ethtool. Skip the stats for now, they are the only outlier in terms of complexity. Stats are a sort-of semi-polymorphic (attr space of a nest depends on value of another attr) or a type-value-scalar, depending on how one wants to look at it... A challenge for another time. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/generated/Makefile | 9 +- tools/net/ynl/generated/ethtool-user.c | 6353 ++++++++++++++++++++++++++++++++ tools/net/ynl/generated/ethtool-user.h | 5531 +++++++++++++++++++++++++++ 3 files changed, 11890 insertions(+), 3 deletions(-) create mode 100644 tools/net/ynl/generated/ethtool-user.c create mode 100644 tools/net/ynl/generated/ethtool-user.h diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 8ce610910b8d..f15c24893296 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -7,9 +7,12 @@ ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan endif +YNL_GEN_ARG_ethtool:=--user-header linux/ethtool_netlink.h \ + --exclude-op stats-get + TOOL:=../ynl-gen-c.py -GENS:=devlink handshake fou netdev +GENS:=ethtool devlink handshake fou netdev SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) @@ -22,11 +25,11 @@ protos.a: $(OBJS) %-user.h: ../../../../Documentation/netlink/specs/%.yaml $(TOOL) @echo -e "\tGEN $@" - @$(TOOL) --mode user --header --spec $< > $@ + @$(TOOL) --mode user --header --spec $< $(YNL_GEN_ARG_$*) > $@ %-user.c: ../../../../Documentation/netlink/specs/%.yaml $(TOOL) @echo -e "\tGEN $@" - @$(TOOL) --mode user --source --spec $< > $@ + @$(TOOL) --mode user --source --spec $< $(YNL_GEN_ARG_$*) > $@ %-user.o: %-user.c %-user.h @echo -e "\tCC $@" diff --git a/tools/net/ynl/generated/ethtool-user.c b/tools/net/ynl/generated/ethtool-user.c new file mode 100644 index 000000000000..74b883a14958 --- /dev/null +++ b/tools/net/ynl/generated/ethtool-user.c @@ -0,0 +1,6353 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/ethtool.yaml */ +/* YNL-GEN user source */ +/* YNL-ARG --user-header linux/ethtool_netlink.h --exclude-op stats-get */ + +#include +#include +#include "ethtool-user.h" +#include "ynl.h" +#include + +#include +#include + +#include "linux/ethtool_netlink.h" + +/* Enums */ +static const char * const ethtool_op_strmap[] = { + [ETHTOOL_MSG_STRSET_GET] = "strset-get", + [ETHTOOL_MSG_LINKINFO_GET] = "linkinfo-get", + [3] = "linkinfo-ntf", + [ETHTOOL_MSG_LINKMODES_GET] = "linkmodes-get", + [5] = "linkmodes-ntf", + [ETHTOOL_MSG_LINKSTATE_GET] = "linkstate-get", + [ETHTOOL_MSG_DEBUG_GET] = "debug-get", + [8] = "debug-ntf", + [ETHTOOL_MSG_WOL_GET] = "wol-get", + [10] = "wol-ntf", + [ETHTOOL_MSG_FEATURES_GET] = "features-get", + [ETHTOOL_MSG_FEATURES_SET] = "features-set", + [13] = "features-ntf", + [14] = "privflags-get", + [15] = "privflags-ntf", + [16] = "rings-get", + [17] = "rings-ntf", + [18] = "channels-get", + [19] = "channels-ntf", + [20] = "coalesce-get", + [21] = "coalesce-ntf", + [22] = "pause-get", + [23] = "pause-ntf", + [24] = "eee-get", + [25] = "eee-ntf", + [26] = "tsinfo-get", + [27] = "cable-test-ntf", + [28] = "cable-test-tdr-ntf", + [29] = "tunnel-info-get", + [30] = "fec-get", + [31] = "fec-ntf", + [32] = "module-eeprom-get", + [34] = "phc-vclocks-get", + [35] = "module-get", + [36] = "module-ntf", + [37] = "pse-get", + [ETHTOOL_MSG_RSS_GET] = "rss-get", + [ETHTOOL_MSG_PLCA_GET_CFG] = "plca-get-cfg", + [40] = "plca-get-status", + [41] = "plca-ntf", + [ETHTOOL_MSG_MM_GET] = "mm-get", + [43] = "mm-ntf", +}; + +const char *ethtool_op_str(int op) +{ + if (op < 0 || op >= (int)MNL_ARRAY_SIZE(ethtool_op_strmap)) + return NULL; + return ethtool_op_strmap[op]; +} + +static const char * const ethtool_udp_tunnel_type_strmap[] = { + [0] = "vxlan", + [1] = "geneve", + [2] = "vxlan-gpe", +}; + +const char *ethtool_udp_tunnel_type_str(int value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(ethtool_udp_tunnel_type_strmap)) + return NULL; + return ethtool_udp_tunnel_type_strmap[value]; +} + +static const char * const ethtool_stringset_strmap[] = { +}; + +const char *ethtool_stringset_str(enum ethtool_stringset value) +{ + if (value < 0 || value >= (int)MNL_ARRAY_SIZE(ethtool_stringset_strmap)) + return NULL; + return ethtool_stringset_strmap[value]; +} + +/* Policies */ +struct ynl_policy_attr ethtool_header_policy[ETHTOOL_A_HEADER_MAX + 1] = { + [ETHTOOL_A_HEADER_DEV_INDEX] = { .name = "dev-index", .type = YNL_PT_U32, }, + [ETHTOOL_A_HEADER_DEV_NAME] = { .name = "dev-name", .type = YNL_PT_NUL_STR, }, + [ETHTOOL_A_HEADER_FLAGS] = { .name = "flags", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_header_nest = { + .max_attr = ETHTOOL_A_HEADER_MAX, + .table = ethtool_header_policy, +}; + +struct ynl_policy_attr ethtool_pause_stat_policy[ETHTOOL_A_PAUSE_STAT_MAX + 1] = { + [ETHTOOL_A_PAUSE_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, + [ETHTOOL_A_PAUSE_STAT_TX_FRAMES] = { .name = "tx-frames", .type = YNL_PT_U64, }, + [ETHTOOL_A_PAUSE_STAT_RX_FRAMES] = { .name = "rx-frames", .type = YNL_PT_U64, }, +}; + +struct ynl_policy_nest ethtool_pause_stat_nest = { + .max_attr = ETHTOOL_A_PAUSE_STAT_MAX, + .table = ethtool_pause_stat_policy, +}; + +struct ynl_policy_attr ethtool_cable_test_tdr_cfg_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX + 1] = { + [ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST] = { .name = "first", .type = YNL_PT_U32, }, + [ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST] = { .name = "last", .type = YNL_PT_U32, }, + [ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP] = { .name = "step", .type = YNL_PT_U32, }, + [ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, +}; + +struct ynl_policy_nest ethtool_cable_test_tdr_cfg_nest = { + .max_attr = ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX, + .table = ethtool_cable_test_tdr_cfg_policy, +}; + +struct ynl_policy_attr ethtool_fec_stat_policy[ETHTOOL_A_FEC_STAT_MAX + 1] = { + [ETHTOOL_A_FEC_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, + [ETHTOOL_A_FEC_STAT_CORRECTED] = { .name = "corrected", .type = YNL_PT_BINARY,}, + [ETHTOOL_A_FEC_STAT_UNCORR] = { .name = "uncorr", .type = YNL_PT_BINARY,}, + [ETHTOOL_A_FEC_STAT_CORR_BITS] = { .name = "corr-bits", .type = YNL_PT_BINARY,}, +}; + +struct ynl_policy_nest ethtool_fec_stat_nest = { + .max_attr = ETHTOOL_A_FEC_STAT_MAX, + .table = ethtool_fec_stat_policy, +}; + +struct ynl_policy_attr ethtool_mm_stat_policy[ETHTOOL_A_MM_STAT_MAX + 1] = { + [ETHTOOL_A_MM_STAT_PAD] = { .name = "pad", .type = YNL_PT_IGNORE, }, + [ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS] = { .name = "reassembly-errors", .type = YNL_PT_U64, }, + [ETHTOOL_A_MM_STAT_SMD_ERRORS] = { .name = "smd-errors", .type = YNL_PT_U64, }, + [ETHTOOL_A_MM_STAT_REASSEMBLY_OK] = { .name = "reassembly-ok", .type = YNL_PT_U64, }, + [ETHTOOL_A_MM_STAT_RX_FRAG_COUNT] = { .name = "rx-frag-count", .type = YNL_PT_U64, }, + [ETHTOOL_A_MM_STAT_TX_FRAG_COUNT] = { .name = "tx-frag-count", .type = YNL_PT_U64, }, + [ETHTOOL_A_MM_STAT_HOLD_COUNT] = { .name = "hold-count", .type = YNL_PT_U64, }, +}; + +struct ynl_policy_nest ethtool_mm_stat_nest = { + .max_attr = ETHTOOL_A_MM_STAT_MAX, + .table = ethtool_mm_stat_policy, +}; + +struct ynl_policy_attr ethtool_cable_result_policy[ETHTOOL_A_CABLE_RESULT_MAX + 1] = { + [ETHTOOL_A_CABLE_RESULT_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, + [ETHTOOL_A_CABLE_RESULT_CODE] = { .name = "code", .type = YNL_PT_U8, }, +}; + +struct ynl_policy_nest ethtool_cable_result_nest = { + .max_attr = ETHTOOL_A_CABLE_RESULT_MAX, + .table = ethtool_cable_result_policy, +}; + +struct ynl_policy_attr ethtool_cable_fault_length_policy[ETHTOOL_A_CABLE_FAULT_LENGTH_MAX + 1] = { + [ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR] = { .name = "pair", .type = YNL_PT_U8, }, + [ETHTOOL_A_CABLE_FAULT_LENGTH_CM] = { .name = "cm", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_cable_fault_length_nest = { + .max_attr = ETHTOOL_A_CABLE_FAULT_LENGTH_MAX, + .table = ethtool_cable_fault_length_policy, +}; + +struct ynl_policy_attr ethtool_bitset_bit_policy[ETHTOOL_A_BITSET_BIT_MAX + 1] = { + [ETHTOOL_A_BITSET_BIT_INDEX] = { .name = "index", .type = YNL_PT_U32, }, + [ETHTOOL_A_BITSET_BIT_NAME] = { .name = "name", .type = YNL_PT_NUL_STR, }, + [ETHTOOL_A_BITSET_BIT_VALUE] = { .name = "value", .type = YNL_PT_FLAG, }, +}; + +struct ynl_policy_nest ethtool_bitset_bit_nest = { + .max_attr = ETHTOOL_A_BITSET_BIT_MAX, + .table = ethtool_bitset_bit_policy, +}; + +struct ynl_policy_attr ethtool_tunnel_udp_entry_policy[ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX + 1] = { + [ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT] = { .name = "port", .type = YNL_PT_U16, }, + [ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE] = { .name = "type", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_tunnel_udp_entry_nest = { + .max_attr = ETHTOOL_A_TUNNEL_UDP_ENTRY_MAX, + .table = ethtool_tunnel_udp_entry_policy, +}; + +struct ynl_policy_attr ethtool_string_policy[ETHTOOL_A_STRING_MAX + 1] = { + [ETHTOOL_A_STRING_INDEX] = { .name = "index", .type = YNL_PT_U32, }, + [ETHTOOL_A_STRING_VALUE] = { .name = "value", .type = YNL_PT_NUL_STR, }, +}; + +struct ynl_policy_nest ethtool_string_nest = { + .max_attr = ETHTOOL_A_STRING_MAX, + .table = ethtool_string_policy, +}; + +struct ynl_policy_attr ethtool_cable_nest_policy[ETHTOOL_A_CABLE_NEST_MAX + 1] = { + [ETHTOOL_A_CABLE_NEST_RESULT] = { .name = "result", .type = YNL_PT_NEST, .nest = ðtool_cable_result_nest, }, + [ETHTOOL_A_CABLE_NEST_FAULT_LENGTH] = { .name = "fault-length", .type = YNL_PT_NEST, .nest = ðtool_cable_fault_length_nest, }, +}; + +struct ynl_policy_nest ethtool_cable_nest_nest = { + .max_attr = ETHTOOL_A_CABLE_NEST_MAX, + .table = ethtool_cable_nest_policy, +}; + +struct ynl_policy_attr ethtool_bitset_bits_policy[ETHTOOL_A_BITSET_BITS_MAX + 1] = { + [ETHTOOL_A_BITSET_BITS_BIT] = { .name = "bit", .type = YNL_PT_NEST, .nest = ðtool_bitset_bit_nest, }, +}; + +struct ynl_policy_nest ethtool_bitset_bits_nest = { + .max_attr = ETHTOOL_A_BITSET_BITS_MAX, + .table = ethtool_bitset_bits_policy, +}; + +struct ynl_policy_attr ethtool_strings_policy[ETHTOOL_A_STRINGS_MAX + 1] = { + [ETHTOOL_A_STRINGS_STRING] = { .name = "string", .type = YNL_PT_NEST, .nest = ðtool_string_nest, }, +}; + +struct ynl_policy_nest ethtool_strings_nest = { + .max_attr = ETHTOOL_A_STRINGS_MAX, + .table = ethtool_strings_policy, +}; + +struct ynl_policy_attr ethtool_bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = { + [ETHTOOL_A_BITSET_NOMASK] = { .name = "nomask", .type = YNL_PT_FLAG, }, + [ETHTOOL_A_BITSET_SIZE] = { .name = "size", .type = YNL_PT_U32, }, + [ETHTOOL_A_BITSET_BITS] = { .name = "bits", .type = YNL_PT_NEST, .nest = ðtool_bitset_bits_nest, }, +}; + +struct ynl_policy_nest ethtool_bitset_nest = { + .max_attr = ETHTOOL_A_BITSET_MAX, + .table = ethtool_bitset_policy, +}; + +struct ynl_policy_attr ethtool_stringset_policy[ETHTOOL_A_STRINGSET_MAX + 1] = { + [ETHTOOL_A_STRINGSET_ID] = { .name = "id", .type = YNL_PT_U32, }, + [ETHTOOL_A_STRINGSET_COUNT] = { .name = "count", .type = YNL_PT_U32, }, + [ETHTOOL_A_STRINGSET_STRINGS] = { .name = "strings", .type = YNL_PT_NEST, .nest = ðtool_strings_nest, }, +}; + +struct ynl_policy_nest ethtool_stringset_nest = { + .max_attr = ETHTOOL_A_STRINGSET_MAX, + .table = ethtool_stringset_policy, +}; + +struct ynl_policy_attr ethtool_tunnel_udp_table_policy[ETHTOOL_A_TUNNEL_UDP_TABLE_MAX + 1] = { + [ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE] = { .name = "size", .type = YNL_PT_U32, }, + [ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES] = { .name = "types", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY] = { .name = "entry", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_entry_nest, }, +}; + +struct ynl_policy_nest ethtool_tunnel_udp_table_nest = { + .max_attr = ETHTOOL_A_TUNNEL_UDP_TABLE_MAX, + .table = ethtool_tunnel_udp_table_policy, +}; + +struct ynl_policy_attr ethtool_stringsets_policy[ETHTOOL_A_STRINGSETS_MAX + 1] = { + [ETHTOOL_A_STRINGSETS_STRINGSET] = { .name = "stringset", .type = YNL_PT_NEST, .nest = ðtool_stringset_nest, }, +}; + +struct ynl_policy_nest ethtool_stringsets_nest = { + .max_attr = ETHTOOL_A_STRINGSETS_MAX, + .table = ethtool_stringsets_policy, +}; + +struct ynl_policy_attr ethtool_tunnel_udp_policy[ETHTOOL_A_TUNNEL_UDP_MAX + 1] = { + [ETHTOOL_A_TUNNEL_UDP_TABLE] = { .name = "table", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_table_nest, }, +}; + +struct ynl_policy_nest ethtool_tunnel_udp_nest = { + .max_attr = ETHTOOL_A_TUNNEL_UDP_MAX, + .table = ethtool_tunnel_udp_policy, +}; + +struct ynl_policy_attr ethtool_strset_policy[ETHTOOL_A_STRSET_MAX + 1] = { + [ETHTOOL_A_STRSET_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_STRSET_STRINGSETS] = { .name = "stringsets", .type = YNL_PT_NEST, .nest = ðtool_stringsets_nest, }, + [ETHTOOL_A_STRSET_COUNTS_ONLY] = { .name = "counts-only", .type = YNL_PT_FLAG, }, +}; + +struct ynl_policy_nest ethtool_strset_nest = { + .max_attr = ETHTOOL_A_STRSET_MAX, + .table = ethtool_strset_policy, +}; + +struct ynl_policy_attr ethtool_linkinfo_policy[ETHTOOL_A_LINKINFO_MAX + 1] = { + [ETHTOOL_A_LINKINFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_LINKINFO_PORT] = { .name = "port", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKINFO_PHYADDR] = { .name = "phyaddr", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKINFO_TP_MDIX] = { .name = "tp-mdix", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .name = "tp-mdix-ctrl", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKINFO_TRANSCEIVER] = { .name = "transceiver", .type = YNL_PT_U8, }, +}; + +struct ynl_policy_nest ethtool_linkinfo_nest = { + .max_attr = ETHTOOL_A_LINKINFO_MAX, + .table = ethtool_linkinfo_policy, +}; + +struct ynl_policy_attr ethtool_linkmodes_policy[ETHTOOL_A_LINKMODES_MAX + 1] = { + [ETHTOOL_A_LINKMODES_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_LINKMODES_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKMODES_OURS] = { .name = "ours", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_LINKMODES_PEER] = { .name = "peer", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_LINKMODES_SPEED] = { .name = "speed", .type = YNL_PT_U32, }, + [ETHTOOL_A_LINKMODES_DUPLEX] = { .name = "duplex", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .name = "master-slave-cfg", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .name = "master-slave-state", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKMODES_LANES] = { .name = "lanes", .type = YNL_PT_U32, }, + [ETHTOOL_A_LINKMODES_RATE_MATCHING] = { .name = "rate-matching", .type = YNL_PT_U8, }, +}; + +struct ynl_policy_nest ethtool_linkmodes_nest = { + .max_attr = ETHTOOL_A_LINKMODES_MAX, + .table = ethtool_linkmodes_policy, +}; + +struct ynl_policy_attr ethtool_linkstate_policy[ETHTOOL_A_LINKSTATE_MAX + 1] = { + [ETHTOOL_A_LINKSTATE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_LINKSTATE_LINK] = { .name = "link", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKSTATE_SQI] = { .name = "sqi", .type = YNL_PT_U32, }, + [ETHTOOL_A_LINKSTATE_SQI_MAX] = { .name = "sqi-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_LINKSTATE_EXT_STATE] = { .name = "ext-state", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKSTATE_EXT_SUBSTATE] = { .name = "ext-substate", .type = YNL_PT_U8, }, + [ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT] = { .name = "ext-down-cnt", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_linkstate_nest = { + .max_attr = ETHTOOL_A_LINKSTATE_MAX, + .table = ethtool_linkstate_policy, +}; + +struct ynl_policy_attr ethtool_debug_policy[ETHTOOL_A_DEBUG_MAX + 1] = { + [ETHTOOL_A_DEBUG_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_DEBUG_MSGMASK] = { .name = "msgmask", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, +}; + +struct ynl_policy_nest ethtool_debug_nest = { + .max_attr = ETHTOOL_A_DEBUG_MAX, + .table = ethtool_debug_policy, +}; + +struct ynl_policy_attr ethtool_wol_policy[ETHTOOL_A_WOL_MAX + 1] = { + [ETHTOOL_A_WOL_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_WOL_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_WOL_SOPASS] = { .name = "sopass", .type = YNL_PT_BINARY,}, +}; + +struct ynl_policy_nest ethtool_wol_nest = { + .max_attr = ETHTOOL_A_WOL_MAX, + .table = ethtool_wol_policy, +}; + +struct ynl_policy_attr ethtool_features_policy[ETHTOOL_A_FEATURES_MAX + 1] = { + [ETHTOOL_A_FEATURES_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_FEATURES_HW] = { .name = "hw", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_FEATURES_WANTED] = { .name = "wanted", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_FEATURES_ACTIVE] = { .name = "active", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_FEATURES_NOCHANGE] = { .name = "nochange", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, +}; + +struct ynl_policy_nest ethtool_features_nest = { + .max_attr = ETHTOOL_A_FEATURES_MAX, + .table = ethtool_features_policy, +}; + +struct ynl_policy_attr ethtool_privflags_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = { + [ETHTOOL_A_PRIVFLAGS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .name = "flags", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, +}; + +struct ynl_policy_nest ethtool_privflags_nest = { + .max_attr = ETHTOOL_A_PRIVFLAGS_MAX, + .table = ethtool_privflags_policy, +}; + +struct ynl_policy_attr ethtool_rings_policy[ETHTOOL_A_RINGS_MAX + 1] = { + [ETHTOOL_A_RINGS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_RINGS_RX_MAX] = { .name = "rx-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_RX_MINI_MAX] = { .name = "rx-mini-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_RX_JUMBO_MAX] = { .name = "rx-jumbo-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_TX_MAX] = { .name = "tx-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_RX] = { .name = "rx", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_RX_MINI] = { .name = "rx-mini", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_RX_JUMBO] = { .name = "rx-jumbo", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_TX] = { .name = "tx", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_RX_BUF_LEN] = { .name = "rx-buf-len", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_TCP_DATA_SPLIT] = { .name = "tcp-data-split", .type = YNL_PT_U8, }, + [ETHTOOL_A_RINGS_CQE_SIZE] = { .name = "cqe-size", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_TX_PUSH] = { .name = "tx-push", .type = YNL_PT_U8, }, + [ETHTOOL_A_RINGS_RX_PUSH] = { .name = "rx-push", .type = YNL_PT_U8, }, + [ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN] = { .name = "tx-push-buf-len", .type = YNL_PT_U32, }, + [ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX] = { .name = "tx-push-buf-len-max", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_rings_nest = { + .max_attr = ETHTOOL_A_RINGS_MAX, + .table = ethtool_rings_policy, +}; + +struct ynl_policy_attr ethtool_channels_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { + [ETHTOOL_A_CHANNELS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_CHANNELS_RX_MAX] = { .name = "rx-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_CHANNELS_TX_MAX] = { .name = "tx-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .name = "other-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .name = "combined-max", .type = YNL_PT_U32, }, + [ETHTOOL_A_CHANNELS_RX_COUNT] = { .name = "rx-count", .type = YNL_PT_U32, }, + [ETHTOOL_A_CHANNELS_TX_COUNT] = { .name = "tx-count", .type = YNL_PT_U32, }, + [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .name = "other-count", .type = YNL_PT_U32, }, + [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .name = "combined-count", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_channels_nest = { + .max_attr = ETHTOOL_A_CHANNELS_MAX, + .table = ethtool_channels_policy, +}; + +struct ynl_policy_attr ethtool_coalesce_policy[ETHTOOL_A_COALESCE_MAX + 1] = { + [ETHTOOL_A_COALESCE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_COALESCE_RX_USECS] = { .name = "rx-usecs", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .name = "rx-max-frames", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .name = "rx-usecs-irq", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ] = { .name = "rx-max-frames-irq", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_USECS] = { .name = "tx-usecs", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_MAX_FRAMES] = { .name = "tx-max-frames", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_USECS_IRQ] = { .name = "tx-usecs-irq", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ] = { .name = "tx-max-frames-irq", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS] = { .name = "stats-block-usecs", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX] = { .name = "use-adaptive-rx", .type = YNL_PT_U8, }, + [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX] = { .name = "use-adaptive-tx", .type = YNL_PT_U8, }, + [ETHTOOL_A_COALESCE_PKT_RATE_LOW] = { .name = "pkt-rate-low", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_RX_USECS_LOW] = { .name = "rx-usecs-low", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW] = { .name = "rx-max-frames-low", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_USECS_LOW] = { .name = "tx-usecs-low", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW] = { .name = "tx-max-frames-low", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_PKT_RATE_HIGH] = { .name = "pkt-rate-high", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_RX_USECS_HIGH] = { .name = "rx-usecs-high", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .name = "rx-max-frames-high", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_USECS_HIGH] = { .name = "tx-usecs-high", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .name = "tx-max-frames-high", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .name = "rate-sample-interval", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_USE_CQE_MODE_TX] = { .name = "use-cqe-mode-tx", .type = YNL_PT_U8, }, + [ETHTOOL_A_COALESCE_USE_CQE_MODE_RX] = { .name = "use-cqe-mode-rx", .type = YNL_PT_U8, }, + [ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES] = { .name = "tx-aggr-max-bytes", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES] = { .name = "tx-aggr-max-frames", .type = YNL_PT_U32, }, + [ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS] = { .name = "tx-aggr-time-usecs", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_coalesce_nest = { + .max_attr = ETHTOOL_A_COALESCE_MAX, + .table = ethtool_coalesce_policy, +}; + +struct ynl_policy_attr ethtool_pause_policy[ETHTOOL_A_PAUSE_MAX + 1] = { + [ETHTOOL_A_PAUSE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_PAUSE_AUTONEG] = { .name = "autoneg", .type = YNL_PT_U8, }, + [ETHTOOL_A_PAUSE_RX] = { .name = "rx", .type = YNL_PT_U8, }, + [ETHTOOL_A_PAUSE_TX] = { .name = "tx", .type = YNL_PT_U8, }, + [ETHTOOL_A_PAUSE_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_pause_stat_nest, }, + [ETHTOOL_A_PAUSE_STATS_SRC] = { .name = "stats-src", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_pause_nest = { + .max_attr = ETHTOOL_A_PAUSE_MAX, + .table = ethtool_pause_policy, +}; + +struct ynl_policy_attr ethtool_eee_policy[ETHTOOL_A_EEE_MAX + 1] = { + [ETHTOOL_A_EEE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_EEE_MODES_OURS] = { .name = "modes-ours", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_EEE_MODES_PEER] = { .name = "modes-peer", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_EEE_ACTIVE] = { .name = "active", .type = YNL_PT_U8, }, + [ETHTOOL_A_EEE_ENABLED] = { .name = "enabled", .type = YNL_PT_U8, }, + [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .name = "tx-lpi-enabled", .type = YNL_PT_U8, }, + [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .name = "tx-lpi-timer", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_eee_nest = { + .max_attr = ETHTOOL_A_EEE_MAX, + .table = ethtool_eee_policy, +}; + +struct ynl_policy_attr ethtool_tsinfo_policy[ETHTOOL_A_TSINFO_MAX + 1] = { + [ETHTOOL_A_TSINFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_TSINFO_TIMESTAMPING] = { .name = "timestamping", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_TSINFO_TX_TYPES] = { .name = "tx-types", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_TSINFO_RX_FILTERS] = { .name = "rx-filters", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_TSINFO_PHC_INDEX] = { .name = "phc-index", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_tsinfo_nest = { + .max_attr = ETHTOOL_A_TSINFO_MAX, + .table = ethtool_tsinfo_policy, +}; + +struct ynl_policy_attr ethtool_cable_test_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { + [ETHTOOL_A_CABLE_TEST_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, +}; + +struct ynl_policy_nest ethtool_cable_test_nest = { + .max_attr = ETHTOOL_A_CABLE_TEST_MAX, + .table = ethtool_cable_test_policy, +}; + +struct ynl_policy_attr ethtool_cable_test_ntf_policy[ETHTOOL_A_CABLE_TEST_NTF_MAX + 1] = { + [ETHTOOL_A_CABLE_TEST_NTF_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_CABLE_TEST_NTF_STATUS] = { .name = "status", .type = YNL_PT_U8, }, + [ETHTOOL_A_CABLE_TEST_NTF_NEST] = { .name = "nest", .type = YNL_PT_NEST, .nest = ðtool_cable_nest_nest, }, +}; + +struct ynl_policy_nest ethtool_cable_test_ntf_nest = { + .max_attr = ETHTOOL_A_CABLE_TEST_NTF_MAX, + .table = ethtool_cable_test_ntf_policy, +}; + +struct ynl_policy_attr ethtool_cable_test_tdr_policy[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1] = { + [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_CABLE_TEST_TDR_CFG] = { .name = "cfg", .type = YNL_PT_NEST, .nest = ðtool_cable_test_tdr_cfg_nest, }, +}; + +struct ynl_policy_nest ethtool_cable_test_tdr_nest = { + .max_attr = ETHTOOL_A_CABLE_TEST_TDR_MAX, + .table = ethtool_cable_test_tdr_policy, +}; + +struct ynl_policy_attr ethtool_cable_test_tdr_ntf_policy[ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX + 1] = { + [ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS] = { .name = "status", .type = YNL_PT_U8, }, + [ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST] = { .name = "nest", .type = YNL_PT_NEST, .nest = ðtool_cable_nest_nest, }, +}; + +struct ynl_policy_nest ethtool_cable_test_tdr_ntf_nest = { + .max_attr = ETHTOOL_A_CABLE_TEST_TDR_NTF_MAX, + .table = ethtool_cable_test_tdr_ntf_policy, +}; + +struct ynl_policy_attr ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = { + [ETHTOOL_A_TUNNEL_INFO_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_TUNNEL_INFO_UDP_PORTS] = { .name = "udp-ports", .type = YNL_PT_NEST, .nest = ðtool_tunnel_udp_nest, }, +}; + +struct ynl_policy_nest ethtool_tunnel_info_nest = { + .max_attr = ETHTOOL_A_TUNNEL_INFO_MAX, + .table = ethtool_tunnel_info_policy, +}; + +struct ynl_policy_attr ethtool_fec_policy[ETHTOOL_A_FEC_MAX + 1] = { + [ETHTOOL_A_FEC_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_FEC_MODES] = { .name = "modes", .type = YNL_PT_NEST, .nest = ðtool_bitset_nest, }, + [ETHTOOL_A_FEC_AUTO] = { .name = "auto", .type = YNL_PT_U8, }, + [ETHTOOL_A_FEC_ACTIVE] = { .name = "active", .type = YNL_PT_U32, }, + [ETHTOOL_A_FEC_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_fec_stat_nest, }, +}; + +struct ynl_policy_nest ethtool_fec_nest = { + .max_attr = ETHTOOL_A_FEC_MAX, + .table = ethtool_fec_policy, +}; + +struct ynl_policy_attr ethtool_module_eeprom_policy[ETHTOOL_A_MODULE_EEPROM_MAX + 1] = { + [ETHTOOL_A_MODULE_EEPROM_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_MODULE_EEPROM_OFFSET] = { .name = "offset", .type = YNL_PT_U32, }, + [ETHTOOL_A_MODULE_EEPROM_LENGTH] = { .name = "length", .type = YNL_PT_U32, }, + [ETHTOOL_A_MODULE_EEPROM_PAGE] = { .name = "page", .type = YNL_PT_U8, }, + [ETHTOOL_A_MODULE_EEPROM_BANK] = { .name = "bank", .type = YNL_PT_U8, }, + [ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS] = { .name = "i2c-address", .type = YNL_PT_U8, }, + [ETHTOOL_A_MODULE_EEPROM_DATA] = { .name = "data", .type = YNL_PT_BINARY,}, +}; + +struct ynl_policy_nest ethtool_module_eeprom_nest = { + .max_attr = ETHTOOL_A_MODULE_EEPROM_MAX, + .table = ethtool_module_eeprom_policy, +}; + +struct ynl_policy_attr ethtool_phc_vclocks_policy[ETHTOOL_A_PHC_VCLOCKS_MAX + 1] = { + [ETHTOOL_A_PHC_VCLOCKS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_PHC_VCLOCKS_NUM] = { .name = "num", .type = YNL_PT_U32, }, + [ETHTOOL_A_PHC_VCLOCKS_INDEX] = { .name = "index", .type = YNL_PT_BINARY,}, +}; + +struct ynl_policy_nest ethtool_phc_vclocks_nest = { + .max_attr = ETHTOOL_A_PHC_VCLOCKS_MAX, + .table = ethtool_phc_vclocks_policy, +}; + +struct ynl_policy_attr ethtool_module_policy[ETHTOOL_A_MODULE_MAX + 1] = { + [ETHTOOL_A_MODULE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_MODULE_POWER_MODE_POLICY] = { .name = "power-mode-policy", .type = YNL_PT_U8, }, + [ETHTOOL_A_MODULE_POWER_MODE] = { .name = "power-mode", .type = YNL_PT_U8, }, +}; + +struct ynl_policy_nest ethtool_module_nest = { + .max_attr = ETHTOOL_A_MODULE_MAX, + .table = ethtool_module_policy, +}; + +struct ynl_policy_attr ethtool_pse_policy[ETHTOOL_A_PSE_MAX + 1] = { + [ETHTOOL_A_PSE_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_PODL_PSE_ADMIN_STATE] = { .name = "admin-state", .type = YNL_PT_U32, }, + [ETHTOOL_A_PODL_PSE_ADMIN_CONTROL] = { .name = "admin-control", .type = YNL_PT_U32, }, + [ETHTOOL_A_PODL_PSE_PW_D_STATUS] = { .name = "pw-d-status", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_pse_nest = { + .max_attr = ETHTOOL_A_PSE_MAX, + .table = ethtool_pse_policy, +}; + +struct ynl_policy_attr ethtool_rss_policy[ETHTOOL_A_RSS_MAX + 1] = { + [ETHTOOL_A_RSS_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_RSS_CONTEXT] = { .name = "context", .type = YNL_PT_U32, }, + [ETHTOOL_A_RSS_HFUNC] = { .name = "hfunc", .type = YNL_PT_U32, }, + [ETHTOOL_A_RSS_INDIR] = { .name = "indir", .type = YNL_PT_BINARY,}, + [ETHTOOL_A_RSS_HKEY] = { .name = "hkey", .type = YNL_PT_BINARY,}, +}; + +struct ynl_policy_nest ethtool_rss_nest = { + .max_attr = ETHTOOL_A_RSS_MAX, + .table = ethtool_rss_policy, +}; + +struct ynl_policy_attr ethtool_plca_policy[ETHTOOL_A_PLCA_MAX + 1] = { + [ETHTOOL_A_PLCA_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_PLCA_VERSION] = { .name = "version", .type = YNL_PT_U16, }, + [ETHTOOL_A_PLCA_ENABLED] = { .name = "enabled", .type = YNL_PT_U8, }, + [ETHTOOL_A_PLCA_STATUS] = { .name = "status", .type = YNL_PT_U8, }, + [ETHTOOL_A_PLCA_NODE_CNT] = { .name = "node-cnt", .type = YNL_PT_U32, }, + [ETHTOOL_A_PLCA_NODE_ID] = { .name = "node-id", .type = YNL_PT_U32, }, + [ETHTOOL_A_PLCA_TO_TMR] = { .name = "to-tmr", .type = YNL_PT_U32, }, + [ETHTOOL_A_PLCA_BURST_CNT] = { .name = "burst-cnt", .type = YNL_PT_U32, }, + [ETHTOOL_A_PLCA_BURST_TMR] = { .name = "burst-tmr", .type = YNL_PT_U32, }, +}; + +struct ynl_policy_nest ethtool_plca_nest = { + .max_attr = ETHTOOL_A_PLCA_MAX, + .table = ethtool_plca_policy, +}; + +struct ynl_policy_attr ethtool_mm_policy[ETHTOOL_A_MM_MAX + 1] = { + [ETHTOOL_A_MM_HEADER] = { .name = "header", .type = YNL_PT_NEST, .nest = ðtool_header_nest, }, + [ETHTOOL_A_MM_PMAC_ENABLED] = { .name = "pmac-enabled", .type = YNL_PT_U8, }, + [ETHTOOL_A_MM_TX_ENABLED] = { .name = "tx-enabled", .type = YNL_PT_U8, }, + [ETHTOOL_A_MM_TX_ACTIVE] = { .name = "tx-active", .type = YNL_PT_U8, }, + [ETHTOOL_A_MM_TX_MIN_FRAG_SIZE] = { .name = "tx-min-frag-size", .type = YNL_PT_U32, }, + [ETHTOOL_A_MM_RX_MIN_FRAG_SIZE] = { .name = "rx-min-frag-size", .type = YNL_PT_U32, }, + [ETHTOOL_A_MM_VERIFY_ENABLED] = { .name = "verify-enabled", .type = YNL_PT_U8, }, + [ETHTOOL_A_MM_VERIFY_STATUS] = { .name = "verify-status", .type = YNL_PT_U8, }, + [ETHTOOL_A_MM_VERIFY_TIME] = { .name = "verify-time", .type = YNL_PT_U32, }, + [ETHTOOL_A_MM_MAX_VERIFY_TIME] = { .name = "max-verify-time", .type = YNL_PT_U32, }, + [ETHTOOL_A_MM_STATS] = { .name = "stats", .type = YNL_PT_NEST, .nest = ðtool_mm_stat_nest, }, +}; + +struct ynl_policy_nest ethtool_mm_nest = { + .max_attr = ETHTOOL_A_MM_MAX, + .table = ethtool_mm_policy, +}; + +/* Common nested types */ +void ethtool_header_free(struct ethtool_header *obj) +{ + free(obj->dev_name); +} + +int ethtool_header_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_header *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.dev_index) + mnl_attr_put_u32(nlh, ETHTOOL_A_HEADER_DEV_INDEX, obj->dev_index); + if (obj->_present.dev_name_len) + mnl_attr_put_strz(nlh, ETHTOOL_A_HEADER_DEV_NAME, obj->dev_name); + if (obj->_present.flags) + mnl_attr_put_u32(nlh, ETHTOOL_A_HEADER_FLAGS, obj->flags); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_header_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_header *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_HEADER_DEV_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.dev_index = 1; + dst->dev_index = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_HEADER_DEV_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.dev_name_len = len; + dst->dev_name = malloc(len + 1); + memcpy(dst->dev_name, mnl_attr_get_str(attr), len); + dst->dev_name[len] = 0; + } else if (type == ETHTOOL_A_HEADER_FLAGS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.flags = 1; + dst->flags = mnl_attr_get_u32(attr); + } + } + + return 0; +} + +void ethtool_pause_stat_free(struct ethtool_pause_stat *obj) +{ +} + +int ethtool_pause_stat_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_pause_stat *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.tx_frames) + mnl_attr_put_u64(nlh, ETHTOOL_A_PAUSE_STAT_TX_FRAMES, obj->tx_frames); + if (obj->_present.rx_frames) + mnl_attr_put_u64(nlh, ETHTOOL_A_PAUSE_STAT_RX_FRAMES, obj->rx_frames); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_pause_stat_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_pause_stat *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_PAUSE_STAT_TX_FRAMES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_frames = 1; + dst->tx_frames = mnl_attr_get_u64(attr); + } else if (type == ETHTOOL_A_PAUSE_STAT_RX_FRAMES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_frames = 1; + dst->rx_frames = mnl_attr_get_u64(attr); + } + } + + return 0; +} + +void ethtool_cable_test_tdr_cfg_free(struct ethtool_cable_test_tdr_cfg *obj) +{ +} + +void ethtool_fec_stat_free(struct ethtool_fec_stat *obj) +{ + free(obj->corrected); + free(obj->uncorr); + free(obj->corr_bits); +} + +int ethtool_fec_stat_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_fec_stat *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.corrected_len) + mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_CORRECTED, obj->_present.corrected_len, obj->corrected); + if (obj->_present.uncorr_len) + mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_UNCORR, obj->_present.uncorr_len, obj->uncorr); + if (obj->_present.corr_bits_len) + mnl_attr_put(nlh, ETHTOOL_A_FEC_STAT_CORR_BITS, obj->_present.corr_bits_len, obj->corr_bits); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_fec_stat_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_fec_stat *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_FEC_STAT_CORRECTED) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.corrected_len = len; + dst->corrected = malloc(len); + memcpy(dst->corrected, mnl_attr_get_payload(attr), len); + } else if (type == ETHTOOL_A_FEC_STAT_UNCORR) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.uncorr_len = len; + dst->uncorr = malloc(len); + memcpy(dst->uncorr, mnl_attr_get_payload(attr), len); + } else if (type == ETHTOOL_A_FEC_STAT_CORR_BITS) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.corr_bits_len = len; + dst->corr_bits = malloc(len); + memcpy(dst->corr_bits, mnl_attr_get_payload(attr), len); + } + } + + return 0; +} + +void ethtool_mm_stat_free(struct ethtool_mm_stat *obj) +{ +} + +int ethtool_mm_stat_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_mm_stat *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_MM_STAT_REASSEMBLY_ERRORS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reassembly_errors = 1; + dst->reassembly_errors = mnl_attr_get_u64(attr); + } else if (type == ETHTOOL_A_MM_STAT_SMD_ERRORS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.smd_errors = 1; + dst->smd_errors = mnl_attr_get_u64(attr); + } else if (type == ETHTOOL_A_MM_STAT_REASSEMBLY_OK) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.reassembly_ok = 1; + dst->reassembly_ok = mnl_attr_get_u64(attr); + } else if (type == ETHTOOL_A_MM_STAT_RX_FRAG_COUNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_frag_count = 1; + dst->rx_frag_count = mnl_attr_get_u64(attr); + } else if (type == ETHTOOL_A_MM_STAT_TX_FRAG_COUNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_frag_count = 1; + dst->tx_frag_count = mnl_attr_get_u64(attr); + } else if (type == ETHTOOL_A_MM_STAT_HOLD_COUNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.hold_count = 1; + dst->hold_count = mnl_attr_get_u64(attr); + } + } + + return 0; +} + +void ethtool_cable_result_free(struct ethtool_cable_result *obj) +{ +} + +int ethtool_cable_result_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_cable_result *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_CABLE_RESULT_PAIR) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.pair = 1; + dst->pair = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_CABLE_RESULT_CODE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.code = 1; + dst->code = mnl_attr_get_u8(attr); + } + } + + return 0; +} + +void ethtool_cable_fault_length_free(struct ethtool_cable_fault_length *obj) +{ +} + +int ethtool_cable_fault_length_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_cable_fault_length *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_CABLE_FAULT_LENGTH_PAIR) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.pair = 1; + dst->pair = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_CABLE_FAULT_LENGTH_CM) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.cm = 1; + dst->cm = mnl_attr_get_u32(attr); + } + } + + return 0; +} + +void ethtool_bitset_bit_free(struct ethtool_bitset_bit *obj) +{ + free(obj->name); +} + +int ethtool_bitset_bit_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_bitset_bit *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.index) + mnl_attr_put_u32(nlh, ETHTOOL_A_BITSET_BIT_INDEX, obj->index); + if (obj->_present.name_len) + mnl_attr_put_strz(nlh, ETHTOOL_A_BITSET_BIT_NAME, obj->name); + if (obj->_present.value) + mnl_attr_put(nlh, ETHTOOL_A_BITSET_BIT_VALUE, 0, NULL); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_bitset_bit_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_bitset_bit *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_BITSET_BIT_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.index = 1; + dst->index = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_BITSET_BIT_NAME) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.name_len = len; + dst->name = malloc(len + 1); + memcpy(dst->name, mnl_attr_get_str(attr), len); + dst->name[len] = 0; + } else if (type == ETHTOOL_A_BITSET_BIT_VALUE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.value = 1; + } + } + + return 0; +} + +void ethtool_tunnel_udp_entry_free(struct ethtool_tunnel_udp_entry *obj) +{ +} + +int ethtool_tunnel_udp_entry_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_tunnel_udp_entry *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_TUNNEL_UDP_ENTRY_PORT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port = 1; + dst->port = mnl_attr_get_u16(attr); + } else if (type == ETHTOOL_A_TUNNEL_UDP_ENTRY_TYPE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.type = 1; + dst->type = mnl_attr_get_u32(attr); + } + } + + return 0; +} + +void ethtool_string_free(struct ethtool_string *obj) +{ + free(obj->value); +} + +int ethtool_string_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_string *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.index) + mnl_attr_put_u32(nlh, ETHTOOL_A_STRING_INDEX, obj->index); + if (obj->_present.value_len) + mnl_attr_put_strz(nlh, ETHTOOL_A_STRING_VALUE, obj->value); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_string_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_string *dst = yarg->data; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_STRING_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.index = 1; + dst->index = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_STRING_VALUE) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = strnlen(mnl_attr_get_str(attr), mnl_attr_get_payload_len(attr)); + dst->_present.value_len = len; + dst->value = malloc(len + 1); + memcpy(dst->value, mnl_attr_get_str(attr), len); + dst->value[len] = 0; + } + } + + return 0; +} + +void ethtool_cable_nest_free(struct ethtool_cable_nest *obj) +{ + ethtool_cable_result_free(&obj->result); + ethtool_cable_fault_length_free(&obj->fault_length); +} + +int ethtool_cable_nest_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_cable_nest *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + parg.ys = yarg->ys; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_CABLE_NEST_RESULT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.result = 1; + + parg.rsp_policy = ðtool_cable_result_nest; + parg.data = &dst->result; + if (ethtool_cable_result_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_CABLE_NEST_FAULT_LENGTH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.fault_length = 1; + + parg.rsp_policy = ðtool_cable_fault_length_nest; + parg.data = &dst->fault_length; + if (ethtool_cable_fault_length_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return 0; +} + +void ethtool_bitset_bits_free(struct ethtool_bitset_bits *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_bit; i++) + ethtool_bitset_bit_free(&obj->bit[i]); + free(obj->bit); +} + +int ethtool_bitset_bits_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_bitset_bits *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + for (unsigned int i = 0; i < obj->n_bit; i++) + ethtool_bitset_bit_put(nlh, ETHTOOL_A_BITSET_BITS_BIT, &obj->bit[i]); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_bitset_bits_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_bitset_bits *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + unsigned int n_bit = 0; + int i; + + parg.ys = yarg->ys; + + if (dst->bit) + return ynl_error_parse(yarg, "attribute already present (bitset-bits.bit)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_BITSET_BITS_BIT) { + n_bit++; + } + } + + if (n_bit) { + dst->bit = calloc(n_bit, sizeof(*dst->bit)); + dst->n_bit = n_bit; + i = 0; + parg.rsp_policy = ðtool_bitset_bit_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == ETHTOOL_A_BITSET_BITS_BIT) { + parg.data = &dst->bit[i]; + if (ethtool_bitset_bit_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void ethtool_strings_free(struct ethtool_strings *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_string; i++) + ethtool_string_free(&obj->string[i]); + free(obj->string); +} + +int ethtool_strings_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_strings *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + for (unsigned int i = 0; i < obj->n_string; i++) + ethtool_string_put(nlh, ETHTOOL_A_STRINGS_STRING, &obj->string[i]); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_strings_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_strings *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + unsigned int n_string = 0; + int i; + + parg.ys = yarg->ys; + + if (dst->string) + return ynl_error_parse(yarg, "attribute already present (strings.string)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_STRINGS_STRING) { + n_string++; + } + } + + if (n_string) { + dst->string = calloc(n_string, sizeof(*dst->string)); + dst->n_string = n_string; + i = 0; + parg.rsp_policy = ðtool_string_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGS_STRING) { + parg.data = &dst->string[i]; + if (ethtool_string_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void ethtool_bitset_free(struct ethtool_bitset *obj) +{ + ethtool_bitset_bits_free(&obj->bits); +} + +int ethtool_bitset_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_bitset *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.nomask) + mnl_attr_put(nlh, ETHTOOL_A_BITSET_NOMASK, 0, NULL); + if (obj->_present.size) + mnl_attr_put_u32(nlh, ETHTOOL_A_BITSET_SIZE, obj->size); + if (obj->_present.bits) + ethtool_bitset_bits_put(nlh, ETHTOOL_A_BITSET_BITS, &obj->bits); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_bitset_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_bitset *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + parg.ys = yarg->ys; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_BITSET_NOMASK) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.nomask = 1; + } else if (type == ETHTOOL_A_BITSET_SIZE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.size = 1; + dst->size = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_BITSET_BITS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.bits = 1; + + parg.rsp_policy = ðtool_bitset_bits_nest; + parg.data = &dst->bits; + if (ethtool_bitset_bits_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return 0; +} + +void ethtool_stringset_free(struct ethtool_stringset_ *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_strings; i++) + ethtool_strings_free(&obj->strings[i]); + free(obj->strings); +} + +int ethtool_stringset_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_stringset_ *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + if (obj->_present.id) + mnl_attr_put_u32(nlh, ETHTOOL_A_STRINGSET_ID, obj->id); + if (obj->_present.count) + mnl_attr_put_u32(nlh, ETHTOOL_A_STRINGSET_COUNT, obj->count); + for (unsigned int i = 0; i < obj->n_strings; i++) + ethtool_strings_put(nlh, ETHTOOL_A_STRINGSET_STRINGS, &obj->strings[i]); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_stringset_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_stringset_ *dst = yarg->data; + unsigned int n_strings = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->strings) + return ynl_error_parse(yarg, "attribute already present (stringset.strings)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_STRINGSET_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.id = 1; + dst->id = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_STRINGSET_COUNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.count = 1; + dst->count = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_STRINGSET_STRINGS) { + n_strings++; + } + } + + if (n_strings) { + dst->strings = calloc(n_strings, sizeof(*dst->strings)); + dst->n_strings = n_strings; + i = 0; + parg.rsp_policy = ðtool_strings_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGSET_STRINGS) { + parg.data = &dst->strings[i]; + if (ethtool_strings_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void ethtool_tunnel_udp_table_free(struct ethtool_tunnel_udp_table *obj) +{ + unsigned int i; + + ethtool_bitset_free(&obj->types); + for (i = 0; i < obj->n_entry; i++) + ethtool_tunnel_udp_entry_free(&obj->entry[i]); + free(obj->entry); +} + +int ethtool_tunnel_udp_table_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_tunnel_udp_table *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + unsigned int n_entry = 0; + int i; + + parg.ys = yarg->ys; + + if (dst->entry) + return ynl_error_parse(yarg, "attribute already present (tunnel-udp-table.entry)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_SIZE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.size = 1; + dst->size = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_TYPES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.types = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->types; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY) { + n_entry++; + } + } + + if (n_entry) { + dst->entry = calloc(n_entry, sizeof(*dst->entry)); + dst->n_entry = n_entry; + i = 0; + parg.rsp_policy = ðtool_tunnel_udp_entry_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == ETHTOOL_A_TUNNEL_UDP_TABLE_ENTRY) { + parg.data = &dst->entry[i]; + if (ethtool_tunnel_udp_entry_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void ethtool_stringsets_free(struct ethtool_stringsets *obj) +{ + unsigned int i; + + for (i = 0; i < obj->n_stringset; i++) + ethtool_stringset_free(&obj->stringset[i]); + free(obj->stringset); +} + +int ethtool_stringsets_put(struct nlmsghdr *nlh, unsigned int attr_type, + struct ethtool_stringsets *obj) +{ + struct nlattr *nest; + + nest = mnl_attr_nest_start(nlh, attr_type); + for (unsigned int i = 0; i < obj->n_stringset; i++) + ethtool_stringset_put(nlh, ETHTOOL_A_STRINGSETS_STRINGSET, &obj->stringset[i]); + mnl_attr_nest_end(nlh, nest); + + return 0; +} + +int ethtool_stringsets_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_stringsets *dst = yarg->data; + unsigned int n_stringset = 0; + const struct nlattr *attr; + struct ynl_parse_arg parg; + int i; + + parg.ys = yarg->ys; + + if (dst->stringset) + return ynl_error_parse(yarg, "attribute already present (stringsets.stringset)"); + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_STRINGSETS_STRINGSET) { + n_stringset++; + } + } + + if (n_stringset) { + dst->stringset = calloc(n_stringset, sizeof(*dst->stringset)); + dst->n_stringset = n_stringset; + i = 0; + parg.rsp_policy = ðtool_stringset_nest; + mnl_attr_for_each_nested(attr, nested) { + if (mnl_attr_get_type(attr) == ETHTOOL_A_STRINGSETS_STRINGSET) { + parg.data = &dst->stringset[i]; + if (ethtool_stringset_parse(&parg, attr)) + return MNL_CB_ERROR; + i++; + } + } + } + + return 0; +} + +void ethtool_tunnel_udp_free(struct ethtool_tunnel_udp *obj) +{ + ethtool_tunnel_udp_table_free(&obj->table); +} + +int ethtool_tunnel_udp_parse(struct ynl_parse_arg *yarg, + const struct nlattr *nested) +{ + struct ethtool_tunnel_udp *dst = yarg->data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + parg.ys = yarg->ys; + + mnl_attr_for_each_nested(attr, nested) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_TUNNEL_UDP_TABLE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.table = 1; + + parg.rsp_policy = ðtool_tunnel_udp_table_nest; + parg.data = &dst->table; + if (ethtool_tunnel_udp_table_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return 0; +} + +/* ============== ETHTOOL_MSG_STRSET_GET ============== */ +/* ETHTOOL_MSG_STRSET_GET - do */ +void ethtool_strset_get_req_free(struct ethtool_strset_get_req *req) +{ + ethtool_header_free(&req->header); + ethtool_stringsets_free(&req->stringsets); + free(req); +} + +void ethtool_strset_get_rsp_free(struct ethtool_strset_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_stringsets_free(&rsp->stringsets); + free(rsp); +} + +int ethtool_strset_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_strset_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_STRSET_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_STRSET_STRINGSETS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.stringsets = 1; + + parg.rsp_policy = ðtool_stringsets_nest; + parg.data = &dst->stringsets; + if (ethtool_stringsets_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct ethtool_strset_get_rsp * +ethtool_strset_get(struct ynl_sock *ys, struct ethtool_strset_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_strset_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1); + ys->req_policy = ðtool_strset_nest; + yrs.yarg.rsp_policy = ðtool_strset_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_STRSET_HEADER, &req->header); + if (req->_present.stringsets) + ethtool_stringsets_put(nlh, ETHTOOL_A_STRSET_STRINGSETS, &req->stringsets); + if (req->_present.counts_only) + mnl_attr_put(nlh, ETHTOOL_A_STRSET_COUNTS_ONLY, 0, NULL); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_strset_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_STRSET_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_strset_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_STRSET_GET - dump */ +void ethtool_strset_get_list_free(struct ethtool_strset_get_list *rsp) +{ + struct ethtool_strset_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_stringsets_free(&rsp->obj.stringsets); + free(rsp); + } +} + +struct ethtool_strset_get_list * +ethtool_strset_get_dump(struct ynl_sock *ys, + struct ethtool_strset_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_strset_get_list); + yds.cb = ethtool_strset_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_STRSET_GET; + yds.rsp_policy = ðtool_strset_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_STRSET_GET, 1); + ys->req_policy = ðtool_strset_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_STRSET_HEADER, &req->header); + if (req->_present.stringsets) + ethtool_stringsets_put(nlh, ETHTOOL_A_STRSET_STRINGSETS, &req->stringsets); + if (req->_present.counts_only) + mnl_attr_put(nlh, ETHTOOL_A_STRSET_COUNTS_ONLY, 0, NULL); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_strset_get_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_LINKINFO_GET ============== */ +/* ETHTOOL_MSG_LINKINFO_GET - do */ +void ethtool_linkinfo_get_req_free(struct ethtool_linkinfo_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_linkinfo_get_rsp_free(struct ethtool_linkinfo_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_linkinfo_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_linkinfo_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_LINKINFO_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_LINKINFO_PORT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.port = 1; + dst->port = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKINFO_PHYADDR) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.phyaddr = 1; + dst->phyaddr = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKINFO_TP_MDIX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tp_mdix = 1; + dst->tp_mdix = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKINFO_TP_MDIX_CTRL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tp_mdix_ctrl = 1; + dst->tp_mdix_ctrl = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKINFO_TRANSCEIVER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.transceiver = 1; + dst->transceiver = mnl_attr_get_u8(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_linkinfo_get_rsp * +ethtool_linkinfo_get(struct ynl_sock *ys, struct ethtool_linkinfo_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_linkinfo_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1); + ys->req_policy = ðtool_linkinfo_nest; + yrs.yarg.rsp_policy = ðtool_linkinfo_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_linkinfo_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_LINKINFO_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_linkinfo_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_LINKINFO_GET - dump */ +void ethtool_linkinfo_get_list_free(struct ethtool_linkinfo_get_list *rsp) +{ + struct ethtool_linkinfo_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_linkinfo_get_list * +ethtool_linkinfo_get_dump(struct ynl_sock *ys, + struct ethtool_linkinfo_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_linkinfo_get_list); + yds.cb = ethtool_linkinfo_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_LINKINFO_GET; + yds.rsp_policy = ðtool_linkinfo_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_GET, 1); + ys->req_policy = ðtool_linkinfo_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_linkinfo_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_LINKINFO_GET - notify */ +void ethtool_linkinfo_get_ntf_free(struct ethtool_linkinfo_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + free(rsp); +} + +/* ============== ETHTOOL_MSG_LINKINFO_SET ============== */ +/* ETHTOOL_MSG_LINKINFO_SET - do */ +void ethtool_linkinfo_set_req_free(struct ethtool_linkinfo_set_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_linkinfo_set(struct ynl_sock *ys, + struct ethtool_linkinfo_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKINFO_SET, 1); + ys->req_policy = ðtool_linkinfo_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_LINKINFO_HEADER, &req->header); + if (req->_present.port) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_PORT, req->port); + if (req->_present.phyaddr) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_PHYADDR, req->phyaddr); + if (req->_present.tp_mdix) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TP_MDIX, req->tp_mdix); + if (req->_present.tp_mdix_ctrl) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, req->tp_mdix_ctrl); + if (req->_present.transceiver) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKINFO_TRANSCEIVER, req->transceiver); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_LINKMODES_GET ============== */ +/* ETHTOOL_MSG_LINKMODES_GET - do */ +void ethtool_linkmodes_get_req_free(struct ethtool_linkmodes_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_linkmodes_get_rsp_free(struct ethtool_linkmodes_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->ours); + ethtool_bitset_free(&rsp->peer); + free(rsp); +} + +int ethtool_linkmodes_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_linkmodes_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_LINKMODES_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_LINKMODES_AUTONEG) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.autoneg = 1; + dst->autoneg = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKMODES_OURS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ours = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->ours; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_LINKMODES_PEER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.peer = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->peer; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_LINKMODES_SPEED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.speed = 1; + dst->speed = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_LINKMODES_DUPLEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.duplex = 1; + dst->duplex = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.master_slave_cfg = 1; + dst->master_slave_cfg = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.master_slave_state = 1; + dst->master_slave_state = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKMODES_LANES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.lanes = 1; + dst->lanes = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_LINKMODES_RATE_MATCHING) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rate_matching = 1; + dst->rate_matching = mnl_attr_get_u8(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_linkmodes_get_rsp * +ethtool_linkmodes_get(struct ynl_sock *ys, + struct ethtool_linkmodes_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_linkmodes_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1); + ys->req_policy = ðtool_linkmodes_nest; + yrs.yarg.rsp_policy = ðtool_linkmodes_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_linkmodes_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_LINKMODES_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_linkmodes_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_LINKMODES_GET - dump */ +void ethtool_linkmodes_get_list_free(struct ethtool_linkmodes_get_list *rsp) +{ + struct ethtool_linkmodes_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.ours); + ethtool_bitset_free(&rsp->obj.peer); + free(rsp); + } +} + +struct ethtool_linkmodes_get_list * +ethtool_linkmodes_get_dump(struct ynl_sock *ys, + struct ethtool_linkmodes_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_linkmodes_get_list); + yds.cb = ethtool_linkmodes_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_LINKMODES_GET; + yds.rsp_policy = ðtool_linkmodes_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_GET, 1); + ys->req_policy = ðtool_linkmodes_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_linkmodes_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_LINKMODES_GET - notify */ +void ethtool_linkmodes_get_ntf_free(struct ethtool_linkmodes_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.ours); + ethtool_bitset_free(&rsp->obj.peer); + free(rsp); +} + +/* ============== ETHTOOL_MSG_LINKMODES_SET ============== */ +/* ETHTOOL_MSG_LINKMODES_SET - do */ +void ethtool_linkmodes_set_req_free(struct ethtool_linkmodes_set_req *req) +{ + ethtool_header_free(&req->header); + ethtool_bitset_free(&req->ours); + ethtool_bitset_free(&req->peer); + free(req); +} + +int ethtool_linkmodes_set(struct ynl_sock *ys, + struct ethtool_linkmodes_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKMODES_SET, 1); + ys->req_policy = ðtool_linkmodes_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_LINKMODES_HEADER, &req->header); + if (req->_present.autoneg) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_AUTONEG, req->autoneg); + if (req->_present.ours) + ethtool_bitset_put(nlh, ETHTOOL_A_LINKMODES_OURS, &req->ours); + if (req->_present.peer) + ethtool_bitset_put(nlh, ETHTOOL_A_LINKMODES_PEER, &req->peer); + if (req->_present.speed) + mnl_attr_put_u32(nlh, ETHTOOL_A_LINKMODES_SPEED, req->speed); + if (req->_present.duplex) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_DUPLEX, req->duplex); + if (req->_present.master_slave_cfg) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG, req->master_slave_cfg); + if (req->_present.master_slave_state) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE, req->master_slave_state); + if (req->_present.lanes) + mnl_attr_put_u32(nlh, ETHTOOL_A_LINKMODES_LANES, req->lanes); + if (req->_present.rate_matching) + mnl_attr_put_u8(nlh, ETHTOOL_A_LINKMODES_RATE_MATCHING, req->rate_matching); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_LINKSTATE_GET ============== */ +/* ETHTOOL_MSG_LINKSTATE_GET - do */ +void ethtool_linkstate_get_req_free(struct ethtool_linkstate_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_linkstate_get_rsp_free(struct ethtool_linkstate_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_linkstate_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_linkstate_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_LINKSTATE_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_LINKSTATE_LINK) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.link = 1; + dst->link = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKSTATE_SQI) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sqi = 1; + dst->sqi = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_LINKSTATE_SQI_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.sqi_max = 1; + dst->sqi_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_LINKSTATE_EXT_STATE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ext_state = 1; + dst->ext_state = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKSTATE_EXT_SUBSTATE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ext_substate = 1; + dst->ext_substate = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.ext_down_cnt = 1; + dst->ext_down_cnt = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_linkstate_get_rsp * +ethtool_linkstate_get(struct ynl_sock *ys, + struct ethtool_linkstate_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_linkstate_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1); + ys->req_policy = ðtool_linkstate_nest; + yrs.yarg.rsp_policy = ðtool_linkstate_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_LINKSTATE_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_linkstate_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_LINKSTATE_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_linkstate_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_LINKSTATE_GET - dump */ +void ethtool_linkstate_get_list_free(struct ethtool_linkstate_get_list *rsp) +{ + struct ethtool_linkstate_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_linkstate_get_list * +ethtool_linkstate_get_dump(struct ynl_sock *ys, + struct ethtool_linkstate_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_linkstate_get_list); + yds.cb = ethtool_linkstate_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_LINKSTATE_GET; + yds.rsp_policy = ðtool_linkstate_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_LINKSTATE_GET, 1); + ys->req_policy = ðtool_linkstate_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_LINKSTATE_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_linkstate_get_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_DEBUG_GET ============== */ +/* ETHTOOL_MSG_DEBUG_GET - do */ +void ethtool_debug_get_req_free(struct ethtool_debug_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_debug_get_rsp_free(struct ethtool_debug_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->msgmask); + free(rsp); +} + +int ethtool_debug_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_debug_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_DEBUG_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_DEBUG_MSGMASK) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.msgmask = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->msgmask; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct ethtool_debug_get_rsp * +ethtool_debug_get(struct ynl_sock *ys, struct ethtool_debug_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_debug_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1); + ys->req_policy = ðtool_debug_nest; + yrs.yarg.rsp_policy = ðtool_debug_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_debug_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_DEBUG_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_debug_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_DEBUG_GET - dump */ +void ethtool_debug_get_list_free(struct ethtool_debug_get_list *rsp) +{ + struct ethtool_debug_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.msgmask); + free(rsp); + } +} + +struct ethtool_debug_get_list * +ethtool_debug_get_dump(struct ynl_sock *ys, + struct ethtool_debug_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_debug_get_list); + yds.cb = ethtool_debug_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_DEBUG_GET; + yds.rsp_policy = ðtool_debug_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_DEBUG_GET, 1); + ys->req_policy = ðtool_debug_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_debug_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_DEBUG_GET - notify */ +void ethtool_debug_get_ntf_free(struct ethtool_debug_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.msgmask); + free(rsp); +} + +/* ============== ETHTOOL_MSG_DEBUG_SET ============== */ +/* ETHTOOL_MSG_DEBUG_SET - do */ +void ethtool_debug_set_req_free(struct ethtool_debug_set_req *req) +{ + ethtool_header_free(&req->header); + ethtool_bitset_free(&req->msgmask); + free(req); +} + +int ethtool_debug_set(struct ynl_sock *ys, struct ethtool_debug_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_DEBUG_SET, 1); + ys->req_policy = ðtool_debug_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_DEBUG_HEADER, &req->header); + if (req->_present.msgmask) + ethtool_bitset_put(nlh, ETHTOOL_A_DEBUG_MSGMASK, &req->msgmask); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_WOL_GET ============== */ +/* ETHTOOL_MSG_WOL_GET - do */ +void ethtool_wol_get_req_free(struct ethtool_wol_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_wol_get_rsp_free(struct ethtool_wol_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->modes); + free(rsp->sopass); + free(rsp); +} + +int ethtool_wol_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct ethtool_wol_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_WOL_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_WOL_MODES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.modes = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->modes; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_WOL_SOPASS) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.sopass_len = len; + dst->sopass = malloc(len); + memcpy(dst->sopass, mnl_attr_get_payload(attr), len); + } + } + + return MNL_CB_OK; +} + +struct ethtool_wol_get_rsp * +ethtool_wol_get(struct ynl_sock *ys, struct ethtool_wol_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_wol_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1); + ys->req_policy = ðtool_wol_nest; + yrs.yarg.rsp_policy = ðtool_wol_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_wol_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_WOL_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_wol_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_WOL_GET - dump */ +void ethtool_wol_get_list_free(struct ethtool_wol_get_list *rsp) +{ + struct ethtool_wol_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.modes); + free(rsp->obj.sopass); + free(rsp); + } +} + +struct ethtool_wol_get_list * +ethtool_wol_get_dump(struct ynl_sock *ys, struct ethtool_wol_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_wol_get_list); + yds.cb = ethtool_wol_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_WOL_GET; + yds.rsp_policy = ðtool_wol_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_WOL_GET, 1); + ys->req_policy = ðtool_wol_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_wol_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_WOL_GET - notify */ +void ethtool_wol_get_ntf_free(struct ethtool_wol_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.modes); + free(rsp->obj.sopass); + free(rsp); +} + +/* ============== ETHTOOL_MSG_WOL_SET ============== */ +/* ETHTOOL_MSG_WOL_SET - do */ +void ethtool_wol_set_req_free(struct ethtool_wol_set_req *req) +{ + ethtool_header_free(&req->header); + ethtool_bitset_free(&req->modes); + free(req->sopass); + free(req); +} + +int ethtool_wol_set(struct ynl_sock *ys, struct ethtool_wol_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_WOL_SET, 1); + ys->req_policy = ðtool_wol_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_WOL_HEADER, &req->header); + if (req->_present.modes) + ethtool_bitset_put(nlh, ETHTOOL_A_WOL_MODES, &req->modes); + if (req->_present.sopass_len) + mnl_attr_put(nlh, ETHTOOL_A_WOL_SOPASS, req->_present.sopass_len, req->sopass); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_FEATURES_GET ============== */ +/* ETHTOOL_MSG_FEATURES_GET - do */ +void ethtool_features_get_req_free(struct ethtool_features_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_features_get_rsp_free(struct ethtool_features_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->hw); + ethtool_bitset_free(&rsp->wanted); + ethtool_bitset_free(&rsp->active); + ethtool_bitset_free(&rsp->nochange); + free(rsp); +} + +int ethtool_features_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_features_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_FEATURES_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEATURES_HW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.hw = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->hw; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEATURES_WANTED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.wanted = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->wanted; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEATURES_ACTIVE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.active = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->active; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEATURES_NOCHANGE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.nochange = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->nochange; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct ethtool_features_get_rsp * +ethtool_features_get(struct ynl_sock *ys, struct ethtool_features_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_features_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1); + ys->req_policy = ðtool_features_nest; + yrs.yarg.rsp_policy = ðtool_features_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_features_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_FEATURES_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_features_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_FEATURES_GET - dump */ +void ethtool_features_get_list_free(struct ethtool_features_get_list *rsp) +{ + struct ethtool_features_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.hw); + ethtool_bitset_free(&rsp->obj.wanted); + ethtool_bitset_free(&rsp->obj.active); + ethtool_bitset_free(&rsp->obj.nochange); + free(rsp); + } +} + +struct ethtool_features_get_list * +ethtool_features_get_dump(struct ynl_sock *ys, + struct ethtool_features_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_features_get_list); + yds.cb = ethtool_features_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_FEATURES_GET; + yds.rsp_policy = ðtool_features_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEATURES_GET, 1); + ys->req_policy = ðtool_features_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_features_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_FEATURES_GET - notify */ +void ethtool_features_get_ntf_free(struct ethtool_features_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.hw); + ethtool_bitset_free(&rsp->obj.wanted); + ethtool_bitset_free(&rsp->obj.active); + ethtool_bitset_free(&rsp->obj.nochange); + free(rsp); +} + +/* ============== ETHTOOL_MSG_FEATURES_SET ============== */ +/* ETHTOOL_MSG_FEATURES_SET - do */ +void ethtool_features_set_req_free(struct ethtool_features_set_req *req) +{ + ethtool_header_free(&req->header); + ethtool_bitset_free(&req->hw); + ethtool_bitset_free(&req->wanted); + ethtool_bitset_free(&req->active); + ethtool_bitset_free(&req->nochange); + free(req); +} + +void ethtool_features_set_rsp_free(struct ethtool_features_set_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->hw); + ethtool_bitset_free(&rsp->wanted); + ethtool_bitset_free(&rsp->active); + ethtool_bitset_free(&rsp->nochange); + free(rsp); +} + +int ethtool_features_set_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_features_set_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_FEATURES_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEATURES_HW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.hw = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->hw; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEATURES_WANTED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.wanted = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->wanted; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEATURES_ACTIVE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.active = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->active; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEATURES_NOCHANGE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.nochange = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->nochange; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct ethtool_features_set_rsp * +ethtool_features_set(struct ynl_sock *ys, struct ethtool_features_set_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_features_set_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEATURES_SET, 1); + ys->req_policy = ðtool_features_nest; + yrs.yarg.rsp_policy = ðtool_features_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_FEATURES_HEADER, &req->header); + if (req->_present.hw) + ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_HW, &req->hw); + if (req->_present.wanted) + ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_WANTED, &req->wanted); + if (req->_present.active) + ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_ACTIVE, &req->active); + if (req->_present.nochange) + ethtool_bitset_put(nlh, ETHTOOL_A_FEATURES_NOCHANGE, &req->nochange); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_features_set_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_FEATURES_SET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_features_set_rsp_free(rsp); + return NULL; +} + +/* ============== ETHTOOL_MSG_PRIVFLAGS_GET ============== */ +/* ETHTOOL_MSG_PRIVFLAGS_GET - do */ +void ethtool_privflags_get_req_free(struct ethtool_privflags_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_privflags_get_rsp_free(struct ethtool_privflags_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->flags); + free(rsp); +} + +int ethtool_privflags_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_privflags_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_PRIVFLAGS_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_PRIVFLAGS_FLAGS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.flags = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->flags; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct ethtool_privflags_get_rsp * +ethtool_privflags_get(struct ynl_sock *ys, + struct ethtool_privflags_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_privflags_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1); + ys->req_policy = ðtool_privflags_nest; + yrs.yarg.rsp_policy = ðtool_privflags_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_privflags_get_rsp_parse; + yrs.rsp_cmd = 14; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_privflags_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_PRIVFLAGS_GET - dump */ +void ethtool_privflags_get_list_free(struct ethtool_privflags_get_list *rsp) +{ + struct ethtool_privflags_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.flags); + free(rsp); + } +} + +struct ethtool_privflags_get_list * +ethtool_privflags_get_dump(struct ynl_sock *ys, + struct ethtool_privflags_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_privflags_get_list); + yds.cb = ethtool_privflags_get_rsp_parse; + yds.rsp_cmd = 14; + yds.rsp_policy = ðtool_privflags_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_GET, 1); + ys->req_policy = ðtool_privflags_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_privflags_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_PRIVFLAGS_GET - notify */ +void ethtool_privflags_get_ntf_free(struct ethtool_privflags_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.flags); + free(rsp); +} + +/* ============== ETHTOOL_MSG_PRIVFLAGS_SET ============== */ +/* ETHTOOL_MSG_PRIVFLAGS_SET - do */ +void ethtool_privflags_set_req_free(struct ethtool_privflags_set_req *req) +{ + ethtool_header_free(&req->header); + ethtool_bitset_free(&req->flags); + free(req); +} + +int ethtool_privflags_set(struct ynl_sock *ys, + struct ethtool_privflags_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PRIVFLAGS_SET, 1); + ys->req_policy = ðtool_privflags_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PRIVFLAGS_HEADER, &req->header); + if (req->_present.flags) + ethtool_bitset_put(nlh, ETHTOOL_A_PRIVFLAGS_FLAGS, &req->flags); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_RINGS_GET ============== */ +/* ETHTOOL_MSG_RINGS_GET - do */ +void ethtool_rings_get_req_free(struct ethtool_rings_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_rings_get_rsp_free(struct ethtool_rings_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_rings_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_rings_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_RINGS_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_RINGS_RX_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_max = 1; + dst->rx_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_RX_MINI_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_mini_max = 1; + dst->rx_mini_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_RX_JUMBO_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_jumbo_max = 1; + dst->rx_jumbo_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_TX_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_max = 1; + dst->tx_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_RX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx = 1; + dst->rx = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_RX_MINI) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_mini = 1; + dst->rx_mini = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_RX_JUMBO) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_jumbo = 1; + dst->rx_jumbo = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_TX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx = 1; + dst->tx = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_RX_BUF_LEN) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_buf_len = 1; + dst->rx_buf_len = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_TCP_DATA_SPLIT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tcp_data_split = 1; + dst->tcp_data_split = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_RINGS_CQE_SIZE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.cqe_size = 1; + dst->cqe_size = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_TX_PUSH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_push = 1; + dst->tx_push = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_RINGS_RX_PUSH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_push = 1; + dst->rx_push = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_push_buf_len = 1; + dst->tx_push_buf_len = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_push_buf_len_max = 1; + dst->tx_push_buf_len_max = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_rings_get_rsp * +ethtool_rings_get(struct ynl_sock *ys, struct ethtool_rings_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_rings_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1); + ys->req_policy = ðtool_rings_nest; + yrs.yarg.rsp_policy = ðtool_rings_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_rings_get_rsp_parse; + yrs.rsp_cmd = 16; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_rings_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_RINGS_GET - dump */ +void ethtool_rings_get_list_free(struct ethtool_rings_get_list *rsp) +{ + struct ethtool_rings_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_rings_get_list * +ethtool_rings_get_dump(struct ynl_sock *ys, + struct ethtool_rings_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_rings_get_list); + yds.cb = ethtool_rings_get_rsp_parse; + yds.rsp_cmd = 16; + yds.rsp_policy = ðtool_rings_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RINGS_GET, 1); + ys->req_policy = ðtool_rings_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_rings_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_RINGS_GET - notify */ +void ethtool_rings_get_ntf_free(struct ethtool_rings_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + free(rsp); +} + +/* ============== ETHTOOL_MSG_RINGS_SET ============== */ +/* ETHTOOL_MSG_RINGS_SET - do */ +void ethtool_rings_set_req_free(struct ethtool_rings_set_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_rings_set(struct ynl_sock *ys, struct ethtool_rings_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RINGS_SET, 1); + ys->req_policy = ðtool_rings_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_RINGS_HEADER, &req->header); + if (req->_present.rx_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MAX, req->rx_max); + if (req->_present.rx_mini_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MINI_MAX, req->rx_mini_max); + if (req->_present.rx_jumbo_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_JUMBO_MAX, req->rx_jumbo_max); + if (req->_present.tx_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_MAX, req->tx_max); + if (req->_present.rx) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX, req->rx); + if (req->_present.rx_mini) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_MINI, req->rx_mini); + if (req->_present.rx_jumbo) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_JUMBO, req->rx_jumbo); + if (req->_present.tx) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX, req->tx); + if (req->_present.rx_buf_len) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_RX_BUF_LEN, req->rx_buf_len); + if (req->_present.tcp_data_split) + mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_TCP_DATA_SPLIT, req->tcp_data_split); + if (req->_present.cqe_size) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_CQE_SIZE, req->cqe_size); + if (req->_present.tx_push) + mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_TX_PUSH, req->tx_push); + if (req->_present.rx_push) + mnl_attr_put_u8(nlh, ETHTOOL_A_RINGS_RX_PUSH, req->rx_push); + if (req->_present.tx_push_buf_len) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN, req->tx_push_buf_len); + if (req->_present.tx_push_buf_len_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX, req->tx_push_buf_len_max); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_CHANNELS_GET ============== */ +/* ETHTOOL_MSG_CHANNELS_GET - do */ +void ethtool_channels_get_req_free(struct ethtool_channels_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_channels_get_rsp_free(struct ethtool_channels_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_channels_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_channels_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_CHANNELS_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_CHANNELS_RX_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_max = 1; + dst->rx_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_CHANNELS_TX_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_max = 1; + dst->tx_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_CHANNELS_OTHER_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.other_max = 1; + dst->other_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_CHANNELS_COMBINED_MAX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.combined_max = 1; + dst->combined_max = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_CHANNELS_RX_COUNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_count = 1; + dst->rx_count = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_CHANNELS_TX_COUNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_count = 1; + dst->tx_count = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_CHANNELS_OTHER_COUNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.other_count = 1; + dst->other_count = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_CHANNELS_COMBINED_COUNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.combined_count = 1; + dst->combined_count = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_channels_get_rsp * +ethtool_channels_get(struct ynl_sock *ys, struct ethtool_channels_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_channels_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1); + ys->req_policy = ðtool_channels_nest; + yrs.yarg.rsp_policy = ðtool_channels_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_channels_get_rsp_parse; + yrs.rsp_cmd = 18; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_channels_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_CHANNELS_GET - dump */ +void ethtool_channels_get_list_free(struct ethtool_channels_get_list *rsp) +{ + struct ethtool_channels_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_channels_get_list * +ethtool_channels_get_dump(struct ynl_sock *ys, + struct ethtool_channels_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_channels_get_list); + yds.cb = ethtool_channels_get_rsp_parse; + yds.rsp_cmd = 18; + yds.rsp_policy = ðtool_channels_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_GET, 1); + ys->req_policy = ðtool_channels_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_channels_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_CHANNELS_GET - notify */ +void ethtool_channels_get_ntf_free(struct ethtool_channels_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + free(rsp); +} + +/* ============== ETHTOOL_MSG_CHANNELS_SET ============== */ +/* ETHTOOL_MSG_CHANNELS_SET - do */ +void ethtool_channels_set_req_free(struct ethtool_channels_set_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_channels_set(struct ynl_sock *ys, + struct ethtool_channels_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CHANNELS_SET, 1); + ys->req_policy = ðtool_channels_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_CHANNELS_HEADER, &req->header); + if (req->_present.rx_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_RX_MAX, req->rx_max); + if (req->_present.tx_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_TX_MAX, req->tx_max); + if (req->_present.other_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_OTHER_MAX, req->other_max); + if (req->_present.combined_max) + mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_COMBINED_MAX, req->combined_max); + if (req->_present.rx_count) + mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_RX_COUNT, req->rx_count); + if (req->_present.tx_count) + mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_TX_COUNT, req->tx_count); + if (req->_present.other_count) + mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_OTHER_COUNT, req->other_count); + if (req->_present.combined_count) + mnl_attr_put_u32(nlh, ETHTOOL_A_CHANNELS_COMBINED_COUNT, req->combined_count); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_COALESCE_GET ============== */ +/* ETHTOOL_MSG_COALESCE_GET - do */ +void ethtool_coalesce_get_req_free(struct ethtool_coalesce_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_coalesce_get_rsp_free(struct ethtool_coalesce_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_coalesce_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_coalesce_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_COALESCE_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_COALESCE_RX_USECS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_usecs = 1; + dst->rx_usecs = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_max_frames = 1; + dst->rx_max_frames = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_RX_USECS_IRQ) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_usecs_irq = 1; + dst->rx_usecs_irq = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_max_frames_irq = 1; + dst->rx_max_frames_irq = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_USECS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_usecs = 1; + dst->tx_usecs = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_max_frames = 1; + dst->tx_max_frames = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_USECS_IRQ) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_usecs_irq = 1; + dst->tx_usecs_irq = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_max_frames_irq = 1; + dst->tx_max_frames_irq = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_STATS_BLOCK_USECS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.stats_block_usecs = 1; + dst->stats_block_usecs = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.use_adaptive_rx = 1; + dst->use_adaptive_rx = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.use_adaptive_tx = 1; + dst->use_adaptive_tx = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_COALESCE_PKT_RATE_LOW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.pkt_rate_low = 1; + dst->pkt_rate_low = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_RX_USECS_LOW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_usecs_low = 1; + dst->rx_usecs_low = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_max_frames_low = 1; + dst->rx_max_frames_low = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_USECS_LOW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_usecs_low = 1; + dst->tx_usecs_low = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_max_frames_low = 1; + dst->tx_max_frames_low = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_PKT_RATE_HIGH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.pkt_rate_high = 1; + dst->pkt_rate_high = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_RX_USECS_HIGH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_usecs_high = 1; + dst->rx_usecs_high = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_max_frames_high = 1; + dst->rx_max_frames_high = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_USECS_HIGH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_usecs_high = 1; + dst->tx_usecs_high = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_max_frames_high = 1; + dst->tx_max_frames_high = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rate_sample_interval = 1; + dst->rate_sample_interval = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_USE_CQE_MODE_TX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.use_cqe_mode_tx = 1; + dst->use_cqe_mode_tx = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_COALESCE_USE_CQE_MODE_RX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.use_cqe_mode_rx = 1; + dst->use_cqe_mode_rx = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_aggr_max_bytes = 1; + dst->tx_aggr_max_bytes = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_aggr_max_frames = 1; + dst->tx_aggr_max_frames = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_aggr_time_usecs = 1; + dst->tx_aggr_time_usecs = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_coalesce_get_rsp * +ethtool_coalesce_get(struct ynl_sock *ys, struct ethtool_coalesce_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_coalesce_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1); + ys->req_policy = ðtool_coalesce_nest; + yrs.yarg.rsp_policy = ðtool_coalesce_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_coalesce_get_rsp_parse; + yrs.rsp_cmd = 20; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_coalesce_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_COALESCE_GET - dump */ +void ethtool_coalesce_get_list_free(struct ethtool_coalesce_get_list *rsp) +{ + struct ethtool_coalesce_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_coalesce_get_list * +ethtool_coalesce_get_dump(struct ynl_sock *ys, + struct ethtool_coalesce_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_coalesce_get_list); + yds.cb = ethtool_coalesce_get_rsp_parse; + yds.rsp_cmd = 20; + yds.rsp_policy = ðtool_coalesce_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_COALESCE_GET, 1); + ys->req_policy = ðtool_coalesce_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_coalesce_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_COALESCE_GET - notify */ +void ethtool_coalesce_get_ntf_free(struct ethtool_coalesce_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + free(rsp); +} + +/* ============== ETHTOOL_MSG_COALESCE_SET ============== */ +/* ETHTOOL_MSG_COALESCE_SET - do */ +void ethtool_coalesce_set_req_free(struct ethtool_coalesce_set_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_coalesce_set(struct ynl_sock *ys, + struct ethtool_coalesce_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_COALESCE_SET, 1); + ys->req_policy = ðtool_coalesce_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_COALESCE_HEADER, &req->header); + if (req->_present.rx_usecs) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS, req->rx_usecs); + if (req->_present.rx_max_frames) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES, req->rx_max_frames); + if (req->_present.rx_usecs_irq) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_IRQ, req->rx_usecs_irq); + if (req->_present.rx_max_frames_irq) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ, req->rx_max_frames_irq); + if (req->_present.tx_usecs) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS, req->tx_usecs); + if (req->_present.tx_max_frames) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES, req->tx_max_frames); + if (req->_present.tx_usecs_irq) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_IRQ, req->tx_usecs_irq); + if (req->_present.tx_max_frames_irq) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ, req->tx_max_frames_irq); + if (req->_present.stats_block_usecs) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_STATS_BLOCK_USECS, req->stats_block_usecs); + if (req->_present.use_adaptive_rx) + mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX, req->use_adaptive_rx); + if (req->_present.use_adaptive_tx) + mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX, req->use_adaptive_tx); + if (req->_present.pkt_rate_low) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_PKT_RATE_LOW, req->pkt_rate_low); + if (req->_present.rx_usecs_low) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_LOW, req->rx_usecs_low); + if (req->_present.rx_max_frames_low) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW, req->rx_max_frames_low); + if (req->_present.tx_usecs_low) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_LOW, req->tx_usecs_low); + if (req->_present.tx_max_frames_low) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW, req->tx_max_frames_low); + if (req->_present.pkt_rate_high) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_PKT_RATE_HIGH, req->pkt_rate_high); + if (req->_present.rx_usecs_high) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_USECS_HIGH, req->rx_usecs_high); + if (req->_present.rx_max_frames_high) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH, req->rx_max_frames_high); + if (req->_present.tx_usecs_high) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_USECS_HIGH, req->tx_usecs_high); + if (req->_present.tx_max_frames_high) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH, req->tx_max_frames_high); + if (req->_present.rate_sample_interval) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL, req->rate_sample_interval); + if (req->_present.use_cqe_mode_tx) + mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_CQE_MODE_TX, req->use_cqe_mode_tx); + if (req->_present.use_cqe_mode_rx) + mnl_attr_put_u8(nlh, ETHTOOL_A_COALESCE_USE_CQE_MODE_RX, req->use_cqe_mode_rx); + if (req->_present.tx_aggr_max_bytes) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_MAX_BYTES, req->tx_aggr_max_bytes); + if (req->_present.tx_aggr_max_frames) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_MAX_FRAMES, req->tx_aggr_max_frames); + if (req->_present.tx_aggr_time_usecs) + mnl_attr_put_u32(nlh, ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, req->tx_aggr_time_usecs); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_PAUSE_GET ============== */ +/* ETHTOOL_MSG_PAUSE_GET - do */ +void ethtool_pause_get_req_free(struct ethtool_pause_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_pause_get_rsp_free(struct ethtool_pause_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_pause_stat_free(&rsp->stats); + free(rsp); +} + +int ethtool_pause_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_pause_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_PAUSE_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_PAUSE_AUTONEG) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.autoneg = 1; + dst->autoneg = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_PAUSE_RX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx = 1; + dst->rx = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_PAUSE_TX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx = 1; + dst->tx = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_PAUSE_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.stats = 1; + + parg.rsp_policy = ðtool_pause_stat_nest; + parg.data = &dst->stats; + if (ethtool_pause_stat_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_PAUSE_STATS_SRC) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.stats_src = 1; + dst->stats_src = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_pause_get_rsp * +ethtool_pause_get(struct ynl_sock *ys, struct ethtool_pause_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_pause_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1); + ys->req_policy = ðtool_pause_nest; + yrs.yarg.rsp_policy = ðtool_pause_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_pause_get_rsp_parse; + yrs.rsp_cmd = 22; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_pause_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_PAUSE_GET - dump */ +void ethtool_pause_get_list_free(struct ethtool_pause_get_list *rsp) +{ + struct ethtool_pause_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_pause_stat_free(&rsp->obj.stats); + free(rsp); + } +} + +struct ethtool_pause_get_list * +ethtool_pause_get_dump(struct ynl_sock *ys, + struct ethtool_pause_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_pause_get_list); + yds.cb = ethtool_pause_get_rsp_parse; + yds.rsp_cmd = 22; + yds.rsp_policy = ðtool_pause_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PAUSE_GET, 1); + ys->req_policy = ðtool_pause_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_pause_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_PAUSE_GET - notify */ +void ethtool_pause_get_ntf_free(struct ethtool_pause_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_pause_stat_free(&rsp->obj.stats); + free(rsp); +} + +/* ============== ETHTOOL_MSG_PAUSE_SET ============== */ +/* ETHTOOL_MSG_PAUSE_SET - do */ +void ethtool_pause_set_req_free(struct ethtool_pause_set_req *req) +{ + ethtool_header_free(&req->header); + ethtool_pause_stat_free(&req->stats); + free(req); +} + +int ethtool_pause_set(struct ynl_sock *ys, struct ethtool_pause_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PAUSE_SET, 1); + ys->req_policy = ðtool_pause_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PAUSE_HEADER, &req->header); + if (req->_present.autoneg) + mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_AUTONEG, req->autoneg); + if (req->_present.rx) + mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_RX, req->rx); + if (req->_present.tx) + mnl_attr_put_u8(nlh, ETHTOOL_A_PAUSE_TX, req->tx); + if (req->_present.stats) + ethtool_pause_stat_put(nlh, ETHTOOL_A_PAUSE_STATS, &req->stats); + if (req->_present.stats_src) + mnl_attr_put_u32(nlh, ETHTOOL_A_PAUSE_STATS_SRC, req->stats_src); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_EEE_GET ============== */ +/* ETHTOOL_MSG_EEE_GET - do */ +void ethtool_eee_get_req_free(struct ethtool_eee_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_eee_get_rsp_free(struct ethtool_eee_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->modes_ours); + ethtool_bitset_free(&rsp->modes_peer); + free(rsp); +} + +int ethtool_eee_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct ethtool_eee_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_EEE_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_EEE_MODES_OURS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.modes_ours = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->modes_ours; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_EEE_MODES_PEER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.modes_peer = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->modes_peer; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_EEE_ACTIVE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.active = 1; + dst->active = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_EEE_ENABLED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.enabled = 1; + dst->enabled = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_EEE_TX_LPI_ENABLED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_lpi_enabled = 1; + dst->tx_lpi_enabled = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_EEE_TX_LPI_TIMER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_lpi_timer = 1; + dst->tx_lpi_timer = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_eee_get_rsp * +ethtool_eee_get(struct ynl_sock *ys, struct ethtool_eee_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_eee_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1); + ys->req_policy = ðtool_eee_nest; + yrs.yarg.rsp_policy = ðtool_eee_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_eee_get_rsp_parse; + yrs.rsp_cmd = 24; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_eee_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_EEE_GET - dump */ +void ethtool_eee_get_list_free(struct ethtool_eee_get_list *rsp) +{ + struct ethtool_eee_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.modes_ours); + ethtool_bitset_free(&rsp->obj.modes_peer); + free(rsp); + } +} + +struct ethtool_eee_get_list * +ethtool_eee_get_dump(struct ynl_sock *ys, struct ethtool_eee_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_eee_get_list); + yds.cb = ethtool_eee_get_rsp_parse; + yds.rsp_cmd = 24; + yds.rsp_policy = ðtool_eee_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_EEE_GET, 1); + ys->req_policy = ðtool_eee_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_eee_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_EEE_GET - notify */ +void ethtool_eee_get_ntf_free(struct ethtool_eee_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.modes_ours); + ethtool_bitset_free(&rsp->obj.modes_peer); + free(rsp); +} + +/* ============== ETHTOOL_MSG_EEE_SET ============== */ +/* ETHTOOL_MSG_EEE_SET - do */ +void ethtool_eee_set_req_free(struct ethtool_eee_set_req *req) +{ + ethtool_header_free(&req->header); + ethtool_bitset_free(&req->modes_ours); + ethtool_bitset_free(&req->modes_peer); + free(req); +} + +int ethtool_eee_set(struct ynl_sock *ys, struct ethtool_eee_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_EEE_SET, 1); + ys->req_policy = ðtool_eee_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_EEE_HEADER, &req->header); + if (req->_present.modes_ours) + ethtool_bitset_put(nlh, ETHTOOL_A_EEE_MODES_OURS, &req->modes_ours); + if (req->_present.modes_peer) + ethtool_bitset_put(nlh, ETHTOOL_A_EEE_MODES_PEER, &req->modes_peer); + if (req->_present.active) + mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_ACTIVE, req->active); + if (req->_present.enabled) + mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_ENABLED, req->enabled); + if (req->_present.tx_lpi_enabled) + mnl_attr_put_u8(nlh, ETHTOOL_A_EEE_TX_LPI_ENABLED, req->tx_lpi_enabled); + if (req->_present.tx_lpi_timer) + mnl_attr_put_u32(nlh, ETHTOOL_A_EEE_TX_LPI_TIMER, req->tx_lpi_timer); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_TSINFO_GET ============== */ +/* ETHTOOL_MSG_TSINFO_GET - do */ +void ethtool_tsinfo_get_req_free(struct ethtool_tsinfo_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_tsinfo_get_rsp_free(struct ethtool_tsinfo_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->timestamping); + ethtool_bitset_free(&rsp->tx_types); + ethtool_bitset_free(&rsp->rx_filters); + free(rsp); +} + +int ethtool_tsinfo_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_tsinfo_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_TSINFO_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_TSINFO_TIMESTAMPING) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.timestamping = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->timestamping; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_TSINFO_TX_TYPES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_types = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->tx_types; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_TSINFO_RX_FILTERS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_filters = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->rx_filters; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_TSINFO_PHC_INDEX) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.phc_index = 1; + dst->phc_index = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_tsinfo_get_rsp * +ethtool_tsinfo_get(struct ynl_sock *ys, struct ethtool_tsinfo_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_tsinfo_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1); + ys->req_policy = ðtool_tsinfo_nest; + yrs.yarg.rsp_policy = ðtool_tsinfo_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_TSINFO_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_tsinfo_get_rsp_parse; + yrs.rsp_cmd = 26; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_tsinfo_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_TSINFO_GET - dump */ +void ethtool_tsinfo_get_list_free(struct ethtool_tsinfo_get_list *rsp) +{ + struct ethtool_tsinfo_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.timestamping); + ethtool_bitset_free(&rsp->obj.tx_types); + ethtool_bitset_free(&rsp->obj.rx_filters); + free(rsp); + } +} + +struct ethtool_tsinfo_get_list * +ethtool_tsinfo_get_dump(struct ynl_sock *ys, + struct ethtool_tsinfo_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_tsinfo_get_list); + yds.cb = ethtool_tsinfo_get_rsp_parse; + yds.rsp_cmd = 26; + yds.rsp_policy = ðtool_tsinfo_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TSINFO_GET, 1); + ys->req_policy = ðtool_tsinfo_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_TSINFO_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_tsinfo_get_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_CABLE_TEST_ACT ============== */ +/* ETHTOOL_MSG_CABLE_TEST_ACT - do */ +void ethtool_cable_test_act_req_free(struct ethtool_cable_test_act_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_cable_test_act(struct ynl_sock *ys, + struct ethtool_cable_test_act_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CABLE_TEST_ACT, 1); + ys->req_policy = ðtool_cable_test_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_CABLE_TEST_HEADER, &req->header); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_CABLE_TEST_TDR_ACT ============== */ +/* ETHTOOL_MSG_CABLE_TEST_TDR_ACT - do */ +void +ethtool_cable_test_tdr_act_req_free(struct ethtool_cable_test_tdr_act_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_cable_test_tdr_act(struct ynl_sock *ys, + struct ethtool_cable_test_tdr_act_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_CABLE_TEST_TDR_ACT, 1); + ys->req_policy = ðtool_cable_test_tdr_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_CABLE_TEST_TDR_HEADER, &req->header); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_TUNNEL_INFO_GET ============== */ +/* ETHTOOL_MSG_TUNNEL_INFO_GET - do */ +void ethtool_tunnel_info_get_req_free(struct ethtool_tunnel_info_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_tunnel_info_get_rsp_free(struct ethtool_tunnel_info_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_tunnel_udp_free(&rsp->udp_ports); + free(rsp); +} + +int ethtool_tunnel_info_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_tunnel_info_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_TUNNEL_INFO_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_TUNNEL_INFO_UDP_PORTS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.udp_ports = 1; + + parg.rsp_policy = ðtool_tunnel_udp_nest; + parg.data = &dst->udp_ports; + if (ethtool_tunnel_udp_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct ethtool_tunnel_info_get_rsp * +ethtool_tunnel_info_get(struct ynl_sock *ys, + struct ethtool_tunnel_info_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_tunnel_info_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1); + ys->req_policy = ðtool_tunnel_info_nest; + yrs.yarg.rsp_policy = ðtool_tunnel_info_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_TUNNEL_INFO_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_tunnel_info_get_rsp_parse; + yrs.rsp_cmd = 29; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_tunnel_info_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_TUNNEL_INFO_GET - dump */ +void +ethtool_tunnel_info_get_list_free(struct ethtool_tunnel_info_get_list *rsp) +{ + struct ethtool_tunnel_info_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_tunnel_udp_free(&rsp->obj.udp_ports); + free(rsp); + } +} + +struct ethtool_tunnel_info_get_list * +ethtool_tunnel_info_get_dump(struct ynl_sock *ys, + struct ethtool_tunnel_info_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_tunnel_info_get_list); + yds.cb = ethtool_tunnel_info_get_rsp_parse; + yds.rsp_cmd = 29; + yds.rsp_policy = ðtool_tunnel_info_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_TUNNEL_INFO_GET, 1); + ys->req_policy = ðtool_tunnel_info_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_TUNNEL_INFO_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_tunnel_info_get_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_FEC_GET ============== */ +/* ETHTOOL_MSG_FEC_GET - do */ +void ethtool_fec_get_req_free(struct ethtool_fec_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_fec_get_rsp_free(struct ethtool_fec_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_bitset_free(&rsp->modes); + ethtool_fec_stat_free(&rsp->stats); + free(rsp); +} + +int ethtool_fec_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct ethtool_fec_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_FEC_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEC_MODES) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.modes = 1; + + parg.rsp_policy = ðtool_bitset_nest; + parg.data = &dst->modes; + if (ethtool_bitset_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_FEC_AUTO) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.auto_ = 1; + dst->auto_ = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_FEC_ACTIVE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.active = 1; + dst->active = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_FEC_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.stats = 1; + + parg.rsp_policy = ðtool_fec_stat_nest; + parg.data = &dst->stats; + if (ethtool_fec_stat_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct ethtool_fec_get_rsp * +ethtool_fec_get(struct ynl_sock *ys, struct ethtool_fec_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_fec_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1); + ys->req_policy = ðtool_fec_nest; + yrs.yarg.rsp_policy = ðtool_fec_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_fec_get_rsp_parse; + yrs.rsp_cmd = 30; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_fec_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_FEC_GET - dump */ +void ethtool_fec_get_list_free(struct ethtool_fec_get_list *rsp) +{ + struct ethtool_fec_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.modes); + ethtool_fec_stat_free(&rsp->obj.stats); + free(rsp); + } +} + +struct ethtool_fec_get_list * +ethtool_fec_get_dump(struct ynl_sock *ys, struct ethtool_fec_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_fec_get_list); + yds.cb = ethtool_fec_get_rsp_parse; + yds.rsp_cmd = 30; + yds.rsp_policy = ðtool_fec_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_FEC_GET, 1); + ys->req_policy = ðtool_fec_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_fec_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_FEC_GET - notify */ +void ethtool_fec_get_ntf_free(struct ethtool_fec_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_bitset_free(&rsp->obj.modes); + ethtool_fec_stat_free(&rsp->obj.stats); + free(rsp); +} + +/* ============== ETHTOOL_MSG_FEC_SET ============== */ +/* ETHTOOL_MSG_FEC_SET - do */ +void ethtool_fec_set_req_free(struct ethtool_fec_set_req *req) +{ + ethtool_header_free(&req->header); + ethtool_bitset_free(&req->modes); + ethtool_fec_stat_free(&req->stats); + free(req); +} + +int ethtool_fec_set(struct ynl_sock *ys, struct ethtool_fec_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_FEC_SET, 1); + ys->req_policy = ðtool_fec_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_FEC_HEADER, &req->header); + if (req->_present.modes) + ethtool_bitset_put(nlh, ETHTOOL_A_FEC_MODES, &req->modes); + if (req->_present.auto_) + mnl_attr_put_u8(nlh, ETHTOOL_A_FEC_AUTO, req->auto_); + if (req->_present.active) + mnl_attr_put_u32(nlh, ETHTOOL_A_FEC_ACTIVE, req->active); + if (req->_present.stats) + ethtool_fec_stat_put(nlh, ETHTOOL_A_FEC_STATS, &req->stats); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_MODULE_EEPROM_GET ============== */ +/* ETHTOOL_MSG_MODULE_EEPROM_GET - do */ +void +ethtool_module_eeprom_get_req_free(struct ethtool_module_eeprom_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void +ethtool_module_eeprom_get_rsp_free(struct ethtool_module_eeprom_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp->data); + free(rsp); +} + +int ethtool_module_eeprom_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_module_eeprom_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_MODULE_EEPROM_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_MODULE_EEPROM_OFFSET) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.offset = 1; + dst->offset = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_MODULE_EEPROM_LENGTH) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.length = 1; + dst->length = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_MODULE_EEPROM_PAGE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.page = 1; + dst->page = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_MODULE_EEPROM_BANK) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.bank = 1; + dst->bank = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.i2c_address = 1; + dst->i2c_address = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_MODULE_EEPROM_DATA) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.data_len = len; + dst->data = malloc(len); + memcpy(dst->data, mnl_attr_get_payload(attr), len); + } + } + + return MNL_CB_OK; +} + +struct ethtool_module_eeprom_get_rsp * +ethtool_module_eeprom_get(struct ynl_sock *ys, + struct ethtool_module_eeprom_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_module_eeprom_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1); + ys->req_policy = ðtool_module_eeprom_nest; + yrs.yarg.rsp_policy = ðtool_module_eeprom_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_MODULE_EEPROM_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_module_eeprom_get_rsp_parse; + yrs.rsp_cmd = 32; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_module_eeprom_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_MODULE_EEPROM_GET - dump */ +void +ethtool_module_eeprom_get_list_free(struct ethtool_module_eeprom_get_list *rsp) +{ + struct ethtool_module_eeprom_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp->obj.data); + free(rsp); + } +} + +struct ethtool_module_eeprom_get_list * +ethtool_module_eeprom_get_dump(struct ynl_sock *ys, + struct ethtool_module_eeprom_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_module_eeprom_get_list); + yds.cb = ethtool_module_eeprom_get_rsp_parse; + yds.rsp_cmd = 32; + yds.rsp_policy = ðtool_module_eeprom_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_EEPROM_GET, 1); + ys->req_policy = ðtool_module_eeprom_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_MODULE_EEPROM_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_module_eeprom_get_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_PHC_VCLOCKS_GET ============== */ +/* ETHTOOL_MSG_PHC_VCLOCKS_GET - do */ +void ethtool_phc_vclocks_get_req_free(struct ethtool_phc_vclocks_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_phc_vclocks_get_rsp_free(struct ethtool_phc_vclocks_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_phc_vclocks_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_phc_vclocks_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_PHC_VCLOCKS_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_PHC_VCLOCKS_NUM) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.num = 1; + dst->num = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_phc_vclocks_get_rsp * +ethtool_phc_vclocks_get(struct ynl_sock *ys, + struct ethtool_phc_vclocks_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_phc_vclocks_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1); + ys->req_policy = ðtool_phc_vclocks_nest; + yrs.yarg.rsp_policy = ðtool_phc_vclocks_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PHC_VCLOCKS_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_phc_vclocks_get_rsp_parse; + yrs.rsp_cmd = 34; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_phc_vclocks_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_PHC_VCLOCKS_GET - dump */ +void +ethtool_phc_vclocks_get_list_free(struct ethtool_phc_vclocks_get_list *rsp) +{ + struct ethtool_phc_vclocks_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_phc_vclocks_get_list * +ethtool_phc_vclocks_get_dump(struct ynl_sock *ys, + struct ethtool_phc_vclocks_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_phc_vclocks_get_list); + yds.cb = ethtool_phc_vclocks_get_rsp_parse; + yds.rsp_cmd = 34; + yds.rsp_policy = ðtool_phc_vclocks_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PHC_VCLOCKS_GET, 1); + ys->req_policy = ðtool_phc_vclocks_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PHC_VCLOCKS_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_phc_vclocks_get_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_MODULE_GET ============== */ +/* ETHTOOL_MSG_MODULE_GET - do */ +void ethtool_module_get_req_free(struct ethtool_module_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_module_get_rsp_free(struct ethtool_module_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_module_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_module_get_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_MODULE_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_MODULE_POWER_MODE_POLICY) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.power_mode_policy = 1; + dst->power_mode_policy = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_MODULE_POWER_MODE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.power_mode = 1; + dst->power_mode = mnl_attr_get_u8(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_module_get_rsp * +ethtool_module_get(struct ynl_sock *ys, struct ethtool_module_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_module_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1); + ys->req_policy = ðtool_module_nest; + yrs.yarg.rsp_policy = ðtool_module_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_module_get_rsp_parse; + yrs.rsp_cmd = 35; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_module_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_MODULE_GET - dump */ +void ethtool_module_get_list_free(struct ethtool_module_get_list *rsp) +{ + struct ethtool_module_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_module_get_list * +ethtool_module_get_dump(struct ynl_sock *ys, + struct ethtool_module_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_module_get_list); + yds.cb = ethtool_module_get_rsp_parse; + yds.rsp_cmd = 35; + yds.rsp_policy = ðtool_module_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MODULE_GET, 1); + ys->req_policy = ðtool_module_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_module_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_MODULE_GET - notify */ +void ethtool_module_get_ntf_free(struct ethtool_module_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + free(rsp); +} + +/* ============== ETHTOOL_MSG_MODULE_SET ============== */ +/* ETHTOOL_MSG_MODULE_SET - do */ +void ethtool_module_set_req_free(struct ethtool_module_set_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_module_set(struct ynl_sock *ys, struct ethtool_module_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MODULE_SET, 1); + ys->req_policy = ðtool_module_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_MODULE_HEADER, &req->header); + if (req->_present.power_mode_policy) + mnl_attr_put_u8(nlh, ETHTOOL_A_MODULE_POWER_MODE_POLICY, req->power_mode_policy); + if (req->_present.power_mode) + mnl_attr_put_u8(nlh, ETHTOOL_A_MODULE_POWER_MODE, req->power_mode); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_PSE_GET ============== */ +/* ETHTOOL_MSG_PSE_GET - do */ +void ethtool_pse_get_req_free(struct ethtool_pse_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_pse_get_rsp_free(struct ethtool_pse_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_pse_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct ethtool_pse_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_PSE_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_PODL_PSE_ADMIN_STATE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.admin_state = 1; + dst->admin_state = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PODL_PSE_ADMIN_CONTROL) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.admin_control = 1; + dst->admin_control = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PODL_PSE_PW_D_STATUS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.pw_d_status = 1; + dst->pw_d_status = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_pse_get_rsp * +ethtool_pse_get(struct ynl_sock *ys, struct ethtool_pse_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_pse_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1); + ys->req_policy = ðtool_pse_nest; + yrs.yarg.rsp_policy = ðtool_pse_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_pse_get_rsp_parse; + yrs.rsp_cmd = 37; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_pse_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_PSE_GET - dump */ +void ethtool_pse_get_list_free(struct ethtool_pse_get_list *rsp) +{ + struct ethtool_pse_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_pse_get_list * +ethtool_pse_get_dump(struct ynl_sock *ys, struct ethtool_pse_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_pse_get_list); + yds.cb = ethtool_pse_get_rsp_parse; + yds.rsp_cmd = 37; + yds.rsp_policy = ðtool_pse_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PSE_GET, 1); + ys->req_policy = ðtool_pse_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_pse_get_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_PSE_SET ============== */ +/* ETHTOOL_MSG_PSE_SET - do */ +void ethtool_pse_set_req_free(struct ethtool_pse_set_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_pse_set(struct ynl_sock *ys, struct ethtool_pse_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PSE_SET, 1); + ys->req_policy = ðtool_pse_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PSE_HEADER, &req->header); + if (req->_present.admin_state) + mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_ADMIN_STATE, req->admin_state); + if (req->_present.admin_control) + mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_ADMIN_CONTROL, req->admin_control); + if (req->_present.pw_d_status) + mnl_attr_put_u32(nlh, ETHTOOL_A_PODL_PSE_PW_D_STATUS, req->pw_d_status); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_RSS_GET ============== */ +/* ETHTOOL_MSG_RSS_GET - do */ +void ethtool_rss_get_req_free(struct ethtool_rss_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_rss_get_rsp_free(struct ethtool_rss_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp->indir); + free(rsp->hkey); + free(rsp); +} + +int ethtool_rss_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct ethtool_rss_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_RSS_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_RSS_CONTEXT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.context = 1; + dst->context = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RSS_HFUNC) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.hfunc = 1; + dst->hfunc = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_RSS_INDIR) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.indir_len = len; + dst->indir = malloc(len); + memcpy(dst->indir, mnl_attr_get_payload(attr), len); + } else if (type == ETHTOOL_A_RSS_HKEY) { + unsigned int len; + + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + + len = mnl_attr_get_payload_len(attr); + dst->_present.hkey_len = len; + dst->hkey = malloc(len); + memcpy(dst->hkey, mnl_attr_get_payload(attr), len); + } + } + + return MNL_CB_OK; +} + +struct ethtool_rss_get_rsp * +ethtool_rss_get(struct ynl_sock *ys, struct ethtool_rss_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_rss_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1); + ys->req_policy = ðtool_rss_nest; + yrs.yarg.rsp_policy = ðtool_rss_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_RSS_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_rss_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_RSS_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_rss_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_RSS_GET - dump */ +void ethtool_rss_get_list_free(struct ethtool_rss_get_list *rsp) +{ + struct ethtool_rss_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp->obj.indir); + free(rsp->obj.hkey); + free(rsp); + } +} + +struct ethtool_rss_get_list * +ethtool_rss_get_dump(struct ynl_sock *ys, struct ethtool_rss_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_rss_get_list); + yds.cb = ethtool_rss_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_RSS_GET; + yds.rsp_policy = ðtool_rss_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_RSS_GET, 1); + ys->req_policy = ðtool_rss_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_RSS_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_rss_get_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_PLCA_GET_CFG ============== */ +/* ETHTOOL_MSG_PLCA_GET_CFG - do */ +void ethtool_plca_get_cfg_req_free(struct ethtool_plca_get_cfg_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_plca_get_cfg_rsp_free(struct ethtool_plca_get_cfg_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_plca_get_cfg_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_plca_get_cfg_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_PLCA_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_PLCA_VERSION) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.version = 1; + dst->version = mnl_attr_get_u16(attr); + } else if (type == ETHTOOL_A_PLCA_ENABLED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.enabled = 1; + dst->enabled = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_PLCA_STATUS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.status = 1; + dst->status = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_PLCA_NODE_CNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.node_cnt = 1; + dst->node_cnt = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PLCA_NODE_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.node_id = 1; + dst->node_id = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PLCA_TO_TMR) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.to_tmr = 1; + dst->to_tmr = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PLCA_BURST_CNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.burst_cnt = 1; + dst->burst_cnt = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PLCA_BURST_TMR) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.burst_tmr = 1; + dst->burst_tmr = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_plca_get_cfg_rsp * +ethtool_plca_get_cfg(struct ynl_sock *ys, struct ethtool_plca_get_cfg_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_plca_get_cfg_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1); + ys->req_policy = ðtool_plca_nest; + yrs.yarg.rsp_policy = ðtool_plca_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_plca_get_cfg_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_PLCA_GET_CFG; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_plca_get_cfg_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_PLCA_GET_CFG - dump */ +void ethtool_plca_get_cfg_list_free(struct ethtool_plca_get_cfg_list *rsp) +{ + struct ethtool_plca_get_cfg_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_plca_get_cfg_list * +ethtool_plca_get_cfg_dump(struct ynl_sock *ys, + struct ethtool_plca_get_cfg_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_plca_get_cfg_list); + yds.cb = ethtool_plca_get_cfg_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_PLCA_GET_CFG; + yds.rsp_policy = ðtool_plca_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_CFG, 1); + ys->req_policy = ðtool_plca_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_plca_get_cfg_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_PLCA_GET_CFG - notify */ +void ethtool_plca_get_cfg_ntf_free(struct ethtool_plca_get_cfg_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + free(rsp); +} + +/* ============== ETHTOOL_MSG_PLCA_SET_CFG ============== */ +/* ETHTOOL_MSG_PLCA_SET_CFG - do */ +void ethtool_plca_set_cfg_req_free(struct ethtool_plca_set_cfg_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_plca_set_cfg(struct ynl_sock *ys, + struct ethtool_plca_set_cfg_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_SET_CFG, 1); + ys->req_policy = ðtool_plca_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); + if (req->_present.version) + mnl_attr_put_u16(nlh, ETHTOOL_A_PLCA_VERSION, req->version); + if (req->_present.enabled) + mnl_attr_put_u8(nlh, ETHTOOL_A_PLCA_ENABLED, req->enabled); + if (req->_present.status) + mnl_attr_put_u8(nlh, ETHTOOL_A_PLCA_STATUS, req->status); + if (req->_present.node_cnt) + mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_NODE_CNT, req->node_cnt); + if (req->_present.node_id) + mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_NODE_ID, req->node_id); + if (req->_present.to_tmr) + mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_TO_TMR, req->to_tmr); + if (req->_present.burst_cnt) + mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_BURST_CNT, req->burst_cnt); + if (req->_present.burst_tmr) + mnl_attr_put_u32(nlh, ETHTOOL_A_PLCA_BURST_TMR, req->burst_tmr); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ============== ETHTOOL_MSG_PLCA_GET_STATUS ============== */ +/* ETHTOOL_MSG_PLCA_GET_STATUS - do */ +void ethtool_plca_get_status_req_free(struct ethtool_plca_get_status_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_plca_get_status_rsp_free(struct ethtool_plca_get_status_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + free(rsp); +} + +int ethtool_plca_get_status_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_plca_get_status_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_PLCA_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_PLCA_VERSION) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.version = 1; + dst->version = mnl_attr_get_u16(attr); + } else if (type == ETHTOOL_A_PLCA_ENABLED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.enabled = 1; + dst->enabled = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_PLCA_STATUS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.status = 1; + dst->status = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_PLCA_NODE_CNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.node_cnt = 1; + dst->node_cnt = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PLCA_NODE_ID) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.node_id = 1; + dst->node_id = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PLCA_TO_TMR) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.to_tmr = 1; + dst->to_tmr = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PLCA_BURST_CNT) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.burst_cnt = 1; + dst->burst_cnt = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_PLCA_BURST_TMR) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.burst_tmr = 1; + dst->burst_tmr = mnl_attr_get_u32(attr); + } + } + + return MNL_CB_OK; +} + +struct ethtool_plca_get_status_rsp * +ethtool_plca_get_status(struct ynl_sock *ys, + struct ethtool_plca_get_status_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_plca_get_status_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1); + ys->req_policy = ðtool_plca_nest; + yrs.yarg.rsp_policy = ðtool_plca_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_plca_get_status_rsp_parse; + yrs.rsp_cmd = 40; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_plca_get_status_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_PLCA_GET_STATUS - dump */ +void +ethtool_plca_get_status_list_free(struct ethtool_plca_get_status_list *rsp) +{ + struct ethtool_plca_get_status_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + free(rsp); + } +} + +struct ethtool_plca_get_status_list * +ethtool_plca_get_status_dump(struct ynl_sock *ys, + struct ethtool_plca_get_status_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_plca_get_status_list); + yds.cb = ethtool_plca_get_status_rsp_parse; + yds.rsp_cmd = 40; + yds.rsp_policy = ðtool_plca_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_PLCA_GET_STATUS, 1); + ys->req_policy = ðtool_plca_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_PLCA_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_plca_get_status_list_free(yds.first); + return NULL; +} + +/* ============== ETHTOOL_MSG_MM_GET ============== */ +/* ETHTOOL_MSG_MM_GET - do */ +void ethtool_mm_get_req_free(struct ethtool_mm_get_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +void ethtool_mm_get_rsp_free(struct ethtool_mm_get_rsp *rsp) +{ + ethtool_header_free(&rsp->header); + ethtool_mm_stat_free(&rsp->stats); + free(rsp); +} + +int ethtool_mm_get_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ynl_parse_arg *yarg = data; + struct ethtool_mm_get_rsp *dst; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_MM_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_MM_PMAC_ENABLED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.pmac_enabled = 1; + dst->pmac_enabled = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_MM_TX_ENABLED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_enabled = 1; + dst->tx_enabled = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_MM_TX_ACTIVE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_active = 1; + dst->tx_active = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_MM_TX_MIN_FRAG_SIZE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.tx_min_frag_size = 1; + dst->tx_min_frag_size = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_MM_RX_MIN_FRAG_SIZE) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.rx_min_frag_size = 1; + dst->rx_min_frag_size = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_MM_VERIFY_ENABLED) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.verify_enabled = 1; + dst->verify_enabled = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_MM_VERIFY_TIME) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.verify_time = 1; + dst->verify_time = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_MM_MAX_VERIFY_TIME) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.max_verify_time = 1; + dst->max_verify_time = mnl_attr_get_u32(attr); + } else if (type == ETHTOOL_A_MM_STATS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.stats = 1; + + parg.rsp_policy = ðtool_mm_stat_nest; + parg.data = &dst->stats; + if (ethtool_mm_stat_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +struct ethtool_mm_get_rsp * +ethtool_mm_get(struct ynl_sock *ys, struct ethtool_mm_get_req *req) +{ + struct ynl_req_state yrs = { .yarg = { .ys = ys, }, }; + struct ethtool_mm_get_rsp *rsp; + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1); + ys->req_policy = ðtool_mm_nest; + yrs.yarg.rsp_policy = ðtool_mm_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); + + rsp = calloc(1, sizeof(*rsp)); + yrs.yarg.data = rsp; + yrs.cb = ethtool_mm_get_rsp_parse; + yrs.rsp_cmd = ETHTOOL_MSG_MM_GET; + + err = ynl_exec(ys, nlh, &yrs); + if (err < 0) + goto err_free; + + return rsp; + +err_free: + ethtool_mm_get_rsp_free(rsp); + return NULL; +} + +/* ETHTOOL_MSG_MM_GET - dump */ +void ethtool_mm_get_list_free(struct ethtool_mm_get_list *rsp) +{ + struct ethtool_mm_get_list *next = rsp; + + while ((void *)next != YNL_LIST_END) { + rsp = next; + next = rsp->next; + + ethtool_header_free(&rsp->obj.header); + ethtool_mm_stat_free(&rsp->obj.stats); + free(rsp); + } +} + +struct ethtool_mm_get_list * +ethtool_mm_get_dump(struct ynl_sock *ys, struct ethtool_mm_get_req_dump *req) +{ + struct ynl_dump_state yds = {}; + struct nlmsghdr *nlh; + int err; + + yds.ys = ys; + yds.alloc_sz = sizeof(struct ethtool_mm_get_list); + yds.cb = ethtool_mm_get_rsp_parse; + yds.rsp_cmd = ETHTOOL_MSG_MM_GET; + yds.rsp_policy = ðtool_mm_nest; + + nlh = ynl_gemsg_start_dump(ys, ys->family_id, ETHTOOL_MSG_MM_GET, 1); + ys->req_policy = ðtool_mm_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); + + err = ynl_exec_dump(ys, nlh, &yds); + if (err < 0) + goto free_list; + + return yds.first; + +free_list: + ethtool_mm_get_list_free(yds.first); + return NULL; +} + +/* ETHTOOL_MSG_MM_GET - notify */ +void ethtool_mm_get_ntf_free(struct ethtool_mm_get_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_mm_stat_free(&rsp->obj.stats); + free(rsp); +} + +/* ============== ETHTOOL_MSG_MM_SET ============== */ +/* ETHTOOL_MSG_MM_SET - do */ +void ethtool_mm_set_req_free(struct ethtool_mm_set_req *req) +{ + ethtool_header_free(&req->header); + free(req); +} + +int ethtool_mm_set(struct ynl_sock *ys, struct ethtool_mm_set_req *req) +{ + struct nlmsghdr *nlh; + int err; + + nlh = ynl_gemsg_start_req(ys, ys->family_id, ETHTOOL_MSG_MM_SET, 1); + ys->req_policy = ðtool_mm_nest; + + if (req->_present.header) + ethtool_header_put(nlh, ETHTOOL_A_MM_HEADER, &req->header); + if (req->_present.verify_enabled) + mnl_attr_put_u8(nlh, ETHTOOL_A_MM_VERIFY_ENABLED, req->verify_enabled); + if (req->_present.verify_time) + mnl_attr_put_u32(nlh, ETHTOOL_A_MM_VERIFY_TIME, req->verify_time); + if (req->_present.tx_enabled) + mnl_attr_put_u8(nlh, ETHTOOL_A_MM_TX_ENABLED, req->tx_enabled); + if (req->_present.pmac_enabled) + mnl_attr_put_u8(nlh, ETHTOOL_A_MM_PMAC_ENABLED, req->pmac_enabled); + if (req->_present.tx_min_frag_size) + mnl_attr_put_u32(nlh, ETHTOOL_A_MM_TX_MIN_FRAG_SIZE, req->tx_min_frag_size); + + err = ynl_exec(ys, nlh, NULL); + if (err < 0) + return -1; + + return 0; +} + +/* ETHTOOL_MSG_CABLE_TEST_NTF - event */ +int ethtool_cable_test_ntf_rsp_parse(const struct nlmsghdr *nlh, void *data) +{ + struct ethtool_cable_test_ntf_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_CABLE_TEST_NTF_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_CABLE_TEST_NTF_STATUS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.status = 1; + dst->status = mnl_attr_get_u8(attr); + } + } + + return MNL_CB_OK; +} + +void ethtool_cable_test_ntf_free(struct ethtool_cable_test_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + free(rsp); +} + +/* ETHTOOL_MSG_CABLE_TEST_TDR_NTF - event */ +int ethtool_cable_test_tdr_ntf_rsp_parse(const struct nlmsghdr *nlh, + void *data) +{ + struct ethtool_cable_test_tdr_ntf_rsp *dst; + struct ynl_parse_arg *yarg = data; + const struct nlattr *attr; + struct ynl_parse_arg parg; + + dst = yarg->data; + parg.ys = yarg->ys; + + mnl_attr_for_each(attr, nlh, sizeof(struct genlmsghdr)) { + unsigned int type = mnl_attr_get_type(attr); + + if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_HEADER) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.header = 1; + + parg.rsp_policy = ðtool_header_nest; + parg.data = &dst->header; + if (ethtool_header_parse(&parg, attr)) + return MNL_CB_ERROR; + } else if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_STATUS) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.status = 1; + dst->status = mnl_attr_get_u8(attr); + } else if (type == ETHTOOL_A_CABLE_TEST_TDR_NTF_NEST) { + if (ynl_attr_validate(yarg, attr)) + return MNL_CB_ERROR; + dst->_present.nest = 1; + + parg.rsp_policy = ðtool_cable_nest_nest; + parg.data = &dst->nest; + if (ethtool_cable_nest_parse(&parg, attr)) + return MNL_CB_ERROR; + } + } + + return MNL_CB_OK; +} + +void ethtool_cable_test_tdr_ntf_free(struct ethtool_cable_test_tdr_ntf *rsp) +{ + ethtool_header_free(&rsp->obj.header); + ethtool_cable_nest_free(&rsp->obj.nest); + free(rsp); +} + +static const struct ynl_ntf_info ethtool_ntf_info[] = { + [ETHTOOL_MSG_LINKINFO_NTF] = { + .alloc_sz = sizeof(struct ethtool_linkinfo_get_ntf), + .cb = ethtool_linkinfo_get_rsp_parse, + .policy = ðtool_linkinfo_nest, + .free = (void *)ethtool_linkinfo_get_ntf_free, + }, + [ETHTOOL_MSG_LINKMODES_NTF] = { + .alloc_sz = sizeof(struct ethtool_linkmodes_get_ntf), + .cb = ethtool_linkmodes_get_rsp_parse, + .policy = ðtool_linkmodes_nest, + .free = (void *)ethtool_linkmodes_get_ntf_free, + }, + [ETHTOOL_MSG_DEBUG_NTF] = { + .alloc_sz = sizeof(struct ethtool_debug_get_ntf), + .cb = ethtool_debug_get_rsp_parse, + .policy = ðtool_debug_nest, + .free = (void *)ethtool_debug_get_ntf_free, + }, + [ETHTOOL_MSG_WOL_NTF] = { + .alloc_sz = sizeof(struct ethtool_wol_get_ntf), + .cb = ethtool_wol_get_rsp_parse, + .policy = ðtool_wol_nest, + .free = (void *)ethtool_wol_get_ntf_free, + }, + [ETHTOOL_MSG_FEATURES_NTF] = { + .alloc_sz = sizeof(struct ethtool_features_get_ntf), + .cb = ethtool_features_get_rsp_parse, + .policy = ðtool_features_nest, + .free = (void *)ethtool_features_get_ntf_free, + }, + [ETHTOOL_MSG_PRIVFLAGS_NTF] = { + .alloc_sz = sizeof(struct ethtool_privflags_get_ntf), + .cb = ethtool_privflags_get_rsp_parse, + .policy = ðtool_privflags_nest, + .free = (void *)ethtool_privflags_get_ntf_free, + }, + [ETHTOOL_MSG_RINGS_NTF] = { + .alloc_sz = sizeof(struct ethtool_rings_get_ntf), + .cb = ethtool_rings_get_rsp_parse, + .policy = ðtool_rings_nest, + .free = (void *)ethtool_rings_get_ntf_free, + }, + [ETHTOOL_MSG_CHANNELS_NTF] = { + .alloc_sz = sizeof(struct ethtool_channels_get_ntf), + .cb = ethtool_channels_get_rsp_parse, + .policy = ðtool_channels_nest, + .free = (void *)ethtool_channels_get_ntf_free, + }, + [ETHTOOL_MSG_COALESCE_NTF] = { + .alloc_sz = sizeof(struct ethtool_coalesce_get_ntf), + .cb = ethtool_coalesce_get_rsp_parse, + .policy = ðtool_coalesce_nest, + .free = (void *)ethtool_coalesce_get_ntf_free, + }, + [ETHTOOL_MSG_PAUSE_NTF] = { + .alloc_sz = sizeof(struct ethtool_pause_get_ntf), + .cb = ethtool_pause_get_rsp_parse, + .policy = ðtool_pause_nest, + .free = (void *)ethtool_pause_get_ntf_free, + }, + [ETHTOOL_MSG_EEE_NTF] = { + .alloc_sz = sizeof(struct ethtool_eee_get_ntf), + .cb = ethtool_eee_get_rsp_parse, + .policy = ðtool_eee_nest, + .free = (void *)ethtool_eee_get_ntf_free, + }, + [ETHTOOL_MSG_CABLE_TEST_NTF] = { + .alloc_sz = sizeof(struct ethtool_cable_test_ntf), + .cb = ethtool_cable_test_ntf_rsp_parse, + .policy = ðtool_cable_test_ntf_nest, + .free = (void *)ethtool_cable_test_ntf_free, + }, + [ETHTOOL_MSG_CABLE_TEST_TDR_NTF] = { + .alloc_sz = sizeof(struct ethtool_cable_test_tdr_ntf), + .cb = ethtool_cable_test_tdr_ntf_rsp_parse, + .policy = ðtool_cable_test_tdr_ntf_nest, + .free = (void *)ethtool_cable_test_tdr_ntf_free, + }, + [ETHTOOL_MSG_FEC_NTF] = { + .alloc_sz = sizeof(struct ethtool_fec_get_ntf), + .cb = ethtool_fec_get_rsp_parse, + .policy = ðtool_fec_nest, + .free = (void *)ethtool_fec_get_ntf_free, + }, + [ETHTOOL_MSG_MODULE_NTF] = { + .alloc_sz = sizeof(struct ethtool_module_get_ntf), + .cb = ethtool_module_get_rsp_parse, + .policy = ðtool_module_nest, + .free = (void *)ethtool_module_get_ntf_free, + }, + [ETHTOOL_MSG_PLCA_NTF] = { + .alloc_sz = sizeof(struct ethtool_plca_get_cfg_ntf), + .cb = ethtool_plca_get_cfg_rsp_parse, + .policy = ðtool_plca_nest, + .free = (void *)ethtool_plca_get_cfg_ntf_free, + }, + [ETHTOOL_MSG_MM_NTF] = { + .alloc_sz = sizeof(struct ethtool_mm_get_ntf), + .cb = ethtool_mm_get_rsp_parse, + .policy = ðtool_mm_nest, + .free = (void *)ethtool_mm_get_ntf_free, + }, +}; + +const struct ynl_family ynl_ethtool_family = { + .name = "ethtool", + .ntf_info = ethtool_ntf_info, + .ntf_info_size = MNL_ARRAY_SIZE(ethtool_ntf_info), +}; diff --git a/tools/net/ynl/generated/ethtool-user.h b/tools/net/ynl/generated/ethtool-user.h new file mode 100644 index 000000000000..d7d4ba855f43 --- /dev/null +++ b/tools/net/ynl/generated/ethtool-user.h @@ -0,0 +1,5531 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/ethtool.yaml */ +/* YNL-GEN user header */ +/* YNL-ARG --user-header linux/ethtool_netlink.h --exclude-op stats-get */ + +#ifndef _LINUX_ETHTOOL_GEN_H +#define _LINUX_ETHTOOL_GEN_H + +#include +#include +#include +#include + +struct ynl_sock; + +extern const struct ynl_family ynl_ethtool_family; + +/* Enums */ +const char *ethtool_op_str(int op); +const char *ethtool_udp_tunnel_type_str(int value); +const char *ethtool_stringset_str(enum ethtool_stringset value); + +/* Common nested types */ +struct ethtool_header { + struct { + __u32 dev_index:1; + __u32 dev_name_len; + __u32 flags:1; + } _present; + + __u32 dev_index; + char *dev_name; + __u32 flags; +}; + +struct ethtool_pause_stat { + struct { + __u32 tx_frames:1; + __u32 rx_frames:1; + } _present; + + __u64 tx_frames; + __u64 rx_frames; +}; + +struct ethtool_cable_test_tdr_cfg { + struct { + __u32 first:1; + __u32 last:1; + __u32 step:1; + __u32 pair:1; + } _present; + + __u32 first; + __u32 last; + __u32 step; + __u8 pair; +}; + +struct ethtool_fec_stat { + struct { + __u32 corrected_len; + __u32 uncorr_len; + __u32 corr_bits_len; + } _present; + + void *corrected; + void *uncorr; + void *corr_bits; +}; + +struct ethtool_mm_stat { + struct { + __u32 reassembly_errors:1; + __u32 smd_errors:1; + __u32 reassembly_ok:1; + __u32 rx_frag_count:1; + __u32 tx_frag_count:1; + __u32 hold_count:1; + } _present; + + __u64 reassembly_errors; + __u64 smd_errors; + __u64 reassembly_ok; + __u64 rx_frag_count; + __u64 tx_frag_count; + __u64 hold_count; +}; + +struct ethtool_cable_result { + struct { + __u32 pair:1; + __u32 code:1; + } _present; + + __u8 pair; + __u8 code; +}; + +struct ethtool_cable_fault_length { + struct { + __u32 pair:1; + __u32 cm:1; + } _present; + + __u8 pair; + __u32 cm; +}; + +struct ethtool_bitset_bit { + struct { + __u32 index:1; + __u32 name_len; + __u32 value:1; + } _present; + + __u32 index; + char *name; +}; + +struct ethtool_tunnel_udp_entry { + struct { + __u32 port:1; + __u32 type:1; + } _present; + + __u16 port /* big-endian */; + __u32 type; +}; + +struct ethtool_string { + struct { + __u32 index:1; + __u32 value_len; + } _present; + + __u32 index; + char *value; +}; + +struct ethtool_cable_nest { + struct { + __u32 result:1; + __u32 fault_length:1; + } _present; + + struct ethtool_cable_result result; + struct ethtool_cable_fault_length fault_length; +}; + +struct ethtool_bitset_bits { + unsigned int n_bit; + struct ethtool_bitset_bit *bit; +}; + +struct ethtool_strings { + unsigned int n_string; + struct ethtool_string *string; +}; + +struct ethtool_bitset { + struct { + __u32 nomask:1; + __u32 size:1; + __u32 bits:1; + } _present; + + __u32 size; + struct ethtool_bitset_bits bits; +}; + +struct ethtool_stringset_ { + struct { + __u32 id:1; + __u32 count:1; + } _present; + + __u32 id; + __u32 count; + unsigned int n_strings; + struct ethtool_strings *strings; +}; + +struct ethtool_tunnel_udp_table { + struct { + __u32 size:1; + __u32 types:1; + } _present; + + __u32 size; + struct ethtool_bitset types; + unsigned int n_entry; + struct ethtool_tunnel_udp_entry *entry; +}; + +struct ethtool_stringsets { + unsigned int n_stringset; + struct ethtool_stringset_ *stringset; +}; + +struct ethtool_tunnel_udp { + struct { + __u32 table:1; + } _present; + + struct ethtool_tunnel_udp_table table; +}; + +/* ============== ETHTOOL_MSG_STRSET_GET ============== */ +/* ETHTOOL_MSG_STRSET_GET - do */ +struct ethtool_strset_get_req { + struct { + __u32 header:1; + __u32 stringsets:1; + __u32 counts_only:1; + } _present; + + struct ethtool_header header; + struct ethtool_stringsets stringsets; +}; + +static inline struct ethtool_strset_get_req *ethtool_strset_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_strset_get_req)); +} +void ethtool_strset_get_req_free(struct ethtool_strset_get_req *req); + +static inline void +ethtool_strset_get_req_set_header_dev_index(struct ethtool_strset_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_strset_get_req_set_header_dev_name(struct ethtool_strset_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_strset_get_req_set_header_flags(struct ethtool_strset_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +__ethtool_strset_get_req_set_stringsets_stringset(struct ethtool_strset_get_req *req, + struct ethtool_stringset_ *stringset, + unsigned int n_stringset) +{ + free(req->stringsets.stringset); + req->stringsets.stringset = stringset; + req->stringsets.n_stringset = n_stringset; +} +static inline void +ethtool_strset_get_req_set_counts_only(struct ethtool_strset_get_req *req) +{ + req->_present.counts_only = 1; +} + +struct ethtool_strset_get_rsp { + struct { + __u32 header:1; + __u32 stringsets:1; + } _present; + + struct ethtool_header header; + struct ethtool_stringsets stringsets; +}; + +void ethtool_strset_get_rsp_free(struct ethtool_strset_get_rsp *rsp); + +/* + * Get string set from the kernel. + */ +struct ethtool_strset_get_rsp * +ethtool_strset_get(struct ynl_sock *ys, struct ethtool_strset_get_req *req); + +/* ETHTOOL_MSG_STRSET_GET - dump */ +struct ethtool_strset_get_req_dump { + struct { + __u32 header:1; + __u32 stringsets:1; + __u32 counts_only:1; + } _present; + + struct ethtool_header header; + struct ethtool_stringsets stringsets; +}; + +static inline struct ethtool_strset_get_req_dump * +ethtool_strset_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_strset_get_req_dump)); +} +void ethtool_strset_get_req_dump_free(struct ethtool_strset_get_req_dump *req); + +static inline void +ethtool_strset_get_req_dump_set_header_dev_index(struct ethtool_strset_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_strset_get_req_dump_set_header_dev_name(struct ethtool_strset_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_strset_get_req_dump_set_header_flags(struct ethtool_strset_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +__ethtool_strset_get_req_dump_set_stringsets_stringset(struct ethtool_strset_get_req_dump *req, + struct ethtool_stringset_ *stringset, + unsigned int n_stringset) +{ + free(req->stringsets.stringset); + req->stringsets.stringset = stringset; + req->stringsets.n_stringset = n_stringset; +} +static inline void +ethtool_strset_get_req_dump_set_counts_only(struct ethtool_strset_get_req_dump *req) +{ + req->_present.counts_only = 1; +} + +struct ethtool_strset_get_list { + struct ethtool_strset_get_list *next; + struct ethtool_strset_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_strset_get_list_free(struct ethtool_strset_get_list *rsp); + +struct ethtool_strset_get_list * +ethtool_strset_get_dump(struct ynl_sock *ys, + struct ethtool_strset_get_req_dump *req); + +/* ============== ETHTOOL_MSG_LINKINFO_GET ============== */ +/* ETHTOOL_MSG_LINKINFO_GET - do */ +struct ethtool_linkinfo_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_linkinfo_get_req * +ethtool_linkinfo_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_linkinfo_get_req)); +} +void ethtool_linkinfo_get_req_free(struct ethtool_linkinfo_get_req *req); + +static inline void +ethtool_linkinfo_get_req_set_header_dev_index(struct ethtool_linkinfo_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_linkinfo_get_req_set_header_dev_name(struct ethtool_linkinfo_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_linkinfo_get_req_set_header_flags(struct ethtool_linkinfo_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_linkinfo_get_rsp { + struct { + __u32 header:1; + __u32 port:1; + __u32 phyaddr:1; + __u32 tp_mdix:1; + __u32 tp_mdix_ctrl:1; + __u32 transceiver:1; + } _present; + + struct ethtool_header header; + __u8 port; + __u8 phyaddr; + __u8 tp_mdix; + __u8 tp_mdix_ctrl; + __u8 transceiver; +}; + +void ethtool_linkinfo_get_rsp_free(struct ethtool_linkinfo_get_rsp *rsp); + +/* + * Get link info. + */ +struct ethtool_linkinfo_get_rsp * +ethtool_linkinfo_get(struct ynl_sock *ys, struct ethtool_linkinfo_get_req *req); + +/* ETHTOOL_MSG_LINKINFO_GET - dump */ +struct ethtool_linkinfo_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_linkinfo_get_req_dump * +ethtool_linkinfo_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_linkinfo_get_req_dump)); +} +void +ethtool_linkinfo_get_req_dump_free(struct ethtool_linkinfo_get_req_dump *req); + +static inline void +ethtool_linkinfo_get_req_dump_set_header_dev_index(struct ethtool_linkinfo_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_linkinfo_get_req_dump_set_header_dev_name(struct ethtool_linkinfo_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_linkinfo_get_req_dump_set_header_flags(struct ethtool_linkinfo_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_linkinfo_get_list { + struct ethtool_linkinfo_get_list *next; + struct ethtool_linkinfo_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_linkinfo_get_list_free(struct ethtool_linkinfo_get_list *rsp); + +struct ethtool_linkinfo_get_list * +ethtool_linkinfo_get_dump(struct ynl_sock *ys, + struct ethtool_linkinfo_get_req_dump *req); + +/* ETHTOOL_MSG_LINKINFO_GET - notify */ +struct ethtool_linkinfo_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_linkinfo_get_ntf *ntf); + struct ethtool_linkinfo_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_linkinfo_get_ntf_free(struct ethtool_linkinfo_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_LINKINFO_SET ============== */ +/* ETHTOOL_MSG_LINKINFO_SET - do */ +struct ethtool_linkinfo_set_req { + struct { + __u32 header:1; + __u32 port:1; + __u32 phyaddr:1; + __u32 tp_mdix:1; + __u32 tp_mdix_ctrl:1; + __u32 transceiver:1; + } _present; + + struct ethtool_header header; + __u8 port; + __u8 phyaddr; + __u8 tp_mdix; + __u8 tp_mdix_ctrl; + __u8 transceiver; +}; + +static inline struct ethtool_linkinfo_set_req * +ethtool_linkinfo_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_linkinfo_set_req)); +} +void ethtool_linkinfo_set_req_free(struct ethtool_linkinfo_set_req *req); + +static inline void +ethtool_linkinfo_set_req_set_header_dev_index(struct ethtool_linkinfo_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_linkinfo_set_req_set_header_dev_name(struct ethtool_linkinfo_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_linkinfo_set_req_set_header_flags(struct ethtool_linkinfo_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_linkinfo_set_req_set_port(struct ethtool_linkinfo_set_req *req, + __u8 port) +{ + req->_present.port = 1; + req->port = port; +} +static inline void +ethtool_linkinfo_set_req_set_phyaddr(struct ethtool_linkinfo_set_req *req, + __u8 phyaddr) +{ + req->_present.phyaddr = 1; + req->phyaddr = phyaddr; +} +static inline void +ethtool_linkinfo_set_req_set_tp_mdix(struct ethtool_linkinfo_set_req *req, + __u8 tp_mdix) +{ + req->_present.tp_mdix = 1; + req->tp_mdix = tp_mdix; +} +static inline void +ethtool_linkinfo_set_req_set_tp_mdix_ctrl(struct ethtool_linkinfo_set_req *req, + __u8 tp_mdix_ctrl) +{ + req->_present.tp_mdix_ctrl = 1; + req->tp_mdix_ctrl = tp_mdix_ctrl; +} +static inline void +ethtool_linkinfo_set_req_set_transceiver(struct ethtool_linkinfo_set_req *req, + __u8 transceiver) +{ + req->_present.transceiver = 1; + req->transceiver = transceiver; +} + +/* + * Set link info. + */ +int ethtool_linkinfo_set(struct ynl_sock *ys, + struct ethtool_linkinfo_set_req *req); + +/* ============== ETHTOOL_MSG_LINKMODES_GET ============== */ +/* ETHTOOL_MSG_LINKMODES_GET - do */ +struct ethtool_linkmodes_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_linkmodes_get_req * +ethtool_linkmodes_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_linkmodes_get_req)); +} +void ethtool_linkmodes_get_req_free(struct ethtool_linkmodes_get_req *req); + +static inline void +ethtool_linkmodes_get_req_set_header_dev_index(struct ethtool_linkmodes_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_linkmodes_get_req_set_header_dev_name(struct ethtool_linkmodes_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_linkmodes_get_req_set_header_flags(struct ethtool_linkmodes_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_linkmodes_get_rsp { + struct { + __u32 header:1; + __u32 autoneg:1; + __u32 ours:1; + __u32 peer:1; + __u32 speed:1; + __u32 duplex:1; + __u32 master_slave_cfg:1; + __u32 master_slave_state:1; + __u32 lanes:1; + __u32 rate_matching:1; + } _present; + + struct ethtool_header header; + __u8 autoneg; + struct ethtool_bitset ours; + struct ethtool_bitset peer; + __u32 speed; + __u8 duplex; + __u8 master_slave_cfg; + __u8 master_slave_state; + __u32 lanes; + __u8 rate_matching; +}; + +void ethtool_linkmodes_get_rsp_free(struct ethtool_linkmodes_get_rsp *rsp); + +/* + * Get link modes. + */ +struct ethtool_linkmodes_get_rsp * +ethtool_linkmodes_get(struct ynl_sock *ys, + struct ethtool_linkmodes_get_req *req); + +/* ETHTOOL_MSG_LINKMODES_GET - dump */ +struct ethtool_linkmodes_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_linkmodes_get_req_dump * +ethtool_linkmodes_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_linkmodes_get_req_dump)); +} +void +ethtool_linkmodes_get_req_dump_free(struct ethtool_linkmodes_get_req_dump *req); + +static inline void +ethtool_linkmodes_get_req_dump_set_header_dev_index(struct ethtool_linkmodes_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_linkmodes_get_req_dump_set_header_dev_name(struct ethtool_linkmodes_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_linkmodes_get_req_dump_set_header_flags(struct ethtool_linkmodes_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_linkmodes_get_list { + struct ethtool_linkmodes_get_list *next; + struct ethtool_linkmodes_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_linkmodes_get_list_free(struct ethtool_linkmodes_get_list *rsp); + +struct ethtool_linkmodes_get_list * +ethtool_linkmodes_get_dump(struct ynl_sock *ys, + struct ethtool_linkmodes_get_req_dump *req); + +/* ETHTOOL_MSG_LINKMODES_GET - notify */ +struct ethtool_linkmodes_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_linkmodes_get_ntf *ntf); + struct ethtool_linkmodes_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_linkmodes_get_ntf_free(struct ethtool_linkmodes_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_LINKMODES_SET ============== */ +/* ETHTOOL_MSG_LINKMODES_SET - do */ +struct ethtool_linkmodes_set_req { + struct { + __u32 header:1; + __u32 autoneg:1; + __u32 ours:1; + __u32 peer:1; + __u32 speed:1; + __u32 duplex:1; + __u32 master_slave_cfg:1; + __u32 master_slave_state:1; + __u32 lanes:1; + __u32 rate_matching:1; + } _present; + + struct ethtool_header header; + __u8 autoneg; + struct ethtool_bitset ours; + struct ethtool_bitset peer; + __u32 speed; + __u8 duplex; + __u8 master_slave_cfg; + __u8 master_slave_state; + __u32 lanes; + __u8 rate_matching; +}; + +static inline struct ethtool_linkmodes_set_req * +ethtool_linkmodes_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_linkmodes_set_req)); +} +void ethtool_linkmodes_set_req_free(struct ethtool_linkmodes_set_req *req); + +static inline void +ethtool_linkmodes_set_req_set_header_dev_index(struct ethtool_linkmodes_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_linkmodes_set_req_set_header_dev_name(struct ethtool_linkmodes_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_linkmodes_set_req_set_header_flags(struct ethtool_linkmodes_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_linkmodes_set_req_set_autoneg(struct ethtool_linkmodes_set_req *req, + __u8 autoneg) +{ + req->_present.autoneg = 1; + req->autoneg = autoneg; +} +static inline void +ethtool_linkmodes_set_req_set_ours_nomask(struct ethtool_linkmodes_set_req *req) +{ + req->_present.ours = 1; + req->ours._present.nomask = 1; +} +static inline void +ethtool_linkmodes_set_req_set_ours_size(struct ethtool_linkmodes_set_req *req, + __u32 size) +{ + req->_present.ours = 1; + req->ours._present.size = 1; + req->ours.size = size; +} +static inline void +__ethtool_linkmodes_set_req_set_ours_bits_bit(struct ethtool_linkmodes_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->ours.bits.bit); + req->ours.bits.bit = bit; + req->ours.bits.n_bit = n_bit; +} +static inline void +ethtool_linkmodes_set_req_set_peer_nomask(struct ethtool_linkmodes_set_req *req) +{ + req->_present.peer = 1; + req->peer._present.nomask = 1; +} +static inline void +ethtool_linkmodes_set_req_set_peer_size(struct ethtool_linkmodes_set_req *req, + __u32 size) +{ + req->_present.peer = 1; + req->peer._present.size = 1; + req->peer.size = size; +} +static inline void +__ethtool_linkmodes_set_req_set_peer_bits_bit(struct ethtool_linkmodes_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->peer.bits.bit); + req->peer.bits.bit = bit; + req->peer.bits.n_bit = n_bit; +} +static inline void +ethtool_linkmodes_set_req_set_speed(struct ethtool_linkmodes_set_req *req, + __u32 speed) +{ + req->_present.speed = 1; + req->speed = speed; +} +static inline void +ethtool_linkmodes_set_req_set_duplex(struct ethtool_linkmodes_set_req *req, + __u8 duplex) +{ + req->_present.duplex = 1; + req->duplex = duplex; +} +static inline void +ethtool_linkmodes_set_req_set_master_slave_cfg(struct ethtool_linkmodes_set_req *req, + __u8 master_slave_cfg) +{ + req->_present.master_slave_cfg = 1; + req->master_slave_cfg = master_slave_cfg; +} +static inline void +ethtool_linkmodes_set_req_set_master_slave_state(struct ethtool_linkmodes_set_req *req, + __u8 master_slave_state) +{ + req->_present.master_slave_state = 1; + req->master_slave_state = master_slave_state; +} +static inline void +ethtool_linkmodes_set_req_set_lanes(struct ethtool_linkmodes_set_req *req, + __u32 lanes) +{ + req->_present.lanes = 1; + req->lanes = lanes; +} +static inline void +ethtool_linkmodes_set_req_set_rate_matching(struct ethtool_linkmodes_set_req *req, + __u8 rate_matching) +{ + req->_present.rate_matching = 1; + req->rate_matching = rate_matching; +} + +/* + * Set link modes. + */ +int ethtool_linkmodes_set(struct ynl_sock *ys, + struct ethtool_linkmodes_set_req *req); + +/* ============== ETHTOOL_MSG_LINKSTATE_GET ============== */ +/* ETHTOOL_MSG_LINKSTATE_GET - do */ +struct ethtool_linkstate_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_linkstate_get_req * +ethtool_linkstate_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_linkstate_get_req)); +} +void ethtool_linkstate_get_req_free(struct ethtool_linkstate_get_req *req); + +static inline void +ethtool_linkstate_get_req_set_header_dev_index(struct ethtool_linkstate_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_linkstate_get_req_set_header_dev_name(struct ethtool_linkstate_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_linkstate_get_req_set_header_flags(struct ethtool_linkstate_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_linkstate_get_rsp { + struct { + __u32 header:1; + __u32 link:1; + __u32 sqi:1; + __u32 sqi_max:1; + __u32 ext_state:1; + __u32 ext_substate:1; + __u32 ext_down_cnt:1; + } _present; + + struct ethtool_header header; + __u8 link; + __u32 sqi; + __u32 sqi_max; + __u8 ext_state; + __u8 ext_substate; + __u32 ext_down_cnt; +}; + +void ethtool_linkstate_get_rsp_free(struct ethtool_linkstate_get_rsp *rsp); + +/* + * Get link state. + */ +struct ethtool_linkstate_get_rsp * +ethtool_linkstate_get(struct ynl_sock *ys, + struct ethtool_linkstate_get_req *req); + +/* ETHTOOL_MSG_LINKSTATE_GET - dump */ +struct ethtool_linkstate_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_linkstate_get_req_dump * +ethtool_linkstate_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_linkstate_get_req_dump)); +} +void +ethtool_linkstate_get_req_dump_free(struct ethtool_linkstate_get_req_dump *req); + +static inline void +ethtool_linkstate_get_req_dump_set_header_dev_index(struct ethtool_linkstate_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_linkstate_get_req_dump_set_header_dev_name(struct ethtool_linkstate_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_linkstate_get_req_dump_set_header_flags(struct ethtool_linkstate_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_linkstate_get_list { + struct ethtool_linkstate_get_list *next; + struct ethtool_linkstate_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_linkstate_get_list_free(struct ethtool_linkstate_get_list *rsp); + +struct ethtool_linkstate_get_list * +ethtool_linkstate_get_dump(struct ynl_sock *ys, + struct ethtool_linkstate_get_req_dump *req); + +/* ============== ETHTOOL_MSG_DEBUG_GET ============== */ +/* ETHTOOL_MSG_DEBUG_GET - do */ +struct ethtool_debug_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_debug_get_req *ethtool_debug_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_debug_get_req)); +} +void ethtool_debug_get_req_free(struct ethtool_debug_get_req *req); + +static inline void +ethtool_debug_get_req_set_header_dev_index(struct ethtool_debug_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_debug_get_req_set_header_dev_name(struct ethtool_debug_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_debug_get_req_set_header_flags(struct ethtool_debug_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_debug_get_rsp { + struct { + __u32 header:1; + __u32 msgmask:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset msgmask; +}; + +void ethtool_debug_get_rsp_free(struct ethtool_debug_get_rsp *rsp); + +/* + * Get debug message mask. + */ +struct ethtool_debug_get_rsp * +ethtool_debug_get(struct ynl_sock *ys, struct ethtool_debug_get_req *req); + +/* ETHTOOL_MSG_DEBUG_GET - dump */ +struct ethtool_debug_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_debug_get_req_dump * +ethtool_debug_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_debug_get_req_dump)); +} +void ethtool_debug_get_req_dump_free(struct ethtool_debug_get_req_dump *req); + +static inline void +ethtool_debug_get_req_dump_set_header_dev_index(struct ethtool_debug_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_debug_get_req_dump_set_header_dev_name(struct ethtool_debug_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_debug_get_req_dump_set_header_flags(struct ethtool_debug_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_debug_get_list { + struct ethtool_debug_get_list *next; + struct ethtool_debug_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_debug_get_list_free(struct ethtool_debug_get_list *rsp); + +struct ethtool_debug_get_list * +ethtool_debug_get_dump(struct ynl_sock *ys, + struct ethtool_debug_get_req_dump *req); + +/* ETHTOOL_MSG_DEBUG_GET - notify */ +struct ethtool_debug_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_debug_get_ntf *ntf); + struct ethtool_debug_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_debug_get_ntf_free(struct ethtool_debug_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_DEBUG_SET ============== */ +/* ETHTOOL_MSG_DEBUG_SET - do */ +struct ethtool_debug_set_req { + struct { + __u32 header:1; + __u32 msgmask:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset msgmask; +}; + +static inline struct ethtool_debug_set_req *ethtool_debug_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_debug_set_req)); +} +void ethtool_debug_set_req_free(struct ethtool_debug_set_req *req); + +static inline void +ethtool_debug_set_req_set_header_dev_index(struct ethtool_debug_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_debug_set_req_set_header_dev_name(struct ethtool_debug_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_debug_set_req_set_header_flags(struct ethtool_debug_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_debug_set_req_set_msgmask_nomask(struct ethtool_debug_set_req *req) +{ + req->_present.msgmask = 1; + req->msgmask._present.nomask = 1; +} +static inline void +ethtool_debug_set_req_set_msgmask_size(struct ethtool_debug_set_req *req, + __u32 size) +{ + req->_present.msgmask = 1; + req->msgmask._present.size = 1; + req->msgmask.size = size; +} +static inline void +__ethtool_debug_set_req_set_msgmask_bits_bit(struct ethtool_debug_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->msgmask.bits.bit); + req->msgmask.bits.bit = bit; + req->msgmask.bits.n_bit = n_bit; +} + +/* + * Set debug message mask. + */ +int ethtool_debug_set(struct ynl_sock *ys, struct ethtool_debug_set_req *req); + +/* ============== ETHTOOL_MSG_WOL_GET ============== */ +/* ETHTOOL_MSG_WOL_GET - do */ +struct ethtool_wol_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_wol_get_req *ethtool_wol_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_wol_get_req)); +} +void ethtool_wol_get_req_free(struct ethtool_wol_get_req *req); + +static inline void +ethtool_wol_get_req_set_header_dev_index(struct ethtool_wol_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_wol_get_req_set_header_dev_name(struct ethtool_wol_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_wol_get_req_set_header_flags(struct ethtool_wol_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_wol_get_rsp { + struct { + __u32 header:1; + __u32 modes:1; + __u32 sopass_len; + } _present; + + struct ethtool_header header; + struct ethtool_bitset modes; + void *sopass; +}; + +void ethtool_wol_get_rsp_free(struct ethtool_wol_get_rsp *rsp); + +/* + * Get WOL params. + */ +struct ethtool_wol_get_rsp * +ethtool_wol_get(struct ynl_sock *ys, struct ethtool_wol_get_req *req); + +/* ETHTOOL_MSG_WOL_GET - dump */ +struct ethtool_wol_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_wol_get_req_dump * +ethtool_wol_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_wol_get_req_dump)); +} +void ethtool_wol_get_req_dump_free(struct ethtool_wol_get_req_dump *req); + +static inline void +ethtool_wol_get_req_dump_set_header_dev_index(struct ethtool_wol_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_wol_get_req_dump_set_header_dev_name(struct ethtool_wol_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_wol_get_req_dump_set_header_flags(struct ethtool_wol_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_wol_get_list { + struct ethtool_wol_get_list *next; + struct ethtool_wol_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_wol_get_list_free(struct ethtool_wol_get_list *rsp); + +struct ethtool_wol_get_list * +ethtool_wol_get_dump(struct ynl_sock *ys, struct ethtool_wol_get_req_dump *req); + +/* ETHTOOL_MSG_WOL_GET - notify */ +struct ethtool_wol_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_wol_get_ntf *ntf); + struct ethtool_wol_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_wol_get_ntf_free(struct ethtool_wol_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_WOL_SET ============== */ +/* ETHTOOL_MSG_WOL_SET - do */ +struct ethtool_wol_set_req { + struct { + __u32 header:1; + __u32 modes:1; + __u32 sopass_len; + } _present; + + struct ethtool_header header; + struct ethtool_bitset modes; + void *sopass; +}; + +static inline struct ethtool_wol_set_req *ethtool_wol_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_wol_set_req)); +} +void ethtool_wol_set_req_free(struct ethtool_wol_set_req *req); + +static inline void +ethtool_wol_set_req_set_header_dev_index(struct ethtool_wol_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_wol_set_req_set_header_dev_name(struct ethtool_wol_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_wol_set_req_set_header_flags(struct ethtool_wol_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_wol_set_req_set_modes_nomask(struct ethtool_wol_set_req *req) +{ + req->_present.modes = 1; + req->modes._present.nomask = 1; +} +static inline void +ethtool_wol_set_req_set_modes_size(struct ethtool_wol_set_req *req, __u32 size) +{ + req->_present.modes = 1; + req->modes._present.size = 1; + req->modes.size = size; +} +static inline void +__ethtool_wol_set_req_set_modes_bits_bit(struct ethtool_wol_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->modes.bits.bit); + req->modes.bits.bit = bit; + req->modes.bits.n_bit = n_bit; +} +static inline void +ethtool_wol_set_req_set_sopass(struct ethtool_wol_set_req *req, + const void *sopass, size_t len) +{ + free(req->sopass); + req->sopass = malloc(req->_present.sopass_len); + memcpy(req->sopass, sopass, req->_present.sopass_len); +} + +/* + * Set WOL params. + */ +int ethtool_wol_set(struct ynl_sock *ys, struct ethtool_wol_set_req *req); + +/* ============== ETHTOOL_MSG_FEATURES_GET ============== */ +/* ETHTOOL_MSG_FEATURES_GET - do */ +struct ethtool_features_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_features_get_req * +ethtool_features_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_features_get_req)); +} +void ethtool_features_get_req_free(struct ethtool_features_get_req *req); + +static inline void +ethtool_features_get_req_set_header_dev_index(struct ethtool_features_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_features_get_req_set_header_dev_name(struct ethtool_features_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_features_get_req_set_header_flags(struct ethtool_features_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_features_get_rsp { + struct { + __u32 header:1; + __u32 hw:1; + __u32 wanted:1; + __u32 active:1; + __u32 nochange:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset hw; + struct ethtool_bitset wanted; + struct ethtool_bitset active; + struct ethtool_bitset nochange; +}; + +void ethtool_features_get_rsp_free(struct ethtool_features_get_rsp *rsp); + +/* + * Get features. + */ +struct ethtool_features_get_rsp * +ethtool_features_get(struct ynl_sock *ys, struct ethtool_features_get_req *req); + +/* ETHTOOL_MSG_FEATURES_GET - dump */ +struct ethtool_features_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_features_get_req_dump * +ethtool_features_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_features_get_req_dump)); +} +void +ethtool_features_get_req_dump_free(struct ethtool_features_get_req_dump *req); + +static inline void +ethtool_features_get_req_dump_set_header_dev_index(struct ethtool_features_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_features_get_req_dump_set_header_dev_name(struct ethtool_features_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_features_get_req_dump_set_header_flags(struct ethtool_features_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_features_get_list { + struct ethtool_features_get_list *next; + struct ethtool_features_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_features_get_list_free(struct ethtool_features_get_list *rsp); + +struct ethtool_features_get_list * +ethtool_features_get_dump(struct ynl_sock *ys, + struct ethtool_features_get_req_dump *req); + +/* ETHTOOL_MSG_FEATURES_GET - notify */ +struct ethtool_features_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_features_get_ntf *ntf); + struct ethtool_features_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_features_get_ntf_free(struct ethtool_features_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_FEATURES_SET ============== */ +/* ETHTOOL_MSG_FEATURES_SET - do */ +struct ethtool_features_set_req { + struct { + __u32 header:1; + __u32 hw:1; + __u32 wanted:1; + __u32 active:1; + __u32 nochange:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset hw; + struct ethtool_bitset wanted; + struct ethtool_bitset active; + struct ethtool_bitset nochange; +}; + +static inline struct ethtool_features_set_req * +ethtool_features_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_features_set_req)); +} +void ethtool_features_set_req_free(struct ethtool_features_set_req *req); + +static inline void +ethtool_features_set_req_set_header_dev_index(struct ethtool_features_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_features_set_req_set_header_dev_name(struct ethtool_features_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_features_set_req_set_header_flags(struct ethtool_features_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_features_set_req_set_hw_nomask(struct ethtool_features_set_req *req) +{ + req->_present.hw = 1; + req->hw._present.nomask = 1; +} +static inline void +ethtool_features_set_req_set_hw_size(struct ethtool_features_set_req *req, + __u32 size) +{ + req->_present.hw = 1; + req->hw._present.size = 1; + req->hw.size = size; +} +static inline void +__ethtool_features_set_req_set_hw_bits_bit(struct ethtool_features_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->hw.bits.bit); + req->hw.bits.bit = bit; + req->hw.bits.n_bit = n_bit; +} +static inline void +ethtool_features_set_req_set_wanted_nomask(struct ethtool_features_set_req *req) +{ + req->_present.wanted = 1; + req->wanted._present.nomask = 1; +} +static inline void +ethtool_features_set_req_set_wanted_size(struct ethtool_features_set_req *req, + __u32 size) +{ + req->_present.wanted = 1; + req->wanted._present.size = 1; + req->wanted.size = size; +} +static inline void +__ethtool_features_set_req_set_wanted_bits_bit(struct ethtool_features_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->wanted.bits.bit); + req->wanted.bits.bit = bit; + req->wanted.bits.n_bit = n_bit; +} +static inline void +ethtool_features_set_req_set_active_nomask(struct ethtool_features_set_req *req) +{ + req->_present.active = 1; + req->active._present.nomask = 1; +} +static inline void +ethtool_features_set_req_set_active_size(struct ethtool_features_set_req *req, + __u32 size) +{ + req->_present.active = 1; + req->active._present.size = 1; + req->active.size = size; +} +static inline void +__ethtool_features_set_req_set_active_bits_bit(struct ethtool_features_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->active.bits.bit); + req->active.bits.bit = bit; + req->active.bits.n_bit = n_bit; +} +static inline void +ethtool_features_set_req_set_nochange_nomask(struct ethtool_features_set_req *req) +{ + req->_present.nochange = 1; + req->nochange._present.nomask = 1; +} +static inline void +ethtool_features_set_req_set_nochange_size(struct ethtool_features_set_req *req, + __u32 size) +{ + req->_present.nochange = 1; + req->nochange._present.size = 1; + req->nochange.size = size; +} +static inline void +__ethtool_features_set_req_set_nochange_bits_bit(struct ethtool_features_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->nochange.bits.bit); + req->nochange.bits.bit = bit; + req->nochange.bits.n_bit = n_bit; +} + +struct ethtool_features_set_rsp { + struct { + __u32 header:1; + __u32 hw:1; + __u32 wanted:1; + __u32 active:1; + __u32 nochange:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset hw; + struct ethtool_bitset wanted; + struct ethtool_bitset active; + struct ethtool_bitset nochange; +}; + +void ethtool_features_set_rsp_free(struct ethtool_features_set_rsp *rsp); + +/* + * Set features. + */ +struct ethtool_features_set_rsp * +ethtool_features_set(struct ynl_sock *ys, struct ethtool_features_set_req *req); + +/* ============== ETHTOOL_MSG_PRIVFLAGS_GET ============== */ +/* ETHTOOL_MSG_PRIVFLAGS_GET - do */ +struct ethtool_privflags_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_privflags_get_req * +ethtool_privflags_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_privflags_get_req)); +} +void ethtool_privflags_get_req_free(struct ethtool_privflags_get_req *req); + +static inline void +ethtool_privflags_get_req_set_header_dev_index(struct ethtool_privflags_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_privflags_get_req_set_header_dev_name(struct ethtool_privflags_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_privflags_get_req_set_header_flags(struct ethtool_privflags_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_privflags_get_rsp { + struct { + __u32 header:1; + __u32 flags:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset flags; +}; + +void ethtool_privflags_get_rsp_free(struct ethtool_privflags_get_rsp *rsp); + +/* + * Get device private flags. + */ +struct ethtool_privflags_get_rsp * +ethtool_privflags_get(struct ynl_sock *ys, + struct ethtool_privflags_get_req *req); + +/* ETHTOOL_MSG_PRIVFLAGS_GET - dump */ +struct ethtool_privflags_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_privflags_get_req_dump * +ethtool_privflags_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_privflags_get_req_dump)); +} +void +ethtool_privflags_get_req_dump_free(struct ethtool_privflags_get_req_dump *req); + +static inline void +ethtool_privflags_get_req_dump_set_header_dev_index(struct ethtool_privflags_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_privflags_get_req_dump_set_header_dev_name(struct ethtool_privflags_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_privflags_get_req_dump_set_header_flags(struct ethtool_privflags_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_privflags_get_list { + struct ethtool_privflags_get_list *next; + struct ethtool_privflags_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_privflags_get_list_free(struct ethtool_privflags_get_list *rsp); + +struct ethtool_privflags_get_list * +ethtool_privflags_get_dump(struct ynl_sock *ys, + struct ethtool_privflags_get_req_dump *req); + +/* ETHTOOL_MSG_PRIVFLAGS_GET - notify */ +struct ethtool_privflags_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_privflags_get_ntf *ntf); + struct ethtool_privflags_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_privflags_get_ntf_free(struct ethtool_privflags_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_PRIVFLAGS_SET ============== */ +/* ETHTOOL_MSG_PRIVFLAGS_SET - do */ +struct ethtool_privflags_set_req { + struct { + __u32 header:1; + __u32 flags:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset flags; +}; + +static inline struct ethtool_privflags_set_req * +ethtool_privflags_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_privflags_set_req)); +} +void ethtool_privflags_set_req_free(struct ethtool_privflags_set_req *req); + +static inline void +ethtool_privflags_set_req_set_header_dev_index(struct ethtool_privflags_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_privflags_set_req_set_header_dev_name(struct ethtool_privflags_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_privflags_set_req_set_header_flags(struct ethtool_privflags_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_privflags_set_req_set_flags_nomask(struct ethtool_privflags_set_req *req) +{ + req->_present.flags = 1; + req->flags._present.nomask = 1; +} +static inline void +ethtool_privflags_set_req_set_flags_size(struct ethtool_privflags_set_req *req, + __u32 size) +{ + req->_present.flags = 1; + req->flags._present.size = 1; + req->flags.size = size; +} +static inline void +__ethtool_privflags_set_req_set_flags_bits_bit(struct ethtool_privflags_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->flags.bits.bit); + req->flags.bits.bit = bit; + req->flags.bits.n_bit = n_bit; +} + +/* + * Set device private flags. + */ +int ethtool_privflags_set(struct ynl_sock *ys, + struct ethtool_privflags_set_req *req); + +/* ============== ETHTOOL_MSG_RINGS_GET ============== */ +/* ETHTOOL_MSG_RINGS_GET - do */ +struct ethtool_rings_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_rings_get_req *ethtool_rings_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_rings_get_req)); +} +void ethtool_rings_get_req_free(struct ethtool_rings_get_req *req); + +static inline void +ethtool_rings_get_req_set_header_dev_index(struct ethtool_rings_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_rings_get_req_set_header_dev_name(struct ethtool_rings_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_rings_get_req_set_header_flags(struct ethtool_rings_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_rings_get_rsp { + struct { + __u32 header:1; + __u32 rx_max:1; + __u32 rx_mini_max:1; + __u32 rx_jumbo_max:1; + __u32 tx_max:1; + __u32 rx:1; + __u32 rx_mini:1; + __u32 rx_jumbo:1; + __u32 tx:1; + __u32 rx_buf_len:1; + __u32 tcp_data_split:1; + __u32 cqe_size:1; + __u32 tx_push:1; + __u32 rx_push:1; + __u32 tx_push_buf_len:1; + __u32 tx_push_buf_len_max:1; + } _present; + + struct ethtool_header header; + __u32 rx_max; + __u32 rx_mini_max; + __u32 rx_jumbo_max; + __u32 tx_max; + __u32 rx; + __u32 rx_mini; + __u32 rx_jumbo; + __u32 tx; + __u32 rx_buf_len; + __u8 tcp_data_split; + __u32 cqe_size; + __u8 tx_push; + __u8 rx_push; + __u32 tx_push_buf_len; + __u32 tx_push_buf_len_max; +}; + +void ethtool_rings_get_rsp_free(struct ethtool_rings_get_rsp *rsp); + +/* + * Get ring params. + */ +struct ethtool_rings_get_rsp * +ethtool_rings_get(struct ynl_sock *ys, struct ethtool_rings_get_req *req); + +/* ETHTOOL_MSG_RINGS_GET - dump */ +struct ethtool_rings_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_rings_get_req_dump * +ethtool_rings_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_rings_get_req_dump)); +} +void ethtool_rings_get_req_dump_free(struct ethtool_rings_get_req_dump *req); + +static inline void +ethtool_rings_get_req_dump_set_header_dev_index(struct ethtool_rings_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_rings_get_req_dump_set_header_dev_name(struct ethtool_rings_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_rings_get_req_dump_set_header_flags(struct ethtool_rings_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_rings_get_list { + struct ethtool_rings_get_list *next; + struct ethtool_rings_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_rings_get_list_free(struct ethtool_rings_get_list *rsp); + +struct ethtool_rings_get_list * +ethtool_rings_get_dump(struct ynl_sock *ys, + struct ethtool_rings_get_req_dump *req); + +/* ETHTOOL_MSG_RINGS_GET - notify */ +struct ethtool_rings_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_rings_get_ntf *ntf); + struct ethtool_rings_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_rings_get_ntf_free(struct ethtool_rings_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_RINGS_SET ============== */ +/* ETHTOOL_MSG_RINGS_SET - do */ +struct ethtool_rings_set_req { + struct { + __u32 header:1; + __u32 rx_max:1; + __u32 rx_mini_max:1; + __u32 rx_jumbo_max:1; + __u32 tx_max:1; + __u32 rx:1; + __u32 rx_mini:1; + __u32 rx_jumbo:1; + __u32 tx:1; + __u32 rx_buf_len:1; + __u32 tcp_data_split:1; + __u32 cqe_size:1; + __u32 tx_push:1; + __u32 rx_push:1; + __u32 tx_push_buf_len:1; + __u32 tx_push_buf_len_max:1; + } _present; + + struct ethtool_header header; + __u32 rx_max; + __u32 rx_mini_max; + __u32 rx_jumbo_max; + __u32 tx_max; + __u32 rx; + __u32 rx_mini; + __u32 rx_jumbo; + __u32 tx; + __u32 rx_buf_len; + __u8 tcp_data_split; + __u32 cqe_size; + __u8 tx_push; + __u8 rx_push; + __u32 tx_push_buf_len; + __u32 tx_push_buf_len_max; +}; + +static inline struct ethtool_rings_set_req *ethtool_rings_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_rings_set_req)); +} +void ethtool_rings_set_req_free(struct ethtool_rings_set_req *req); + +static inline void +ethtool_rings_set_req_set_header_dev_index(struct ethtool_rings_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_rings_set_req_set_header_dev_name(struct ethtool_rings_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_rings_set_req_set_header_flags(struct ethtool_rings_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_rings_set_req_set_rx_max(struct ethtool_rings_set_req *req, + __u32 rx_max) +{ + req->_present.rx_max = 1; + req->rx_max = rx_max; +} +static inline void +ethtool_rings_set_req_set_rx_mini_max(struct ethtool_rings_set_req *req, + __u32 rx_mini_max) +{ + req->_present.rx_mini_max = 1; + req->rx_mini_max = rx_mini_max; +} +static inline void +ethtool_rings_set_req_set_rx_jumbo_max(struct ethtool_rings_set_req *req, + __u32 rx_jumbo_max) +{ + req->_present.rx_jumbo_max = 1; + req->rx_jumbo_max = rx_jumbo_max; +} +static inline void +ethtool_rings_set_req_set_tx_max(struct ethtool_rings_set_req *req, + __u32 tx_max) +{ + req->_present.tx_max = 1; + req->tx_max = tx_max; +} +static inline void +ethtool_rings_set_req_set_rx(struct ethtool_rings_set_req *req, __u32 rx) +{ + req->_present.rx = 1; + req->rx = rx; +} +static inline void +ethtool_rings_set_req_set_rx_mini(struct ethtool_rings_set_req *req, + __u32 rx_mini) +{ + req->_present.rx_mini = 1; + req->rx_mini = rx_mini; +} +static inline void +ethtool_rings_set_req_set_rx_jumbo(struct ethtool_rings_set_req *req, + __u32 rx_jumbo) +{ + req->_present.rx_jumbo = 1; + req->rx_jumbo = rx_jumbo; +} +static inline void +ethtool_rings_set_req_set_tx(struct ethtool_rings_set_req *req, __u32 tx) +{ + req->_present.tx = 1; + req->tx = tx; +} +static inline void +ethtool_rings_set_req_set_rx_buf_len(struct ethtool_rings_set_req *req, + __u32 rx_buf_len) +{ + req->_present.rx_buf_len = 1; + req->rx_buf_len = rx_buf_len; +} +static inline void +ethtool_rings_set_req_set_tcp_data_split(struct ethtool_rings_set_req *req, + __u8 tcp_data_split) +{ + req->_present.tcp_data_split = 1; + req->tcp_data_split = tcp_data_split; +} +static inline void +ethtool_rings_set_req_set_cqe_size(struct ethtool_rings_set_req *req, + __u32 cqe_size) +{ + req->_present.cqe_size = 1; + req->cqe_size = cqe_size; +} +static inline void +ethtool_rings_set_req_set_tx_push(struct ethtool_rings_set_req *req, + __u8 tx_push) +{ + req->_present.tx_push = 1; + req->tx_push = tx_push; +} +static inline void +ethtool_rings_set_req_set_rx_push(struct ethtool_rings_set_req *req, + __u8 rx_push) +{ + req->_present.rx_push = 1; + req->rx_push = rx_push; +} +static inline void +ethtool_rings_set_req_set_tx_push_buf_len(struct ethtool_rings_set_req *req, + __u32 tx_push_buf_len) +{ + req->_present.tx_push_buf_len = 1; + req->tx_push_buf_len = tx_push_buf_len; +} +static inline void +ethtool_rings_set_req_set_tx_push_buf_len_max(struct ethtool_rings_set_req *req, + __u32 tx_push_buf_len_max) +{ + req->_present.tx_push_buf_len_max = 1; + req->tx_push_buf_len_max = tx_push_buf_len_max; +} + +/* + * Set ring params. + */ +int ethtool_rings_set(struct ynl_sock *ys, struct ethtool_rings_set_req *req); + +/* ============== ETHTOOL_MSG_CHANNELS_GET ============== */ +/* ETHTOOL_MSG_CHANNELS_GET - do */ +struct ethtool_channels_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_channels_get_req * +ethtool_channels_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_channels_get_req)); +} +void ethtool_channels_get_req_free(struct ethtool_channels_get_req *req); + +static inline void +ethtool_channels_get_req_set_header_dev_index(struct ethtool_channels_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_channels_get_req_set_header_dev_name(struct ethtool_channels_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_channels_get_req_set_header_flags(struct ethtool_channels_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_channels_get_rsp { + struct { + __u32 header:1; + __u32 rx_max:1; + __u32 tx_max:1; + __u32 other_max:1; + __u32 combined_max:1; + __u32 rx_count:1; + __u32 tx_count:1; + __u32 other_count:1; + __u32 combined_count:1; + } _present; + + struct ethtool_header header; + __u32 rx_max; + __u32 tx_max; + __u32 other_max; + __u32 combined_max; + __u32 rx_count; + __u32 tx_count; + __u32 other_count; + __u32 combined_count; +}; + +void ethtool_channels_get_rsp_free(struct ethtool_channels_get_rsp *rsp); + +/* + * Get channel params. + */ +struct ethtool_channels_get_rsp * +ethtool_channels_get(struct ynl_sock *ys, struct ethtool_channels_get_req *req); + +/* ETHTOOL_MSG_CHANNELS_GET - dump */ +struct ethtool_channels_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_channels_get_req_dump * +ethtool_channels_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_channels_get_req_dump)); +} +void +ethtool_channels_get_req_dump_free(struct ethtool_channels_get_req_dump *req); + +static inline void +ethtool_channels_get_req_dump_set_header_dev_index(struct ethtool_channels_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_channels_get_req_dump_set_header_dev_name(struct ethtool_channels_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_channels_get_req_dump_set_header_flags(struct ethtool_channels_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_channels_get_list { + struct ethtool_channels_get_list *next; + struct ethtool_channels_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_channels_get_list_free(struct ethtool_channels_get_list *rsp); + +struct ethtool_channels_get_list * +ethtool_channels_get_dump(struct ynl_sock *ys, + struct ethtool_channels_get_req_dump *req); + +/* ETHTOOL_MSG_CHANNELS_GET - notify */ +struct ethtool_channels_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_channels_get_ntf *ntf); + struct ethtool_channels_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_channels_get_ntf_free(struct ethtool_channels_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_CHANNELS_SET ============== */ +/* ETHTOOL_MSG_CHANNELS_SET - do */ +struct ethtool_channels_set_req { + struct { + __u32 header:1; + __u32 rx_max:1; + __u32 tx_max:1; + __u32 other_max:1; + __u32 combined_max:1; + __u32 rx_count:1; + __u32 tx_count:1; + __u32 other_count:1; + __u32 combined_count:1; + } _present; + + struct ethtool_header header; + __u32 rx_max; + __u32 tx_max; + __u32 other_max; + __u32 combined_max; + __u32 rx_count; + __u32 tx_count; + __u32 other_count; + __u32 combined_count; +}; + +static inline struct ethtool_channels_set_req * +ethtool_channels_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_channels_set_req)); +} +void ethtool_channels_set_req_free(struct ethtool_channels_set_req *req); + +static inline void +ethtool_channels_set_req_set_header_dev_index(struct ethtool_channels_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_channels_set_req_set_header_dev_name(struct ethtool_channels_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_channels_set_req_set_header_flags(struct ethtool_channels_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_channels_set_req_set_rx_max(struct ethtool_channels_set_req *req, + __u32 rx_max) +{ + req->_present.rx_max = 1; + req->rx_max = rx_max; +} +static inline void +ethtool_channels_set_req_set_tx_max(struct ethtool_channels_set_req *req, + __u32 tx_max) +{ + req->_present.tx_max = 1; + req->tx_max = tx_max; +} +static inline void +ethtool_channels_set_req_set_other_max(struct ethtool_channels_set_req *req, + __u32 other_max) +{ + req->_present.other_max = 1; + req->other_max = other_max; +} +static inline void +ethtool_channels_set_req_set_combined_max(struct ethtool_channels_set_req *req, + __u32 combined_max) +{ + req->_present.combined_max = 1; + req->combined_max = combined_max; +} +static inline void +ethtool_channels_set_req_set_rx_count(struct ethtool_channels_set_req *req, + __u32 rx_count) +{ + req->_present.rx_count = 1; + req->rx_count = rx_count; +} +static inline void +ethtool_channels_set_req_set_tx_count(struct ethtool_channels_set_req *req, + __u32 tx_count) +{ + req->_present.tx_count = 1; + req->tx_count = tx_count; +} +static inline void +ethtool_channels_set_req_set_other_count(struct ethtool_channels_set_req *req, + __u32 other_count) +{ + req->_present.other_count = 1; + req->other_count = other_count; +} +static inline void +ethtool_channels_set_req_set_combined_count(struct ethtool_channels_set_req *req, + __u32 combined_count) +{ + req->_present.combined_count = 1; + req->combined_count = combined_count; +} + +/* + * Set channel params. + */ +int ethtool_channels_set(struct ynl_sock *ys, + struct ethtool_channels_set_req *req); + +/* ============== ETHTOOL_MSG_COALESCE_GET ============== */ +/* ETHTOOL_MSG_COALESCE_GET - do */ +struct ethtool_coalesce_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_coalesce_get_req * +ethtool_coalesce_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_coalesce_get_req)); +} +void ethtool_coalesce_get_req_free(struct ethtool_coalesce_get_req *req); + +static inline void +ethtool_coalesce_get_req_set_header_dev_index(struct ethtool_coalesce_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_coalesce_get_req_set_header_dev_name(struct ethtool_coalesce_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_coalesce_get_req_set_header_flags(struct ethtool_coalesce_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_coalesce_get_rsp { + struct { + __u32 header:1; + __u32 rx_usecs:1; + __u32 rx_max_frames:1; + __u32 rx_usecs_irq:1; + __u32 rx_max_frames_irq:1; + __u32 tx_usecs:1; + __u32 tx_max_frames:1; + __u32 tx_usecs_irq:1; + __u32 tx_max_frames_irq:1; + __u32 stats_block_usecs:1; + __u32 use_adaptive_rx:1; + __u32 use_adaptive_tx:1; + __u32 pkt_rate_low:1; + __u32 rx_usecs_low:1; + __u32 rx_max_frames_low:1; + __u32 tx_usecs_low:1; + __u32 tx_max_frames_low:1; + __u32 pkt_rate_high:1; + __u32 rx_usecs_high:1; + __u32 rx_max_frames_high:1; + __u32 tx_usecs_high:1; + __u32 tx_max_frames_high:1; + __u32 rate_sample_interval:1; + __u32 use_cqe_mode_tx:1; + __u32 use_cqe_mode_rx:1; + __u32 tx_aggr_max_bytes:1; + __u32 tx_aggr_max_frames:1; + __u32 tx_aggr_time_usecs:1; + } _present; + + struct ethtool_header header; + __u32 rx_usecs; + __u32 rx_max_frames; + __u32 rx_usecs_irq; + __u32 rx_max_frames_irq; + __u32 tx_usecs; + __u32 tx_max_frames; + __u32 tx_usecs_irq; + __u32 tx_max_frames_irq; + __u32 stats_block_usecs; + __u8 use_adaptive_rx; + __u8 use_adaptive_tx; + __u32 pkt_rate_low; + __u32 rx_usecs_low; + __u32 rx_max_frames_low; + __u32 tx_usecs_low; + __u32 tx_max_frames_low; + __u32 pkt_rate_high; + __u32 rx_usecs_high; + __u32 rx_max_frames_high; + __u32 tx_usecs_high; + __u32 tx_max_frames_high; + __u32 rate_sample_interval; + __u8 use_cqe_mode_tx; + __u8 use_cqe_mode_rx; + __u32 tx_aggr_max_bytes; + __u32 tx_aggr_max_frames; + __u32 tx_aggr_time_usecs; +}; + +void ethtool_coalesce_get_rsp_free(struct ethtool_coalesce_get_rsp *rsp); + +/* + * Get coalesce params. + */ +struct ethtool_coalesce_get_rsp * +ethtool_coalesce_get(struct ynl_sock *ys, struct ethtool_coalesce_get_req *req); + +/* ETHTOOL_MSG_COALESCE_GET - dump */ +struct ethtool_coalesce_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_coalesce_get_req_dump * +ethtool_coalesce_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_coalesce_get_req_dump)); +} +void +ethtool_coalesce_get_req_dump_free(struct ethtool_coalesce_get_req_dump *req); + +static inline void +ethtool_coalesce_get_req_dump_set_header_dev_index(struct ethtool_coalesce_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_coalesce_get_req_dump_set_header_dev_name(struct ethtool_coalesce_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_coalesce_get_req_dump_set_header_flags(struct ethtool_coalesce_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_coalesce_get_list { + struct ethtool_coalesce_get_list *next; + struct ethtool_coalesce_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_coalesce_get_list_free(struct ethtool_coalesce_get_list *rsp); + +struct ethtool_coalesce_get_list * +ethtool_coalesce_get_dump(struct ynl_sock *ys, + struct ethtool_coalesce_get_req_dump *req); + +/* ETHTOOL_MSG_COALESCE_GET - notify */ +struct ethtool_coalesce_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_coalesce_get_ntf *ntf); + struct ethtool_coalesce_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_coalesce_get_ntf_free(struct ethtool_coalesce_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_COALESCE_SET ============== */ +/* ETHTOOL_MSG_COALESCE_SET - do */ +struct ethtool_coalesce_set_req { + struct { + __u32 header:1; + __u32 rx_usecs:1; + __u32 rx_max_frames:1; + __u32 rx_usecs_irq:1; + __u32 rx_max_frames_irq:1; + __u32 tx_usecs:1; + __u32 tx_max_frames:1; + __u32 tx_usecs_irq:1; + __u32 tx_max_frames_irq:1; + __u32 stats_block_usecs:1; + __u32 use_adaptive_rx:1; + __u32 use_adaptive_tx:1; + __u32 pkt_rate_low:1; + __u32 rx_usecs_low:1; + __u32 rx_max_frames_low:1; + __u32 tx_usecs_low:1; + __u32 tx_max_frames_low:1; + __u32 pkt_rate_high:1; + __u32 rx_usecs_high:1; + __u32 rx_max_frames_high:1; + __u32 tx_usecs_high:1; + __u32 tx_max_frames_high:1; + __u32 rate_sample_interval:1; + __u32 use_cqe_mode_tx:1; + __u32 use_cqe_mode_rx:1; + __u32 tx_aggr_max_bytes:1; + __u32 tx_aggr_max_frames:1; + __u32 tx_aggr_time_usecs:1; + } _present; + + struct ethtool_header header; + __u32 rx_usecs; + __u32 rx_max_frames; + __u32 rx_usecs_irq; + __u32 rx_max_frames_irq; + __u32 tx_usecs; + __u32 tx_max_frames; + __u32 tx_usecs_irq; + __u32 tx_max_frames_irq; + __u32 stats_block_usecs; + __u8 use_adaptive_rx; + __u8 use_adaptive_tx; + __u32 pkt_rate_low; + __u32 rx_usecs_low; + __u32 rx_max_frames_low; + __u32 tx_usecs_low; + __u32 tx_max_frames_low; + __u32 pkt_rate_high; + __u32 rx_usecs_high; + __u32 rx_max_frames_high; + __u32 tx_usecs_high; + __u32 tx_max_frames_high; + __u32 rate_sample_interval; + __u8 use_cqe_mode_tx; + __u8 use_cqe_mode_rx; + __u32 tx_aggr_max_bytes; + __u32 tx_aggr_max_frames; + __u32 tx_aggr_time_usecs; +}; + +static inline struct ethtool_coalesce_set_req * +ethtool_coalesce_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_coalesce_set_req)); +} +void ethtool_coalesce_set_req_free(struct ethtool_coalesce_set_req *req); + +static inline void +ethtool_coalesce_set_req_set_header_dev_index(struct ethtool_coalesce_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_coalesce_set_req_set_header_dev_name(struct ethtool_coalesce_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_coalesce_set_req_set_header_flags(struct ethtool_coalesce_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_coalesce_set_req_set_rx_usecs(struct ethtool_coalesce_set_req *req, + __u32 rx_usecs) +{ + req->_present.rx_usecs = 1; + req->rx_usecs = rx_usecs; +} +static inline void +ethtool_coalesce_set_req_set_rx_max_frames(struct ethtool_coalesce_set_req *req, + __u32 rx_max_frames) +{ + req->_present.rx_max_frames = 1; + req->rx_max_frames = rx_max_frames; +} +static inline void +ethtool_coalesce_set_req_set_rx_usecs_irq(struct ethtool_coalesce_set_req *req, + __u32 rx_usecs_irq) +{ + req->_present.rx_usecs_irq = 1; + req->rx_usecs_irq = rx_usecs_irq; +} +static inline void +ethtool_coalesce_set_req_set_rx_max_frames_irq(struct ethtool_coalesce_set_req *req, + __u32 rx_max_frames_irq) +{ + req->_present.rx_max_frames_irq = 1; + req->rx_max_frames_irq = rx_max_frames_irq; +} +static inline void +ethtool_coalesce_set_req_set_tx_usecs(struct ethtool_coalesce_set_req *req, + __u32 tx_usecs) +{ + req->_present.tx_usecs = 1; + req->tx_usecs = tx_usecs; +} +static inline void +ethtool_coalesce_set_req_set_tx_max_frames(struct ethtool_coalesce_set_req *req, + __u32 tx_max_frames) +{ + req->_present.tx_max_frames = 1; + req->tx_max_frames = tx_max_frames; +} +static inline void +ethtool_coalesce_set_req_set_tx_usecs_irq(struct ethtool_coalesce_set_req *req, + __u32 tx_usecs_irq) +{ + req->_present.tx_usecs_irq = 1; + req->tx_usecs_irq = tx_usecs_irq; +} +static inline void +ethtool_coalesce_set_req_set_tx_max_frames_irq(struct ethtool_coalesce_set_req *req, + __u32 tx_max_frames_irq) +{ + req->_present.tx_max_frames_irq = 1; + req->tx_max_frames_irq = tx_max_frames_irq; +} +static inline void +ethtool_coalesce_set_req_set_stats_block_usecs(struct ethtool_coalesce_set_req *req, + __u32 stats_block_usecs) +{ + req->_present.stats_block_usecs = 1; + req->stats_block_usecs = stats_block_usecs; +} +static inline void +ethtool_coalesce_set_req_set_use_adaptive_rx(struct ethtool_coalesce_set_req *req, + __u8 use_adaptive_rx) +{ + req->_present.use_adaptive_rx = 1; + req->use_adaptive_rx = use_adaptive_rx; +} +static inline void +ethtool_coalesce_set_req_set_use_adaptive_tx(struct ethtool_coalesce_set_req *req, + __u8 use_adaptive_tx) +{ + req->_present.use_adaptive_tx = 1; + req->use_adaptive_tx = use_adaptive_tx; +} +static inline void +ethtool_coalesce_set_req_set_pkt_rate_low(struct ethtool_coalesce_set_req *req, + __u32 pkt_rate_low) +{ + req->_present.pkt_rate_low = 1; + req->pkt_rate_low = pkt_rate_low; +} +static inline void +ethtool_coalesce_set_req_set_rx_usecs_low(struct ethtool_coalesce_set_req *req, + __u32 rx_usecs_low) +{ + req->_present.rx_usecs_low = 1; + req->rx_usecs_low = rx_usecs_low; +} +static inline void +ethtool_coalesce_set_req_set_rx_max_frames_low(struct ethtool_coalesce_set_req *req, + __u32 rx_max_frames_low) +{ + req->_present.rx_max_frames_low = 1; + req->rx_max_frames_low = rx_max_frames_low; +} +static inline void +ethtool_coalesce_set_req_set_tx_usecs_low(struct ethtool_coalesce_set_req *req, + __u32 tx_usecs_low) +{ + req->_present.tx_usecs_low = 1; + req->tx_usecs_low = tx_usecs_low; +} +static inline void +ethtool_coalesce_set_req_set_tx_max_frames_low(struct ethtool_coalesce_set_req *req, + __u32 tx_max_frames_low) +{ + req->_present.tx_max_frames_low = 1; + req->tx_max_frames_low = tx_max_frames_low; +} +static inline void +ethtool_coalesce_set_req_set_pkt_rate_high(struct ethtool_coalesce_set_req *req, + __u32 pkt_rate_high) +{ + req->_present.pkt_rate_high = 1; + req->pkt_rate_high = pkt_rate_high; +} +static inline void +ethtool_coalesce_set_req_set_rx_usecs_high(struct ethtool_coalesce_set_req *req, + __u32 rx_usecs_high) +{ + req->_present.rx_usecs_high = 1; + req->rx_usecs_high = rx_usecs_high; +} +static inline void +ethtool_coalesce_set_req_set_rx_max_frames_high(struct ethtool_coalesce_set_req *req, + __u32 rx_max_frames_high) +{ + req->_present.rx_max_frames_high = 1; + req->rx_max_frames_high = rx_max_frames_high; +} +static inline void +ethtool_coalesce_set_req_set_tx_usecs_high(struct ethtool_coalesce_set_req *req, + __u32 tx_usecs_high) +{ + req->_present.tx_usecs_high = 1; + req->tx_usecs_high = tx_usecs_high; +} +static inline void +ethtool_coalesce_set_req_set_tx_max_frames_high(struct ethtool_coalesce_set_req *req, + __u32 tx_max_frames_high) +{ + req->_present.tx_max_frames_high = 1; + req->tx_max_frames_high = tx_max_frames_high; +} +static inline void +ethtool_coalesce_set_req_set_rate_sample_interval(struct ethtool_coalesce_set_req *req, + __u32 rate_sample_interval) +{ + req->_present.rate_sample_interval = 1; + req->rate_sample_interval = rate_sample_interval; +} +static inline void +ethtool_coalesce_set_req_set_use_cqe_mode_tx(struct ethtool_coalesce_set_req *req, + __u8 use_cqe_mode_tx) +{ + req->_present.use_cqe_mode_tx = 1; + req->use_cqe_mode_tx = use_cqe_mode_tx; +} +static inline void +ethtool_coalesce_set_req_set_use_cqe_mode_rx(struct ethtool_coalesce_set_req *req, + __u8 use_cqe_mode_rx) +{ + req->_present.use_cqe_mode_rx = 1; + req->use_cqe_mode_rx = use_cqe_mode_rx; +} +static inline void +ethtool_coalesce_set_req_set_tx_aggr_max_bytes(struct ethtool_coalesce_set_req *req, + __u32 tx_aggr_max_bytes) +{ + req->_present.tx_aggr_max_bytes = 1; + req->tx_aggr_max_bytes = tx_aggr_max_bytes; +} +static inline void +ethtool_coalesce_set_req_set_tx_aggr_max_frames(struct ethtool_coalesce_set_req *req, + __u32 tx_aggr_max_frames) +{ + req->_present.tx_aggr_max_frames = 1; + req->tx_aggr_max_frames = tx_aggr_max_frames; +} +static inline void +ethtool_coalesce_set_req_set_tx_aggr_time_usecs(struct ethtool_coalesce_set_req *req, + __u32 tx_aggr_time_usecs) +{ + req->_present.tx_aggr_time_usecs = 1; + req->tx_aggr_time_usecs = tx_aggr_time_usecs; +} + +/* + * Set coalesce params. + */ +int ethtool_coalesce_set(struct ynl_sock *ys, + struct ethtool_coalesce_set_req *req); + +/* ============== ETHTOOL_MSG_PAUSE_GET ============== */ +/* ETHTOOL_MSG_PAUSE_GET - do */ +struct ethtool_pause_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_pause_get_req *ethtool_pause_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_pause_get_req)); +} +void ethtool_pause_get_req_free(struct ethtool_pause_get_req *req); + +static inline void +ethtool_pause_get_req_set_header_dev_index(struct ethtool_pause_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_pause_get_req_set_header_dev_name(struct ethtool_pause_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_pause_get_req_set_header_flags(struct ethtool_pause_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_pause_get_rsp { + struct { + __u32 header:1; + __u32 autoneg:1; + __u32 rx:1; + __u32 tx:1; + __u32 stats:1; + __u32 stats_src:1; + } _present; + + struct ethtool_header header; + __u8 autoneg; + __u8 rx; + __u8 tx; + struct ethtool_pause_stat stats; + __u32 stats_src; +}; + +void ethtool_pause_get_rsp_free(struct ethtool_pause_get_rsp *rsp); + +/* + * Get pause params. + */ +struct ethtool_pause_get_rsp * +ethtool_pause_get(struct ynl_sock *ys, struct ethtool_pause_get_req *req); + +/* ETHTOOL_MSG_PAUSE_GET - dump */ +struct ethtool_pause_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_pause_get_req_dump * +ethtool_pause_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_pause_get_req_dump)); +} +void ethtool_pause_get_req_dump_free(struct ethtool_pause_get_req_dump *req); + +static inline void +ethtool_pause_get_req_dump_set_header_dev_index(struct ethtool_pause_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_pause_get_req_dump_set_header_dev_name(struct ethtool_pause_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_pause_get_req_dump_set_header_flags(struct ethtool_pause_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_pause_get_list { + struct ethtool_pause_get_list *next; + struct ethtool_pause_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_pause_get_list_free(struct ethtool_pause_get_list *rsp); + +struct ethtool_pause_get_list * +ethtool_pause_get_dump(struct ynl_sock *ys, + struct ethtool_pause_get_req_dump *req); + +/* ETHTOOL_MSG_PAUSE_GET - notify */ +struct ethtool_pause_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_pause_get_ntf *ntf); + struct ethtool_pause_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_pause_get_ntf_free(struct ethtool_pause_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_PAUSE_SET ============== */ +/* ETHTOOL_MSG_PAUSE_SET - do */ +struct ethtool_pause_set_req { + struct { + __u32 header:1; + __u32 autoneg:1; + __u32 rx:1; + __u32 tx:1; + __u32 stats:1; + __u32 stats_src:1; + } _present; + + struct ethtool_header header; + __u8 autoneg; + __u8 rx; + __u8 tx; + struct ethtool_pause_stat stats; + __u32 stats_src; +}; + +static inline struct ethtool_pause_set_req *ethtool_pause_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_pause_set_req)); +} +void ethtool_pause_set_req_free(struct ethtool_pause_set_req *req); + +static inline void +ethtool_pause_set_req_set_header_dev_index(struct ethtool_pause_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_pause_set_req_set_header_dev_name(struct ethtool_pause_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_pause_set_req_set_header_flags(struct ethtool_pause_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_pause_set_req_set_autoneg(struct ethtool_pause_set_req *req, + __u8 autoneg) +{ + req->_present.autoneg = 1; + req->autoneg = autoneg; +} +static inline void +ethtool_pause_set_req_set_rx(struct ethtool_pause_set_req *req, __u8 rx) +{ + req->_present.rx = 1; + req->rx = rx; +} +static inline void +ethtool_pause_set_req_set_tx(struct ethtool_pause_set_req *req, __u8 tx) +{ + req->_present.tx = 1; + req->tx = tx; +} +static inline void +ethtool_pause_set_req_set_stats_tx_frames(struct ethtool_pause_set_req *req, + __u64 tx_frames) +{ + req->_present.stats = 1; + req->stats._present.tx_frames = 1; + req->stats.tx_frames = tx_frames; +} +static inline void +ethtool_pause_set_req_set_stats_rx_frames(struct ethtool_pause_set_req *req, + __u64 rx_frames) +{ + req->_present.stats = 1; + req->stats._present.rx_frames = 1; + req->stats.rx_frames = rx_frames; +} +static inline void +ethtool_pause_set_req_set_stats_src(struct ethtool_pause_set_req *req, + __u32 stats_src) +{ + req->_present.stats_src = 1; + req->stats_src = stats_src; +} + +/* + * Set pause params. + */ +int ethtool_pause_set(struct ynl_sock *ys, struct ethtool_pause_set_req *req); + +/* ============== ETHTOOL_MSG_EEE_GET ============== */ +/* ETHTOOL_MSG_EEE_GET - do */ +struct ethtool_eee_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_eee_get_req *ethtool_eee_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_eee_get_req)); +} +void ethtool_eee_get_req_free(struct ethtool_eee_get_req *req); + +static inline void +ethtool_eee_get_req_set_header_dev_index(struct ethtool_eee_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_eee_get_req_set_header_dev_name(struct ethtool_eee_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_eee_get_req_set_header_flags(struct ethtool_eee_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_eee_get_rsp { + struct { + __u32 header:1; + __u32 modes_ours:1; + __u32 modes_peer:1; + __u32 active:1; + __u32 enabled:1; + __u32 tx_lpi_enabled:1; + __u32 tx_lpi_timer:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset modes_ours; + struct ethtool_bitset modes_peer; + __u8 active; + __u8 enabled; + __u8 tx_lpi_enabled; + __u32 tx_lpi_timer; +}; + +void ethtool_eee_get_rsp_free(struct ethtool_eee_get_rsp *rsp); + +/* + * Get eee params. + */ +struct ethtool_eee_get_rsp * +ethtool_eee_get(struct ynl_sock *ys, struct ethtool_eee_get_req *req); + +/* ETHTOOL_MSG_EEE_GET - dump */ +struct ethtool_eee_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_eee_get_req_dump * +ethtool_eee_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_eee_get_req_dump)); +} +void ethtool_eee_get_req_dump_free(struct ethtool_eee_get_req_dump *req); + +static inline void +ethtool_eee_get_req_dump_set_header_dev_index(struct ethtool_eee_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_eee_get_req_dump_set_header_dev_name(struct ethtool_eee_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_eee_get_req_dump_set_header_flags(struct ethtool_eee_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_eee_get_list { + struct ethtool_eee_get_list *next; + struct ethtool_eee_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_eee_get_list_free(struct ethtool_eee_get_list *rsp); + +struct ethtool_eee_get_list * +ethtool_eee_get_dump(struct ynl_sock *ys, struct ethtool_eee_get_req_dump *req); + +/* ETHTOOL_MSG_EEE_GET - notify */ +struct ethtool_eee_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_eee_get_ntf *ntf); + struct ethtool_eee_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_eee_get_ntf_free(struct ethtool_eee_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_EEE_SET ============== */ +/* ETHTOOL_MSG_EEE_SET - do */ +struct ethtool_eee_set_req { + struct { + __u32 header:1; + __u32 modes_ours:1; + __u32 modes_peer:1; + __u32 active:1; + __u32 enabled:1; + __u32 tx_lpi_enabled:1; + __u32 tx_lpi_timer:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset modes_ours; + struct ethtool_bitset modes_peer; + __u8 active; + __u8 enabled; + __u8 tx_lpi_enabled; + __u32 tx_lpi_timer; +}; + +static inline struct ethtool_eee_set_req *ethtool_eee_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_eee_set_req)); +} +void ethtool_eee_set_req_free(struct ethtool_eee_set_req *req); + +static inline void +ethtool_eee_set_req_set_header_dev_index(struct ethtool_eee_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_eee_set_req_set_header_dev_name(struct ethtool_eee_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_eee_set_req_set_header_flags(struct ethtool_eee_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_eee_set_req_set_modes_ours_nomask(struct ethtool_eee_set_req *req) +{ + req->_present.modes_ours = 1; + req->modes_ours._present.nomask = 1; +} +static inline void +ethtool_eee_set_req_set_modes_ours_size(struct ethtool_eee_set_req *req, + __u32 size) +{ + req->_present.modes_ours = 1; + req->modes_ours._present.size = 1; + req->modes_ours.size = size; +} +static inline void +__ethtool_eee_set_req_set_modes_ours_bits_bit(struct ethtool_eee_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->modes_ours.bits.bit); + req->modes_ours.bits.bit = bit; + req->modes_ours.bits.n_bit = n_bit; +} +static inline void +ethtool_eee_set_req_set_modes_peer_nomask(struct ethtool_eee_set_req *req) +{ + req->_present.modes_peer = 1; + req->modes_peer._present.nomask = 1; +} +static inline void +ethtool_eee_set_req_set_modes_peer_size(struct ethtool_eee_set_req *req, + __u32 size) +{ + req->_present.modes_peer = 1; + req->modes_peer._present.size = 1; + req->modes_peer.size = size; +} +static inline void +__ethtool_eee_set_req_set_modes_peer_bits_bit(struct ethtool_eee_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->modes_peer.bits.bit); + req->modes_peer.bits.bit = bit; + req->modes_peer.bits.n_bit = n_bit; +} +static inline void +ethtool_eee_set_req_set_active(struct ethtool_eee_set_req *req, __u8 active) +{ + req->_present.active = 1; + req->active = active; +} +static inline void +ethtool_eee_set_req_set_enabled(struct ethtool_eee_set_req *req, __u8 enabled) +{ + req->_present.enabled = 1; + req->enabled = enabled; +} +static inline void +ethtool_eee_set_req_set_tx_lpi_enabled(struct ethtool_eee_set_req *req, + __u8 tx_lpi_enabled) +{ + req->_present.tx_lpi_enabled = 1; + req->tx_lpi_enabled = tx_lpi_enabled; +} +static inline void +ethtool_eee_set_req_set_tx_lpi_timer(struct ethtool_eee_set_req *req, + __u32 tx_lpi_timer) +{ + req->_present.tx_lpi_timer = 1; + req->tx_lpi_timer = tx_lpi_timer; +} + +/* + * Set eee params. + */ +int ethtool_eee_set(struct ynl_sock *ys, struct ethtool_eee_set_req *req); + +/* ============== ETHTOOL_MSG_TSINFO_GET ============== */ +/* ETHTOOL_MSG_TSINFO_GET - do */ +struct ethtool_tsinfo_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_tsinfo_get_req *ethtool_tsinfo_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_tsinfo_get_req)); +} +void ethtool_tsinfo_get_req_free(struct ethtool_tsinfo_get_req *req); + +static inline void +ethtool_tsinfo_get_req_set_header_dev_index(struct ethtool_tsinfo_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_tsinfo_get_req_set_header_dev_name(struct ethtool_tsinfo_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_tsinfo_get_req_set_header_flags(struct ethtool_tsinfo_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_tsinfo_get_rsp { + struct { + __u32 header:1; + __u32 timestamping:1; + __u32 tx_types:1; + __u32 rx_filters:1; + __u32 phc_index:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset timestamping; + struct ethtool_bitset tx_types; + struct ethtool_bitset rx_filters; + __u32 phc_index; +}; + +void ethtool_tsinfo_get_rsp_free(struct ethtool_tsinfo_get_rsp *rsp); + +/* + * Get tsinfo params. + */ +struct ethtool_tsinfo_get_rsp * +ethtool_tsinfo_get(struct ynl_sock *ys, struct ethtool_tsinfo_get_req *req); + +/* ETHTOOL_MSG_TSINFO_GET - dump */ +struct ethtool_tsinfo_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_tsinfo_get_req_dump * +ethtool_tsinfo_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_tsinfo_get_req_dump)); +} +void ethtool_tsinfo_get_req_dump_free(struct ethtool_tsinfo_get_req_dump *req); + +static inline void +ethtool_tsinfo_get_req_dump_set_header_dev_index(struct ethtool_tsinfo_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_tsinfo_get_req_dump_set_header_dev_name(struct ethtool_tsinfo_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_tsinfo_get_req_dump_set_header_flags(struct ethtool_tsinfo_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_tsinfo_get_list { + struct ethtool_tsinfo_get_list *next; + struct ethtool_tsinfo_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_tsinfo_get_list_free(struct ethtool_tsinfo_get_list *rsp); + +struct ethtool_tsinfo_get_list * +ethtool_tsinfo_get_dump(struct ynl_sock *ys, + struct ethtool_tsinfo_get_req_dump *req); + +/* ============== ETHTOOL_MSG_CABLE_TEST_ACT ============== */ +/* ETHTOOL_MSG_CABLE_TEST_ACT - do */ +struct ethtool_cable_test_act_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_cable_test_act_req * +ethtool_cable_test_act_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_cable_test_act_req)); +} +void ethtool_cable_test_act_req_free(struct ethtool_cable_test_act_req *req); + +static inline void +ethtool_cable_test_act_req_set_header_dev_index(struct ethtool_cable_test_act_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_cable_test_act_req_set_header_dev_name(struct ethtool_cable_test_act_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_cable_test_act_req_set_header_flags(struct ethtool_cable_test_act_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +/* + * Cable test. + */ +int ethtool_cable_test_act(struct ynl_sock *ys, + struct ethtool_cable_test_act_req *req); + +/* ============== ETHTOOL_MSG_CABLE_TEST_TDR_ACT ============== */ +/* ETHTOOL_MSG_CABLE_TEST_TDR_ACT - do */ +struct ethtool_cable_test_tdr_act_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_cable_test_tdr_act_req * +ethtool_cable_test_tdr_act_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_cable_test_tdr_act_req)); +} +void +ethtool_cable_test_tdr_act_req_free(struct ethtool_cable_test_tdr_act_req *req); + +static inline void +ethtool_cable_test_tdr_act_req_set_header_dev_index(struct ethtool_cable_test_tdr_act_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_cable_test_tdr_act_req_set_header_dev_name(struct ethtool_cable_test_tdr_act_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_cable_test_tdr_act_req_set_header_flags(struct ethtool_cable_test_tdr_act_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +/* + * Cable test TDR. + */ +int ethtool_cable_test_tdr_act(struct ynl_sock *ys, + struct ethtool_cable_test_tdr_act_req *req); + +/* ============== ETHTOOL_MSG_TUNNEL_INFO_GET ============== */ +/* ETHTOOL_MSG_TUNNEL_INFO_GET - do */ +struct ethtool_tunnel_info_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_tunnel_info_get_req * +ethtool_tunnel_info_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_tunnel_info_get_req)); +} +void ethtool_tunnel_info_get_req_free(struct ethtool_tunnel_info_get_req *req); + +static inline void +ethtool_tunnel_info_get_req_set_header_dev_index(struct ethtool_tunnel_info_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_tunnel_info_get_req_set_header_dev_name(struct ethtool_tunnel_info_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_tunnel_info_get_req_set_header_flags(struct ethtool_tunnel_info_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_tunnel_info_get_rsp { + struct { + __u32 header:1; + __u32 udp_ports:1; + } _present; + + struct ethtool_header header; + struct ethtool_tunnel_udp udp_ports; +}; + +void ethtool_tunnel_info_get_rsp_free(struct ethtool_tunnel_info_get_rsp *rsp); + +/* + * Get tsinfo params. + */ +struct ethtool_tunnel_info_get_rsp * +ethtool_tunnel_info_get(struct ynl_sock *ys, + struct ethtool_tunnel_info_get_req *req); + +/* ETHTOOL_MSG_TUNNEL_INFO_GET - dump */ +struct ethtool_tunnel_info_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_tunnel_info_get_req_dump * +ethtool_tunnel_info_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_tunnel_info_get_req_dump)); +} +void +ethtool_tunnel_info_get_req_dump_free(struct ethtool_tunnel_info_get_req_dump *req); + +static inline void +ethtool_tunnel_info_get_req_dump_set_header_dev_index(struct ethtool_tunnel_info_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_tunnel_info_get_req_dump_set_header_dev_name(struct ethtool_tunnel_info_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_tunnel_info_get_req_dump_set_header_flags(struct ethtool_tunnel_info_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_tunnel_info_get_list { + struct ethtool_tunnel_info_get_list *next; + struct ethtool_tunnel_info_get_rsp obj __attribute__ ((aligned (8))); +}; + +void +ethtool_tunnel_info_get_list_free(struct ethtool_tunnel_info_get_list *rsp); + +struct ethtool_tunnel_info_get_list * +ethtool_tunnel_info_get_dump(struct ynl_sock *ys, + struct ethtool_tunnel_info_get_req_dump *req); + +/* ============== ETHTOOL_MSG_FEC_GET ============== */ +/* ETHTOOL_MSG_FEC_GET - do */ +struct ethtool_fec_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_fec_get_req *ethtool_fec_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_fec_get_req)); +} +void ethtool_fec_get_req_free(struct ethtool_fec_get_req *req); + +static inline void +ethtool_fec_get_req_set_header_dev_index(struct ethtool_fec_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_fec_get_req_set_header_dev_name(struct ethtool_fec_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_fec_get_req_set_header_flags(struct ethtool_fec_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_fec_get_rsp { + struct { + __u32 header:1; + __u32 modes:1; + __u32 auto_:1; + __u32 active:1; + __u32 stats:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset modes; + __u8 auto_; + __u32 active; + struct ethtool_fec_stat stats; +}; + +void ethtool_fec_get_rsp_free(struct ethtool_fec_get_rsp *rsp); + +/* + * Get FEC params. + */ +struct ethtool_fec_get_rsp * +ethtool_fec_get(struct ynl_sock *ys, struct ethtool_fec_get_req *req); + +/* ETHTOOL_MSG_FEC_GET - dump */ +struct ethtool_fec_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_fec_get_req_dump * +ethtool_fec_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_fec_get_req_dump)); +} +void ethtool_fec_get_req_dump_free(struct ethtool_fec_get_req_dump *req); + +static inline void +ethtool_fec_get_req_dump_set_header_dev_index(struct ethtool_fec_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_fec_get_req_dump_set_header_dev_name(struct ethtool_fec_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_fec_get_req_dump_set_header_flags(struct ethtool_fec_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_fec_get_list { + struct ethtool_fec_get_list *next; + struct ethtool_fec_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_fec_get_list_free(struct ethtool_fec_get_list *rsp); + +struct ethtool_fec_get_list * +ethtool_fec_get_dump(struct ynl_sock *ys, struct ethtool_fec_get_req_dump *req); + +/* ETHTOOL_MSG_FEC_GET - notify */ +struct ethtool_fec_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_fec_get_ntf *ntf); + struct ethtool_fec_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_fec_get_ntf_free(struct ethtool_fec_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_FEC_SET ============== */ +/* ETHTOOL_MSG_FEC_SET - do */ +struct ethtool_fec_set_req { + struct { + __u32 header:1; + __u32 modes:1; + __u32 auto_:1; + __u32 active:1; + __u32 stats:1; + } _present; + + struct ethtool_header header; + struct ethtool_bitset modes; + __u8 auto_; + __u32 active; + struct ethtool_fec_stat stats; +}; + +static inline struct ethtool_fec_set_req *ethtool_fec_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_fec_set_req)); +} +void ethtool_fec_set_req_free(struct ethtool_fec_set_req *req); + +static inline void +ethtool_fec_set_req_set_header_dev_index(struct ethtool_fec_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_fec_set_req_set_header_dev_name(struct ethtool_fec_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_fec_set_req_set_header_flags(struct ethtool_fec_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_fec_set_req_set_modes_nomask(struct ethtool_fec_set_req *req) +{ + req->_present.modes = 1; + req->modes._present.nomask = 1; +} +static inline void +ethtool_fec_set_req_set_modes_size(struct ethtool_fec_set_req *req, __u32 size) +{ + req->_present.modes = 1; + req->modes._present.size = 1; + req->modes.size = size; +} +static inline void +__ethtool_fec_set_req_set_modes_bits_bit(struct ethtool_fec_set_req *req, + struct ethtool_bitset_bit *bit, + unsigned int n_bit) +{ + free(req->modes.bits.bit); + req->modes.bits.bit = bit; + req->modes.bits.n_bit = n_bit; +} +static inline void +ethtool_fec_set_req_set_auto_(struct ethtool_fec_set_req *req, __u8 auto_) +{ + req->_present.auto_ = 1; + req->auto_ = auto_; +} +static inline void +ethtool_fec_set_req_set_active(struct ethtool_fec_set_req *req, __u32 active) +{ + req->_present.active = 1; + req->active = active; +} +static inline void +ethtool_fec_set_req_set_stats_corrected(struct ethtool_fec_set_req *req, + const void *corrected, size_t len) +{ + free(req->stats.corrected); + req->stats.corrected = malloc(req->stats._present.corrected_len); + memcpy(req->stats.corrected, corrected, req->stats._present.corrected_len); +} +static inline void +ethtool_fec_set_req_set_stats_uncorr(struct ethtool_fec_set_req *req, + const void *uncorr, size_t len) +{ + free(req->stats.uncorr); + req->stats.uncorr = malloc(req->stats._present.uncorr_len); + memcpy(req->stats.uncorr, uncorr, req->stats._present.uncorr_len); +} +static inline void +ethtool_fec_set_req_set_stats_corr_bits(struct ethtool_fec_set_req *req, + const void *corr_bits, size_t len) +{ + free(req->stats.corr_bits); + req->stats.corr_bits = malloc(req->stats._present.corr_bits_len); + memcpy(req->stats.corr_bits, corr_bits, req->stats._present.corr_bits_len); +} + +/* + * Set FEC params. + */ +int ethtool_fec_set(struct ynl_sock *ys, struct ethtool_fec_set_req *req); + +/* ============== ETHTOOL_MSG_MODULE_EEPROM_GET ============== */ +/* ETHTOOL_MSG_MODULE_EEPROM_GET - do */ +struct ethtool_module_eeprom_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_module_eeprom_get_req * +ethtool_module_eeprom_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_module_eeprom_get_req)); +} +void +ethtool_module_eeprom_get_req_free(struct ethtool_module_eeprom_get_req *req); + +static inline void +ethtool_module_eeprom_get_req_set_header_dev_index(struct ethtool_module_eeprom_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_module_eeprom_get_req_set_header_dev_name(struct ethtool_module_eeprom_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_module_eeprom_get_req_set_header_flags(struct ethtool_module_eeprom_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_module_eeprom_get_rsp { + struct { + __u32 header:1; + __u32 offset:1; + __u32 length:1; + __u32 page:1; + __u32 bank:1; + __u32 i2c_address:1; + __u32 data_len; + } _present; + + struct ethtool_header header; + __u32 offset; + __u32 length; + __u8 page; + __u8 bank; + __u8 i2c_address; + void *data; +}; + +void +ethtool_module_eeprom_get_rsp_free(struct ethtool_module_eeprom_get_rsp *rsp); + +/* + * Get module EEPROM params. + */ +struct ethtool_module_eeprom_get_rsp * +ethtool_module_eeprom_get(struct ynl_sock *ys, + struct ethtool_module_eeprom_get_req *req); + +/* ETHTOOL_MSG_MODULE_EEPROM_GET - dump */ +struct ethtool_module_eeprom_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_module_eeprom_get_req_dump * +ethtool_module_eeprom_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_module_eeprom_get_req_dump)); +} +void +ethtool_module_eeprom_get_req_dump_free(struct ethtool_module_eeprom_get_req_dump *req); + +static inline void +ethtool_module_eeprom_get_req_dump_set_header_dev_index(struct ethtool_module_eeprom_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_module_eeprom_get_req_dump_set_header_dev_name(struct ethtool_module_eeprom_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_module_eeprom_get_req_dump_set_header_flags(struct ethtool_module_eeprom_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_module_eeprom_get_list { + struct ethtool_module_eeprom_get_list *next; + struct ethtool_module_eeprom_get_rsp obj __attribute__ ((aligned (8))); +}; + +void +ethtool_module_eeprom_get_list_free(struct ethtool_module_eeprom_get_list *rsp); + +struct ethtool_module_eeprom_get_list * +ethtool_module_eeprom_get_dump(struct ynl_sock *ys, + struct ethtool_module_eeprom_get_req_dump *req); + +/* ============== ETHTOOL_MSG_PHC_VCLOCKS_GET ============== */ +/* ETHTOOL_MSG_PHC_VCLOCKS_GET - do */ +struct ethtool_phc_vclocks_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_phc_vclocks_get_req * +ethtool_phc_vclocks_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_phc_vclocks_get_req)); +} +void ethtool_phc_vclocks_get_req_free(struct ethtool_phc_vclocks_get_req *req); + +static inline void +ethtool_phc_vclocks_get_req_set_header_dev_index(struct ethtool_phc_vclocks_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_phc_vclocks_get_req_set_header_dev_name(struct ethtool_phc_vclocks_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_phc_vclocks_get_req_set_header_flags(struct ethtool_phc_vclocks_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_phc_vclocks_get_rsp { + struct { + __u32 header:1; + __u32 num:1; + } _present; + + struct ethtool_header header; + __u32 num; +}; + +void ethtool_phc_vclocks_get_rsp_free(struct ethtool_phc_vclocks_get_rsp *rsp); + +/* + * Get PHC VCLOCKs. + */ +struct ethtool_phc_vclocks_get_rsp * +ethtool_phc_vclocks_get(struct ynl_sock *ys, + struct ethtool_phc_vclocks_get_req *req); + +/* ETHTOOL_MSG_PHC_VCLOCKS_GET - dump */ +struct ethtool_phc_vclocks_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_phc_vclocks_get_req_dump * +ethtool_phc_vclocks_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_phc_vclocks_get_req_dump)); +} +void +ethtool_phc_vclocks_get_req_dump_free(struct ethtool_phc_vclocks_get_req_dump *req); + +static inline void +ethtool_phc_vclocks_get_req_dump_set_header_dev_index(struct ethtool_phc_vclocks_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_phc_vclocks_get_req_dump_set_header_dev_name(struct ethtool_phc_vclocks_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_phc_vclocks_get_req_dump_set_header_flags(struct ethtool_phc_vclocks_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_phc_vclocks_get_list { + struct ethtool_phc_vclocks_get_list *next; + struct ethtool_phc_vclocks_get_rsp obj __attribute__ ((aligned (8))); +}; + +void +ethtool_phc_vclocks_get_list_free(struct ethtool_phc_vclocks_get_list *rsp); + +struct ethtool_phc_vclocks_get_list * +ethtool_phc_vclocks_get_dump(struct ynl_sock *ys, + struct ethtool_phc_vclocks_get_req_dump *req); + +/* ============== ETHTOOL_MSG_MODULE_GET ============== */ +/* ETHTOOL_MSG_MODULE_GET - do */ +struct ethtool_module_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_module_get_req *ethtool_module_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_module_get_req)); +} +void ethtool_module_get_req_free(struct ethtool_module_get_req *req); + +static inline void +ethtool_module_get_req_set_header_dev_index(struct ethtool_module_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_module_get_req_set_header_dev_name(struct ethtool_module_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_module_get_req_set_header_flags(struct ethtool_module_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_module_get_rsp { + struct { + __u32 header:1; + __u32 power_mode_policy:1; + __u32 power_mode:1; + } _present; + + struct ethtool_header header; + __u8 power_mode_policy; + __u8 power_mode; +}; + +void ethtool_module_get_rsp_free(struct ethtool_module_get_rsp *rsp); + +/* + * Get module params. + */ +struct ethtool_module_get_rsp * +ethtool_module_get(struct ynl_sock *ys, struct ethtool_module_get_req *req); + +/* ETHTOOL_MSG_MODULE_GET - dump */ +struct ethtool_module_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_module_get_req_dump * +ethtool_module_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_module_get_req_dump)); +} +void ethtool_module_get_req_dump_free(struct ethtool_module_get_req_dump *req); + +static inline void +ethtool_module_get_req_dump_set_header_dev_index(struct ethtool_module_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_module_get_req_dump_set_header_dev_name(struct ethtool_module_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_module_get_req_dump_set_header_flags(struct ethtool_module_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_module_get_list { + struct ethtool_module_get_list *next; + struct ethtool_module_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_module_get_list_free(struct ethtool_module_get_list *rsp); + +struct ethtool_module_get_list * +ethtool_module_get_dump(struct ynl_sock *ys, + struct ethtool_module_get_req_dump *req); + +/* ETHTOOL_MSG_MODULE_GET - notify */ +struct ethtool_module_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_module_get_ntf *ntf); + struct ethtool_module_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_module_get_ntf_free(struct ethtool_module_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_MODULE_SET ============== */ +/* ETHTOOL_MSG_MODULE_SET - do */ +struct ethtool_module_set_req { + struct { + __u32 header:1; + __u32 power_mode_policy:1; + __u32 power_mode:1; + } _present; + + struct ethtool_header header; + __u8 power_mode_policy; + __u8 power_mode; +}; + +static inline struct ethtool_module_set_req *ethtool_module_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_module_set_req)); +} +void ethtool_module_set_req_free(struct ethtool_module_set_req *req); + +static inline void +ethtool_module_set_req_set_header_dev_index(struct ethtool_module_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_module_set_req_set_header_dev_name(struct ethtool_module_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_module_set_req_set_header_flags(struct ethtool_module_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_module_set_req_set_power_mode_policy(struct ethtool_module_set_req *req, + __u8 power_mode_policy) +{ + req->_present.power_mode_policy = 1; + req->power_mode_policy = power_mode_policy; +} +static inline void +ethtool_module_set_req_set_power_mode(struct ethtool_module_set_req *req, + __u8 power_mode) +{ + req->_present.power_mode = 1; + req->power_mode = power_mode; +} + +/* + * Set module params. + */ +int ethtool_module_set(struct ynl_sock *ys, struct ethtool_module_set_req *req); + +/* ============== ETHTOOL_MSG_PSE_GET ============== */ +/* ETHTOOL_MSG_PSE_GET - do */ +struct ethtool_pse_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_pse_get_req *ethtool_pse_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_pse_get_req)); +} +void ethtool_pse_get_req_free(struct ethtool_pse_get_req *req); + +static inline void +ethtool_pse_get_req_set_header_dev_index(struct ethtool_pse_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_pse_get_req_set_header_dev_name(struct ethtool_pse_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_pse_get_req_set_header_flags(struct ethtool_pse_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_pse_get_rsp { + struct { + __u32 header:1; + __u32 admin_state:1; + __u32 admin_control:1; + __u32 pw_d_status:1; + } _present; + + struct ethtool_header header; + __u32 admin_state; + __u32 admin_control; + __u32 pw_d_status; +}; + +void ethtool_pse_get_rsp_free(struct ethtool_pse_get_rsp *rsp); + +/* + * Get Power Sourcing Equipment params. + */ +struct ethtool_pse_get_rsp * +ethtool_pse_get(struct ynl_sock *ys, struct ethtool_pse_get_req *req); + +/* ETHTOOL_MSG_PSE_GET - dump */ +struct ethtool_pse_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_pse_get_req_dump * +ethtool_pse_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_pse_get_req_dump)); +} +void ethtool_pse_get_req_dump_free(struct ethtool_pse_get_req_dump *req); + +static inline void +ethtool_pse_get_req_dump_set_header_dev_index(struct ethtool_pse_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_pse_get_req_dump_set_header_dev_name(struct ethtool_pse_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_pse_get_req_dump_set_header_flags(struct ethtool_pse_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_pse_get_list { + struct ethtool_pse_get_list *next; + struct ethtool_pse_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_pse_get_list_free(struct ethtool_pse_get_list *rsp); + +struct ethtool_pse_get_list * +ethtool_pse_get_dump(struct ynl_sock *ys, struct ethtool_pse_get_req_dump *req); + +/* ============== ETHTOOL_MSG_PSE_SET ============== */ +/* ETHTOOL_MSG_PSE_SET - do */ +struct ethtool_pse_set_req { + struct { + __u32 header:1; + __u32 admin_state:1; + __u32 admin_control:1; + __u32 pw_d_status:1; + } _present; + + struct ethtool_header header; + __u32 admin_state; + __u32 admin_control; + __u32 pw_d_status; +}; + +static inline struct ethtool_pse_set_req *ethtool_pse_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_pse_set_req)); +} +void ethtool_pse_set_req_free(struct ethtool_pse_set_req *req); + +static inline void +ethtool_pse_set_req_set_header_dev_index(struct ethtool_pse_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_pse_set_req_set_header_dev_name(struct ethtool_pse_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_pse_set_req_set_header_flags(struct ethtool_pse_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_pse_set_req_set_admin_state(struct ethtool_pse_set_req *req, + __u32 admin_state) +{ + req->_present.admin_state = 1; + req->admin_state = admin_state; +} +static inline void +ethtool_pse_set_req_set_admin_control(struct ethtool_pse_set_req *req, + __u32 admin_control) +{ + req->_present.admin_control = 1; + req->admin_control = admin_control; +} +static inline void +ethtool_pse_set_req_set_pw_d_status(struct ethtool_pse_set_req *req, + __u32 pw_d_status) +{ + req->_present.pw_d_status = 1; + req->pw_d_status = pw_d_status; +} + +/* + * Set Power Sourcing Equipment params. + */ +int ethtool_pse_set(struct ynl_sock *ys, struct ethtool_pse_set_req *req); + +/* ============== ETHTOOL_MSG_RSS_GET ============== */ +/* ETHTOOL_MSG_RSS_GET - do */ +struct ethtool_rss_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_rss_get_req *ethtool_rss_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_rss_get_req)); +} +void ethtool_rss_get_req_free(struct ethtool_rss_get_req *req); + +static inline void +ethtool_rss_get_req_set_header_dev_index(struct ethtool_rss_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_rss_get_req_set_header_dev_name(struct ethtool_rss_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_rss_get_req_set_header_flags(struct ethtool_rss_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_rss_get_rsp { + struct { + __u32 header:1; + __u32 context:1; + __u32 hfunc:1; + __u32 indir_len; + __u32 hkey_len; + } _present; + + struct ethtool_header header; + __u32 context; + __u32 hfunc; + void *indir; + void *hkey; +}; + +void ethtool_rss_get_rsp_free(struct ethtool_rss_get_rsp *rsp); + +/* + * Get RSS params. + */ +struct ethtool_rss_get_rsp * +ethtool_rss_get(struct ynl_sock *ys, struct ethtool_rss_get_req *req); + +/* ETHTOOL_MSG_RSS_GET - dump */ +struct ethtool_rss_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_rss_get_req_dump * +ethtool_rss_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_rss_get_req_dump)); +} +void ethtool_rss_get_req_dump_free(struct ethtool_rss_get_req_dump *req); + +static inline void +ethtool_rss_get_req_dump_set_header_dev_index(struct ethtool_rss_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_rss_get_req_dump_set_header_dev_name(struct ethtool_rss_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_rss_get_req_dump_set_header_flags(struct ethtool_rss_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_rss_get_list { + struct ethtool_rss_get_list *next; + struct ethtool_rss_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_rss_get_list_free(struct ethtool_rss_get_list *rsp); + +struct ethtool_rss_get_list * +ethtool_rss_get_dump(struct ynl_sock *ys, struct ethtool_rss_get_req_dump *req); + +/* ============== ETHTOOL_MSG_PLCA_GET_CFG ============== */ +/* ETHTOOL_MSG_PLCA_GET_CFG - do */ +struct ethtool_plca_get_cfg_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_plca_get_cfg_req * +ethtool_plca_get_cfg_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_plca_get_cfg_req)); +} +void ethtool_plca_get_cfg_req_free(struct ethtool_plca_get_cfg_req *req); + +static inline void +ethtool_plca_get_cfg_req_set_header_dev_index(struct ethtool_plca_get_cfg_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_plca_get_cfg_req_set_header_dev_name(struct ethtool_plca_get_cfg_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_plca_get_cfg_req_set_header_flags(struct ethtool_plca_get_cfg_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_plca_get_cfg_rsp { + struct { + __u32 header:1; + __u32 version:1; + __u32 enabled:1; + __u32 status:1; + __u32 node_cnt:1; + __u32 node_id:1; + __u32 to_tmr:1; + __u32 burst_cnt:1; + __u32 burst_tmr:1; + } _present; + + struct ethtool_header header; + __u16 version; + __u8 enabled; + __u8 status; + __u32 node_cnt; + __u32 node_id; + __u32 to_tmr; + __u32 burst_cnt; + __u32 burst_tmr; +}; + +void ethtool_plca_get_cfg_rsp_free(struct ethtool_plca_get_cfg_rsp *rsp); + +/* + * Get PLCA params. + */ +struct ethtool_plca_get_cfg_rsp * +ethtool_plca_get_cfg(struct ynl_sock *ys, struct ethtool_plca_get_cfg_req *req); + +/* ETHTOOL_MSG_PLCA_GET_CFG - dump */ +struct ethtool_plca_get_cfg_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_plca_get_cfg_req_dump * +ethtool_plca_get_cfg_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_plca_get_cfg_req_dump)); +} +void +ethtool_plca_get_cfg_req_dump_free(struct ethtool_plca_get_cfg_req_dump *req); + +static inline void +ethtool_plca_get_cfg_req_dump_set_header_dev_index(struct ethtool_plca_get_cfg_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_plca_get_cfg_req_dump_set_header_dev_name(struct ethtool_plca_get_cfg_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_plca_get_cfg_req_dump_set_header_flags(struct ethtool_plca_get_cfg_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_plca_get_cfg_list { + struct ethtool_plca_get_cfg_list *next; + struct ethtool_plca_get_cfg_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_plca_get_cfg_list_free(struct ethtool_plca_get_cfg_list *rsp); + +struct ethtool_plca_get_cfg_list * +ethtool_plca_get_cfg_dump(struct ynl_sock *ys, + struct ethtool_plca_get_cfg_req_dump *req); + +/* ETHTOOL_MSG_PLCA_GET_CFG - notify */ +struct ethtool_plca_get_cfg_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_plca_get_cfg_ntf *ntf); + struct ethtool_plca_get_cfg_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_plca_get_cfg_ntf_free(struct ethtool_plca_get_cfg_ntf *rsp); + +/* ============== ETHTOOL_MSG_PLCA_SET_CFG ============== */ +/* ETHTOOL_MSG_PLCA_SET_CFG - do */ +struct ethtool_plca_set_cfg_req { + struct { + __u32 header:1; + __u32 version:1; + __u32 enabled:1; + __u32 status:1; + __u32 node_cnt:1; + __u32 node_id:1; + __u32 to_tmr:1; + __u32 burst_cnt:1; + __u32 burst_tmr:1; + } _present; + + struct ethtool_header header; + __u16 version; + __u8 enabled; + __u8 status; + __u32 node_cnt; + __u32 node_id; + __u32 to_tmr; + __u32 burst_cnt; + __u32 burst_tmr; +}; + +static inline struct ethtool_plca_set_cfg_req * +ethtool_plca_set_cfg_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_plca_set_cfg_req)); +} +void ethtool_plca_set_cfg_req_free(struct ethtool_plca_set_cfg_req *req); + +static inline void +ethtool_plca_set_cfg_req_set_header_dev_index(struct ethtool_plca_set_cfg_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_plca_set_cfg_req_set_header_dev_name(struct ethtool_plca_set_cfg_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_plca_set_cfg_req_set_header_flags(struct ethtool_plca_set_cfg_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_plca_set_cfg_req_set_version(struct ethtool_plca_set_cfg_req *req, + __u16 version) +{ + req->_present.version = 1; + req->version = version; +} +static inline void +ethtool_plca_set_cfg_req_set_enabled(struct ethtool_plca_set_cfg_req *req, + __u8 enabled) +{ + req->_present.enabled = 1; + req->enabled = enabled; +} +static inline void +ethtool_plca_set_cfg_req_set_status(struct ethtool_plca_set_cfg_req *req, + __u8 status) +{ + req->_present.status = 1; + req->status = status; +} +static inline void +ethtool_plca_set_cfg_req_set_node_cnt(struct ethtool_plca_set_cfg_req *req, + __u32 node_cnt) +{ + req->_present.node_cnt = 1; + req->node_cnt = node_cnt; +} +static inline void +ethtool_plca_set_cfg_req_set_node_id(struct ethtool_plca_set_cfg_req *req, + __u32 node_id) +{ + req->_present.node_id = 1; + req->node_id = node_id; +} +static inline void +ethtool_plca_set_cfg_req_set_to_tmr(struct ethtool_plca_set_cfg_req *req, + __u32 to_tmr) +{ + req->_present.to_tmr = 1; + req->to_tmr = to_tmr; +} +static inline void +ethtool_plca_set_cfg_req_set_burst_cnt(struct ethtool_plca_set_cfg_req *req, + __u32 burst_cnt) +{ + req->_present.burst_cnt = 1; + req->burst_cnt = burst_cnt; +} +static inline void +ethtool_plca_set_cfg_req_set_burst_tmr(struct ethtool_plca_set_cfg_req *req, + __u32 burst_tmr) +{ + req->_present.burst_tmr = 1; + req->burst_tmr = burst_tmr; +} + +/* + * Set PLCA params. + */ +int ethtool_plca_set_cfg(struct ynl_sock *ys, + struct ethtool_plca_set_cfg_req *req); + +/* ============== ETHTOOL_MSG_PLCA_GET_STATUS ============== */ +/* ETHTOOL_MSG_PLCA_GET_STATUS - do */ +struct ethtool_plca_get_status_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_plca_get_status_req * +ethtool_plca_get_status_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_plca_get_status_req)); +} +void ethtool_plca_get_status_req_free(struct ethtool_plca_get_status_req *req); + +static inline void +ethtool_plca_get_status_req_set_header_dev_index(struct ethtool_plca_get_status_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_plca_get_status_req_set_header_dev_name(struct ethtool_plca_get_status_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_plca_get_status_req_set_header_flags(struct ethtool_plca_get_status_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_plca_get_status_rsp { + struct { + __u32 header:1; + __u32 version:1; + __u32 enabled:1; + __u32 status:1; + __u32 node_cnt:1; + __u32 node_id:1; + __u32 to_tmr:1; + __u32 burst_cnt:1; + __u32 burst_tmr:1; + } _present; + + struct ethtool_header header; + __u16 version; + __u8 enabled; + __u8 status; + __u32 node_cnt; + __u32 node_id; + __u32 to_tmr; + __u32 burst_cnt; + __u32 burst_tmr; +}; + +void ethtool_plca_get_status_rsp_free(struct ethtool_plca_get_status_rsp *rsp); + +/* + * Get PLCA status params. + */ +struct ethtool_plca_get_status_rsp * +ethtool_plca_get_status(struct ynl_sock *ys, + struct ethtool_plca_get_status_req *req); + +/* ETHTOOL_MSG_PLCA_GET_STATUS - dump */ +struct ethtool_plca_get_status_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_plca_get_status_req_dump * +ethtool_plca_get_status_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_plca_get_status_req_dump)); +} +void +ethtool_plca_get_status_req_dump_free(struct ethtool_plca_get_status_req_dump *req); + +static inline void +ethtool_plca_get_status_req_dump_set_header_dev_index(struct ethtool_plca_get_status_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_plca_get_status_req_dump_set_header_dev_name(struct ethtool_plca_get_status_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_plca_get_status_req_dump_set_header_flags(struct ethtool_plca_get_status_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_plca_get_status_list { + struct ethtool_plca_get_status_list *next; + struct ethtool_plca_get_status_rsp obj __attribute__ ((aligned (8))); +}; + +void +ethtool_plca_get_status_list_free(struct ethtool_plca_get_status_list *rsp); + +struct ethtool_plca_get_status_list * +ethtool_plca_get_status_dump(struct ynl_sock *ys, + struct ethtool_plca_get_status_req_dump *req); + +/* ============== ETHTOOL_MSG_MM_GET ============== */ +/* ETHTOOL_MSG_MM_GET - do */ +struct ethtool_mm_get_req { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_mm_get_req *ethtool_mm_get_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_mm_get_req)); +} +void ethtool_mm_get_req_free(struct ethtool_mm_get_req *req); + +static inline void +ethtool_mm_get_req_set_header_dev_index(struct ethtool_mm_get_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_mm_get_req_set_header_dev_name(struct ethtool_mm_get_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_mm_get_req_set_header_flags(struct ethtool_mm_get_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_mm_get_rsp { + struct { + __u32 header:1; + __u32 pmac_enabled:1; + __u32 tx_enabled:1; + __u32 tx_active:1; + __u32 tx_min_frag_size:1; + __u32 rx_min_frag_size:1; + __u32 verify_enabled:1; + __u32 verify_time:1; + __u32 max_verify_time:1; + __u32 stats:1; + } _present; + + struct ethtool_header header; + __u8 pmac_enabled; + __u8 tx_enabled; + __u8 tx_active; + __u32 tx_min_frag_size; + __u32 rx_min_frag_size; + __u8 verify_enabled; + __u32 verify_time; + __u32 max_verify_time; + struct ethtool_mm_stat stats; +}; + +void ethtool_mm_get_rsp_free(struct ethtool_mm_get_rsp *rsp); + +/* + * Get MAC Merge configuration and state + */ +struct ethtool_mm_get_rsp * +ethtool_mm_get(struct ynl_sock *ys, struct ethtool_mm_get_req *req); + +/* ETHTOOL_MSG_MM_GET - dump */ +struct ethtool_mm_get_req_dump { + struct { + __u32 header:1; + } _present; + + struct ethtool_header header; +}; + +static inline struct ethtool_mm_get_req_dump * +ethtool_mm_get_req_dump_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_mm_get_req_dump)); +} +void ethtool_mm_get_req_dump_free(struct ethtool_mm_get_req_dump *req); + +static inline void +ethtool_mm_get_req_dump_set_header_dev_index(struct ethtool_mm_get_req_dump *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_mm_get_req_dump_set_header_dev_name(struct ethtool_mm_get_req_dump *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_mm_get_req_dump_set_header_flags(struct ethtool_mm_get_req_dump *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} + +struct ethtool_mm_get_list { + struct ethtool_mm_get_list *next; + struct ethtool_mm_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_mm_get_list_free(struct ethtool_mm_get_list *rsp); + +struct ethtool_mm_get_list * +ethtool_mm_get_dump(struct ynl_sock *ys, struct ethtool_mm_get_req_dump *req); + +/* ETHTOOL_MSG_MM_GET - notify */ +struct ethtool_mm_get_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_mm_get_ntf *ntf); + struct ethtool_mm_get_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_mm_get_ntf_free(struct ethtool_mm_get_ntf *rsp); + +/* ============== ETHTOOL_MSG_MM_SET ============== */ +/* ETHTOOL_MSG_MM_SET - do */ +struct ethtool_mm_set_req { + struct { + __u32 header:1; + __u32 verify_enabled:1; + __u32 verify_time:1; + __u32 tx_enabled:1; + __u32 pmac_enabled:1; + __u32 tx_min_frag_size:1; + } _present; + + struct ethtool_header header; + __u8 verify_enabled; + __u32 verify_time; + __u8 tx_enabled; + __u8 pmac_enabled; + __u32 tx_min_frag_size; +}; + +static inline struct ethtool_mm_set_req *ethtool_mm_set_req_alloc(void) +{ + return calloc(1, sizeof(struct ethtool_mm_set_req)); +} +void ethtool_mm_set_req_free(struct ethtool_mm_set_req *req); + +static inline void +ethtool_mm_set_req_set_header_dev_index(struct ethtool_mm_set_req *req, + __u32 dev_index) +{ + req->_present.header = 1; + req->header._present.dev_index = 1; + req->header.dev_index = dev_index; +} +static inline void +ethtool_mm_set_req_set_header_dev_name(struct ethtool_mm_set_req *req, + const char *dev_name) +{ + free(req->header.dev_name); + req->header._present.dev_name_len = strlen(dev_name); + req->header.dev_name = malloc(req->header._present.dev_name_len + 1); + memcpy(req->header.dev_name, dev_name, req->header._present.dev_name_len); + req->header.dev_name[req->header._present.dev_name_len] = 0; +} +static inline void +ethtool_mm_set_req_set_header_flags(struct ethtool_mm_set_req *req, + __u32 flags) +{ + req->_present.header = 1; + req->header._present.flags = 1; + req->header.flags = flags; +} +static inline void +ethtool_mm_set_req_set_verify_enabled(struct ethtool_mm_set_req *req, + __u8 verify_enabled) +{ + req->_present.verify_enabled = 1; + req->verify_enabled = verify_enabled; +} +static inline void +ethtool_mm_set_req_set_verify_time(struct ethtool_mm_set_req *req, + __u32 verify_time) +{ + req->_present.verify_time = 1; + req->verify_time = verify_time; +} +static inline void +ethtool_mm_set_req_set_tx_enabled(struct ethtool_mm_set_req *req, + __u8 tx_enabled) +{ + req->_present.tx_enabled = 1; + req->tx_enabled = tx_enabled; +} +static inline void +ethtool_mm_set_req_set_pmac_enabled(struct ethtool_mm_set_req *req, + __u8 pmac_enabled) +{ + req->_present.pmac_enabled = 1; + req->pmac_enabled = pmac_enabled; +} +static inline void +ethtool_mm_set_req_set_tx_min_frag_size(struct ethtool_mm_set_req *req, + __u32 tx_min_frag_size) +{ + req->_present.tx_min_frag_size = 1; + req->tx_min_frag_size = tx_min_frag_size; +} + +/* + * Set MAC Merge configuration + */ +int ethtool_mm_set(struct ynl_sock *ys, struct ethtool_mm_set_req *req); + +/* ETHTOOL_MSG_CABLE_TEST_NTF - event */ +struct ethtool_cable_test_ntf_rsp { + struct { + __u32 header:1; + __u32 status:1; + } _present; + + struct ethtool_header header; + __u8 status; +}; + +struct ethtool_cable_test_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_cable_test_ntf *ntf); + struct ethtool_cable_test_ntf_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_cable_test_ntf_free(struct ethtool_cable_test_ntf *rsp); + +/* ETHTOOL_MSG_CABLE_TEST_TDR_NTF - event */ +struct ethtool_cable_test_tdr_ntf_rsp { + struct { + __u32 header:1; + __u32 status:1; + __u32 nest:1; + } _present; + + struct ethtool_header header; + __u8 status; + struct ethtool_cable_nest nest; +}; + +struct ethtool_cable_test_tdr_ntf { + __u16 family; + __u8 cmd; + struct ynl_ntf_base_type *next; + void (*free)(struct ethtool_cable_test_tdr_ntf *ntf); + struct ethtool_cable_test_tdr_ntf_rsp obj __attribute__ ((aligned (8))); +}; + +void ethtool_cable_test_tdr_ntf_free(struct ethtool_cable_test_tdr_ntf *rsp); + +#endif /* _LINUX_ETHTOOL_GEN_H */ -- cgit v1.2.3 From f561ff232a6b502bda020ac47200e88f0bc5f98a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:43:46 -0700 Subject: tools: ynl: add sample for ethtool Configuring / reading ring sizes and counts is a fairly common operation for ethtool netlink. Present a sample doing that with YNL: $ ./ethtool Channels: enp1s0: combined 1 eni1np1: combined 1 eni2np1: combined 1 Rings: enp1s0: rx 256 tx 256 eni1np1: rx 0 tx 0 eni2np1: rx 0 tx 0 Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/samples/.gitignore | 1 + tools/net/ynl/samples/ethtool.c | 65 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 tools/net/ynl/samples/ethtool.c diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore index a24678b67557..2aae60c4829f 100644 --- a/tools/net/ynl/samples/.gitignore +++ b/tools/net/ynl/samples/.gitignore @@ -1,2 +1,3 @@ +ethtool devlink netdev diff --git a/tools/net/ynl/samples/ethtool.c b/tools/net/ynl/samples/ethtool.c new file mode 100644 index 000000000000..a7ebbd1b98db --- /dev/null +++ b/tools/net/ynl/samples/ethtool.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include + +#include + +#include "ethtool-user.h" + +int main(int argc, char **argv) +{ + struct ethtool_channels_get_req_dump creq = {}; + struct ethtool_rings_get_req_dump rreq = {}; + struct ethtool_channels_get_list *channels; + struct ethtool_rings_get_list *rings; + struct ynl_sock *ys; + + ys = ynl_sock_create(&ynl_ethtool_family, NULL); + if (!ys) + return 1; + + creq._present.header = 1; /* ethtool needs an empty nest, sigh */ + channels = ethtool_channels_get_dump(ys, &creq); + if (!channels) + goto err_close; + + printf("Channels:\n"); + ynl_dump_foreach(channels, dev) { + printf(" %8s: ", dev->header.dev_name); + if (dev->_present.rx_count) + printf("rx %d ", dev->rx_count); + if (dev->_present.tx_count) + printf("tx %d ", dev->tx_count); + if (dev->_present.combined_count) + printf("combined %d ", dev->combined_count); + printf("\n"); + } + ethtool_channels_get_list_free(channels); + + rreq._present.header = 1; /* ethtool needs an empty nest.. */ + rings = ethtool_rings_get_dump(ys, &rreq); + if (!rings) + goto err_close; + + printf("Rings:\n"); + ynl_dump_foreach(rings, dev) { + printf(" %8s: ", dev->header.dev_name); + if (dev->_present.rx) + printf("rx %d ", dev->rx); + if (dev->_present.tx) + printf("tx %d ", dev->tx); + printf("\n"); + } + ethtool_rings_get_list_free(rings); + + ynl_sock_destroy(ys); + + return 0; + +err_close: + fprintf(stderr, "YNL (%d): %s\n", ys->err.code, ys->err.msg); + ynl_sock_destroy(ys); + return 2; +} -- cgit v1.2.3 From 5ab8c41cef30d8b6160a80b69d2eb39d570491ac Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:53:30 -0700 Subject: netlink: support extack in dump ->start() Commit 4a19edb60d02 ("netlink: Pass extack to dump handlers") added extack support to netlink dumps. It was focused on rtnl and since rtnl does not use ->start(), ->done() callbacks it ignored those. Genetlink on the other hand uses ->start() extensively, for parsing and input validation. Pass the extact in via struct netlink_dump_control and link it to cb for the time of ->start(). Both struct netlink_dump_control and extack itself live on the stack so we can't keep the same extack for the duration of the dump. This means that the extack visible in ->start() and each ->dump() callbacks will be different. Corner cases like reporting a warning message in DONE across dump calls are still not supported. We could put the extack (for dumps) in the socket struct, but layering makes it slightly awkward (extack pointer is decided before the DO / DUMP split). The genetlink dump error extacks are now surfaced: $ cli.py --spec netlink/specs/ethtool.yaml --dump channels-get lib.ynl.NlError: Netlink error: Invalid argument nl_len = 64 (48) nl_flags = 0x300 nl_type = 2 error: -22 extack: {'msg': 'request header missing'} Previously extack was missing: $ cli.py --spec netlink/specs/ethtool.yaml --dump channels-get lib.ynl.NlError: Netlink error: Invalid argument nl_len = 36 (20) nl_flags = 0x100 nl_type = 2 error: -22 Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- include/linux/netlink.h | 1 + net/netlink/af_netlink.c | 2 ++ net/netlink/genetlink.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 19c0791ed9d5..9eec3f4f5351 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -311,6 +311,7 @@ struct netlink_dump_control { int (*start)(struct netlink_callback *); int (*dump)(struct sk_buff *skb, struct netlink_callback *); int (*done)(struct netlink_callback *); + struct netlink_ext_ack *extack; void *data; struct module *module; u32 min_dump_alloc; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3a1e0fd5bf14..cbd9aa7ee24a 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2360,7 +2360,9 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, cb->strict_check = !!(nlk2->flags & NETLINK_F_STRICT_CHK); if (control->start) { + cb->extack = control->extack; ret = control->start(cb); + cb->extack = NULL; if (ret) goto error_put; } diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 04c4036bf406..a157247a1e45 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -912,6 +912,7 @@ static int genl_family_rcv_msg_dumpit(const struct genl_family *family, .start = genl_start, .dump = genl_lock_dumpit, .done = genl_lock_done, + .extack = extack, }; genl_unlock(); @@ -924,6 +925,7 @@ static int genl_family_rcv_msg_dumpit(const struct genl_family *family, .start = genl_start, .dump = ops->dumpit, .done = genl_parallel_done, + .extack = extack, }; err = __netlink_dump_start(net->genl_sock, skb, nlh, &c); -- cgit v1.2.3 From 500e1340d1d2695de3f15fc0b3781f593a77acc2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 9 Jun 2023 14:53:31 -0700 Subject: net: ethtool: don't require empty header nests Ethtool currently requires a header nest (which is used to carry the common family options) in all requests including dumps. $ cli.py --spec netlink/specs/ethtool.yaml --dump channels-get lib.ynl.NlError: Netlink error: Invalid argument nl_len = 64 (48) nl_flags = 0x300 nl_type = 2 error: -22 extack: {'msg': 'request header missing'} $ cli.py --spec netlink/specs/ethtool.yaml --dump channels-get \ --json '{"header":{}}'; ) [{'combined-count': 1, 'combined-max': 1, 'header': {'dev-index': 2, 'dev-name': 'enp1s0'}}] Requiring the header nest to always be there may seem nice from the consistency perspective, but it's not serving any practical purpose. We shouldn't burden the user like this. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- net/ethtool/netlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 08120095cc68..5dd5e8222c45 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -96,6 +96,8 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, int ret; if (!header) { + if (!require_dev) + return 0; NL_SET_ERR_MSG(extack, "request header missing"); return -EINVAL; } -- cgit v1.2.3 From fbf934068f6b93a8c4ddda293fc02b4eb3747323 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Jun 2023 20:42:44 +0000 Subject: tcp: let tcp_send_syn_data() build headless packets tcp_send_syn_data() is the last component in TCP transmit path to put payload in skb->head. Switch it to use page frags, so that we can remove dead code later. This allows to put more payload than previous implementation. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 1 + net/ipv4/tcp.c | 2 +- net/ipv4/tcp_output.c | 31 +++++++++++++++++++------------ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 49611af31bb7..f718ed258f07 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -333,6 +333,7 @@ int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, size_t size, int flags); int tcp_send_mss(struct sock *sk, int *size_goal, int flags); +int tcp_wmem_schedule(struct sock *sk, int copy); void tcp_push(struct sock *sk, int flags, int mss_now, int nonagle, int size_goal); void tcp_release_cb(struct sock *sk); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 09f03221a6f1..da7f156d9fad 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -957,7 +957,7 @@ static int tcp_downgrade_zcopy_pure(struct sock *sk, struct sk_buff *skb) } -static int tcp_wmem_schedule(struct sock *sk, int copy) +int tcp_wmem_schedule(struct sock *sk, int copy) { int left; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f8ce77ce7c3e..d03966337359 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -3802,8 +3802,9 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); struct tcp_fastopen_request *fo = tp->fastopen_req; - int space, err = 0; + struct page_frag *pfrag = sk_page_frag(sk); struct sk_buff *syn_data; + int space, err = 0; tp->rx_opt.mss_clamp = tp->advmss; /* If MSS is not cached */ if (!tcp_fastopen_cookie_check(sk, &tp->rx_opt.mss_clamp, &fo->cookie)) @@ -3822,25 +3823,31 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) space = min_t(size_t, space, fo->size); - /* limit to order-0 allocations */ - space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER)); - - syn_data = tcp_stream_alloc_skb(sk, space, sk->sk_allocation, false); + if (space && + !skb_page_frag_refill(min_t(size_t, space, PAGE_SIZE), + pfrag, sk->sk_allocation)) + goto fallback; + syn_data = tcp_stream_alloc_skb(sk, 0, sk->sk_allocation, false); if (!syn_data) goto fallback; memcpy(syn_data->cb, syn->cb, sizeof(syn->cb)); if (space) { - int copied = copy_from_iter(skb_put(syn_data, space), space, - &fo->data->msg_iter); - if (unlikely(!copied)) { + space = min_t(size_t, space, pfrag->size - pfrag->offset); + space = tcp_wmem_schedule(sk, space); + } + if (space) { + space = copy_page_from_iter(pfrag->page, pfrag->offset, + space, &fo->data->msg_iter); + if (unlikely(!space)) { tcp_skb_tsorted_anchor_cleanup(syn_data); kfree_skb(syn_data); goto fallback; } - if (copied != space) { - skb_trim(syn_data, copied); - space = copied; - } + skb_fill_page_desc(syn_data, 0, pfrag->page, + pfrag->offset, space); + page_ref_inc(pfrag->page); + pfrag->offset += space; + skb_len_add(syn_data, space); skb_zcopy_set(syn_data, fo->uarg, NULL); } /* No more data pending in inet_wait_for_connect() */ -- cgit v1.2.3 From b4a24397139cd943c8fa057c372f8a019e07168d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Jun 2023 20:42:45 +0000 Subject: tcp: remove some dead code Now all skbs in write queue do not contain any payload in skb->head, we can remove some dead code. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index d03966337359..fedbe842abdd 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1530,7 +1530,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *buff; - int nsize, old_factor; + int old_factor; long limit; int nlen; u8 flags; @@ -1538,9 +1538,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, if (WARN_ON(len > skb->len)) return -EINVAL; - nsize = skb_headlen(skb) - len; - if (nsize < 0) - nsize = 0; + DEBUG_NET_WARN_ON_ONCE(skb_headlen(skb)); /* tcp_sendmsg() can overshoot sk_wmem_queued by one full size skb. * We need some allowance to not penalize applications setting small @@ -1560,7 +1558,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, return -ENOMEM; /* Get a new skb... force flag on. */ - buff = tcp_stream_alloc_skb(sk, nsize, gfp, true); + buff = tcp_stream_alloc_skb(sk, 0, gfp, true); if (!buff) return -ENOMEM; /* We'll just try again later. */ skb_copy_decrypted(buff, skb); @@ -1568,7 +1566,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, sk_wmem_queued_add(sk, buff->truesize); sk_mem_charge(sk, buff->truesize); - nlen = skb->len - len - nsize; + nlen = skb->len - len; buff->truesize += nlen; skb->truesize -= nlen; @@ -1626,13 +1624,7 @@ static int __pskb_trim_head(struct sk_buff *skb, int len) struct skb_shared_info *shinfo; int i, k, eat; - eat = min_t(int, len, skb_headlen(skb)); - if (eat) { - __skb_pull(skb, eat); - len -= eat; - if (!len) - return 0; - } + DEBUG_NET_WARN_ON_ONCE(skb_headlen(skb)); eat = len; k = 0; shinfo = skb_shinfo(skb); @@ -1671,12 +1663,10 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) TCP_SKB_CB(skb)->seq += len; - if (delta_truesize) { - skb->truesize -= delta_truesize; - sk_wmem_queued_add(sk, -delta_truesize); - if (!skb_zcopy_pure(skb)) - sk_mem_uncharge(sk, delta_truesize); - } + skb->truesize -= delta_truesize; + sk_wmem_queued_add(sk, -delta_truesize); + if (!skb_zcopy_pure(skb)) + sk_mem_uncharge(sk, delta_truesize); /* Any change of skb->len requires recalculation of tso factor. */ if (tcp_skb_pcount(skb) > 1) @@ -2126,9 +2116,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, u8 flags; /* All of a TSO frame must be composed of paged data. */ - if (skb->len != skb->data_len) - return tcp_fragment(sk, TCP_FRAG_IN_WRITE_QUEUE, - skb, len, mss_now, gfp); + DEBUG_NET_WARN_ON_ONCE(skb->len != skb->data_len); buff = tcp_stream_alloc_skb(sk, 0, gfp, true); if (unlikely(!buff)) @@ -2487,12 +2475,8 @@ static int tcp_mtu_probe(struct sock *sk) } else { TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags & ~(TCPHDR_FIN|TCPHDR_PSH); - if (!skb_shinfo(skb)->nr_frags) { - skb_pull(skb, copy); - } else { - __pskb_trim_head(skb, copy); - tcp_set_skb_tso_segs(skb, mss_now); - } + __pskb_trim_head(skb, copy); + tcp_set_skb_tso_segs(skb, mss_now); TCP_SKB_CB(skb)->seq += copy; } -- cgit v1.2.3 From 5882efff88aa7063ebdecd4ee92cc2cd1d0b3a8f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Jun 2023 20:42:46 +0000 Subject: tcp: remove size parameter from tcp_stream_alloc_skb() Now all tcp_stream_alloc_skb() callers pass @size == 0, we can remove this parameter. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp.c | 6 +++--- net/ipv4/tcp_output.c | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index f718ed258f07..bf9f56225821 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -350,7 +350,7 @@ void tcp_twsk_purge(struct list_head *net_exit_list, int family); ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); -struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, +struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, gfp_t gfp, bool force_schedule); void tcp_enter_quickack_mode(struct sock *sk, unsigned int max_quickacks); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index da7f156d9fad..fba6578bc98f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -858,12 +858,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, } EXPORT_SYMBOL(tcp_splice_read); -struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, +struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, gfp_t gfp, bool force_schedule) { struct sk_buff *skb; - skb = alloc_skb_fclone(size + MAX_TCP_HEADER, gfp); + skb = alloc_skb_fclone(MAX_TCP_HEADER, gfp); if (likely(skb)) { bool mem_scheduled; @@ -1178,7 +1178,7 @@ new_segment: goto restart; } first_skb = tcp_rtx_and_write_queues_empty(sk); - skb = tcp_stream_alloc_skb(sk, 0, sk->sk_allocation, + skb = tcp_stream_alloc_skb(sk, sk->sk_allocation, first_skb); if (!skb) goto wait_for_space; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index fedbe842abdd..660eac4bf2a7 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1558,7 +1558,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, return -ENOMEM; /* Get a new skb... force flag on. */ - buff = tcp_stream_alloc_skb(sk, 0, gfp, true); + buff = tcp_stream_alloc_skb(sk, gfp, true); if (!buff) return -ENOMEM; /* We'll just try again later. */ skb_copy_decrypted(buff, skb); @@ -2118,7 +2118,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, /* All of a TSO frame must be composed of paged data. */ DEBUG_NET_WARN_ON_ONCE(skb->len != skb->data_len); - buff = tcp_stream_alloc_skb(sk, 0, gfp, true); + buff = tcp_stream_alloc_skb(sk, gfp, true); if (unlikely(!buff)) return -ENOMEM; skb_copy_decrypted(buff, skb); @@ -2434,7 +2434,7 @@ static int tcp_mtu_probe(struct sock *sk) return -1; /* We're allowed to probe. Build it now. */ - nskb = tcp_stream_alloc_skb(sk, 0, GFP_ATOMIC, false); + nskb = tcp_stream_alloc_skb(sk, GFP_ATOMIC, false); if (!nskb) return -1; @@ -3811,7 +3811,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) !skb_page_frag_refill(min_t(size_t, space, PAGE_SIZE), pfrag, sk->sk_allocation)) goto fallback; - syn_data = tcp_stream_alloc_skb(sk, 0, sk->sk_allocation, false); + syn_data = tcp_stream_alloc_skb(sk, sk->sk_allocation, false); if (!syn_data) goto fallback; memcpy(syn_data->cb, syn->cb, sizeof(syn->cb)); @@ -3896,7 +3896,7 @@ int tcp_connect(struct sock *sk) return 0; } - buff = tcp_stream_alloc_skb(sk, 0, sk->sk_allocation, true); + buff = tcp_stream_alloc_skb(sk, sk->sk_allocation, true); if (unlikely(!buff)) return -ENOBUFS; -- cgit v1.2.3 From 98c485eaf509bc0e2a85f9b58d17cd501f274c4e Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 11 Jun 2023 00:48:10 +0100 Subject: net: phy: add driver for MediaTek SoC built-in GE PHYs Some of MediaTek's Filogic SoCs come with built-in gigabit Ethernet PHYs which require calibration data from the SoC's efuse. Despite the similar design the driver doesn't share any code with the existing mediatek-ge.c. Add support for such PHYs by introducing a new driver with basic support for MediaTek SoCs MT7981 and MT7988 built-in 1GE PHYs. Signed-off-by: Daniel Golle Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- MAINTAINERS | 9 + drivers/net/phy/Kconfig | 12 + drivers/net/phy/Makefile | 1 + drivers/net/phy/mediatek-ge-soc.c | 1116 +++++++++++++++++++++++++++++++++++++ drivers/net/phy/mediatek-ge.c | 3 +- 5 files changed, 1140 insertions(+), 1 deletion(-) create mode 100644 drivers/net/phy/mediatek-ge-soc.c diff --git a/MAINTAINERS b/MAINTAINERS index ecac69046d30..cd9752472d77 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13151,6 +13151,15 @@ S: Maintained F: drivers/net/pcs/pcs-mtk-lynxi.c F: include/linux/pcs/pcs-mtk-lynxi.h +MEDIATEK ETHERNET PHY DRIVERS +M: Daniel Golle +M: Qingfang Deng +M: SkyLake Huang +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/phy/mediatek-ge-soc.c +F: drivers/net/phy/mediatek-ge.c + MEDIATEK I2C CONTROLLER DRIVER M: Qii Wang L: linux-i2c@vger.kernel.org diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 059bd06a8cce..a40269c17597 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -236,6 +236,18 @@ config MEDIATEK_GE_PHY help Supports the MediaTek Gigabit Ethernet PHYs. +config MEDIATEK_GE_SOC_PHY + tristate "MediaTek SoC Ethernet PHYs" + depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST + select NVMEM_MTK_EFUSE + help + Supports MediaTek SoC built-in Gigabit Ethernet PHYs. + + Include support for built-in Ethernet PHYs which are present in + the MT7981 and MT7988 SoCs. These PHYs need calibration data + present in the SoCs efuse and will dynamically calibrate VCM + (common-mode voltage) during startup. + config MICREL_PHY tristate "Micrel PHYs" depends on PTP_1588_CLOCK_OPTIONAL diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index f289ab16a1da..2fe51ea83bab 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o +obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o obj-$(CONFIG_MICREL_PHY) += micrel.o diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c new file mode 100644 index 000000000000..95369171a7ba --- /dev/null +++ b/drivers/net/phy/mediatek-ge-soc.c @@ -0,0 +1,1116 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include +#include +#include +#include +#include +#include +#include + +#define MTK_GPHY_ID_MT7981 0x03a29461 +#define MTK_GPHY_ID_MT7988 0x03a29481 + +#define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_STANDARD 0x0000 +#define MTK_PHY_PAGE_EXTENDED_3 0x0003 + +#define MTK_PHY_LPI_REG_14 0x14 +#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0) + +#define MTK_PHY_LPI_REG_1c 0x1c +#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8) + +#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 +#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + +#define ANALOG_INTERNAL_OPERATION_MAX_US 20 +#define TXRESERVE_MIN 0 +#define TXRESERVE_MAX 7 + +#define MTK_PHY_ANARG_RG 0x10 +#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8) + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_TXVLD_DA_RG 0x12 +#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10) +#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16 +#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10) +#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17 +#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18 +#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19 +#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20 +#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21 +#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22 +#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_RXADC_CTRL_RG7 0xc6 +#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) + +#define MTK_PHY_RXADC_CTRL_RG9 0xc8 +#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12) +#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8) +#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4) +#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0) + +#define MTK_PHY_LDO_OUTPUT_V 0xd7 + +#define MTK_PHY_RG_ANA_CAL_RG0 0xdb +#define MTK_PHY_RG_CAL_CKINV BIT(12) +#define MTK_PHY_RG_ANA_CALEN BIT(8) +#define MTK_PHY_RG_ZCALEN_A BIT(0) + +#define MTK_PHY_RG_ANA_CAL_RG1 0xdc +#define MTK_PHY_RG_ZCALEN_B BIT(12) +#define MTK_PHY_RG_ZCALEN_C BIT(8) +#define MTK_PHY_RG_ZCALEN_D BIT(4) +#define MTK_PHY_RG_TXVOS_CALEN BIT(0) + +#define MTK_PHY_RG_ANA_CAL_RG5 0xe0 +#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8) + +#define MTK_PHY_RG_TX_FILTER 0xfe + +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120 +#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8) +#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0) + +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122 +#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0) + +#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144 +#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5) + +#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172 +#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8) +#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0) + +#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173 +#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8) +#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) + +#define MTK_PHY_RG_AD_CAL_COMP 0x17a +#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) + +#define MTK_PHY_RG_AD_CAL_CLK 0x17b +#define MTK_PHY_DA_CAL_CLK BIT(0) + +#define MTK_PHY_RG_AD_CALIN 0x17c +#define MTK_PHY_DA_CALIN_FLAG BIT(0) + +#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d +#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e +#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f +#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180 +#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181 +#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182 +#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183 +#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184 +#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DEV1E_REG19b 0x19b +#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8) + +#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a +#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b +#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c +#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d +#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e +#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f +#define MTK_PHY_RG_LP_IIR2_K4_L 0x230 +#define MTK_PHY_RG_LP_IIR2_K4_U 0x231 +#define MTK_PHY_RG_LP_IIR2_K5_L 0x232 +#define MTK_PHY_RG_LP_IIR2_K5_U 0x233 + +#define MTK_PHY_RG_DEV1E_REG234 0x234 +#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0) +#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4) +#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12) + +#define MTK_PHY_RG_LPF_CNT_VAL 0x235 + +#define MTK_PHY_RG_DEV1E_REG238 0x238 +#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0) +#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12) + +#define MTK_PHY_RG_DEV1E_REG239 0x239 +#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0) +#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12) + +#define MTK_PHY_RG_DEV1E_REG27C 0x27c +#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8) +#define MTK_PHY_RG_DEV1E_REG27D 0x27d +#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0) + +#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7 +#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0) +#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8) + +#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1 +#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0) +#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8) +#define MTK_PHY_LPI_TR_READY BIT(9) +#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10) + +#define MTK_PHY_RG_DEV1E_REG323 0x323 +#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0) +#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4) + +#define MTK_PHY_RG_DEV1E_REG324 0x324 +#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0) +#define MTK_PHY_SMI_DET_MAX_EN BIT(8) + +#define MTK_PHY_RG_DEV1E_REG326 0x326 +#define MTK_PHY_LPI_MODE_SD_ON BIT(0) +#define MTK_PHY_RESET_RANDUPD_CNT BIT(1) +#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2) +#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4) +#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5) + +#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502 +#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503 + +#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d +#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e +#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f +#define MTK_PHY_DA_TX_R50_PAIR_D 0x540 + +#define MTK_PHY_RG_BG_RASEL 0x115 +#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0) + +/* These macro privides efuse parsing for internal phy. */ +#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0)) + +#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0)) + +#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0)) + +#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0)) +#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0)) + +enum { + NO_PAIR, + PAIR_A, + PAIR_B, + PAIR_C, + PAIR_D, +}; + +enum { + GPHY_PORT0, + GPHY_PORT1, + GPHY_PORT2, + GPHY_PORT3, +}; + +enum calibration_mode { + EFUSE_K, + SW_K +}; + +enum CAL_ITEM { + REXT, + TX_OFFSET, + TX_AMP, + TX_R50, + TX_VCM +}; + +enum CAL_MODE { + EFUSE_M, + SW_M +}; + +static int mtk_socphy_read_page(struct phy_device *phydev) +{ + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +} + +static int mtk_socphy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); +} + +/* One calibration cycle consists of: + * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high + * until AD_CAL_COMP is ready to output calibration result. + * 2.Wait until DA_CAL_CLK is available. + * 3.Fetch AD_CAL_COMP_OUT. + */ +static int cal_cycle(struct phy_device *phydev, int devad, + u32 regnum, u16 mask, u16 cal_val) +{ + int reg_val; + int ret; + + phy_modify_mmd(phydev, devad, regnum, + mask, cal_val); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); + + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_AD_CAL_CLK, reg_val, + reg_val & MTK_PHY_DA_CAL_CLK, 500, + ANALOG_INTERNAL_OPERATION_MAX_US, false); + if (ret) { + phydev_err(phydev, "Calibration cycle timeout\n"); + return ret; + } + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >> + MTK_PHY_AD_CAL_COMP_OUT_SHIFT; + phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); + + return ret; +} + +static int rext_fill_result(struct phy_device *phydev, u16 *buf) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, + MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL, + MTK_PHY_RG_BG_RASEL_MASK, buf[1]); + + return 0; +} + +static int rext_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 rext_cal_val[2]; + + rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]); + rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]); + rext_fill_result(phydev, rext_cal_val); + + return 0; +} + +static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, + MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, + MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, + MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, + MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]); + + return 0; +} + +static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 tx_offset_cal_val[4]; + + tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]); + tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]); + tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]); + tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]); + + tx_offset_fill_result(phydev, tx_offset_cal_val); + + return 0; +} + +static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) +{ + int i; + int bias[16] = {}; + const int vals_9461[16] = { 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7 }; + const int vals_9481[16] = { 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10 }; + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + /* We add some calibration to efuse values + * due to board level influence. + * GBE: +7, TBT: +1, HBT: +4, TST: +7 + */ + memcpy(bias, (const void *)vals_9461, sizeof(bias)); + break; + case MTK_GPHY_ID_MT7988: + memcpy(bias, (const void *)vals_9481, sizeof(bias)); + break; + } + + /* Prevent overflow */ + for (i = 0; i < 12; i++) { + if (buf[i >> 2] + bias[i] > 63) { + buf[i >> 2] = 63; + bias[i] = 0; + } + } + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, + MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, + MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, + MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, + MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, + MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, + MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, + MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, + MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, + MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, + MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, + MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, + MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, + MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, + MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, + MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, + MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]); + + return 0; +} + +static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 tx_amp_cal_val[4]; + + tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]); + tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]); + tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]); + tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]); + tx_amp_fill_result(phydev, tx_amp_cal_val); + + return 0; +} + +static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val, + u8 txg_calen_x) +{ + int bias = 0; + u16 reg, val; + + if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988) + bias = -2; + + val = clamp_val(bias + tx_r50_cal_val, 0, 63); + + switch (txg_calen_x) { + case PAIR_A: + reg = MTK_PHY_DA_TX_R50_PAIR_A; + break; + case PAIR_B: + reg = MTK_PHY_DA_TX_R50_PAIR_B; + break; + case PAIR_C: + reg = MTK_PHY_DA_TX_R50_PAIR_C; + break; + case PAIR_D: + reg = MTK_PHY_DA_TX_R50_PAIR_D; + break; + default: + return -EINVAL; + } + + phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8); + + return 0; +} + +static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf, + u8 txg_calen_x) +{ + u16 tx_r50_cal_val; + + switch (txg_calen_x) { + case PAIR_A: + tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]); + break; + case PAIR_B: + tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]); + break; + case PAIR_C: + tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]); + break; + case PAIR_D: + tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]); + break; + default: + return -EINVAL; + } + tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); + + return 0; +} + +static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) +{ + u8 lower_idx, upper_idx, txreserve_val; + u8 lower_ret, upper_ret; + int ret; + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ANA_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_CAL_CKINV); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_TXVOS_CALEN); + + switch (rg_txreserve_x) { + case PAIR_A: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_A, + MTK_PHY_DASN_DAC_IN0_A_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_A, + MTK_PHY_DASN_DAC_IN1_A_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ZCALEN_A); + break; + case PAIR_B: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_B, + MTK_PHY_DASN_DAC_IN0_B_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_B, + MTK_PHY_DASN_DAC_IN1_B_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_B); + break; + case PAIR_C: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_C, + MTK_PHY_DASN_DAC_IN0_C_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_C, + MTK_PHY_DASN_DAC_IN1_C_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_C); + break; + case PAIR_D: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_D, + MTK_PHY_DASN_DAC_IN0_D_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_D, + MTK_PHY_DASN_DAC_IN1_D_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_D); + break; + default: + ret = -EINVAL; + goto restore; + } + + lower_idx = TXRESERVE_MIN; + upper_idx = TXRESERVE_MAX; + + phydev_dbg(phydev, "Start TX-VCM SW cal.\n"); + while ((upper_idx - lower_idx) > 1) { + txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2); + ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + txreserve_val << 12 | txreserve_val << 8 | + txreserve_val << 4 | txreserve_val); + if (ret == 1) { + upper_idx = txreserve_val; + upper_ret = ret; + } else if (ret == 0) { + lower_idx = txreserve_val; + lower_ret = ret; + } else { + goto restore; + } + } + + if (lower_idx == TXRESERVE_MIN) { + lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, + MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + lower_idx << 12 | lower_idx << 8 | + lower_idx << 4 | lower_idx); + ret = lower_ret; + } else if (upper_idx == TXRESERVE_MAX) { + upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, + MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + upper_idx << 12 | upper_idx << 8 | + upper_idx << 4 | upper_idx); + ret = upper_ret; + } + if (ret < 0) + goto restore; + + /* We calibrate TX-VCM in different logic. Check upper index and then + * lower index. If this calibration is valid, apply lower index's result. + */ + ret = upper_ret - lower_ret; + if (ret == 1) { + ret = 0; + /* Make sure we use upper_idx in our calibration system */ + cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + upper_idx << 12 | upper_idx << 8 | + upper_idx << 4 | upper_idx); + phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx); + } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && + lower_ret == 1) { + ret = 0; + cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + lower_idx << 12 | lower_idx << 8 | + lower_idx << 4 | lower_idx); + phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n", + lower_idx); + } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && + lower_ret == 0) { + ret = 0; + phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n", + upper_idx); + } else { + ret = -EINVAL; + } + +restore: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ANA_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_TXVOS_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ZCALEN_A); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | + MTK_PHY_RG_ZCALEN_D); + + return ret; +} + +static void mt798x_phy_common_finetune(struct phy_device *phydev) +{ + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* EnabRandUpdTrig = 1 */ + __phy_write(phydev, 0x11, 0x2f00); + __phy_write(phydev, 0x12, 0xe); + __phy_write(phydev, 0x10, 0x8fb0); + + /* NormMseLoThresh = 85 */ + __phy_write(phydev, 0x11, 0x55a0); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x83aa); + + /* TrFreeze = 0 */ + __phy_write(phydev, 0x11, 0x0); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9686); + + /* SSTrKp1000Slv = 5 */ + __phy_write(phydev, 0x11, 0xbaef); + __phy_write(phydev, 0x12, 0x2e); + __phy_write(phydev, 0x10, 0x968c); + + /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, + * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 + */ + __phy_write(phydev, 0x11, 0xd10a); + __phy_write(phydev, 0x12, 0x34); + __phy_write(phydev, 0x10, 0x8f82); + + /* VcoSlicerThreshBitsHigh */ + __phy_write(phydev, 0x11, 0x5555); + __phy_write(phydev, 0x12, 0x55); + __phy_write(phydev, 0x10, 0x8ec0); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, + MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, + BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); + + /* rg_tr_lpf_cnt_val = 512 */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); + + /* IIR2 related */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); + + /* FFE peaking */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, + MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, + MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); + + /* Disable LDO pump */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0); + /* Adjust LDO output voltage */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222); +} + +static void mt7981_phy_finetune(struct phy_device *phydev) +{ + u16 val[8] = { 0x01ce, 0x01c1, + 0x020f, 0x0202, + 0x03d0, 0x03c0, + 0x0013, 0x0005 }; + int i, k; + + /* 100M eye finetune: + * Keep middle level of TX MLT3 shapper as default. + * Only change TX MLT3 overshoot level here. + */ + for (k = 0, i = 1; i < 12; i++) { + if (i % 3 == 0) + continue; + phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]); + } + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */ + __phy_write(phydev, 0x11, 0xc71); + __phy_write(phydev, 0x12, 0xc); + __phy_write(phydev, 0x10, 0x8fae); + + /* ResetSyncOffset = 6 */ + __phy_write(phydev, 0x11, 0x600); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8fc0); + + /* VgaDecRate = 1 */ + __phy_write(phydev, 0x11, 0x4c2a); + __phy_write(phydev, 0x12, 0x3e); + __phy_write(phydev, 0x10, 0x8fa4); + + /* FfeUpdGainForce = 4 */ + __phy_write(phydev, 0x11, 0x240); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9680); + + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); +} + +static void mt7988_phy_finetune(struct phy_device *phydev) +{ + u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182, + 0x020d, 0x0206, 0x0384, 0x03d0, + 0x03c6, 0x030a, 0x0011, 0x0005 }; + int i; + + /* Set default MLT3 shaper first */ + for (i = 0; i < 12; i++) + phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]); + + /* TCT finetune */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); + + /* Disable TX power saving */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, + MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + + /* SlvDSPreadyTime = 24, MasDSPreadyTime = 12 */ + __phy_write(phydev, 0x11, 0x671); + __phy_write(phydev, 0x12, 0xc); + __phy_write(phydev, 0x10, 0x8fae); + + /* ResetSyncOffset = 5 */ + __phy_write(phydev, 0x11, 0x500); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8fc0); + + /* VgaDecRate is 1 at default on mt7988 */ + + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30); + /* TxClkOffset = 2 */ + __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK, + FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); +} + +static void mt798x_phy_eee(struct phy_device *phydev) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120, + MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK | + MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) | + FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, + MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + 0xff)); + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_TESTMUX_ADC_CTRL, + MTK_PHY_RG_TXEN_DIG_MASK); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY); + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238, + MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK | + MTK_PHY_LPI_SLV_SEND_TX_EN, + FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239, + MTK_PHY_LPI_SEND_LOC_TIMER_MASK | + MTK_PHY_LPI_TXPCS_LOC_RCV, + FIELD_PREP(MTK_PHY_LPI_SEND_LOC_TIMER_MASK, 0x117)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7, + MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK, + FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) | + FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1, + MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK, + FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK, + 0x33) | + MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY | + MTK_PHY_LPI_VCO_EEE_STG0_EN); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323, + MTK_PHY_EEE_WAKE_MAS_INT_DC | + MTK_PHY_EEE_WAKE_SLV_INT_DC); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324, + MTK_PHY_SMI_DETCNT_MAX_MASK, + FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) | + MTK_PHY_SMI_DET_MAX_EN); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326, + MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT | + MTK_PHY_TREC_UPDATE_ENAB_CLR | + MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF | + MTK_PHY_TR_READY_SKIP_AFE_WAKEUP); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* Regsigdet_sel_1000 = 0 */ + __phy_write(phydev, 0x11, 0xb); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9690); + + /* REG_EEE_st2TrKf1000 = 3 */ + __phy_write(phydev, 0x11, 0x114f); + __phy_write(phydev, 0x12, 0x2); + __phy_write(phydev, 0x10, 0x969a); + + /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */ + __phy_write(phydev, 0x11, 0x3028); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x969e); + + /* RegEEE_slv_wake_int_timer_tar = 8 */ + __phy_write(phydev, 0x11, 0x5010); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96a0); + + /* RegEEE_trfreeze_timer2 = 586 */ + __phy_write(phydev, 0x11, 0x24a); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96a8); + + /* RegEEE100Stg1_tar = 16 */ + __phy_write(phydev, 0x11, 0x3210); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96b8); + + /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 1 */ + __phy_write(phydev, 0x11, 0x1463); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96ca); + + /* DfeTailEnableVgaThresh1000 = 27 */ + __phy_write(phydev, 0x11, 0x36); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8f80); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3); + __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK, + FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c)); + + __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK, + FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, + MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff)); +} + +static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item, + u8 start_pair, u8 end_pair) +{ + u8 pair_n; + int ret; + + for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { + /* TX_OFFSET & TX_AMP have no SW calibration. */ + switch (cal_item) { + case TX_VCM: + ret = tx_vcm_cal_sw(phydev, pair_n); + break; + default: + return -EINVAL; + } + if (ret) + return ret; + } + return 0; +} + +static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item, + u8 start_pair, u8 end_pair, u32 *buf) +{ + u8 pair_n; + int ret; + + for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { + /* TX_VCM has no efuse calibration. */ + switch (cal_item) { + case REXT: + ret = rext_cal_efuse(phydev, buf); + break; + case TX_OFFSET: + ret = tx_offset_cal_efuse(phydev, buf); + break; + case TX_AMP: + ret = tx_amp_cal_efuse(phydev, buf); + break; + case TX_R50: + ret = tx_r50_cal_efuse(phydev, buf, pair_n); + break; + default: + return -EINVAL; + } + if (ret) + return ret; + } + + return 0; +} + +static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item, + enum CAL_MODE cal_mode, u8 start_pair, + u8 end_pair, u32 *buf) +{ + int ret; + + switch (cal_mode) { + case EFUSE_M: + ret = cal_efuse(phydev, cal_item, start_pair, + end_pair, buf); + break; + case SW_M: + ret = cal_sw(phydev, cal_item, start_pair, end_pair); + break; + default: + return -EINVAL; + } + + if (ret) { + phydev_err(phydev, "cal %d failed\n", cal_item); + return -EIO; + } + + return 0; +} + +static int mt798x_phy_calibration(struct phy_device *phydev) +{ + int ret = 0; + u32 *buf; + size_t len; + struct nvmem_cell *cell; + + cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); + if (IS_ERR(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) + return PTR_ERR(cell); + return 0; + } + + buf = (u32 *)nvmem_cell_read(cell, &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + nvmem_cell_put(cell); + + if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) { + phydev_err(phydev, "invalid efuse data\n"); + ret = -EINVAL; + goto out; + } + + ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf); + if (ret) + goto out; + +out: + kfree(buf); + return ret; +} + +static int mt798x_phy_config_init(struct phy_device *phydev) +{ + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + mt7981_phy_finetune(phydev); + break; + case MTK_GPHY_ID_MT7988: + mt7988_phy_finetune(phydev); + break; + } + + mt798x_phy_common_finetune(phydev); + mt798x_phy_eee(phydev); + + return mt798x_phy_calibration(phydev); +} + +static struct phy_driver mtk_socphy_driver[] = { + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981), + .name = "MediaTek MT7981 PHY", + .config_init = mt798x_phy_config_init, + .config_intr = genphy_no_config_intr, + .handle_interrupt = genphy_handle_interrupt_no_ack, + .probe = mt798x_phy_calibration, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_socphy_read_page, + .write_page = mtk_socphy_write_page, + }, + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988), + .name = "MediaTek MT7988 PHY", + .config_init = mt798x_phy_config_init, + .config_intr = genphy_no_config_intr, + .handle_interrupt = genphy_handle_interrupt_no_ack, + .probe = mt798x_phy_calibration, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_socphy_read_page, + .write_page = mtk_socphy_write_page, + }, +}; + +module_phy_driver(mtk_socphy_driver); + +static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, + { } +}; + +MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver"); +MODULE_AUTHOR("Daniel Golle "); +MODULE_AUTHOR("SkyLake Huang "); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl); diff --git a/drivers/net/phy/mediatek-ge.c b/drivers/net/phy/mediatek-ge.c index 68ee434f9dea..a493ae01b267 100644 --- a/drivers/net/phy/mediatek-ge.c +++ b/drivers/net/phy/mediatek-ge.c @@ -102,7 +102,8 @@ static struct phy_driver mtk_gephy_driver[] = { module_phy_driver(mtk_gephy_driver); static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { - { PHY_ID_MATCH_VENDOR(0x03a29400) }, + { PHY_ID_MATCH_EXACT(0x03a29441) }, + { PHY_ID_MATCH_EXACT(0x03a29412) }, { } }; -- cgit v1.2.3 From 3a2cb45ca0ccb5dab9b701f50cfd981f8dfd1673 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 12 Jun 2023 09:22:22 +0200 Subject: net: mlxsw: i2c: Switch back to use struct i2c_driver's .probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit b8a1a4cd5a98 ("i2c: Provide a temporary .probe_new() call-back type"), all drivers being converted to .probe_new() and then commit 03c835f498b5 ("i2c: Switch .probe() to not take an id parameter") convert back to (the new) .probe() to be able to eventually drop .probe_new() from struct i2c_driver. Signed-off-by: Uwe Kleine-König Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c index 2c586c2308ae..41298835a11e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c +++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c @@ -751,7 +751,7 @@ static void mlxsw_i2c_remove(struct i2c_client *client) int mlxsw_i2c_driver_register(struct i2c_driver *i2c_driver) { - i2c_driver->probe_new = mlxsw_i2c_probe; + i2c_driver->probe = mlxsw_i2c_probe; i2c_driver->remove = mlxsw_i2c_remove; return i2c_add_driver(i2c_driver); } -- cgit v1.2.3 From b23ed4d74c4d583b5f621ee4c776699442833554 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Sat, 10 Jun 2023 01:16:37 +0300 Subject: selftests/bpf: Fix invalid pointer check in get_xlated_program() Dan Carpenter reported invalid check for calloc() result in test_verifier.c:get_xlated_program(): ./tools/testing/selftests/bpf/test_verifier.c:1365 get_xlated_program() warn: variable dereferenced before check 'buf' (see line 1364) ./tools/testing/selftests/bpf/test_verifier.c 1363 *cnt = xlated_prog_len / buf_element_size; 1364 *buf = calloc(*cnt, buf_element_size); 1365 if (!buf) { This should be if (!*buf) { 1366 perror("can't allocate xlated program buffer"); 1367 return -ENOMEM; This commit refactors the get_xlated_program() to avoid using double pointer type. Fixes: 933ff53191eb ("selftests/bpf: specify expected instructions in test_verifier tests") Reported-by: Dan Carpenter Signed-off-by: Eduard Zingerman Signed-off-by: Daniel Borkmann Closes: https://lore.kernel.org/bpf/ZH7u0hEGVB4MjGZq@moroto/ Link: https://lore.kernel.org/bpf/20230609221637.2631800-1-eddyz87@gmail.com --- tools/testing/selftests/bpf/test_verifier.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 71704a38cac3..31f1c935cd07 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1341,45 +1341,46 @@ static bool cmp_str_seq(const char *log, const char *exp) return true; } -static int get_xlated_program(int fd_prog, struct bpf_insn **buf, int *cnt) +static struct bpf_insn *get_xlated_program(int fd_prog, int *cnt) { + __u32 buf_element_size = sizeof(struct bpf_insn); struct bpf_prog_info info = {}; __u32 info_len = sizeof(info); __u32 xlated_prog_len; - __u32 buf_element_size = sizeof(struct bpf_insn); + struct bpf_insn *buf; if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { perror("bpf_prog_get_info_by_fd failed"); - return -1; + return NULL; } xlated_prog_len = info.xlated_prog_len; if (xlated_prog_len % buf_element_size) { printf("Program length %d is not multiple of %d\n", xlated_prog_len, buf_element_size); - return -1; + return NULL; } *cnt = xlated_prog_len / buf_element_size; - *buf = calloc(*cnt, buf_element_size); + buf = calloc(*cnt, buf_element_size); if (!buf) { perror("can't allocate xlated program buffer"); - return -ENOMEM; + return NULL; } bzero(&info, sizeof(info)); info.xlated_prog_len = xlated_prog_len; - info.xlated_prog_insns = (__u64)(unsigned long)*buf; + info.xlated_prog_insns = (__u64)(unsigned long)buf; if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) { perror("second bpf_prog_get_info_by_fd failed"); goto out_free_buf; } - return 0; + return buf; out_free_buf: - free(*buf); - return -1; + free(buf); + return NULL; } static bool is_null_insn(struct bpf_insn *insn) @@ -1512,7 +1513,8 @@ static bool check_xlated_program(struct bpf_test *test, int fd_prog) if (!check_expected && !check_unexpected) goto out; - if (get_xlated_program(fd_prog, &buf, &cnt)) { + buf = get_xlated_program(fd_prog, &cnt); + if (!buf) { printf("FAIL: can't get xlated program\n"); result = false; goto out; -- cgit v1.2.3 From ba49f976885869835a1783863376221dc24f1817 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Jun 2023 15:50:18 +0200 Subject: bpf: Hide unused bpf_patch_call_args This function is only used when CONFIG_BPF_JIT_ALWAYS_ON is disabled, but CONFIG_BPF_SYSCALL is enabled. When both are turned off, the prototype is missing but the unused function is still compiled, as seen from this W=1 warning: [...] kernel/bpf/core.c:2075:6: error: no previous prototype for 'bpf_patch_call_args' [-Werror=missing-prototypes] [...] Add a matching #ifdef for the definition to leave it out. Signed-off-by: Arnd Bergmann Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230602135128.1498362-1-arnd@kernel.org --- kernel/bpf/core.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 7421487422d4..dc85240a0134 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -2064,14 +2064,16 @@ EVAL4(PROG_NAME_LIST, 416, 448, 480, 512) }; #undef PROG_NAME_LIST #define PROG_NAME_LIST(stack_size) PROG_NAME_ARGS(stack_size), -static u64 (*interpreters_args[])(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5, - const struct bpf_insn *insn) = { +static __maybe_unused +u64 (*interpreters_args[])(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5, + const struct bpf_insn *insn) = { EVAL6(PROG_NAME_LIST, 32, 64, 96, 128, 160, 192) EVAL6(PROG_NAME_LIST, 224, 256, 288, 320, 352, 384) EVAL4(PROG_NAME_LIST, 416, 448, 480, 512) }; #undef PROG_NAME_LIST +#ifdef CONFIG_BPF_SYSCALL void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth) { stack_depth = max_t(u32, stack_depth, 1); @@ -2080,7 +2082,7 @@ void bpf_patch_call_args(struct bpf_insn *insn, u32 stack_depth) __bpf_call_base_args; insn->code = BPF_JMP | BPF_CALL_ARGS; } - +#endif #else static unsigned int __bpf_prog_ret0_warn(const void *ctx, const struct bpf_insn *insn) -- cgit v1.2.3 From 5ba3a7a851e3ebffc4cb8f052a4581c4d8af3ae3 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 9 Jun 2023 22:50:49 -0500 Subject: bpf: Add bpf_cpumask_first_and() kfunc We currently provide bpf_cpumask_first(), bpf_cpumask_any(), and bpf_cpumask_any_and() kfuncs. bpf_cpumask_any() and bpf_cpumask_any_and() are confusing misnomers in that they actually just call cpumask_first() and cpumask_first_and() respectively. We'll replace them with bpf_cpumask_any_distribute() and bpf_cpumask_any_distribute_and() kfuncs in a subsequent patch, so let's ensure feature parity by adding a bpf_cpumask_first_and() kfunc to account for bpf_cpumask_any_and() being removed. Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230610035053.117605-1-void@manifault.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/cpumask.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c index 7efdf5d770ca..9416c8ac8a04 100644 --- a/kernel/bpf/cpumask.c +++ b/kernel/bpf/cpumask.c @@ -131,6 +131,21 @@ __bpf_kfunc u32 bpf_cpumask_first_zero(const struct cpumask *cpumask) return cpumask_first_zero(cpumask); } +/** + * bpf_cpumask_first_and() - Return the index of the first nonzero bit from the + * AND of two cpumasks. + * @src1: The first cpumask. + * @src2: The second cpumask. + * + * Find the index of the first nonzero bit of the AND of two cpumasks. + * struct bpf_cpumask pointers may be safely passed to @src1 and @src2. + */ +__bpf_kfunc u32 bpf_cpumask_first_and(const struct cpumask *src1, + const struct cpumask *src2) +{ + return cpumask_first_and(src1, src2); +} + /** * bpf_cpumask_set_cpu() - Set a bit for a CPU in a BPF cpumask. * @cpu: The CPU to be set in the cpumask. @@ -406,6 +421,7 @@ BTF_ID_FLAGS(func, bpf_cpumask_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_cpumask_acquire, KF_ACQUIRE | KF_TRUSTED_ARGS) BTF_ID_FLAGS(func, bpf_cpumask_first, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_first_zero, KF_RCU) +BTF_ID_FLAGS(func, bpf_cpumask_first_and, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_set_cpu, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_clear_cpu, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_test_cpu, KF_RCU) -- cgit v1.2.3 From 58476d8a24bd94b96ac1ab78baba8af1cc89fbeb Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 9 Jun 2023 22:50:50 -0500 Subject: selftests/bpf: Add test for new bpf_cpumask_first_and() kfunc A prior patch added a new kfunc called bpf_cpumask_first_and() which wraps cpumask_first_and(). This patch adds a selftest to validate its behavior. Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230610035053.117605-2-void@manifault.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/prog_tests/cpumask.c | 1 + tools/testing/selftests/bpf/progs/cpumask_common.h | 2 ++ .../testing/selftests/bpf/progs/cpumask_success.c | 32 ++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/cpumask.c b/tools/testing/selftests/bpf/prog_tests/cpumask.c index d89191440fb1..756ea8b590b6 100644 --- a/tools/testing/selftests/bpf/prog_tests/cpumask.c +++ b/tools/testing/selftests/bpf/prog_tests/cpumask.c @@ -10,6 +10,7 @@ static const char * const cpumask_success_testcases[] = { "test_set_clear_cpu", "test_setall_clear_cpu", "test_first_firstzero_cpu", + "test_firstand_nocpu", "test_test_and_set_clear", "test_and_or_xor", "test_intersects_subset", diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h index 0c5b785a93e4..b3493d5d263e 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_common.h +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h @@ -28,6 +28,8 @@ void bpf_cpumask_release(struct bpf_cpumask *cpumask) __ksym; struct bpf_cpumask *bpf_cpumask_acquire(struct bpf_cpumask *cpumask) __ksym; u32 bpf_cpumask_first(const struct cpumask *cpumask) __ksym; u32 bpf_cpumask_first_zero(const struct cpumask *cpumask) __ksym; +u32 bpf_cpumask_first_and(const struct cpumask *src1, + const struct cpumask *src2) __ksym; void bpf_cpumask_set_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym; void bpf_cpumask_clear_cpu(u32 cpu, struct bpf_cpumask *cpumask) __ksym; bool bpf_cpumask_test_cpu(u32 cpu, const struct cpumask *cpumask) __ksym; diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index 602a88b03dbc..fbaf510f4ab5 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -175,6 +175,38 @@ release_exit: return 0; } +SEC("tp_btf/task_newtask") +int BPF_PROG(test_firstand_nocpu, struct task_struct *task, u64 clone_flags) +{ + struct bpf_cpumask *mask1, *mask2; + u32 first; + + if (!is_test_task()) + return 0; + + mask1 = create_cpumask(); + if (!mask1) + return 0; + + mask2 = create_cpumask(); + if (!mask2) + goto release_exit; + + bpf_cpumask_set_cpu(0, mask1); + bpf_cpumask_set_cpu(1, mask2); + + first = bpf_cpumask_first_and(cast(mask1), cast(mask2)); + if (first <= 1) + err = 3; + +release_exit: + if (mask1) + bpf_cpumask_release(mask1); + if (mask2) + bpf_cpumask_release(mask2); + return 0; +} + SEC("tp_btf/task_newtask") int BPF_PROG(test_test_and_set_clear, struct task_struct *task, u64 clone_flags) { -- cgit v1.2.3 From f983be917332ea5e03f689e12c6668be48cb4cfe Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 9 Jun 2023 22:50:51 -0500 Subject: bpf: Replace bpf_cpumask_any* with bpf_cpumask_any_distribute* We currently export the bpf_cpumask_any() and bpf_cpumask_any_and() kfuncs. Intuitively, one would expect these to choose any CPU in the cpumask, but what they actually do is alias to cpumask_first() and cpmkas_first_and(). This is useless given that we already export bpf_cpumask_first() and bpf_cpumask_first_and(), so this patch replaces them with kfuncs that call cpumask_any_distribute() and cpumask_any_and_distribute(), which actually choose any CPU from the cpumask (or the AND of two cpumasks for the latter). Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230610035053.117605-3-void@manifault.com Signed-off-by: Alexei Starovoitov --- kernel/bpf/cpumask.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/cpumask.c b/kernel/bpf/cpumask.c index 9416c8ac8a04..938a60ff4295 100644 --- a/kernel/bpf/cpumask.c +++ b/kernel/bpf/cpumask.c @@ -382,7 +382,7 @@ __bpf_kfunc void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask } /** - * bpf_cpumask_any() - Return a random set CPU from a cpumask. + * bpf_cpumask_any_distribute() - Return a random set CPU from a cpumask. * @cpumask: The cpumask being queried. * * Return: @@ -391,26 +391,28 @@ __bpf_kfunc void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask * * A struct bpf_cpumask pointer may be safely passed to @src. */ -__bpf_kfunc u32 bpf_cpumask_any(const struct cpumask *cpumask) +__bpf_kfunc u32 bpf_cpumask_any_distribute(const struct cpumask *cpumask) { - return cpumask_any(cpumask); + return cpumask_any_distribute(cpumask); } /** - * bpf_cpumask_any_and() - Return a random set CPU from the AND of two - * cpumasks. + * bpf_cpumask_any_and_distribute() - Return a random set CPU from the AND of + * two cpumasks. * @src1: The first cpumask. * @src2: The second cpumask. * * Return: - * * A random set bit within [0, num_cpus) if at least one bit is set. + * * A random set bit within [0, num_cpus) from the AND of two cpumasks, if at + * least one bit is set. * * >= num_cpus if no bit is set. * * struct bpf_cpumask pointers may be safely passed to @src1 and @src2. */ -__bpf_kfunc u32 bpf_cpumask_any_and(const struct cpumask *src1, const struct cpumask *src2) +__bpf_kfunc u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, + const struct cpumask *src2) { - return cpumask_any_and(src1, src2); + return cpumask_any_and_distribute(src1, src2); } __diag_pop(); @@ -438,8 +440,8 @@ BTF_ID_FLAGS(func, bpf_cpumask_subset, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_empty, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_full, KF_RCU) BTF_ID_FLAGS(func, bpf_cpumask_copy, KF_RCU) -BTF_ID_FLAGS(func, bpf_cpumask_any, KF_RCU) -BTF_ID_FLAGS(func, bpf_cpumask_any_and, KF_RCU) +BTF_ID_FLAGS(func, bpf_cpumask_any_distribute, KF_RCU) +BTF_ID_FLAGS(func, bpf_cpumask_any_and_distribute, KF_RCU) BTF_SET8_END(cpumask_kfunc_btf_ids) static const struct btf_kfunc_id_set cpumask_kfunc_set = { -- cgit v1.2.3 From 5a73efc7d1b4b48ccb74fb399a818dfbd2250c89 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 9 Jun 2023 22:50:52 -0500 Subject: selftests/bpf: Update bpf_cpumask_any* tests to use bpf_cpumask_any_distribute* In a prior patch, we removed the bpf_cpumask_any() and bpf_cpumask_any_and() kfuncs, and replaced them with bpf_cpumask_any_distribute() and bpf_cpumask_any_distribute_and(). The advertised semantics between the two kfuncs were identical, with the former always returning the first CPU, and the latter actually returning any CPU. This patch updates the selftests for these kfuncs to use the new names. Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230610035053.117605-4-void@manifault.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/cpumask_common.h | 4 ++-- tools/testing/selftests/bpf/progs/cpumask_success.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/cpumask_common.h b/tools/testing/selftests/bpf/progs/cpumask_common.h index b3493d5d263e..b15c588ace15 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_common.h +++ b/tools/testing/selftests/bpf/progs/cpumask_common.h @@ -52,8 +52,8 @@ bool bpf_cpumask_subset(const struct cpumask *src1, const struct cpumask *src2) bool bpf_cpumask_empty(const struct cpumask *cpumask) __ksym; bool bpf_cpumask_full(const struct cpumask *cpumask) __ksym; void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src) __ksym; -u32 bpf_cpumask_any(const struct cpumask *src) __ksym; -u32 bpf_cpumask_any_and(const struct cpumask *src1, const struct cpumask *src2) __ksym; +u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym; +u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, const struct cpumask *src2) __ksym; void bpf_rcu_read_lock(void) __ksym; void bpf_rcu_read_unlock(void) __ksym; diff --git a/tools/testing/selftests/bpf/progs/cpumask_success.c b/tools/testing/selftests/bpf/progs/cpumask_success.c index fbaf510f4ab5..674a63424dee 100644 --- a/tools/testing/selftests/bpf/progs/cpumask_success.c +++ b/tools/testing/selftests/bpf/progs/cpumask_success.c @@ -344,13 +344,13 @@ int BPF_PROG(test_copy_any_anyand, struct task_struct *task, u64 clone_flags) bpf_cpumask_set_cpu(1, mask2); bpf_cpumask_or(dst1, cast(mask1), cast(mask2)); - cpu = bpf_cpumask_any(cast(mask1)); + cpu = bpf_cpumask_any_distribute(cast(mask1)); if (cpu != 0) { err = 6; goto release_exit; } - cpu = bpf_cpumask_any(cast(dst2)); + cpu = bpf_cpumask_any_distribute(cast(dst2)); if (cpu < nr_cpus) { err = 7; goto release_exit; @@ -362,13 +362,13 @@ int BPF_PROG(test_copy_any_anyand, struct task_struct *task, u64 clone_flags) goto release_exit; } - cpu = bpf_cpumask_any(cast(dst2)); + cpu = bpf_cpumask_any_distribute(cast(dst2)); if (cpu > 1) { err = 9; goto release_exit; } - cpu = bpf_cpumask_any_and(cast(mask1), cast(mask2)); + cpu = bpf_cpumask_any_and_distribute(cast(mask1), cast(mask2)); if (cpu < nr_cpus) { err = 10; goto release_exit; -- cgit v1.2.3 From 25085b4e9251c77758964a8e8651338972353642 Mon Sep 17 00:00:00 2001 From: David Vernet Date: Fri, 9 Jun 2023 22:50:53 -0500 Subject: bpf/docs: Update documentation for new cpumask kfuncs We recently added the bpf_cpumask_first_and() kfunc, and changed bpf_cpumask_any() / bpf_cpumask_any_and() to bpf_cpumask_any_distribute() and bpf_cpumask_any_distribute_and() respectively. This patch adds an entry for the bpf_cpumask_first_and() kfunc, and updates the documentation for the *any* kfuncs to the new names. Signed-off-by: David Vernet Acked-by: Yonghong Song Link: https://lore.kernel.org/r/20230610035053.117605-5-void@manifault.com Signed-off-by: Alexei Starovoitov --- Documentation/bpf/cpumasks.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/bpf/cpumasks.rst b/Documentation/bpf/cpumasks.rst index 41efd8874eeb..3139c7c02e79 100644 --- a/Documentation/bpf/cpumasks.rst +++ b/Documentation/bpf/cpumasks.rst @@ -351,14 +351,15 @@ In addition to the above kfuncs, there is also a set of read-only kfuncs that can be used to query the contents of cpumasks. .. kernel-doc:: kernel/bpf/cpumask.c - :identifiers: bpf_cpumask_first bpf_cpumask_first_zero bpf_cpumask_test_cpu + :identifiers: bpf_cpumask_first bpf_cpumask_first_zero bpf_cpumask_first_and + bpf_cpumask_test_cpu .. kernel-doc:: kernel/bpf/cpumask.c :identifiers: bpf_cpumask_equal bpf_cpumask_intersects bpf_cpumask_subset bpf_cpumask_empty bpf_cpumask_full .. kernel-doc:: kernel/bpf/cpumask.c - :identifiers: bpf_cpumask_any bpf_cpumask_any_and + :identifiers: bpf_cpumask_any_distribute bpf_cpumask_any_and_distribute ---- -- cgit v1.2.3 From d7ad70b5ef5ab8dedaa403e0e5c711ca1aa8cb14 Mon Sep 17 00:00:00 2001 From: Zahari Doychev Date: Thu, 8 Jun 2023 12:56:46 +0200 Subject: net: flow_dissector: add support for cfm packets Add support for dissecting cfm packets. The cfm packet header fields maintenance domain level and opcode can be dissected. Signed-off-by: Zahari Doychev Reviewed-by: Simon Horman Reviewed-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- include/net/flow_dissector.h | 21 +++++++++++++++++++++ net/core/flow_dissector.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 8b41668c77fc..8664ed4fbbdf 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -301,6 +301,26 @@ struct flow_dissector_key_l2tpv3 { __be32 session_id; }; +/** + * struct flow_dissector_key_cfm + * @mdl_ver: maintenance domain level (mdl) and cfm protocol version + * @opcode: code specifying a type of cfm protocol packet + * + * See 802.1ag, ITU-T G.8013/Y.1731 + * 1 2 + * |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | mdl | version | opcode | + * +-----+---------+-+-+-+-+-+-+-+-+ + */ +struct flow_dissector_key_cfm { + u8 mdl_ver; + u8 opcode; +}; + +#define FLOW_DIS_CFM_MDL_MASK GENMASK(7, 5) +#define FLOW_DIS_CFM_MDL_MAX 7 + enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ @@ -333,6 +353,7 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_NUM_OF_VLANS, /* struct flow_dissector_key_num_of_vlans */ FLOW_DISSECTOR_KEY_PPPOE, /* struct flow_dissector_key_pppoe */ FLOW_DISSECTOR_KEY_L2TPV3, /* struct flow_dissector_key_l2tpv3 */ + FLOW_DISSECTOR_KEY_CFM, /* struct flow_dissector_key_cfm */ FLOW_DISSECTOR_KEY_MAX, }; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 481ca4080cbd..85a2d0d9bd39 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -557,6 +557,30 @@ __skb_flow_dissect_arp(const struct sk_buff *skb, return FLOW_DISSECT_RET_OUT_GOOD; } +static enum flow_dissect_ret +__skb_flow_dissect_cfm(const struct sk_buff *skb, + struct flow_dissector *flow_dissector, + void *target_container, const void *data, + int nhoff, int hlen) +{ + struct flow_dissector_key_cfm *key, *hdr, _hdr; + + if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_CFM)) + return FLOW_DISSECT_RET_OUT_GOOD; + + hdr = __skb_header_pointer(skb, nhoff, sizeof(*key), data, hlen, &_hdr); + if (!hdr) + return FLOW_DISSECT_RET_OUT_BAD; + + key = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_CFM, + target_container); + + key->mdl_ver = hdr->mdl_ver; + key->opcode = hdr->opcode; + + return FLOW_DISSECT_RET_OUT_GOOD; +} + static enum flow_dissect_ret __skb_flow_dissect_gre(const struct sk_buff *skb, struct flow_dissector_key_control *key_control, @@ -1400,6 +1424,12 @@ proto_again: break; } + case htons(ETH_P_CFM): + fdret = __skb_flow_dissect_cfm(skb, flow_dissector, + target_container, data, + nhoff, hlen); + break; + default: fdret = FLOW_DISSECT_RET_OUT_BAD; break; -- cgit v1.2.3 From 7cfffd5fed3e385010583840402f0bf66c4ed147 Mon Sep 17 00:00:00 2001 From: Zahari Doychev Date: Thu, 8 Jun 2023 12:56:47 +0200 Subject: net: flower: add support for matching cfm fields Add support to the tc flower classifier to match based on fields in CFM information elements like level and opcode. tc filter add dev ens6 ingress protocol 802.1q \ flower vlan_id 698 vlan_ethtype 0x8902 cfm mdl 5 op 46 \ action drop Signed-off-by: Zahari Doychev Reviewed-by: Simon Horman Reviewed-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- include/uapi/linux/pkt_cls.h | 9 ++++ net/sched/cls_flower.c | 102 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h index 00933dda7b10..7865f5a9885b 100644 --- a/include/uapi/linux/pkt_cls.h +++ b/include/uapi/linux/pkt_cls.h @@ -596,6 +596,8 @@ enum { TCA_FLOWER_L2_MISS, /* u8 */ + TCA_FLOWER_KEY_CFM, /* nested */ + __TCA_FLOWER_MAX, }; @@ -704,6 +706,13 @@ enum { TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1), }; +enum { + TCA_FLOWER_KEY_CFM_OPT_UNSPEC, + TCA_FLOWER_KEY_CFM_MD_LEVEL, + TCA_FLOWER_KEY_CFM_OPCODE, + TCA_FLOWER_KEY_CFM_OPT_MAX, +}; + #define TCA_FLOWER_MASK_FLAGS_RANGE (1 << 0) /* Range-based match */ /* Match-all classifier */ diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index e02ecabbb75c..56065cc5a661 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,7 @@ struct fl_flow_key { struct flow_dissector_key_num_of_vlans num_of_vlans; struct flow_dissector_key_pppoe pppoe; struct flow_dissector_key_l2tpv3 l2tpv3; + struct flow_dissector_key_cfm cfm; } __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */ struct fl_flow_mask_range { @@ -725,6 +727,7 @@ static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = { [TCA_FLOWER_KEY_PPP_PROTO] = { .type = NLA_U16 }, [TCA_FLOWER_KEY_L2TPV3_SID] = { .type = NLA_U32 }, [TCA_FLOWER_L2_MISS] = NLA_POLICY_MAX(NLA_U8, 1), + [TCA_FLOWER_KEY_CFM] = { .type = NLA_NESTED }, }; static const struct nla_policy @@ -773,6 +776,12 @@ mpls_stack_entry_policy[TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX + 1] = { [TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL] = { .type = NLA_U32 }, }; +static const struct nla_policy cfm_opt_policy[TCA_FLOWER_KEY_CFM_OPT_MAX] = { + [TCA_FLOWER_KEY_CFM_MD_LEVEL] = NLA_POLICY_MAX(NLA_U8, + FLOW_DIS_CFM_MDL_MAX), + [TCA_FLOWER_KEY_CFM_OPCODE] = { .type = NLA_U8 }, +}; + static void fl_set_key_val(struct nlattr **tb, void *val, int val_type, void *mask, int mask_type, int len) @@ -1660,6 +1669,53 @@ static bool is_vlan_key(struct nlattr *tb, __be16 *ethertype, return false; } +static void fl_set_key_cfm_md_level(struct nlattr **tb, + struct fl_flow_key *key, + struct fl_flow_key *mask, + struct netlink_ext_ack *extack) +{ + u8 level; + + if (!tb[TCA_FLOWER_KEY_CFM_MD_LEVEL]) + return; + + level = nla_get_u8(tb[TCA_FLOWER_KEY_CFM_MD_LEVEL]); + key->cfm.mdl_ver = FIELD_PREP(FLOW_DIS_CFM_MDL_MASK, level); + mask->cfm.mdl_ver = FLOW_DIS_CFM_MDL_MASK; +} + +static void fl_set_key_cfm_opcode(struct nlattr **tb, + struct fl_flow_key *key, + struct fl_flow_key *mask, + struct netlink_ext_ack *extack) +{ + fl_set_key_val(tb, &key->cfm.opcode, TCA_FLOWER_KEY_CFM_OPCODE, + &mask->cfm.opcode, TCA_FLOWER_UNSPEC, + sizeof(key->cfm.opcode)); +} + +static int fl_set_key_cfm(struct nlattr **tb, + struct fl_flow_key *key, + struct fl_flow_key *mask, + struct netlink_ext_ack *extack) +{ + struct nlattr *nla_cfm_opt[TCA_FLOWER_KEY_CFM_OPT_MAX]; + int err; + + if (!tb[TCA_FLOWER_KEY_CFM]) + return 0; + + err = nla_parse_nested(nla_cfm_opt, TCA_FLOWER_KEY_CFM_OPT_MAX, + tb[TCA_FLOWER_KEY_CFM], cfm_opt_policy, extack); + if (err < 0) + return err; + + fl_set_key_cfm_opcode(nla_cfm_opt, key, mask, extack); + fl_set_key_cfm_md_level(nla_cfm_opt, key, mask, extack); + + return 0; +} + static int fl_set_key(struct net *net, struct nlattr **tb, struct fl_flow_key *key, struct fl_flow_key *mask, struct netlink_ext_ack *extack) @@ -1814,6 +1870,10 @@ static int fl_set_key(struct net *net, struct nlattr **tb, TCA_FLOWER_KEY_L2TPV3_SID, &mask->l2tpv3.session_id, TCA_FLOWER_UNSPEC, sizeof(key->l2tpv3.session_id)); + } else if (key->basic.n_proto == htons(ETH_P_CFM)) { + ret = fl_set_key_cfm(tb, key, mask, extack); + if (ret) + return ret; } if (key->basic.ip_proto == IPPROTO_TCP || @@ -1996,6 +2056,8 @@ static void fl_init_dissector(struct flow_dissector *dissector, FLOW_DISSECTOR_KEY_PPPOE, pppoe); FL_KEY_SET_IF_MASKED(mask, keys, cnt, FLOW_DISSECTOR_KEY_L2TPV3, l2tpv3); + FL_KEY_SET_IF_MASKED(mask, keys, cnt, + FLOW_DISSECTOR_KEY_CFM, cfm); skb_flow_dissector_init(dissector, keys, cnt); } @@ -3029,6 +3091,43 @@ nla_put_failure: return -EMSGSIZE; } +static int fl_dump_key_cfm(struct sk_buff *skb, + struct flow_dissector_key_cfm *key, + struct flow_dissector_key_cfm *mask) +{ + struct nlattr *opts; + int err; + u8 mdl; + + if (!memchr_inv(mask, 0, sizeof(*mask))) + return 0; + + opts = nla_nest_start(skb, TCA_FLOWER_KEY_CFM); + if (!opts) + return -EMSGSIZE; + + if (FIELD_GET(FLOW_DIS_CFM_MDL_MASK, mask->mdl_ver)) { + mdl = FIELD_GET(FLOW_DIS_CFM_MDL_MASK, key->mdl_ver); + err = nla_put_u8(skb, TCA_FLOWER_KEY_CFM_MD_LEVEL, mdl); + if (err) + goto err_cfm_opts; + } + + if (mask->opcode) { + err = nla_put_u8(skb, TCA_FLOWER_KEY_CFM_OPCODE, key->opcode); + if (err) + goto err_cfm_opts; + } + + nla_nest_end(skb, opts); + + return 0; + +err_cfm_opts: + nla_nest_cancel(skb, opts); + return err; +} + static int fl_dump_key_options(struct sk_buff *skb, int enc_opt_type, struct flow_dissector_key_enc_opts *enc_opts) { @@ -3316,6 +3415,9 @@ static int fl_dump_key(struct sk_buff *skb, struct net *net, sizeof(key->hash.hash))) goto nla_put_failure; + if (fl_dump_key_cfm(skb, &key->cfm, &mask->cfm)) + goto nla_put_failure; + return 0; nla_put_failure: -- cgit v1.2.3 From 1668a55a73f5a3ddde1019695223eed8e23b9436 Mon Sep 17 00:00:00 2001 From: Zahari Doychev Date: Thu, 8 Jun 2023 12:56:48 +0200 Subject: selftests: net: add tc flower cfm test New cfm flower test case is added to the net forwarding selfttests. Example output: # ./tc_flower_cfm.sh p1 p2 TEST: CFM opcode match test [ OK ] TEST: CFM level match test [ OK ] TEST: CFM opcode and level match test [ OK ] Signed-off-by: Zahari Doychev Reviewed-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/Makefile | 1 + .../selftests/net/forwarding/tc_flower_cfm.sh | 206 +++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_flower_cfm.sh diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile index 9d0062b542e5..770efbe24f0d 100644 --- a/tools/testing/selftests/net/forwarding/Makefile +++ b/tools/testing/selftests/net/forwarding/Makefile @@ -84,6 +84,7 @@ TEST_PROGS = bridge_igmp.sh \ tc_flower_router.sh \ tc_flower.sh \ tc_flower_l2_miss.sh \ + tc_flower_cfm.sh \ tc_mpls_l2vpn.sh \ tc_police.sh \ tc_shblocks.sh \ diff --git a/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh b/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh new file mode 100755 index 000000000000..3ca20df952eb --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_flower_cfm.sh @@ -0,0 +1,206 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ALL_TESTS="match_cfm_opcode match_cfm_level match_cfm_level_and_opcode" +NUM_NETIFS=2 +source tc_common.sh +source lib.sh + +h1_create() +{ + simple_if_init $h1 +} + +h1_destroy() +{ + simple_if_fini $h1 +} + +h2_create() +{ + simple_if_init $h2 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 +} + +u8_to_hex() +{ + local u8=$1; shift + + printf "%02x" $u8 +} + +generate_cfm_hdr() +{ + local mdl=$1; shift + local op=$1; shift + local flags=$1; shift + local tlv_offset=$1; shift + + local cfm_hdr=$(: + )"$(u8_to_hex $((mdl << 5))):"$( : MD level and Version + )"$(u8_to_hex $op):"$( : OpCode + )"$(u8_to_hex $flags):"$( : Flags + )"$(u8_to_hex $tlv_offset)"$( : TLV offset + ) + + echo $cfm_hdr +} + +match_cfm_opcode() +{ + local ethtype="89 02"; readonly ethtype + RET=0 + + tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \ + flower cfm op 47 action drop + tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \ + flower cfm op 43 action drop + + pkt="$ethtype $(generate_cfm_hdr 7 47 0 32)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 6 5 0 4)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match on correct opcode" + + tc_check_packets "dev $h2 ingress" 102 0 + check_err $? "Matched on the wrong opcode" + + pkt="$ethtype $(generate_cfm_hdr 0 43 0 12)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Matched on the wrong opcode" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct opcode" + + tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower + + log_test "CFM opcode match test" +} + +match_cfm_level() +{ + local ethtype="89 02"; readonly ethtype + RET=0 + + tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \ + flower cfm mdl 5 action drop + tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \ + flower cfm mdl 3 action drop + tc filter add dev $h2 ingress protocol cfm pref 1 handle 103 \ + flower cfm mdl 0 action drop + + pkt="$ethtype $(generate_cfm_hdr 5 42 0 12)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 6 1 0 70)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 0 1 0 70)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match on correct level" + + tc_check_packets "dev $h2 ingress" 102 0 + check_err $? "Matched on the wrong level" + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Did not match on correct level" + + pkt="$ethtype $(generate_cfm_hdr 3 0 0 4)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Matched on the wrong level" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct level" + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Matched on the wrong level" + + tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower + tc filter del dev $h2 ingress protocol cfm pref 1 handle 103 flower + + log_test "CFM level match test" +} + +match_cfm_level_and_opcode() +{ + local ethtype="89 02"; readonly ethtype + RET=0 + + tc filter add dev $h2 ingress protocol cfm pref 1 handle 101 \ + flower cfm mdl 5 op 41 action drop + tc filter add dev $h2 ingress protocol cfm pref 1 handle 102 \ + flower cfm mdl 7 op 42 action drop + + pkt="$ethtype $(generate_cfm_hdr 5 41 0 4)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 7 3 0 4)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + pkt="$ethtype $(generate_cfm_hdr 3 42 0 12)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match on correct level and opcode" + + tc_check_packets "dev $h2 ingress" 102 0 + check_err $? "Matched on the wrong level and opcode" + + pkt="$ethtype $(generate_cfm_hdr 7 42 0 12)" + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac "$pkt" -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Matched on the wrong level and opcode" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct level and opcode" + + tc filter del dev $h2 ingress protocol cfm pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol cfm pref 1 handle 102 flower + + log_test "CFM opcode and level match test" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + h2=${NETIFS[p2]} + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + vrf_prepare + + h1_create + h2_create +} + +cleanup() +{ + pre_cleanup + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +tests_run + +exit $EXIT_STATUS -- cgit v1.2.3 From a3bbdc52c38fa95488ca713e54bcb40699c26acf Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 9 Jun 2023 11:02:16 +0100 Subject: Remove file->f_op->sendpage Remove file->f_op->sendpage as splicing to a socket now calls sendmsg rather than sendpage. Signed-off-by: David Howells cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/linux/fs.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index de2cb1132f07..67998c64556d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1790,7 +1790,6 @@ struct file_operations { int (*fsync) (struct file *, loff_t, loff_t, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); - ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*flock) (struct file *, int, struct file_lock *); -- cgit v1.2.3 From 345ee3e8126aa042e8b4c61ed9eca42e9334b09e Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 9 Jun 2023 11:02:17 +0100 Subject: algif: Remove hash_sendpage*() Remove hash_sendpage*() as nothing should now call it since the rewrite of splice_to_socket()[1]. Signed-off-by: David Howells cc: Herbert Xu cc: Jens Axboe cc: Matthew Wilcox Link: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=2dc334f1a63a8839b88483a3e73c0f27c9c1791c [1] Signed-off-by: Jakub Kicinski --- crypto/algif_hash.c | 66 ----------------------------------------------------- 1 file changed, 66 deletions(-) diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index 1a2d80c6c91a..dfb048cefb60 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -161,58 +161,6 @@ unlock_free: goto unlock; } -static ssize_t hash_sendpage(struct socket *sock, struct page *page, - int offset, size_t size, int flags) -{ - struct sock *sk = sock->sk; - struct alg_sock *ask = alg_sk(sk); - struct hash_ctx *ctx = ask->private; - int err; - - if (flags & MSG_SENDPAGE_NOTLAST) - flags |= MSG_MORE; - - lock_sock(sk); - sg_init_table(ctx->sgl.sgl, 1); - sg_set_page(ctx->sgl.sgl, page, size, offset); - - if (!(flags & MSG_MORE)) { - err = hash_alloc_result(sk, ctx); - if (err) - goto unlock; - } else if (!ctx->more) - hash_free_result(sk, ctx); - - ahash_request_set_crypt(&ctx->req, ctx->sgl.sgl, ctx->result, size); - - if (!(flags & MSG_MORE)) { - if (ctx->more) - err = crypto_ahash_finup(&ctx->req); - else - err = crypto_ahash_digest(&ctx->req); - } else { - if (!ctx->more) { - err = crypto_ahash_init(&ctx->req); - err = crypto_wait_req(err, &ctx->wait); - if (err) - goto unlock; - } - - err = crypto_ahash_update(&ctx->req); - } - - err = crypto_wait_req(err, &ctx->wait); - if (err) - goto unlock; - - ctx->more = flags & MSG_MORE; - -unlock: - release_sock(sk); - - return err ?: size; -} - static int hash_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) { @@ -328,7 +276,6 @@ static struct proto_ops algif_hash_ops = { .release = af_alg_release, .sendmsg = hash_sendmsg, - .sendpage = hash_sendpage, .recvmsg = hash_recvmsg, .accept = hash_accept, }; @@ -380,18 +327,6 @@ static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg, return hash_sendmsg(sock, msg, size); } -static ssize_t hash_sendpage_nokey(struct socket *sock, struct page *page, - int offset, size_t size, int flags) -{ - int err; - - err = hash_check_key(sock); - if (err) - return err; - - return hash_sendpage(sock, page, offset, size, flags); -} - static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { @@ -430,7 +365,6 @@ static struct proto_ops algif_hash_ops_nokey = { .release = af_alg_release, .sendmsg = hash_sendmsg_nokey, - .sendpage = hash_sendpage_nokey, .recvmsg = hash_recvmsg_nokey, .accept = hash_accept_nokey, }; -- cgit v1.2.3 From 5df5dd03a8f71ca9640f208d8f523856e1069ee7 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 9 Jun 2023 11:02:18 +0100 Subject: sunrpc: Use sendmsg(MSG_SPLICE_PAGES) rather then sendpage When transmitting data, call down into TCP using sendmsg with MSG_SPLICE_PAGES to indicate that content should be spliced rather than performing sendpage calls to transmit header, data pages and trailer. Signed-off-by: David Howells Acked-by: Chuck Lever cc: Trond Myklebust cc: Anna Schumaker cc: Jeff Layton cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/linux/sunrpc/svc.h | 11 +++++------ net/sunrpc/svcsock.c | 38 ++++++++++++-------------------------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 762d7231e574..f66ec8fdb331 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -161,16 +161,15 @@ static inline bool svc_put_not_last(struct svc_serv *serv) extern u32 svc_max_payload(const struct svc_rqst *rqstp); /* - * RPC Requsts and replies are stored in one or more pages. + * RPC Requests and replies are stored in one or more pages. * We maintain an array of pages for each server thread. * Requests are copied into these pages as they arrive. Remaining * pages are available to write the reply into. * - * Pages are sent using ->sendpage so each server thread needs to - * allocate more to replace those used in sending. To help keep track - * of these pages we have a receive list where all pages initialy live, - * and a send list where pages are moved to when there are to be part - * of a reply. + * Pages are sent using ->sendmsg with MSG_SPLICE_PAGES so each server thread + * needs to allocate more to replace those used in sending. To help keep track + * of these pages we have a receive list where all pages initialy live, and a + * send list where pages are moved to when there are to be part of a reply. * * We use xdr_buf for holding responses as it fits well with NFS * read responses (that have a header, and some data pages, and possibly diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index f77cebe2c071..9d9f522e3ae1 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -1203,13 +1203,14 @@ err_noclose: static int svc_tcp_send_kvec(struct socket *sock, const struct kvec *vec, int flags) { - return kernel_sendpage(sock, virt_to_page(vec->iov_base), - offset_in_page(vec->iov_base), - vec->iov_len, flags); + struct msghdr msg = { .msg_flags = MSG_SPLICE_PAGES | flags, }; + + iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, vec, 1, vec->iov_len); + return sock_sendmsg(sock, &msg); } /* - * kernel_sendpage() is used exclusively to reduce the number of + * MSG_SPLICE_PAGES is used exclusively to reduce the number of * copy operations in this path. Therefore the caller must ensure * that the pages backing @xdr are unchanging. * @@ -1249,28 +1250,13 @@ static int svc_tcp_sendmsg(struct socket *sock, struct xdr_buf *xdr, if (ret != head->iov_len) goto out; - if (xdr->page_len) { - unsigned int offset, len, remaining; - struct bio_vec *bvec; - - bvec = xdr->bvec + (xdr->page_base >> PAGE_SHIFT); - offset = offset_in_page(xdr->page_base); - remaining = xdr->page_len; - while (remaining > 0) { - len = min(remaining, bvec->bv_len - offset); - ret = kernel_sendpage(sock, bvec->bv_page, - bvec->bv_offset + offset, - len, 0); - if (ret < 0) - return ret; - *sentp += ret; - if (ret != len) - goto out; - remaining -= len; - offset = 0; - bvec++; - } - } + msg.msg_flags = MSG_SPLICE_PAGES; + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, xdr->bvec, + xdr_buf_pagecount(xdr), xdr->page_len); + ret = sock_sendmsg(sock, &msg); + if (ret < 0) + return ret; + *sentp += ret; if (tail->iov_len) { ret = svc_tcp_send_kvec(sock, tail, 0); -- cgit v1.2.3 From de17c6857301f1f5b0e71dd064bb816d6628a91d Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 9 Jun 2023 11:02:19 +0100 Subject: tcp_bpf: Make tcp_bpf_sendpage() go through tcp_bpf_sendmsg(MSG_SPLICE_PAGES) Make tcp_bpf_sendpage() a wrapper around tcp_bpf_sendmsg(MSG_SPLICE_PAGES) rather than a loop calling tcp_sendpage(). sendpage() will be removed in the future. Signed-off-by: David Howells cc: John Fastabend cc: Jakub Sitnicki cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_bpf.c | 49 +++++++++---------------------------------------- 1 file changed, 9 insertions(+), 40 deletions(-) diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index e75023ea052f..5a84053ac62b 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -568,49 +568,18 @@ out_err: static int tcp_bpf_sendpage(struct sock *sk, struct page *page, int offset, size_t size, int flags) { - struct sk_msg tmp, *msg = NULL; - int err = 0, copied = 0; - struct sk_psock *psock; - bool enospc = false; - - psock = sk_psock_get(sk); - if (unlikely(!psock)) - return tcp_sendpage(sk, page, offset, size, flags); + struct bio_vec bvec; + struct msghdr msg = { + .msg_flags = flags | MSG_SPLICE_PAGES, + }; - lock_sock(sk); - if (psock->cork) { - msg = psock->cork; - } else { - msg = &tmp; - sk_msg_init(msg); - } + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - /* Catch case where ring is full and sendpage is stalled. */ - if (unlikely(sk_msg_full(msg))) - goto out_err; - - sk_msg_page_add(msg, page, size, offset); - sk_mem_charge(sk, size); - copied = size; - if (sk_msg_full(msg)) - enospc = true; - if (psock->cork_bytes) { - if (size > psock->cork_bytes) - psock->cork_bytes = 0; - else - psock->cork_bytes -= size; - if (psock->cork_bytes && !enospc) - goto out_err; - /* All cork bytes are accounted, rerun the prog. */ - psock->eval = __SK_NONE; - psock->cork_bytes = 0; - } + if (flags & MSG_SENDPAGE_NOTLAST) + msg.msg_flags |= MSG_MORE; - err = tcp_bpf_send_verdict(sk, psock, msg, &copied, flags); -out_err: - release_sock(sk); - sk_psock_put(sk, psock); - return copied ? copied : err; + return tcp_bpf_sendmsg(sk, &msg, size); } enum { -- cgit v1.2.3 From 264ba53fac79b03ff754bce62da5027ee3c57b8f Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 9 Jun 2023 11:02:20 +0100 Subject: kcm: Use sendmsg(MSG_SPLICE_PAGES) rather then sendpage When transmitting data, call down into the transport socket using sendmsg with MSG_SPLICE_PAGES to indicate that content should be spliced rather than using sendpage. Signed-off-by: David Howells cc: Tom Herbert cc: Tom Herbert cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- net/kcm/kcmsock.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 7dee74430b59..3bcac1453f10 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -641,6 +641,10 @@ do_frag_list: for (fragidx = 0; fragidx < skb_shinfo(skb)->nr_frags; fragidx++) { + struct bio_vec bvec; + struct msghdr msg = { + .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, + }; skb_frag_t *frag; frag_offset = 0; @@ -651,11 +655,13 @@ do_frag: goto out; } - ret = kernel_sendpage(psock->sk->sk_socket, - skb_frag_page(frag), - skb_frag_off(frag) + frag_offset, - skb_frag_size(frag) - frag_offset, - MSG_DONTWAIT); + bvec_set_page(&bvec, + skb_frag_page(frag), + skb_frag_size(frag) - frag_offset, + skb_frag_off(frag) + frag_offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, + bvec.bv_len); + ret = sock_sendmsg(psock->sk->sk_socket, &msg); if (ret <= 0) { if (ret == -EAGAIN) { /* Save state to try again when there's -- cgit v1.2.3 From c31a25e1db486f36a0ffe3c849b0a82cda3db7db Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 9 Jun 2023 11:02:21 +0100 Subject: kcm: Send multiple frags in one sendmsg() Rewrite the AF_KCM transmission loop to send all the fragments in a single skb or frag_list-skb in one sendmsg() with MSG_SPLICE_PAGES set. The list of fragments in each skb is conveniently a bio_vec[] that can just be attached to a BVEC iter. Note: I'm working out the size of each fragment-skb by adding up bv_len for all the bio_vecs in skb->frags[] - but surely this information is recorded somewhere? For the skbs in head->frag_list, this is equal to skb->data_len, but not for the head. head->data_len includes all the tail frags too. Signed-off-by: David Howells cc: Tom Herbert cc: Tom Herbert cc: Jens Axboe cc: Matthew Wilcox Signed-off-by: Jakub Kicinski --- include/net/kcm.h | 2 +- net/kcm/kcmsock.c | 126 ++++++++++++++++++++++-------------------------------- 2 files changed, 51 insertions(+), 77 deletions(-) diff --git a/include/net/kcm.h b/include/net/kcm.h index 2d704f8f4905..90279e5e09a5 100644 --- a/include/net/kcm.h +++ b/include/net/kcm.h @@ -47,9 +47,9 @@ struct kcm_stats { struct kcm_tx_msg { unsigned int sent; - unsigned int fragidx; unsigned int frag_offset; unsigned int msg_flags; + bool started_tx; struct sk_buff *frag_skb; struct sk_buff *last_skb; }; diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 3bcac1453f10..d75d775e9462 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -581,12 +581,10 @@ static void kcm_report_tx_retry(struct kcm_sock *kcm) */ static int kcm_write_msgs(struct kcm_sock *kcm) { + unsigned int total_sent = 0; struct sock *sk = &kcm->sk; struct kcm_psock *psock; - struct sk_buff *skb, *head; - struct kcm_tx_msg *txm; - unsigned short fragidx, frag_offset; - unsigned int sent, total_sent = 0; + struct sk_buff *head; int ret = 0; kcm->tx_wait_more = false; @@ -600,78 +598,57 @@ static int kcm_write_msgs(struct kcm_sock *kcm) if (skb_queue_empty(&sk->sk_write_queue)) return 0; - kcm_tx_msg(skb_peek(&sk->sk_write_queue))->sent = 0; - - } else if (skb_queue_empty(&sk->sk_write_queue)) { - return 0; + kcm_tx_msg(skb_peek(&sk->sk_write_queue))->started_tx = false; } - head = skb_peek(&sk->sk_write_queue); - txm = kcm_tx_msg(head); - - if (txm->sent) { - /* Send of first skbuff in queue already in progress */ - if (WARN_ON(!psock)) { - ret = -EINVAL; - goto out; +retry: + while ((head = skb_peek(&sk->sk_write_queue))) { + struct msghdr msg = { + .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, + }; + struct kcm_tx_msg *txm = kcm_tx_msg(head); + struct sk_buff *skb; + unsigned int msize; + int i; + + if (!txm->started_tx) { + psock = reserve_psock(kcm); + if (!psock) + goto out; + skb = head; + txm->frag_offset = 0; + txm->sent = 0; + txm->started_tx = true; + } else { + if (WARN_ON(!psock)) { + ret = -EINVAL; + goto out; + } + skb = txm->frag_skb; } - sent = txm->sent; - frag_offset = txm->frag_offset; - fragidx = txm->fragidx; - skb = txm->frag_skb; - - goto do_frag; - } - -try_again: - psock = reserve_psock(kcm); - if (!psock) - goto out; - - do { - skb = head; - txm = kcm_tx_msg(head); - sent = 0; -do_frag_list: if (WARN_ON(!skb_shinfo(skb)->nr_frags)) { ret = -EINVAL; goto out; } - for (fragidx = 0; fragidx < skb_shinfo(skb)->nr_frags; - fragidx++) { - struct bio_vec bvec; - struct msghdr msg = { - .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, - }; - skb_frag_t *frag; - - frag_offset = 0; -do_frag: - frag = &skb_shinfo(skb)->frags[fragidx]; - if (WARN_ON(!skb_frag_size(frag))) { - ret = -EINVAL; - goto out; - } + msize = 0; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + msize += skb_shinfo(skb)->frags[i].bv_len; + + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, + skb_shinfo(skb)->frags, skb_shinfo(skb)->nr_frags, + msize); + iov_iter_advance(&msg.msg_iter, txm->frag_offset); - bvec_set_page(&bvec, - skb_frag_page(frag), - skb_frag_size(frag) - frag_offset, - skb_frag_off(frag) + frag_offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, - bvec.bv_len); + do { ret = sock_sendmsg(psock->sk->sk_socket, &msg); if (ret <= 0) { if (ret == -EAGAIN) { /* Save state to try again when there's * write space on the socket */ - txm->sent = sent; - txm->frag_offset = frag_offset; - txm->fragidx = fragidx; txm->frag_skb = skb; - ret = 0; goto out; } @@ -685,39 +662,36 @@ do_frag: true); unreserve_psock(kcm); - txm->sent = 0; + txm->started_tx = false; kcm_report_tx_retry(kcm); ret = 0; - - goto try_again; + goto retry; } - sent += ret; - frag_offset += ret; + txm->sent += ret; + txm->frag_offset += ret; KCM_STATS_ADD(psock->stats.tx_bytes, ret); - if (frag_offset < skb_frag_size(frag)) { - /* Not finished with this frag */ - goto do_frag; - } - } + } while (msg.msg_iter.count > 0); if (skb == head) { if (skb_has_frag_list(skb)) { - skb = skb_shinfo(skb)->frag_list; - goto do_frag_list; + txm->frag_skb = skb_shinfo(skb)->frag_list; + txm->frag_offset = 0; + continue; } } else if (skb->next) { - skb = skb->next; - goto do_frag_list; + txm->frag_skb = skb->next; + txm->frag_offset = 0; + continue; } /* Successfully sent the whole packet, account for it. */ + sk->sk_wmem_queued -= txm->sent; + total_sent += txm->sent; skb_dequeue(&sk->sk_write_queue); kfree_skb(head); - sk->sk_wmem_queued -= sent; - total_sent += sent; KCM_STATS_INCR(psock->stats.tx_msgs); - } while ((head = skb_peek(&sk->sk_write_queue))); + } out: if (!head) { /* Done with all queued messages. */ -- cgit v1.2.3 From 91ccdbb94feadb0d8bf3b35c841b33ac95f2f45f Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 7 Jun 2023 09:27:41 +0800 Subject: wifi: rtw88: add missing unwind goto for __rtw_download_firmware() This flaw is detected by smatch: drivers/net/wireless/realtek/rtw88/mac.c:748 __rtw_download_firmware() warn: missing unwind goto? Though most things of dlfw_fail have been done by download_firmware_end_flow() and wlan_cpu_enable(), an exception is that download_firmware_end_flow() clear BIT_MCUFWDL_EN bit conditionally. So, make this change to clear the bit. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202306052310.OVhcUjZ3-lkp@intel.com/ Cc: Sascha Hauer Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230607012741.10353-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/mac.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index a168f36c38ec..298663b03580 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -794,8 +794,10 @@ static int __rtw_download_firmware(struct rtw_dev *rtwdev, wlan_cpu_enable(rtwdev, true); - if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) - return -EBUSY; + if (!ltecoex_reg_write(rtwdev, 0x38, ltecoex_bckp)) { + ret = -EBUSY; + goto dlfw_fail; + } ret = download_firmware_validate(rtwdev); if (ret) -- cgit v1.2.3 From c29e012eae29c13f092a95f1ffab40a269fe5bc2 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Jun 2023 14:22:18 +0300 Subject: selftests: forwarding: Fix layer 2 miss test syntax The test currently specifies "l2_miss" as "true" / "false", but the version that eventually landed in iproute2 uses "1" / "0" [1]. Align the test accordingly. [1] https://lore.kernel.org/netdev/20230607153550.3829340-1-idosch@nvidia.com/ Fixes: 8c33266ae26a ("selftests: forwarding: Add layer 2 miss test cases") Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/tc_flower_l2_miss.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh index 37b0369b5246..e22c2d28b6eb 100755 --- a/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh +++ b/tools/testing/selftests/net/forwarding/tc_flower_l2_miss.sh @@ -78,11 +78,11 @@ test_l2_miss_unicast() # Unknown unicast. tc filter add dev $swp2 egress protocol ipv4 handle 101 pref 1 \ - flower indev $swp1 l2_miss true dst_mac $dmac src_ip $sip \ + flower indev $swp1 l2_miss 1 dst_mac $dmac src_ip $sip \ dst_ip $dip action pass # Known unicast. tc filter add dev $swp2 egress protocol ipv4 handle 102 pref 1 \ - flower indev $swp1 l2_miss false dst_mac $dmac src_ip $sip \ + flower indev $swp1 l2_miss 0 dst_mac $dmac src_ip $sip \ dst_ip $dip action pass # Before adding FDB entry. @@ -134,11 +134,11 @@ test_l2_miss_multicast_common() # Unregistered multicast. tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \ - flower indev $swp1 l2_miss true src_ip $sip dst_ip $dip \ + flower indev $swp1 l2_miss 1 src_ip $sip dst_ip $dip \ action pass # Registered multicast. tc filter add dev $swp2 egress protocol $proto handle 102 pref 1 \ - flower indev $swp1 l2_miss false src_ip $sip dst_ip $dip \ + flower indev $swp1 l2_miss 0 src_ip $sip dst_ip $dip \ action pass # Before adding MDB entry. @@ -245,7 +245,7 @@ test_l2_miss_ll_multicast_common() RET=0 tc filter add dev $swp2 egress protocol $proto handle 101 pref 1 \ - flower indev $swp1 l2_miss true dst_mac $dmac src_ip $sip \ + flower indev $swp1 l2_miss 1 dst_mac $dmac src_ip $sip \ dst_ip $dip action pass $MZ $mode $h1 -a own -b $dmac -t ip -A $sip -B $dip -c 1 -p 100 -q @@ -296,10 +296,10 @@ test_l2_miss_broadcast() RET=0 tc filter add dev $swp2 egress protocol all handle 101 pref 1 \ - flower l2_miss true dst_mac $dmac src_mac $smac \ + flower l2_miss 1 dst_mac $dmac src_mac $smac \ action pass tc filter add dev $swp2 egress protocol all handle 102 pref 1 \ - flower l2_miss false dst_mac $dmac src_mac $smac \ + flower l2_miss 0 dst_mac $dmac src_mac $smac \ action pass $MZ $h1 -a $smac -b $dmac -c 1 -p 100 -q -- cgit v1.2.3 From 09de114c770fef0c8c586b4dd59431226d873387 Mon Sep 17 00:00:00 2001 From: Naveen Mamindlapalli Date: Mon, 12 Jun 2023 11:34:19 +0530 Subject: octeontx2-af: Add devlink option to adjust mcam high prio zone entries The NPC MCAM entries are currently divided into three priority zones in AF driver: high, mid, and low. The high priority zone and low priority zone take up 1/8th (each) of the available MCAM entries, and remaining going to the mid priority zone. The current allocation scheme may not meet certain requirements, such as when a requester needs more high priority zone entries than are reserved. This patch adds a devlink configurable option to increase the number of high priority zone entries that can be allocated by requester. The max number of entries that can be reserved for high priority usage is 100% of available MCAM entries. Usage: 1) Change high priority zone percentage to 75%: devlink -p dev param set pci/0002:01:00.0 name npc_mcam_high_zone_percent \ value 75 cmode runtime 2) Read high priority zone percentage: devlink -p dev param show pci/0002:01:00.0 name npc_mcam_high_zone_percent The devlink set configuration is only permitted when no MCAM entries are assigned, i.e., all MCAM entries are free, indicating that no PF/VF driver is loaded. So user must unload/unbind PF/VF driver/devices before modifying the high priority zone percentage. Signed-off-by: Naveen Mamindlapalli Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../ethernet/marvell/octeontx2/af/rvu_devlink.c | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c index e4407f09c9d3..548549604c49 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c @@ -1438,6 +1438,7 @@ enum rvu_af_dl_param_id { RVU_AF_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU, RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE, + RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT, }; static int rvu_af_npc_exact_feature_get(struct devlink *devlink, u32 id, @@ -1494,6 +1495,67 @@ static int rvu_af_npc_exact_feature_validate(struct devlink *devlink, u32 id, return -EFAULT; } +static int rvu_af_dl_npc_mcam_high_zone_percent_get(struct devlink *devlink, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct rvu_devlink *rvu_dl = devlink_priv(devlink); + struct rvu *rvu = rvu_dl->rvu; + struct npc_mcam *mcam; + u32 percent; + + mcam = &rvu->hw->mcam; + percent = (mcam->hprio_count * 100) / mcam->bmap_entries; + ctx->val.vu8 = (u8)percent; + + return 0; +} + +static int rvu_af_dl_npc_mcam_high_zone_percent_set(struct devlink *devlink, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct rvu_devlink *rvu_dl = devlink_priv(devlink); + struct rvu *rvu = rvu_dl->rvu; + struct npc_mcam *mcam; + u32 percent; + + percent = ctx->val.vu8; + mcam = &rvu->hw->mcam; + mcam->hprio_count = (mcam->bmap_entries * percent) / 100; + mcam->hprio_end = mcam->hprio_count; + mcam->lprio_count = (mcam->bmap_entries - mcam->hprio_count) / 2; + mcam->lprio_start = mcam->bmap_entries - mcam->lprio_count; + + return 0; +} + +static int rvu_af_dl_npc_mcam_high_zone_percent_validate(struct devlink *devlink, u32 id, + union devlink_param_value val, + struct netlink_ext_ack *extack) +{ + struct rvu_devlink *rvu_dl = devlink_priv(devlink); + struct rvu *rvu = rvu_dl->rvu; + struct npc_mcam *mcam; + + /* The percent of high prio zone must range from 12% to 100% of unreserved mcam space */ + if (val.vu8 < 12 || val.vu8 > 100) { + NL_SET_ERR_MSG_MOD(extack, + "mcam high zone percent must be between 12% to 100%"); + return -EINVAL; + } + + /* Do not allow user to modify the high priority zone entries while mcam entries + * have already been assigned. + */ + mcam = &rvu->hw->mcam; + if (mcam->bmap_fcnt < mcam->bmap_entries) { + NL_SET_ERR_MSG_MOD(extack, + "mcam entries have already been assigned, can't resize"); + return -EPERM; + } + + return 0; +} + static const struct devlink_param rvu_af_dl_params[] = { DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU, "dwrr_mtu", DEVLINK_PARAM_TYPE_U32, @@ -1509,6 +1571,12 @@ static const struct devlink_param rvu_af_dl_param_exact_match[] = { rvu_af_npc_exact_feature_get, rvu_af_npc_exact_feature_disable, rvu_af_npc_exact_feature_validate), + DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT, + "npc_mcam_high_zone_percent", DEVLINK_PARAM_TYPE_U8, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + rvu_af_dl_npc_mcam_high_zone_percent_get, + rvu_af_dl_npc_mcam_high_zone_percent_set, + rvu_af_dl_npc_mcam_high_zone_percent_validate), }; /* Devlink switch mode */ -- cgit v1.2.3 From 79bc788c038c9c87224d41ba6bbab20b6bf1a141 Mon Sep 17 00:00:00 2001 From: Kiran Kumar K Date: Mon, 12 Jun 2023 11:34:20 +0530 Subject: octeontx2-af: extend RSS supported offload types Add support to select L3 SRC or DST only, L4 SRC or DST only for RSS calculation. AF consumer may have requirement as we can select only SRC or DST data for RSS calculation in L3, L4 layers. With this requirement there will be following combinations, IPV[4,6]_SRC_ONLY, IPV[4,6]_DST_ONLY, [TCP,UDP,SCTP]_SRC_ONLY, [TCP,UDP,SCTP]_DST_ONLY. So, instead of creating a bit for each combination, we are using upper 4 bits (31:28) in the flow_key_cfg to represent the SRC, DST selection. 31 => L3_SRC, 30 => L3_DST, 29 => L4_SRC, 28 => L4_DST. These won't be part of flow_cfg, so that we don't need to change the existing ABI. Signed-off-by: Kiran Kumar K Signed-off-by: Geetha sowjanya Signed-off-by: Naveen Mamindlapalli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 6 +++ .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 57 ++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 6389ed83637d..671fcf86ed87 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1080,6 +1080,8 @@ struct nix_vtag_config_rsp { */ }; +#define NIX_FLOW_KEY_TYPE_L3_L4_MASK (~(0xf << 28)) + struct nix_rss_flowkey_cfg { struct mbox_msghdr hdr; int mcam_index; /* MCAM entry index to modify */ @@ -1105,6 +1107,10 @@ struct nix_rss_flowkey_cfg { #define NIX_FLOW_KEY_TYPE_IPV4_PROTO BIT(21) #define NIX_FLOW_KEY_TYPE_AH BIT(22) #define NIX_FLOW_KEY_TYPE_ESP BIT(23) +#define NIX_FLOW_KEY_TYPE_L4_DST_ONLY BIT(28) +#define NIX_FLOW_KEY_TYPE_L4_SRC_ONLY BIT(29) +#define NIX_FLOW_KEY_TYPE_L3_DST_ONLY BIT(30) +#define NIX_FLOW_KEY_TYPE_L3_SRC_ONLY BIT(31) u32 flowkey_cfg; /* Flowkey types selected */ u8 group; /* RSS context or group */ }; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 79ed7af0b0a4..ee52b86c061f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -3353,6 +3353,7 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) struct nix_rx_flowkey_alg *field; struct nix_rx_flowkey_alg tmp; u32 key_type, valid_key; + u32 l3_l4_src_dst; int l4_key_offset = 0; if (!alg) @@ -3380,6 +3381,15 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) * group_member - Enabled when protocol is part of a group. */ + /* Last 4 bits (31:28) are reserved to specify SRC, DST + * selection for L3, L4 i.e IPV[4,6]_SRC, IPV[4,6]_DST, + * [TCP,UDP,SCTP]_SRC, [TCP,UDP,SCTP]_DST + * 31 => L3_SRC, 30 => L3_DST, 29 => L4_SRC, 28 => L4_DST + */ + l3_l4_src_dst = flow_cfg; + /* Reset these 4 bits, so that these won't be part of key */ + flow_cfg &= NIX_FLOW_KEY_TYPE_L3_L4_MASK; + keyoff_marker = 0; max_key_off = 0; group_member = 0; nr_field = 0; key_off = 0; field_marker = 1; field = &tmp; max_bit_pos = fls(flow_cfg); @@ -3417,6 +3427,22 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) } field->hdr_offset = 12; /* SIP offset */ field->bytesm1 = 7; /* SIP + DIP, 8 bytes */ + + /* Only SIP */ + if (l3_l4_src_dst & NIX_FLOW_KEY_TYPE_L3_SRC_ONLY) + field->bytesm1 = 3; /* SIP, 4 bytes */ + + if (l3_l4_src_dst & NIX_FLOW_KEY_TYPE_L3_DST_ONLY) { + /* Both SIP + DIP */ + if (field->bytesm1 == 3) { + field->bytesm1 = 7; /* SIP + DIP, 8B */ + } else { + /* Only DIP */ + field->hdr_offset = 16; /* DIP off */ + field->bytesm1 = 3; /* DIP, 4 bytes */ + } + } + field->ltype_mask = 0xF; /* Match only IPv4 */ keyoff_marker = false; break; @@ -3430,6 +3456,22 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) } field->hdr_offset = 8; /* SIP offset */ field->bytesm1 = 31; /* SIP + DIP, 32 bytes */ + + /* Only SIP */ + if (l3_l4_src_dst & NIX_FLOW_KEY_TYPE_L3_SRC_ONLY) + field->bytesm1 = 15; /* SIP, 16 bytes */ + + if (l3_l4_src_dst & NIX_FLOW_KEY_TYPE_L3_DST_ONLY) { + /* Both SIP + DIP */ + if (field->bytesm1 == 15) { + /* SIP + DIP, 32 bytes */ + field->bytesm1 = 31; + } else { + /* Only DIP */ + field->hdr_offset = 24; /* DIP off */ + field->bytesm1 = 15; /* DIP,16 bytes */ + } + } field->ltype_mask = 0xF; /* Match only IPv6 */ break; case NIX_FLOW_KEY_TYPE_TCP: @@ -3445,6 +3487,21 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) field->lid = NPC_LID_LH; field->bytesm1 = 3; /* Sport + Dport, 4 bytes */ + if (l3_l4_src_dst & NIX_FLOW_KEY_TYPE_L4_SRC_ONLY) + field->bytesm1 = 1; /* SRC, 2 bytes */ + + if (l3_l4_src_dst & NIX_FLOW_KEY_TYPE_L4_DST_ONLY) { + /* Both SRC + DST */ + if (field->bytesm1 == 1) { + /* SRC + DST, 4 bytes */ + field->bytesm1 = 3; + } else { + /* Only DIP */ + field->hdr_offset = 2; /* DST off */ + field->bytesm1 = 1; /* DST, 2 bytes */ + } + } + /* Enum values for NPC_LID_LD and NPC_LID_LG are same, * so no need to change the ltype_match, just change * the lid for inner protocols -- cgit v1.2.3 From bbba125eade7916277ef694d562cc95a39e86487 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Mon, 12 Jun 2023 11:34:21 +0530 Subject: octeontx2-af: cn10k: Set NIX DWRR MTU for CN10KB silicon The DWRR MTU config added for SDP and RPM/LBK links on CN10K silicon is further extended on CK10KB silicon variant and made it configurable. Now there are 4 DWRR MTU config to choose while setting transmit scheduler's RR_WEIGHT. Here we are reserving one config for each of RPM, SDP and LBK. NIXX_AF_DWRR_MTUX(0) ---> RPM NIXX_AF_DWRR_MTUX(1) ---> SDP NIXX_AF_DWRR_MTUX(2) ---> LBK PF/VF drivers can choose the DWRR_MTU to be used by setting SMQX_CFG[pkt_link_type] to one of above. TLx_SCHEDULE[RR_WEIGHT] is to be as configured 'quantum / 2^DWRR_MTUX[MTU]'. DWRR_MTU of each link is exposed to PF/VF drivers via mailbox for RR_WEIGHT calculation. Signed-off-by: Sunil Goutham Signed-off-by: Geetha sowjanya Signed-off-by: Naveen Mamindlapalli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/common.h | 7 ++++ drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 4 +- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 2 + .../ethernet/marvell/octeontx2/af/rvu_devlink.c | 6 ++- .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 44 ++++++++++++++++++---- .../net/ethernet/marvell/octeontx2/af/rvu_reg.h | 3 +- .../ethernet/marvell/octeontx2/nic/otx2_common.c | 18 ++++++++- .../ethernet/marvell/octeontx2/nic/otx2_common.h | 1 + 8 files changed, 73 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index f5bf719a6ccf..2436c1ff9ba4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -145,6 +145,13 @@ enum nix_scheduler { #define TXSCH_TL1_DFLT_RR_PRIO (0x7ull) #define CN10K_MAX_DWRR_WEIGHT 16384 /* Weight is 14bit on CN10K */ +/* Don't change the order as on CN10K (except CN10KB) + * SMQX_CFG[SDP] value should be 1 for SDP flows. + */ +#define SMQ_LINK_TYPE_RPM 0 +#define SMQ_LINK_TYPE_SDP 1 +#define SMQ_LINK_TYPE_LBK 2 + /* Min/Max packet sizes, excluding FCS */ #define NIC_HW_MIN_FRS 40 #define NIC_HW_MAX_FRS 9212 diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 671fcf86ed87..1794ef0f9ae0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1245,7 +1245,9 @@ struct nix_hw_info { u16 min_mtu; u32 rpm_dwrr_mtu; u32 sdp_dwrr_mtu; - u64 rsvd[16]; /* Add reserved fields for future expansion */ + u32 lbk_dwrr_mtu; + u32 rsvd32[1]; + u64 rsvd[15]; /* Add reserved fields for future expansion */ }; struct nix_bandprof_alloc_req { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index d655bf04a483..12e644bc239a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -346,6 +346,7 @@ struct hw_cap { bool per_pf_mbox_regs; /* PF mbox specified in per PF registers ? */ bool programmable_chans; /* Channels programmable ? */ bool ipolicer; + bool nix_multiple_dwrr_mtu; /* Multiple DWRR_MTU to choose from */ bool npc_hash_extract; /* Hash extract enabled ? */ bool npc_exact_match_enabled; /* Exact match supported ? */ }; @@ -802,6 +803,7 @@ int nix_aq_context_read(struct rvu *rvu, struct nix_hw *nix_hw, struct nix_cn10k_aq_enq_rsp *aq_rsp, u16 pcifunc, u8 ctype, u32 qidx); int rvu_get_nix_blkaddr(struct rvu *rvu, u16 pcifunc); +int nix_get_dwrr_mtu_reg(struct rvu_hwinfo *hw, int smq_link_type); u32 convert_dwrr_mtu_to_bytes(u8 dwrr_mtu); u32 convert_bytes_to_dwrr_mtu(u32 bytes); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c index 548549604c49..41df5ac23f92 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c @@ -1413,7 +1413,8 @@ static int rvu_af_dl_dwrr_mtu_set(struct devlink *devlink, u32 id, u64 dwrr_mtu; dwrr_mtu = convert_bytes_to_dwrr_mtu(ctx->val.vu32); - rvu_write64(rvu, BLKADDR_NIX0, NIX_AF_DWRR_RPM_MTU, dwrr_mtu); + rvu_write64(rvu, BLKADDR_NIX0, + nix_get_dwrr_mtu_reg(rvu->hw, SMQ_LINK_TYPE_RPM), dwrr_mtu); return 0; } @@ -1428,7 +1429,8 @@ static int rvu_af_dl_dwrr_mtu_get(struct devlink *devlink, u32 id, if (!rvu->hw->cap.nix_common_dwrr_mtu) return -EOPNOTSUPP; - dwrr_mtu = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_DWRR_RPM_MTU); + dwrr_mtu = rvu_read64(rvu, BLKADDR_NIX0, + nix_get_dwrr_mtu_reg(rvu->hw, SMQ_LINK_TYPE_RPM)); ctx->val.vu32 = convert_dwrr_mtu_to_bytes(dwrr_mtu); return 0; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index ee52b86c061f..f069d13dcb54 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -191,6 +191,18 @@ struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr) return NULL; } +int nix_get_dwrr_mtu_reg(struct rvu_hwinfo *hw, int smq_link_type) +{ + if (hw->cap.nix_multiple_dwrr_mtu) + return NIX_AF_DWRR_MTUX(smq_link_type); + + if (smq_link_type == SMQ_LINK_TYPE_SDP) + return NIX_AF_DWRR_SDP_MTU; + + /* Here it's same reg for RPM and LBK */ + return NIX_AF_DWRR_RPM_MTU; +} + u32 convert_dwrr_mtu_to_bytes(u8 dwrr_mtu) { dwrr_mtu &= 0x1FULL; @@ -3191,10 +3203,16 @@ static int nix_setup_txschq(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) } /* Setup a default value of 8192 as DWRR MTU */ - if (rvu->hw->cap.nix_common_dwrr_mtu) { - rvu_write64(rvu, blkaddr, NIX_AF_DWRR_RPM_MTU, + if (rvu->hw->cap.nix_common_dwrr_mtu || + rvu->hw->cap.nix_multiple_dwrr_mtu) { + rvu_write64(rvu, blkaddr, + nix_get_dwrr_mtu_reg(rvu->hw, SMQ_LINK_TYPE_RPM), convert_bytes_to_dwrr_mtu(8192)); - rvu_write64(rvu, blkaddr, NIX_AF_DWRR_SDP_MTU, + rvu_write64(rvu, blkaddr, + nix_get_dwrr_mtu_reg(rvu->hw, SMQ_LINK_TYPE_LBK), + convert_bytes_to_dwrr_mtu(8192)); + rvu_write64(rvu, blkaddr, + nix_get_dwrr_mtu_reg(rvu->hw, SMQ_LINK_TYPE_SDP), convert_bytes_to_dwrr_mtu(8192)); } @@ -3292,19 +3310,28 @@ int rvu_mbox_handler_nix_get_hw_info(struct rvu *rvu, struct msg_req *req, rsp->min_mtu = NIC_HW_MIN_FRS; - if (!rvu->hw->cap.nix_common_dwrr_mtu) { + if (!rvu->hw->cap.nix_common_dwrr_mtu && + !rvu->hw->cap.nix_multiple_dwrr_mtu) { /* Return '1' on OTx2 */ rsp->rpm_dwrr_mtu = 1; rsp->sdp_dwrr_mtu = 1; + rsp->lbk_dwrr_mtu = 1; return 0; } - dwrr_mtu = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_DWRR_RPM_MTU); + /* Return DWRR_MTU for TLx_SCHEDULE[RR_WEIGHT] config */ + dwrr_mtu = rvu_read64(rvu, blkaddr, + nix_get_dwrr_mtu_reg(rvu->hw, SMQ_LINK_TYPE_RPM)); rsp->rpm_dwrr_mtu = convert_dwrr_mtu_to_bytes(dwrr_mtu); - dwrr_mtu = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_DWRR_SDP_MTU); + dwrr_mtu = rvu_read64(rvu, blkaddr, + nix_get_dwrr_mtu_reg(rvu->hw, SMQ_LINK_TYPE_SDP)); rsp->sdp_dwrr_mtu = convert_dwrr_mtu_to_bytes(dwrr_mtu); + dwrr_mtu = rvu_read64(rvu, blkaddr, + nix_get_dwrr_mtu_reg(rvu->hw, SMQ_LINK_TYPE_LBK)); + rsp->lbk_dwrr_mtu = convert_dwrr_mtu_to_bytes(dwrr_mtu); + return 0; } @@ -4371,8 +4398,11 @@ static void rvu_nix_setup_capabilities(struct rvu *rvu, int blkaddr) * Check if HW uses a common MTU for all DWRR quantum configs. * On OcteonTx2 this register field is '0'. */ - if (((hw_const >> 56) & 0x10) == 0x10) + if ((((hw_const >> 56) & 0x10) == 0x10) && !(hw_const & BIT_ULL(61))) hw->cap.nix_common_dwrr_mtu = true; + + if (hw_const & BIT_ULL(61)) + hw->cap.nix_multiple_dwrr_mtu = true; } static int rvu_nix_block_init(struct rvu *rvu, struct nix_hw *nix_hw) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index 7007f0b8e659..b42e631e52d0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -272,7 +272,8 @@ #define NIX_AF_DEBUG_NPC_RESP_DATAX(a) (0x680 | (a) << 3) #define NIX_AF_SMQX_CFG(a) (0x700 | (a) << 16) #define NIX_AF_SQM_DBG_CTL_STATUS (0x750) -#define NIX_AF_DWRR_SDP_MTU (0x790) +#define NIX_AF_DWRR_SDP_MTU (0x790) /* All CN10K except CN10KB */ +#define NIX_AF_DWRR_MTUX(a) (0x790 | (a) << 16) /* Only for CN10KB */ #define NIX_AF_DWRR_RPM_MTU (0x7A0) #define NIX_AF_PSE_CHANNEL_LEVEL (0x800) #define NIX_AF_PSE_SHAPER_CFG (0x810) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index a79cb680bb23..77c8f650f7ac 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "otx2_reg.h" #include "otx2_common.h" @@ -642,6 +643,10 @@ int otx2_txschq_config(struct otx2_nic *pfvf, int lvl, int prio, bool txschq_for req->regval[0] = ((u64)pfvf->tx_max_pktlen << 8) | OTX2_MIN_MTU; req->regval[0] |= (0x20ULL << 51) | (0x80ULL << 39) | (0x2ULL << 36); + /* Set link type for DWRR MTU selection on CN10K silicons */ + if (!is_dev_otx2(pfvf->pdev)) + req->regval[0] |= FIELD_PREP(GENMASK_ULL(58, 57), + (u64)hw->smq_link_type); req->num_regs++; /* MDQ config */ parent = schq_list[NIX_TXSCH_LVL_TL4][prio]; @@ -1824,6 +1829,17 @@ void otx2_set_cints_affinity(struct otx2_nic *pfvf) } } +static u32 get_dwrr_mtu(struct otx2_nic *pfvf, struct nix_hw_info *hw) +{ + if (is_otx2_lbkvf(pfvf->pdev)) { + pfvf->hw.smq_link_type = SMQ_LINK_TYPE_LBK; + return hw->lbk_dwrr_mtu; + } + + pfvf->hw.smq_link_type = SMQ_LINK_TYPE_RPM; + return hw->rpm_dwrr_mtu; +} + u16 otx2_get_max_mtu(struct otx2_nic *pfvf) { struct nix_hw_info *rsp; @@ -1853,7 +1869,7 @@ u16 otx2_get_max_mtu(struct otx2_nic *pfvf) max_mtu = rsp->max_mtu - 8 - OTX2_ETH_HLEN; /* Also save DWRR MTU, needed for DWRR weight calculation */ - pfvf->hw.dwrr_mtu = rsp->rpm_dwrr_mtu; + pfvf->hw.dwrr_mtu = get_dwrr_mtu(pfvf, rsp); if (!pfvf->hw.dwrr_mtu) pfvf->hw.dwrr_mtu = 1; } diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index a9ed15d1793a..ba8091131ec0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -227,6 +227,7 @@ struct otx2_hw { u16 txschq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC]; u16 matchall_ipolicer; u32 dwrr_mtu; + u8 smq_link_type; /* HW settings, coalescing etc */ u16 rx_chan_base; -- cgit v1.2.3 From b6a072a153277dc590703ada2fd1f53ecb7f8cb9 Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Mon, 12 Jun 2023 11:34:22 +0530 Subject: octeontx2-af: Enable LBK links only when switch mode is on. Currently, all the TL3_TL2 nodes are being configured to enable switch LBK channel 63 in them. Instead enable them only when switch mode is enabled. Signed-off-by: Subbaraya Sundeep Signed-off-by: Naveen Mamindlapalli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 2 ++ drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c | 11 +++++------ drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 12e644bc239a..c07d826e36d1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -806,6 +806,8 @@ int rvu_get_nix_blkaddr(struct rvu *rvu, u16 pcifunc); int nix_get_dwrr_mtu_reg(struct rvu_hwinfo *hw, int smq_link_type); u32 convert_dwrr_mtu_to_bytes(u8 dwrr_mtu); u32 convert_bytes_to_dwrr_mtu(u32 bytes); +void rvu_nix_tx_tl2_cfg(struct rvu *rvu, int blkaddr, u16 pcifunc, + struct nix_txsch *txsch, bool enable); /* NPC APIs */ void rvu_npc_freemem(struct rvu *rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index f069d13dcb54..8a89cc5e5e40 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -2460,17 +2460,19 @@ static int nix_txschq_cfg_read(struct rvu *rvu, struct nix_hw *nix_hw, return 0; } -static void rvu_nix_tx_tl2_cfg(struct rvu *rvu, int blkaddr, - u16 pcifunc, struct nix_txsch *txsch) +void rvu_nix_tx_tl2_cfg(struct rvu *rvu, int blkaddr, u16 pcifunc, + struct nix_txsch *txsch, bool enable) { struct rvu_hwinfo *hw = rvu->hw; int lbk_link_start, lbk_links; u8 pf = rvu_get_pf(pcifunc); int schq; + u64 cfg; if (!is_pf_cgxmapped(rvu, pf)) return; + cfg = enable ? (BIT_ULL(12) | RVU_SWITCH_LBK_CHAN) : 0; lbk_link_start = hw->cgx_links; for (schq = 0; schq < txsch->schq.max; schq++) { @@ -2484,8 +2486,7 @@ static void rvu_nix_tx_tl2_cfg(struct rvu *rvu, int blkaddr, rvu_write64(rvu, blkaddr, NIX_AF_TL3_TL2X_LINKX_CFG(schq, lbk_link_start + - lbk_links), - BIT_ULL(12) | RVU_SWITCH_LBK_CHAN); + lbk_links), cfg); } } @@ -2591,8 +2592,6 @@ int rvu_mbox_handler_nix_txschq_cfg(struct rvu *rvu, rvu_write64(rvu, blkaddr, reg, regval); } - rvu_nix_tx_tl2_cfg(rvu, blkaddr, pcifunc, - &nix_hw->txsch[NIX_TXSCH_LVL_TL2]); return 0; } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c index 3392487f6b47..592b317f4637 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_switch.c @@ -8,6 +8,17 @@ #include #include "rvu.h" +static void rvu_switch_enable_lbk_link(struct rvu *rvu, u16 pcifunc, bool enable) +{ + struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); + struct nix_hw *nix_hw; + + nix_hw = get_nix_hw(rvu->hw, pfvf->nix_blkaddr); + /* Enable LBK links with channel 63 for TX MCAM rule */ + rvu_nix_tx_tl2_cfg(rvu, pfvf->nix_blkaddr, pcifunc, + &nix_hw->txsch[NIX_TXSCH_LVL_TL2], enable); +} + static int rvu_switch_install_rx_rule(struct rvu *rvu, u16 pcifunc, u16 chan_mask) { @@ -52,6 +63,8 @@ static int rvu_switch_install_tx_rule(struct rvu *rvu, u16 pcifunc, u16 entry) if (!test_bit(NIXLF_INITIALIZED, &pfvf->flags)) return 0; + rvu_switch_enable_lbk_link(rvu, pcifunc, true); + lbkid = pfvf->nix_blkaddr == BLKADDR_NIX0 ? 0 : 1; ether_addr_copy(req.packet.dmac, pfvf->mac_addr); eth_broadcast_addr((u8 *)&req.mask.dmac); @@ -218,6 +231,9 @@ void rvu_switch_disable(struct rvu *rvu) "Reverting RX rule for PF%d failed(%d)\n", pf, err); + /* Disable LBK link */ + rvu_switch_enable_lbk_link(rvu, pcifunc, false); + rvu_get_pf_numvfs(rvu, pf, &numvfs, NULL); for (vf = 0; vf < numvfs; vf++) { pcifunc = pf << 10 | ((vf + 1) & 0x3FF); @@ -226,6 +242,8 @@ void rvu_switch_disable(struct rvu *rvu) dev_err(rvu->dev, "Reverting RX rule for PF%dVF%d failed(%d)\n", pf, vf, err); + + rvu_switch_enable_lbk_link(rvu, pcifunc, false); } } -- cgit v1.2.3 From 4ed6387a61fcc96f46859349b7e7696db9988ed6 Mon Sep 17 00:00:00 2001 From: Nithin Dabilpuram Date: Mon, 12 Jun 2023 11:34:23 +0530 Subject: octeontx2-af: add option to toggle DROP_RE enable in rx cfg Add option to toggle DROP_RE bit in rx cfg mbox. This helps in modifying the config runtime as opposed to setting available via nix_lf_alloc() mbox at NIX LF init time. Signed-off-by: Nithin Dabilpuram Signed-off-by: Jerin Jacob Kollanukkaran Signed-off-by: Sunil Kovvuri Goutham Signed-off-by: Naveen Mamindlapalli Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 1 + drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 1794ef0f9ae0..eba307eee2b2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1157,6 +1157,7 @@ struct nix_rx_cfg { struct mbox_msghdr hdr; #define NIX_RX_OL3_VERIFY BIT(0) #define NIX_RX_OL4_VERIFY BIT(1) +#define NIX_RX_DROP_RE BIT(2) u8 len_verify; /* Outer L3/L4 len check */ #define NIX_RX_CSUM_OL4_VERIFY BIT(0) u8 csum_verify; /* Outer L4 checksum verification */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 8a89cc5e5e40..23149036be77 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -4196,6 +4196,11 @@ int rvu_mbox_handler_nix_set_rx_cfg(struct rvu *rvu, struct nix_rx_cfg *req, else cfg &= ~BIT_ULL(40); + if (req->len_verify & NIX_RX_DROP_RE) + cfg |= BIT_ULL(32); + else + cfg &= ~BIT_ULL(32); + if (req->csum_verify & BIT(0)) cfg |= BIT_ULL(37); else -- cgit v1.2.3 From e18aab0470d8f6259be82282ffb3fdcfeaeff6c3 Mon Sep 17 00:00:00 2001 From: Naveen Mamindlapalli Date: Mon, 12 Jun 2023 11:34:24 +0530 Subject: octeontx2-af: Set XOFF on other child transmit schedulers during SMQ flush When multiple transmit scheduler queues feed a TL1 transmit link, the SMQ flush initiated on a low priority queue might get stuck when a high priority queue fully subscribes the transmit link. This inturn effects interface teardown. To avoid this, temporarily XOFF all TL1's other immediate child transmit scheduler queues and also clear any rate limit configuration on all the scheduler queues in SMQ(flush) hierarchy. Signed-off-by: Naveen Mamindlapalli Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 16 +++ .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 130 ++++++++++++++++++++- 2 files changed, 144 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index c07d826e36d1..b5a7ee63508c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -285,6 +285,22 @@ struct nix_mark_format { u32 *cfg; }; +/* smq(flush) to tl1 cir/pir info */ +struct nix_smq_tree_ctx { + u64 cir_off; + u64 cir_val; + u64 pir_off; + u64 pir_val; +}; + +/* smq flush context */ +struct nix_smq_flush_ctx { + int smq; + u16 tl1_schq; + u16 tl2_schq; + struct nix_smq_tree_ctx smq_tree_ctx[NIX_TXSCH_LVL_CNT]; +}; + struct npc_pkind { struct rsrc_bmap rsrc; u32 *pfchan_map; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 23149036be77..601ef269aa29 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -2114,9 +2114,121 @@ exit: return rc; } +static void nix_smq_flush_fill_ctx(struct rvu *rvu, int blkaddr, int smq, + struct nix_smq_flush_ctx *smq_flush_ctx) +{ + struct nix_smq_tree_ctx *smq_tree_ctx; + u64 parent_off, regval; + u16 schq; + int lvl; + + smq_flush_ctx->smq = smq; + + schq = smq; + for (lvl = NIX_TXSCH_LVL_SMQ; lvl <= NIX_TXSCH_LVL_TL1; lvl++) { + smq_tree_ctx = &smq_flush_ctx->smq_tree_ctx[lvl]; + if (lvl == NIX_TXSCH_LVL_TL1) { + smq_flush_ctx->tl1_schq = schq; + smq_tree_ctx->cir_off = NIX_AF_TL1X_CIR(schq); + smq_tree_ctx->pir_off = 0; + smq_tree_ctx->pir_val = 0; + parent_off = 0; + } else if (lvl == NIX_TXSCH_LVL_TL2) { + smq_flush_ctx->tl2_schq = schq; + smq_tree_ctx->cir_off = NIX_AF_TL2X_CIR(schq); + smq_tree_ctx->pir_off = NIX_AF_TL2X_PIR(schq); + parent_off = NIX_AF_TL2X_PARENT(schq); + } else if (lvl == NIX_TXSCH_LVL_TL3) { + smq_tree_ctx->cir_off = NIX_AF_TL3X_CIR(schq); + smq_tree_ctx->pir_off = NIX_AF_TL3X_PIR(schq); + parent_off = NIX_AF_TL3X_PARENT(schq); + } else if (lvl == NIX_TXSCH_LVL_TL4) { + smq_tree_ctx->cir_off = NIX_AF_TL4X_CIR(schq); + smq_tree_ctx->pir_off = NIX_AF_TL4X_PIR(schq); + parent_off = NIX_AF_TL4X_PARENT(schq); + } else if (lvl == NIX_TXSCH_LVL_MDQ) { + smq_tree_ctx->cir_off = NIX_AF_MDQX_CIR(schq); + smq_tree_ctx->pir_off = NIX_AF_MDQX_PIR(schq); + parent_off = NIX_AF_MDQX_PARENT(schq); + } + /* save cir/pir register values */ + smq_tree_ctx->cir_val = rvu_read64(rvu, blkaddr, smq_tree_ctx->cir_off); + if (smq_tree_ctx->pir_off) + smq_tree_ctx->pir_val = rvu_read64(rvu, blkaddr, smq_tree_ctx->pir_off); + + /* get parent txsch node */ + if (parent_off) { + regval = rvu_read64(rvu, blkaddr, parent_off); + schq = (regval >> 16) & 0x1FF; + } + } +} + +static void nix_smq_flush_enadis_xoff(struct rvu *rvu, int blkaddr, + struct nix_smq_flush_ctx *smq_flush_ctx, bool enable) +{ + struct nix_txsch *txsch; + struct nix_hw *nix_hw; + u64 regoff; + int tl2; + + nix_hw = get_nix_hw(rvu->hw, blkaddr); + if (!nix_hw) + return; + + /* loop through all TL2s with matching PF_FUNC */ + txsch = &nix_hw->txsch[NIX_TXSCH_LVL_TL2]; + for (tl2 = 0; tl2 < txsch->schq.max; tl2++) { + /* skip the smq(flush) TL2 */ + if (tl2 == smq_flush_ctx->tl2_schq) + continue; + /* skip unused TL2s */ + if (TXSCH_MAP_FLAGS(txsch->pfvf_map[tl2]) & NIX_TXSCHQ_FREE) + continue; + /* skip if PF_FUNC doesn't match */ + if ((TXSCH_MAP_FUNC(txsch->pfvf_map[tl2]) & ~RVU_PFVF_FUNC_MASK) != + (TXSCH_MAP_FUNC(txsch->pfvf_map[smq_flush_ctx->tl2_schq] & + ~RVU_PFVF_FUNC_MASK))) + continue; + /* enable/disable XOFF */ + regoff = NIX_AF_TL2X_SW_XOFF(tl2); + if (enable) + rvu_write64(rvu, blkaddr, regoff, 0x1); + else + rvu_write64(rvu, blkaddr, regoff, 0x0); + } +} + +static void nix_smq_flush_enadis_rate(struct rvu *rvu, int blkaddr, + struct nix_smq_flush_ctx *smq_flush_ctx, bool enable) +{ + u64 cir_off, pir_off, cir_val, pir_val; + struct nix_smq_tree_ctx *smq_tree_ctx; + int lvl; + + for (lvl = NIX_TXSCH_LVL_SMQ; lvl <= NIX_TXSCH_LVL_TL1; lvl++) { + smq_tree_ctx = &smq_flush_ctx->smq_tree_ctx[lvl]; + cir_off = smq_tree_ctx->cir_off; + cir_val = smq_tree_ctx->cir_val; + pir_off = smq_tree_ctx->pir_off; + pir_val = smq_tree_ctx->pir_val; + + if (enable) { + rvu_write64(rvu, blkaddr, cir_off, cir_val); + if (lvl != NIX_TXSCH_LVL_TL1) + rvu_write64(rvu, blkaddr, pir_off, pir_val); + } else { + rvu_write64(rvu, blkaddr, cir_off, 0x0); + if (lvl != NIX_TXSCH_LVL_TL1) + rvu_write64(rvu, blkaddr, pir_off, 0x0); + } + } +} + static int nix_smq_flush(struct rvu *rvu, int blkaddr, int smq, u16 pcifunc, int nixlf) { + struct nix_smq_flush_ctx *smq_flush_ctx; int pf = rvu_get_pf(pcifunc); u8 cgx_id = 0, lmac_id = 0; int err, restore_tx_en = 0; @@ -2136,6 +2248,14 @@ static int nix_smq_flush(struct rvu *rvu, int blkaddr, lmac_id, true); } + /* XOFF all TL2s whose parent TL1 matches SMQ tree TL1 */ + smq_flush_ctx = kzalloc(sizeof(*smq_flush_ctx), GFP_KERNEL); + if (!smq_flush_ctx) + return -ENOMEM; + nix_smq_flush_fill_ctx(rvu, blkaddr, smq, smq_flush_ctx); + nix_smq_flush_enadis_xoff(rvu, blkaddr, smq_flush_ctx, true); + nix_smq_flush_enadis_rate(rvu, blkaddr, smq_flush_ctx, false); + cfg = rvu_read64(rvu, blkaddr, NIX_AF_SMQX_CFG(smq)); /* Do SMQ flush and set enqueue xoff */ cfg |= BIT_ULL(50) | BIT_ULL(49); @@ -2150,8 +2270,14 @@ static int nix_smq_flush(struct rvu *rvu, int blkaddr, err = rvu_poll_reg(rvu, blkaddr, NIX_AF_SMQX_CFG(smq), BIT_ULL(49), true); if (err) - dev_err(rvu->dev, - "NIXLF%d: SMQ%d flush failed\n", nixlf, smq); + dev_info(rvu->dev, + "NIXLF%d: SMQ%d flush failed, txlink might be busy\n", + nixlf, smq); + + /* clear XOFF on TL2s */ + nix_smq_flush_enadis_rate(rvu, blkaddr, smq_flush_ctx, true); + nix_smq_flush_enadis_xoff(rvu, blkaddr, smq_flush_ctx, false); + kfree(smq_flush_ctx); rvu_cgx_enadis_rx_bp(rvu, pf, true); /* restore cgx tx state */ -- cgit v1.2.3 From 75086cc6dee046e3fbb3dba148b376d8802f83bc Mon Sep 17 00:00:00 2001 From: Remi Pommarel Date: Fri, 9 Jun 2023 11:37:44 +0200 Subject: wifi: ath9k: Fix possible stall on ath9k_txq_list_has_key() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On EDMA capable hardware, ath9k_txq_list_has_key() can enter infinite loop if it is called while all txq_fifos have packets that use different key that the one we are looking for. Fix it by exiting the loop if all txq_fifos have been checked already. Because this loop is called under spin_lock_bh() (see ath_txq_lock) it causes the following rcu stall: rcu: INFO: rcu_sched self-detected stall on CPU ath10k_pci 0000:01:00.0: failed to read temperature -11 rcu: 1-....: (5254 ticks this GP) idle=189/1/0x4000000000000002 softirq=8442983/8442984 fqs=2579 (t=5257 jiffies g=17983297 q=334) Task dump for CPU 1: task:hostapd state:R running task stack: 0 pid: 297 ppid: 289 flags:0x0000000a Call trace: dump_backtrace+0x0/0x170 show_stack+0x1c/0x24 sched_show_task+0x140/0x170 dump_cpu_task+0x48/0x54 rcu_dump_cpu_stacks+0xf0/0x134 rcu_sched_clock_irq+0x8d8/0x9fc update_process_times+0xa0/0xec tick_sched_timer+0x5c/0xd0 __hrtimer_run_queues+0x154/0x320 hrtimer_interrupt+0x120/0x2f0 arch_timer_handler_virt+0x38/0x44 handle_percpu_devid_irq+0x9c/0x1e0 handle_domain_irq+0x64/0x90 gic_handle_irq+0x78/0xb0 call_on_irq_stack+0x28/0x38 do_interrupt_handler+0x54/0x5c el1_interrupt+0x2c/0x4c el1h_64_irq_handler+0x14/0x1c el1h_64_irq+0x74/0x78 ath9k_txq_has_key+0x1bc/0x250 [ath9k] ath9k_set_key+0x1cc/0x3dc [ath9k] drv_set_key+0x78/0x170 ieee80211_key_replace+0x564/0x6cc ieee80211_key_link+0x174/0x220 ieee80211_add_key+0x11c/0x300 nl80211_new_key+0x12c/0x330 genl_family_rcv_msg_doit+0xbc/0x11c genl_rcv_msg+0xd8/0x1c4 netlink_rcv_skb+0x40/0x100 genl_rcv+0x3c/0x50 netlink_unicast+0x1ec/0x2c0 netlink_sendmsg+0x198/0x3c0 ____sys_sendmsg+0x210/0x250 ___sys_sendmsg+0x78/0xc4 __sys_sendmsg+0x4c/0x90 __arm64_sys_sendmsg+0x28/0x30 invoke_syscall.constprop.0+0x60/0x100 do_el0_svc+0x48/0xd0 el0_svc+0x14/0x50 el0t_64_sync_handler+0xa8/0xb0 el0t_64_sync+0x158/0x15c This rcu stall is hard to reproduce as is, but changing ATH_TXFIFO_DEPTH from 8 to 2 makes it reasonably easy to reproduce. Fixes: ca2848022c12 ("ath9k: Postpone key cache entry deletion for TXQ frames reference it") Signed-off-by: Remi Pommarel Tested-by: Nicolas Escande Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609093744.1985-1-repk@triplefau.lt --- drivers/net/wireless/ath/ath9k/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a4197c14f0a9..7f9f06ea8a05 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -850,7 +850,7 @@ static bool ath9k_txq_list_has_key(struct list_head *txq_list, u32 keyix) static bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix) { struct ath_hw *ah = sc->sc_ah; - int i; + int i, j; struct ath_txq *txq; bool key_in_use = false; @@ -868,8 +868,9 @@ static bool ath9k_txq_has_key(struct ath_softc *sc, u32 keyix) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { int idx = txq->txq_tailidx; - while (!key_in_use && - !list_empty(&txq->txq_fifo[idx])) { + for (j = 0; !key_in_use && + !list_empty(&txq->txq_fifo[idx]) && + j < ATH_TXFIFO_DEPTH; j++) { key_in_use = ath9k_txq_list_has_key( &txq->txq_fifo[idx], keyix); INCR(idx, ATH_TXFIFO_DEPTH); -- cgit v1.2.3 From d13936d57927574815db968f1e5f9026dade3370 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:26 +0300 Subject: wifi: ath11k: debug: remove unused ATH11K_DBG_ANY It's not used anywhere so can be easily removed. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-2-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/debug.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index 621d85f3118c..0a9418c36bf4 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -26,7 +26,6 @@ enum ath11k_debug_mask { ATH11K_DBG_PCI = 0x00001000, ATH11K_DBG_DP_TX = 0x00002000, ATH11K_DBG_DP_RX = 0x00004000, - ATH11K_DBG_ANY = 0xffffffff, }; __printf(2, 3) void ath11k_info(struct ath11k_base *ab, const char *fmt, ...); -- cgit v1.2.3 From 9a599e968f022e77519e5f13f421369699f95269 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:27 +0300 Subject: wifi: ath11k: print debug level in debug messages To make it easier understand the context of a debug message print the debug level before the actual message. An example: [21867.231900] ath11k_pci 0000:06:00.0: wmi processed regulatory ext channel list The tracepoint call is not modified, it's better to userspace print the debug level if needed. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-3-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/debug.c | 2 +- drivers/net/wireless/ath/ath11k/debug.h | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index 958d87429062..f5c8a34c8802 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -66,7 +66,7 @@ void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask, vaf.va = &args; if (ath11k_debug_mask & mask) - dev_printk(KERN_DEBUG, ab->dev, "%pV", &vaf); + dev_printk(KERN_DEBUG, ab->dev, "%s %pV", ath11k_dbg_str(mask), &vaf); trace_ath11k_log_dbg(ab, mask, &vaf); diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index 0a9418c36bf4..2dd84d8ed5a5 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -28,6 +28,48 @@ enum ath11k_debug_mask { ATH11K_DBG_DP_RX = 0x00004000, }; +static inline const char *ath11k_dbg_str(enum ath11k_debug_mask mask) +{ + switch (mask) { + case ATH11K_DBG_AHB: + return "ahb"; + case ATH11K_DBG_WMI: + return "wmi"; + case ATH11K_DBG_HTC: + return "htc"; + case ATH11K_DBG_DP_HTT: + return "dp_htt"; + case ATH11K_DBG_MAC: + return "mac"; + case ATH11K_DBG_BOOT: + return "boot"; + case ATH11K_DBG_QMI: + return "qmi"; + case ATH11K_DBG_DATA: + return "data"; + case ATH11K_DBG_MGMT: + return "mgmt"; + case ATH11K_DBG_REG: + return "reg"; + case ATH11K_DBG_TESTMODE: + return "testmode"; + case ATH11k_DBG_HAL: + return "hal"; + case ATH11K_DBG_PCI: + return "pci"; + case ATH11K_DBG_DP_TX: + return "dp_tx"; + case ATH11K_DBG_DP_RX: + return "dp_rx"; + + /* no default handler to allow compiler to check that the + * enum is fully handled + */ + } + + return ""; +} + __printf(2, 3) void ath11k_info(struct ath11k_base *ab, const char *fmt, ...); __printf(2, 3) void ath11k_err(struct ath11k_base *ab, const char *fmt, ...); __printf(2, 3) void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...); -- cgit v1.2.3 From fc3b984a7d99bcac74d10fae40fcbffce5495024 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:28 +0300 Subject: wifi: ath11k: remove manual mask names from debug messages Now that the previous patch changed ath11k_dbg() to print the debug level there's no need to have the level in the actual message anymore. So remove those. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-4-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/ahb.c | 4 +- drivers/net/wireless/ath/ath11k/core.c | 14 ++-- drivers/net/wireless/ath/ath11k/dp_rx.c | 2 +- drivers/net/wireless/ath/ath11k/hal.c | 2 +- drivers/net/wireless/ath/ath11k/htc.c | 20 ++--- drivers/net/wireless/ath/ath11k/mac.c | 110 +++++++++++++------------- drivers/net/wireless/ath/ath11k/mhi.c | 2 +- drivers/net/wireless/ath/ath11k/pci.c | 12 +-- drivers/net/wireless/ath/ath11k/peer.c | 4 +- drivers/net/wireless/ath/ath11k/qmi.c | 58 +++++++------- drivers/net/wireless/ath/ath11k/reg.c | 4 +- drivers/net/wireless/ath/ath11k/wmi.c | 136 ++++++++++++++++---------------- 12 files changed, 184 insertions(+), 184 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 32911fa6e505..ddd27e05ede4 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -734,7 +734,7 @@ static int ath11k_ahb_hif_suspend(struct ath11k_base *ab) return ret; } - ath11k_dbg(ab, ATH11K_DBG_AHB, "ahb device suspended\n"); + ath11k_dbg(ab, ATH11K_DBG_AHB, "device suspended\n"); return ret; } @@ -777,7 +777,7 @@ static int ath11k_ahb_hif_resume(struct ath11k_base *ab) return -ETIMEDOUT; } - ath11k_dbg(ab, ATH11K_DBG_AHB, "ahb device resumed\n"); + ath11k_dbg(ab, ATH11K_DBG_AHB, "device resumed\n"); return 0; } diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 8a82a4ed0af5..147395e622b9 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -878,16 +878,16 @@ static void ath11k_core_check_cc_code_bdfext(const struct dmi_header *hdr, void case ATH11K_SMBIOS_CC_ISO: ab->new_alpha2[0] = (smbios->cc_code >> 8) & 0xff; ab->new_alpha2[1] = smbios->cc_code & 0xff; - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot smbios cc_code %c%c\n", + ath11k_dbg(ab, ATH11K_DBG_BOOT, "smbios cc_code %c%c\n", ab->new_alpha2[0], ab->new_alpha2[1]); break; case ATH11K_SMBIOS_CC_WW: ab->new_alpha2[0] = '0'; ab->new_alpha2[1] = '0'; - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot smbios worldwide regdomain\n"); + ath11k_dbg(ab, ATH11K_DBG_BOOT, "smbios worldwide regdomain\n"); break; default: - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot ignore smbios country code setting %d\n", + ath11k_dbg(ab, ATH11K_DBG_BOOT, "ignore smbios country code setting %d\n", smbios->country_code_flag); break; } @@ -1001,7 +1001,7 @@ static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name, break; } - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot using board name '%s'\n", name); + ath11k_dbg(ab, ATH11K_DBG_BOOT, "using board name '%s'\n", name); return 0; } @@ -1040,7 +1040,7 @@ const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, if (ret) return ERR_PTR(ret); - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot firmware request %s size %zu\n", + ath11k_dbg(ab, ATH11K_DBG_BOOT, "firmware request %s size %zu\n", path, fw->size); return fw; @@ -1101,7 +1101,7 @@ static int ath11k_core_parse_bd_ie_board(struct ath11k_base *ab, name_match_found = true; ath11k_dbg(ab, ATH11K_DBG_BOOT, - "boot found match %s for name '%s'", + "found match %s for name '%s'", ath11k_bd_ie_type_str(ie_id), boardname); } else if (board_ie_id == data_id) { @@ -1110,7 +1110,7 @@ static int ath11k_core_parse_bd_ie_board(struct ath11k_base *ab, goto next; ath11k_dbg(ab, ATH11K_DBG_BOOT, - "boot found %s for '%s'", + "found %s for '%s'", ath11k_bd_ie_type_str(ie_id), boardname); diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index f67ce62b2b48..0ed3d2580e91 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1651,7 +1651,7 @@ static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab, backpressure_time = *data; - ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt backpressure event, pdev %d, ring type %d,ring id %d, hp %d tp %d, backpressure time %d\n", + ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "backpressure event, pdev %d, ring type %d,ring id %d, hp %d tp %d, backpressure time %d\n", pdev_id, ring_type, ring_id, hp, tp, backpressure_time); if (ring_type == HTT_BACKPRESSURE_UMAC_RING_TYPE) { diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 22422237500c..2cdc8478d253 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1010,7 +1010,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, (u32 *)((unsigned long)ab->mem + reg_base); else ath11k_dbg(ab, ATH11k_DBG_HAL, - "hal type %d ring_num %d reg_base 0x%x shadow 0x%lx\n", + "type %d ring_num %d reg_base 0x%x shadow 0x%lx\n", type, ring_num, reg_base, (unsigned long)srng->u.src_ring.hp_addr - diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index ca3aedc0252d..7d277cd60b07 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -96,7 +96,7 @@ int ath11k_htc_send(struct ath11k_htc *htc, spin_lock_bh(&htc->tx_lock); if (ep->tx_credits < credits) { ath11k_dbg(ab, ATH11K_DBG_HTC, - "htc insufficient credits ep %d required %d available %d\n", + "insufficient credits ep %d required %d available %d\n", eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); ret = -EAGAIN; @@ -104,7 +104,7 @@ int ath11k_htc_send(struct ath11k_htc *htc, } ep->tx_credits -= credits; ath11k_dbg(ab, ATH11K_DBG_HTC, - "htc ep %d consumed %d credits (total %d)\n", + "ep %d consumed %d credits (total %d)\n", eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); } @@ -132,7 +132,7 @@ err_credits: spin_lock_bh(&htc->tx_lock); ep->tx_credits += credits; ath11k_dbg(ab, ATH11K_DBG_HTC, - "htc ep %d reverted %d credits back (total %d)\n", + "ep %d reverted %d credits back (total %d)\n", eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); @@ -167,7 +167,7 @@ ath11k_htc_process_credit_report(struct ath11k_htc *htc, ep = &htc->endpoint[report->eid]; ep->tx_credits += report->credits; - ath11k_dbg(ab, ATH11K_DBG_HTC, "htc ep %d got %d credits (total %d)\n", + ath11k_dbg(ab, ATH11K_DBG_HTC, "ep %d got %d credits (total %d)\n", report->eid, report->credits, ep->tx_credits); if (ep->ep_ops.ep_tx_credits) { @@ -239,7 +239,7 @@ static int ath11k_htc_process_trailer(struct ath11k_htc *htc, static void ath11k_htc_suspend_complete(struct ath11k_base *ab, bool ack) { - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot suspend complete %d\n", ack); + ath11k_dbg(ab, ATH11K_DBG_BOOT, "suspend complete %d\n", ack); if (ack) set_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); @@ -276,7 +276,7 @@ void ath11k_htc_tx_completion_handler(struct ath11k_base *ab, static void ath11k_htc_wakeup_from_suspend(struct ath11k_base *ab) { - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot wakeup from suspend is received\n"); + ath11k_dbg(ab, ATH11K_DBG_BOOT, "wakeup from suspend is received\n"); } void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, @@ -393,7 +393,7 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, goto out; } - ath11k_dbg(ab, ATH11K_DBG_HTC, "htc rx completion ep %d skb %pK\n", + ath11k_dbg(ab, ATH11K_DBG_HTC, "rx completion ep %d skb %pK\n", eid, skb); ep->ep_ops.ep_rx_complete(ab, skb); @@ -615,7 +615,7 @@ int ath11k_htc_connect_service(struct ath11k_htc *htc, conn_req->service_id); if (!tx_alloc) ath11k_dbg(ab, ATH11K_DBG_BOOT, - "boot htc service %s does not allocate target credits\n", + "htc service %s does not allocate target credits\n", htc_service_name(conn_req->service_id)); skb = ath11k_htc_build_tx_ctrl_skb(htc->ab); @@ -740,14 +740,14 @@ setup: return status; ath11k_dbg(ab, ATH11K_DBG_BOOT, - "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n", + "htc service '%s' ul pipe %d dl pipe %d eid %d ready\n", htc_service_name(ep->service_id), ep->ul_pipe_id, ep->dl_pipe_id, ep->eid); if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { ep->tx_credit_flow_enabled = false; ath11k_dbg(ab, ATH11K_DBG_BOOT, - "boot htc service '%s' eid %d TX flow control disabled\n", + "htc service '%s' eid %d TX flow control disabled\n", htc_service_name(ep->service_id), assigned_eid); } diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index a31b8e89684b..1bb2a88fecb2 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -818,7 +818,7 @@ static int ath11k_recalc_rtscts_prot(struct ath11k_vif *arvif) arvif->rtscts_prot_mode = rts_cts; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d recalc rts/cts prot %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %d recalc rts/cts prot %d\n", arvif->vdev_id, rts_cts); ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, @@ -974,7 +974,7 @@ static int ath11k_mac_monitor_vdev_start(struct ath11k *ar, int vdev_id, goto vdev_stop; } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i started\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "monitor vdev %i started\n", vdev_id); return 0; @@ -1028,7 +1028,7 @@ static int ath11k_mac_monitor_vdev_stop(struct ath11k *ar) return ret; } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i stopped\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "monitor vdev %i stopped\n", ar->monitor_vdev_id); return 0; @@ -1099,7 +1099,7 @@ static int ath11k_mac_monitor_vdev_create(struct ath11k *ar) ar->num_created_vdevs++; set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags); - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %d created\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "monitor vdev %d created\n", ar->monitor_vdev_id); return 0; @@ -1134,7 +1134,7 @@ static int ath11k_mac_monitor_vdev_delete(struct ath11k *ar) if (time_left == 0) { ath11k_warn(ar->ab, "Timeout in receiving vdev delete response\n"); } else { - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %d deleted\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "monitor vdev %d deleted\n", ar->monitor_vdev_id); ar->allocated_vdev_map &= ~(1LL << ar->monitor_vdev_id); @@ -1180,7 +1180,7 @@ static int ath11k_mac_monitor_start(struct ath11k *ar) return ret; } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor started\n"); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "monitor started\n"); return 0; } @@ -1210,7 +1210,7 @@ static int ath11k_mac_monitor_stop(struct ath11k *ar) return ret; } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor stopped ret %d\n", ret); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "monitor stopped ret %d\n", ret); return 0; } @@ -1261,7 +1261,7 @@ static int ath11k_mac_vif_setup_ps(struct ath11k_vif *arvif) psmode = WMI_STA_PS_MODE_DISABLED; } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d psmode %s\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %d psmode %s\n", arvif->vdev_id, psmode ? "enable" : "disable"); ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode); @@ -1641,7 +1641,7 @@ static void ath11k_control_beaconing(struct ath11k_vif *arvif, arvif->is_up = true; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %d up\n", arvif->vdev_id); } static void ath11k_mac_handle_beacon_iter(void *data, u8 *mac, @@ -1964,7 +1964,7 @@ static void ath11k_peer_assoc_h_ht(struct ath11k *ar, arg->peer_nss = min(sta->deflink.rx_nss, max_nss); } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "ht peer %pM mcs cnt %d nss %d\n", arg->peer_mac, arg->peer_ht_rates.num_rates, arg->peer_nss); @@ -2128,7 +2128,7 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar, } if (!user_rate_valid) { - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac setting vht range mcs value to peer supported nss %d for peer %pM\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "setting vht range mcs value to peer supported nss %d for peer %pM\n", sta->deflink.rx_nss, sta->addr); vht_mcs_mask[sta->deflink.rx_nss - 1] = vht_mcs_mask[vht_nss - 1]; } @@ -2185,7 +2185,7 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac vht peer %pM max_mpdu %d flags 0x%x nss_override 0x%x\n", + "vht peer %pM max_mpdu %d flags 0x%x nss_override 0x%x\n", sta->addr, arg->peer_max_mpdu, arg->peer_flags, arg->peer_bw_rxnss_override); } @@ -2410,7 +2410,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, } if (!user_rate_valid) { - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac setting he range mcs value to peer supported nss %d for peer %pM\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "setting he range mcs value to peer supported nss %d for peer %pM\n", sta->deflink.rx_nss, sta->addr); he_mcs_mask[sta->deflink.rx_nss - 1] = he_mcs_mask[he_nss - 1]; } @@ -2491,7 +2491,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac he peer %pM nss %d mcs cnt %d nss_override 0x%x\n", + "he peer %pM nss %d mcs cnt %d nss_override 0x%x\n", sta->addr, arg->peer_nss, arg->peer_he_mcs_count, arg->peer_bw_rxnss_override); @@ -2611,7 +2611,7 @@ static void ath11k_peer_assoc_h_qos(struct ath11k *ar, break; } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac peer %pM qos %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "peer %pM qos %d\n", sta->addr, arg->qos_flag); } @@ -2628,7 +2628,7 @@ static int ath11k_peer_assoc_qos_ap(struct ath11k *ar, params.vdev_id = arvif->vdev_id; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "uapsd_queues 0x%x max_sp %d\n", sta->uapsd_queues, sta->max_sp); uapsd = 0; @@ -2814,7 +2814,7 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar, break; } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac peer %pM phymode %s\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "peer %pM phymode %s\n", sta->addr, ath11k_wmi_phymode_str(phymode)); arg->peer_phymode = phymode; @@ -3005,7 +3005,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, lockdep_assert_held(&ar->conf_mutex); - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %i assoc bssid %pM aid %d\n", arvif->vdev_id, arvif->bssid, arvif->aid); rcu_read_lock(); @@ -3071,7 +3071,7 @@ static void ath11k_bss_assoc(struct ieee80211_hw *hw, arvif->rekey_data.enable_offload = false; ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac vdev %d up (associated) bssid %pM aid %d\n", + "vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, vif->cfg.aid); spin_lock_bh(&ar->ab->base_lock); @@ -3116,7 +3116,7 @@ static void ath11k_bss_disassoc(struct ieee80211_hw *hw, lockdep_assert_held(&ar->conf_mutex); - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %i disassoc bssid %pM\n", arvif->vdev_id, arvif->bssid); ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id); @@ -3265,7 +3265,7 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac obss pd sr_ctrl %x non_srg_thres %u srg_max %u\n", + "obss pd sr_ctrl %x non_srg_thres %u srg_max %u\n", he_obss_pd->sr_ctrl, he_obss_pd->non_srg_max_offset, he_obss_pd->max_offset); @@ -3593,7 +3593,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_TXPOWER) { - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev_id %i txpower %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev_id %i txpower %d\n", arvif->vdev_id, info->txpower); arvif->txpower = info->txpower; @@ -3634,7 +3634,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, rate = ATH11K_HW_RATE_CODE(hw_value, 0, preamble); ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac vdev %d mcast_rate %x\n", + "vdev %d mcast_rate %x\n", arvif->vdev_id, rate); vdev_param = WMI_VDEV_PARAM_MCAST_DATA_RATE; @@ -3743,7 +3743,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, memcpy(arvif->arp_ns_offload.mac_addr, vif->addr, ETH_ALEN); arvif->arp_ns_offload.ipv4_count = ipv4_cnt; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac arp_addr_cnt %d vif->addr %pM, offload_addr %pI4\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "arp_addr_cnt %d vif->addr %pM, offload_addr %pI4\n", vif->cfg.arp_addr_cnt, vif->addr, arvif->arp_ns_offload.ipv4_addr); } @@ -4465,7 +4465,7 @@ ath11k_mac_set_peer_he_fixed_rate(struct ath11k_vif *arvif, return -EINVAL; ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac setting fixed he rate for peer %pM, device will not switch to any other selected rates", + "setting fixed he rate for peer %pM, device will not switch to any other selected rates", sta->addr); rate_code = ATH11K_HW_RATE_CODE(he_rate, nss - 1, @@ -4707,14 +4707,14 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) ath11k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg); peer_phymode = peer_arg.peer_phymode; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM peer bw %d phymode %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "update sta %pM peer bw %d phymode %d\n", sta->addr, bw, peer_phymode); if (bw > bw_prev) { /* BW is upgraded. In this case we send WMI_PEER_PHYMODE * followed by WMI_PEER_CHWIDTH */ - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW upgrade for sta %pM new BW %d, old BW %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "BW upgrade for sta %pM new BW %d, old BW %d\n", sta->addr, bw, bw_prev); err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, @@ -4736,7 +4736,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) /* BW is downgraded. In this case we send WMI_PEER_CHWIDTH * followed by WMI_PEER_PHYMODE */ - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW downgrade for sta %pM new BW %d,old BW %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "BW downgrade for sta %pM new BW %d,old BW %d\n", sta->addr, bw, bw_prev); err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, @@ -4758,7 +4758,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) } if (changed & IEEE80211_RC_NSS_CHANGED) { - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM nss %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "update sta %pM nss %d\n", sta->addr, nss); err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, @@ -4769,7 +4769,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk) } if (changed & IEEE80211_RC_SMPS_CHANGED) { - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM smps %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "update sta %pM smps %d\n", sta->addr, smps); err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, @@ -5227,7 +5227,7 @@ static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, spin_unlock_bh(&ar->ab->base_lock); ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", + "sta rc update for %pM changed %08x bw %d nss %d smps %d\n", sta->addr, changed, sta->deflink.bandwidth, sta->deflink.rx_nss, sta->deflink.smps_mode); @@ -6038,7 +6038,7 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, spin_unlock_bh(&ar->txmgmt_idr_lock); ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac tx mgmt frame, buf id %d\n", buf_id); + "tx mgmt frame, buf id %d\n", buf_id); if (buf_id < 0) return -ENOSPC; @@ -6115,7 +6115,7 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) ath11k_mgmt_over_wmi_tx_drop(ar, skb); } else { ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac tx mgmt frame, vdev_id %d\n", + "tx mgmt frame, vdev_id %d\n", arvif->vdev_id); } } else { @@ -6587,7 +6587,7 @@ void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id) mutex_lock(&ar->ab->vdev_id_11d_lock); - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev id for 11d scan %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev id for 11d scan %d\n", ar->vdev_id_11d_scan); if (ar->regdom_set_by_user) @@ -6606,7 +6606,7 @@ void ath11k_mac_11d_scan_start(struct ath11k *ar, u32 vdev_id) param.start_interval_msec = 0; param.scan_period_msec = ATH11K_SCAN_11D_INTERVAL; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac start 11d scan\n"); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "start 11d scan\n"); ret = ath11k_wmi_send_11d_scan_start_cmd(ar, ¶m); if (ret) { @@ -6635,11 +6635,11 @@ void ath11k_mac_11d_scan_stop(struct ath11k *ar) if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map)) return; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d scan\n"); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "stop 11d scan\n"); mutex_lock(&ar->ab->vdev_id_11d_lock); - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac stop 11d vdev id %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "stop 11d vdev id %d\n", ar->vdev_id_11d_scan); if (ar->state_11d == ATH11K_11D_PREPARING) { @@ -6670,7 +6670,7 @@ void ath11k_mac_11d_scan_stop_all(struct ath11k_base *ab) struct ath11k_pdev *pdev; int i; - ath11k_dbg(ab, ATH11K_DBG_MAC, "mac stop soc 11d scan\n"); + ath11k_dbg(ab, ATH11K_DBG_MAC, "stop soc 11d scan\n"); for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; @@ -6798,7 +6798,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, break; } - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac add interface id %d type %d subtype %d map %llx\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "add interface id %d type %d subtype %d map %llx\n", arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, ab->free_vdev_map); @@ -6989,7 +6989,7 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); - ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", + ath11k_dbg(ab, ATH11K_DBG_MAC, "remove interface (vdev %d)\n", arvif->vdev_id); ret = ath11k_spectral_vif_stop(arvif); @@ -7144,7 +7144,7 @@ static int ath11k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ath11k_base *ab = ar->ab; ath11k_dbg(ab, ATH11K_DBG_MAC, - "mac chanctx add freq %u width %d ptr %pK\n", + "chanctx add freq %u width %d ptr %pK\n", ctx->def.chan->center_freq, ctx->def.width, ctx); mutex_lock(&ar->conf_mutex); @@ -7168,7 +7168,7 @@ static void ath11k_mac_op_remove_chanctx(struct ieee80211_hw *hw, struct ath11k_base *ab = ar->ab; ath11k_dbg(ab, ATH11K_DBG_MAC, - "mac chanctx remove freq %u width %d ptr %pK\n", + "chanctx remove freq %u width %d ptr %pK\n", ctx->def.chan->center_freq, ctx->def.width, ctx); mutex_lock(&ar->conf_mutex); @@ -7248,7 +7248,7 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif, arg.channel.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); ath11k_dbg(ab, ATH11K_DBG_MAC, - "mac vdev %d start center_freq %d phymode %s\n", + "vdev %d start center_freq %d phymode %s\n", arg.vdev_id, arg.channel.freq, ath11k_wmi_phymode_str(arg.channel.mode)); @@ -7522,7 +7522,7 @@ static void ath11k_mac_op_change_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ath11k_dbg(ab, ATH11K_DBG_MAC, - "mac chanctx change freq %u width %d ptr %pK changed %x\n", + "chanctx change freq %u width %d ptr %pK changed %x\n", ctx->def.chan->center_freq, ctx->def.width, ctx, changed); /* This shouldn't really happen because channel switching should use @@ -7603,7 +7603,7 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ath11k_dbg(ab, ATH11K_DBG_MAC, - "mac chanctx assign ptr %pK vdev_id %i\n", + "chanctx assign ptr %pK vdev_id %i\n", ctx, arvif->vdev_id); /* for QCA6390 bss peer must be created before vdev_start */ @@ -7693,7 +7693,7 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ath11k_dbg(ab, ATH11K_DBG_MAC, - "mac chanctx unassign ptr %pK vdev_id %i\n", + "chanctx unassign ptr %pK vdev_id %i\n", ctx, arvif->vdev_id); WARN_ON(!arvif->is_started); @@ -7737,7 +7737,7 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, arvif->bssid, arvif->vdev_id, ret); else ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac removed peer %pM vdev %d after vdev stop\n", + "removed peer %pM vdev %d after vdev stop\n", arvif->bssid, arvif->vdev_id); } @@ -7772,7 +7772,7 @@ ath11k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac chanctx switch n_vifs %d mode %d\n", + "chanctx switch n_vifs %d mode %d\n", n_vifs, mode); ath11k_mac_update_vif_chan(ar, vifs, n_vifs); @@ -8104,7 +8104,7 @@ static int ath11k_mac_set_rate_params(struct ath11k_vif *arvif, lockdep_assert_held(&ar->conf_mutex); ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac set rate params vdev %i rate 0x%02x nss 0x%02x sgi 0x%02x ldpc 0x%02x he_gi 0x%02x he_ltf 0x%02x he_fixed_rate %d\n", + "set rate params vdev %i rate 0x%02x nss 0x%02x sgi 0x%02x ldpc 0x%02x he_gi 0x%02x he_ltf 0x%02x he_fixed_rate %d\n", arvif->vdev_id, rate, nss, sgi, ldpc, he_gi, he_ltf, he_fixed_rate); @@ -8609,7 +8609,7 @@ static void ath11k_mac_put_chain_rssi(struct station_info *sinfo, arsta->chain_signal[i] = ATH11K_INVALID_RSSI_FULL; ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac sta statistics %s rssi[%d] %d\n", pre, i, rssi); + "sta statistics %s rssi[%d] %d\n", pre, i, rssi); if (rssi != ATH11K_DEFAULT_NOISE_FLOOR && rssi != ATH11K_INVALID_RSSI_FULL && @@ -8673,7 +8673,7 @@ static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, signal = arsta->rssi_beacon; ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "mac sta statistics db2dbm %u rssi comb %d rssi beacon %d\n", + "sta statistics db2dbm %u rssi comb %d rssi beacon %d\n", db2dbm, arsta->rssi_comb, arsta->rssi_beacon); if (signal) { @@ -8720,7 +8720,7 @@ static void ath11k_mac_op_ipv6_changed(struct ieee80211_hw *hw, struct list_head *p; u32 count, scope; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac op ipv6 changed\n"); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "op ipv6 changed\n"); offload = &arvif->arp_ns_offload; count = 0; @@ -8745,7 +8745,7 @@ static void ath11k_mac_op_ipv6_changed(struct ieee80211_hw *hw, memcpy(offload->ipv6_addr[count], &ifa6->addr.s6_addr, sizeof(ifa6->addr.s6_addr)); offload->ipv6_type[count] = ATH11K_IPV6_UC_TYPE; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac count %d ipv6 uc %pI6 scope %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "count %d ipv6 uc %pI6 scope %d\n", count, offload->ipv6_addr[count], scope); count++; @@ -8765,7 +8765,7 @@ static void ath11k_mac_op_ipv6_changed(struct ieee80211_hw *hw, memcpy(offload->ipv6_addr[count], &ifaca6->aca_addr, sizeof(ifaca6->aca_addr)); offload->ipv6_type[count] = ATH11K_IPV6_AC_TYPE; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac count %d ipv6 ac %pI6 scope %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "count %d ipv6 ac %pI6 scope %d\n", count, offload->ipv6_addr[count], scope); count++; @@ -8791,7 +8791,7 @@ static void ath11k_mac_op_set_rekey_data(struct ieee80211_hw *hw, struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_rekey_data *rekey_data = &arvif->rekey_data; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set rekey data vdev %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "set rekey data vdev %d\n", arvif->vdev_id); mutex_lock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index a62ee05c5409..d5f25e708bdc 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -325,7 +325,7 @@ static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, { struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev); - ath11k_dbg(ab, ATH11K_DBG_BOOT, "mhi notify status reason %s\n", + ath11k_dbg(ab, ATH11K_DBG_BOOT, "notify status reason %s\n", ath11k_mhi_op_callback_to_str(cb)); switch (cb) { diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 5a779abe666b..75157e6be632 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -312,14 +312,14 @@ static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) val = ath11k_pcic_read32(ab, PCIE_PCIE_PARF_LTSSM); } - ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); + ath11k_dbg(ab, ATH11K_DBG_PCI, "ltssm 0x%x\n", val); val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); val |= GCC_GCC_PCIE_HOT_RST_VAL; ath11k_pcic_write32(ab, GCC_GCC_PCIE_HOT_RST, val); val = ath11k_pcic_read32(ab, GCC_GCC_PCIE_HOT_RST); - ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); + ath11k_dbg(ab, ATH11K_DBG_PCI, "pcie_hot_rst 0x%x\n", val); mdelay(5); } @@ -487,7 +487,7 @@ static int ath11k_pci_config_msi_data(struct ath11k_pci *ab_pci) ab_pci->ab->pci.msi.ep_base_data = msi_desc->msg.data; - ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n", + ath11k_dbg(ab_pci->ab, ATH11K_DBG_PCI, "after request_irq msi_ep_base_data %d\n", ab_pci->ab->pci.msi.ep_base_data); return 0; @@ -545,7 +545,7 @@ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) ab->mem_ce = ab->mem; - ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); + ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci_mem 0x%pK\n", ab->mem); return 0; release_region: @@ -575,7 +575,7 @@ static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci) pcie_capability_read_word(ab_pci->pdev, PCI_EXP_LNKCTL, &ab_pci->link_ctl); - ath11k_dbg(ab, ATH11K_DBG_PCI, "pci link_ctl 0x%04x L0s %d L1 %d\n", + ath11k_dbg(ab, ATH11K_DBG_PCI, "link_ctl 0x%04x L0s %d L1 %d\n", ab_pci->link_ctl, u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L0S), u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1)); @@ -709,7 +709,7 @@ static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 * *minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK, soc_hw_version); - ath11k_dbg(ab, ATH11K_DBG_PCI, "pci tcsr_soc_hw_version major %d minor %d\n", + ath11k_dbg(ab, ATH11K_DBG_PCI, "tcsr_soc_hw_version major %d minor %d\n", *major, *minor); } diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 1380811827a8..114aa3a9a339 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -106,7 +106,7 @@ void ath11k_peer_unmap_event(struct ath11k_base *ab, u16 peer_id) goto exit; } - ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n", + ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer unmap vdev %d peer %pM id %d\n", peer->vdev_id, peer->addr, peer_id); list_del(&peer->list); @@ -138,7 +138,7 @@ void ath11k_peer_map_event(struct ath11k_base *ab, u8 vdev_id, u16 peer_id, wake_up(&ab->peer_mapping_wq); } - ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n", + ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "peer map vdev %d peer %pM id %d\n", vdev_id, mac_addr, peer_id); exit: diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index fa94ad828599..5da4c7663b45 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -1755,7 +1755,7 @@ static int ath11k_qmi_host_cap_send(struct ath11k_base *ab) req.nm_modem |= PLATFORM_CAP_PCIE_PME_D3COLD; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi host cap request\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "host cap request\n"); ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp); @@ -1833,7 +1833,7 @@ static int ath11k_qmi_fw_ind_register_send(struct ath11k_base *ab) if (ret < 0) goto out; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi indication register request\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "indication register request\n"); ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, QMI_WLANFW_IND_REGISTER_REQ_V01, @@ -1889,7 +1889,7 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab) test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) && ab->qmi.target_mem_delayed) { delayed = true; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi delays mem_request %d\n", + ath11k_dbg(ab, ATH11K_DBG_QMI, "delays mem_request %d\n", ab->qmi.mem_seg_count); memset(req, 0, sizeof(*req)); } else { @@ -1901,7 +1901,7 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab) req->mem_seg[i].size = ab->qmi.target_mem[i].size; req->mem_seg[i].type = ab->qmi.target_mem[i].type; ath11k_dbg(ab, ATH11K_DBG_QMI, - "qmi req mem_seg[%d] %pad %u %u\n", i, + "req mem_seg[%d] %pad %u %u\n", i, &ab->qmi.target_mem[i].paddr, ab->qmi.target_mem[i].size, ab->qmi.target_mem[i].type); @@ -1913,7 +1913,7 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab) if (ret < 0) goto out; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi respond memory request delayed %i\n", + ath11k_dbg(ab, ATH11K_DBG_QMI, "respond memory request delayed %i\n", delayed); ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, @@ -2002,7 +2002,7 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) if (!chunk->vaddr) { if (ab->qmi.mem_seg_count <= ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT) { ath11k_dbg(ab, ATH11K_DBG_QMI, - "qmi dma allocation failed (%d B type %u), will try later with small size\n", + "dma allocation failed (%d B type %u), will try later with small size\n", chunk->size, chunk->type); ath11k_qmi_free_target_mem_chunk(ab); @@ -2036,7 +2036,7 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) hremote_node = of_parse_phandle(dev->of_node, "memory-region", 0); if (!hremote_node) { ath11k_dbg(ab, ATH11K_DBG_QMI, - "qmi fail to get hremote_node\n"); + "fail to get hremote_node\n"); return -ENODEV; } @@ -2044,13 +2044,13 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) of_node_put(hremote_node); if (ret) { ath11k_dbg(ab, ATH11K_DBG_QMI, - "qmi fail to get reg from hremote\n"); + "fail to get reg from hremote\n"); return ret; } if (res.end - res.start + 1 < ab->qmi.target_mem[i].size) { ath11k_dbg(ab, ATH11K_DBG_QMI, - "qmi fail to assign memory of sz\n"); + "fail to assign memory of sz\n"); return -EINVAL; } @@ -2198,7 +2198,7 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) if (ret < 0) goto out; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi target cap request\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "target cap request\n"); ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, QMI_WLANFW_CAP_REQ_V01, @@ -2251,7 +2251,7 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) if (resp.eeprom_read_timeout_valid) { ab->qmi.target.eeprom_caldata = resp.eeprom_read_timeout; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cal data supported from eeprom\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "cal data supported from eeprom\n"); } fw_build_id = ab->qmi.target.fw_build_id; @@ -2348,7 +2348,7 @@ static int ath11k_qmi_load_file_target_mem(struct ath11k_base *ab, if (ret < 0) goto err_iounmap; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download req fixed addr type %d\n", + ath11k_dbg(ab, ATH11K_DBG_QMI, "bdf download req fixed addr type %d\n", type); ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, @@ -2381,7 +2381,7 @@ static int ath11k_qmi_load_file_target_mem(struct ath11k_base *ab, remaining -= req->data_len; temp += req->data_len; req->seg_id++; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf download request remaining %i\n", + ath11k_dbg(ab, ATH11K_DBG_QMI, "bdf download request remaining %i\n", remaining); } } @@ -2427,7 +2427,7 @@ static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab, else bdf_type = ATH11K_QMI_BDF_TYPE_BIN; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi bdf_type %d\n", bdf_type); + ath11k_dbg(ab, ATH11K_DBG_QMI, "bdf_type %d\n", bdf_type); fw_size = min_t(u32, ab->hw_params.fw.board_size, bd.len); @@ -2482,14 +2482,14 @@ success: goto out_qmi_cal; } - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi caldata type: %u\n", file_type); + ath11k_dbg(ab, ATH11K_DBG_QMI, "caldata type: %u\n", file_type); out_qmi_cal: if (!ab->qmi.target.eeprom_caldata) release_firmware(fw_entry); out: ath11k_core_free_bdf(ab, &bd); - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi BDF download sequence completed\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "BDF download sequence completed\n"); return ret; } @@ -2574,7 +2574,7 @@ static int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab) if (ret < 0) goto out; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi m3 info req\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "m3 info req\n"); ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, QMI_WLANFW_M3_INFO_REQ_V01, @@ -2623,7 +2623,7 @@ static int ath11k_qmi_wlanfw_mode_send(struct ath11k_base *ab, if (ret < 0) goto out; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wlan mode req mode %d\n", mode); + ath11k_dbg(ab, ATH11K_DBG_QMI, "wlan mode req mode %d\n", mode); ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, QMI_WLANFW_WLAN_MODE_REQ_V01, @@ -2718,7 +2718,7 @@ static int ath11k_qmi_wlanfw_wlan_cfg_send(struct ath11k_base *ab) if (ret < 0) goto out; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wlan cfg req\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "wlan cfg req\n"); ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, QMI_WLANFW_WLAN_CFG_REQ_V01, @@ -2795,7 +2795,7 @@ void ath11k_qmi_firmware_stop(struct ath11k_base *ab) { int ret; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware stop\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "firmware stop\n"); ret = ath11k_qmi_wlanfw_mode_send(ab, ATH11K_FIRMWARE_MODE_OFF); if (ret < 0) { @@ -2809,7 +2809,7 @@ int ath11k_qmi_firmware_start(struct ath11k_base *ab, { int ret; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware start\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "firmware start\n"); if (ab->hw_params.fw_wmi_diag_event) { ret = ath11k_qmi_wlanfw_wlan_ini_send(ab, true); @@ -2967,7 +2967,7 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl, const struct qmi_wlanfw_request_mem_ind_msg_v01 *msg = data; int i, ret; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware request memory request\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "firmware request memory request\n"); if (msg->mem_seg_len == 0 || msg->mem_seg_len > ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01) @@ -2979,7 +2979,7 @@ static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl, for (i = 0; i < qmi->mem_seg_count ; i++) { ab->qmi.target_mem[i].type = msg->mem_seg[i].type; ab->qmi.target_mem[i].size = msg->mem_seg[i].size; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi mem seg type %d size %d\n", + ath11k_dbg(ab, ATH11K_DBG_QMI, "mem seg type %d size %d\n", msg->mem_seg[i].type, msg->mem_seg[i].size); } @@ -3011,7 +3011,7 @@ static void ath11k_qmi_msg_mem_ready_cb(struct qmi_handle *qmi_hdl, struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle); struct ath11k_base *ab = qmi->ab; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware memory ready indication\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "firmware memory ready indication\n"); ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_MEM_READY, NULL); } @@ -3023,7 +3023,7 @@ static void ath11k_qmi_msg_fw_ready_cb(struct qmi_handle *qmi_hdl, struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle); struct ath11k_base *ab = qmi->ab; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware ready\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "firmware ready\n"); if (!ab->qmi.cal_done) { ab->qmi.cal_done = 1; @@ -3044,7 +3044,7 @@ static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi_hdl, ab->qmi.cal_done = 1; wake_up(&ab->qmi.cold_boot_waitq); - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cold boot calibration done\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "cold boot calibration done\n"); } static void ath11k_qmi_msg_fw_init_done_cb(struct qmi_handle *qmi_hdl, @@ -3057,7 +3057,7 @@ static void ath11k_qmi_msg_fw_init_done_cb(struct qmi_handle *qmi_hdl, struct ath11k_base *ab = qmi->ab; ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_INIT_DONE, NULL); - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware init done\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "firmware init done\n"); } static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { @@ -3122,7 +3122,7 @@ static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl, return ret; } - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wifi fw qmi service connected\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "wifi fw qmi service connected\n"); ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_SERVER_ARRIVE, NULL); return ret; @@ -3134,7 +3134,7 @@ static void ath11k_qmi_ops_del_server(struct qmi_handle *qmi_hdl, struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle); struct ath11k_base *ab = qmi->ab; - ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wifi fw del server\n"); + ath11k_dbg(ab, ATH11K_DBG_QMI, "wifi fw del server\n"); ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_SERVER_EXIT, NULL); } diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 67443457f4da..7f9fb968dac6 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -123,7 +123,7 @@ int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait) ar->state_11d = ATH11K_11D_IDLE; } ath11k_dbg(ar->ab, ATH11K_DBG_REG, - "reg 11d scan wait left time %d\n", left); + "11d scan wait left time %d\n", left); } if (wait && @@ -136,7 +136,7 @@ int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait) "failed to receive hw scan complete: timed out\n"); ath11k_dbg(ar->ab, ATH11K_DBG_REG, - "reg hw scan wait left time %d\n", left); + "hw scan wait left time %d\n", left); } if (ar->state == ATH11K_STATE_RESTARTING) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 68622a850527..12a9e220df52 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -766,7 +766,7 @@ int ath11k_wmi_vdev_create(struct ath11k *ar, u8 *macaddr, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n", + "vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n", param->if_id, param->type, param->subtype, macaddr, param->pdev_id); @@ -795,7 +795,7 @@ int ath11k_wmi_vdev_delete(struct ath11k *ar, u8 vdev_id) dev_kfree_skb(skb); } - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "WMI vdev delete id %d\n", vdev_id); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "vdev delete id %d\n", vdev_id); return ret; } @@ -823,7 +823,7 @@ int ath11k_wmi_vdev_stop(struct ath11k *ar, u8 vdev_id) dev_kfree_skb(skb); } - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "WMI vdev stop id 0x%x\n", vdev_id); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "vdev stop id 0x%x\n", vdev_id); return ret; } @@ -851,7 +851,7 @@ int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id) dev_kfree_skb(skb); } - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "WMI vdev down id 0x%x\n", vdev_id); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "vdev down id 0x%x\n", vdev_id); return ret; } @@ -1049,7 +1049,7 @@ int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI mgmt vdev up id 0x%x assoc id %d bssid %pM\n", + "mgmt vdev up id 0x%x assoc id %d bssid %pM\n", vdev_id, aid, bssid); return ret; @@ -1082,7 +1082,7 @@ int ath11k_wmi_send_peer_create_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI peer create vdev_id %d peer_addr %pM\n", + "peer create vdev_id %d peer_addr %pM\n", param->vdev_id, param->peer_addr); return ret; @@ -1108,7 +1108,7 @@ int ath11k_wmi_send_peer_delete_cmd(struct ath11k *ar, cmd->vdev_id = vdev_id; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI peer delete vdev_id %d peer_addr %pM\n", + "peer delete vdev_id %d peer_addr %pM\n", vdev_id, peer_addr); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_DELETE_CMDID); @@ -1146,7 +1146,7 @@ int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar, cmd->pdev_id = param->pdev_id; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI pdev regd rd %d rd2g %d rd5g %d domain %d pdev id %d\n", + "pdev regd rd %d rd2g %d rd5g %d domain %d pdev id %d\n", param->current_rd_in_use, param->current_rd_2g, param->current_rd_5g, param->dfs_domain, param->pdev_id); @@ -1187,7 +1187,7 @@ int ath11k_wmi_set_peer_param(struct ath11k *ar, const u8 *peer_addr, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev %d peer 0x%pM set param %d value %d\n", + "vdev %d peer 0x%pM set param %d value %d\n", vdev_id, peer_addr, param_id, param_val); return ret; @@ -1222,7 +1222,7 @@ int ath11k_wmi_send_peer_flush_tids_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI peer flush vdev_id %d peer_addr %pM tids %08x\n", + "peer flush vdev_id %d peer_addr %pM tids %08x\n", param->vdev_id, peer_addr, param->peer_tid_bitmap); return ret; @@ -1265,7 +1265,7 @@ int ath11k_wmi_peer_rx_reorder_queue_setup(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi rx reorder queue setup addr %pM vdev_id %d tid %d\n", + "rx reorder queue setup addr %pM vdev_id %d tid %d\n", addr, vdev_id, tid); return ret; @@ -1334,7 +1334,7 @@ int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI pdev set param %d pdev id %d value %d\n", + "pdev set param %d pdev id %d value %d\n", param_id, pdev_id, param_value); return ret; @@ -1365,7 +1365,7 @@ int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev set psmode %d vdev id %d\n", + "vdev set psmode %d vdev id %d\n", psmode, vdev_id); return ret; @@ -1398,7 +1398,7 @@ int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI pdev suspend pdev_id %d\n", pdev_id); + "pdev suspend pdev_id %d\n", pdev_id); return ret; } @@ -1421,7 +1421,7 @@ int ath11k_wmi_pdev_resume(struct ath11k *ar, u32 pdev_id) cmd->pdev_id = pdev_id; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI pdev resume pdev id %d\n", pdev_id); + "pdev resume pdev id %d\n", pdev_id); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_RESUME_CMDID); if (ret) { @@ -1457,7 +1457,7 @@ int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar, cmd->pdev_id = ar->pdev->pdev_id; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI bss chan info req type %d\n", type); + "bss chan info req type %d\n", type); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID); @@ -1499,7 +1499,7 @@ int ath11k_wmi_send_set_ap_ps_param_cmd(struct ath11k *ar, u8 *peer_addr, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI set ap ps vdev id %d peer %pM param %d value %d\n", + "set ap ps vdev id %d peer %pM param %d value %d\n", param->vdev_id, peer_addr, param->param, param->value); return ret; @@ -1527,7 +1527,7 @@ int ath11k_wmi_set_sta_ps_param(struct ath11k *ar, u32 vdev_id, cmd->value = param_value; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI set sta ps vdev_id %d param %d value %d\n", + "set sta ps vdev_id %d param %d value %d\n", vdev_id, param, param_value); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_PARAM_CMDID); @@ -1596,7 +1596,7 @@ int ath11k_wmi_vdev_set_param_cmd(struct ath11k *ar, u32 vdev_id, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev id 0x%x set param %d value %d\n", + "vdev id 0x%x set param %d value %d\n", vdev_id, param_id, param_value); return ret; @@ -1629,7 +1629,7 @@ int ath11k_wmi_send_stats_request_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI request stats 0x%x vdev id %d pdev id %d\n", + "request stats 0x%x vdev id %d pdev id %d\n", param->stats_id, param->vdev_id, param->pdev_id); return ret; @@ -1658,7 +1658,7 @@ int ath11k_wmi_send_pdev_temperature_cmd(struct ath11k *ar) } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI pdev get temperature for pdev_id %d\n", ar->pdev->pdev_id); + "pdev get temperature for pdev_id %d\n", ar->pdev->pdev_id); return ret; } @@ -1684,7 +1684,7 @@ int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, cmd->bcn_ctrl_op = bcn_ctrl_op; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI bcn ctrl offload vdev id %d ctrl_op %d\n", + "bcn ctrl offload vdev id %d ctrl_op %d\n", vdev_id, bcn_ctrl_op); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_BCN_OFFLOAD_CTRL_CMDID); @@ -1812,7 +1812,7 @@ int ath11k_wmi_vdev_install_key(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev install key idx %d cipher %d len %d\n", + "vdev install key idx %d cipher %d len %d\n", arg->key_idx, arg->key_cipher, arg->key_len); return ret; @@ -2048,7 +2048,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x\n", + "peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x\n", cmd->vdev_id, cmd->peer_associd, param->peer_mac, cmd->peer_flags, cmd->peer_rate_caps, cmd->peer_caps, cmd->peer_listen_intval, cmd->peer_ht_caps, @@ -2457,7 +2457,7 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, cmd->flags |= WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI no.of chan = %d len = %d pdev_id = %d num_sends = %d\n", + "no.of chan = %d len = %d pdev_id = %d num_sends = %d\n", num_send_chans, len, cmd->pdev_id, num_sends); ptr = skb->data + sizeof(*cmd); @@ -2516,7 +2516,7 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, tchan_info->maxregpower); ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n", + "chan scan list chan[%d] = %u, chan_info->info %8x\n", i, chan_info->mhz, chan_info->info); ptr += sizeof(*chan_info); @@ -2590,7 +2590,7 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id, wmm_param->no_ack = wmi_wmm_arg->no_ack; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi wmm set ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n", + "wmm set ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n", ac, wmm_param->aifs, wmm_param->cwmin, wmm_param->cwmax, wmm_param->txoplimit, wmm_param->acm, wmm_param->no_ack); @@ -2627,7 +2627,7 @@ int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar, cmd->pdev_id = pdev_id; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI dfs phy err offload enable pdev id %d\n", pdev_id); + "dfs phy err offload enable pdev id %d\n", pdev_id); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID); @@ -2662,7 +2662,7 @@ int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, cmd->reasoncode = reason; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n", + "delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n", vdev_id, mac, tid, initiator, reason); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_DELBA_SEND_CMDID); @@ -2698,7 +2698,7 @@ int ath11k_wmi_addba_set_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac, cmd->statuscode = status; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n", + "addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n", vdev_id, mac, tid, status); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SET_RESP_CMDID); @@ -2733,7 +2733,7 @@ int ath11k_wmi_addba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, cmd->buffersize = buf_size; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n", + "addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n", vdev_id, mac, tid, buf_size); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SEND_CMDID); @@ -2766,7 +2766,7 @@ int ath11k_wmi_addba_clear_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac) ether_addr_copy(cmd->peer_macaddr.addr, mac); ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n", + "addba clear resp vdev_id 0x%X mac_addr %pM\n", vdev_id, mac); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_CLEAR_RESP_CMDID); @@ -2975,7 +2975,7 @@ ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev set thermal throt pdev_id %d enable %d dc %d dc_per_event %x levels %d\n", + "vdev set thermal throt pdev_id %d enable %d dc %d dc_per_event %x levels %d\n", ar->pdev->pdev_id, param->enable, param->dc, param->dc_per_event, THERMAL_LEVELS); @@ -3248,7 +3248,7 @@ int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_PROTECTION; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi add twt dialog vdev %u dialog id %u wake interval %u mantissa %u wake duration %u service period offset %u flags 0x%x\n", + "add twt dialog vdev %u dialog id %u wake interval %u mantissa %u wake duration %u service period offset %u flags 0x%x\n", cmd->vdev_id, cmd->dialog_id, cmd->wake_intvl_us, cmd->wake_intvl_mantis, cmd->wake_dura_us, cmd->sp_offset_us, cmd->flags); @@ -3288,7 +3288,7 @@ int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, cmd->dialog_id = params->dialog_id; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi delete twt dialog vdev %u dialog id %u\n", + "delete twt dialog vdev %u dialog id %u\n", cmd->vdev_id, cmd->dialog_id); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DEL_DIALOG_CMDID); @@ -3326,7 +3326,7 @@ int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, cmd->dialog_id = params->dialog_id; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi pause twt dialog vdev %u dialog id %u\n", + "pause twt dialog vdev %u dialog id %u\n", cmd->vdev_id, cmd->dialog_id); ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_PAUSE_DIALOG_CMDID); @@ -3366,7 +3366,7 @@ int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, cmd->next_twt_size = params->next_twt_size; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi resume twt dialog vdev %u dialog id %u service period offset %u next twt subfield size %u\n", + "resume twt dialog vdev %u dialog id %u service period offset %u next twt subfield size %u\n", cmd->vdev_id, cmd->dialog_id, cmd->sp_offset_us, cmd->next_twt_size); @@ -3734,7 +3734,7 @@ int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar, u32 vdev_id, len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev %i set FILS discovery template\n", vdev_id); + "vdev %i set FILS discovery template\n", vdev_id); skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); if (!skb) @@ -3775,7 +3775,7 @@ int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, size_t aligned_len = roundup(tmpl->len, 4); ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev %i set probe response template\n", vdev_id); + "vdev %i set probe response template\n", vdev_id); len = sizeof(*cmd) + sizeof(*probe_info) + TLV_HDR_SIZE + aligned_len; @@ -3824,7 +3824,7 @@ int ath11k_wmi_fils_discovery(struct ath11k *ar, u32 vdev_id, u32 interval, struct wmi_fils_discovery_cmd *cmd; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI vdev %i set %s interval to %u TU\n", + "vdev %i set %s interval to %u TU\n", vdev_id, unsol_bcast_probe_resp_enabled ? "unsolicited broadcast probe response" : "FILS discovery", interval); @@ -4060,7 +4060,7 @@ static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, host_mem_chunks[idx].req_id = param->mem_chunks[idx].req_id; ath11k_dbg(ab, ATH11K_DBG_WMI, - "WMI host mem chunk req_id %d paddr 0x%llx len %d\n", + "host mem chunk req_id %d paddr 0x%llx len %d\n", param->mem_chunks[idx].req_id, (u64)param->mem_chunks[idx].paddr, param->mem_chunks[idx].len); @@ -4147,7 +4147,7 @@ int ath11k_wmi_pdev_lro_cfg(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI lro cfg cmd pdev_id 0x%x\n", pdev_id); + "lro cfg cmd pdev_id 0x%x\n", pdev_id); return 0; err: dev_kfree_skb(skb); @@ -4268,7 +4268,7 @@ int ath11k_wmi_vdev_spectral_conf(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI spectral scan config cmd vdev_id 0x%x\n", + "spectral scan config cmd vdev_id 0x%x\n", param->vdev_id); return 0; @@ -4306,7 +4306,7 @@ int ath11k_wmi_vdev_spectral_enable(struct ath11k *ar, u32 vdev_id, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI spectral enable cmd vdev id 0x%x\n", + "spectral enable cmd vdev id 0x%x\n", vdev_id); return 0; @@ -4352,7 +4352,7 @@ int ath11k_wmi_pdev_dma_ring_cfg(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI DMA ring cfg req cmd pdev_id 0x%x\n", + "DMA ring cfg req cmd pdev_id 0x%x\n", param->pdev_id); return 0; @@ -5773,7 +5773,7 @@ static int wmi_process_mgmt_tx_comp(struct ath11k *ar, WARN_ON_ONCE(1); ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi mgmt tx comp pending %d desc id %d\n", + "mgmt tx comp pending %d desc id %d\n", num_mgmt, tx_compl_param->desc_id); if (!num_mgmt) @@ -6342,7 +6342,7 @@ static int ath11k_wmi_tlv_rssi_chain_parse(struct ath11k_base *ab, stats->stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; ath11k_dbg(ab, ATH11K_DBG_WMI, - "wmi stats vdev id %d mac %pM\n", + "stats vdev id %d mac %pM\n", stats_rssi->vdev_id, stats_rssi->peer_macaddr.addr); arvif = ath11k_mac_get_arvif(ar, stats_rssi->vdev_id); @@ -6354,7 +6354,7 @@ static int ath11k_wmi_tlv_rssi_chain_parse(struct ath11k_base *ab, } ath11k_dbg(ab, ATH11K_DBG_WMI, - "wmi stats bssid %pM vif %pK\n", + "stats bssid %pM vif %pK\n", arvif->bssid, arvif->vif); sta = ieee80211_find_sta_by_ifaddr(ar->hw, @@ -6375,7 +6375,7 @@ static int ath11k_wmi_tlv_rssi_chain_parse(struct ath11k_base *ab, for (j = 0; j < ARRAY_SIZE(arsta->chain_signal); j++) { arsta->chain_signal[j] = stats_rssi->rssi_avg_beacon[j]; ath11k_dbg(ab, ATH11K_DBG_WMI, - "wmi stats beacon rssi[%d] %d data rssi[%d] %d\n", + "stats beacon rssi[%d] %d data rssi[%d] %d\n", j, stats_rssi->rssi_avg_beacon[j], j, @@ -6458,7 +6458,7 @@ static int ath11k_wmi_tlv_fw_stats_data_parse(struct ath11k_base *ab, arsta = (struct ath11k_sta *)sta->drv_priv; arsta->rssi_beacon = src->beacon_snr; ath11k_dbg(ab, ATH11K_DBG_WMI, - "wmi stats vdev id %d snr %d\n", + "stats vdev id %d snr %d\n", src->vdev_id, src->beacon_snr); } else { ath11k_dbg(ab, ATH11K_DBG_WMI, @@ -6528,7 +6528,7 @@ static int ath11k_wmi_tlv_fw_stats_parse(struct ath11k_base *ab, parse->rssi_num = parse->rssi->num_per_chain_rssi_stats; ath11k_dbg(ab, ATH11K_DBG_WMI, - "wmi stats id 0x%x num chain %d\n", + "stats id 0x%x num chain %d\n", parse->ev->stats_id, parse->rssi_num); break; @@ -6927,7 +6927,7 @@ static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *s memcpy(&ab->new_alpha2, &ev->new_alpha2, 2); spin_unlock_bh(&ab->base_lock); - ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi 11d new cc %c%c\n", + ath11k_dbg(ab, ATH11K_DBG_WMI, "11d new cc %c%c\n", ab->new_alpha2[0], ab->new_alpha2[1]); @@ -7497,7 +7497,7 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) if (rx_ev.phy_mode == MODE_11B && (status->band == NL80211_BAND_5GHZ || status->band == NL80211_BAND_6GHZ)) ath11k_dbg(ab, ATH11K_DBG_WMI, - "wmi mgmt rx 11b (CCK) on 5/6GHz, band = %d\n", status->band); + "mgmt rx 11b (CCK) on 5/6GHz, band = %d\n", status->band); sband = &ar->mac.sbands[status->band]; @@ -7747,7 +7747,7 @@ static void ath11k_roam_event(struct ath11k_base *ab, struct sk_buff *skb) } ath11k_dbg(ab, ATH11K_DBG_WMI, - "wmi roam event vdev %u reason 0x%08x rssi %d\n", + "roam event vdev %u reason 0x%08x rssi %d\n", roam_ev.vdev_id, roam_ev.reason, roam_ev.rssi); rcu_read_lock(); @@ -8503,7 +8503,7 @@ static void ath11k_wmi_gtk_offload_status_event(struct ath11k_base *ab, return; } - ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi gtk offload event refresh_cnt %d\n", + ath11k_dbg(ab, ATH11K_DBG_WMI, "gtk offload event refresh_cnt %d\n", ev->refresh_cnt); ath11k_dbg_dump(ab, ATH11K_DBG_WMI, "replay_cnt", NULL, ev->replay_ctr.counter, GTK_REPLAY_COUNTER_BYTES); @@ -8760,7 +8760,7 @@ ath11k_wmi_send_unit_test_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI unit test : module %d vdev %d n_args %d token %d\n", + "unit test : module %d vdev %d n_args %d token %d\n", cmd->module_id, cmd->vdev_id, cmd->num_args, cmd->diag_token); @@ -8957,7 +8957,7 @@ int ath11k_wmi_hw_data_filter_cmd(struct ath11k *ar, u32 vdev_id, cmd->hw_filter_bitmap = ((u32)~0U); ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi hw data filter enable %d filter_bitmap 0x%x\n", + "hw data filter enable %d filter_bitmap 0x%x\n", enable, filter_bitmap); return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_HW_DATA_FILTER_CMDID); @@ -8979,7 +8979,7 @@ int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar) WMI_TAG_WOW_HOSTWAKEUP_FROM_SLEEP_CMD) | FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow host wakeup ind\n"); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow host wakeup ind\n"); return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); } @@ -9001,7 +9001,7 @@ int ath11k_wmi_wow_enable(struct ath11k *ar) cmd->enable = 1; cmd->pause_iface_config = WOW_IFACE_PAUSE_ENABLED; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow enable\n"); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow enable\n"); return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID); } @@ -9028,7 +9028,7 @@ int ath11k_wmi_scan_prob_req_oui(struct ath11k *ar, FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); cmd->prob_req_oui = prob_req_oui; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi scan prob req oui %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "scan prob req oui %d\n", prob_req_oui); return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_SCAN_PROB_REQ_OUI_CMDID); @@ -9055,7 +9055,7 @@ int ath11k_wmi_wow_add_wakeup_event(struct ath11k *ar, u32 vdev_id, cmd->is_add = enable; cmd->event_bitmap = (1 << event); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow add wakeup event %s enable %d vdev_id %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow add wakeup event %s enable %d vdev_id %d\n", wow_wakeup_event(event), enable, vdev_id); return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); @@ -9160,7 +9160,7 @@ int ath11k_wmi_wow_add_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id, WMI_TAG_ARRAY_UINT32) | FIELD_PREP(WMI_TLV_LEN, sizeof(u32)); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow add pattern vdev_id %d pattern_id %d pattern_offset %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow add pattern vdev_id %d pattern_id %d pattern_offset %d\n", vdev_id, pattern_id, pattern_offset); return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ADD_WAKE_PATTERN_CMDID); @@ -9186,7 +9186,7 @@ int ath11k_wmi_wow_del_pattern(struct ath11k *ar, u32 vdev_id, u32 pattern_id) cmd->pattern_id = pattern_id; cmd->pattern_type = WOW_BITMAP_PATTERN; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow del pattern vdev_id %d pattern_id %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv wow del pattern vdev_id %d pattern_id %d\n", vdev_id, pattern_id); return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_DEL_WAKE_PATTERN_CMDID); @@ -9299,7 +9299,7 @@ ath11k_wmi_op_gen_config_pno_start(struct ath11k *ar, for (i = 0; i < cmd->num_of_channels; i++) channel_list[i] = pno->a_networks[0].channels[i]; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv start pno config vdev_id %d\n", + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "tlv start pno config vdev_id %d\n", vdev_id); return skb; @@ -9325,7 +9325,7 @@ static struct sk_buff *ath11k_wmi_op_gen_config_pno_stop(struct ath11k *ar, cmd->flags = WMI_NLO_CONFIG_STOP; ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi tlv stop pno config vdev_id %d\n", vdev_id); + "tlv stop pno config vdev_id %d\n", vdev_id); return skb; } @@ -9402,7 +9402,7 @@ static void ath11k_wmi_fill_ns_offload(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi index %d ns_solicited %pI6 target %pI6", + "index %d ns_solicited %pI6 target %pI6", i, ns->solicitation_ipaddr, ns->target_ipaddr[0]); } @@ -9440,7 +9440,7 @@ static void ath11k_wmi_fill_arp_offload(struct ath11k *ar, memcpy(arp->target_ipaddr, offload->ipv4_addr[i], 4); ath11k_ce_byte_swap(arp->target_ipaddr, 4); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi arp offload address %pI4", + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "arp offload address %pI4", arp->target_ipaddr); } @@ -9673,7 +9673,7 @@ int ath11k_wmi_sta_keepalive(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi sta keepalive vdev %d enabled %d method %d interval %d\n", + "sta keepalive vdev %d enabled %d method %d interval %d\n", arg->vdev_id, arg->enabled, arg->method, arg->interval); return ath11k_wmi_cmd_send(wmi, skb, WMI_STA_KEEPALIVE_CMDID); -- cgit v1.2.3 From e5df15773d8d7b4269bc97a0378dc6d9ba400e84 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:29 +0300 Subject: wifi: ath11k: add WMI event debug messages Add a debug message for every WMI event to make it easier track what's happening in WMI. For better readability start every debug message with "event". Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-5-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/wmi.c | 72 ++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 12a9e220df52..99beb7636835 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -606,6 +606,8 @@ static int ath11k_service_ready_event(struct ath11k_base *ab, struct sk_buff *sk return ret; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event service ready"); + return 0; } @@ -3866,6 +3868,8 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event obss color collision"); + rcu_read_lock(); ev = tb[WMI_TAG_OBSS_COLOR_COLLISION_EVT]; @@ -4458,6 +4462,8 @@ static void ath11k_wmi_pdev_dma_ring_buf_release_event(struct ath11k_base *ab, return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event pdev dma ring buf release"); + param.fixed = parse.fixed; param.buf_entry = parse.buf_entry; param.num_buf_entry = parse.num_buf_entry; @@ -4852,6 +4858,8 @@ static int ath11k_service_ready_ext_event(struct ath11k_base *ab, goto err; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event service ready ext"); + if (!test_bit(WMI_TLV_SERVICE_EXT2_MSG, ab->wmi_ab.svc_map)) complete(&ab->wmi_ab.service_ready); @@ -4902,6 +4910,8 @@ static int ath11k_service_ready_ext2_event(struct ath11k_base *ab, goto err; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event service ready ext2"); + complete(&ab->wmi_ab.service_ready); return 0; @@ -6927,7 +6937,7 @@ static int ath11k_reg_11d_new_cc_event(struct ath11k_base *ab, struct sk_buff *s memcpy(&ab->new_alpha2, &ev->new_alpha2, 2); spin_unlock_bh(&ab->base_lock); - ath11k_dbg(ab, ATH11K_DBG_WMI, "11d new cc %c%c\n", + ath11k_dbg(ab, ATH11K_DBG_WMI, "event 11d new cc %c%c\n", ab->new_alpha2[0], ab->new_alpha2[1]); @@ -7011,6 +7021,8 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, goto fallback; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event reg chan list id %d", id); + if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { /* In case of failure to set the requested ctry, * fw retains the current regd. We print a failure info @@ -7176,6 +7188,8 @@ static int ath11k_ready_event(struct ath11k_base *ab, struct sk_buff *skb) return ret; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event ready"); + complete(&ab->wmi_ab.unified_ready); return 0; } @@ -7190,6 +7204,8 @@ static void ath11k_peer_delete_resp_event(struct ath11k_base *ab, struct sk_buff return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event peer delete resp"); + rcu_read_lock(); ar = ath11k_mac_get_ar_by_vdev_id(ab, peer_del_resp.vdev_id); if (!ar) { @@ -7229,7 +7245,7 @@ static void ath11k_vdev_delete_resp_event(struct ath11k_base *ab, rcu_read_unlock(); - ath11k_dbg(ab, ATH11K_DBG_WMI, "vdev delete resp for vdev id %d\n", + ath11k_dbg(ab, ATH11K_DBG_WMI, "event vdev delete resp for vdev id %d\n", vdev_id); } @@ -7260,6 +7276,8 @@ static void ath11k_vdev_start_resp_event(struct ath11k_base *ab, struct sk_buff return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event start resp event"); + rcu_read_lock(); ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_start_resp.vdev_id); if (!ar) { @@ -7298,6 +7316,8 @@ static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *s return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event offload bcn tx status"); + rcu_read_lock(); arvif = ath11k_mac_get_arvif_by_vdev_id(ab, vdev_id); if (!arvif) { @@ -7337,7 +7357,7 @@ static void ath11k_wmi_event_peer_sta_ps_state_chg(struct ath11k_base *ab, } ath11k_dbg(ab, ATH11K_DBG_WMI, - "peer sta ps change ev addr %pM state %u sup_bitmap %x ps_valid %u ts %u\n", + "event peer sta ps change ev addr %pM state %u sup_bitmap %x ps_valid %u ts %u\n", ev->peer_macaddr.addr, ev->peer_ps_state, ev->ps_supported_bitmap, ev->peer_ps_valid, ev->peer_ps_timestamp); @@ -7421,6 +7441,8 @@ static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *sk return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event vdev stopped"); + rcu_read_lock(); ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id); if (!ar) { @@ -7454,7 +7476,7 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) memset(status, 0, sizeof(*status)); - ath11k_dbg(ab, ATH11K_DBG_MGMT, "mgmt rx event status %08x\n", + ath11k_dbg(ab, ATH11K_DBG_MGMT, "event mgmt rx status %08x\n", rx_ev.status); rcu_read_lock(); @@ -7573,7 +7595,7 @@ static void ath11k_mgmt_tx_compl_event(struct ath11k_base *ab, struct sk_buff *s wmi_process_mgmt_tx_comp(ar, &tx_compl_param); ath11k_dbg(ab, ATH11K_DBG_MGMT, - "mgmt tx compl ev pdev_id %d, desc_id %d, status %d ack_rssi %d", + "event mgmt tx compl ev pdev_id %d, desc_id %d, status %d ack_rssi %d", tx_compl_param.pdev_id, tx_compl_param.desc_id, tx_compl_param.status, tx_compl_param.ack_rssi); @@ -7644,7 +7666,7 @@ static void ath11k_scan_event(struct ath11k_base *ab, struct sk_buff *skb) spin_lock_bh(&ar->data_lock); ath11k_dbg(ab, ATH11K_DBG_WMI, - "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n", + "event scan %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n", ath11k_wmi_event_scan_type_str(scan_ev.event_type, scan_ev.reason), scan_ev.event_type, scan_ev.reason, scan_ev.channel_freq, scan_ev.scan_req_id, scan_ev.scan_id, scan_ev.vdev_id, @@ -7727,7 +7749,7 @@ static void ath11k_peer_sta_kickout_event(struct ath11k_base *ab, struct sk_buff goto exit; } - ath11k_dbg(ab, ATH11K_DBG_WMI, "peer sta kickout event %pM", + ath11k_dbg(ab, ATH11K_DBG_WMI, "event peer sta kickout %pM", arg.mac_addr); ieee80211_report_low_ack(sta, 10); @@ -7747,7 +7769,7 @@ static void ath11k_roam_event(struct ath11k_base *ab, struct sk_buff *skb) } ath11k_dbg(ab, ATH11K_DBG_WMI, - "roam event vdev %u reason 0x%08x rssi %d\n", + "event roam vdev %u reason 0x%08x rssi %d\n", roam_ev.vdev_id, roam_ev.reason, roam_ev.rssi); rcu_read_lock(); @@ -7794,7 +7816,7 @@ static void ath11k_chan_info_event(struct ath11k_base *ab, struct sk_buff *skb) } ath11k_dbg(ab, ATH11K_DBG_WMI, - "chan info vdev_id %d err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d mac_clk_mhz %d\n", + "event chan info vdev_id %d err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d mac_clk_mhz %d\n", ch_info_ev.vdev_id, ch_info_ev.err_code, ch_info_ev.freq, ch_info_ev.cmd_flags, ch_info_ev.noise_floor, ch_info_ev.rx_clear_count, ch_info_ev.cycle_count, @@ -7883,7 +7905,7 @@ ath11k_pdev_bss_chan_info_event(struct ath11k_base *ab, struct sk_buff *skb) bss_ch_info_ev.rx_bss_cycle_count_low; ath11k_dbg(ab, ATH11K_DBG_WMI, - "pdev bss chan info:\n pdev_id: %d freq: %d noise: %d cycle: busy %llu total %llu tx %llu rx %llu rx_bss %llu\n", + "event pdev bss chan info:\n pdev_id: %d freq: %d noise: %d cycle: busy %llu total %llu tx %llu rx %llu rx_bss %llu\n", bss_ch_info_ev.pdev_id, bss_ch_info_ev.freq, bss_ch_info_ev.noise_floor, busy, total, tx, rx, rx_bss); @@ -7937,7 +7959,7 @@ static void ath11k_vdev_install_key_compl_event(struct ath11k_base *ab, } ath11k_dbg(ab, ATH11K_DBG_WMI, - "vdev install key ev idx %d flags %08x macaddr %pM status %d\n", + "event vdev install key ev idx %d flags %08x macaddr %pM status %d\n", install_key_compl.key_idx, install_key_compl.key_flags, install_key_compl.macaddr, install_key_compl.status); @@ -8020,6 +8042,8 @@ static void ath11k_service_available_event(struct ath11k_base *ab, struct sk_buf NULL); if (ret) ath11k_warn(ab, "failed to parse services available tlv %d\n", ret); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "event service available"); } static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff *skb) @@ -8033,7 +8057,7 @@ static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff } ath11k_dbg(ab, ATH11K_DBG_WMI, - "peer assoc conf ev vdev id %d macaddr %pM\n", + "event peer assoc conf ev vdev id %d macaddr %pM\n", peer_assoc_conf.vdev_id, peer_assoc_conf.macaddr); rcu_read_lock(); @@ -8066,6 +8090,8 @@ static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *sk goto free; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event update stats"); + rcu_read_lock(); ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id); if (!ar) { @@ -8126,7 +8152,7 @@ static void ath11k_pdev_ctl_failsafe_check_event(struct ath11k_base *ab, } ath11k_dbg(ab, ATH11K_DBG_WMI, - "pdev ctl failsafe check ev status %d\n", + "event pdev ctl failsafe check status %d\n", ev->ctl_failsafe_status); /* If ctl_failsafe_status is set to 1 FW will max out the Transmit power @@ -8193,7 +8219,7 @@ ath11k_wmi_pdev_csa_switch_count_status_event(struct ath11k_base *ab, } ath11k_dbg(ab, ATH11K_DBG_WMI, - "pdev csa switch count %d for pdev %d, num_vdevs %d", + "event pdev csa switch count %d for pdev %d, num_vdevs %d", ev->current_switch_count, ev->pdev_id, ev->num_vdevs); @@ -8226,7 +8252,7 @@ ath11k_wmi_pdev_dfs_radar_detected_event(struct ath11k_base *ab, struct sk_buff } ath11k_dbg(ab, ATH11K_DBG_WMI, - "pdev dfs radar detected on pdev %d, detection mode %d, chan freq %d, chan_width %d, detector id %d, seg id %d, timestamp %d, chirp %d, freq offset %d, sidx %d", + "event pdev dfs radar detected on pdev %d, detection mode %d, chan freq %d, chan_width %d, detector id %d, seg id %d, timestamp %d, chirp %d, freq offset %d, sidx %d", ev->pdev_id, ev->detection_mode, ev->chan_freq, ev->chan_width, ev->detector_id, ev->segment_id, ev->timestamp, ev->is_chirp, ev->freq_offset, ev->sidx); @@ -8274,8 +8300,8 @@ ath11k_wmi_pdev_temperature_event(struct ath11k_base *ab, return; } - ath11k_dbg(ab, ATH11K_DBG_WMI, - "pdev temperature ev temp %d pdev_id %d\n", ev->temp, ev->pdev_id); + ath11k_dbg(ab, ATH11K_DBG_WMI, "event pdev temperature ev temp %d pdev_id %d\n", + ev->temp, ev->pdev_id); ar = ath11k_mac_get_ar_by_pdev_id(ab, ev->pdev_id); if (!ar) { @@ -8305,6 +8331,8 @@ static void ath11k_fils_discovery_event(struct ath11k_base *ab, return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event fils discovery"); + ev = tb[WMI_TAG_HOST_SWFDA_EVENT]; if (!ev) { ath11k_warn(ab, "failed to fetch FILS discovery event\n"); @@ -8335,6 +8363,8 @@ static void ath11k_probe_resp_tx_status_event(struct ath11k_base *ab, return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event probe resp tx status"); + ev = tb[WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT]; if (!ev) { ath11k_warn(ab, @@ -8401,6 +8431,8 @@ static void ath11k_wmi_event_wow_wakeup_host(struct ath11k_base *ab, struct sk_b return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event wow wakeup host"); + complete(&ab->wow.wakeup_completed); } @@ -8408,6 +8440,8 @@ static void ath11k_wmi_diag_event(struct ath11k_base *ab, struct sk_buff *skb) { + ath11k_dbg(ab, ATH11K_DBG_WMI, "event diag"); + trace_ath11k_wmi_diag(ab, skb->data, skb->len); } @@ -8455,6 +8489,8 @@ static void ath11k_wmi_twt_add_dialog_event(struct ath11k_base *ab, return; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "event twt add dialog"); + ev = tb[WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT]; if (!ev) { ath11k_warn(ab, "failed to fetch twt add dialog wmi event\n"); @@ -8503,7 +8539,7 @@ static void ath11k_wmi_gtk_offload_status_event(struct ath11k_base *ab, return; } - ath11k_dbg(ab, ATH11K_DBG_WMI, "gtk offload event refresh_cnt %d\n", + ath11k_dbg(ab, ATH11K_DBG_WMI, "event gtk offload refresh_cnt %d\n", ev->refresh_cnt); ath11k_dbg_dump(ab, ATH11K_DBG_WMI, "replay_cnt", NULL, ev->replay_ctr.counter, GTK_REPLAY_COUNTER_BYTES); -- cgit v1.2.3 From 8fbeaca7a001cf6e854fceade17865c7b23b3ce2 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:30 +0300 Subject: wifi: ath11k: remove unsupported event handlers Now that we have a default handler there's no need anymore to list every unsupported event id anymore, so remove that to clean this up. While at it remove the pointless todo comment and change the debug message to follow the preferred style. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-6-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/wmi.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 99beb7636835..6ce36879a503 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -8663,19 +8663,6 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_TWT_ADD_DIALOG_EVENTID: ath11k_wmi_twt_add_dialog_event(ab, skb); break; - /* add Unsupported events here */ - case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: - case WMI_PEER_OPER_MODE_CHANGE_EVENTID: - case WMI_TWT_ENABLE_EVENTID: - case WMI_TWT_DISABLE_EVENTID: - case WMI_TWT_DEL_DIALOG_EVENTID: - case WMI_TWT_PAUSE_DIALOG_EVENTID: - case WMI_TWT_RESUME_DIALOG_EVENTID: - case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: - case WMI_PEER_CREATE_CONF_EVENTID: - ath11k_dbg(ab, ATH11K_DBG_WMI, - "ignoring unsupported event 0x%x\n", id); - break; case WMI_PDEV_DFS_RADAR_DETECTION_EVENTID: ath11k_wmi_pdev_dfs_radar_detected_event(ab, skb); break; @@ -8697,9 +8684,8 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_GTK_OFFLOAD_STATUS_EVENTID: ath11k_wmi_gtk_offload_status_event(ab, skb); break; - /* TODO: Add remaining events */ default: - ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); + ath11k_dbg(ab, ATH11K_DBG_WMI, "unsupported event id 0x%x\n", id); break; } -- cgit v1.2.3 From 90a9fb5b6618ae070c94b2141ec5de6a2a207eae Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:31 +0300 Subject: wifi: ath11k: wmi: cleanup error handling in ath11k_wmi_send_init_country_cmd() The error handling doesn't follow the preferred style so fix that. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-7-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/wmi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 6ce36879a503..3b26e227e80c 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -2866,21 +2866,25 @@ ath11k_wmi_send_init_country_cmd(struct ath11k *ar, cmd->cc_info.regdom_id = init_cc_params.cc_info.regdom_id; break; default: + ath11k_warn(ar->ab, "unknown cc params flags: 0x%x", + init_cc_params.flags); ret = -EINVAL; - goto out; + goto err; } ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_INIT_COUNTRY_CMDID); - -out: if (ret) { ath11k_warn(ar->ab, "failed to send WMI_SET_INIT_COUNTRY CMD :%d\n", ret); - dev_kfree_skb(skb); + goto err; } + return 0; + +err: + dev_kfree_skb(skb); return ret; } -- cgit v1.2.3 From afba35d7d12514aa1122fdfb4ca5459417656813 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:32 +0300 Subject: wifi: ath11k: wmi: use common error handling style Also these functions don't follow the preferred style so fix those. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-8-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/wmi.c | 80 ++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 3b26e227e80c..972f282a3032 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -3181,10 +3181,12 @@ int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id, if (ret) { ath11k_warn(ab, "Failed to send WMI_TWT_ENABLE_CMDID"); dev_kfree_skb(skb); - } else { - ar->twt_enabled = 1; + return ret; } - return ret; + + ar->twt_enabled = 1; + + return 0; } int @@ -3211,10 +3213,12 @@ ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id) if (ret) { ath11k_warn(ab, "Failed to send WMI_TWT_DISABLE_CMDID"); dev_kfree_skb(skb); - } else { - ar->twt_enabled = 0; + return ret; } - return ret; + + ar->twt_enabled = 0; + + return 0; } int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, @@ -3266,8 +3270,10 @@ int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, "failed to send wmi command to add twt dialog: %d", ret); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, @@ -3303,8 +3309,10 @@ int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, "failed to send wmi command to delete twt dialog: %d", ret); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, @@ -3341,8 +3349,10 @@ int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, "failed to send wmi command to pause twt dialog: %d", ret); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, @@ -3382,8 +3392,10 @@ int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, "failed to send wmi command to resume twt dialog: %d", ret); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int @@ -3417,8 +3429,10 @@ ath11k_wmi_send_obss_spr_cmd(struct ath11k *ar, u32 vdev_id, ath11k_warn(ab, "Failed to send WMI_PDEV_OBSS_PD_SPATIAL_REUSE_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int @@ -3453,9 +3467,10 @@ ath11k_wmi_pdev_set_srg_bss_color_bitmap(struct ath11k *ar, u32 *bitmap) ath11k_warn(ab, "failed to send WMI_PDEV_SET_SRG_BSS_COLOR_BITMAP_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + return 0; } int @@ -3491,9 +3506,10 @@ ath11k_wmi_pdev_set_srg_patial_bssid_bitmap(struct ath11k *ar, u32 *bitmap) ath11k_warn(ab, "failed to send WMI_PDEV_SET_SRG_PARTIAL_BSSID_BITMAP_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + return 0; } int @@ -3529,9 +3545,10 @@ ath11k_wmi_pdev_srg_obss_color_enable_bitmap(struct ath11k *ar, u32 *bitmap) ath11k_warn(ab, "failed to send WMI_PDEV_SET_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + return 0; } int @@ -3567,9 +3584,10 @@ ath11k_wmi_pdev_srg_obss_bssid_enable_bitmap(struct ath11k *ar, u32 *bitmap) ath11k_warn(ab, "failed to send WMI_PDEV_SET_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + return 0; } int @@ -3605,9 +3623,10 @@ ath11k_wmi_pdev_non_srg_obss_color_enable_bitmap(struct ath11k *ar, u32 *bitmap) ath11k_warn(ab, "failed to send WMI_PDEV_SET_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + return 0; } int @@ -3643,9 +3662,10 @@ ath11k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(struct ath11k *ar, u32 *bitmap) ath11k_warn(ab, "failed to send WMI_PDEV_SET_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + return 0; } int @@ -3688,8 +3708,10 @@ ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id, if (ret) { ath11k_warn(ab, "Failed to send WMI_OBSS_COLOR_COLLISION_DET_CONFIG_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id, @@ -3722,8 +3744,10 @@ int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id, if (ret) { ath11k_warn(ab, "Failed to send WMI_BSS_COLOR_CHANGE_ENABLE_CMDID"); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar, u32 vdev_id, @@ -3765,8 +3789,10 @@ int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar, u32 vdev_id, "WMI vdev %i failed to send FILS discovery template command\n", vdev_id); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, @@ -3818,8 +3844,10 @@ int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, "WMI vdev %i failed to send probe response template command\n", vdev_id); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } int ath11k_wmi_fils_discovery(struct ath11k *ar, u32 vdev_id, u32 interval, @@ -3853,8 +3881,10 @@ int ath11k_wmi_fils_discovery(struct ath11k *ar, u32 vdev_id, u32 interval, "WMI vdev %i failed to send FILS discovery enable/disable command\n", vdev_id); dev_kfree_skb(skb); + return ret; } - return ret; + + return 0; } static void @@ -4122,9 +4152,10 @@ static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, if (ret) { ath11k_warn(ab, "failed to send WMI_INIT_CMDID\n"); dev_kfree_skb(skb); + return ret; } - return ret; + return 0; } int ath11k_wmi_pdev_lro_cfg(struct ath11k *ar, @@ -4213,9 +4244,10 @@ int ath11k_wmi_set_hw_mode(struct ath11k_base *ab, if (ret) { ath11k_warn(ab, "failed to send WMI_PDEV_SET_HW_MODE_CMDID\n"); dev_kfree_skb(skb); + return ret; } - return ret; + return 0; } int ath11k_wmi_cmd_init(struct ath11k_base *ab) -- cgit v1.2.3 From 00608b40ae1aea8b79d110b51784ae291af380f4 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:33 +0300 Subject: wifi: ath11k: wmi: add unified command debug messages Add debug messages for every command and cleanup the existing ones to make them all follow the same style. For better readability start every message with "cmd". Print the debug message after a successful ath11k_wmi_cmd_send() call. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-9-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/wmi.c | 328 +++++++++++++++++++--------------- 1 file changed, 185 insertions(+), 143 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 972f282a3032..17d565b03238 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -692,6 +692,8 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd mgmt tx send"); + return ret; } @@ -768,7 +770,7 @@ int ath11k_wmi_vdev_create(struct ath11k *ar, u8 *macaddr, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n", + "cmd vdev create id %d type %d subtype %d macaddr %pM pdevid %d\n", param->if_id, param->type, param->subtype, macaddr, param->pdev_id); @@ -797,7 +799,7 @@ int ath11k_wmi_vdev_delete(struct ath11k *ar, u8 vdev_id) dev_kfree_skb(skb); } - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "vdev delete id %d\n", vdev_id); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev delete id %d\n", vdev_id); return ret; } @@ -825,7 +827,7 @@ int ath11k_wmi_vdev_stop(struct ath11k *ar, u8 vdev_id) dev_kfree_skb(skb); } - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "vdev stop id 0x%x\n", vdev_id); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev stop id 0x%x\n", vdev_id); return ret; } @@ -853,7 +855,7 @@ int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id) dev_kfree_skb(skb); } - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "vdev down id 0x%x\n", vdev_id); + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev down id 0x%x\n", vdev_id); return ret; } @@ -996,7 +998,7 @@ int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg, dev_kfree_skb(skb); } - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "vdev %s id 0x%x freq 0x%x mode 0x%x\n", + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev %s id 0x%x freq 0x%x mode 0x%x\n", restart ? "restart" : "start", arg->vdev_id, arg->channel.freq, arg->channel.mode); @@ -1051,7 +1053,7 @@ int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "mgmt vdev up id 0x%x assoc id %d bssid %pM\n", + "cmd vdev up id 0x%x assoc id %d bssid %pM\n", vdev_id, aid, bssid); return ret; @@ -1084,7 +1086,7 @@ int ath11k_wmi_send_peer_create_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "peer create vdev_id %d peer_addr %pM\n", + "cmd peer create vdev_id %d peer_addr %pM\n", param->vdev_id, param->peer_addr); return ret; @@ -1109,16 +1111,16 @@ int ath11k_wmi_send_peer_delete_cmd(struct ath11k *ar, ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); cmd->vdev_id = vdev_id; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "peer delete vdev_id %d peer_addr %pM\n", - vdev_id, peer_addr); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_DELETE_CMDID); if (ret) { ath11k_warn(ar->ab, "failed to send WMI_PEER_DELETE cmd\n"); dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd peer delete vdev_id %d peer_addr %pM\n", + vdev_id, peer_addr); + return ret; } @@ -1147,11 +1149,6 @@ int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar, cmd->dfs_domain = param->dfs_domain; cmd->pdev_id = param->pdev_id; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "pdev regd rd %d rd2g %d rd5g %d domain %d pdev id %d\n", - param->current_rd_in_use, param->current_rd_2g, - param->current_rd_5g, param->dfs_domain, param->pdev_id); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_REGDOMAIN_CMDID); if (ret) { ath11k_warn(ar->ab, @@ -1159,6 +1156,11 @@ int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev regd rd %d rd2g %d rd5g %d domain %d pdev id %d\n", + param->current_rd_in_use, param->current_rd_2g, + param->current_rd_5g, param->dfs_domain, param->pdev_id); + return ret; } @@ -1189,7 +1191,7 @@ int ath11k_wmi_set_peer_param(struct ath11k *ar, const u8 *peer_addr, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "vdev %d peer 0x%pM set param %d value %d\n", + "cmd peer set param vdev %d peer 0x%pM set param %d value %d\n", vdev_id, peer_addr, param_id, param_val); return ret; @@ -1224,7 +1226,7 @@ int ath11k_wmi_send_peer_flush_tids_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "peer flush vdev_id %d peer_addr %pM tids %08x\n", + "cmd peer flush tids vdev_id %d peer_addr %pM tids %08x\n", param->vdev_id, peer_addr, param->peer_tid_bitmap); return ret; @@ -1267,7 +1269,7 @@ int ath11k_wmi_peer_rx_reorder_queue_setup(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "rx reorder queue setup addr %pM vdev_id %d tid %d\n", + "cmd peer reorder queue setup addr %pM vdev_id %d tid %d\n", addr, vdev_id, tid); return ret; @@ -1295,10 +1297,6 @@ ath11k_wmi_rx_reord_queue_remove(struct ath11k *ar, cmd->vdev_id = param->vdev_id; cmd->tid_mask = param->peer_tid_bitmap; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "%s: peer_macaddr %pM vdev_id %d, tid_map %d", __func__, - param->peer_macaddr, param->vdev_id, param->peer_tid_bitmap); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PEER_REORDER_QUEUE_REMOVE_CMDID); if (ret) { @@ -1307,6 +1305,10 @@ ath11k_wmi_rx_reord_queue_remove(struct ath11k *ar, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd peer reorder queue remove peer_macaddr %pM vdev_id %d tid_map %d", + param->peer_macaddr, param->vdev_id, param->peer_tid_bitmap); + return ret; } @@ -1336,7 +1338,7 @@ int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "pdev set param %d pdev id %d value %d\n", + "cmd pdev set param %d pdev id %d value %d\n", param_id, pdev_id, param_value); return ret; @@ -1367,7 +1369,7 @@ int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "vdev set psmode %d vdev id %d\n", + "cmd sta powersave mode psmode %d vdev id %d\n", psmode, vdev_id); return ret; @@ -1400,7 +1402,7 @@ int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "pdev suspend pdev_id %d\n", pdev_id); + "cmd pdev suspend pdev_id %d\n", pdev_id); return ret; } @@ -1422,15 +1424,15 @@ int ath11k_wmi_pdev_resume(struct ath11k *ar, u32 pdev_id) FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); cmd->pdev_id = pdev_id; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "pdev resume pdev id %d\n", pdev_id); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_RESUME_CMDID); if (ret) { ath11k_warn(ar->ab, "failed to send WMI_PDEV_RESUME cmd\n"); dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev resume pdev id %d\n", pdev_id); + return ret; } @@ -1458,9 +1460,6 @@ int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar, cmd->req_type = type; cmd->pdev_id = ar->pdev->pdev_id; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "bss chan info req type %d\n", type); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID); if (ret) { @@ -1469,6 +1468,9 @@ int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev bss chan info request type %d\n", type); + return ret; } @@ -1501,7 +1503,7 @@ int ath11k_wmi_send_set_ap_ps_param_cmd(struct ath11k *ar, u8 *peer_addr, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "set ap ps vdev id %d peer %pM param %d value %d\n", + "cmd ap ps peer param vdev id %d peer %pM param %d value %d\n", param->vdev_id, peer_addr, param->param, param->value); return ret; @@ -1528,16 +1530,16 @@ int ath11k_wmi_set_sta_ps_param(struct ath11k *ar, u32 vdev_id, cmd->param = param; cmd->value = param_value; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "set sta ps vdev_id %d param %d value %d\n", - vdev_id, param, param_value); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_PARAM_CMDID); if (ret) { ath11k_warn(ar->ab, "failed to send WMI_STA_POWERSAVE_PARAM_CMDID"); dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd set powersave param vdev_id %d param %d value %d\n", + vdev_id, param, param_value); + return ret; } @@ -1567,6 +1569,9 @@ int ath11k_wmi_force_fw_hang_cmd(struct ath11k *ar, u32 type, u32 delay_time_ms) ath11k_warn(ar->ab, "Failed to send WMI_FORCE_FW_HANG_CMDID"); dev_kfree_skb(skb); } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd force fw hang"); + return ret; } @@ -1598,7 +1603,7 @@ int ath11k_wmi_vdev_set_param_cmd(struct ath11k *ar, u32 vdev_id, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "vdev id 0x%x set param %d value %d\n", + "cmd vdev set param vdev 0x%x param %d value %d\n", vdev_id, param_id, param_value); return ret; @@ -1631,7 +1636,7 @@ int ath11k_wmi_send_stats_request_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "request stats 0x%x vdev id %d pdev id %d\n", + "cmd request stats 0x%x vdev id %d pdev id %d\n", param->stats_id, param->vdev_id, param->pdev_id); return ret; @@ -1660,7 +1665,7 @@ int ath11k_wmi_send_pdev_temperature_cmd(struct ath11k *ar) } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "pdev get temperature for pdev_id %d\n", ar->pdev->pdev_id); + "cmd pdev get temperature for pdev_id %d\n", ar->pdev->pdev_id); return ret; } @@ -1685,10 +1690,6 @@ int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, cmd->vdev_id = vdev_id; cmd->bcn_ctrl_op = bcn_ctrl_op; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "bcn ctrl offload vdev id %d ctrl_op %d\n", - vdev_id, bcn_ctrl_op); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_BCN_OFFLOAD_CTRL_CMDID); if (ret) { ath11k_warn(ar->ab, @@ -1696,6 +1697,10 @@ int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd bcn offload ctrl vdev id %d ctrl_op %d\n", + vdev_id, bcn_ctrl_op); + return ret; } @@ -1765,6 +1770,8 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd bcn tmpl"); + return ret; } @@ -1814,7 +1821,7 @@ int ath11k_wmi_vdev_install_key(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "vdev install key idx %d cipher %d len %d\n", + "cmd vdev install key idx %d cipher %d len %d\n", arg->key_idx, arg->key_cipher, arg->key_len); return ret; @@ -2050,7 +2057,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x\n", + "cmd peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x\n", cmd->vdev_id, cmd->peer_associd, param->peer_mac, cmd->peer_flags, cmd->peer_rate_caps, cmd->peer_caps, cmd->peer_listen_intval, cmd->peer_ht_caps, @@ -2367,6 +2374,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd start scan"); + return ret; } @@ -2415,6 +2424,8 @@ int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd stop scan"); + return ret; } @@ -2533,6 +2544,9 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd scan chan list channels %d", + num_send_chans); + num_sends++; } @@ -2605,6 +2619,8 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd vdev set wmm params"); + return ret; } @@ -2628,9 +2644,6 @@ int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar, cmd->pdev_id = pdev_id; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "dfs phy err offload enable pdev id %d\n", pdev_id); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID); if (ret) { @@ -2639,6 +2652,9 @@ int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev dfs phyerr offload enable pdev id %d\n", pdev_id); + return ret; } @@ -2663,10 +2679,6 @@ int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, cmd->initiator = initiator; cmd->reasoncode = reason; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n", - vdev_id, mac, tid, initiator, reason); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_DELBA_SEND_CMDID); if (ret) { @@ -2675,6 +2687,10 @@ int ath11k_wmi_delba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n", + vdev_id, mac, tid, initiator, reason); + return ret; } @@ -2699,10 +2715,6 @@ int ath11k_wmi_addba_set_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac, cmd->tid = tid; cmd->statuscode = status; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n", - vdev_id, mac, tid, status); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SET_RESP_CMDID); if (ret) { @@ -2711,6 +2723,10 @@ int ath11k_wmi_addba_set_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n", + vdev_id, mac, tid, status); + return ret; } @@ -2734,10 +2750,6 @@ int ath11k_wmi_addba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, cmd->tid = tid; cmd->buffersize = buf_size; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n", - vdev_id, mac, tid, buf_size); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SEND_CMDID); if (ret) { @@ -2746,6 +2758,10 @@ int ath11k_wmi_addba_send(struct ath11k *ar, u32 vdev_id, const u8 *mac, dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n", + vdev_id, mac, tid, buf_size); + return ret; } @@ -2767,10 +2783,6 @@ int ath11k_wmi_addba_clear_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac) cmd->vdev_id = vdev_id; ether_addr_copy(cmd->peer_macaddr.addr, mac); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "addba clear resp vdev_id 0x%X mac_addr %pM\n", - vdev_id, mac); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_ADDBA_CLEAR_RESP_CMDID); if (ret) { @@ -2779,6 +2791,10 @@ int ath11k_wmi_addba_clear_resp(struct ath11k *ar, u32 vdev_id, const u8 *mac) dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd addba clear resp vdev_id 0x%X mac_addr %pM\n", + vdev_id, mac); + return ret; } @@ -2827,6 +2843,8 @@ int ath11k_wmi_pdev_peer_pktlog_filter(struct ath11k *ar, u8 *addr, u8 enable) dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd pdev pktlog filter"); + return ret; } @@ -2881,6 +2899,8 @@ ath11k_wmi_send_init_country_cmd(struct ath11k *ar, goto err; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd set init country"); + return 0; err: @@ -2907,20 +2927,20 @@ int ath11k_wmi_send_set_current_country_cmd(struct ath11k *ar, cmd->pdev_id = ar->pdev->pdev_id; memcpy(&cmd->new_alpha2, ¶m->alpha2, 3); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); - - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "set current country pdev id %d alpha2 %c%c\n", - ar->pdev->pdev_id, - param->alpha2[0], - param->alpha2[1]); + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID); if (ret) { ath11k_warn(ar->ab, "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret); dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd set current country pdev id %d alpha2 %c%c\n", + ar->pdev->pdev_id, + param->alpha2[0], + param->alpha2[1]); + return ret; } @@ -2981,7 +3001,7 @@ ath11k_wmi_send_thermal_mitigation_param_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "vdev set thermal throt pdev_id %d enable %d dc %d dc_per_event %x levels %d\n", + "cmd therm throt set conf pdev_id %d enable %d dc %d dc_per_event %x levels %d\n", ar->pdev->pdev_id, param->enable, param->dc, param->dc_per_event, THERMAL_LEVELS); @@ -3008,20 +3028,20 @@ int ath11k_wmi_send_11d_scan_start_cmd(struct ath11k *ar, cmd->vdev_id = param->vdev_id; cmd->scan_period_msec = param->scan_period_msec; cmd->start_interval_msec = param->start_interval_msec; - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID); - - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "send 11d scan start vdev id %d period %d ms internal %d ms\n", - cmd->vdev_id, - cmd->scan_period_msec, - cmd->start_interval_msec); + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID); if (ret) { ath11k_warn(ar->ab, "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret); dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd 11d scan start vdev id %d period %d ms internal %d ms\n", + cmd->vdev_id, + cmd->scan_period_msec, + cmd->start_interval_msec); + return ret; } @@ -3042,18 +3062,18 @@ int ath11k_wmi_send_11d_scan_stop_cmd(struct ath11k *ar, u32 vdev_id) FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); cmd->vdev_id = vdev_id; - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID); - - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "send 11d scan stop vdev id %d\n", - cmd->vdev_id); + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID); if (ret) { ath11k_warn(ar->ab, "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret); dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd 11d scan stop vdev id %d\n", + cmd->vdev_id); + return ret; } @@ -3084,6 +3104,8 @@ int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter) dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd pdev pktlog enable"); + return ret; } @@ -3112,6 +3134,8 @@ int ath11k_wmi_pdev_pktlog_disable(struct ath11k *ar) dev_kfree_skb(skb); } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd pdev pktlog disable"); + return ret; } @@ -3186,6 +3210,8 @@ int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id, ar->twt_enabled = 1; + ath11k_dbg(ab, ATH11K_DBG_WMI, "cmd twt enable"); + return 0; } @@ -3216,6 +3242,8 @@ ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id) return ret; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "cmd twt disable"); + ar->twt_enabled = 0; return 0; @@ -3257,14 +3285,7 @@ int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, if (params->flag_protection) cmd->flags |= WMI_TWT_ADD_DIALOG_FLAG_PROTECTION; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "add twt dialog vdev %u dialog id %u wake interval %u mantissa %u wake duration %u service period offset %u flags 0x%x\n", - cmd->vdev_id, cmd->dialog_id, cmd->wake_intvl_us, - cmd->wake_intvl_mantis, cmd->wake_dura_us, cmd->sp_offset_us, - cmd->flags); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_ADD_DIALOG_CMDID); - if (ret) { ath11k_warn(ab, "failed to send wmi command to add twt dialog: %d", @@ -3273,6 +3294,12 @@ int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd twt add dialog vdev %u dialog id %u wake interval %u mantissa %u wake duration %u service period offset %u flags 0x%x\n", + cmd->vdev_id, cmd->dialog_id, cmd->wake_intvl_us, + cmd->wake_intvl_mantis, cmd->wake_dura_us, cmd->sp_offset_us, + cmd->flags); + return 0; } @@ -3299,10 +3326,6 @@ int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); cmd->dialog_id = params->dialog_id; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "delete twt dialog vdev %u dialog id %u\n", - cmd->vdev_id, cmd->dialog_id); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DEL_DIALOG_CMDID); if (ret) { ath11k_warn(ab, @@ -3312,6 +3335,10 @@ int ath11k_wmi_send_twt_del_dialog_cmd(struct ath11k *ar, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd twt del dialog vdev %u dialog id %u\n", + cmd->vdev_id, cmd->dialog_id); + return 0; } @@ -3339,10 +3366,6 @@ int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, ether_addr_copy(cmd->peer_macaddr.addr, params->peer_macaddr); cmd->dialog_id = params->dialog_id; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "pause twt dialog vdev %u dialog id %u\n", - cmd->vdev_id, cmd->dialog_id); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_PAUSE_DIALOG_CMDID); if (ret) { ath11k_warn(ab, @@ -3352,6 +3375,10 @@ int ath11k_wmi_send_twt_pause_dialog_cmd(struct ath11k *ar, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd twt pause dialog vdev %u dialog id %u\n", + cmd->vdev_id, cmd->dialog_id); + return 0; } @@ -3381,11 +3408,6 @@ int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, cmd->sp_offset_us = params->sp_offset_us; cmd->next_twt_size = params->next_twt_size; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "resume twt dialog vdev %u dialog id %u service period offset %u next twt subfield size %u\n", - cmd->vdev_id, cmd->dialog_id, cmd->sp_offset_us, - cmd->next_twt_size); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_RESUME_DIALOG_CMDID); if (ret) { ath11k_warn(ab, @@ -3395,6 +3417,11 @@ int ath11k_wmi_send_twt_resume_dialog_cmd(struct ath11k *ar, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd twt resume dialog vdev %u dialog id %u service period offset %u next twt subfield size %u\n", + cmd->vdev_id, cmd->dialog_id, cmd->sp_offset_us, + cmd->next_twt_size); + return 0; } @@ -3432,6 +3459,8 @@ ath11k_wmi_send_obss_spr_cmd(struct ath11k *ar, u32 vdev_id, return ret; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "cmd pdev obss pd spatial reuse"); + return 0; } @@ -3457,10 +3486,6 @@ ath11k_wmi_pdev_set_srg_bss_color_bitmap(struct ath11k *ar, u32 *bitmap) cmd->pdev_id = ar->pdev->pdev_id; memcpy(cmd->bitmap, bitmap, sizeof(cmd->bitmap)); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "obss pd pdev_id %d bss color bitmap %08x %08x\n", - cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_SRG_BSS_COLOR_BITMAP_CMDID); if (ret) { @@ -3470,6 +3495,10 @@ ath11k_wmi_pdev_set_srg_bss_color_bitmap(struct ath11k *ar, u32 *bitmap) return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev set srg bss color bitmap pdev_id %d bss color bitmap %08x %08x\n", + cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); + return 0; } @@ -3496,10 +3525,6 @@ ath11k_wmi_pdev_set_srg_patial_bssid_bitmap(struct ath11k *ar, u32 *bitmap) cmd->pdev_id = ar->pdev->pdev_id; memcpy(cmd->bitmap, bitmap, sizeof(cmd->bitmap)); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "obss pd pdev_id %d partial bssid bitmap %08x %08x\n", - cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_SRG_PARTIAL_BSSID_BITMAP_CMDID); if (ret) { @@ -3509,6 +3534,10 @@ ath11k_wmi_pdev_set_srg_patial_bssid_bitmap(struct ath11k *ar, u32 *bitmap) return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev set srg partial bssid bitmap pdev_id %d partial bssid bitmap %08x %08x\n", + cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); + return 0; } @@ -3535,10 +3564,6 @@ ath11k_wmi_pdev_srg_obss_color_enable_bitmap(struct ath11k *ar, u32 *bitmap) cmd->pdev_id = ar->pdev->pdev_id; memcpy(cmd->bitmap, bitmap, sizeof(cmd->bitmap)); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "obss pd srg pdev_id %d bss color enable bitmap %08x %08x\n", - cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID); if (ret) { @@ -3548,6 +3573,10 @@ ath11k_wmi_pdev_srg_obss_color_enable_bitmap(struct ath11k *ar, u32 *bitmap) return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev set srg obsscolor enable pdev_id %d bss color enable bitmap %08x %08x\n", + cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); + return 0; } @@ -3574,10 +3603,6 @@ ath11k_wmi_pdev_srg_obss_bssid_enable_bitmap(struct ath11k *ar, u32 *bitmap) cmd->pdev_id = ar->pdev->pdev_id; memcpy(cmd->bitmap, bitmap, sizeof(cmd->bitmap)); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "obss pd srg pdev_id %d bssid enable bitmap %08x %08x\n", - cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID); if (ret) { @@ -3587,6 +3612,10 @@ ath11k_wmi_pdev_srg_obss_bssid_enable_bitmap(struct ath11k *ar, u32 *bitmap) return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev set srg obss bssid enable bitmap pdev_id %d bssid enable bitmap %08x %08x\n", + cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); + return 0; } @@ -3613,10 +3642,6 @@ ath11k_wmi_pdev_non_srg_obss_color_enable_bitmap(struct ath11k *ar, u32 *bitmap) cmd->pdev_id = ar->pdev->pdev_id; memcpy(cmd->bitmap, bitmap, sizeof(cmd->bitmap)); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "obss pd non_srg pdev_id %d bss color enable bitmap %08x %08x\n", - cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID); if (ret) { @@ -3626,6 +3651,10 @@ ath11k_wmi_pdev_non_srg_obss_color_enable_bitmap(struct ath11k *ar, u32 *bitmap) return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev set non srg obss color enable bitmap pdev_id %d bss color enable bitmap %08x %08x\n", + cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); + return 0; } @@ -3652,10 +3681,6 @@ ath11k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(struct ath11k *ar, u32 *bitmap) cmd->pdev_id = ar->pdev->pdev_id; memcpy(cmd->bitmap, bitmap, sizeof(cmd->bitmap)); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "obss pd non_srg pdev_id %d bssid enable bitmap %08x %08x\n", - cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID); if (ret) { @@ -3665,6 +3690,10 @@ ath11k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(struct ath11k *ar, u32 *bitmap) return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd pdev set non srg obss bssid enable bitmap pdev_id %d bssid enable bitmap %08x %08x\n", + cmd->pdev_id, cmd->bitmap[0], cmd->bitmap[1]); + return 0; } @@ -3698,11 +3727,6 @@ ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id, cmd->free_slot_expiry_time_ms = 0; cmd->flags = 0; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi_send_obss_color_collision_cfg id %d type %d bss_color %d detect_period %d scan_period %d\n", - cmd->vdev_id, cmd->evt_type, cmd->current_bss_color, - cmd->detection_period_ms, cmd->scan_period_ms); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_OBSS_COLOR_COLLISION_DET_CONFIG_CMDID); if (ret) { @@ -3711,6 +3735,11 @@ ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd obss color collision det config id %d type %d bss_color %d detect_period %d scan_period %d\n", + cmd->vdev_id, cmd->evt_type, cmd->current_bss_color, + cmd->detection_period_ms, cmd->scan_period_ms); + return 0; } @@ -3735,10 +3764,6 @@ int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id, cmd->vdev_id = vdev_id; cmd->enable = enable ? 1 : 0; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "wmi_send_bss_color_change_enable id %d enable %d\n", - cmd->vdev_id, cmd->enable); - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_BSS_COLOR_CHANGE_ENABLE_CMDID); if (ret) { @@ -3747,6 +3772,10 @@ int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "cmd bss color change enable id %d enable %d\n", + cmd->vdev_id, cmd->enable); + return 0; } @@ -3792,6 +3821,8 @@ int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar, u32 vdev_id, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd fils discovery tmpl"); + return 0; } @@ -3847,6 +3878,8 @@ int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd "); + return 0; } @@ -3884,6 +3917,8 @@ int ath11k_wmi_fils_discovery(struct ath11k *ar, u32 vdev_id, u32 interval, return ret; } + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd enable fils"); + return 0; } @@ -4155,6 +4190,8 @@ static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, return ret; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "cmd wmi init"); + return 0; } @@ -4186,7 +4223,7 @@ int ath11k_wmi_pdev_lro_cfg(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "lro cfg cmd pdev_id 0x%x\n", pdev_id); + "cmd lro config pdev_id 0x%x\n", pdev_id); return 0; err: dev_kfree_skb(skb); @@ -4247,6 +4284,8 @@ int ath11k_wmi_set_hw_mode(struct ath11k_base *ab, return ret; } + ath11k_dbg(ab, ATH11K_DBG_WMI, "cmd pdev set hw mode %d", cmd->hw_mode_index); + return 0; } @@ -4308,7 +4347,7 @@ int ath11k_wmi_vdev_spectral_conf(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "spectral scan config cmd vdev_id 0x%x\n", + "cmd vdev spectral scan configure vdev_id 0x%x\n", param->vdev_id); return 0; @@ -4346,7 +4385,7 @@ int ath11k_wmi_vdev_spectral_enable(struct ath11k *ar, u32 vdev_id, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "spectral enable cmd vdev id 0x%x\n", + "cmd vdev spectral scan enable vdev id 0x%x\n", vdev_id); return 0; @@ -4392,7 +4431,7 @@ int ath11k_wmi_pdev_dma_ring_cfg(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "DMA ring cfg req cmd pdev_id 0x%x\n", + "cmd pdev dma ring cfg req pdev_id 0x%x\n", param->pdev_id); return 0; @@ -8818,7 +8857,7 @@ ath11k_wmi_send_unit_test_cmd(struct ath11k *ar, } ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "unit test : module %d vdev %d n_args %d token %d\n", + "cmd unit test module %d vdev %d n_args %d token %d\n", cmd->module_id, cmd->vdev_id, cmd->num_args, cmd->diag_token); @@ -8910,6 +8949,9 @@ int ath11k_wmi_fw_dbglog_cfg(struct ath11k *ar, u32 *module_id_bitmap, "failed to send WMI_DBGLOG_CFG_CMDID\n"); dev_kfree_skb(skb); } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd dbglog cfg"); + return ret; } -- cgit v1.2.3 From 332c656289388887b2cd39a3f53fc05dcc65e310 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:34 +0300 Subject: wifi: ath11k: pci: cleanup debug logging For better readability fix PCI debug messages to follow the preferred style. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-10-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/mhi.c | 4 ++-- drivers/net/wireless/ath/ath11k/pci.c | 10 +++++----- drivers/net/wireless/ath/ath11k/pcic.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index d5f25e708bdc..3ac689f1def4 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -211,7 +211,7 @@ void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab) val = ath11k_pcic_read32(ab, MHISTATUS); - ath11k_dbg(ab, ATH11K_DBG_PCI, "MHISTATUS 0x%x\n", val); + ath11k_dbg(ab, ATH11K_DBG_PCI, "mhistatus 0x%x\n", val); /* Observed on QCA6390 that after SOC_GLOBAL_RESET, MHISTATUS * has SYSERR bit set and thus need to set MHICTRL_RESET @@ -263,7 +263,7 @@ static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci) if (ret) return ret; - ath11k_dbg(ab, ATH11K_DBG_PCI, "Number of assigned MSI for MHI is %d, base vector is %d\n", + ath11k_dbg(ab, ATH11K_DBG_PCI, "num_vectors %d base_vector %d\n", num_vectors, base_vector); irq = kcalloc(num_vectors, sizeof(int), GFP_KERNEL); diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 75157e6be632..ee67bfd90abe 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -203,10 +203,10 @@ static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) /* read cookie */ val = ath11k_pcic_read32(ab, PCIE_Q6_COOKIE_ADDR); - ath11k_dbg(ab, ATH11K_DBG_PCI, "cookie:0x%x\n", val); + ath11k_dbg(ab, ATH11K_DBG_PCI, "pcie_q6_cookie_addr 0x%x\n", val); val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); - ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); + ath11k_dbg(ab, ATH11K_DBG_PCI, "wlaon_warm_sw_entry 0x%x\n", val); /* TODO: exact time to sleep is uncertain */ mdelay(10); @@ -218,13 +218,13 @@ static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) mdelay(10); val = ath11k_pcic_read32(ab, WLAON_WARM_SW_ENTRY); - ath11k_dbg(ab, ATH11K_DBG_PCI, "WLAON_WARM_SW_ENTRY 0x%x\n", val); + ath11k_dbg(ab, ATH11K_DBG_PCI, "wlaon_warm_sw_entry 0x%x\n", val); /* A read clear register. clear the register to prevent * Q6 from entering wrong code path. */ val = ath11k_pcic_read32(ab, WLAON_SOC_RESET_CAUSE_REG); - ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); + ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause %d\n", val); } static int ath11k_pci_set_link_reg(struct ath11k_base *ab, @@ -433,7 +433,7 @@ static int ath11k_pci_alloc_msi(struct ath11k_pci *ab_pci) } clear_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags); ab->pci.msi.config = &msi_config_one_msi; - ath11k_dbg(ab, ATH11K_DBG_PCI, "request MSI one vector\n"); + ath11k_dbg(ab, ATH11K_DBG_PCI, "request one msi vector\n"); } ath11k_info(ab, "MSI vectors: %d\n", num_vectors); diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index 30d66147223f..c899616fbee4 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -263,7 +263,7 @@ int ath11k_pcic_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, *user_base_data = *base_vector + ab->pci.msi.ep_base_data; ath11k_dbg(ab, ATH11K_DBG_PCI, - "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", + "msi assignment %s num_vectors %d user_base_data %u base_vector %u\n", user_name, *num_vectors, *user_base_data, *base_vector); @@ -527,7 +527,7 @@ static irqreturn_t ath11k_pcic_ext_interrupt_handler(int irq, void *arg) if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) return IRQ_HANDLED; - ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); + ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq %d\n", irq); /* last interrupt received for this group */ irq_grp->timestamp = jiffies; @@ -597,7 +597,7 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) ab->irq_num[irq_idx] = irq; ath11k_dbg(ab, ATH11K_DBG_PCI, - "irq:%d group:%d\n", irq, i); + "irq %d group %d\n", irq, i); irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); ret = request_irq(irq, ath11k_pcic_ext_interrupt_handler, -- cgit v1.2.3 From 947b5e22481837117a7a75bfe04a699538cad836 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:35 +0300 Subject: wifi: ath11k: dp: cleanup debug message Merge the two debug messages into and fix them to follow the preferred style. Also change the log level to ATH11K_DBG_DP_TX to match the filename. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-11-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/dp_tx.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 08a28464eb7a..a34833de7c67 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -964,14 +964,10 @@ int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id, params.low_threshold); } - ath11k_dbg(ab, ATH11k_DBG_HAL, - "%s msi_addr_lo:0x%x, msi_addr_hi:0x%x, msi_data:0x%x\n", - __func__, cmd->ring_msi_addr_lo, cmd->ring_msi_addr_hi, - cmd->msi_data); - - ath11k_dbg(ab, ATH11k_DBG_HAL, - "ring_id:%d, ring_type:%d, intr_info:0x%x, flags:0x%x\n", - ring_id, ring_type, cmd->intr_info, cmd->info2); + ath11k_dbg(ab, ATH11K_DBG_DP_TX, + "htt srng setup msi_addr_lo 0x%x msi_addr_hi 0x%x msi_data 0x%x ring_id %d ring_type %d intr_info 0x%x flags 0x%x\n", + cmd->ring_msi_addr_lo, cmd->ring_msi_addr_hi, + cmd->msi_data, ring_id, ring_type, cmd->intr_info, cmd->info2); ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb); if (ret) -- cgit v1.2.3 From 06819e471f28a4f818c3abf4fb2520a2db9047d9 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:36 +0300 Subject: wifi: ath11k: debug: use all upper case in ATH11k_DBG_HAL Somehow the character 'k' in ATH11k_DBG_HAL was in lower case. Change it to upper case. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-12-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/debug.h | 4 ++-- drivers/net/wireless/ath/ath11k/hal.c | 6 +++--- drivers/net/wireless/ath/ath11k/hal_rx.c | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index 2dd84d8ed5a5..f0dddd188ef0 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -22,7 +22,7 @@ enum ath11k_debug_mask { ATH11K_DBG_MGMT = 0x00000100, ATH11K_DBG_REG = 0x00000200, ATH11K_DBG_TESTMODE = 0x00000400, - ATH11k_DBG_HAL = 0x00000800, + ATH11K_DBG_HAL = 0x00000800, ATH11K_DBG_PCI = 0x00001000, ATH11K_DBG_DP_TX = 0x00002000, ATH11K_DBG_DP_RX = 0x00004000, @@ -53,7 +53,7 @@ static inline const char *ath11k_dbg_str(enum ath11k_debug_mask mask) return "reg"; case ATH11K_DBG_TESTMODE: return "testmode"; - case ATH11k_DBG_HAL: + case ATH11K_DBG_HAL: return "hal"; case ATH11K_DBG_PCI: return "pci"; diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 2cdc8478d253..148eeb06a906 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1009,7 +1009,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, srng->u.src_ring.hp_addr = (u32 *)((unsigned long)ab->mem + reg_base); else - ath11k_dbg(ab, ATH11k_DBG_HAL, + ath11k_dbg(ab, ATH11K_DBG_HAL, "type %d ring_num %d reg_base 0x%x shadow 0x%lx\n", type, ring_num, reg_base, @@ -1043,7 +1043,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, (u32 *)((unsigned long)ab->mem + reg_base + (HAL_REO1_RING_TP(ab) - HAL_REO1_RING_HP(ab))); else - ath11k_dbg(ab, ATH11k_DBG_HAL, + ath11k_dbg(ab, ATH11K_DBG_HAL, "type %d ring_num %d target_reg 0x%x shadow 0x%lx\n", type, ring_num, reg_base + (HAL_REO1_RING_TP(ab) - @@ -1118,7 +1118,7 @@ int ath11k_hal_srng_update_shadow_config(struct ath11k_base *ab, ath11k_hal_srng_update_hp_tp_addr(ab, shadow_cfg_idx, ring_type, ring_num); - ath11k_dbg(ab, ATH11k_DBG_HAL, + ath11k_dbg(ab, ATH11K_DBG_HAL, "target_reg %x, shadow reg 0x%x shadow_idx 0x%x, ring_type %d, ring num %d", target_reg, HAL_SHADOW_REG(ab, shadow_cfg_idx), diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c index bb1d40034aa8..e5ed5efb139e 100644 --- a/drivers/net/wireless/ath/ath11k/hal_rx.c +++ b/drivers/net/wireless/ath/ath11k/hal_rx.c @@ -442,54 +442,54 @@ void ath11k_hal_reo_status_queue_stats(struct ath11k_base *ab, u32 *reo_desc, FIELD_GET(HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS, desc->hdr.info0); - ath11k_dbg(ab, ATH11k_DBG_HAL, "Queue stats status:\n"); - ath11k_dbg(ab, ATH11k_DBG_HAL, "header: cmd_num %d status %d\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "Queue stats status:\n"); + ath11k_dbg(ab, ATH11K_DBG_HAL, "header: cmd_num %d status %d\n", status->uniform_hdr.cmd_num, status->uniform_hdr.cmd_status); - ath11k_dbg(ab, ATH11k_DBG_HAL, "ssn %ld cur_idx %ld\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "ssn %ld cur_idx %ld\n", FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_SSN, desc->info0), FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO0_CUR_IDX, desc->info0)); - ath11k_dbg(ab, ATH11k_DBG_HAL, "pn = [%08x, %08x, %08x, %08x]\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "pn = [%08x, %08x, %08x, %08x]\n", desc->pn[0], desc->pn[1], desc->pn[2], desc->pn[3]); - ath11k_dbg(ab, ATH11k_DBG_HAL, + ath11k_dbg(ab, ATH11K_DBG_HAL, "last_rx: enqueue_tstamp %08x dequeue_tstamp %08x\n", desc->last_rx_enqueue_timestamp, desc->last_rx_dequeue_timestamp); - ath11k_dbg(ab, ATH11k_DBG_HAL, + ath11k_dbg(ab, ATH11K_DBG_HAL, "rx_bitmap [%08x %08x %08x %08x %08x %08x %08x %08x]\n", desc->rx_bitmap[0], desc->rx_bitmap[1], desc->rx_bitmap[2], desc->rx_bitmap[3], desc->rx_bitmap[4], desc->rx_bitmap[5], desc->rx_bitmap[6], desc->rx_bitmap[7]); - ath11k_dbg(ab, ATH11k_DBG_HAL, "count: cur_mpdu %ld cur_msdu %ld\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "count: cur_mpdu %ld cur_msdu %ld\n", FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MPDU_COUNT, desc->info1), FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO1_MSDU_COUNT, desc->info1)); - ath11k_dbg(ab, ATH11k_DBG_HAL, "fwd_timeout %ld fwd_bar %ld dup_count %ld\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "fwd_timeout %ld fwd_bar %ld dup_count %ld\n", FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_TIMEOUT_COUNT, desc->info2), FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_FDTB_COUNT, desc->info2), FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO2_DUPLICATE_COUNT, desc->info2)); - ath11k_dbg(ab, ATH11k_DBG_HAL, "frames_in_order %ld bar_rcvd %ld\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "frames_in_order %ld bar_rcvd %ld\n", FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO3_FIO_COUNT, desc->info3), FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO3_BAR_RCVD_CNT, desc->info3)); - ath11k_dbg(ab, ATH11k_DBG_HAL, "num_mpdus %d num_msdus %d total_bytes %d\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "num_mpdus %d num_msdus %d total_bytes %d\n", desc->num_mpdu_frames, desc->num_msdu_frames, desc->total_bytes); - ath11k_dbg(ab, ATH11k_DBG_HAL, "late_rcvd %ld win_jump_2k %ld hole_cnt %ld\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "late_rcvd %ld win_jump_2k %ld hole_cnt %ld\n", FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_LATE_RX_MPDU, desc->info4), FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_WINDOW_JMP2K, desc->info4), FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO4_HOLE_COUNT, desc->info4)); - ath11k_dbg(ab, ATH11k_DBG_HAL, "looping count %ld\n", + ath11k_dbg(ab, ATH11K_DBG_HAL, "looping count %ld\n", FIELD_GET(HAL_REO_GET_QUEUE_STATS_STATUS_INFO5_LOOPING_CNT, desc->info5)); } -- cgit v1.2.3 From ac483942616a068da25348c473d96725226189c8 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:37 +0300 Subject: wifi: ath11k: hal: cleanup debug message Fix the debug message to follow the preferred style. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-13-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/hal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 148eeb06a906..0a99aa7ddbf4 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -1119,7 +1119,7 @@ int ath11k_hal_srng_update_shadow_config(struct ath11k_base *ab, ring_num); ath11k_dbg(ab, ATH11K_DBG_HAL, - "target_reg %x, shadow reg 0x%x shadow_idx 0x%x, ring_type %d, ring num %d", + "update shadow config target_reg %x shadow reg 0x%x shadow_idx 0x%x ring_type %d ring num %d", target_reg, HAL_SHADOW_REG(ab, shadow_cfg_idx), shadow_cfg_idx, -- cgit v1.2.3 From cf036c416e9a0a8216900f9f43c41a1815847a00 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:38 +0300 Subject: wifi: ath11k: don't use %pK According to Documentation/core-api/printk-formats.rst %pK should not be used with printk(), so switch back to using just %p. printk() will hash the address so addresses are not leaked to user space. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-14-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/dp_rx.c | 6 +++--- drivers/net/wireless/ath/ath11k/htc.c | 4 ++-- drivers/net/wireless/ath/ath11k/mac.c | 10 +++++----- drivers/net/wireless/ath/ath11k/pci.c | 2 +- drivers/net/wireless/ath/ath11k/wmi.c | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 0ed3d2580e91..5c76664ba0dd 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -2466,7 +2466,7 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap spin_unlock_bh(&ar->ab->base_lock); ath11k_dbg(ar->ab, ATH11K_DBG_DATA, - "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + "rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", msdu, msdu->len, peer ? peer->addr : NULL, @@ -4908,7 +4908,7 @@ ath11k_dp_rx_mon_merg_msdus(struct ath11k *ar, goto err_merge_fail; ath11k_dbg(ab, ATH11K_DBG_DATA, - "mpdu_buf %pK mpdu_buf->len %u", + "mpdu_buf %p mpdu_buf->len %u", prev_buf, prev_buf->len); } else { ath11k_dbg(ab, ATH11K_DBG_DATA, @@ -5099,7 +5099,7 @@ static void ath11k_dp_rx_mon_dest_process(struct ath11k *ar, int mac_id, if (!mon_dst_srng) { ath11k_warn(ar->ab, - "HAL Monitor Destination Ring Init Failed -- %pK", + "HAL Monitor Destination Ring Init Failed -- %p", mon_dst_srng); return; } diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index 7d277cd60b07..deace873da85 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -46,7 +46,7 @@ static struct sk_buff *ath11k_htc_build_tx_ctrl_skb(void *ab) skb_cb = ATH11K_SKB_CB(skb); memset(skb_cb, 0, sizeof(*skb_cb)); - ath11k_dbg(ab, ATH11K_DBG_HTC, "%s: skb %pK\n", __func__, skb); + ath11k_dbg(ab, ATH11K_DBG_HTC, "%s: skb %p\n", __func__, skb); return skb; } @@ -393,7 +393,7 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, goto out; } - ath11k_dbg(ab, ATH11K_DBG_HTC, "rx completion ep %d skb %pK\n", + ath11k_dbg(ab, ATH11K_DBG_HTC, "rx completion ep %d skb %p\n", eid, skb); ep->ep_ops.ep_rx_complete(ab, skb); diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 1bb2a88fecb2..32d958b66ba4 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -7144,7 +7144,7 @@ static int ath11k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ath11k_base *ab = ar->ab; ath11k_dbg(ab, ATH11K_DBG_MAC, - "chanctx add freq %u width %d ptr %pK\n", + "chanctx add freq %u width %d ptr %p\n", ctx->def.chan->center_freq, ctx->def.width, ctx); mutex_lock(&ar->conf_mutex); @@ -7168,7 +7168,7 @@ static void ath11k_mac_op_remove_chanctx(struct ieee80211_hw *hw, struct ath11k_base *ab = ar->ab; ath11k_dbg(ab, ATH11K_DBG_MAC, - "chanctx remove freq %u width %d ptr %pK\n", + "chanctx remove freq %u width %d ptr %p\n", ctx->def.chan->center_freq, ctx->def.width, ctx); mutex_lock(&ar->conf_mutex); @@ -7522,7 +7522,7 @@ static void ath11k_mac_op_change_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ath11k_dbg(ab, ATH11K_DBG_MAC, - "chanctx change freq %u width %d ptr %pK changed %x\n", + "chanctx change freq %u width %d ptr %p changed %x\n", ctx->def.chan->center_freq, ctx->def.width, ctx, changed); /* This shouldn't really happen because channel switching should use @@ -7603,7 +7603,7 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ath11k_dbg(ab, ATH11K_DBG_MAC, - "chanctx assign ptr %pK vdev_id %i\n", + "chanctx assign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); /* for QCA6390 bss peer must be created before vdev_start */ @@ -7693,7 +7693,7 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ath11k_dbg(ab, ATH11K_DBG_MAC, - "chanctx unassign ptr %pK vdev_id %i\n", + "chanctx unassign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); WARN_ON(!arvif->is_started); diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index ee67bfd90abe..79e2cbe82638 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -545,7 +545,7 @@ static int ath11k_pci_claim(struct ath11k_pci *ab_pci, struct pci_dev *pdev) ab->mem_ce = ab->mem; - ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci_mem 0x%pK\n", ab->mem); + ath11k_dbg(ab, ATH11K_DBG_BOOT, "pci_mem 0x%p\n", ab->mem); return 0; release_region: diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 17d565b03238..6dc2109557bc 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -6439,7 +6439,7 @@ static int ath11k_wmi_tlv_rssi_chain_parse(struct ath11k_base *ab, } ath11k_dbg(ab, ATH11K_DBG_WMI, - "stats bssid %pM vif %pK\n", + "stats bssid %pM vif %p\n", arvif->bssid, arvif->vif); sta = ieee80211_find_sta_by_ifaddr(ar->hw, @@ -7634,7 +7634,7 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) ath11k_mac_handle_beacon(ar, skb); ath11k_dbg(ab, ATH11K_DBG_MGMT, - "event mgmt rx skb %pK len %d ftype %02x stype %02x\n", + "event mgmt rx skb %p len %d ftype %02x stype %02x\n", skb, skb->len, fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); -- cgit v1.2.3 From 3512593884b3b3f10e1b42cb2fe3ca8c469a8f15 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:39 +0300 Subject: wifi: ath11k: htc: cleanup debug messages Cleanup HTC debug messages to follow the preferred style and try to make them more readable. Also add a few more and remove unnecessary. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-15-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/htc.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index deace873da85..2c2e425c8665 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -46,7 +46,6 @@ static struct sk_buff *ath11k_htc_build_tx_ctrl_skb(void *ab) skb_cb = ATH11K_SKB_CB(skb); memset(skb_cb, 0, sizeof(*skb_cb)); - ath11k_dbg(ab, ATH11K_DBG_HTC, "%s: skb %p\n", __func__, skb); return skb; } @@ -96,7 +95,7 @@ int ath11k_htc_send(struct ath11k_htc *htc, spin_lock_bh(&htc->tx_lock); if (ep->tx_credits < credits) { ath11k_dbg(ab, ATH11K_DBG_HTC, - "insufficient credits ep %d required %d available %d\n", + "ep %d insufficient credits required %d total %d\n", eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); ret = -EAGAIN; @@ -104,7 +103,7 @@ int ath11k_htc_send(struct ath11k_htc *htc, } ep->tx_credits -= credits; ath11k_dbg(ab, ATH11K_DBG_HTC, - "ep %d consumed %d credits (total %d)\n", + "ep %d credits consumed %d total %d\n", eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); } @@ -119,6 +118,9 @@ int ath11k_htc_send(struct ath11k_htc *htc, goto err_credits; } + ath11k_dbg(ab, ATH11K_DBG_HTC, "tx skb %p eid %d paddr %pad\n", + skb, skb_cb->eid, &skb_cb->paddr); + ret = ath11k_ce_send(htc->ab, skb, ep->ul_pipe_id, ep->eid); if (ret) goto err_unmap; @@ -132,7 +134,7 @@ err_credits: spin_lock_bh(&htc->tx_lock); ep->tx_credits += credits; ath11k_dbg(ab, ATH11K_DBG_HTC, - "ep %d reverted %d credits back (total %d)\n", + "ep %d credits reverted %d total %d\n", eid, credits, ep->tx_credits); spin_unlock_bh(&htc->tx_lock); @@ -167,7 +169,7 @@ ath11k_htc_process_credit_report(struct ath11k_htc *htc, ep = &htc->endpoint[report->eid]; ep->tx_credits += report->credits; - ath11k_dbg(ab, ATH11K_DBG_HTC, "ep %d got %d credits (total %d)\n", + ath11k_dbg(ab, ATH11K_DBG_HTC, "ep %d credits got %d total %d\n", report->eid, report->credits, ep->tx_credits); if (ep->ep_ops.ep_tx_credits) { @@ -287,7 +289,7 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, struct ath11k_htc_hdr *hdr; struct ath11k_htc_ep *ep; u16 payload_len; - u32 trailer_len = 0; + u32 message_id, trailer_len = 0; size_t min_len; u8 eid; bool trailer_present; @@ -322,6 +324,9 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, trailer_present = (FIELD_GET(HTC_HDR_FLAGS, hdr->htc_info)) & ATH11K_HTC_FLAG_TRAILER_PRESENT; + ath11k_dbg(ab, ATH11K_DBG_HTC, "rx ep %d skb %p trailer_present %d\n", + eid, skb, trailer_present); + if (trailer_present) { u8 *trailer; @@ -354,7 +359,12 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, if (eid == ATH11K_HTC_EP_0) { struct ath11k_htc_msg *msg = (struct ath11k_htc_msg *)skb->data; - switch (FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id)) { + message_id = FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id); + + ath11k_dbg(ab, ATH11K_DBG_HTC, "rx ep %d skb %p message_id %d\n", + eid, skb, message_id); + + switch (message_id) { case ATH11K_HTC_MSG_READY_ID: case ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID: /* handle HTC control message */ @@ -393,8 +403,6 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, goto out; } - ath11k_dbg(ab, ATH11K_DBG_HTC, "rx completion ep %d skb %p\n", - eid, skb); ep->ep_ops.ep_rx_complete(ab, skb); /* poll tx completion for interrupt disabled CE's */ @@ -564,7 +572,7 @@ int ath11k_htc_wait_target(struct ath11k_htc *htc) htc->target_credit_size = credit_size; ath11k_dbg(ab, ATH11K_DBG_HTC, - "Target ready! transmit resources: %d size:%d\n", + "target ready total_transmit_credits %d target_credit_size %d\n", htc->total_transmit_credits, htc->target_credit_size); if ((htc->total_transmit_credits == 0) || @@ -680,7 +688,7 @@ int ath11k_htc_connect_service(struct ath11k_htc *htc, } ath11k_dbg(ab, ATH11K_DBG_HTC, - "HTC Service %s connect response: status: 0x%lx, assigned ep: 0x%lx\n", + "service %s connect response status 0x%lx assigned ep 0x%lx\n", htc_service_name(service_id), FIELD_GET(HTC_SVC_RESP_MSG_STATUS, resp_msg->flags_len), FIELD_GET(HTC_SVC_RESP_MSG_ENDPOINTID, resp_msg->flags_len)); @@ -747,7 +755,7 @@ setup: if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) { ep->tx_credit_flow_enabled = false; ath11k_dbg(ab, ATH11K_DBG_BOOT, - "htc service '%s' eid %d TX flow control disabled\n", + "htc service '%s' eid %d tx flow control disabled\n", htc_service_name(ep->service_id), assigned_eid); } @@ -773,7 +781,7 @@ int ath11k_htc_start(struct ath11k_htc *htc) ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID); if (ab->hw_params.credit_flow) - ath11k_dbg(ab, ATH11K_DBG_HTC, "HTC is using TX credit flow control\n"); + ath11k_dbg(ab, ATH11K_DBG_HTC, "using tx credit flow control\n"); else msg->flags |= ATH11K_GLOBAL_DISABLE_CREDIT_FLOW; -- cgit v1.2.3 From 4f52ec65a9aef4755f46e613e6fbfb3333bbe3db Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 9 Jun 2023 17:24:40 +0300 Subject: wifi: ath11k: debug: add ATH11K_DBG_CE Add a new debug level for CE so that we don't need to use AHB level in ce.c. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23 Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230609142440.24643-16-kvalo@kernel.org --- drivers/net/wireless/ath/ath11k/ce.c | 4 ++-- drivers/net/wireless/ath/ath11k/debug.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index f2da95fd4253..289d47ae92af 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -442,7 +442,7 @@ static void ath11k_ce_recv_process_cb(struct ath11k_ce_pipe *pipe) } while ((skb = __skb_dequeue(&list))) { - ath11k_dbg(ab, ATH11K_DBG_AHB, "rx ce pipe %d len %d\n", + ath11k_dbg(ab, ATH11K_DBG_CE, "rx ce pipe %d len %d\n", pipe->pipe_num, skb->len); pipe->recv_cb(ab, skb); } @@ -520,7 +520,7 @@ static void ath11k_ce_tx_process_cb(struct ath11k_ce_pipe *pipe) } while ((skb = __skb_dequeue(&list))) { - ath11k_dbg(ab, ATH11K_DBG_AHB, "tx ce pipe %d len %d\n", + ath11k_dbg(ab, ATH11K_DBG_CE, "tx ce pipe %d len %d\n", pipe->pipe_num, skb->len); pipe->send_cb(ab, skb); } diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h index f0dddd188ef0..9c52804ef8ac 100644 --- a/drivers/net/wireless/ath/ath11k/debug.h +++ b/drivers/net/wireless/ath/ath11k/debug.h @@ -26,6 +26,7 @@ enum ath11k_debug_mask { ATH11K_DBG_PCI = 0x00001000, ATH11K_DBG_DP_TX = 0x00002000, ATH11K_DBG_DP_RX = 0x00004000, + ATH11K_DBG_CE = 0x00008000, }; static inline const char *ath11k_dbg_str(enum ath11k_debug_mask mask) @@ -61,6 +62,8 @@ static inline const char *ath11k_dbg_str(enum ath11k_debug_mask mask) return "dp_tx"; case ATH11K_DBG_DP_RX: return "dp_rx"; + case ATH11K_DBG_CE: + return "ce"; /* no default handler to allow compiler to check that the * enum is fully handled -- cgit v1.2.3 From 6aafa1c2d3e3fea2ebe84c018003f2a91722e607 Mon Sep 17 00:00:00 2001 From: P Praneesh Date: Tue, 6 Jun 2023 14:41:28 +0530 Subject: wifi: ath11k: fix memory leak in WMI firmware stats Memory allocated for firmware pdev, vdev and beacon statistics are not released during rmmod. Fix it by calling ath11k_fw_stats_free() function before hardware unregister. While at it, avoid calling ath11k_fw_stats_free() while processing the firmware stats received in the WMI event because the local list is getting spliced and reinitialised and hence there are no elements in the list after splicing. Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1 Signed-off-by: P Praneesh Signed-off-by: Aditya Kumar Singh Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230606091128.14202-1-quic_adisi@quicinc.com --- drivers/net/wireless/ath/ath11k/mac.c | 1 + drivers/net/wireless/ath/ath11k/wmi.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 32d958b66ba4..8c77ade49437 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -9792,6 +9792,7 @@ void ath11k_mac_destroy(struct ath11k_base *ab) if (!ar) continue; + ath11k_fw_stats_free(&ar->fw_stats); ieee80211_free_hw(ar->hw); pdev->ar = NULL; } diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 6dc2109557bc..23ad6825e5be 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -8198,6 +8198,11 @@ complete: rcu_read_unlock(); spin_unlock_bh(&ar->data_lock); + /* Since the stats's pdev, vdev and beacon list are spliced and reinitialised + * at this point, no need to free the individual list. + */ + return; + free: ath11k_fw_stats_free(&stats); } -- cgit v1.2.3 From 6b5f9a87e12d044f513a4f4c0e31ac7b5e988b66 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Mon, 12 Jun 2023 11:37:24 +0530 Subject: amd-xgbe: extend 10Mbps support to MAC version 21H MAC version 21H supports the 10Mbps speed. So, extend support to platforms that support it. Acked-by: Shyam Sundar S K Reviewed-by: Sridhar Samudrala Signed-off-by: Raju Rangoju Signed-off-by: David S. Miller --- drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index 16e7fb2c0dae..6a716337f48b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -2782,9 +2782,9 @@ static bool xgbe_phy_valid_speed_baset_mode(struct xgbe_prv_data *pdata, switch (speed) { case SPEED_10: - /* Supported in ver >= 30H */ + /* Supported in ver 21H and ver >= 30H */ ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); - return (ver >= 0x30) ? true : false; + return (ver == 0x21 || ver >= 0x30); case SPEED_100: case SPEED_1000: return true; @@ -2806,9 +2806,10 @@ static bool xgbe_phy_valid_speed_sfp_mode(struct xgbe_prv_data *pdata, switch (speed) { case SPEED_10: - /* Supported in ver >= 30H */ + /* Supported in ver 21H and ver >= 30H */ ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); - return (ver >= 0x30) && (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000); + return ((ver == 0x21 || ver >= 0x30) && + (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000)); case SPEED_100: return (phy_data->sfp_speed == XGBE_SFP_SPEED_100_1000); case SPEED_1000: @@ -3158,9 +3159,9 @@ static bool xgbe_phy_port_mode_mismatch(struct xgbe_prv_data *pdata) struct xgbe_phy_data *phy_data = pdata->phy_data; unsigned int ver; - /* 10 Mbps speed is not supported in ver < 30H */ + /* 10 Mbps speed is supported in ver 21H and ver >= 30H */ ver = XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER); - if (ver < 0x30 && (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10)) + if ((ver < 0x30 && ver != 0x21) && (phy_data->port_speeds & XGBE_PHY_PORT_SPEED_10)) return true; switch (phy_data->port_mode) { -- cgit v1.2.3 From 10c4d2a7b88d65471a5e56bb8946b5bb59ff5cf7 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 12 Jun 2023 08:59:19 -0700 Subject: tools: ynl-gen: correct enum policies Scalar range validation assumes enums start at 0. Teach it to properly calculate the value range. Reviewed-by: Jacob Keller Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 870f98d0e12c..54777d529f5e 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -300,8 +300,10 @@ class TypeScalar(Type): return f"NLA_POLICY_MIN({policy}, {self.checks['min']})" elif 'enum' in self.attr: enum = self.family.consts[self.attr['enum']] - cnt = len(enum['entries']) - return f"NLA_POLICY_MAX({policy}, {cnt - 1})" + low, high = enum.value_range() + if low == 0: + return f"NLA_POLICY_MAX({policy}, {high})" + return f"NLA_POLICY_RANGE({policy}, {low}, {high})" return super()._attr_policy(policy) def _attr_typol(self): @@ -676,6 +678,15 @@ class EnumSet(SpecEnumSet): def new_entry(self, entry, prev_entry, value_start): return EnumEntry(self, entry, prev_entry, value_start) + def value_range(self): + low = min([x.value for x in self.entries.values()]) + high = max([x.value for x in self.entries.values()]) + + if high - low + 1 != len(self.entries): + raise Exception("Can't get value range for a noncontiguous enum") + + return low, high + class AttrSet(SpecAttrSet): def __init__(self, family, yaml): -- cgit v1.2.3 From be093a80dff0982ba2d205f1ef302a3ace285fa3 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 12 Jun 2023 08:59:20 -0700 Subject: tools: ynl-gen: inherit policy in multi-attr Instead of reimplementing policies in MutliAttr for every underlying type forward the calls to the base type. This will be needed for DPLL which uses a multi-attr nest, and currently gets an invalid NLA_NEST policy generated. Reviewed-by: Jacob Keller Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-gen-c.py | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/tools/net/ynl/ynl-gen-c.py b/tools/net/ynl/ynl-gen-c.py index 54777d529f5e..71c5e79e877f 100755 --- a/tools/net/ynl/ynl-gen-c.py +++ b/tools/net/ynl/ynl-gen-c.py @@ -462,6 +462,11 @@ class TypeNest(Type): class TypeMultiAttr(Type): + def __init__(self, family, attr_set, attr, value, base_type): + super().__init__(family, attr_set, attr, value) + + self.base_type = base_type + def is_multi_val(self): return True @@ -497,13 +502,11 @@ class TypeMultiAttr(Type): else: raise Exception(f"Free of MultiAttr sub-type {self.attr['type']} not supported yet") + def _attr_policy(self, policy): + return self.base_type._attr_policy(policy) + def _attr_typol(self): - if 'type' not in self.attr or self.attr['type'] == 'nest': - return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' - elif self.attr['type'] in scalars: - return f".type = YNL_PT_U{self.attr['type'][1:]}, " - else: - raise Exception(f"Sub-type {self.attr['type']} not supported yet") + return self.base_type._attr_typol() def _attr_get(self, ri, var): return f'n_{self.c_name}++;', None, None @@ -717,29 +720,32 @@ class AttrSet(SpecAttrSet): self.c_name = '' def new_attr(self, elem, value): - if 'multi-attr' in elem and elem['multi-attr']: - return TypeMultiAttr(self.family, self, elem, value) - elif elem['type'] in scalars: - return TypeScalar(self.family, self, elem, value) + if elem['type'] in scalars: + t = TypeScalar(self.family, self, elem, value) elif elem['type'] == 'unused': - return TypeUnused(self.family, self, elem, value) + t = TypeUnused(self.family, self, elem, value) elif elem['type'] == 'pad': - return TypePad(self.family, self, elem, value) + t = TypePad(self.family, self, elem, value) elif elem['type'] == 'flag': - return TypeFlag(self.family, self, elem, value) + t = TypeFlag(self.family, self, elem, value) elif elem['type'] == 'string': - return TypeString(self.family, self, elem, value) + t = TypeString(self.family, self, elem, value) elif elem['type'] == 'binary': - return TypeBinary(self.family, self, elem, value) + t = TypeBinary(self.family, self, elem, value) elif elem['type'] == 'nest': - return TypeNest(self.family, self, elem, value) + t = TypeNest(self.family, self, elem, value) elif elem['type'] == 'array-nest': - return TypeArrayNest(self.family, self, elem, value) + t = TypeArrayNest(self.family, self, elem, value) elif elem['type'] == 'nest-type-value': - return TypeNestTypeValue(self.family, self, elem, value) + t = TypeNestTypeValue(self.family, self, elem, value) else: raise Exception(f"No typed class for type {elem['type']}") + if 'multi-attr' in elem and elem['multi-attr']: + t = TypeMultiAttr(self.family, self, elem, value, t) + + return t + class Operation(SpecOperation): def __init__(self, family, yaml, req_value, rsp_value): -- cgit v1.2.3 From 904e6ddf4133c52fdb9654c2cd2ad90f320d48b9 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Tue, 13 Jun 2023 18:38:21 +0300 Subject: bpf: Use scalar ids in mark_chain_precision() Change mark_chain_precision() to track precision in situations like below: r2 = unknown value ... --- state #0 --- ... r1 = r2 // r1 and r2 now share the same ID ... --- state #1 {r1.id = A, r2.id = A} --- ... if (r2 > 10) goto exit; // find_equal_scalars() assigns range to r1 ... --- state #2 {r1.id = A, r2.id = A} --- r3 = r10 r3 += r1 // need to mark both r1 and r2 At the beginning of the processing of each state, ensure that if a register with a scalar ID is marked as precise, all registers sharing this ID are also marked as precise. This property would be used by a follow-up change in regsafe(). Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230613153824.3324830-2-eddyz87@gmail.com --- include/linux/bpf_verifier.h | 10 ++- kernel/bpf/verifier.c | 115 +++++++++++++++++++++++++ tools/testing/selftests/bpf/verifier/precise.c | 8 +- 3 files changed, 128 insertions(+), 5 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 5b11a3b0fec0..22fb13c738a9 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -557,6 +557,11 @@ struct backtrack_state { u64 stack_masks[MAX_CALL_FRAMES]; }; +struct bpf_idset { + u32 count; + u32 ids[BPF_ID_MAP_SIZE]; +}; + /* single container for all structs * one verifier_env per bpf_check() call */ @@ -588,7 +593,10 @@ struct bpf_verifier_env { const struct bpf_line_info *prev_linfo; struct bpf_verifier_log log; struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; - struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE]; + union { + struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE]; + struct bpf_idset idset_scratch; + }; struct { int *insn_state; int *insn_stack; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 1e38584d497c..064aef5cd186 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3779,6 +3779,96 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_ } } +static bool idset_contains(struct bpf_idset *s, u32 id) +{ + u32 i; + + for (i = 0; i < s->count; ++i) + if (s->ids[i] == id) + return true; + + return false; +} + +static int idset_push(struct bpf_idset *s, u32 id) +{ + if (WARN_ON_ONCE(s->count >= ARRAY_SIZE(s->ids))) + return -EFAULT; + s->ids[s->count++] = id; + return 0; +} + +static void idset_reset(struct bpf_idset *s) +{ + s->count = 0; +} + +/* Collect a set of IDs for all registers currently marked as precise in env->bt. + * Mark all registers with these IDs as precise. + */ +static int mark_precise_scalar_ids(struct bpf_verifier_env *env, struct bpf_verifier_state *st) +{ + struct bpf_idset *precise_ids = &env->idset_scratch; + struct backtrack_state *bt = &env->bt; + struct bpf_func_state *func; + struct bpf_reg_state *reg; + DECLARE_BITMAP(mask, 64); + int i, fr; + + idset_reset(precise_ids); + + for (fr = bt->frame; fr >= 0; fr--) { + func = st->frame[fr]; + + bitmap_from_u64(mask, bt_frame_reg_mask(bt, fr)); + for_each_set_bit(i, mask, 32) { + reg = &func->regs[i]; + if (!reg->id || reg->type != SCALAR_VALUE) + continue; + if (idset_push(precise_ids, reg->id)) + return -EFAULT; + } + + bitmap_from_u64(mask, bt_frame_stack_mask(bt, fr)); + for_each_set_bit(i, mask, 64) { + if (i >= func->allocated_stack / BPF_REG_SIZE) + break; + if (!is_spilled_scalar_reg(&func->stack[i])) + continue; + reg = &func->stack[i].spilled_ptr; + if (!reg->id) + continue; + if (idset_push(precise_ids, reg->id)) + return -EFAULT; + } + } + + for (fr = 0; fr <= st->curframe; ++fr) { + func = st->frame[fr]; + + for (i = BPF_REG_0; i < BPF_REG_10; ++i) { + reg = &func->regs[i]; + if (!reg->id) + continue; + if (!idset_contains(precise_ids, reg->id)) + continue; + bt_set_frame_reg(bt, fr, i); + } + for (i = 0; i < func->allocated_stack / BPF_REG_SIZE; ++i) { + if (!is_spilled_scalar_reg(&func->stack[i])) + continue; + reg = &func->stack[i].spilled_ptr; + if (!reg->id) + continue; + if (!idset_contains(precise_ids, reg->id)) + continue; + bt_set_frame_slot(bt, fr, i); + } + } + + return 0; +} + /* * __mark_chain_precision() backtracks BPF program instruction sequence and * chain of verifier states making sure that register *regno* (if regno >= 0) @@ -3910,6 +4000,31 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno) bt->frame, last_idx, first_idx, subseq_idx); } + /* If some register with scalar ID is marked as precise, + * make sure that all registers sharing this ID are also precise. + * This is needed to estimate effect of find_equal_scalars(). + * Do this at the last instruction of each state, + * bpf_reg_state::id fields are valid for these instructions. + * + * Allows to track precision in situation like below: + * + * r2 = unknown value + * ... + * --- state #0 --- + * ... + * r1 = r2 // r1 and r2 now share the same ID + * ... + * --- state #1 {r1.id = A, r2.id = A} --- + * ... + * if (r2 > 10) goto exit; // find_equal_scalars() assigns range to r1 + * ... + * --- state #2 {r1.id = A, r2.id = A} --- + * r3 = r10 + * r3 += r1 // need to mark both r1 and r2 + */ + if (mark_precise_scalar_ids(env, st)) + return -EFAULT; + if (last_idx < 0) { /* we are at the entry into subprog, which * is expected for global funcs, but only if diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c index b8c0aae8e7ec..99272bb890da 100644 --- a/tools/testing/selftests/bpf/verifier/precise.c +++ b/tools/testing/selftests/bpf/verifier/precise.c @@ -46,7 +46,7 @@ mark_precise: frame0: regs=r2 stack= before 20\ mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 19 first_idx 10\ - mark_precise: frame0: regs=r2 stack= before 19\ + mark_precise: frame0: regs=r2,r9 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\ mark_precise: frame0: regs=r8,r9 stack= before 17\ mark_precise: frame0: regs=r0,r9 stack= before 15\ @@ -106,10 +106,10 @@ mark_precise: frame0: regs=r2 stack= before 22\ mark_precise: frame0: parent state regs=r2 stack=:\ mark_precise: frame0: last_idx 20 first_idx 20\ - mark_precise: frame0: regs=r2 stack= before 20\ - mark_precise: frame0: parent state regs=r2 stack=:\ + mark_precise: frame0: regs=r2,r9 stack= before 20\ + mark_precise: frame0: parent state regs=r2,r9 stack=:\ mark_precise: frame0: last_idx 19 first_idx 17\ - mark_precise: frame0: regs=r2 stack= before 19\ + mark_precise: frame0: regs=r2,r9 stack= before 19\ mark_precise: frame0: regs=r9 stack= before 18\ mark_precise: frame0: regs=r8,r9 stack= before 17\ mark_precise: frame0: parent state regs= stack=:", -- cgit v1.2.3 From dec020280373c60d6df48d1954e72dd6c5640282 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Tue, 13 Jun 2023 18:38:22 +0300 Subject: selftests/bpf: Check if mark_chain_precision() follows scalar ids Check __mark_chain_precision() log to verify that scalars with same IDs are marked as precise. Use several scenarios to test that precision marks are propagated through: - registers of scalar type with the same ID within one state; - registers of scalar type with the same ID cross several states; - registers of scalar type with the same ID cross several stack frames; - stack slot of scalar type with the same ID; - multiple scalar IDs are tracked independently. Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230613153824.3324830-3-eddyz87@gmail.com --- tools/testing/selftests/bpf/prog_tests/verifier.c | 2 + .../selftests/bpf/progs/verifier_scalar_ids.c | 344 +++++++++++++++++++++ 2 files changed, 346 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/verifier_scalar_ids.c diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c index 531621adef42..070a13833c3f 100644 --- a/tools/testing/selftests/bpf/prog_tests/verifier.c +++ b/tools/testing/selftests/bpf/prog_tests/verifier.c @@ -50,6 +50,7 @@ #include "verifier_regalloc.skel.h" #include "verifier_ringbuf.skel.h" #include "verifier_runtime_jit.skel.h" +#include "verifier_scalar_ids.skel.h" #include "verifier_search_pruning.skel.h" #include "verifier_sock.skel.h" #include "verifier_spill_fill.skel.h" @@ -150,6 +151,7 @@ void test_verifier_ref_tracking(void) { RUN(verifier_ref_tracking); } void test_verifier_regalloc(void) { RUN(verifier_regalloc); } void test_verifier_ringbuf(void) { RUN(verifier_ringbuf); } void test_verifier_runtime_jit(void) { RUN(verifier_runtime_jit); } +void test_verifier_scalar_ids(void) { RUN(verifier_scalar_ids); } void test_verifier_search_pruning(void) { RUN(verifier_search_pruning); } void test_verifier_sock(void) { RUN(verifier_sock); } void test_verifier_spill_fill(void) { RUN(verifier_spill_fill); } diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c new file mode 100644 index 000000000000..8a5203fb14ca --- /dev/null +++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include "bpf_misc.h" + +/* Check that precision marks propagate through scalar IDs. + * Registers r{0,1,2} have the same scalar ID at the moment when r0 is + * marked to be precise, this mark is immediately propagated to r{1,2}. + */ +SEC("socket") +__success __log_level(2) +__msg("frame0: regs=r0,r1,r2 stack= before 4: (bf) r3 = r10") +__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_same_state(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" + /* force r0 to be precise, this immediately marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Same as precision_same_state, but mark propagates through state / + * parent state boundary. + */ +SEC("socket") +__success __log_level(2) +__msg("frame0: last_idx 6 first_idx 5 subseq_idx -1") +__msg("frame0: regs=r0,r1,r2 stack= before 5: (bf) r3 = r10") +__msg("frame0: parent state regs=r0,r1,r2 stack=:") +__msg("frame0: regs=r0,r1,r2 stack= before 4: (05) goto pc+0") +__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__msg("frame0: parent state regs=r0 stack=:") +__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_cross_state(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" + /* force checkpoint */ + "goto +0;" + /* force r0 to be precise, this immediately marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Same as precision_same_state, but break one of the + * links, note that r1 is absent from regs=... in __msg below. + */ +SEC("socket") +__success __log_level(2) +__msg("frame0: regs=r0,r2 stack= before 5: (bf) r3 = r10") +__msg("frame0: regs=r0,r2 stack= before 4: (b7) r1 = 0") +__msg("frame0: regs=r0,r2 stack= before 3: (bf) r2 = r0") +__msg("frame0: regs=r0 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_same_state_broken_link(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" + /* break link for r1, this is the only line that differs + * compared to the previous test + */ + "r1 = 0;" + /* force r0 to be precise, this immediately marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Same as precision_same_state_broken_link, but with state / + * parent state boundary. + */ +SEC("socket") +__success __log_level(2) +__msg("frame0: regs=r0,r2 stack= before 6: (bf) r3 = r10") +__msg("frame0: regs=r0,r2 stack= before 5: (b7) r1 = 0") +__msg("frame0: parent state regs=r0,r2 stack=:") +__msg("frame0: regs=r0,r1,r2 stack= before 4: (05) goto pc+0") +__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__msg("frame0: parent state regs=r0 stack=:") +__msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_cross_state_broken_link(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r2.id */ + "r1 = r0;" + "r2 = r0;" + /* force checkpoint, although link between r1 and r{0,2} is + * broken by the next statement current precision tracking + * algorithm can't react to it and propagates mark for r1 to + * the parent state. + */ + "goto +0;" + /* break link for r1, this is the only line that differs + * compared to precision_cross_state() + */ + "r1 = 0;" + /* force r0 to be precise, this immediately marks r1 and r2 as + * precise as well because of shared IDs + */ + "r3 = r10;" + "r3 += r0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that precision marks propagate through scalar IDs. + * Use the same scalar ID in multiple stack frames, check that + * precision information is propagated up the call stack. + */ +SEC("socket") +__success __log_level(2) +__msg("11: (0f) r2 += r1") +/* Current state */ +__msg("frame2: last_idx 11 first_idx 10 subseq_idx -1") +__msg("frame2: regs=r1 stack= before 10: (bf) r2 = r10") +__msg("frame2: parent state regs=r1 stack=") +/* frame1.r{6,7} are marked because mark_precise_scalar_ids() + * looks for all registers with frame2.r1.id in the current state + */ +__msg("frame1: parent state regs=r6,r7 stack=") +__msg("frame0: parent state regs=r6 stack=") +/* Parent state */ +__msg("frame2: last_idx 8 first_idx 8 subseq_idx 10") +__msg("frame2: regs=r1 stack= before 8: (85) call pc+1") +/* frame1.r1 is marked because of backtracking of call instruction */ +__msg("frame1: parent state regs=r1,r6,r7 stack=") +__msg("frame0: parent state regs=r6 stack=") +/* Parent state */ +__msg("frame1: last_idx 7 first_idx 6 subseq_idx 8") +__msg("frame1: regs=r1,r6,r7 stack= before 7: (bf) r7 = r1") +__msg("frame1: regs=r1,r6 stack= before 6: (bf) r6 = r1") +__msg("frame1: parent state regs=r1 stack=") +__msg("frame0: parent state regs=r6 stack=") +/* Parent state */ +__msg("frame1: last_idx 4 first_idx 4 subseq_idx 6") +__msg("frame1: regs=r1 stack= before 4: (85) call pc+1") +__msg("frame0: parent state regs=r1,r6 stack=") +/* Parent state */ +__msg("frame0: last_idx 3 first_idx 1 subseq_idx 4") +__msg("frame0: regs=r0,r1,r6 stack= before 3: (bf) r6 = r0") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_many_frames(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == r6.id */ + "r1 = r0;" + "r6 = r0;" + "call precision_many_frames__foo;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +static __naked __noinline __used +void precision_many_frames__foo(void) +{ + asm volatile ( + /* conflate one of the register numbers (r6) with outer frame, + * to verify that those are tracked independently + */ + "r6 = r1;" + "r7 = r1;" + "call precision_many_frames__bar;" + "exit" + ::: __clobber_all); +} + +static __naked __noinline __used +void precision_many_frames__bar(void) +{ + asm volatile ( + /* force r1 to be precise, this immediately marks: + * - bar frame r1 + * - foo frame r{1,6,7} + * - main frame r{1,6} + */ + "r2 = r10;" + "r2 += r1;" + "r0 = 0;" + "exit;" + ::: __clobber_all); +} + +/* Check that scalars with the same IDs are marked precise on stack as + * well as in registers. + */ +SEC("socket") +__success __log_level(2) +/* foo frame */ +__msg("frame1: regs=r1 stack=-8,-16 before 9: (bf) r2 = r10") +__msg("frame1: regs=r1 stack=-8,-16 before 8: (7b) *(u64 *)(r10 -16) = r1") +__msg("frame1: regs=r1 stack=-8 before 7: (7b) *(u64 *)(r10 -8) = r1") +__msg("frame1: regs=r1 stack= before 4: (85) call pc+2") +/* main frame */ +__msg("frame0: regs=r0,r1 stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r1") +__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") +__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_stack(void) +{ + asm volatile ( + /* r0 = random number up to 0xff */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* tie r0.id == r1.id == fp[-8].id */ + "r1 = r0;" + "*(u64*)(r10 - 8) = r1;" + "call precision_stack__foo;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +static __naked __noinline __used +void precision_stack__foo(void) +{ + asm volatile ( + /* conflate one of the register numbers (r6) with outer frame, + * to verify that those are tracked independently + */ + "*(u64*)(r10 - 8) = r1;" + "*(u64*)(r10 - 16) = r1;" + /* force r1 to be precise, this immediately marks: + * - foo frame r1,fp{-8,-16} + * - main frame r1,fp{-8} + */ + "r2 = r10;" + "r2 += r1;" + "exit" + ::: __clobber_all); +} + +/* Use two separate scalar IDs to check that these are propagated + * independently. + */ +SEC("socket") +__success __log_level(2) +/* r{6,7} */ +__msg("11: (0f) r3 += r7") +__msg("frame0: regs=r6,r7 stack= before 10: (bf) r3 = r10") +/* ... skip some insns ... */ +__msg("frame0: regs=r6,r7 stack= before 3: (bf) r7 = r0") +__msg("frame0: regs=r0,r6 stack= before 2: (bf) r6 = r0") +/* r{8,9} */ +__msg("12: (0f) r3 += r9") +__msg("frame0: regs=r8,r9 stack= before 11: (0f) r3 += r7") +/* ... skip some insns ... */ +__msg("frame0: regs=r8,r9 stack= before 7: (bf) r9 = r0") +__msg("frame0: regs=r0,r8 stack= before 6: (bf) r8 = r0") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void precision_two_ids(void) +{ + asm volatile ( + /* r6 = random number up to 0xff + * r6.id == r7.id + */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r6 = r0;" + "r7 = r0;" + /* same, but for r{8,9} */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r8 = r0;" + "r9 = r0;" + /* clear r0 id */ + "r0 = 0;" + /* force checkpoint */ + "goto +0;" + "r3 = r10;" + /* force r7 to be precise, this also marks r6 */ + "r3 += r7;" + /* force r9 to be precise, this also marks r8 */ + "r3 += r9;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 1ffc85d9298e0ca0137ba65c93a786143fe167b8 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Tue, 13 Jun 2023 18:38:23 +0300 Subject: bpf: Verify scalar ids mapping in regsafe() using check_ids() Make sure that the following unsafe example is rejected by verifier: 1: r9 = ... some pointer with range X ... 2: r6 = ... unbound scalar ID=a ... 3: r7 = ... unbound scalar ID=b ... 4: if (r6 > r7) goto +1 5: r6 = r7 6: if (r6 > X) goto ... --- checkpoint --- 7: r9 += r7 8: *(u64 *)r9 = Y This example is unsafe because not all execution paths verify r7 range. Because of the jump at (4) the verifier would arrive at (6) in two states: I. r6{.id=b}, r7{.id=b} via path 1-6; II. r6{.id=a}, r7{.id=b} via path 1-4, 6. Currently regsafe() does not call check_ids() for scalar registers, thus from POV of regsafe() states (I) and (II) are identical. If the path 1-6 is taken by verifier first, and checkpoint is created at (6) the path [1-4, 6] would be considered safe. Changes in this commit: - check_ids() is modified to disallow mapping multiple old_id to the same cur_id. - check_scalar_ids() is added, unlike check_ids() it treats ID zero as a unique scalar ID. - check_scalar_ids() needs to generate temporary unique IDs, field 'tmp_id_gen' is added to bpf_verifier_env::idmap_scratch to facilitate this. - regsafe() is updated to: - use check_scalar_ids() for precise scalar registers. - compare scalar registers using memcmp only for explore_alu_limits branch. This simplifies control flow for scalar case, and has no measurable performance impact. - check_alu_op() is updated to avoid generating bpf_reg_state::id for constant scalar values when processing BPF_MOV. ID is needed to propagate range information for identical values, but there is nothing to propagate for constants. Fixes: 75748837b7e5 ("bpf: Propagate scalar ranges through register assignments.") Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230613153824.3324830-4-eddyz87@gmail.com --- include/linux/bpf_verifier.h | 17 ++++++--- kernel/bpf/verifier.c | 91 +++++++++++++++++++++++++++++++++----------- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 22fb13c738a9..f70f9ac884d2 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -313,11 +313,6 @@ struct bpf_idx_pair { u32 idx; }; -struct bpf_id_pair { - u32 old; - u32 cur; -}; - #define MAX_CALL_FRAMES 8 /* Maximum number of register states that can exist at once */ #define BPF_ID_MAP_SIZE ((MAX_BPF_REG + MAX_BPF_STACK / BPF_REG_SIZE) * MAX_CALL_FRAMES) @@ -557,6 +552,16 @@ struct backtrack_state { u64 stack_masks[MAX_CALL_FRAMES]; }; +struct bpf_id_pair { + u32 old; + u32 cur; +}; + +struct bpf_idmap { + u32 tmp_id_gen; + struct bpf_id_pair map[BPF_ID_MAP_SIZE]; +}; + struct bpf_idset { u32 count; u32 ids[BPF_ID_MAP_SIZE]; @@ -594,7 +599,7 @@ struct bpf_verifier_env { struct bpf_verifier_log log; struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; union { - struct bpf_id_pair idmap_scratch[BPF_ID_MAP_SIZE]; + struct bpf_idmap idmap_scratch; struct bpf_idset idset_scratch; }; struct { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 064aef5cd186..fa43dc8e85b9 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -12934,12 +12934,14 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) if (BPF_SRC(insn->code) == BPF_X) { struct bpf_reg_state *src_reg = regs + insn->src_reg; struct bpf_reg_state *dst_reg = regs + insn->dst_reg; + bool need_id = src_reg->type == SCALAR_VALUE && !src_reg->id && + !tnum_is_const(src_reg->var_off); if (BPF_CLASS(insn->code) == BPF_ALU64) { /* case: R1 = R2 * copy register state to dest reg */ - if (src_reg->type == SCALAR_VALUE && !src_reg->id) + if (need_id) /* Assign src and dst registers the same ID * that will be used by find_equal_scalars() * to propagate min/max range. @@ -12958,7 +12960,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn) } else if (src_reg->type == SCALAR_VALUE) { bool is_src_reg_u32 = src_reg->umax_value <= U32_MAX; - if (is_src_reg_u32 && !src_reg->id) + if (is_src_reg_u32 && need_id) src_reg->id = ++env->id_gen; copy_register_state(dst_reg, src_reg); /* Make sure ID is cleared if src_reg is not in u32 range otherwise @@ -15114,8 +15116,9 @@ static bool range_within(struct bpf_reg_state *old, * So we look through our idmap to see if this old id has been seen before. If * so, we require the new id to match; otherwise, we add the id pair to the map. */ -static bool check_ids(u32 old_id, u32 cur_id, struct bpf_id_pair *idmap) +static bool check_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) { + struct bpf_id_pair *map = idmap->map; unsigned int i; /* either both IDs should be set or both should be zero */ @@ -15126,20 +15129,34 @@ static bool check_ids(u32 old_id, u32 cur_id, struct bpf_id_pair *idmap) return true; for (i = 0; i < BPF_ID_MAP_SIZE; i++) { - if (!idmap[i].old) { + if (!map[i].old) { /* Reached an empty slot; haven't seen this id before */ - idmap[i].old = old_id; - idmap[i].cur = cur_id; + map[i].old = old_id; + map[i].cur = cur_id; return true; } - if (idmap[i].old == old_id) - return idmap[i].cur == cur_id; + if (map[i].old == old_id) + return map[i].cur == cur_id; + if (map[i].cur == cur_id) + return false; } /* We ran out of idmap slots, which should be impossible */ WARN_ON_ONCE(1); return false; } +/* Similar to check_ids(), but allocate a unique temporary ID + * for 'old_id' or 'cur_id' of zero. + * This makes pairs like '0 vs unique ID', 'unique ID vs 0' valid. + */ +static bool check_scalar_ids(u32 old_id, u32 cur_id, struct bpf_idmap *idmap) +{ + old_id = old_id ? old_id : ++idmap->tmp_id_gen; + cur_id = cur_id ? cur_id : ++idmap->tmp_id_gen; + + return check_ids(old_id, cur_id, idmap); +} + static void clean_func_state(struct bpf_verifier_env *env, struct bpf_func_state *st) { @@ -15238,7 +15255,7 @@ next: static bool regs_exact(const struct bpf_reg_state *rold, const struct bpf_reg_state *rcur, - struct bpf_id_pair *idmap) + struct bpf_idmap *idmap) { return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 && check_ids(rold->id, rcur->id, idmap) && @@ -15247,7 +15264,7 @@ static bool regs_exact(const struct bpf_reg_state *rold, /* Returns true if (rold safe implies rcur safe) */ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, - struct bpf_reg_state *rcur, struct bpf_id_pair *idmap) + struct bpf_reg_state *rcur, struct bpf_idmap *idmap) { if (!(rold->live & REG_LIVE_READ)) /* explored state didn't use this */ @@ -15284,15 +15301,42 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, switch (base_type(rold->type)) { case SCALAR_VALUE: - if (regs_exact(rold, rcur, idmap)) - return true; - if (env->explore_alu_limits) - return false; + if (env->explore_alu_limits) { + /* explore_alu_limits disables tnum_in() and range_within() + * logic and requires everything to be strict + */ + return memcmp(rold, rcur, offsetof(struct bpf_reg_state, id)) == 0 && + check_scalar_ids(rold->id, rcur->id, idmap); + } if (!rold->precise) return true; - /* new val must satisfy old val knowledge */ + /* Why check_ids() for scalar registers? + * + * Consider the following BPF code: + * 1: r6 = ... unbound scalar, ID=a ... + * 2: r7 = ... unbound scalar, ID=b ... + * 3: if (r6 > r7) goto +1 + * 4: r6 = r7 + * 5: if (r6 > X) goto ... + * 6: ... memory operation using r7 ... + * + * First verification path is [1-6]: + * - at (4) same bpf_reg_state::id (b) would be assigned to r6 and r7; + * - at (5) r6 would be marked <= X, find_equal_scalars() would also mark + * r7 <= X, because r6 and r7 share same id. + * Next verification path is [1-4, 6]. + * + * Instruction (6) would be reached in two states: + * I. r6{.id=b}, r7{.id=b} via path 1-6; + * II. r6{.id=a}, r7{.id=b} via path 1-4, 6. + * + * Use check_ids() to distinguish these states. + * --- + * Also verify that new value satisfies old value range knowledge. + */ return range_within(rold, rcur) && - tnum_in(rold->var_off, rcur->var_off); + tnum_in(rold->var_off, rcur->var_off) && + check_scalar_ids(rold->id, rcur->id, idmap); case PTR_TO_MAP_KEY: case PTR_TO_MAP_VALUE: case PTR_TO_MEM: @@ -15338,7 +15382,7 @@ static bool regsafe(struct bpf_verifier_env *env, struct bpf_reg_state *rold, } static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, - struct bpf_func_state *cur, struct bpf_id_pair *idmap) + struct bpf_func_state *cur, struct bpf_idmap *idmap) { int i, spi; @@ -15441,7 +15485,7 @@ static bool stacksafe(struct bpf_verifier_env *env, struct bpf_func_state *old, } static bool refsafe(struct bpf_func_state *old, struct bpf_func_state *cur, - struct bpf_id_pair *idmap) + struct bpf_idmap *idmap) { int i; @@ -15489,13 +15533,13 @@ static bool func_states_equal(struct bpf_verifier_env *env, struct bpf_func_stat for (i = 0; i < MAX_BPF_REG; i++) if (!regsafe(env, &old->regs[i], &cur->regs[i], - env->idmap_scratch)) + &env->idmap_scratch)) return false; - if (!stacksafe(env, old, cur, env->idmap_scratch)) + if (!stacksafe(env, old, cur, &env->idmap_scratch)) return false; - if (!refsafe(old, cur, env->idmap_scratch)) + if (!refsafe(old, cur, &env->idmap_scratch)) return false; return true; @@ -15510,7 +15554,8 @@ static bool states_equal(struct bpf_verifier_env *env, if (old->curframe != cur->curframe) return false; - memset(env->idmap_scratch, 0, sizeof(env->idmap_scratch)); + env->idmap_scratch.tmp_id_gen = env->id_gen; + memset(&env->idmap_scratch.map, 0, sizeof(env->idmap_scratch.map)); /* Verification state from speculative execution simulation * must never prune a non-speculative execution one. @@ -15528,7 +15573,7 @@ static bool states_equal(struct bpf_verifier_env *env, return false; if (old->active_lock.id && - !check_ids(old->active_lock.id, cur->active_lock.id, env->idmap_scratch)) + !check_ids(old->active_lock.id, cur->active_lock.id, &env->idmap_scratch)) return false; if (old->active_rcu_lock != cur->active_rcu_lock) -- cgit v1.2.3 From 18b89265572b5c899522b6c1f8698e87edfad369 Mon Sep 17 00:00:00 2001 From: Eduard Zingerman Date: Tue, 13 Jun 2023 18:38:24 +0300 Subject: selftests/bpf: Verify that check_ids() is used for scalars in regsafe() Verify that the following example is rejected by verifier: r9 = ... some pointer with range X ... r6 = ... unbound scalar ID=a ... r7 = ... unbound scalar ID=b ... if (r6 > r7) goto +1 r7 = r6 if (r7 > X) goto exit r9 += r6 *(u64 *)r9 = Y Also add test cases to: - check that check_alu_op() for BPF_MOV instruction does not allocate scalar ID if source register is a constant; - check that unique scalar IDs are ignored when new verifier state is compared to cached verifier state; - check that two different scalar IDs in a verified state can't be mapped to the same scalar ID in current state. Signed-off-by: Eduard Zingerman Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230613153824.3324830-5-eddyz87@gmail.com --- .../selftests/bpf/progs/verifier_scalar_ids.c | 315 +++++++++++++++++++++ 1 file changed, 315 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c index 8a5203fb14ca..13b29a7faa71 100644 --- a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c +++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c @@ -341,4 +341,319 @@ __naked void precision_two_ids(void) : __clobber_all); } +/* Verify that check_ids() is used by regsafe() for scalars. + * + * r9 = ... some pointer with range X ... + * r6 = ... unbound scalar ID=a ... + * r7 = ... unbound scalar ID=b ... + * if (r6 > r7) goto +1 + * r7 = r6 + * if (r7 > X) goto exit + * r9 += r6 + * ... access memory using r9 ... + * + * The memory access is safe only if r7 is bounded, + * which is true for one branch and not true for another. + */ +SEC("socket") +__failure __msg("register with unbounded min value") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void check_ids_in_regsafe(void) +{ + asm volatile ( + /* Bump allocated stack */ + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + /* r9 = pointer to stack */ + "r9 = r10;" + "r9 += -8;" + /* r7 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r7 = r0;" + /* r6 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r6 = r0;" + /* if r6 > r7 is an unpredictable jump */ + "if r6 > r7 goto l1_%=;" + "r7 = r6;" +"l1_%=:" + /* if r7 > 4 ...; transfers range to r6 on one execution path + * but does not transfer on another + */ + "if r7 > 4 goto l2_%=;" + /* Access memory at r9[r6], r6 is not always bounded */ + "r9 += r6;" + "r0 = *(u8*)(r9 + 0);" +"l2_%=:" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Similar to check_ids_in_regsafe. + * The l0 could be reached in two states: + * + * (1) r6{.id=A}, r7{.id=A}, r8{.id=B} + * (2) r6{.id=B}, r7{.id=A}, r8{.id=B} + * + * Where (2) is not safe, as "r7 > 4" check won't propagate range for it. + * This example would be considered safe without changes to + * mark_chain_precision() to track scalar values with equal IDs. + */ +SEC("socket") +__failure __msg("register with unbounded min value") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void check_ids_in_regsafe_2(void) +{ + asm volatile ( + /* Bump allocated stack */ + "r1 = 0;" + "*(u64*)(r10 - 8) = r1;" + /* r9 = pointer to stack */ + "r9 = r10;" + "r9 += -8;" + /* r8 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r8 = r0;" + /* r7 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r7 = r0;" + /* r6 = ktime_get_ns() */ + "call %[bpf_ktime_get_ns];" + "r6 = r0;" + /* scratch .id from r0 */ + "r0 = 0;" + /* if r6 > r7 is an unpredictable jump */ + "if r6 > r7 goto l1_%=;" + /* tie r6 and r7 .id */ + "r6 = r7;" +"l0_%=:" + /* if r7 > 4 exit(0) */ + "if r7 > 4 goto l2_%=;" + /* Access memory at r9[r6] */ + "r9 += r6;" + "r0 = *(u8*)(r9 + 0);" +"l2_%=:" + "r0 = 0;" + "exit;" +"l1_%=:" + /* tie r6 and r8 .id */ + "r6 = r8;" + "goto l0_%=;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that scalar IDs *are not* generated on register to register + * assignments if source register is a constant. + * + * If such IDs *are* generated the 'l1' below would be reached in + * two states: + * + * (1) r1{.id=A}, r2{.id=A} + * (2) r1{.id=C}, r2{.id=C} + * + * Thus forcing 'if r1 == r2' verification twice. + */ +SEC("socket") +__success __log_level(2) +__msg("11: (1d) if r3 == r4 goto pc+0") +__msg("frame 0: propagating r3,r4") +__msg("11: safe") +__msg("processed 15 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void no_scalar_id_for_const(void) +{ + asm volatile ( + "call %[bpf_ktime_get_ns];" + /* unpredictable jump */ + "if r0 > 7 goto l0_%=;" + /* possibly generate same scalar ids for r3 and r4 */ + "r1 = 0;" + "r1 = r1;" + "r3 = r1;" + "r4 = r1;" + "goto l1_%=;" +"l0_%=:" + /* possibly generate different scalar ids for r3 and r4 */ + "r1 = 0;" + "r2 = 0;" + "r3 = r1;" + "r4 = r2;" +"l1_%=:" + /* predictable jump, marks r3 and r4 precise */ + "if r3 == r4 goto +0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Same as no_scalar_id_for_const() but for 32-bit values */ +SEC("socket") +__success __log_level(2) +__msg("11: (1e) if w3 == w4 goto pc+0") +__msg("frame 0: propagating r3,r4") +__msg("11: safe") +__msg("processed 15 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void no_scalar_id_for_const32(void) +{ + asm volatile ( + "call %[bpf_ktime_get_ns];" + /* unpredictable jump */ + "if r0 > 7 goto l0_%=;" + /* possibly generate same scalar ids for r3 and r4 */ + "w1 = 0;" + "w1 = w1;" + "w3 = w1;" + "w4 = w1;" + "goto l1_%=;" +"l0_%=:" + /* possibly generate different scalar ids for r3 and r4 */ + "w1 = 0;" + "w2 = 0;" + "w3 = w1;" + "w4 = w2;" +"l1_%=:" + /* predictable jump, marks r1 and r2 precise */ + "if w3 == w4 goto +0;" + "r0 = 0;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that unique scalar IDs are ignored when new verifier state is + * compared to cached verifier state. For this test: + * - cached state has no id on r1 + * - new state has a unique id on r1 + */ +SEC("socket") +__success __log_level(2) +__msg("6: (25) if r6 > 0x7 goto pc+1") +__msg("7: (57) r1 &= 255") +__msg("8: (bf) r2 = r10") +__msg("from 6 to 8: safe") +__msg("processed 12 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void ignore_unique_scalar_ids_cur(void) +{ + asm volatile ( + "call %[bpf_ktime_get_ns];" + "r6 = r0;" + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* r1.id == r0.id */ + "r1 = r0;" + /* make r1.id unique */ + "r0 = 0;" + "if r6 > 7 goto l0_%=;" + /* clear r1 id, but keep the range compatible */ + "r1 &= 0xff;" +"l0_%=:" + /* get here in two states: + * - first: r1 has no id (cached state) + * - second: r1 has a unique id (should be considered equivalent) + */ + "r2 = r10;" + "r2 += r1;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that unique scalar IDs are ignored when new verifier state is + * compared to cached verifier state. For this test: + * - cached state has a unique id on r1 + * - new state has no id on r1 + */ +SEC("socket") +__success __log_level(2) +__msg("6: (25) if r6 > 0x7 goto pc+1") +__msg("7: (05) goto pc+1") +__msg("9: (bf) r2 = r10") +__msg("9: safe") +__msg("processed 13 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void ignore_unique_scalar_ids_old(void) +{ + asm volatile ( + "call %[bpf_ktime_get_ns];" + "r6 = r0;" + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + /* r1.id == r0.id */ + "r1 = r0;" + /* make r1.id unique */ + "r0 = 0;" + "if r6 > 7 goto l1_%=;" + "goto l0_%=;" +"l1_%=:" + /* clear r1 id, but keep the range compatible */ + "r1 &= 0xff;" +"l0_%=:" + /* get here in two states: + * - first: r1 has a unique id (cached state) + * - second: r1 has no id (should be considered equivalent) + */ + "r2 = r10;" + "r2 += r1;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + +/* Check that two different scalar IDs in a verified state can't be + * mapped to the same scalar ID in current state. + */ +SEC("socket") +__success __log_level(2) +/* The exit instruction should be reachable from two states, + * use two matches and "processed .. insns" to ensure this. + */ +__msg("13: (95) exit") +__msg("13: (95) exit") +__msg("processed 18 insns") +__flag(BPF_F_TEST_STATE_FREQ) +__naked void two_old_ids_one_cur_id(void) +{ + asm volatile ( + /* Give unique scalar IDs to r{6,7} */ + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r6 = r0;" + "call %[bpf_ktime_get_ns];" + "r0 &= 0xff;" + "r7 = r0;" + "r0 = 0;" + /* Maybe make r{6,7} IDs identical */ + "if r6 > r7 goto l0_%=;" + "goto l1_%=;" +"l0_%=:" + "r6 = r7;" +"l1_%=:" + /* Mark r{6,7} precise. + * Get here in two states: + * - first: r6{.id=A}, r7{.id=B} (cached state) + * - second: r6{.id=A}, r7{.id=A} + * Currently we don't want to consider such states equivalent. + * Thus "exit;" would be verified twice. + */ + "r2 = r10;" + "r2 += r6;" + "r2 += r7;" + "exit;" + : + : __imm(bpf_ktime_get_ns) + : __clobber_all); +} + char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From e5d4a21b3a9477ead1c32504a56569a848c22736 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 12 Jun 2023 09:16:41 +0200 Subject: mctp i2c: Switch back to use struct i2c_driver's .probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit b8a1a4cd5a98 ("i2c: Provide a temporary .probe_new() call-back type"), all drivers being converted to .probe_new() and then commit 03c835f498b5 ("i2c: Switch .probe() to not take an id parameter") convert back to (the new) .probe() to be able to eventually drop .probe_new() from struct i2c_driver. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230612071641.836976-1-u.kleine-koenig@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/mctp/mctp-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c index 1d67a3ca1fd1..b37a9e4bade4 100644 --- a/drivers/net/mctp/mctp-i2c.c +++ b/drivers/net/mctp/mctp-i2c.c @@ -1058,7 +1058,7 @@ static struct i2c_driver mctp_i2c_driver = { .name = "mctp-i2c-interface", .of_match_table = mctp_i2c_of_match, }, - .probe_new = mctp_i2c_probe, + .probe = mctp_i2c_probe, .remove = mctp_i2c_remove, .id_table = mctp_i2c_id, }; -- cgit v1.2.3 From 2bddad9ec65a925da4ab4f73a9377d80540ca67b Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Mon, 12 Jun 2023 14:37:00 -0700 Subject: ethtool: ioctl: account for sopass diff in set_wol sopass won't be set if wolopt doesn't change. This means the following will fail to set the correct sopass. ethtool -s eth0 wol s sopass 11:22:33:44:55:66 ethtool -s eth0 wol s sopass 22:44:55:66:77:88 Make sure we call into the driver layer set_wol if sopass is different. Fixes: 55b24334c0f2 ("ethtool: ioctl: improve error checking for set_wol") Signed-off-by: Justin Chen Link: https://lore.kernel.org/r/1686605822-34544-1-git-send-email-justin.chen@broadcom.com Signed-off-by: Jakub Kicinski --- net/ethtool/ioctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c index 37b582225854..4a51e0ec295c 100644 --- a/net/ethtool/ioctl.c +++ b/net/ethtool/ioctl.c @@ -1452,7 +1452,8 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) if (wol.wolopts & ~cur_wol.supported) return -EINVAL; - if (wol.wolopts == cur_wol.wolopts) + if (wol.wolopts == cur_wol.wolopts && + !memcmp(wol.sopass, cur_wol.sopass, sizeof(wol.sopass))) return 0; ret = dev->ethtool_ops->set_wol(dev, &wol); -- cgit v1.2.3 From 2ad66fcb2fded5359a676f7146cf442641d28307 Mon Sep 17 00:00:00 2001 From: Gilad Itzkovitch Date: Thu, 18 May 2023 12:07:23 +1200 Subject: wifi: cfg80211: S1G rate information and calculations Increase the size of S1G rate_info flags to support S1G and add flags for new S1G MCS and the supported bandwidths. Also, include S1G rate information to netlink STA rate message. Lastly, add rate calculation function for S1G MCS. Signed-off-by: Gilad Itzkovitch Link: https://lore.kernel.org/r/20230518000723.991912-1-gilad.itzkovitch@morsemicro.com Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 18 +++++-- include/uapi/linux/nl80211.h | 14 ++++++ net/wireless/nl80211.c | 23 +++++++++ net/wireless/util.c | 110 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+), 3 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 1b8619685bf6..5d04e7eed43d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -1702,6 +1702,7 @@ int cfg80211_check_station_change(struct wiphy *wiphy, * @RATE_INFO_FLAGS_EDMG: 60GHz MCS in EDMG mode * @RATE_INFO_FLAGS_EXTENDED_SC_DMG: 60GHz extended SC MCS * @RATE_INFO_FLAGS_EHT_MCS: EHT MCS information + * @RATE_INFO_FLAGS_S1G_MCS: MCS field filled with S1G MCS */ enum rate_info_flags { RATE_INFO_FLAGS_MCS = BIT(0), @@ -1712,6 +1713,7 @@ enum rate_info_flags { RATE_INFO_FLAGS_EDMG = BIT(5), RATE_INFO_FLAGS_EXTENDED_SC_DMG = BIT(6), RATE_INFO_FLAGS_EHT_MCS = BIT(7), + RATE_INFO_FLAGS_S1G_MCS = BIT(8), }; /** @@ -1728,6 +1730,11 @@ enum rate_info_flags { * @RATE_INFO_BW_HE_RU: bandwidth determined by HE RU allocation * @RATE_INFO_BW_320: 320 MHz bandwidth * @RATE_INFO_BW_EHT_RU: bandwidth determined by EHT RU allocation + * @RATE_INFO_BW_1: 1 MHz bandwidth + * @RATE_INFO_BW_2: 2 MHz bandwidth + * @RATE_INFO_BW_4: 4 MHz bandwidth + * @RATE_INFO_BW_8: 8 MHz bandwidth + * @RATE_INFO_BW_16: 16 MHz bandwidth */ enum rate_info_bw { RATE_INFO_BW_20 = 0, @@ -1739,6 +1746,11 @@ enum rate_info_bw { RATE_INFO_BW_HE_RU, RATE_INFO_BW_320, RATE_INFO_BW_EHT_RU, + RATE_INFO_BW_1, + RATE_INFO_BW_2, + RATE_INFO_BW_4, + RATE_INFO_BW_8, + RATE_INFO_BW_16, }; /** @@ -1747,8 +1759,8 @@ enum rate_info_bw { * Information about a receiving or transmitting bitrate * * @flags: bitflag of flags from &enum rate_info_flags - * @mcs: mcs index if struct describes an HT/VHT/HE rate * @legacy: bitrate in 100kbit/s for 802.11abg + * @mcs: mcs index if struct describes an HT/VHT/HE/EHT/S1G rate * @nss: number of streams (VHT & HE only) * @bw: bandwidth (from &enum rate_info_bw) * @he_gi: HE guard interval (from &enum nl80211_he_gi) @@ -1761,9 +1773,9 @@ enum rate_info_bw { * only valid if bw is %RATE_INFO_BW_EHT_RU) */ struct rate_info { - u8 flags; - u8 mcs; + u16 flags; u16 legacy; + u8 mcs; u8 nss; u8 bw; u8 he_gi; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index c59fec406da5..435c4ac5d9bf 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -3667,6 +3667,13 @@ enum nl80211_eht_ru_alloc { * (u8, see &enum nl80211_eht_gi) * @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then * non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc) + * @NL80211_RATE_INFO_S1G_MCS: S1G MCS index (u8, 0-10) + * @NL80211_RATE_INFO_S1G_NSS: S1G NSS value (u8, 1-4) + * @NL80211_RATE_INFO_1_MHZ_WIDTH: 1 MHz S1G rate + * @NL80211_RATE_INFO_2_MHZ_WIDTH: 2 MHz S1G rate + * @NL80211_RATE_INFO_4_MHZ_WIDTH: 4 MHz S1G rate + * @NL80211_RATE_INFO_8_MHZ_WIDTH: 8 MHz S1G rate + * @NL80211_RATE_INFO_16_MHZ_WIDTH: 16 MHz S1G rate * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ enum nl80211_rate_info { @@ -3693,6 +3700,13 @@ enum nl80211_rate_info { NL80211_RATE_INFO_EHT_NSS, NL80211_RATE_INFO_EHT_GI, NL80211_RATE_INFO_EHT_RU_ALLOC, + NL80211_RATE_INFO_S1G_MCS, + NL80211_RATE_INFO_S1G_NSS, + NL80211_RATE_INFO_1_MHZ_WIDTH, + NL80211_RATE_INFO_2_MHZ_WIDTH, + NL80211_RATE_INFO_4_MHZ_WIDTH, + NL80211_RATE_INFO_8_MHZ_WIDTH, + NL80211_RATE_INFO_16_MHZ_WIDTH, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 772671b9bc42..f962765f7e0f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -6368,12 +6368,27 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr) return false; switch (info->bw) { + case RATE_INFO_BW_1: + rate_flg = NL80211_RATE_INFO_1_MHZ_WIDTH; + break; + case RATE_INFO_BW_2: + rate_flg = NL80211_RATE_INFO_2_MHZ_WIDTH; + break; + case RATE_INFO_BW_4: + rate_flg = NL80211_RATE_INFO_4_MHZ_WIDTH; + break; case RATE_INFO_BW_5: rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH; break; + case RATE_INFO_BW_8: + rate_flg = NL80211_RATE_INFO_8_MHZ_WIDTH; + break; case RATE_INFO_BW_10: rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH; break; + case RATE_INFO_BW_16: + rate_flg = NL80211_RATE_INFO_16_MHZ_WIDTH; + break; default: WARN_ON(1); fallthrough; @@ -6432,6 +6447,14 @@ bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr) nla_put_u8(msg, NL80211_RATE_INFO_HE_RU_ALLOC, info->he_ru_alloc)) return false; + } else if (info->flags & RATE_INFO_FLAGS_S1G_MCS) { + if (nla_put_u8(msg, NL80211_RATE_INFO_S1G_MCS, info->mcs)) + return false; + if (nla_put_u8(msg, NL80211_RATE_INFO_S1G_NSS, info->nss)) + return false; + if (info->flags & RATE_INFO_FLAGS_SHORT_GI && + nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)) + return false; } else if (info->flags & RATE_INFO_FLAGS_EHT_MCS) { if (nla_put_u8(msg, NL80211_RATE_INFO_EHT_MCS, info->mcs)) return false; diff --git a/net/wireless/util.c b/net/wireless/util.c index 3bc0c3072e78..610a867c14f7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1646,6 +1646,114 @@ static u32 cfg80211_calculate_bitrate_eht(struct rate_info *rate) return result / 10000; } +static u32 cfg80211_calculate_bitrate_s1g(struct rate_info *rate) +{ + /* For 1, 2, 4, 8 and 16 MHz channels */ + static const u32 base[5][11] = { + { 300000, + 600000, + 900000, + 1200000, + 1800000, + 2400000, + 2700000, + 3000000, + 3600000, + 4000000, + /* MCS 10 supported in 1 MHz only */ + 150000, + }, + { 650000, + 1300000, + 1950000, + 2600000, + 3900000, + 5200000, + 5850000, + 6500000, + 7800000, + /* MCS 9 not valid */ + }, + { 1350000, + 2700000, + 4050000, + 5400000, + 8100000, + 10800000, + 12150000, + 13500000, + 16200000, + 18000000, + }, + { 2925000, + 5850000, + 8775000, + 11700000, + 17550000, + 23400000, + 26325000, + 29250000, + 35100000, + 39000000, + }, + { 8580000, + 11700000, + 17550000, + 23400000, + 35100000, + 46800000, + 52650000, + 58500000, + 70200000, + 78000000, + }, + }; + u32 bitrate; + /* default is 1 MHz index */ + int idx = 0; + + if (rate->mcs >= 11) + goto warn; + + switch (rate->bw) { + case RATE_INFO_BW_16: + idx = 4; + break; + case RATE_INFO_BW_8: + idx = 3; + break; + case RATE_INFO_BW_4: + idx = 2; + break; + case RATE_INFO_BW_2: + idx = 1; + break; + case RATE_INFO_BW_1: + idx = 0; + break; + case RATE_INFO_BW_5: + case RATE_INFO_BW_10: + case RATE_INFO_BW_20: + case RATE_INFO_BW_40: + case RATE_INFO_BW_80: + case RATE_INFO_BW_160: + default: + goto warn; + } + + bitrate = base[idx][rate->mcs]; + bitrate *= rate->nss; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +warn: + WARN_ONCE(1, "invalid rate bw=%d, mcs=%d, nss=%d\n", + rate->bw, rate->mcs, rate->nss); + return 0; +} + u32 cfg80211_calculate_bitrate(struct rate_info *rate) { if (rate->flags & RATE_INFO_FLAGS_MCS) @@ -1662,6 +1770,8 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate) return cfg80211_calculate_bitrate_he(rate); if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) return cfg80211_calculate_bitrate_eht(rate); + if (rate->flags & RATE_INFO_FLAGS_S1G_MCS) + return cfg80211_calculate_bitrate_s1g(rate); return rate->legacy; } -- cgit v1.2.3 From 1ec7291e247055fab3a088e1a333a31e7c06e2dd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 4 Jun 2023 12:11:24 +0300 Subject: wifi: mac80211: add helpers to access sband iftype data There's quite a bit of code accessing sband iftype data (HE, HE 6 GHz, EHT) and we always need to remember to use the ieee80211_vif_type_p2p() helper. Add new helpers to directly get it from the sband/vif rather than having to call ieee80211_vif_type_p2p(). Convert most code with the following spatch: @@ expression vif, sband; @@ -ieee80211_get_he_iftype_cap(sband, ieee80211_vif_type_p2p(vif)) +ieee80211_get_he_iftype_cap_vif(sband, vif) @@ expression vif, sband; @@ -ieee80211_get_eht_iftype_cap(sband, ieee80211_vif_type_p2p(vif)) +ieee80211_get_eht_iftype_cap_vif(sband, vif) @@ expression vif, sband; @@ -ieee80211_get_he_6ghz_capa(sband, ieee80211_vif_type_p2p(vif)) +ieee80211_get_he_6ghz_capa_vif(sband, vif) Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230604120651.db099f49e764.Ie892966c49e22c7b7ee1073bc684f142debfdc84@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 ++-- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 5 ++- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 5 ++- include/net/mac80211.h | 44 ++++++++++++++++++++++- net/mac80211/eht.c | 5 ++- net/mac80211/he.c | 3 +- net/mac80211/mlme.c | 30 ++++++---------- net/mac80211/util.c | 11 +++--- 8 files changed, 66 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 1ade1f003420..91c38d42d034 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2269,8 +2269,7 @@ bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * so take it from one of them. */ sband = mvm->hw->wiphy->bands[NL80211_BAND_2GHZ]; - own_he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(vif)); + own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); return (own_he_cap && (own_he_cap->he_cap_elem.mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_ACK_EN)); @@ -3452,8 +3451,7 @@ static void iwl_mvm_reset_cca_40mhz_workaround(struct iwl_mvm *mvm, sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; - he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(vif)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); if (he_cap) { /* we know that ours is writable */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 8cc2e2145cf9..430642576f5d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -192,8 +192,7 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, WARN_ON(!(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)); sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(vif)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); if (he_cap) { /* we know that ours is writable */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index c3a00bfbeef2..f72d1ca3cfed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include "rs.h" #include "fw-api.h" @@ -94,8 +94,7 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm, IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; - sband_he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(vif)); + sband_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); if (sband_he_cap && !(sband_he_cap->he_cap_elem.phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index f4516c034da2..8ea23884a583 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -7,7 +7,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2022 Intel Corporation + * Copyright (C) 2018 - 2023 Intel Corporation */ #ifndef MAC80211_H @@ -6866,6 +6866,48 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif) return ieee80211_iftype_p2p(vif->type, vif->p2p); } +/** + * ieee80211_get_he_iftype_cap_vif - return HE capabilities for sband/vif + * @sband: the sband to search for the iftype on + * @vif: the vif to get the iftype from + * + * Return: pointer to the struct ieee80211_sta_he_cap, or %NULL is none found + */ +static inline const struct ieee80211_sta_he_cap * +ieee80211_get_he_iftype_cap_vif(const struct ieee80211_supported_band *sband, + struct ieee80211_vif *vif) +{ + return ieee80211_get_he_iftype_cap(sband, ieee80211_vif_type_p2p(vif)); +} + +/** + * ieee80211_get_he_6ghz_capa_vif - return HE 6 GHz capabilities + * @sband: the sband to search for the STA on + * @vif: the vif to get the iftype from + * + * Return: the 6GHz capabilities + */ +static inline __le16 +ieee80211_get_he_6ghz_capa_vif(const struct ieee80211_supported_band *sband, + struct ieee80211_vif *vif) +{ + return ieee80211_get_he_6ghz_capa(sband, ieee80211_vif_type_p2p(vif)); +} + +/** + * ieee80211_get_eht_iftype_cap_vif - return ETH capabilities for sband/vif + * @sband: the sband to search for the iftype on + * @vif: the vif to get the iftype from + * + * Return: pointer to the struct ieee80211_sta_eht_cap, or %NULL is none found + */ +static inline const struct ieee80211_sta_eht_cap * +ieee80211_get_eht_iftype_cap_vif(const struct ieee80211_supported_band *sband, + struct ieee80211_vif *vif) +{ + return ieee80211_get_eht_iftype_cap(sband, ieee80211_vif_type_p2p(vif)); +} + /** * ieee80211_update_mu_groups - set the VHT MU-MIMO groud data * diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c index 18bc6b78b267..ddc7acc68335 100644 --- a/net/mac80211/eht.c +++ b/net/mac80211/eht.c @@ -2,7 +2,7 @@ /* * EHT handling * - * Copyright(c) 2021-2022 Intel Corporation + * Copyright(c) 2021-2023 Intel Corporation */ #include "ieee80211_i.h" @@ -25,8 +25,7 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata, memset(eht_cap, 0, sizeof(*eht_cap)); if (!eht_cap_ie_elem || - !ieee80211_get_eht_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif))) + !ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif)) return; mcs_nss_size = ieee80211_eht_mcs_nss_size(he_cap_ie_elem, diff --git a/net/mac80211/he.c b/net/mac80211/he.c index 0322abae0825..9f5ffdc9db28 100644 --- a/net/mac80211/he.c +++ b/net/mac80211/he.c @@ -128,8 +128,7 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata, return; own_he_cap_ptr = - ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); + ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); if (!own_he_cap_ptr) return; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3827b5dcdb03..270133883882 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -511,16 +511,14 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link, /* don't check HE if we associated as non-HE station */ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE || - !ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif))) { + !ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif)) { he_oper = NULL; eht_oper = NULL; } /* don't check EHT if we associated as non-EHT station */ if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT || - !ieee80211_get_eht_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif))) + !ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif)) eht_oper = NULL; /* @@ -776,8 +774,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata, const struct ieee80211_sta_he_cap *he_cap; u8 he_cap_size; - he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); if (WARN_ON(!he_cap)) return; @@ -806,10 +803,8 @@ static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata, const struct ieee80211_sta_eht_cap *eht_cap; u8 eht_cap_size; - he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); - eht_cap = ieee80211_get_eht_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); /* * EHT capabilities element is only added if the HE capabilities element @@ -3945,8 +3940,7 @@ static bool ieee80211_twt_req_supported(struct ieee80211_sub_if_data *sdata, const struct ieee802_11_elems *elems) { const struct ieee80211_sta_he_cap *own_he_cap = - ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); + ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); if (elems->ext_capab_len < 10) return false; @@ -3982,8 +3976,7 @@ static bool ieee80211_twt_bcast_support(struct ieee80211_sub_if_data *sdata, struct link_sta_info *link_sta) { const struct ieee80211_sta_he_cap *own_he_cap = - ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); + ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); return bss_conf->he_support && (link_sta->pub->he_cap.he_cap_elem.mac_cap_info[2] & @@ -4620,8 +4613,7 @@ ieee80211_verify_sta_he_mcs_support(struct ieee80211_sub_if_data *sdata, const struct ieee80211_he_operation *he_op) { const struct ieee80211_sta_he_cap *sta_he_cap = - ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); + ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); u16 ap_min_req_set; int i; @@ -4755,15 +4747,13 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, *conn_flags |= IEEE80211_CONN_DISABLE_EHT; } - if (!ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif))) { + if (!ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif)) { mlme_dbg(sdata, "HE not supported, disabling HE and EHT\n"); *conn_flags |= IEEE80211_CONN_DISABLE_HE; *conn_flags |= IEEE80211_CONN_DISABLE_EHT; } - if (!ieee80211_get_eht_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif))) { + if (!ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif)) { mlme_dbg(sdata, "EHT not supported, disabling EHT\n"); *conn_flags |= IEEE80211_CONN_DISABLE_EHT; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 083ad56d08d9..a5be07a4dbe3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -6,7 +6,7 @@ * Copyright 2007 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation * * utilities for mac80211 */ @@ -2121,8 +2121,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, *offset = noffset; } - he_cap = ieee80211_get_he_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); if (he_cap && cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), IEEE80211_CHAN_NO_HE)) { @@ -2131,8 +2130,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, goto out_err; } - eht_cap = ieee80211_get_eht_iftype_cap(sband, - ieee80211_vif_type_p2p(&sdata->vif)); + eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); if (eht_cap && cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band), @@ -2150,8 +2148,7 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband6; sband6 = local->hw.wiphy->bands[NL80211_BAND_6GHZ]; - he_cap = ieee80211_get_he_iftype_cap(sband6, - ieee80211_vif_type_p2p(&sdata->vif)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband6, &sdata->vif); if (he_cap) { enum nl80211_iftype iftype = -- cgit v1.2.3 From 4c2d68f7981d7794b03fb5035208e6dd3014c9bc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Jun 2023 16:35:57 +0300 Subject: wifi: mac80211: include key action/command in tracing We trace the key information and all, but not whether the key is added or removed - add that information. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.546e86e216df.Ie3bf9009926f8fa154dde52b0c02537ff7edae36@changeid Signed-off-by: Johannes Berg --- net/mac80211/trace.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index db0d0132c58c..e5edf6fe576f 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -2,7 +2,7 @@ /* * Portions of this file * Copyright(c) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2022 Intel Corporation + * Copyright (C) 2018 - 2023 Intel Corporation */ #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) @@ -634,6 +634,7 @@ TRACE_EVENT(drv_set_key, LOCAL_ENTRY VIF_ENTRY STA_ENTRY + __field(u32, cmd) KEY_ENTRY ), @@ -641,12 +642,13 @@ TRACE_EVENT(drv_set_key, LOCAL_ASSIGN; VIF_ASSIGN; STA_ASSIGN; + __entry->cmd = cmd; KEY_ASSIGN(key); ), TP_printk( - LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT KEY_PR_FMT, - LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, KEY_PR_ARG + LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " cmd: %d" KEY_PR_FMT, + LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->cmd, KEY_PR_ARG ) ); -- cgit v1.2.3 From c6968d4fc9aac110d607722d92fc17dfa65f0716 Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Thu, 8 Jun 2023 16:35:58 +0300 Subject: wifi: mac80211: pass roc->sdata to drv_cancel_remain_on_channel() In suspend flow "sdata" is NULL, destroy all roc's which are started. pass "roc->sdata" to drv_cancel_remain_on_channel() to avoid NULL dereference and destroy that roc Signed-off-by: Anjaneyulu Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.c678187a308c.Ic11578778655e273931efc5355d570a16465d1be@changeid Signed-off-by: Johannes Berg --- net/mac80211/offchannel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index d78c82d6b696..cdf991e74ab9 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -8,7 +8,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007, Michael Wu * Copyright 2009 Johannes Berg - * Copyright (C) 2019, 2022 Intel Corporation + * Copyright (C) 2019, 2022-2023 Intel Corporation */ #include #include @@ -1014,7 +1014,7 @@ void ieee80211_roc_purge(struct ieee80211_local *local, if (roc->started) { if (local->ops->remain_on_channel) { /* can race, so ignore return value */ - drv_cancel_remain_on_channel(local, sdata); + drv_cancel_remain_on_channel(local, roc->sdata); ieee80211_roc_notify_destroy(roc); } else { roc->abort = true; -- cgit v1.2.3 From b580a372b84fa4895f9c8c96585f0cb9986a921c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Jun 2023 16:36:00 +0300 Subject: wifi: mac80211: mlme: clarify WMM messages These messages apply to a single link only, use link_info() to indicate that. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.21a6bece4313.I08118e5e851fae2f9e43f8a58d3b6217709bf578@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 270133883882..f13792994b4f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2639,9 +2639,9 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local, params[ac].aifs = pos[0] & 0x0f; if (params[ac].aifs < 2) { - sdata_info(sdata, - "AP has invalid WMM params (AIFSN=%d for ACI %d), will use 2\n", - params[ac].aifs, aci); + link_info(link, + "AP has invalid WMM params (AIFSN=%d for ACI %d), will use 2\n", + params[ac].aifs, aci); params[ac].aifs = 2; } params[ac].cw_max = ecw2cw((pos[1] & 0xf0) >> 4); @@ -2652,9 +2652,9 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local, if (params[ac].cw_min == 0 || params[ac].cw_min > params[ac].cw_max) { - sdata_info(sdata, - "AP has invalid WMM params (CWmin/max=%d/%d for ACI %d), using defaults\n", - params[ac].cw_min, params[ac].cw_max, aci); + link_info(link, + "AP has invalid WMM params (CWmin/max=%d/%d for ACI %d), using defaults\n", + params[ac].cw_min, params[ac].cw_max, aci); return false; } ieee80211_regulatory_limit_wmm_params(sdata, ¶ms[ac], ac); @@ -2663,9 +2663,9 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local, /* WMM specification requires all 4 ACIs. */ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { if (params[ac].cw_min == 0) { - sdata_info(sdata, - "AP has invalid WMM params (missing AC %d), using defaults\n", - ac); + link_info(link, + "AP has invalid WMM params (missing AC %d), using defaults\n", + ac); return false; } } -- cgit v1.2.3 From 556f16b83459590a2d8d1394fd3af4d6d8ccabc7 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 8 Jun 2023 16:36:03 +0300 Subject: wifi: mac80211: fix CSA processing while scanning The channel switch parsing code would simply return if a scan is in-progress. Supposedly, this was because channel switch announcements from other APs should be ignored. For the beacon case, the function is already only called if we are associated with the sender. For the action frame cases, add the appropriate check whether the frame is coming from the AP we are associated with. Finally, drop the scanning check from ieee80211_sta_process_chanswitch. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.3366e9302468.I6c7e0b58c33b7fb4c675374cfe8c3a5cddcec416@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f13792994b4f..d1e30ff54c1f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1857,9 +1857,6 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, if (!cbss) return; - if (local->scanning) - return; - current_band = cbss->channel->band; bss = (void *)cbss->priv; res = ieee80211_parse_ch_switch_ie(sdata, elems, current_band, @@ -5997,6 +5994,10 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len); break; case IEEE80211_STYPE_ACTION: + if (!sdata->u.mgd.associated || + !ether_addr_equal(mgmt->bssid, sdata->vif.cfg.ap_addr)) + break; + if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) { struct ieee802_11_elems *elems; -- cgit v1.2.3 From 0e966d9a35fa5a3967a4900654fa925b8fb8e71b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Jun 2023 16:36:05 +0300 Subject: wifi: mac80211: don't update rx_stats.last_rate for NDP If we get an NDP (null data packet), there's reason to believe the peer is just sending it to probe, and that would happen at a low rate. Don't track this packet for purposes of last RX rate reporting. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.8af46c4ac094.I13d9d5019addeaa4aff3c8a05f56c9f5a86b1ebd@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ed9939466198..77c7dac760ba 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -6,7 +6,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include @@ -1732,7 +1732,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) && test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { link_sta->rx_stats.last_rx = jiffies; - if (ieee80211_is_data(hdr->frame_control) && + if (ieee80211_is_data_present(hdr->frame_control) && !is_multicast_ether_addr(hdr->addr1)) link_sta->rx_stats.last_rate = sta_stats_encode_rate(status); @@ -1746,7 +1746,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) * match the current local configuration when processed. */ link_sta->rx_stats.last_rx = jiffies; - if (ieee80211_is_data(hdr->frame_control)) + if (ieee80211_is_data_present(hdr->frame_control)) link_sta->rx_stats.last_rate = sta_stats_encode_rate(status); } -- cgit v1.2.3 From bc1be54d7eb4ab4c6bd44e9f73d5b44b6c8e761c Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 8 Jun 2023 16:36:06 +0300 Subject: wifi: mac80211: allow disabling SMPS debugfs controls There are cases in which we don't want the user to override the smps mode, e.g. when SMPS should be disabled due to EMLSR. Add a driver flag to disable SMPS overriding and don't override if it is set. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.ef129e80556c.I74a298fdc86b87074c95228d3916739de1400597@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 3 +++ net/mac80211/debugfs_netdev.c | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8ea23884a583..98cb2c532025 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1755,12 +1755,15 @@ struct ieee80211_channel_switch { * @IEEE80211_VIF_GET_NOA_UPDATE: request to handle NOA attributes * and send P2P_PS notification to the driver if NOA changed, even * this is not pure P2P vif. + * @IEEE80211_VIF_DISABLE_SMPS_OVERRIDE: disable user configuration of + * SMPS mode via debugfs. */ enum ieee80211_vif_flags { IEEE80211_VIF_BEACON_FILTER = BIT(0), IEEE80211_VIF_SUPPORTS_CQM_RSSI = BIT(1), IEEE80211_VIF_SUPPORTS_UAPSD = BIT(2), IEEE80211_VIF_GET_NOA_UPDATE = BIT(3), + IEEE80211_VIF_DISABLE_SMPS_OVERRIDE = BIT(4), }; diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index b0cef37eb394..3fea86c9a276 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2006 Jiri Benc * Copyright 2007 Johannes Berg - * Copyright (C) 2020-2022 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation */ #include @@ -267,6 +267,9 @@ static int ieee80211_set_smps(struct ieee80211_link_data *link, struct ieee80211_local *local = sdata->local; int err; + if (sdata->vif.driver_flags & IEEE80211_VIF_DISABLE_SMPS_OVERRIDE) + return -EOPNOTSUPP; + if (!(local->hw.wiphy->features & NL80211_FEATURE_STATIC_SMPS) && smps_mode == IEEE80211_SMPS_STATIC) return -EINVAL; -- cgit v1.2.3 From f1871abd27641c020298b5c7654e1d8341f22e5f Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Jun 2023 16:36:08 +0300 Subject: wifi: mac80211: Add getter functions for vif MLD state As a preparation to support disabled/dormant links, add the following function: - ieee80211_vif_usable_links(): returns the bitmap of the links that can be activated. Use this function in all the places that the bitmap of the usable links is needed. - ieee80211_vif_is_mld(): returns true iff the vif is an MLD. Use this function in all the places where an indication that the connection is a MLD is needed. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.86e3351da1fc.If6fe3a339fda2019f13f57ff768ecffb711b710a@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 21 +++++++++++++++++++++ net/mac80211/cfg.c | 4 ++-- net/mac80211/debug.h | 8 ++++---- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/iface.c | 4 ++-- net/mac80211/link.c | 4 ++-- net/mac80211/mlme.c | 43 ++++++++++++++++++++++--------------------- net/mac80211/rx.c | 2 +- net/mac80211/tx.c | 22 +++++++++++----------- net/mac80211/util.c | 14 +++++++------- 10 files changed, 73 insertions(+), 51 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 98cb2c532025..5424301df3c8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1909,6 +1909,27 @@ struct ieee80211_vif { u8 drv_priv[] __aligned(sizeof(void *)); }; +/** + * ieee80211_vif_usable_links - Return the usable links for the vif + * @vif: the vif for which the usable links are requested + * Return: the usable link bitmap + */ +static inline u16 ieee80211_vif_usable_links(const struct ieee80211_vif *vif) +{ + return vif->valid_links; +} + +/** + * ieee80211_vif_is_mld - Returns true iff the vif is an MLD one + * @vif: the vif + * Return: %true if the vif is an MLD, %false otherwise. + */ +static inline bool ieee80211_vif_is_mld(const struct ieee80211_vif *vif) +{ + /* valid_links != 0 indicates this vif is an MLD */ + return vif->valid_links != 0; +} + #define for_each_vif_active_link(vif, link, link_id) \ for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) \ if ((!(vif)->active_links || \ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 1b78a2ae7a83..d31b66723ccc 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -35,7 +35,7 @@ ieee80211_link_or_deflink(struct ieee80211_sub_if_data *sdata, int link_id, * the return value at all (if it's not a pairwise key), * so in that case (require_valid==false) don't error. */ - if (require_valid && sdata->vif.valid_links) + if (require_valid && ieee80211_vif_is_mld(&sdata->vif)) return ERR_PTR(-EINVAL); return &sdata->deflink; @@ -228,7 +228,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, return 0; /* FIXME: no support for 4-addr MLO yet */ - if (sdata->vif.valid_links) + if (ieee80211_vif_is_mld(&sdata->vif)) return -EOPNOTSUPP; sdata->u.mgd.use_4addr = params->use_4addr; diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h index b4c20f5e778e..d49894df2351 100644 --- a/net/mac80211/debug.h +++ b/net/mac80211/debug.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Portions - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022 - 2023 Intel Corporation */ #ifndef __MAC80211_DEBUG_H #define __MAC80211_DEBUG_H @@ -136,7 +136,7 @@ do { \ #define link_info(link, fmt, ...) \ do { \ - if ((link)->sdata->vif.valid_links) \ + if (ieee80211_vif_is_mld(&(link)->sdata->vif)) \ _sdata_info((link)->sdata, "[link %d] " fmt, \ (link)->link_id, \ ##__VA_ARGS__); \ @@ -145,7 +145,7 @@ do { \ } while (0) #define link_err(link, fmt, ...) \ do { \ - if ((link)->sdata->vif.valid_links) \ + if (ieee80211_vif_is_mld(&(link)->sdata->vif)) \ _sdata_err((link)->sdata, "[link %d] " fmt, \ (link)->link_id, \ ##__VA_ARGS__); \ @@ -154,7 +154,7 @@ do { \ } while (0) #define link_dbg(link, fmt, ...) \ do { \ - if ((link)->sdata->vif.valid_links) \ + if (ieee80211_vif_is_mld(&(link)->sdata->vif)) \ _sdata_dbg(1, (link)->sdata, "[link %d] " fmt, \ (link)->link_id, \ ##__VA_ARGS__); \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f918e73469a7..f55cec0e6b2d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1614,7 +1614,7 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata) struct ieee80211_chanctx_conf *chanctx_conf; enum nl80211_band band; - WARN_ON(sdata->vif.valid_links); + WARN_ON(ieee80211_vif_is_mld(&sdata->vif)); rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5b67b44e3f89..9518acf9643b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -521,7 +521,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do cancel_work_sync(&sdata->recalc_smps); sdata_lock(sdata); - WARN(sdata->vif.valid_links, + WARN(ieee80211_vif_is_mld(&sdata->vif), "destroying interface with valid links 0x%04x\n", sdata->vif.valid_links); @@ -1815,7 +1815,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata, return -EBUSY; /* for now, don't support changing while links exist */ - if (sdata->vif.valid_links) + if (ieee80211_vif_is_mld(&sdata->vif)) return -EBUSY; switch (sdata->vif.type) { diff --git a/net/mac80211/link.c b/net/mac80211/link.c index e82db88a47f8..5ec60f0d821c 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -329,7 +329,7 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata, return -EINVAL; /* cannot activate links that don't exist */ - if (active_links & ~sdata->vif.valid_links) + if (active_links & ~ieee80211_vif_usable_links(&sdata->vif)) return -EINVAL; /* nothing to do */ @@ -485,7 +485,7 @@ void ieee80211_set_active_links_async(struct ieee80211_vif *vif, return; /* cannot activate links that don't exist */ - if (active_links & ~sdata->vif.valid_links) + if (active_links & ~ieee80211_vif_usable_links(&sdata->vif)) return; /* nothing to do */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d1e30ff54c1f..fdd80f73e6cb 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1282,7 +1282,7 @@ static void ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata, u8 *ml_elem_len; void *capab_pos; - if (!sdata->vif.valid_links) + if (!ieee80211_vif_is_mld(&sdata->vif)) return; ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, @@ -1456,7 +1456,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) capab |= WLAN_CAPABILITY_PRIVACY; } - if (sdata->vif.valid_links) { + if (ieee80211_vif_is_mld(&sdata->vif)) { /* consider the multi-link element with STA profile */ size += sizeof(struct ieee80211_multi_link_elem); /* max common info field in basic multi-link element */ @@ -1789,7 +1789,7 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - if (WARN_ON(sdata->vif.valid_links)) + if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif))) success = false; trace_api_chswitch_done(sdata, success); @@ -2835,7 +2835,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, if (vif_cfg->arp_addr_cnt) vif_changed |= BSS_CHANGED_ARP_FILTER; - if (sdata->vif.valid_links) { + if (ieee80211_vif_is_mld(&sdata->vif)) { for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { @@ -2867,7 +2867,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, mutex_unlock(&local->iflist_mtx); /* leave this here to not change ordering in non-MLO cases */ - if (!sdata->vif.valid_links) + if (!ieee80211_vif_is_mld(&sdata->vif)) ieee80211_recalc_smps(sdata, &sdata->deflink); ieee80211_recalc_ps_vif(sdata); @@ -2963,7 +2963,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sta_info_flush(sdata); /* finally reset all BSS / config parameters */ - if (!sdata->vif.valid_links) + if (!ieee80211_vif_is_mld(&sdata->vif)) changed |= ieee80211_reset_erp_info(sdata); ieee80211_led_assoc(local, 0); @@ -2988,7 +2988,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, sizeof(sdata->vif.bss_conf.mu_group.membership)); memset(sdata->vif.bss_conf.mu_group.position, 0, sizeof(sdata->vif.bss_conf.mu_group.position)); - if (!sdata->vif.valid_links) + if (!ieee80211_vif_is_mld(&sdata->vif)) changed |= BSS_CHANGED_MU_GROUPS; sdata->vif.bss_conf.mu_mimo_owner = false; @@ -3002,7 +3002,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, changed |= BSS_CHANGED_ARP_FILTER; sdata->vif.bss_conf.qos = false; - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { changed |= BSS_CHANGED_QOS; /* The BSSID (not really interesting) and HT changed */ changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT; @@ -3171,7 +3171,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) u8 unicast_limit = max(1, max_probe_tries - 3); struct sta_info *sta; - if (WARN_ON(sdata->vif.valid_links)) + if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif))) return; /* @@ -3219,7 +3219,7 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; bool already = false; - if (WARN_ON_ONCE(sdata->vif.valid_links)) + if (WARN_ON_ONCE(ieee80211_vif_is_mld(&sdata->vif))) return; if (!ieee80211_sdata_running(sdata)) @@ -3294,7 +3294,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, int ssid_len; if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION || - sdata->vif.valid_links)) + ieee80211_vif_is_mld(&sdata->vif))) return NULL; sdata_assert_lock(sdata); @@ -3359,7 +3359,8 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) } /* in MLO assume we have a link where we can TX the frame */ - tx = sdata->vif.valid_links || !sdata->deflink.csa_block_tx; + tx = ieee80211_vif_is_mld(&sdata->vif) || + !sdata->deflink.csa_block_tx; if (!ifmgd->driver_disconnect) { unsigned int link_id; @@ -3560,7 +3561,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, for (i = 0; i < ARRAY_SIZE(data.bss); i++) data.bss[i] = assoc_data->link[i].bss; - if (sdata->vif.valid_links) + if (ieee80211_vif_is_mld(&sdata->vif)) data.ap_mld_addr = assoc_data->ap_addr; cfg80211_assoc_failure(sdata->dev, &data); @@ -4989,7 +4990,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!sta)) goto out_err; - if (sdata->vif.valid_links) { + if (ieee80211_vif_is_mld(&sdata->vif)) { for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { if (!assoc_data->link[link_id].bss) continue; @@ -5017,7 +5018,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!link)) goto out_err; - if (sdata->vif.valid_links) + if (ieee80211_vif_is_mld(&sdata->vif)) link_info(link, "local address %pM, AP link address %pM%s\n", link->conf->addr, @@ -5266,7 +5267,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ifmgd->broken_ap = true; } - if (sdata->vif.valid_links) { + if (ieee80211_vif_is_mld(&sdata->vif)) { if (!elems->multi_link) { sdata_info(sdata, "MLO association with %pM but no multi-link element in response!\n", @@ -5333,7 +5334,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, resp.uapsd_queues |= ieee80211_ac_to_qos_mask[ac]; } - if (sdata->vif.valid_links) { + if (ieee80211_vif_is_mld(&sdata->vif)) { ether_addr_copy(ap_mld_addr, sdata->vif.cfg.ap_addr); resp.ap_mld_addr = ap_mld_addr; } @@ -5659,7 +5660,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, rcu_read_unlock(); if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && - !WARN_ON(sdata->vif.valid_links) && + !WARN_ON(ieee80211_vif_is_mld(&sdata->vif)) && ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->link[0].bss)) { parse_params.bss = ifmgd->assoc_data->link[0].bss; elems = ieee802_11_parse_elems_full(&parse_params); @@ -6357,7 +6358,7 @@ static void ieee80211_sta_bcn_mon_timer(struct timer_list *t) struct ieee80211_sub_if_data *sdata = from_timer(sdata, t, u.mgd.bcn_mon_timer); - if (WARN_ON(sdata->vif.valid_links)) + if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif))) return; if (sdata->vif.bss_conf.csa_active && @@ -6381,7 +6382,7 @@ static void ieee80211_sta_conn_mon_timer(struct timer_list *t) struct sta_info *sta; unsigned long timeout; - if (WARN_ON(sdata->vif.valid_links)) + if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif))) return; if (sdata->vif.bss_conf.csa_active && @@ -6937,7 +6938,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, return 0; err_clear: - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { eth_zero_addr(sdata->deflink.u.mgd.bssid); ieee80211_link_info_change_notify(sdata, &sdata->deflink, BSS_CHANGED_BSSID); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 77c7dac760ba..6ebec32b4ebc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2505,7 +2505,7 @@ bool ieee80211_is_our_addr(struct ieee80211_sub_if_data *sdata, if (ether_addr_equal(sdata->vif.addr, addr)) return true; - if (!sdata->vif.valid_links) + if (!ieee80211_vif_is_mld(&sdata->vif)) return false; for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 148a0e2aa740..bdb09c8ccc96 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -844,7 +844,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) /* SNS11 from 802.11be 10.3.2.14 */ if (unlikely(is_multicast_ether_addr(hdr->addr1) && - info->control.vif->valid_links && + ieee80211_vif_is_mld(info->control.vif) && info->control.vif->type == NL80211_IFTYPE_AP)) { if (info->control.flags & IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX) tx->sdata->mld_mcast_seq += 0x10; @@ -2610,7 +2610,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, ethertype = (skb->data[12] << 8) | skb->data[13]; fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); - if (!sdata->vif.valid_links) + if (!ieee80211_vif_is_mld(&sdata->vif)) chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); @@ -2627,7 +2627,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); wme_sta = sta->sta.wme; } - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { struct ieee80211_sub_if_data *ap_sdata; /* override chanctx_conf from AP (we don't have one) */ @@ -2645,7 +2645,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, /* DA BSSID SA */ memcpy(hdr.addr1, skb->data, ETH_ALEN); - if (sdata->vif.valid_links && sta && !sta->sta.mlo) { + if (ieee80211_vif_is_mld(&sdata->vif) && sta && !sta->sta.mlo) { struct ieee80211_link_data *link; link_id = sta->deflink.link_id; @@ -2797,7 +2797,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, } if (!chanctx_conf) { - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { ret = -ENOTCONN; goto free; } @@ -3039,7 +3039,7 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) !ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG)) goto out; - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { rcu_read_lock(); chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); @@ -3110,7 +3110,7 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); /* DA BSSID SA */ build.da_offs = offsetof(struct ieee80211_hdr, addr1); - if (sta->sta.mlo || !sdata->vif.valid_links) { + if (sta->sta.mlo || !ieee80211_vif_is_mld(&sdata->vif)) { memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); } else { unsigned int link_id = sta->deflink.link_id; @@ -4479,7 +4479,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, __ieee80211_subif_start_xmit(skb, dev, 0, IEEE80211_TX_CTRL_MLO_LINK_UNSPEC, NULL); - } else if (sdata->vif.valid_links && + } else if (ieee80211_vif_is_mld(&sdata->vif) && sdata->vif.type == NL80211_IFTYPE_AP && !ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX)) { ieee80211_mlo_multicast_tx(dev, skb); @@ -4755,7 +4755,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) { /* update band only for non-MLD */ - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); if (unlikely(!chanctx_conf)) { @@ -6002,7 +6002,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, BUILD_BUG_ON(!FIELD_FIT(IEEE80211_TX_CTRL_MLO_LINK, IEEE80211_LINK_UNSPECIFIED)); - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { link = 0; } else if (link_id >= 0) { link = link_id; @@ -6048,7 +6048,7 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, enum nl80211_band band; rcu_read_lock(); - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { WARN_ON(link_id >= 0); chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index a5be07a4dbe3..3aa363bdb6e0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1824,7 +1824,7 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - bool multi_link = sdata->vif.valid_links; + bool multi_link = ieee80211_vif_is_mld(&sdata->vif); struct { u8 id; u8 len; @@ -2671,7 +2671,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) continue; sdata_lock(sdata); - if (sdata->vif.valid_links) { + if (ieee80211_vif_is_mld(&sdata->vif)) { struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS] = { [0] = &sdata->vif.bss_conf, }; @@ -2691,7 +2691,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) for (link_id = 0; link_id < ARRAY_SIZE(sdata->vif.link_conf); link_id++) { - if (sdata->vif.valid_links && + if (ieee80211_vif_is_mld(&sdata->vif) && !(sdata->vif.active_links & BIT(link_id))) continue; @@ -2723,12 +2723,12 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (sdata->vif.bss_conf.mu_mimo_owner) changed |= BSS_CHANGED_MU_GROUPS; - if (!sdata->vif.valid_links) + if (!ieee80211_vif_is_mld(&sdata->vif)) changed |= BSS_CHANGED_IDLE; switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: - if (!sdata->vif.valid_links) { + if (!ieee80211_vif_is_mld(&sdata->vif)) { changed |= BSS_CHANGED_ASSOC | BSS_CHANGED_ARP_FILTER | BSS_CHANGED_PS; @@ -2766,7 +2766,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) case NL80211_IFTYPE_AP: changed |= BSS_CHANGED_P2P_PS; - if (sdata->vif.valid_links) + if (ieee80211_vif_is_mld(&sdata->vif)) ieee80211_vif_cfg_change_notify(sdata, BSS_CHANGED_SSID); else @@ -2780,7 +2780,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (sdata->vif.type == NL80211_IFTYPE_AP) { changed |= BSS_CHANGED_AP_PROBE_RESP; - if (sdata->vif.valid_links) { + if (ieee80211_vif_is_mld(&sdata->vif)) { ieee80211_reconfig_ap_links(local, sdata, changed); -- cgit v1.2.3 From 01ae1209c0ecb62c31b0d9b75bcff55303a77314 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Jun 2023 16:36:09 +0300 Subject: wifi: mac80211_hwsim: Don't access vif valid links directly And instead use the vif getter functions, as a preparation for supporting disabled/dormant links. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.8966bd5ce7c8.Ia73e3555aaf4ddf9917bced8d413fad08cc28f1b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/virtual/mac80211_hwsim.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 37bf392ae9a2..f446fd0e8cd0 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -1860,7 +1860,7 @@ mac80211_hwsim_select_tx_link(struct mac80211_hwsim_data *data, struct hwsim_sta_priv *sp = (void *)sta->drv_priv; int i; - if (!vif->valid_links) + if (!ieee80211_vif_is_mld(vif)) return &vif->bss_conf; WARN_ON(is_multicast_ether_addr(hdr->addr1)); @@ -2636,7 +2636,8 @@ static int mac80211_hwsim_sta_state(struct ieee80211_hw *hw, */ if (vif->type == NL80211_IFTYPE_STATION && new_state == IEEE80211_STA_AUTHORIZED && !sta->tdls) - ieee80211_set_active_links_async(vif, vif->valid_links); + ieee80211_set_active_links_async(vif, + ieee80211_vif_usable_links(vif)); return 0; } -- cgit v1.2.3 From 6cf963edbbd3b279185e28e4864c9698ffaa23c3 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Jun 2023 16:36:10 +0300 Subject: wifi: cfg80211: Support association to AP MLD with disabled links An AP part of an AP MLD might be temporarily disabled, and might be enabled later. Such a link should be included in the association exchange, but should not be used until enabled. Extend the NL80211_CMD_ASSOCIATE to also indicate disabled links. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.c4c61ee4c4a5.I784ef4a0d619fc9120514b5615458fbef3b3684a@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 5 ++++- include/uapi/linux/nl80211.h | 7 ++++++- net/wireless/nl80211.c | 13 ++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 5d04e7eed43d..388f2a3851a2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -7,7 +7,7 @@ * Copyright 2006-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2021, 2023 Intel Corporation */ #include @@ -2882,11 +2882,14 @@ struct cfg80211_auth_request { * if this is %NULL for a link, that link is not requested * @elems: extra elements for the per-STA profile for this link * @elems_len: length of the elements + * @disabled: If set this link should be included during association etc. but it + * should not be used until enabled by the AP MLD. */ struct cfg80211_assoc_link { struct cfg80211_bss *bss; const u8 *elems; size_t elems_len; + bool disabled; }; /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 435c4ac5d9bf..03939bdb0e48 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -11,7 +11,7 @@ * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -2805,6 +2805,9 @@ enum nl80211_commands { * index. If the userspace includes more RNR elements than number of * MBSSID elements then these will be added in every EMA beacon. * + * @NL80211_ATTR_MLO_LINK_DISABLED: Flag attribute indicating that the link is + * disabled. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3341,6 +3344,8 @@ enum nl80211_attrs { NL80211_ATTR_EMA_RNR_ELEMS, + NL80211_ATTR_MLO_LINK_DISABLED, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index f962765f7e0f..ec7d467cb096 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -5,7 +5,7 @@ * Copyright 2006-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include @@ -816,6 +816,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS] = { .type = NLA_U16 }, [NL80211_ATTR_HW_TIMESTAMP_ENABLED] = { .type = NLA_FLAG }, [NL80211_ATTR_EMA_RNR_ELEMS] = { .type = NLA_NESTED }, + [NL80211_ATTR_MLO_LINK_DISABLED] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -11138,6 +11139,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto free; } } + + req.links[link_id].disabled = + nla_get_flag(attrs[NL80211_ATTR_MLO_LINK_DISABLED]); } if (!req.links[req.link_id].bss) { @@ -11152,6 +11156,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto free; } + if (req.links[req.link_id].disabled) { + GENL_SET_ERR_MSG(info, + "cannot have assoc link disabled"); + err = -EINVAL; + goto free; + } + kfree(attrs); attrs = NULL; } else { -- cgit v1.2.3 From 43ea09285f523df084de7c916667bcac99076095 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 11 Jun 2023 12:14:27 +0300 Subject: wifi: mac80211: Do not use "non-MLD AP" syntax Instead clarify the cases where link ID == 0 is intended for an AP STA that is not part of an AP MLD. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230611121219.77236a2e26ad.I8193ca8e236c9eb015870471f77a7d5134da3156@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5424301df3c8..2ecc8d0c6ef4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5280,7 +5280,8 @@ struct ieee80211_mutable_offsets { * @vif: &struct ieee80211_vif pointer from the add_interface callback. * @offs: &struct ieee80211_mutable_offsets pointer to struct that will * receive the offsets that may be updated by the driver. - * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) + * @link_id: the link id to which the beacon belongs (or 0 for an AP STA + * that is not associated with AP MLD). * * If the driver implements beaconing modes, it must use this function to * obtain the beacon template. @@ -5377,7 +5378,8 @@ void ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons *ema_beacons); * @tim_length: pointer to variable that will receive the TIM IE length, * (including the ID and length bytes!). * Set to 0 if invalid (in non-AP modes). - * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) + * @link_id: the link id to which the beacon belongs (or 0 for an AP STA + * that is not associated with AP MLD). * * If the driver implements beaconing modes, it must use this function to * obtain the beacon frame. @@ -5400,7 +5402,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, * ieee80211_beacon_get - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from the add_interface callback. - * @link_id: the link id to which the beacon belongs (or 0 for a non-MLD AP) + * @link_id: the link id to which the beacon belongs (or 0 for an AP STA + * that is not associated with AP MLD). * * See ieee80211_beacon_get_tim(). * -- cgit v1.2.3 From 4cacadc0dbd8013e6161aa8843d8e9d8ad435b47 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 11 Jun 2023 12:14:28 +0300 Subject: wifi: mac80211: Fix permissions for valid_links debugfs entry The entry should be a read only one and not a write only one. Fix it. Fixes: 3d9011029227 ("wifi: mac80211: implement link switching") Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230611121219.c75316990411.I1565a7fcba8a37f83efffb0cc6b71c572b896e94@changeid [remove x16 change since it doesn't work yet] Signed-off-by: Johannes Berg --- net/mac80211/debugfs_netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 3fea86c9a276..1b9293379c1e 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -720,7 +720,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD_MODE(uapsd_queues, 0600); DEBUGFS_ADD_MODE(uapsd_max_sp_len, 0600); DEBUGFS_ADD_MODE(tdls_wider_bw, 0600); - DEBUGFS_ADD_MODE(valid_links, 0200); + DEBUGFS_ADD_MODE(valid_links, 0400); DEBUGFS_ADD_MODE(active_links, 0600); } -- cgit v1.2.3 From 3f244876ef73c8ef5eaeb8f01768a2bf33c4421e Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 12 Jun 2023 18:51:02 +0300 Subject: wifi: iwlwifi: make debugfs entries link specific All of the station elements are really elements for the link. Create them from the correct callback and return the link specific information rather than always using the default link. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.a8e0c40d325e.I374d9433c3b8694667e1ce550d65f6f1f0d23c05@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 198 ++++++++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 8 +- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 9 +- 6 files changed, 169 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 84a488538427..c037b2ad5fa1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -391,13 +391,14 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf, +static ssize_t iwl_dbgfs_rs_data_read(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, + char __user *user_buf, size_t count, loff_t *ppos) { - struct ieee80211_sta *sta = file->private_data; - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->deflink.lq_sta.rs_fw; - struct iwl_mvm *mvm = lq_sta->pers.drv; + struct iwl_lq_sta_rs_fw *lq_sta = &mvm_link_sta->lq_sta.rs_fw; static const size_t bufsz = 2048; char *buff; int desc = 0; @@ -407,8 +408,6 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf, if (!buff) return -ENOMEM; - mutex_lock(&mvm->mutex); - desc += scnprintf(buff + desc, bufsz - desc, "sta_id %d\n", lq_sta->pers.sta_id); desc += scnprintf(buff + desc, bufsz - desc, @@ -429,18 +428,19 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf, lq_sta->last_rate_n_flags); if (desc < bufsz - 1) buff[desc++] = '\n'; - mutex_unlock(&mvm->mutex); ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc); kfree(buff); return ret; } -static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta, +static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, char *buf, size_t count, loff_t *ppos) { - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); int i; u16 amsdu_len; @@ -448,36 +448,39 @@ static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta, return -EINVAL; /* only change from debug set <-> debug unset */ - if (amsdu_len && mvmsta->orig_amsdu_len) + if (amsdu_len && mvm_link_sta->orig_amsdu_len) return -EBUSY; if (amsdu_len) { - mvmsta->orig_amsdu_len = sta->cur->max_amsdu_len; - sta->deflink.agg.max_amsdu_len = amsdu_len; - sta->deflink.agg.max_amsdu_len = amsdu_len; - for (i = 0; i < ARRAY_SIZE(sta->deflink.agg.max_tid_amsdu_len); i++) - sta->deflink.agg.max_tid_amsdu_len[i] = amsdu_len; + mvm_link_sta->orig_amsdu_len = link_sta->agg.max_amsdu_len; + link_sta->agg.max_amsdu_len = amsdu_len; + link_sta->agg.max_amsdu_len = amsdu_len; + for (i = 0; i < ARRAY_SIZE(link_sta->agg.max_tid_amsdu_len); i++) + link_sta->agg.max_tid_amsdu_len[i] = amsdu_len; } else { - sta->deflink.agg.max_amsdu_len = mvmsta->orig_amsdu_len; - mvmsta->orig_amsdu_len = 0; + link_sta->agg.max_amsdu_len = mvm_link_sta->orig_amsdu_len; + mvm_link_sta->orig_amsdu_len = 0; } + ieee80211_sta_recalc_aggregates(link_sta->sta); + return count; } -static ssize_t iwl_dbgfs_amsdu_len_read(struct file *file, +static ssize_t iwl_dbgfs_amsdu_len_read(struct ieee80211_link_sta *link_sta, + struct iwl_mvm_sta *mvmsta, + struct iwl_mvm *mvm, + struct iwl_mvm_link_sta *mvm_link_sta, char __user *user_buf, size_t count, loff_t *ppos) { - struct ieee80211_sta *sta = file->private_data; - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - char buf[32]; int pos; - pos = scnprintf(buf, sizeof(buf), "current %d ", sta->cur->max_amsdu_len); + pos = scnprintf(buf, sizeof(buf), "current %d ", + link_sta->agg.max_amsdu_len); pos += scnprintf(buf + pos, sizeof(buf) - pos, "stored %d\n", - mvmsta->orig_amsdu_len); + mvm_link_sta->orig_amsdu_len); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1596,17 +1599,127 @@ static ssize_t iwl_dbgfs_dbg_time_point_write(struct iwl_mvm *mvm, #define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \ MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) -#define MVM_DEBUGFS_WRITE_STA_FILE_OPS(name, bufsz) \ - _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_sta) -#define MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(name, bufsz) \ - _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_sta) +static ssize_t +_iwl_dbgfs_link_sta_wrap_write(ssize_t (*real)(struct ieee80211_link_sta *, + struct iwl_mvm_sta *, + struct iwl_mvm *, + struct iwl_mvm_link_sta *, + char *, + size_t, loff_t *), + struct file *file, + char *buf, size_t buf_size, loff_t *ppos) +{ + struct ieee80211_link_sta *link_sta = file->private_data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(link_sta->sta); + struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(mvmsta->vif)->mvm; + struct iwl_mvm_link_sta *mvm_link_sta; + ssize_t ret; -#define MVM_DEBUGFS_ADD_STA_FILE_ALIAS(alias, name, parent, mode) do { \ - debugfs_create_file(alias, mode, parent, sta, \ - &iwl_dbgfs_##name##_ops); \ - } while (0) -#define MVM_DEBUGFS_ADD_STA_FILE(name, parent, mode) \ - MVM_DEBUGFS_ADD_STA_FILE_ALIAS(#name, name, parent, mode) + mutex_lock(&mvm->mutex); + + mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_sta->link_id], + lockdep_is_held(&mvm->mutex)); + if (WARN_ON(!mvm_link_sta)) { + mutex_unlock(&mvm->mutex); + return -ENODEV; + } + + ret = real(link_sta, mvmsta, mvm, mvm_link_sta, buf, buf_size, ppos); + + mutex_unlock(&mvm->mutex); + + return ret; +} + +static ssize_t +_iwl_dbgfs_link_sta_wrap_read(ssize_t (*real)(struct ieee80211_link_sta *, + struct iwl_mvm_sta *, + struct iwl_mvm *, + struct iwl_mvm_link_sta *, + char __user *, + size_t, loff_t *), + struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + struct ieee80211_link_sta *link_sta = file->private_data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(link_sta->sta); + struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(mvmsta->vif)->mvm; + struct iwl_mvm_link_sta *mvm_link_sta; + ssize_t ret; + + mutex_lock(&mvm->mutex); + + mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_sta->link_id], + lockdep_is_held(&mvm->mutex)); + if (WARN_ON(!mvm_link_sta)) { + mutex_unlock(&mvm->mutex); + return -ENODEV; + } + + ret = real(link_sta, mvmsta, mvm, mvm_link_sta, user_buf, count, ppos); + + mutex_unlock(&mvm->mutex); + + return ret; +} + +#define MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, buflen) \ +static ssize_t _iwl_dbgfs_link_sta_##name##_write(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + char buf[buflen] = {}; \ + size_t buf_size = min(count, sizeof(buf) - 1); \ + \ + if (copy_from_user(buf, user_buf, sizeof(buf))) \ + return -EFAULT; \ + \ + return _iwl_dbgfs_link_sta_wrap_write(iwl_dbgfs_##name##_write, \ + file, \ + buf, buf_size, ppos); \ +} \ + +#define MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +static ssize_t _iwl_dbgfs_link_sta_##name##_read(struct file *file, \ + char __user *user_buf, \ + size_t count, loff_t *ppos) \ +{ \ + return _iwl_dbgfs_link_sta_wrap_read(iwl_dbgfs_##name##_read, \ + file, \ + user_buf, count, ppos); \ +} \ + +#define MVM_DEBUGFS_WRITE_LINK_STA_FILE_OPS(name, bufsz) \ +MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, bufsz) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .write = _iwl_dbgfs_link_sta_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + +#define MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(name) \ +MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .read = _iwl_dbgfs_link_sta_##name##_read, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + +#define MVM_DEBUGFS_READ_WRITE_LINK_STA_FILE_OPS(name, bufsz) \ +MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \ +MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, bufsz) \ +static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \ + .read = _iwl_dbgfs_link_sta_##name##_read, \ + .write = _iwl_dbgfs_link_sta_##name##_write, \ + .open = simple_open, \ + .llseek = generic_file_llseek, \ +} + +#define MVM_DEBUGFS_ADD_LINK_STA_FILE_ALIAS(alias, name, parent, mode) \ + debugfs_create_file(alias, mode, parent, link_sta, \ + &iwl_dbgfs_link_sta_##name##_ops) +#define MVM_DEBUGFS_ADD_LINK_STA_FILE(name, parent, mode) \ + MVM_DEBUGFS_ADD_LINK_STA_FILE_ALIAS(#name, name, parent, mode) static ssize_t iwl_dbgfs_prph_reg_read(struct file *file, @@ -1891,7 +2004,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64); MVM_DEBUGFS_READ_FILE_OPS(nic_temp); MVM_DEBUGFS_READ_FILE_OPS(stations); -MVM_DEBUGFS_READ_FILE_OPS(rs_data); +MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(rs_data); MVM_DEBUGFS_READ_FILE_OPS(bt_notif); MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); @@ -1921,7 +2034,7 @@ MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile); MVM_DEBUGFS_READ_FILE_OPS(wifi_6e_enable); #endif -MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(amsdu_len, 16); +MVM_DEBUGFS_READ_WRITE_LINK_STA_FILE_OPS(amsdu_len, 16); MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32); @@ -2068,17 +2181,18 @@ static const struct file_operations iwl_dbgfs_mem_ops = { .llseek = default_llseek, }; -void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir) +void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct dentry *dir) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); if (iwl_mvm_has_tlc_offload(mvm)) { - MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, 0400); + MVM_DEBUGFS_ADD_LINK_STA_FILE(rs_data, dir, 0400); } - MVM_DEBUGFS_ADD_STA_FILE(amsdu_len, dir, 0600); + + MVM_DEBUGFS_ADD_LINK_STA_FILE(amsdu_len, dir, 0600); } void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 91c38d42d034..f8fd34305e69 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -6255,7 +6255,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .can_aggregate_in_amsdu = iwl_mvm_mac_can_aggregate, #ifdef CONFIG_IWLWIFI_DEBUGFS - .sta_add_debugfs = iwl_mvm_sta_add_debugfs, + .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs, #endif .set_hw_timestamp = iwl_mvm_set_hw_timestamp, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index fb06cf94fcc3..5e28a1645aa9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -1093,7 +1093,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .abort_pmsr = iwl_mvm_abort_pmsr, #ifdef CONFIG_IWLWIFI_DEBUGFS - .sta_add_debugfs = iwl_mvm_sta_add_debugfs, + .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs, #endif .set_hw_timestamp = iwl_mvm_set_hw_timestamp, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 7b5db55ebe92..90cb8eeec47c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2337,10 +2337,10 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm); void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm); #ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct dentry *dir); +void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct dentry *dir); #endif /* new MLD related APIs */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index f72d1ca3cfed..e77b6157f759 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -478,7 +478,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate); } - if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) { + if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvm_link_sta->orig_amsdu_len) { u16 size = le32_to_cpu(notif->amsdu_size); int i; @@ -488,7 +488,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, * so also check with orig_amsdu_len which holds the * original data before debugfs changed the value */ - WARN_ON(mvmsta->orig_amsdu_len < size); + WARN_ON(mvm_link_sta->orig_amsdu_len < size); goto out; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 9acc01b7a4c9..7364346a1209 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -336,6 +336,9 @@ struct iwl_mvm_rxq_dup_data { * @sta_id: the index of the station in the fw * @lq_sta: holds rate scaling data, either for the case when RS is done in * the driver - %rs_drv or in the FW - %rs_fw. + * @orig_amsdu_len: used to save the original amsdu_len when it is changed via + * debugfs. If it's set to 0, it means that it is it's not set via + * debugfs. * @avg_energy: energy as reported by FW statistics notification */ struct iwl_mvm_link_sta { @@ -346,6 +349,8 @@ struct iwl_mvm_link_sta { struct iwl_lq_sta rs_drv; } lq_sta; + u16 orig_amsdu_len; + u8 avg_energy; }; @@ -375,9 +380,6 @@ struct iwl_mvm_link_sta { * @amsdu_enabled: bitmap of TX AMSDU allowed TIDs. * In case TLC offload is not active it is either 0xFFFF or 0. * @max_amsdu_len: max AMSDU length - * @orig_amsdu_len: used to save the original amsdu_len when it is changed via - * debugfs. If it's set to 0, it means that it is it's not set via - * debugfs. * @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON) * @sleeping: sta sleep transitions in power management * @sleep_tx_count: the number of frames that we told the firmware to let out @@ -429,7 +431,6 @@ struct iwl_mvm_sta { bool disable_tx; u16 amsdu_enabled; u16 max_amsdu_len; - u16 orig_amsdu_len; bool sleeping; u8 agg_tids; u8 sleep_tx_count; -- cgit v1.2.3 From 8d507812cb4bb3c3b05404a7dda70b32a1fc1324 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Mon, 12 Jun 2023 18:51:04 +0300 Subject: wifi: iwlwifi: mvm: Handle return value for iwl_mvm_sta_init sta_init function can fail and if it returns an error then driver should not send the request to fw to add a station. Fixes: 69aef848052b ("wifi: iwlwifi: mvm: refactor iwl_mvm_add_sta(), iwl_mvm_rm_sta()") Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.1ecd293539e8.I5ec6aab387bb2fe743a7402581beaeb9c801d31f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index b9b9082676d4..5e11b101d02e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1859,6 +1859,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, ret = iwl_mvm_sta_init(mvm, vif, sta, sta_id, sta->tdls ? IWL_STA_TDLS_LINK : IWL_STA_LINK); + if (ret) + goto err; update_fw: ret = iwl_mvm_sta_send_to_fw(mvm, sta, sta_update, sta_flags); -- cgit v1.2.3 From 44fa698c78543527d132cbb806b1740a0e87376a Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 12 Jun 2023 18:51:05 +0300 Subject: wifi: iwlwifi: mvm: FTM initiator MLO support When checking if the initiator is associated to the responder, iterate over all active links. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.1737f26e9cf7.I8f140ca55094da1d73c387fc036394fb2c148c85@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 48 ++++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 652a603c4500..233ae81884a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -72,15 +72,24 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * the TK is already configured for this station, so it * shouldn't be set again here. */ - if (vif->cfg.assoc && - !memcmp(addr, vif->bss_conf.bssid, ETH_ALEN)) { + if (vif->cfg.assoc) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; struct ieee80211_sta *sta; + u8 sta_id; rcu_read_lock(); - sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); - if (!IS_ERR_OR_NULL(sta) && sta->mfp) - expected_tk_len = 0; + for_each_vif_active_link(vif, link_conf, link_id) { + if (memcmp(addr, link_conf->bssid, ETH_ALEN)) + continue; + + sta_id = mvmvif->link[link_id]->ap_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); + if (!IS_ERR_OR_NULL(sta) && sta->mfp) + expected_tk_len = 0; + break; + } rcu_read_unlock(); } @@ -518,25 +527,30 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_ftm_put_target_common(mvm, peer, target); - if (vif->cfg.assoc && - !memcmp(peer->addr, vif->bss_conf.bssid, ETH_ALEN)) { + if (vif->cfg.assoc) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; rcu_read_lock(); + for_each_vif_active_link(vif, link_conf, link_id) { + if (memcmp(peer->addr, link_conf->bssid, ETH_ALEN)) + continue; + + target->sta_id = mvmvif->link[link_id]->ap_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[target->sta_id]); + if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { + rcu_read_unlock(); + return PTR_ERR_OR_ZERO(sta); + } - sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]); - if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { - rcu_read_unlock(); - return PTR_ERR_OR_ZERO(sta); + if (sta->mfp && (peer->ftm.trigger_based || + peer->ftm.non_trigger_based)) + FTM_PUT_FLAG(PMF); + break; } - - if (sta->mfp && (peer->ftm.trigger_based || peer->ftm.non_trigger_based)) - FTM_PUT_FLAG(PMF); - rcu_read_unlock(); - - target->sta_id = mvmvif->deflink.ap_sta_id; } else { target->sta_id = IWL_MVM_INVALID_STA; } -- cgit v1.2.3 From e9b63341dc15d8ee20b04e174f41873a44ca3f34 Mon Sep 17 00:00:00 2001 From: Abhishek Naik Date: Mon, 12 Jun 2023 18:51:06 +0300 Subject: wifi: iwlwifi: update response for mcc_update command Add support for the MCC update response version 8. Versions 5-6 are already covered by the existing flags conversion, and 7 isn't used. The capabilities field in iwl_mcc_update_resp is 32 bits wide now, and the flags moved, so some more changes are needed. While at it, convert the flags to bool (to avoid having to deal with BIT(16) specially etc.) and use the struct_size() macro for the memory allocation. Signed-off-by: Abhishek Naik Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.71a7070aecd7.Ibddcb9fbfa74895f742c0ac20968720691c94853@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 35 +++++- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 117 ++++++++++++++------- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/nvm.c | 63 ++++++++--- 6 files changed, 166 insertions(+), 59 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 71cce6dfeaf9..28bfabb399b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -322,7 +322,7 @@ struct iwl_mcc_update_resp_v3 { } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ /** - * struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD. + * struct iwl_mcc_update_resp_v4 - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). * The new MCC may be different than what was requested in MCC_UPDATE_CMD. @@ -338,7 +338,7 @@ struct iwl_mcc_update_resp_v3 { * @channels: channel control data map, DWORD for each channel. Only the first * 16bits are used. */ -struct iwl_mcc_update_resp { +struct iwl_mcc_update_resp_v4 { __le32 status; __le16 mcc; __le16 cap; @@ -350,6 +350,37 @@ struct iwl_mcc_update_resp { __le32 channels[]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */ +/** + * struct iwl_mcc_update_resp_v8 - response to MCC_UPDATE_CMD. + * Contains the new channel control profile map, if changed, and the new MCC + * (mobile country code). + * The new MCC may be different than what was requested in MCC_UPDATE_CMD. + * @status: see &enum iwl_mcc_update_status + * @mcc: the new applied MCC + * @padding: padding for 2 bytes. + * @cap: capabilities for all channels which matches the MCC + * @time: time elapsed from the MCC test start (in units of 30 seconds) + * @geo_info: geographic specific profile information + * see &enum iwl_geo_information. + * @source_id: the MCC source, see iwl_mcc_source + * @reserved: for four bytes alignment. + * @n_channels: number of channels in @channels_data. + * @channels: channel control data map, DWORD for each channel. Only the first + * 16bits are used. + */ +struct iwl_mcc_update_resp_v8 { + __le32 status; + __le16 mcc; + u8 padding[2]; + __le32 cap; + __le16 time; + __le16 geo_info; + u8 source_id; + u8 reserved[3]; + __le32 n_channels; + __le32 channels[]; +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_8 */ + /** * struct iwl_mcc_chub_notif - chub notifies of mcc change * (MCC_CHUB_UPDATE_CMD = 0xc9) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index cf19e8a561e9..7edb98ef8093 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -173,34 +173,34 @@ enum iwl_nvm_channel_flags { }; /** - * enum iwl_reg_capa_flags - global flags applied for the whole regulatory + * enum iwl_reg_capa_flags_v1 - global flags applied for the whole regulatory * domain. - * @REG_CAPA_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the + * @REG_CAPA_V1_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the * 2.4Ghz band is allowed. - * @REG_CAPA_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the + * @REG_CAPA_V1_BF_CCD_HIGH_BAND: Beam-forming or Cyclic Delay Diversity in the * 5Ghz band is allowed. - * @REG_CAPA_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed + * @REG_CAPA_V1_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed + * @REG_CAPA_V1_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. - * @REG_CAPA_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. - * @REG_CAPA_40MHZ_FORBIDDEN: 11n channel with a width of 40Mhz is forbidden + * @REG_CAPA_V1_MCS_8_ALLOWED: 11ac with MCS 8 is allowed. + * @REG_CAPA_V1_MCS_9_ALLOWED: 11ac with MCS 9 is allowed. + * @REG_CAPA_V1_40MHZ_FORBIDDEN: 11n channel with a width of 40Mhz is forbidden * for this regulatory domain (valid only in 5Ghz). - * @REG_CAPA_DC_HIGH_ENABLED: DC HIGH allowed. - * @REG_CAPA_11AX_DISABLED: 11ax is forbidden for this regulatory domain. + * @REG_CAPA_V1_DC_HIGH_ENABLED: DC HIGH allowed. + * @REG_CAPA_V1_11AX_DISABLED: 11ax is forbidden for this regulatory domain. */ -enum iwl_reg_capa_flags { - REG_CAPA_BF_CCD_LOW_BAND = BIT(0), - REG_CAPA_BF_CCD_HIGH_BAND = BIT(1), - REG_CAPA_160MHZ_ALLOWED = BIT(2), - REG_CAPA_80MHZ_ALLOWED = BIT(3), - REG_CAPA_MCS_8_ALLOWED = BIT(4), - REG_CAPA_MCS_9_ALLOWED = BIT(5), - REG_CAPA_40MHZ_FORBIDDEN = BIT(7), - REG_CAPA_DC_HIGH_ENABLED = BIT(9), - REG_CAPA_11AX_DISABLED = BIT(10), -}; +enum iwl_reg_capa_flags_v1 { + REG_CAPA_V1_BF_CCD_LOW_BAND = BIT(0), + REG_CAPA_V1_BF_CCD_HIGH_BAND = BIT(1), + REG_CAPA_V1_160MHZ_ALLOWED = BIT(2), + REG_CAPA_V1_80MHZ_ALLOWED = BIT(3), + REG_CAPA_V1_MCS_8_ALLOWED = BIT(4), + REG_CAPA_V1_MCS_9_ALLOWED = BIT(5), + REG_CAPA_V1_40MHZ_FORBIDDEN = BIT(7), + REG_CAPA_V1_DC_HIGH_ENABLED = BIT(9), + REG_CAPA_V1_11AX_DISABLED = BIT(10), +}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_1 */ /** * enum iwl_reg_capa_flags_v2 - global flags applied for the whole regulatory @@ -234,7 +234,31 @@ enum iwl_reg_capa_flags_v2 { REG_CAPA_V2_WEATHER_DISABLED = BIT(7), REG_CAPA_V2_40MHZ_ALLOWED = BIT(8), REG_CAPA_V2_11AX_DISABLED = BIT(10), -}; +}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_2 */ + +/** + * enum iwl_reg_capa_flags_v4 - global flags applied for the whole regulatory + * domain. + * @REG_CAPA_V4_160MHZ_ALLOWED: 11ac channel with a width of 160Mhz is allowed + * for this regulatory domain (valid only in 5Ghz). + * @REG_CAPA_V4_80MHZ_ALLOWED: 11ac channel with a width of 80Mhz is allowed + * for this regulatory domain (valid only in 5Ghz). + * @REG_CAPA_V4_MCS_12_ALLOWED: 11ac with MCS 12 is allowed. + * @REG_CAPA_V4_MCS_13_ALLOWED: 11ac with MCS 13 is allowed. + * @REG_CAPA_V4_11BE_DISABLED: 11be is forbidden for this regulatory domain. + * @REG_CAPA_V4_11AX_DISABLED: 11ax is forbidden for this regulatory domain. + * @REG_CAPA_V4_320MHZ_ALLOWED: 11be channel with a width of 320Mhz is allowed + * for this regulatory domain (valid only in 5GHz). + */ +enum iwl_reg_capa_flags_v4 { + REG_CAPA_V4_160MHZ_ALLOWED = BIT(3), + REG_CAPA_V4_80MHZ_ALLOWED = BIT(4), + REG_CAPA_V4_MCS_12_ALLOWED = BIT(5), + REG_CAPA_V4_MCS_13_ALLOWED = BIT(6), + REG_CAPA_V4_11BE_DISABLED = BIT(8), + REG_CAPA_V4_11AX_DISABLED = BIT(13), + REG_CAPA_V4_320MHZ_ALLOWED = BIT(16), +}; /* GEO_CHANNEL_CAPABILITIES_API_S_VER_4 */ /* * API v2 for reg_capa_flags is relevant from version 6 and onwards of the @@ -242,23 +266,33 @@ enum iwl_reg_capa_flags_v2 { */ #define REG_CAPA_V2_RESP_VER 6 +/* API v4 for reg_capa_flags is relevant from version 8 and onwards of the + * MCC update command response. + */ +#define REG_CAPA_V4_RESP_VER 8 + /** * struct iwl_reg_capa - struct for global regulatory capabilities, Used for * handling the different APIs of reg_capa_flags. * * @allow_40mhz: 11n channel with a width of 40Mhz is allowed - * for this regulatory domain (valid only in 5Ghz). + * for this regulatory domain. * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed - * for this regulatory domain (valid only in 5Ghz). + * for this regulatory domain (valid only in 5 and 6 Ghz). * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed - * for this regulatory domain (valid only in 5Ghz). + * for this regulatory domain (valid only in 5 and 6 Ghz). + * @allow_320mhz: 11be channel with a width of 320Mhz is allowed + * for this regulatory domain (valid only in 6 Ghz). * @disable_11ax: 11ax is forbidden for this regulatory domain. + * @disable_11be: 11be is forbidden for this regulatory domain. */ struct iwl_reg_capa { - u16 allow_40mhz; - u16 allow_80mhz; - u16 allow_160mhz; - u16 disable_11ax; + bool allow_40mhz; + bool allow_80mhz; + bool allow_160mhz; + bool allow_320mhz; + bool disable_11ax; + bool disable_11be; }; static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, @@ -1538,20 +1572,27 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, return flags; } -static struct iwl_reg_capa iwl_get_reg_capa(u16 flags, u8 resp_ver) +static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver) { - struct iwl_reg_capa reg_capa; - - if (resp_ver >= REG_CAPA_V2_RESP_VER) { + struct iwl_reg_capa reg_capa = {}; + + if (resp_ver >= REG_CAPA_V4_RESP_VER) { + reg_capa.allow_40mhz = true; + reg_capa.allow_80mhz = flags & REG_CAPA_V4_80MHZ_ALLOWED; + reg_capa.allow_160mhz = flags & REG_CAPA_V4_160MHZ_ALLOWED; + reg_capa.allow_320mhz = flags & REG_CAPA_V4_320MHZ_ALLOWED; + reg_capa.disable_11ax = flags & REG_CAPA_V4_11AX_DISABLED; + reg_capa.disable_11be = flags & REG_CAPA_V4_11BE_DISABLED; + } else if (resp_ver >= REG_CAPA_V2_RESP_VER) { reg_capa.allow_40mhz = flags & REG_CAPA_V2_40MHZ_ALLOWED; reg_capa.allow_80mhz = flags & REG_CAPA_V2_80MHZ_ALLOWED; reg_capa.allow_160mhz = flags & REG_CAPA_V2_160MHZ_ALLOWED; reg_capa.disable_11ax = flags & REG_CAPA_V2_11AX_DISABLED; } else { - reg_capa.allow_40mhz = !(flags & REG_CAPA_40MHZ_FORBIDDEN); - reg_capa.allow_80mhz = flags & REG_CAPA_80MHZ_ALLOWED; - reg_capa.allow_160mhz = flags & REG_CAPA_160MHZ_ALLOWED; - reg_capa.disable_11ax = flags & REG_CAPA_11AX_DISABLED; + reg_capa.allow_40mhz = !(flags & REG_CAPA_V1_40MHZ_FORBIDDEN); + reg_capa.allow_80mhz = flags & REG_CAPA_V1_80MHZ_ALLOWED; + reg_capa.allow_160mhz = flags & REG_CAPA_V1_160MHZ_ALLOWED; + reg_capa.disable_11ax = flags & REG_CAPA_V1_11AX_DISABLED; } return reg_capa; } @@ -1559,7 +1600,7 @@ static struct iwl_reg_capa iwl_get_reg_capa(u16 flags, u8 resp_ver) struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc, - u16 geo_info, u16 cap, u8 resp_ver) + u16 geo_info, u32 cap, u8 resp_ver) { int ch_idx; u16 ch_flags; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index e01f7751cf11..c79f72d54482 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2015, 2018-2021 Intel Corporation + * Copyright (C) 2005-2015, 2018-2022 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_nvm_parse_h__ @@ -50,7 +50,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct ieee80211_regdomain * iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, int num_of_ch, __le32 *channels, u16 fw_mcc, - u16 geo_info, u16 cap, u8 resp_ver); + u16 geo_info, u32 cap, u8 resp_ver); /** * struct iwl_nvm_section - describes an NVM section in memory. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f8fd34305e69..96577dcc22b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -108,7 +108,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, struct ieee80211_regdomain *regd = NULL; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct iwl_mcc_update_resp *resp; + struct iwl_mcc_update_resp_v8 *resp; u8 resp_ver; IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); @@ -138,7 +138,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, resp->channels, __le16_to_cpu(resp->mcc), __le16_to_cpu(resp->geo_info), - __le16_to_cpu(resp->cap), resp_ver); + le32_to_cpu(resp->cap), resp_ver); /* Store the return source id */ src_id = resp->source_id; if (IS_ERR_OR_NULL(regd)) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 90cb8eeec47c..a406ea699690 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2219,7 +2219,7 @@ static inline void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) {} #endif /* Location Aware Regulatory */ -struct iwl_mcc_update_resp * +struct iwl_mcc_update_resp_v8 * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id); int iwl_mvm_init_mcc(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index fdf60afb0f3f..f67ab8ee18c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -404,7 +404,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm) return ret < 0 ? ret : 0; } -struct iwl_mcc_update_resp * +struct iwl_mcc_update_resp_v8 * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id) { @@ -412,7 +412,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), .source_id = (u8)src_id, }; - struct iwl_mcc_update_resp *resp_cp; + struct iwl_mcc_update_resp_v8 *resp_cp; struct iwl_rx_packet *pkt; struct iwl_host_cmd cmd = { .id = MCC_UPDATE_CMD, @@ -420,7 +420,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, .data = { &mcc_update_cmd }, }; - int ret; + int ret, resp_ver; u32 status; int resp_len, n_channels; u16 mcc; @@ -439,24 +439,60 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, pkt = cmd.resp_pkt; + resp_ver = iwl_fw_lookup_notif_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, + MCC_UPDATE_CMD, 0); + /* Extract MCC response */ - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { - struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data; + if (resp_ver >= 8) { + struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (void *)pkt->data; + + n_channels = __le32_to_cpu(mcc_resp_v8->n_channels); + if (iwl_rx_packet_payload_len(pkt) != + struct_size(mcc_resp_v8, channels, n_channels)) { + resp_cp = ERR_PTR(-EINVAL); + goto exit; + } + resp_len = struct_size(resp_cp, channels, n_channels); + resp_cp = kzalloc(resp_len, GFP_KERNEL); + if (!resp_cp) { + resp_cp = ERR_PTR(-ENOMEM); + goto exit; + } + resp_cp->status = mcc_resp_v8->status; + resp_cp->mcc = mcc_resp_v8->mcc; + resp_cp->cap = mcc_resp_v8->cap; + resp_cp->source_id = mcc_resp_v8->source_id; + resp_cp->time = mcc_resp_v8->time; + resp_cp->geo_info = mcc_resp_v8->geo_info; + resp_cp->n_channels = mcc_resp_v8->n_channels; + memcpy(resp_cp->channels, mcc_resp_v8->channels, + n_channels * sizeof(__le32)); + } else if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) { + struct iwl_mcc_update_resp_v4 *mcc_resp_v4 = (void *)pkt->data; - n_channels = __le32_to_cpu(mcc_resp->n_channels); + n_channels = __le32_to_cpu(mcc_resp_v4->n_channels); if (iwl_rx_packet_payload_len(pkt) != - struct_size(mcc_resp, channels, n_channels)) { + struct_size(mcc_resp_v4, channels, n_channels)) { resp_cp = ERR_PTR(-EINVAL); goto exit; } - resp_len = sizeof(struct iwl_mcc_update_resp) + - n_channels * sizeof(__le32); - resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL); + resp_len = struct_size(resp_cp, channels, n_channels); + resp_cp = kzalloc(resp_len, GFP_KERNEL); if (!resp_cp) { resp_cp = ERR_PTR(-ENOMEM); goto exit; } + + resp_cp->status = mcc_resp_v4->status; + resp_cp->mcc = mcc_resp_v4->mcc; + resp_cp->cap = cpu_to_le32(le16_to_cpu(mcc_resp_v4->cap)); + resp_cp->source_id = mcc_resp_v4->source_id; + resp_cp->time = mcc_resp_v4->time; + resp_cp->geo_info = mcc_resp_v4->geo_info; + resp_cp->n_channels = mcc_resp_v4->n_channels; + memcpy(resp_cp->channels, mcc_resp_v4->channels, + n_channels * sizeof(__le32)); } else { struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data; @@ -466,8 +502,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_cp = ERR_PTR(-EINVAL); goto exit; } - resp_len = sizeof(struct iwl_mcc_update_resp) + - n_channels * sizeof(__le32); + resp_len = struct_size(resp_cp, channels, n_channels); resp_cp = kzalloc(resp_len, GFP_KERNEL); if (!resp_cp) { resp_cp = ERR_PTR(-ENOMEM); @@ -476,7 +511,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, resp_cp->status = mcc_resp_v3->status; resp_cp->mcc = mcc_resp_v3->mcc; - resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap); + resp_cp->cap = cpu_to_le32(mcc_resp_v3->cap); resp_cp->source_id = mcc_resp_v3->source_id; resp_cp->time = mcc_resp_v3->time; resp_cp->geo_info = mcc_resp_v3->geo_info; -- cgit v1.2.3 From ea05ef3f60e7ebdd7e50f6338942544adc4da10d Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 12 Jun 2023 18:51:07 +0300 Subject: wifi: iwlwifi: bump FW API to 79 for AX devices Start supporting API version 79 for AX devices. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.c54013425732.I4df33c68ee3ef6b6a330f1cbef7f5bbf4f54b269@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 2cf3af284680..fce4fcdc4dfb 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 78 +#define IWL_22000_UCODE_API_MAX 79 #define IWL_22500_UCODE_API_MAX 77 /* Lowest firmware API version supported */ -- cgit v1.2.3 From cda2e9d7978dadc3f5d56bef69c20e9f9e6cbb97 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Mon, 12 Jun 2023 18:51:08 +0300 Subject: wifi: iwlwifi: mvm: fix getting LDPC/STBC support Use flags field from struct ieee80211_tx_info in order to get LDPC/STBC support. The rate parameter, used originally, is 16 bits only and does not have details of LDPC/STBC support. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.5a8856739b11.I6af4a55b22ed856f484ba77f87723dceec4904f2@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 5fa6f98b8e55..ccd1e41604f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -343,9 +343,9 @@ static u32 iwl_mvm_get_inject_tx_rate(struct iwl_mvm *mvm, result |= RATE_MCS_SGI_MSK_V1; if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1); - if (rate->flags & IEEE80211_TX_CTL_LDPC) + if (info->flags & IEEE80211_TX_CTL_LDPC) result |= RATE_MCS_LDPC_MSK_V1; - if (u32_get_bits(rate->flags, IEEE80211_TX_CTL_STBC)) + if (u32_get_bits(info->flags, IEEE80211_TX_CTL_STBC)) result |= RATE_MCS_STBC_MSK; } else { return 0; -- cgit v1.2.3 From d4f1a50ca998420e27f904128a8dac5f69c291ed Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Jun 2023 18:51:10 +0300 Subject: wifi: iwlwifi: unify checks for HW error values The hardware, depending on which part fails or times out, returns 0xA5A5A5A. or 0x5A5A5A5. with the lowest 4 bits encoding some further reason/status. However, mostly we don't really need to care about the exact reasons, so unify the checks for this to avoid hardcoding those magic values all over the driver. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.3e2959741a38.I1c297a53787b87e4e2b8f296c041921338573f4d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/fw/dump.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-io.c | 4 +++- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 5 +++++ drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 6 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 3c5a43a619c6..3253d89e522a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1038,7 +1038,7 @@ iwl_dump_ini_prph_mac_iter(struct iwl_fw_runtime *fwrt, range->range_data_size = reg->dev_addr.size; for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) { prph_val = iwl_read_prph(fwrt->trans, addr + i); - if ((prph_val & ~0xf) == 0xa5a5a5a0) + if (iwl_trans_is_hw_error_value(prph_val)) return -EBUSY; *val++ = cpu_to_le32(prph_val); } @@ -1562,7 +1562,7 @@ iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt, prph_data = iwl_read_prph_no_grab(fwrt->trans, (i % 2) ? DBGI_SRAM_TARGET_ACCESS_RDATA_MSB : DBGI_SRAM_TARGET_ACCESS_RDATA_LSB); - if ((prph_data & ~0xf) == 0xa5a5a5a0) { + if (iwl_trans_is_hw_error_value(prph_data)) { iwl_trans_release_nic_access(fwrt->trans); return -EBUSY; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index f86f7b4baa18..64e83f30f947 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -194,7 +194,7 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu /* check if there is a HW error */ val = iwl_trans_read_mem32(trans, base); - if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) { + if (iwl_trans_is_hw_error_value(val)) { int err; IWL_ERR(trans, "HW error, resetting before reading\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 396f2c997da6..c60f9466c5fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2003-2014, 2018-2021 Intel Corporation + * Copyright (C) 2003-2014, 2018-2022 Intel Corporation * Copyright (C) 2015-2016 Intel Deutschland GmbH */ #include @@ -72,6 +72,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) return value; } + /* return as if we have a HW timeout/failure */ return 0x5a5a5a5a; } IWL_EXPORT_SYMBOL(iwl_read_direct32); @@ -143,6 +144,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) return val; } + /* return as if we have a HW timeout/failure */ return 0x5a5a5a5a; } IWL_EXPORT_SYMBOL(iwl_read_prph); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index d9e465d0f4af..1fa035decc03 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1613,6 +1613,11 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, int iwl_trans_init(struct iwl_trans *trans); void iwl_trans_free(struct iwl_trans *trans); +static inline bool iwl_trans_is_hw_error_value(u32 val) +{ + return ((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50); +} + /***************************************************** * driver (transport) register/unregister functions ******************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 0d7890f99a5f..4ee4886babcb 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1873,7 +1873,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) return IRQ_NONE; } - if (unlikely(inta == 0xFFFFFFFF || (inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + if (unlikely(inta == 0xFFFFFFFF || iwl_trans_is_hw_error_value(inta))) { /* * Hardware disappeared. It might have * already raised an interrupt. diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 15419397ac73..7240beca6419 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1788,7 +1788,7 @@ static int iwl_trans_pcie_clear_persistence_bit(struct iwl_trans *trans) } hpm = iwl_read_umac_prph_no_grab(trans, HPM_DEBUG); - if (hpm != 0xa5a5a5a0 && (hpm & PERSISTENCE_BIT)) { + if (!iwl_trans_is_hw_error_value(hpm) && (hpm & PERSISTENCE_BIT)) { u32 wprot_val = iwl_read_umac_prph_no_grab(trans, wprot); if (wprot_val & PREG_WFPM_ACCESS) { -- cgit v1.2.3 From 2b69d242e29b891b11f1190201f4a08abb0c8342 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Mon, 12 Jun 2023 18:51:11 +0300 Subject: wifi: iwlwifi: fw: print PC register value instead of address The program counter address is read from the TLV and PC address is printed in debug messages. Read the value at PC address and print the value instead of the register address. Fixes: 5e31b3df86ec ("wifi: iwlwifi: dbg: print pc register data once fw dump occurred") Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.e5a5f18f1b2c.Ib6117a4e7f66a075913241cc81477c0059953d5d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dump.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index 64e83f30f947..23388261e97f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -507,11 +507,16 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) iwl_fwrt_dump_fseq_regs(fwrt); if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { pc_data = fwrt->trans->dbg.pc_data; + + if (!iwl_trans_grab_nic_access(fwrt->trans)) + return; for (count = 0; count < fwrt->trans->dbg.num_pc; count++, pc_data++) IWL_ERR(fwrt, "%s: 0x%x\n", pc_data->pc_name, - pc_data->pc_address); + iwl_read_prph_no_grab(fwrt->trans, + pc_data->pc_address)); + iwl_trans_release_nic_access(fwrt->trans); } if (fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { -- cgit v1.2.3 From af8bfc7e38a7ad4f8e1663de7ab1463e644050b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Jun 2023 18:51:12 +0300 Subject: wifi: iwlwifi: mvm: always set MH len in offload_assist Some versions of the new hardware don't have a functional version of the new offload method, but still have stricter checks on the MAC header (MH) length in the offload assist word. Include that even if checksumming isn't offloaded to hardware. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.bba713f7495a.Idbc8e3ce313b51af4060326e0191bd338b3163a2@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ccd1e41604f3..547694c89ffa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -44,9 +44,9 @@ static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_tx_info *info, bool amsdu) { struct ieee80211_hdr *hdr = (void *)skb->data; + u16 mh_len = ieee80211_hdrlen(hdr->frame_control); u16 offload_assist = 0; #if IS_ENABLED(CONFIG_INET) - u16 mh_len = ieee80211_hdrlen(hdr->frame_control); u8 protocol = 0; /* Do not compute checksum if already computed */ @@ -118,6 +118,8 @@ static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb, else udp_hdr(skb)->check = 0; +out: +#endif /* * mac header len should include IV, size is in words unless * the IV is added by the firmware like in WEP. @@ -130,8 +132,6 @@ static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb, mh_len /= 2; offload_assist |= mh_len << TX_CMD_OFFLD_MH_SIZE; -out: -#endif if (amsdu) offload_assist |= BIT(TX_CMD_OFFLD_AMSDU); else if (ieee80211_hdrlen(hdr->frame_control) % 4) -- cgit v1.2.3 From a114c4f5f9ca94e79d2ddf67f318d831cf87faf2 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Mon, 12 Jun 2023 18:51:13 +0300 Subject: wifi: iwlwifi: debugfs: add ppag capa to fw info file Add information about ppag_china_bit_support capability. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.4655922aff4d.Ie934027940bd53d05124222aa6a8a8b7021952c4@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/debugfs.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index 607e07ed2477..ebacf0e9fb0f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -354,9 +354,18 @@ static int iwl_dbgfs_fw_info_seq_show(struct seq_file *seq, void *v) const struct iwl_fw *fw = priv->fwrt->fw; const struct iwl_fw_cmd_version *ver; u32 cmd_id; - - if (!state->pos) + int has_capa; + + if (!state->pos) { + seq_puts(seq, "fw_capa:\n"); + has_capa = fw_has_capa(&fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT) ? 1 : 0; + seq_printf(seq, + " %d: %d\n", + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT, + has_capa); seq_puts(seq, "fw_api_ver:\n"); + } ver = &fw->ucode_capa.cmd_versions[state->pos]; -- cgit v1.2.3 From 6107f300132bb3ff6a22add4a29980ed6ea929a1 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 12 Jun 2023 18:51:14 +0300 Subject: wifi: iwlwifi: pass ESR parameters to the firmware The firmware needs to know the esr_transtition_timeout to time the transition between EMLSR and single radio with the AP. Add the EMLSR support bit to the wiphy extended capabilities so that it'll be sent in our association request frame. There are some limitations in the implementation so we cannot use zero padding/transition delay; fill the correct values. Also, feed the medium_synchronization delay to the firmware. Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.09fa06820d03.Ie9a9fd37d4948f8c5dd91161de254184b1a093c0@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 11 ++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c | 12 ++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index a4cb24934a01..184db5a6f06f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -236,7 +236,7 @@ struct iwl_mac_low_latency_cmd { * Available only from version 2 of the command. * This values comes from the EMLSR transition delay in the EML * Capabilities subfield. - * @reserved: alignment + * @medium_sync_delay: the value as it appeasr in P802.11be_D2.2 Figure 9-1002j. * @assoc_id: unique ID assigned by the AP during association * @reserved1: alignment * @data_policy: see &enum iwl_mac_data_policy @@ -247,7 +247,7 @@ struct iwl_mac_low_latency_cmd { struct iwl_mac_client_data { u8 is_assoc; u8 esr_transition_timeout; - __le16 reserved; + __le16 medium_sync_delay; __le16 assoc_id; __le16 reserved1; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 96577dcc22b7..f7e2ca7eebf0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -245,12 +245,21 @@ static const u8 tm_if_types_ext_capa_sta[] = { /* Additional interface types for which extended capabilities are * specified separately */ + +#define IWL_MVM_EMLSR_CAPA (IEEE80211_EML_CAP_EMLSR_SUPP | \ + IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US << \ + __bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \ + IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \ + __bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY)) + static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { { .iftype = NL80211_IFTYPE_STATION, .extended_capabilities = he_if_types_ext_capa_sta, .extended_capabilities_mask = he_if_types_ext_capa_sta, .extended_capabilities_len = sizeof(he_if_types_ext_capa_sta), + /* relevant only if EHT is supported */ + .eml_capabilities = IWL_MVM_EMLSR_CAPA, }, { .iftype = NL80211_IFTYPE_STATION, @@ -258,7 +267,7 @@ static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { .extended_capabilities_mask = tm_if_types_ext_capa_sta, .extended_capabilities_len = sizeof(tm_if_types_ext_capa_sta), /* relevant only if EHT is supported */ - .eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP, + .eml_capabilities = IWL_MVM_EMLSR_CAPA, }, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 99bf71a2b690..0ff99deb0ae7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -96,6 +96,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, u32 action, bool force_assoc_off) { struct iwl_mac_config_cmd cmd = {}; + u16 esr_transition_timeout; WARN_ON(vif->type != NL80211_IFTYPE_STATION); @@ -133,6 +134,17 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, } cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid); + if (ieee80211_vif_is_mld(vif)) { + esr_transition_timeout = + u16_get_bits(vif->cfg.eml_cap, + IEEE80211_EML_CAP_TRANSITION_TIMEOUT); + + cmd.client.esr_transition_timeout = + min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU, + esr_transition_timeout); + cmd.client.medium_sync_delay = + cpu_to_le16(vif->cfg.eml_med_sync_delay); + } if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p) cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ); -- cgit v1.2.3 From fd940de72d493c4bb1c4368ff0f87663492e5645 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 12 Jun 2023 18:51:15 +0300 Subject: wifi: iwlwifi: mvm: FTM responder MLO support Add a link configuration parameter to FTM responder start instead of using the default link. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.b367f9bd19b8.I158c71998f39a6c15463ff5ae30129da8ad46d22@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/ftm-responder.c | 23 ++++++++++++---------- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++++-- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c index 1b6fb73ddfc7..b49781d1a07a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c @@ -104,7 +104,8 @@ iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm *mvm, static int iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct cfg80211_chan_def *chandef) + struct cfg80211_chan_def *chandef, + struct ieee80211_bss_conf *link_conf) { u32 cmd_id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_CONFIG_CMD); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -119,7 +120,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | IWL_TOF_RESPONDER_CMD_VALID_BSSID | IWL_TOF_RESPONDER_CMD_VALID_STA_ID), - .sta_id = mvmvif->deflink.bcast_sta.sta_id, + .sta_id = mvmvif->link[link_conf->link_id]->bcast_sta.sta_id, }; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 6); int err; @@ -386,7 +387,8 @@ int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm, return -EINVAL; } -int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_ftm_responder_params *params; @@ -395,11 +397,11 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_phy_ctxt *phy_ctxt; int ret; - params = vif->bss_conf.ftmr_params; + params = bss_conf->ftmr_params; lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder)) + if (WARN_ON_ONCE(!bss_conf->ftm_responder)) return -EINVAL; if (vif->p2p || vif->type != NL80211_IFTYPE_AP || @@ -409,7 +411,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } rcu_read_lock(); - pctx = rcu_dereference(vif->bss_conf.chanctx_conf); + pctx = rcu_dereference(bss_conf->chanctx_conf); /* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care * about changes in the ctx after releasing the lock because the driver * is still protected by the mutex. */ @@ -424,7 +426,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (ret) return ret; - ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def); + ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def, bss_conf); if (ret) return ret; @@ -446,13 +448,14 @@ void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm, } void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) { - if (!vif->bss_conf.ftm_responder) + if (!bss_conf->ftm_responder) return; iwl_mvm_ftm_responder_clear(mvm, vif); - iwl_mvm_ftm_start_responder(mvm, vif); + iwl_mvm_ftm_start_responder(mvm, vif, bss_conf); } void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f7e2ca7eebf0..bf78b7df4700 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2890,7 +2890,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (iwl_mvm_phy_ctx_count(mvm) > 1) iwl_mvm_teardown_tdls_peers(mvm); - iwl_mvm_ftm_restart_responder(mvm, vif); + iwl_mvm_ftm_restart_responder(mvm, vif, &vif->bss_conf); goto out_unlock; @@ -3032,7 +3032,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm, IWL_WARN(mvm, "Failed updating beacon data\n"); if (changes & BSS_CHANGED_FTM_RESPONDER) { - int ret = iwl_mvm_ftm_start_responder(mvm, vif); + int ret = iwl_mvm_ftm_start_responder(mvm, vif, &vif->bss_conf); if (ret) IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 5e28a1645aa9..ff99bf91f931 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -422,7 +422,7 @@ static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw, if (iwl_mvm_phy_ctx_count(mvm) > 1) iwl_mvm_teardown_tdls_peers(mvm); - iwl_mvm_ftm_restart_responder(mvm, vif); + iwl_mvm_ftm_restart_responder(mvm, vif, link_conf); goto out_unlock; @@ -711,7 +711,7 @@ iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm, /* FIXME: need to decide if we need FTM responder per link */ if (changes & BSS_CHANGED_FTM_RESPONDER) { - int ret = iwl_mvm_ftm_start_responder(mvm, vif); + int ret = iwl_mvm_ftm_start_responder(mvm, vif, link_conf); if (ret) IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index a406ea699690..143c79f62cfd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2239,9 +2239,11 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool added_vif); /* FTM responder */ -int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf); void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf); void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm, -- cgit v1.2.3 From a3ff9303b496b29bf182481d152a5efbb57a630e Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 12 Jun 2023 18:51:16 +0300 Subject: wifi: iwlwifi: mvm: Propagate ERP slot changes to FW In AP mode, ERP slot changes weren't properly indicated to the FW. Fix it. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230612184434.ef242b8ce245.I01eddee9d3a9a3208499c223eb8e70fe6663f42c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index ff99bf91f931..cb4df8c6f9de 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -697,7 +697,11 @@ iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm, if (link_conf->he_support) link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS; - if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT | + if (changes & BSS_CHANGED_ERP_SLOT) + link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO; + + if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_SLOT | + BSS_CHANGED_HT | BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS | BSS_CHANGED_HE_BSS_COLOR) && iwl_mvm_link_changed(mvm, vif, link_conf, -- cgit v1.2.3 From 0ffe85885b31ac0308bb13a31eec6a441e2a2d77 Mon Sep 17 00:00:00 2001 From: Azeem Shaikh Date: Mon, 12 Jun 2023 23:23:01 +0000 Subject: wifi: cfg80211: replace strlcpy() with strscpy() strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated [1]. In an effort to remove strlcpy() completely [2], replace strlcpy() here with strscpy(). Direct replacement is safe here since WIPHY_ASSIGN is only used by TRACE macros and the return values are ignored. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [2] https://github.com/KSPP/linux/issues/89 Signed-off-by: Azeem Shaikh Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230612232301.2572316-1-azeemshaikh38@gmail.com Signed-off-by: Johannes Berg --- net/wireless/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 716a1fa70069..a00da3ebfed5 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -22,7 +22,7 @@ #define MAXNAME 32 #define WIPHY_ENTRY __array(char, wiphy_name, 32) -#define WIPHY_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(wiphy), MAXNAME) +#define WIPHY_ASSIGN strscpy(__entry->wiphy_name, wiphy_name(wiphy), MAXNAME) #define WIPHY_PR_FMT "%s" #define WIPHY_PR_ARG __entry->wiphy_name -- cgit v1.2.3 From f3c21ed9ce17438b9b6fb4a959640c486cabda24 Mon Sep 17 00:00:00 2001 From: Azeem Shaikh Date: Tue, 13 Jun 2023 00:34:04 +0000 Subject: wifi: mac80211: Replace strlcpy with strscpy strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated [1]. In an effort to remove strlcpy() completely [2], replace strlcpy() here with strscpy(). Direct replacement is safe here since LOCAL_ASSIGN is only used by TRACE macros and the return values are ignored. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [2] https://github.com/KSPP/linux/issues/89 Signed-off-by: Azeem Shaikh Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20230613003404.3538524-1-azeemshaikh38@gmail.com Signed-off-by: Johannes Berg --- net/mac80211/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index e5edf6fe576f..b8c53b4a710b 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -17,7 +17,7 @@ #define MAXNAME 32 #define LOCAL_ENTRY __array(char, wiphy_name, 32) -#define LOCAL_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME) +#define LOCAL_ASSIGN strscpy(__entry->wiphy_name, wiphy_name(local->hw.wiphy), MAXNAME) #define LOCAL_PR_FMT "%s" #define LOCAL_PR_ARG __entry->wiphy_name -- cgit v1.2.3 From 557b56d523d597a415ddfa27860259fcc835356c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Jun 2023 15:57:14 +0300 Subject: wifi: iwlwifi: mvm: support U-SIG EHT validate checks Support new firmware that can validate the validate bits in sniffer mode, and advertise that fact and the result of the checks in the U-SIG radiotap field. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.c20480aa1171.Icc0d077dae01d662ccb948823e196aa9c5c87976@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 9 +++++++++ include/net/ieee80211_radiotap.h | 2 ++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 67af922fd3ba..25e2e23dce3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -292,7 +292,7 @@ enum iwl_rx_phy_he_data0 { /* TSF overload low dword */ enum iwl_rx_phy_eht_data0 { /* info type: EHT any */ - /* 1 bits reserved */ + IWL_RX_PHY_DATA0_EHT_VALIDATE = BIT(0), IWL_RX_PHY_DATA0_EHT_UPLINK = BIT(1), IWL_RX_PHY_DATA0_EHT_BSS_COLOR_MASK = 0x000000fc, IWL_RX_PHY_DATA0_ETH_SPATIAL_REUSE_MASK = 0x00000f00, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index a78b68c2ae3d..1a4f7c04ebae 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -467,6 +467,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT = (__force iwl_ucode_tlv_capa_t)112, IWL_UCODE_TLV_CAPA_OFFLOAD_REJ_BTM_SUPPORT = (__force iwl_ucode_tlv_capa_t)113, IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT = (__force iwl_ucode_tlv_capa_t)114, + IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT = (__force iwl_ucode_tlv_capa_t)116, #ifdef __CHECKER__ /* sparse says it cannot increment the previous enum member */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 89ab440ad377..70db4fef6290 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1773,6 +1773,15 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT)) { + usig->common |= + cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED); + usig->common |= + LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_VALIDATE, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); + } + eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE); eht->data[0] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_ETH_SPATIAL_REUSE_MASK, diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index f980a72f2ce6..c4722a9963de 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -535,6 +535,8 @@ enum ieee80211_radiotap_eht_usig_common { IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN = 0x00000008, IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN = 0x00000010, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC = 0x00000020, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED = 0x00000040, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK = 0x00000080, IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER = 0x00007000, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW = 0x00038000, IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL = 0x00040000, -- cgit v1.2.3 From e9f5ce3471d824039069c740f4fb4de36dd2eccb Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Tue, 13 Jun 2023 15:57:15 +0300 Subject: wifi: iwlwifi: mvm: rename BTM support flag and its TLV Currently, we only need to support BTM rejection. However, in the future we might want to support other BTM modes. Rephrase its naming. Signed-off-by: Haim Dreyfuss Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.ad20f10668d1.Icbb3fbae50b2302b97225b183dd336b02a4f37ee@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/d3.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/offloading.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 37ac2364e714..380eeb2363c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -47,14 +47,14 @@ struct iwl_d3_manager_config { * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled * @IWL_D3_PROTO_IPV4_VALID: IPv4 data is valid * @IWL_D3_PROTO_IPV6_VALID: IPv6 data is valid - * @IWL_D3_PROTO_REJECT_BTM: reject BTM request + * @IWL_D3_PROTO_OFFLOAD_BTM: BTM offload is enabled */ enum iwl_proto_offloads { IWL_D3_PROTO_OFFLOAD_ARP = BIT(0), IWL_D3_PROTO_OFFLOAD_NS = BIT(1), IWL_D3_PROTO_IPV4_VALID = BIT(2), IWL_D3_PROTO_IPV6_VALID = BIT(3), - IWL_D3_PROTO_REJECT_BTM = BIT(4), + IWL_D3_PROTO_OFFLOAD_BTM = BIT(4), }; #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 1a4f7c04ebae..b36e9613a52c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -465,7 +465,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT = (__force iwl_ucode_tlv_capa_t)110, IWL_UCODE_TLV_CAPA_SCAN_DONT_TOGGLE_ANT = (__force iwl_ucode_tlv_capa_t)111, IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT = (__force iwl_ucode_tlv_capa_t)112, - IWL_UCODE_TLV_CAPA_OFFLOAD_REJ_BTM_SUPPORT = (__force iwl_ucode_tlv_capa_t)113, + IWL_UCODE_TLV_CAPA_OFFLOAD_BTM_SUPPORT = (__force iwl_ucode_tlv_capa_t)113, IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT = (__force iwl_ucode_tlv_capa_t)114, IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT = (__force iwl_ucode_tlv_capa_t)116, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index 797b1f70937e..dfb16ca5b438 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -199,8 +199,8 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, } if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_OFFLOAD_REJ_BTM_SUPPORT)) - enabled |= IWL_D3_PROTO_REJECT_BTM; + IWL_UCODE_TLV_CAPA_OFFLOAD_BTM_SUPPORT)) + enabled |= IWL_D3_PROTO_OFFLOAD_BTM; if (!disable_offloading) common->enabled = cpu_to_le32(enabled); -- cgit v1.2.3 From 97110233c0af777ce6d6c25541cd7fd86e309ecc Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Tue, 13 Jun 2023 15:57:16 +0300 Subject: wifi: iwlwifi: mvm: initialize the rx_vec before using it Initialize the phy_data.rx_vec for both version-3 and above where it is 4-byte data size and below version which has data size of 2-byte. The data will be sent uninitialized in called function if notification version is less than three. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.a6bb856f04bc.I9a15075f3dad61dcabdcd1ed0d34cf3e8ec5453f@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 70db4fef6290..9d8d9def9391 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -2642,6 +2642,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK); phy_data.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK); phy_data.with_data = false; + phy_data.rx_vec[0] = desc->rx_vec[0]; + phy_data.rx_vec[1] = desc->rx_vec[1]; if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, RX_NO_DATA_NOTIF, 0) < 2) { @@ -2660,7 +2662,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, sizeof(struct iwl_rx_no_data_ver_3))) /* invalid len for ver 3 */ return; - memcpy(phy_data.rx_vec, desc->rx_vec, sizeof(phy_data.rx_vec)); + phy_data.rx_vec[2] = desc->rx_vec[2]; + phy_data.rx_vec[3] = desc->rx_vec[3]; } else { if (format == RATE_MCS_EHT_MSK) /* no support for EHT before version 3 API */ -- cgit v1.2.3 From ff75c21c20b10855d68c95543400951252bf796e Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 13 Jun 2023 15:57:17 +0300 Subject: wifi: iwlwifi: improve debug prints in iwl_read_ppag_table() Add prints of ETSI and China bits. Check if need to mask the China bit (when the firmware doesn't support it) in a separate flow, so it will be easier to follow the conditions. Add a separate message for the command version. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.4ee455ec1ee8.I6f1a4b7dfa5cfd9b4f4a4b5bb5567849e629ae96@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 37 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 018d820ae231..4e4048310f0f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -1169,41 +1169,48 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c */ cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); + IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver); if (cmd_ver == 1) { num_sub_bands = IWL_NUM_SUB_BANDS_V1; gain = cmd->v1.gain[0]; *cmd_size = sizeof(cmd->v1); if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) { + /* in this case FW supports revision 0 */ IWL_DEBUG_RADIO(fwrt, - "PPAG table rev is %d but FW supports v1, sending truncated table\n", + "PPAG table rev is %d, send truncated table\n", fwrt->ppag_ver); - if (!fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) { - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); - IWL_DEBUG_RADIO(fwrt, - "FW doesn't support ppag China bit\n"); - } else { - IWL_DEBUG_RADIO(fwrt, - "FW supports ppag China bit\n"); - } } } else if (cmd_ver >= 2 && cmd_ver <= 4) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; gain = cmd->v2.gain[0]; *cmd_size = sizeof(cmd->v2); if (fwrt->ppag_ver == 0) { + /* in this case FW supports revisions 1 or 2 */ IWL_DEBUG_RADIO(fwrt, - "PPAG table is v1 but FW supports v2, sending padded table\n"); - } else if (cmd_ver == 2 && fwrt->ppag_ver == 2) { - IWL_DEBUG_RADIO(fwrt, - "PPAG table is v3 but FW supports v2, sending partial bitmap.\n"); - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); + "PPAG table rev is 0, send padded table\n"); } } else { IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); return -EINVAL; } + /* ppag mode */ + IWL_DEBUG_RADIO(fwrt, + "PPAG MODE bits were read from bios: %d\n", + cmd->v1.flags & cpu_to_le32(ACPI_PPAG_MASK)); + if ((cmd_ver == 1 && !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || + (cmd_ver == 2 && fwrt->ppag_ver == 2)) { + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); + IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); + } else { + IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); + } + + IWL_DEBUG_RADIO(fwrt, + "PPAG MODE bits going to be sent: %d\n", + cmd->v1.flags & cpu_to_le32(ACPI_PPAG_MASK)); + for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { for (j = 0; j < num_sub_bands; j++) { gain[i * num_sub_bands + j] = -- cgit v1.2.3 From d51439a6d79fd251b0d92fa8b1aa3bd4cb17d102 Mon Sep 17 00:00:00 2001 From: Ariel Malamud Date: Tue, 13 Jun 2023 15:57:18 +0300 Subject: wifi: iwlwifi: mvm: Refactor iwl_mvm_get_lmac_id() The iwl_mvm_get_lmac_id() function is currently defined as a static inline function under fw/api and receives mvm's fw pointer. It will need the ability to access other mvm struct members for future capabilities such as debug. Move the function out of the fw/api and into mvm proper as a regular function and have it receive the pointer to mvm. Signed-off-by: Ariel Malamud Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.507b2f9f64eb.I0ec91310e1911c33faf396b5e17bcb11a164f6ea@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/binding.h | 8 -------- drivers/net/wireless/intel/iwlwifi/mvm/binding.c | 10 +++++++++- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 +- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h index b6b5959cb259..d9044ada6a43 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h @@ -59,14 +59,6 @@ struct iwl_binding_cmd { #define IWL_LMAC_24G_INDEX 0 #define IWL_LMAC_5G_INDEX 1 -static inline u32 iwl_mvm_get_lmac_id(const struct iwl_fw *fw, - enum nl80211_band band){ - if (!fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT) || - band == NL80211_BAND_2GHZ) - return IWL_LMAC_24G_INDEX; - return IWL_LMAC_5G_INDEX; -} - /* The maximal number of fragments in the FW's schedule session */ #define IWL_MVM_MAX_QUOTA 128 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c index ef50ccabcc73..458b97930059 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c @@ -32,7 +32,7 @@ static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action, if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) { size = sizeof(cmd); - cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw, + cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm, phyctxt->channel->band)); } else { size = IWL_BINDING_CMD_SIZE_V1; @@ -164,3 +164,11 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return ret; } + +u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band) +{ + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT) || + band == NL80211_BAND_2GHZ) + return IWL_LMAC_24G_INDEX; + return IWL_LMAC_5G_INDEX; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index bf78b7df4700..f1c7d0bef609 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4595,7 +4595,7 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, switch (vif->type) { case NL80211_IFTYPE_STATION: - lmac_id = iwl_mvm_get_lmac_id(mvm->fw, channel->band); + lmac_id = iwl_mvm_get_lmac_id(mvm, channel->band); /* Use aux roc framework (HS20) */ ret = ops->add_aux_sta_for_hs20(mvm, lmac_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 143c79f62cfd..b04631195535 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1841,6 +1841,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, /* Bindings */ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band); /* Links */ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 3ab6fb83a175..55541e90770a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -151,7 +151,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { - cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw, + cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm, chandef->chan->band)); /* Set the channel info data */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 547694c89ffa..bacc3045ea16 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -896,7 +896,7 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, band = mvmsta->vif->bss_conf.chandef.chan->band; } - lmac = iwl_mvm_get_lmac_id(mvm->fw, band); + lmac = iwl_mvm_get_lmac_id(mvm, band); } else if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) { /* for real MLO restrict to both LMACs if they exist */ -- cgit v1.2.3 From 18c0ffb404db2093b6afdc8ae15f18ba3975e1ed Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 13 Jun 2023 15:57:19 +0300 Subject: wifi: iwlwifi: mvm: add support for Extra EHT LTF Add support for Extra EHT LTF defined in 9.4.2.313 EHT Capabilities element. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.de019d7cc174.I806f0f6042b89274192701a60b4f7900822db666@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/rs.h | 2 ++ drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 15 +++++++++++++++ include/linux/ieee80211.h | 1 + 4 files changed, 20 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index c9a48fc5fac8..a1a272433b09 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -21,6 +21,7 @@ * @IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK: enable HE Dual Carrier Modulation * for BPSK (MCS 0) with 2 spatial * streams + * @IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK: enable support for EHT extra LTF */ enum iwl_tlc_mng_cfg_flags { IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0), @@ -28,6 +29,7 @@ enum iwl_tlc_mng_cfg_flags { IWL_TLC_MNG_CFG_FLAGS_HE_STBC_160MHZ_MSK = BIT(2), IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK = BIT(3), IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK = BIT(4), + IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK = BIT(6), }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 7edb98ef8093..fad71f490313 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1012,6 +1012,8 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, iftype_data->eht_cap.eht_cap_elem.phy_cap_info[6] &= ~(IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP); + iftype_data->eht_cap.eht_cap_elem.phy_cap_info[5] |= + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF; } if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_BROADCAST_TWT)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index e77b6157f759..7c6eff4fa58a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -591,6 +591,21 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, int cmd_ver; int ret; + /* Enable external EHT LTF only for GL device and if there's + * mutual support by AP and client + */ + if (CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && + sband->iftype_data->eht_cap.has_eht && + sband->iftype_data->eht_cap.eht_cap_elem.phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF && + link_sta->eht_cap.has_eht && + link_sta->eht_cap.eht_cap_elem.phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF) { + IWL_DEBUG_RATE(mvm, "Set support for Extra EHT LTF\n"); + cfg_cmd.flags |= + cpu_to_le16(IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK); + } + rcu_read_lock(); mvm_link_sta = rcu_dereference(mvmsta->link[link_id]); if (WARN_ON_ONCE(!mvm_link_sta)) { diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 516cd32d6196..5dfed1a6625c 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2859,6 +2859,7 @@ ieee80211_he_spr_size(const u8 *he_spr_ie) /* Maximum number of supported EHT LTF is split */ #define IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK 0xc0 +#define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x40 #define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x07 #define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x78 -- cgit v1.2.3 From 9c5608b3643e99ad03c4a99e88842f2a3ce7f1e0 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Tue, 13 Jun 2023 15:57:20 +0300 Subject: wifi: iwlwifi: support version C0 of BZ and GL devices Add support for C0 version of MAC and RF for BZ and GL devices. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.90ad8aab8a03.I86d1675095f0e4f5286d9b7c2b00a0220f524472@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 27 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 14 +++++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index fce4fcdc4dfb..29dded1531a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -65,9 +65,12 @@ #define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-" #define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0-" #define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0-" +#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0-" #define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0-" #define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-" #define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0-" +#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0-" + #define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" #define IWL_BNJ_A_FM_A_FW_PRE "iwlwifi-BzBnj-a0-fm-a0-" #define IWL_BNJ_A_FM4_A_FW_PRE "iwlwifi-BzBnj-a0-fm4-a0-" @@ -153,12 +156,16 @@ IWL_BZ_A_FM4_A_FW_PRE __stringify(api) ".ucode" #define IWL_BZ_A_FM_B_MODULE_FIRMWARE(api) \ IWL_BZ_A_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_FM_C_MODULE_FIRMWARE(api) \ + IWL_BZ_A_FM_C_FW_PRE __stringify(api) ".ucode" #define IWL_BZ_A_FM4_B_MODULE_FIRMWARE(api) \ IWL_BZ_A_FM4_B_FW_PRE __stringify(api) ".ucode" #define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode" #define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \ IWL_GL_B_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_GL_C_FM_C_MODULE_FIRMWARE(api) \ + IWL_GL_C_FM_C_FW_PRE __stringify(api) ".ucode" #define IWL_BNJ_A_FM_A_MODULE_FIRMWARE(api) \ IWL_BNJ_A_FM_A_FW_PRE __stringify(api) ".ucode" #define IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(api) \ @@ -173,6 +180,7 @@ IWL_BNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" #define IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(api) \ IWL_BNJ_B_GF4_A_FW_PRE __stringify(api) ".ucode" + #define IWL_BNJ_A_HR_A_MODULE_FIRMWARE(api) \ IWL_BNJ_A_HR_A_FW_PRE __stringify(api) ".ucode" #define IWL_BNJ_A_HR_B_MODULE_FIRMWARE(api) \ @@ -1053,6 +1061,14 @@ const struct iwl_cfg iwl_cfg_bz_a0_fm_b0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_bz_a0_fm_c0 = { + .fw_name_pre = IWL_BZ_A_FM_C_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0 = { .fw_name_pre = IWL_BZ_A_FM4_B_FW_PRE, .uhb_supported = true, @@ -1077,6 +1093,14 @@ const struct iwl_cfg iwl_cfg_gl_b0_fm_b0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_gl_c0_fm_c0 = { + .fw_name_pre = IWL_GL_C_FM_C_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = { .fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE, .uhb_supported = true, @@ -1180,6 +1204,7 @@ const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = { .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, .num_rbds = IWL_NUM_RBDS_AX210_HE, }; + MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); @@ -1214,6 +1239,7 @@ MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_MR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BNJ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); @@ -1228,4 +1254,5 @@ MODULE_FIRMWARE(IWL_BNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BNJ_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 411b7d4fcc9a..17c357634455 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -658,9 +658,11 @@ extern const struct iwl_cfg iwl_cfg_bz_a0_mr_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm_b0; +extern const struct iwl_cfg iwl_cfg_bz_a0_fm_c0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0; extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_gl_b0_fm_b0; +extern const struct iwl_cfg iwl_cfg_gl_c0_fm_c0; extern const struct iwl_cfg iwl_cfg_bz_z0_gf_a0; extern const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index dba112394838..fcc0f3319bcd 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1198,12 +1198,17 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, iwl_cfg_bz_a0_fm_b0, iwl_bz_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + iwl_cfg_bz_a0_fm_c0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET, iwl_cfg_bz_a0_fm4_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, @@ -1215,6 +1220,11 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, iwl_cfg_gl_b0_fm_b0, iwl_bz_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_GL, SILICON_C_STEP, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + iwl_cfg_gl_c0_fm_c0, iwl_bz_name), /* BZ Z step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, -- cgit v1.2.3 From 637452360ecde9ac972d19416e9606529576b302 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 13 Jun 2023 15:57:21 +0300 Subject: wifi: iwlwifi: mvm: fix potential array out of bounds access Account for IWL_SEC_WEP_KEY_OFFSET when needed while verifying key_len size in iwl_mvm_sec_key_add(). Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.f193b7493a93.I6948ba625b9318924b96a5e22602ac75d2bd0125@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index 3e6f86f644b5..995c0e01b331 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022 - 2023 Intel Corporation */ #include #include @@ -175,9 +175,14 @@ int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags, .u.add.key_flags = cpu_to_le32(key_flags), .u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)), }; + int max_key_len = sizeof(cmd.u.add.key); int ret; - if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key))) + if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || + keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) + max_key_len -= IWL_SEC_WEP_KEY_OFFSET; + + if (WARN_ON(keyconf->keylen > max_key_len)) return -EINVAL; if (WARN_ON(!sta_mask)) -- cgit v1.2.3 From d615ea32f62042c3484520dca648f5120fb1035a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Jun 2023 15:57:22 +0300 Subject: wifi: iwlwifi: mvm: put only a single IGTK into FW The firmware only supports a single IGTK, and due to some changes it really doesn't like to have multiple programmed in later versions. Since only newer firmware cannot remove a key that isn't present any more, adjust only the MLD API code to keep track of the previous IGTK and remove it when a new one is added. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.3fde1ef09270.I2e12a3b0bba4325c07dc8fcce39b711f158bd621@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 63 ++++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 +- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f1c7d0bef609..8267ff08e38d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1038,6 +1038,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; mvmvif->link[link_id]->phy_ctxt = NULL; mvmvif->link[link_id]->active = 0; + mvmvif->link[link_id]->igtk = NULL; } probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index 995c0e01b331..b27f6a70f8d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -231,8 +231,49 @@ int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, { u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *mvm_link = NULL; + int ret; + + if (keyconf->keyidx == 4 || keyconf->keyidx == 5) { + unsigned int link_id = 0; + + /* set to -1 for non-MLO right now */ + if (keyconf->link_id >= 0) + link_id = keyconf->link_id; + + mvm_link = mvmvif->link[link_id]; + if (WARN_ON(!mvm_link)) + return -EINVAL; + + if (mvm_link->igtk) { + IWL_DEBUG_MAC80211(mvm, "remove old IGTK %d\n", + mvm_link->igtk->keyidx); + ret = iwl_mvm_sec_key_del(mvm, vif, sta, + mvm_link->igtk); + if (ret) + IWL_ERR(mvm, + "failed to remove old IGTK (ret=%d)\n", + ret); + } + + WARN_ON(mvm_link->igtk); + } + + ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf); + if (ret) + return ret; + + if (mvm_link) + mvm_link->igtk = keyconf; - return iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf); + /* We don't really need this, but need it to be not invalid, + * and if we switch links multiple times it might go to be + * invalid when removed. + */ + keyconf->hw_key_idx = 0; + + return 0; } static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm, @@ -243,11 +284,31 @@ static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm, { u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; if (WARN_ON(!sta_mask)) return -EINVAL; + if (keyconf->keyidx == 4 || keyconf->keyidx == 5) { + struct iwl_mvm_vif_link_info *mvm_link; + unsigned int link_id = 0; + + /* set to -1 for non-MLO right now */ + if (keyconf->link_id >= 0) + link_id = keyconf->link_id; + + mvm_link = mvmvif->link[link_id]; + if (WARN_ON(!mvm_link)) + return -EINVAL; + + if (mvm_link->igtk == keyconf) { + /* no longer in HW - mark for later */ + mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID; + mvm_link->igtk = NULL; + } + } + ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx, flags); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b04631195535..95efab52cdc2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -300,6 +300,7 @@ struct iwl_probe_resp_data { * @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked * @queue_params: QoS params for this MAC * @mgmt_queue: queue number for unbufferable management frames + * @igtk: the current IGTK programmed into the firmware */ struct iwl_mvm_vif_link_info { u8 bssid[ETH_ALEN]; @@ -317,6 +318,8 @@ struct iwl_mvm_vif_link_info { enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ]; struct iwl_probe_resp_data __rcu *probe_resp_data; + struct ieee80211_key_conf *igtk; + bool he_ru_2mhz_block; bool active; -- cgit v1.2.3 From 1724fc781ffe6e1e44dfe25c3a27e19db42dc0ff Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 13 Jun 2023 15:57:23 +0300 Subject: wifi: iwlwifi: mvm: allow ADD_STA not to be advertised by the firwmare Newest firmware don't advertise the version of ADD_STA because it has been replaced by another command. There are old firmware images that also don't advertise it. Replace all the checks with a new inline, and in that check for either MLD API or the ADD_STA command version. Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.4b9305510223.I7cc143d87186f8441e9b8435cc550b76734c7eef@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 6 +++--- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 10 +++++----- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 4 ++-- 6 files changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index d1a559c4c6b9..ed9370aac1b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1637,7 +1637,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) * internal aux station for all aux activities that don't * requires a dedicated data queue. */ - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { + if (!iwl_mvm_has_new_station_api(mvm->fw)) { /* * In old version the aux station uses mac id like other * station and not lmac id @@ -1806,7 +1806,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL); } - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { + if (!iwl_mvm_has_new_station_api(mvm->fw)) { /* * Add auxiliary station for scanning. * Newer versions of this command implies that the fw uses diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 8267ff08e38d..ee838dd60f4e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1243,7 +1243,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) /* async_handlers_wk is now blocked */ - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) + if (!iwl_mvm_has_new_station_api(mvm->fw)) iwl_mvm_rm_aux_sta(mvm); iwl_mvm_stop_device(mvm); @@ -4521,7 +4521,7 @@ static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id) return -EINVAL; } - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12) { + if (iwl_mvm_has_new_station_api(mvm->fw)) { ret = iwl_mvm_add_aux_sta(mvm, lmac_id); WARN(ret, "Failed to allocate aux station"); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 95efab52cdc2..b452c35443d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1433,6 +1433,12 @@ static inline bool iwl_mvm_has_mld_api(const struct iwl_fw *fw) IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT); } +static inline bool iwl_mvm_has_new_station_api(const struct iwl_fw *fw) +{ + return iwl_mvm_has_mld_api(fw) || + iwl_fw_lookup_cmd_ver(fw, ADD_STA, 0) >= 12; +} + static inline bool iwl_mvm_has_new_tx_api(struct iwl_mvm *mvm) { /* TODO - replace with TLV once defined */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 175615755d9d..d7ac9ddbcfba 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -647,7 +647,7 @@ static void iwl_mvm_scan_fill_tx_cmd(struct iwl_mvm *mvm, NL80211_BAND_2GHZ, no_cck); - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { + if (!iwl_mvm_has_new_station_api(mvm->fw)) { tx_cmd[0].sta_id = mvm->aux_sta.sta_id; tx_cmd[1].sta_id = mvm->aux_sta.sta_id; @@ -1084,7 +1084,7 @@ static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config, memcpy(&cfg->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); /* This function should not be called when using ADD_STA ver >=12 */ - WARN_ON_ONCE(iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12); + WARN_ON_ONCE(iwl_mvm_has_new_station_api(mvm->fw)); cfg->bcast_sta_id = mvm->aux_sta.sta_id; cfg->channel_flags = channel_flags; @@ -1135,7 +1135,7 @@ static void iwl_mvm_fill_scan_config_v2(struct iwl_mvm *mvm, void *config, memcpy(&cfg->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); /* This function should not be called when using ADD_STA ver >=12 */ - WARN_ON_ONCE(iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12); + WARN_ON_ONCE(iwl_mvm_has_new_station_api(mvm->fw)); cfg->bcast_sta_id = mvm->aux_sta.sta_id; cfg->channel_flags = channel_flags; @@ -1250,7 +1250,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) memset(&cfg, 0, sizeof(cfg)); - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) { + if (!iwl_mvm_has_new_station_api(mvm->fw)) { cfg.bcast_sta_id = mvm->aux_sta.sta_id; } else if (iwl_fw_lookup_cmd_ver(mvm->fw, SCAN_CFG_CMD, 0) < 5) { /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 5e11b101d02e..ff1ce990a9d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2015, 2018-2022 Intel Corporation + * Copyright (C) 2012-2015, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1679,7 +1679,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, memset(&cmd, 0, sizeof(cmd)); cmd.sta_id = sta->sta_id; - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12 && + if (iwl_mvm_has_new_station_api(mvm->fw) && sta->type == IWL_STA_AUX_ACTIVITY) cmd.mac_id_n_color = cpu_to_le32(mac_id); else diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 6b7b6250f1bb..5f0e7144a951 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -103,7 +103,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) /* In newer version of this command an aux station is added only * in cases of dedicated tx queue and need to be removed in end * of use */ - if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12) + if (iwl_mvm_has_new_station_api(mvm->fw)) iwl_mvm_rm_aux_sta(mvm); } -- cgit v1.2.3 From c2a2f505e0bcb45052131d173504887041e1faae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Jun 2023 15:57:24 +0300 Subject: wifi: iwlwifi: dbg-tlv: fix DRAM data init Given the existing code in iwl_dbg_tlv_update_drams(), the following can happen and cause firmware asserts, and even the device to become unusable: * We set the magic so the firmware will use the data; * we try to fill multiple allocation IDs, with at least one successful, but - crucially - one failing and thus not touching the data; * we don't clear the data since there was one success. This doesn't seem like much of a problem just yet, however, what happens now is that the allocation ID(s) that failed are not initialized. There are two additional things to know: * we never free these allocations across FW restart or interface down/up etc., in fact we never free them until the driver is unbound from the device (e.g. unloaded) * the firmware uses the DRAM info structure for real debug data when it has used it completely Given that, and the fact that we never initialize the data on restart, we can be unlucky and end up with an allocation that looks for the most part valid (valid ID, valid number of buffers, etc.) but has bad sizes - causing the firmware to throw an assert we can never recover from. Fixing the code to have the entire buffers cleared (which we should do so old debug data isn't sticking around) is a bit more complex, so as a first step make the actual code that fills the information more robust by clearing the structure first, and filling the magic values only if it actually succeeded for one, rather than doing it the other way around. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.87cf5528f4bc.I26ac907a4162297808b33467fc7f5d8177474a34@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index fb0277bd12cf..3f9d4670f6c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include #include "iwl-drv.h" @@ -795,8 +795,7 @@ static void iwl_dbg_tlv_update_drams(struct iwl_fw_runtime *fwrt) IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT)) return; - dram_info->first_word = cpu_to_le32(DRAM_INFO_FIRST_MAGIC_WORD); - dram_info->second_word = cpu_to_le32(DRAM_INFO_SECOND_MAGIC_WORD); + memset(dram_info, 0, sizeof(*dram_info)); for (i = IWL_FW_INI_ALLOCATION_ID_DBGC1; i < IWL_FW_INI_ALLOCATION_NUM; i++) { @@ -813,11 +812,10 @@ static void iwl_dbg_tlv_update_drams(struct iwl_fw_runtime *fwrt) i, ret); } - if (dram_alloc) - IWL_DEBUG_FW(fwrt, "block data after %08x\n", - dram_info->first_word); - else - memset(frags->block, 0, sizeof(*dram_info)); + if (dram_alloc) { + dram_info->first_word = cpu_to_le32(DRAM_INFO_FIRST_MAGIC_WORD); + dram_info->second_word = cpu_to_le32(DRAM_INFO_SECOND_MAGIC_WORD); + } } static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt, -- cgit v1.2.3 From 583c58e3b1fa3718c52a5cbba2176cc30688c53c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Jun 2023 15:57:25 +0300 Subject: wifi: iwlwifi: pcie: clear FW debug memory on init When we restart the firmware, we shouldn't keep old debug data around. Since the "allocate" function might not reallocate the memory block (it's only freed when we unbind from the device), clear the memory to have a clean slate for debug data. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.73c32255a132.Ibd7101dcd285b01ee879fddfbf52c30d49ced3c0@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 7240beca6419..84e832fdfa83 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2007-2015, 2018-2022 Intel Corporation + * Copyright (C) 2007-2015, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -171,8 +171,10 @@ static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, u32 size = 0; u8 power; - if (fw_mon->size) + if (fw_mon->size) { + memset(fw_mon->block, 0, fw_mon->size); return; + } for (power = max_power; power >= min_power; power--) { size = BIT(power); @@ -215,9 +217,6 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) max_power)) return; - if (trans->dbg.fw_mon.size) - return; - iwl_pcie_alloc_fw_monitor_block(trans, max_power, 11); } -- cgit v1.2.3 From 855e2f60fe341a4fd1f9343ed07d6e7fd05ab3f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Jun 2023 15:57:26 +0300 Subject: wifi: iwlwifi: pcie: remove redundant argument The iwl_pcie_alloc_fw_monitor_block() function has an argument that's only ever hard-coded to 11, remove it and hard-code the value into the function itself with a comment. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.737c153e8259.Ibe6250ca812cfa2f00ac47e5e0d1595c6b9b4875@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 84e832fdfa83..3e88bbdb1f82 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -163,7 +163,7 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) } static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, - u8 max_power, u8 min_power) + u8 max_power) { struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; void *block = NULL; @@ -176,7 +176,8 @@ static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, return; } - for (power = max_power; power >= min_power; power--) { + /* need at least 2 KiB, so stop at 11 */ + for (power = max_power; power >= 11; power--) { size = BIT(power); block = dma_alloc_coherent(trans->dev, size, &physical, GFP_KERNEL | __GFP_NOWARN); @@ -217,7 +218,7 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) max_power)) return; - iwl_pcie_alloc_fw_monitor_block(trans, max_power, 11); + iwl_pcie_alloc_fw_monitor_block(trans, max_power); } static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) -- cgit v1.2.3 From 93ae81454b1107843ad36dcdc457dd10ee0f2cbe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 13 Jun 2023 15:57:27 +0300 Subject: wifi: iwlwifi: dbg-tlv: clear FW debug memory on init When we restart the firmware, we shouldn't keep old debug data around. Since the "allocate" function might not reallocate the memory blocks (they're only freed when we unbind from the device), clear the memory to have a clean slate for debug data. This is a bit more complex since we normally don't enter into the allocation function, but duplicating the logic didn't seem enticing either, so rework the allocation a bit to always go into the individual block allocation, but there clear if it's already allocated, rather than allocating again. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230613155501.30b82881cfbf.I39520aff8ac95ee64d39dc5913525a1efd7995fa@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 35 ++++++++++++++++-------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 3f9d4670f6c6..ef5baee6c9c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -586,8 +586,14 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt, fw_mon_cfg = &fwrt->trans->dbg.fw_mon_cfg[alloc_id]; fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; - if (fw_mon->num_frags || - fw_mon_cfg->buf_location != + if (fw_mon->num_frags) { + for (i = 0; i < fw_mon->num_frags; i++) + memset(fw_mon->frags[i].block, 0, + fw_mon->frags[i].size); + return 0; + } + + if (fw_mon_cfg->buf_location != cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH)) return 0; @@ -1272,18 +1278,23 @@ static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) int ret, i; u32 failed_alloc = 0; - if (*ini_dest != IWL_FW_INI_LOCATION_INVALID) - return; - - IWL_DEBUG_FW(fwrt, - "WRT: Generating active triggers list, domain 0x%x\n", - fwrt->trans->dbg.domains_bitmap); + if (*ini_dest == IWL_FW_INI_LOCATION_INVALID) { + IWL_DEBUG_FW(fwrt, + "WRT: Generating active triggers list, domain 0x%x\n", + fwrt->trans->dbg.domains_bitmap); - for (i = 0; i < ARRAY_SIZE(fwrt->trans->dbg.time_point); i++) { - struct iwl_dbg_tlv_time_point_data *tp = - &fwrt->trans->dbg.time_point[i]; + for (i = 0; i < ARRAY_SIZE(fwrt->trans->dbg.time_point); i++) { + struct iwl_dbg_tlv_time_point_data *tp = + &fwrt->trans->dbg.time_point[i]; - iwl_dbg_tlv_gen_active_trig_list(fwrt, tp); + iwl_dbg_tlv_gen_active_trig_list(fwrt, tp); + } + } else if (*ini_dest != IWL_FW_INI_LOCATION_DRAM_PATH) { + /* For DRAM, go through the loop below to clear all the buffers + * properly on restart, otherwise garbage may be left there and + * leak into new debug dumps. + */ + return; } *ini_dest = IWL_FW_INI_LOCATION_INVALID; -- cgit v1.2.3 From e0db883b6949bd0b5b221893e30afd5f838783b1 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:00 +0200 Subject: mlxsw: spectrum_router: Extract a helper from mlxsw_sp_port_vlan_router_join() Split out of mlxsw_sp_port_vlan_router_join() the part that checks for RIF and dispatches to __mlxsw_sp_port_vlan_router_join(), leaving it as wrapper that just manages the router lock. The new function, mlxsw_sp_port_vlan_router_join_existing(), will be useful as an atom in later patches. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index f9328e8410f5..0edda06e92bb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8562,24 +8562,35 @@ __mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) mlxsw_sp_rif_subport_put(rif); } +static int +mlxsw_sp_port_vlan_router_join_existing(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, + struct net_device *l3_dev, + struct netlink_ext_ack *extack) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port_vlan->mlxsw_sp_port->mlxsw_sp; + + lockdep_assert_held(&mlxsw_sp->router->lock); + + if (!mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev)) + return 0; + + return __mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan, l3_dev, + extack); +} + int mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct net_device *l3_dev, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port_vlan->mlxsw_sp_port->mlxsw_sp; - struct mlxsw_sp_rif *rif; - int err = 0; + int err; mutex_lock(&mlxsw_sp->router->lock); - rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); - if (!rif) - goto out; - - err = __mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan, l3_dev, - extack); -out: + err = mlxsw_sp_port_vlan_router_join_existing(mlxsw_sp_port_vlan, + l3_dev, extack); mutex_unlock(&mlxsw_sp->router->lock); + return err; } -- cgit v1.2.3 From 76962b802efe27a32425d2abe818e53167c71dbe Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:01 +0200 Subject: mlxsw: spectrum_router: Add a helper specifically for joining a LAG Currently, joining a LAG very simply means that the LAG RIF should be joined by the subport representing untagged traffic. If the RIF does not exist, it does not have to be created: if the user wants there to be RIF for the LAG device, they are supposed to add an IP address, and they are supposed to do it after tha LAG becomes mlxsw upper. We can also assume that the LAG has no uppers, otherwise the enslavement is not allowed. In the future, these ordering dependencies should be removed. That means that joining LAG will be more complex operation, possibly involving a lazy RIF creation, and possibly joining / lazily creating RIFs for VLAN uppers of the LAG. It will be handy to have a dedicated function that handles all this. The new function mlxsw_sp_router_port_join_lag() is that. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 +- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 4 -- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 56 +++++++++++++++------- .../net/ethernet/mellanox/mlxsw/spectrum_router.h | 3 ++ 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 4609b13bda02..25a01dafde1b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4337,8 +4337,8 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan); /* Join a router interface configured on the LAG, if exists */ - err = mlxsw_sp_port_vlan_router_join(mlxsw_sp_port->default_vlan, - lag_dev, extack); + err = mlxsw_sp_router_port_join_lag(mlxsw_sp_port, lag_dev, + extack); if (err) goto err_router_join; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 0b57c8d0cce0..231e364cbb7c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -755,10 +755,6 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp, const struct net_device *macvlan_dev); -int -mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, - struct net_device *l3_dev, - struct netlink_ext_ack *extack); void mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 0edda06e92bb..2c3dcbc2f9a6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8578,22 +8578,6 @@ mlxsw_sp_port_vlan_router_join_existing(struct mlxsw_sp_port_vlan *mlxsw_sp_port extack); } -int -mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, - struct net_device *l3_dev, - struct netlink_ext_ack *extack) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port_vlan->mlxsw_sp_port->mlxsw_sp; - int err; - - mutex_lock(&mlxsw_sp->router->lock); - err = mlxsw_sp_port_vlan_router_join_existing(mlxsw_sp_port_vlan, - l3_dev, extack); - mutex_unlock(&mlxsw_sp->router->lock); - - return err; -} - void mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { @@ -9278,6 +9262,46 @@ mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, return err; } +static int +mlxsw_sp_port_vid_router_join_existing(struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid, struct net_device *dev, + struct netlink_ext_ack *extack) +{ + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, + vid); + if (WARN_ON(!mlxsw_sp_port_vlan)) + return -EINVAL; + + return mlxsw_sp_port_vlan_router_join_existing(mlxsw_sp_port_vlan, + dev, extack); +} + +static int __mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *lag_dev, + struct netlink_ext_ack *extack) +{ + u16 default_vid = MLXSW_SP_DEFAULT_VID; + + return mlxsw_sp_port_vid_router_join_existing(mlxsw_sp_port, + default_vid, lag_dev, + extack); +} + +int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *lag_dev, + struct netlink_ext_ack *extack) +{ + int err; + + mutex_lock(&mlxsw_sp_port->mlxsw_sp->router->lock); + err = __mlxsw_sp_router_port_join_lag(mlxsw_sp_port, lag_dev, extack); + mutex_unlock(&mlxsw_sp_port->mlxsw_sp->router->lock); + + return err; +} + static int mlxsw_sp_router_netdevice_event(struct notifier_block *nb, unsigned long event, void *ptr) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index 5ff443f27136..5a0babc614b4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -170,5 +170,8 @@ int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp); struct net_device * mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev); +int mlxsw_sp_router_port_join_lag(struct mlxsw_sp_port *mlxsw_sp_port, + struct net_device *lag_dev, + struct netlink_ext_ack *extack); #endif /* _MLXSW_ROUTER_H_*/ -- cgit v1.2.3 From fb6ac45e86668456e5750d2a1c874ca2f5526171 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:02 +0200 Subject: mlxsw: spectrum_router: Access rif->dev through a helper In order to abstract away deduction of netdevice from the corresponding RIF, introduce a helper, mlxsw_sp_rif_dev(), and use it throughout. This will make it possible to change the deduction path easily later on. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 109 ++++++++++++--------- 1 file changed, 64 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 2c3dcbc2f9a6..e9183c223575 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -71,6 +71,11 @@ struct mlxsw_sp_rif { bool counter_egress_valid; }; +static struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif) +{ + return rif->dev; +} + struct mlxsw_sp_rif_params { struct net_device *dev; union { @@ -1560,6 +1565,7 @@ mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, u16 ul_vr_id, u16 ul_rif_id, bool enable) { struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config; + struct net_device *dev = mlxsw_sp_rif_dev(&lb_rif->common); enum mlxsw_reg_ritr_loopback_ipip_options ipip_options; struct mlxsw_sp_rif *rif = &lb_rif->common; struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; @@ -1572,7 +1578,7 @@ mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, u16 ul_vr_id, case MLXSW_SP_L3_PROTO_IPV4: saddr4 = be32_to_cpu(lb_cf.saddr.addr4); mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF, - rif->rif_index, rif->vr_id, rif->dev->mtu); + rif->rif_index, rif->vr_id, dev->mtu); mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt, ipip_options, ul_vr_id, ul_rif_id, saddr4, @@ -1582,7 +1588,7 @@ mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif, u16 ul_vr_id, case MLXSW_SP_L3_PROTO_IPV6: saddr6 = &lb_cf.saddr.addr6; mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF, - rif->rif_index, rif->vr_id, rif->dev->mtu); + rif->rif_index, rif->vr_id, dev->mtu); mlxsw_reg_ritr_loopback_ipip6_pack(ritr_pl, lb_cf.lb_ipipt, ipip_options, ul_vr_id, ul_rif_id, saddr6, @@ -2332,7 +2338,7 @@ static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp, } dipn = htonl(dip); - dev = mlxsw_sp->router->rifs[rif]->dev; + dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]); n = neigh_lookup(&arp_tbl, &dipn, dev); if (!n) return; @@ -2360,7 +2366,7 @@ static void mlxsw_sp_router_neigh_ent_ipv6_process(struct mlxsw_sp *mlxsw_sp, return; } - dev = mlxsw_sp->router->rifs[rif]->dev; + dev = mlxsw_sp_rif_dev(mlxsw_sp->router->rifs[rif]); n = neigh_lookup(&nd_tbl, &dip, dev); if (!n) return; @@ -4368,6 +4374,7 @@ static void mlxsw_sp_nexthop4_event(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp_nexthop *nh; bool removing; @@ -4377,7 +4384,7 @@ static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, removing = false; break; case MLXSW_SP_NEXTHOP_TYPE_IPIP: - removing = !mlxsw_sp_ipip_netdev_ul_up(rif->dev); + removing = !mlxsw_sp_ipip_netdev_ul_up(dev); break; default: WARN_ON(1); @@ -7798,7 +7805,7 @@ mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, struct net_device *dev, return true; if (rif && addr_list_empty && - !netif_is_l3_slave(rif->dev)) + !netif_is_l3_slave(mlxsw_sp_rif_dev(rif))) return true; /* It is possible we already removed the RIF ourselves * if it was assigned to a netdev that is now a bridge @@ -7895,7 +7902,8 @@ u16 mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb *lb_rif) u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif) { - u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(lb_rif->common.dev); + struct net_device *dev = mlxsw_sp_rif_dev(&lb_rif->common); + u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(dev); struct mlxsw_sp_vr *ul_vr; ul_vr = mlxsw_sp_vr_get(lb_rif->common.mlxsw_sp, ul_tb_id, NULL); @@ -8072,12 +8080,7 @@ mlxsw_sp_router_hwstats_notify_schedule(struct net_device *dev) int mlxsw_sp_rif_dev_ifindex(const struct mlxsw_sp_rif *rif) { - return rif->dev->ifindex; -} - -static const struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif) -{ - return rif->dev; + return mlxsw_sp_rif_dev(rif)->ifindex; } bool mlxsw_sp_rif_has_dev(const struct mlxsw_sp_rif *rif) @@ -8096,7 +8099,7 @@ static void mlxsw_sp_rif_push_l3_stats(struct mlxsw_sp_rif *rif) struct rtnl_hw_stats64 stats = {}; if (!mlxsw_sp_router_port_l3_stats_fetch(rif, &stats)) - netdev_offload_xstats_push_delta(rif->dev, + netdev_offload_xstats_push_delta(mlxsw_sp_rif_dev(rif), NETDEV_OFFLOAD_XSTATS_TYPE_L3, &stats); } @@ -8198,6 +8201,7 @@ err_rif_index_alloc: static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); const struct mlxsw_sp_rif_ops *ops = rif->ops; struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; struct mlxsw_sp_fid *fid = rif->fid; @@ -8210,11 +8214,10 @@ static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); vr = &mlxsw_sp->router->vrs[rif->vr_id]; - if (netdev_offload_xstats_enabled(rif->dev, - NETDEV_OFFLOAD_XSTATS_TYPE_L3)) { + if (netdev_offload_xstats_enabled(dev, NETDEV_OFFLOAD_XSTATS_TYPE_L3)) { mlxsw_sp_rif_push_l3_stats(rif); mlxsw_sp_router_port_l3_stats_disable(rif); - mlxsw_sp_router_hwstats_notify_schedule(rif->dev); + mlxsw_sp_router_hwstats_notify_schedule(dev); } else { mlxsw_sp_rif_counters_free(rif); } @@ -8226,7 +8229,7 @@ static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) /* Loopback RIFs are not associated with a FID. */ mlxsw_sp_fid_put(fid); mlxsw_sp->router->rifs[rif->rif_index] = NULL; - dev_put(rif->dev); + dev_put(dev); kfree(rif); mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries); vr->rif_count--; @@ -9012,7 +9015,7 @@ mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif, struct netlink_ext_ack *extack) { - struct net_device *dev = rif->dev; + struct net_device *dev = mlxsw_sp_rif_dev(rif); u8 old_mac_profile; u16 fid_index; int err; @@ -9348,15 +9351,16 @@ static int __mlxsw_sp_rif_macvlan_flush(struct net_device *dev, static int mlxsw_sp_rif_macvlan_flush(struct mlxsw_sp_rif *rif) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); struct netdev_nested_priv priv = { .data = (void *)rif, }; - if (!netif_is_macvlan_port(rif->dev)) + if (!netif_is_macvlan_port(dev)) return 0; - netdev_warn(rif->dev, "Router interface is deleted. Upper macvlans will not work\n"); - return netdev_walk_all_upper_dev_rcu(rif->dev, + netdev_warn(dev, "Router interface is deleted. Upper macvlans will not work\n"); + return netdev_walk_all_upper_dev_rcu(dev, __mlxsw_sp_rif_macvlan_flush, &priv); } @@ -9377,6 +9381,7 @@ static void mlxsw_sp_rif_subport_setup(struct mlxsw_sp_rif *rif, static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; struct mlxsw_sp_rif_subport *rif_subport; char ritr_pl[MLXSW_REG_RITR_LEN]; @@ -9384,8 +9389,8 @@ static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable) rif_subport = mlxsw_sp_rif_subport_rif(rif); mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF, - rif->rif_index, rif->vr_id, rif->dev->mtu); - mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr); + rif->rif_index, rif->vr_id, dev->mtu); + mlxsw_reg_ritr_mac_pack(ritr_pl, dev->dev_addr); mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id); efid = mlxsw_sp_fid_index(rif->fid); mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag, @@ -9398,6 +9403,7 @@ static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable) static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif, struct netlink_ext_ack *extack) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); u8 mac_profile; int err; @@ -9411,7 +9417,7 @@ static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif, if (err) goto err_rif_subport_op; - err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(rif->fid), true); if (err) goto err_rif_fdb_op; @@ -9423,7 +9429,7 @@ static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif, return 0; err_fid_rif_set: - mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(rif->fid), false); err_rif_fdb_op: mlxsw_sp_rif_subport_op(rif, false); @@ -9434,10 +9440,11 @@ err_rif_subport_op: static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp_fid *fid = rif->fid; mlxsw_sp_fid_rif_unset(fid); - mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(fid), false); mlxsw_sp_rif_macvlan_flush(rif); mlxsw_sp_rif_subport_op(rif, false); @@ -9463,12 +9470,13 @@ static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = { static int mlxsw_sp_rif_fid_op(struct mlxsw_sp_rif *rif, u16 fid, bool enable) { enum mlxsw_reg_ritr_if_type type = MLXSW_REG_RITR_FID_IF; + struct net_device *dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; char ritr_pl[MLXSW_REG_RITR_LEN]; mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id, - rif->dev->mtu); - mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr); + dev->mtu); + mlxsw_reg_ritr_mac_pack(ritr_pl, dev->dev_addr); mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id); mlxsw_reg_ritr_fid_if_fid_set(ritr_pl, fid); @@ -9483,6 +9491,7 @@ u16 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif, struct netlink_ext_ack *extack) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; u16 fid_index = mlxsw_sp_fid_index(rif->fid); u8 mac_profile; @@ -9508,7 +9517,7 @@ static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif, if (err) goto err_fid_bc_flood_set; - err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(rif->fid), true); if (err) goto err_rif_fdb_op; @@ -9520,7 +9529,7 @@ static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif, return 0; err_fid_rif_set: - mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(rif->fid), false); err_rif_fdb_op: mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, @@ -9537,12 +9546,13 @@ err_rif_fid_op: static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); u16 fid_index = mlxsw_sp_fid_index(rif->fid); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; struct mlxsw_sp_fid *fid = rif->fid; mlxsw_sp_fid_rif_unset(fid); - mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(fid), false); mlxsw_sp_rif_macvlan_flush(rif); mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, @@ -9557,7 +9567,9 @@ static struct mlxsw_sp_fid * mlxsw_sp_rif_fid_fid_get(struct mlxsw_sp_rif *rif, struct netlink_ext_ack *extack) { - return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif->dev->ifindex); + int rif_ifindex = mlxsw_sp_rif_dev_ifindex(rif); + + return mlxsw_sp_fid_8021d_get(rif->mlxsw_sp, rif_ifindex); } static void mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) @@ -9565,7 +9577,7 @@ static void mlxsw_sp_rif_fid_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) struct switchdev_notifier_fdb_info info = {}; struct net_device *dev; - dev = br_fdb_find_port(rif->dev, mac, 0); + dev = br_fdb_find_port(mlxsw_sp_rif_dev(rif), mac, 0); if (!dev) return; @@ -9588,17 +9600,18 @@ static struct mlxsw_sp_fid * mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif, struct netlink_ext_ack *extack) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); struct net_device *br_dev; u16 vid; int err; - if (is_vlan_dev(rif->dev)) { - vid = vlan_dev_vlan_id(rif->dev); - br_dev = vlan_dev_real_dev(rif->dev); + if (is_vlan_dev(dev)) { + vid = vlan_dev_vlan_id(dev); + br_dev = vlan_dev_real_dev(dev); if (WARN_ON(!netif_is_bridge_master(br_dev))) return ERR_PTR(-EINVAL); } else { - err = br_vlan_get_pvid(rif->dev, &vid); + err = br_vlan_get_pvid(dev, &vid); if (err < 0 || !vid) { NL_SET_ERR_MSG_MOD(extack, "Couldn't determine bridge PVID"); return ERR_PTR(-EINVAL); @@ -9610,12 +9623,13 @@ mlxsw_sp_rif_vlan_fid_get(struct mlxsw_sp_rif *rif, static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) { + struct net_device *rif_dev = mlxsw_sp_rif_dev(rif); struct switchdev_notifier_fdb_info info = {}; u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); struct net_device *br_dev; struct net_device *dev; - br_dev = is_vlan_dev(rif->dev) ? vlan_dev_real_dev(rif->dev) : rif->dev; + br_dev = is_vlan_dev(rif_dev) ? vlan_dev_real_dev(rif_dev) : rif_dev; dev = br_fdb_find_port(br_dev, mac, vid); if (!dev) return; @@ -9629,11 +9643,12 @@ static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac) static int mlxsw_sp_rif_vlan_op(struct mlxsw_sp_rif *rif, u16 vid, u16 efid, bool enable) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; char ritr_pl[MLXSW_REG_RITR_LEN]; mlxsw_reg_ritr_vlan_if_pack(ritr_pl, enable, rif->rif_index, rif->vr_id, - rif->dev->mtu, rif->dev->dev_addr, + dev->mtu, dev->dev_addr, rif->mac_profile_id, vid, efid); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); @@ -9642,6 +9657,7 @@ static int mlxsw_sp_rif_vlan_op(struct mlxsw_sp_rif *rif, u16 vid, u16 efid, static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif, u16 efid, struct netlink_ext_ack *extack) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; u8 mac_profile; @@ -9667,7 +9683,7 @@ static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif, u16 efid, if (err) goto err_fid_bc_flood_set; - err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(rif->fid), true); if (err) goto err_rif_fdb_op; @@ -9679,7 +9695,7 @@ static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif, u16 efid, return 0; err_fid_rif_set: - mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(rif->fid), false); err_rif_fdb_op: mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, @@ -9696,11 +9712,12 @@ err_rif_vlan_fid_op: static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif) { + struct net_device *dev = mlxsw_sp_rif_dev(rif); u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; mlxsw_sp_fid_rif_unset(rif->fid); - mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr, + mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, dev->dev_addr, mlxsw_sp_fid_index(rif->fid), false); mlxsw_sp_rif_macvlan_flush(rif); mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC, @@ -9767,7 +9784,8 @@ mlxsw_sp1_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif, struct netlink_ext_ack *extack) { struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif); - u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev); + struct net_device *dev = mlxsw_sp_rif_dev(rif); + u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(dev); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; struct mlxsw_sp_vr *ul_vr; int err; @@ -9966,7 +9984,8 @@ mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif, struct netlink_ext_ack *extack) { struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif); - u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(rif->dev); + struct net_device *dev = mlxsw_sp_rif_dev(rif); + u32 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(dev); struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; struct mlxsw_sp_rif *ul_rif; int err; -- cgit v1.2.3 From 2019b5eeae2af862af41882b0863d61dfdaee25d Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:03 +0200 Subject: mlxsw: spectrum_router: Access rif->dev from params in mlxsw_sp_rif_create() The previous patch added a helper to access a netdevice given a RIF. Using this helper in mlxsw_sp_rif_create() is unreasonable: the netdevice was given in RIF creation parameters. Just take it there. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index e9183c223575..da582ef8efda 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8138,7 +8138,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, err = -ENOMEM; goto err_rif_alloc; } - dev_hold(rif->dev); + dev_hold(params->dev); mlxsw_sp->router->rifs[rif_index] = rif; rif->mlxsw_sp = mlxsw_sp; rif->ops = ops; @@ -8166,12 +8166,12 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, goto err_mr_rif_add; } - if (netdev_offload_xstats_enabled(rif->dev, + if (netdev_offload_xstats_enabled(params->dev, NETDEV_OFFLOAD_XSTATS_TYPE_L3)) { err = mlxsw_sp_router_port_l3_stats_enable(rif); if (err) goto err_stats_enable; - mlxsw_sp_router_hwstats_notify_schedule(rif->dev); + mlxsw_sp_router_hwstats_notify_schedule(params->dev); } else { mlxsw_sp_rif_counters_alloc(rif); } @@ -8189,7 +8189,7 @@ err_configure: mlxsw_sp_fid_put(fid); err_fid_get: mlxsw_sp->router->rifs[rif_index] = NULL; - dev_put(rif->dev); + dev_put(params->dev); kfree(rif); err_rif_alloc: mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries); -- cgit v1.2.3 From 69f4ba177d6bb863925e586fa15bd0d454a875d7 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:04 +0200 Subject: mlxsw: spectrum_router: Access nh->rif->dev through a helper In order to abstract away deduction of netdevice from the corresponding next hop, introduce a helper, mlxsw_sp_nexthop_dev(), and use it throughout. This will make it possible to change the deduction path easily later on. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index da582ef8efda..d7013727da21 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2941,6 +2941,14 @@ struct mlxsw_sp_nexthop { bool counter_valid; }; +static struct net_device * +mlxsw_sp_nexthop_dev(const struct mlxsw_sp_nexthop *nh) +{ + if (nh->rif) + return mlxsw_sp_rif_dev(nh->rif); + return NULL; +} + enum mlxsw_sp_nexthop_group_type { MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV4, MLXSW_SP_NEXTHOP_GROUP_TYPE_IPV6, @@ -4014,16 +4022,18 @@ mlxsw_sp_nexthop_dead_neigh_replace(struct mlxsw_sp *mlxsw_sp, { struct neighbour *n, *old_n = neigh_entry->key.n; struct mlxsw_sp_nexthop *nh; + struct net_device *dev; bool entry_connected; u8 nud_state, dead; int err; nh = list_first_entry(&neigh_entry->nexthop_list, struct mlxsw_sp_nexthop, neigh_list_node); + dev = mlxsw_sp_nexthop_dev(nh); - n = neigh_lookup(nh->neigh_tbl, &nh->gw_addr, nh->rif->dev); + n = neigh_lookup(nh->neigh_tbl, &nh->gw_addr, dev); if (!n) { - n = neigh_create(nh->neigh_tbl, &nh->gw_addr, nh->rif->dev); + n = neigh_create(nh->neigh_tbl, &nh->gw_addr, dev); if (IS_ERR(n)) return PTR_ERR(n); neigh_event_send(n, NULL); @@ -4110,21 +4120,23 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { struct mlxsw_sp_neigh_entry *neigh_entry; + struct net_device *dev; struct neighbour *n; u8 nud_state, dead; int err; if (!nh->nhgi->gateway || nh->neigh_entry) return 0; + dev = mlxsw_sp_nexthop_dev(nh); /* Take a reference of neigh here ensuring that neigh would * not be destructed before the nexthop entry is finished. * The reference is taken either in neigh_lookup() or * in neigh_create() in case n is not found. */ - n = neigh_lookup(nh->neigh_tbl, &nh->gw_addr, nh->rif->dev); + n = neigh_lookup(nh->neigh_tbl, &nh->gw_addr, dev); if (!n) { - n = neigh_create(nh->neigh_tbl, &nh->gw_addr, nh->rif->dev); + n = neigh_create(nh->neigh_tbl, &nh->gw_addr, dev); if (IS_ERR(n)) return PTR_ERR(n); neigh_event_send(n, NULL); @@ -5516,9 +5528,10 @@ mlxsw_sp_rt6_nexthop(struct mlxsw_sp_nexthop_group *nh_grp, for (i = 0; i < nh_grp->nhgi->count; i++) { struct mlxsw_sp_nexthop *nh = &nh_grp->nhgi->nexthops[i]; + struct net_device *dev = mlxsw_sp_nexthop_dev(nh); struct fib6_info *rt = mlxsw_sp_rt6->rt; - if (nh->rif && nh->rif->dev == rt->fib6_nh->fib_nh_dev && + if (dev && dev == rt->fib6_nh->fib_nh_dev && ipv6_addr_equal((const struct in6_addr *) &nh->gw_addr, &rt->fib6_nh->fib_nh_gw6)) return nh; -- cgit v1.2.3 From 532b6e2bbc190c899086da5be1fd83e69fb41c12 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:05 +0200 Subject: mlxsw: spectrum_router: Access nhgi->rif through a helper To abstract away deduction of RIF from the corresponding next hop group info (NHGI), mlxsw currently uses a macro. In its current form, that macro is impossible to extend to more general computation. Therefore introduce a helper, mlxsw_sp_nhgi_rif(), and use it throughout. This will make it possible to change the deduction path easily later on. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index d7013727da21..e05c47568ece 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -2966,9 +2966,14 @@ struct mlxsw_sp_nexthop_group_info { is_resilient:1; struct list_head list; /* member in nh_res_grp_list */ struct mlxsw_sp_nexthop nexthops[]; -#define nh_rif nexthops[0].rif }; +static struct mlxsw_sp_rif * +mlxsw_sp_nhgi_rif(const struct mlxsw_sp_nexthop_group_info *nhgi) +{ + return nhgi->nexthops[0].rif; +} + struct mlxsw_sp_nexthop_group_vr_key { u16 vr_id; enum mlxsw_sp_l3proto proto; @@ -5510,7 +5515,7 @@ mlxsw_sp_fib_entry_should_offload(const struct mlxsw_sp_fib_entry *fib_entry) case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE: return !!nh_group->nhgi->adj_index_valid; case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL: - return !!nh_group->nhgi->nh_rif; + return !!mlxsw_sp_nhgi_rif(nh_group->nhgi); case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE: case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP: @@ -5772,7 +5777,8 @@ static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP; adjacency_index = nhgi->adj_index; ecmp_size = nhgi->ecmp_size; - } else if (!nhgi->adj_index_valid && nhgi->count && nhgi->nh_rif) { + } else if (!nhgi->adj_index_valid && nhgi->count && + mlxsw_sp_nhgi_rif(nhgi)) { trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP; adjacency_index = mlxsw_sp->router->adj_trap_index; ecmp_size = 1; @@ -5791,7 +5797,7 @@ static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry, enum mlxsw_reg_ralue_op op) { - struct mlxsw_sp_rif *rif = fib_entry->nh_group->nhgi->nh_rif; + struct mlxsw_sp_rif *rif = mlxsw_sp_nhgi_rif(fib_entry->nh_group->nhgi); enum mlxsw_reg_ralue_trap_action trap_action; char ralue_pl[MLXSW_REG_RALUE_LEN]; u16 trap_id = 0; -- cgit v1.2.3 From 571c56911b45059dbdd2fb7912152e3412b658cf Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:06 +0200 Subject: mlxsw: spectrum_router: Extract a helper to free a RIF Right now freeing the object that mlxsw uses to keep track of a RIF is as simple as calling a kfree. But later on as CRIF abstraction is brought in, it will involve severing the link between CRIF and its RIF as well. Better to have the logic encapsulated in a helper. Since a helper is being introduced, make it a full-fledged destructor and have it validate that the objects tracked at the RIF have been released. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index e05c47568ece..1e05ecd29c8d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -7903,6 +7903,13 @@ static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, return rif; } +static void mlxsw_sp_rif_free(struct mlxsw_sp_rif *rif) +{ + WARN_ON(!list_empty(&rif->neigh_list)); + WARN_ON(!list_empty(&rif->nexthop_list)); + kfree(rif); +} + struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp, u16 rif_index) { @@ -8209,7 +8216,7 @@ err_configure: err_fid_get: mlxsw_sp->router->rifs[rif_index] = NULL; dev_put(params->dev); - kfree(rif); + mlxsw_sp_rif_free(rif); err_rif_alloc: mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries); err_rif_index_alloc: @@ -8249,7 +8256,7 @@ static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) mlxsw_sp_fid_put(fid); mlxsw_sp->router->rifs[rif->rif_index] = NULL; dev_put(dev); - kfree(rif); + mlxsw_sp_rif_free(rif); mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries); vr->rif_count--; mlxsw_sp_vr_put(mlxsw_sp, vr); @@ -9902,7 +9909,7 @@ mlxsw_sp_ul_rif_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr, ul_rif_op_err: mlxsw_sp->router->rifs[rif_index] = NULL; - kfree(ul_rif); + mlxsw_sp_rif_free(ul_rif); err_rif_alloc: mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries); return ERR_PTR(err); @@ -9917,7 +9924,7 @@ static void mlxsw_sp_ul_rif_destroy(struct mlxsw_sp_rif *ul_rif) atomic_sub(rif_entries, &mlxsw_sp->router->rifs_count); mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, false); mlxsw_sp->router->rifs[ul_rif->rif_index] = NULL; - kfree(ul_rif); + mlxsw_sp_rif_free(ul_rif); mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries); } -- cgit v1.2.3 From 33d11c4e5ce922bc16493fc75ad3c20cc55ed88a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:07 +0200 Subject: mlxsw: spectrum_router: Add a helper to check if netdev has addresses This function will be useful later as the driver will need to retroactively create RIFs for new uppers with addresses. Add another helper that assumes RCU lock, and restructure the code to skip the IPv6 branch not through conditioning on the addr_list_empty variable, but by directly returning the result value. This makes the skip more obvious than it previously was. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 42 +++++++++++++++------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 1e05ecd29c8d..25dbddabd91e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -7794,28 +7794,44 @@ static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif); } +static bool __mlxsw_sp_dev_addr_list_empty(const struct net_device *dev) +{ + struct inet6_dev *inet6_dev; + struct in_device *idev; + + idev = __in_dev_get_rcu(dev); + if (idev && idev->ifa_list) + return false; + + inet6_dev = __in6_dev_get(dev); + if (inet6_dev && !list_empty(&inet6_dev->addr_list)) + return false; + + return true; +} + +static bool mlxsw_sp_dev_addr_list_empty(const struct net_device *dev) +{ + bool addr_list_empty; + + rcu_read_lock(); + addr_list_empty = __mlxsw_sp_dev_addr_list_empty(dev); + rcu_read_unlock(); + + return addr_list_empty; +} + static bool mlxsw_sp_rif_should_config(struct mlxsw_sp_rif *rif, struct net_device *dev, unsigned long event) { - struct inet6_dev *inet6_dev; - bool addr_list_empty = true; - struct in_device *idev; + bool addr_list_empty; switch (event) { case NETDEV_UP: return rif == NULL; case NETDEV_DOWN: - rcu_read_lock(); - idev = __in_dev_get_rcu(dev); - if (idev && idev->ifa_list) - addr_list_empty = false; - - inet6_dev = __in6_dev_get(dev); - if (addr_list_empty && inet6_dev && - !list_empty(&inet6_dev->addr_list)) - addr_list_empty = false; - rcu_read_unlock(); + addr_list_empty = mlxsw_sp_dev_addr_list_empty(dev); /* macvlans do not have a RIF, but rather piggy back on the * RIF of their lower device. -- cgit v1.2.3 From 440273e763f575bfd801e00a8892a9abb82fa263 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:08 +0200 Subject: mlxsw: spectrum_router: Extract a helper for RIF migration RIF configuration contains a number of parameters that cannot be changed after the RIF is created. For the IPIP loopbacks, this is currently worked around by creating a new RIF with the desired configuration changes applied, and updating next hops to the new RIF, and then destroying the old RIF. This operation will be useful as a reusable atom, so extract a helper to that effect. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 25dbddabd91e..fdb812152e71 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -1651,6 +1651,17 @@ static void mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *old_rif, struct mlxsw_sp_rif *new_rif); +static void mlxsw_sp_rif_migrate_destroy(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_rif *old_rif, + struct mlxsw_sp_rif *new_rif, + bool migrate_nhs) +{ + if (migrate_nhs) + mlxsw_sp_nexthop_rif_migrate(mlxsw_sp, old_rif, new_rif); + + mlxsw_sp_rif_destroy(old_rif); +} + static int mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_ipip_entry *ipip_entry, @@ -1668,12 +1679,8 @@ mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp, return PTR_ERR(new_lb_rif); ipip_entry->ol_lb = new_lb_rif; - if (keep_encap) - mlxsw_sp_nexthop_rif_migrate(mlxsw_sp, &old_lb_rif->common, - &new_lb_rif->common); - - mlxsw_sp_rif_destroy(&old_lb_rif->common); - + mlxsw_sp_rif_migrate_destroy(mlxsw_sp, &old_lb_rif->common, + &new_lb_rif->common, keep_encap); return 0; } -- cgit v1.2.3 From d4a37bf0943d70ca78ae93da9b05e70632c2019c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 12 Jun 2023 17:31:09 +0200 Subject: mlxsw: spectrum_router: Move IPIP init up mlxsw will need to keep track of certain devices that are not related to any of its front panel ports. This includes IPIP netdevices. To be able to query the list of supported IPIP types, router->ipip_ops_arr needs to be initialized. To that end, move the IPIP initialization up (and finalization correspondingly down). Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Paolo Abeni --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index fdb812152e71..43e8f19c7a0a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -10643,14 +10643,14 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, if (err) goto err_router_init; - err = mlxsw_sp_rifs_init(mlxsw_sp); - if (err) - goto err_rifs_init; - err = mlxsw_sp->router_ops->ipips_init(mlxsw_sp); if (err) goto err_ipips_init; + err = mlxsw_sp_rifs_init(mlxsw_sp); + if (err) + goto err_rifs_init; + err = rhashtable_init(&mlxsw_sp->router->nexthop_ht, &mlxsw_sp_nexthop_ht_params); if (err) @@ -10776,10 +10776,10 @@ err_lpm_init: err_nexthop_group_ht_init: rhashtable_destroy(&mlxsw_sp->router->nexthop_ht); err_nexthop_ht_init: - mlxsw_sp_ipips_fini(mlxsw_sp); -err_ipips_init: mlxsw_sp_rifs_fini(mlxsw_sp); err_rifs_init: + mlxsw_sp_ipips_fini(mlxsw_sp); +err_ipips_init: __mlxsw_sp_router_fini(mlxsw_sp); err_router_init: cancel_delayed_work_sync(&mlxsw_sp->router->nh_grp_activity_dw); @@ -10812,8 +10812,8 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_sp_lpm_fini(mlxsw_sp); rhashtable_destroy(&router->nexthop_group_ht); rhashtable_destroy(&router->nexthop_ht); - mlxsw_sp_ipips_fini(mlxsw_sp); mlxsw_sp_rifs_fini(mlxsw_sp); + mlxsw_sp_ipips_fini(mlxsw_sp); __mlxsw_sp_router_fini(mlxsw_sp); cancel_delayed_work_sync(&router->nh_grp_activity_dw); mutex_destroy(&router->lock); -- cgit v1.2.3 From fa0e21fa44438a0e856d42224bfa24641d37b979 Mon Sep 17 00:00:00 2001 From: Edwin Peer Date: Sun, 11 Jun 2023 13:51:08 +0300 Subject: rtnetlink: extend RTEXT_FILTER_SKIP_STATS to IFLA_VF_INFO This filter already exists for excluding IPv6 SNMP stats. Extend its definition to also exclude IFLA_VF_INFO stats in RTM_GETLINK. This patch constitutes a partial fix for a netlink attribute nesting overflow bug in IFLA_VFINFO_LIST. By excluding the stats when the requester doesn't need them, the truncation of the VF list is avoided. While it was technically only the stats added in commit c5a9f6f0ab40 ("net/core: Add drop counters to VF statistics") breaking the camel's back, the appreciable size of the stats data should never have been included without due consideration for the maximum number of VFs supported by PCI. Fixes: 3b766cd83232 ("net/core: Add reading VF statistics through the PF netdevice") Fixes: c5a9f6f0ab40 ("net/core: Add drop counters to VF statistics") Signed-off-by: Edwin Peer Cc: Edwin Peer Signed-off-by: Gal Pressman Link: https://lore.kernel.org/r/20230611105108.122586-1-gal@nvidia.com Signed-off-by: Paolo Abeni --- net/core/rtnetlink.c | 96 ++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 41de3a2f29e1..d1815122298d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -961,24 +961,27 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev, nla_total_size(sizeof(struct ifla_vf_rate)) + nla_total_size(sizeof(struct ifla_vf_link_state)) + nla_total_size(sizeof(struct ifla_vf_rss_query_en)) + - nla_total_size(0) + /* nest IFLA_VF_STATS */ - /* IFLA_VF_STATS_RX_PACKETS */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_TX_PACKETS */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_RX_BYTES */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_TX_BYTES */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_BROADCAST */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_MULTICAST */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_RX_DROPPED */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_TX_DROPPED */ - nla_total_size_64bit(sizeof(__u64)) + nla_total_size(sizeof(struct ifla_vf_trust))); + if (~ext_filter_mask & RTEXT_FILTER_SKIP_STATS) { + size += num_vfs * + (nla_total_size(0) + /* nest IFLA_VF_STATS */ + /* IFLA_VF_STATS_RX_PACKETS */ + nla_total_size_64bit(sizeof(__u64)) + + /* IFLA_VF_STATS_TX_PACKETS */ + nla_total_size_64bit(sizeof(__u64)) + + /* IFLA_VF_STATS_RX_BYTES */ + nla_total_size_64bit(sizeof(__u64)) + + /* IFLA_VF_STATS_TX_BYTES */ + nla_total_size_64bit(sizeof(__u64)) + + /* IFLA_VF_STATS_BROADCAST */ + nla_total_size_64bit(sizeof(__u64)) + + /* IFLA_VF_STATS_MULTICAST */ + nla_total_size_64bit(sizeof(__u64)) + + /* IFLA_VF_STATS_RX_DROPPED */ + nla_total_size_64bit(sizeof(__u64)) + + /* IFLA_VF_STATS_TX_DROPPED */ + nla_total_size_64bit(sizeof(__u64))); + } return size; } else return 0; @@ -1270,7 +1273,8 @@ static noinline_for_stack int rtnl_fill_stats(struct sk_buff *skb, static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb, struct net_device *dev, int vfs_num, - struct nlattr *vfinfo) + struct nlattr *vfinfo, + u32 ext_filter_mask) { struct ifla_vf_rss_query_en vf_rss_query_en; struct nlattr *vf, *vfstats, *vfvlanlist; @@ -1376,33 +1380,35 @@ static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb, goto nla_put_vf_failure; } nla_nest_end(skb, vfvlanlist); - memset(&vf_stats, 0, sizeof(vf_stats)); - if (dev->netdev_ops->ndo_get_vf_stats) - dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num, - &vf_stats); - vfstats = nla_nest_start_noflag(skb, IFLA_VF_STATS); - if (!vfstats) - goto nla_put_vf_failure; - if (nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_PACKETS, - vf_stats.rx_packets, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_PACKETS, - vf_stats.tx_packets, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_BYTES, - vf_stats.rx_bytes, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_BYTES, - vf_stats.tx_bytes, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST, - vf_stats.broadcast, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST, - vf_stats.multicast, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_DROPPED, - vf_stats.rx_dropped, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_DROPPED, - vf_stats.tx_dropped, IFLA_VF_STATS_PAD)) { - nla_nest_cancel(skb, vfstats); - goto nla_put_vf_failure; + if (~ext_filter_mask & RTEXT_FILTER_SKIP_STATS) { + memset(&vf_stats, 0, sizeof(vf_stats)); + if (dev->netdev_ops->ndo_get_vf_stats) + dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num, + &vf_stats); + vfstats = nla_nest_start_noflag(skb, IFLA_VF_STATS); + if (!vfstats) + goto nla_put_vf_failure; + if (nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_PACKETS, + vf_stats.rx_packets, IFLA_VF_STATS_PAD) || + nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_PACKETS, + vf_stats.tx_packets, IFLA_VF_STATS_PAD) || + nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_BYTES, + vf_stats.rx_bytes, IFLA_VF_STATS_PAD) || + nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_BYTES, + vf_stats.tx_bytes, IFLA_VF_STATS_PAD) || + nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST, + vf_stats.broadcast, IFLA_VF_STATS_PAD) || + nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST, + vf_stats.multicast, IFLA_VF_STATS_PAD) || + nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_DROPPED, + vf_stats.rx_dropped, IFLA_VF_STATS_PAD) || + nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_DROPPED, + vf_stats.tx_dropped, IFLA_VF_STATS_PAD)) { + nla_nest_cancel(skb, vfstats); + goto nla_put_vf_failure; + } + nla_nest_end(skb, vfstats); } - nla_nest_end(skb, vfstats); nla_nest_end(skb, vf); return 0; @@ -1435,7 +1441,7 @@ static noinline_for_stack int rtnl_fill_vf(struct sk_buff *skb, return -EMSGSIZE; for (i = 0; i < num_vfs; i++) { - if (rtnl_fill_vfinfo(skb, dev, i, vfinfo)) + if (rtnl_fill_vfinfo(skb, dev, i, vfinfo, ext_filter_mask)) return -EMSGSIZE; } -- cgit v1.2.3 From 89da780aa4c7667c8b1a144959206262aebdeabe Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 12 Jun 2023 11:55:34 -0400 Subject: rtnetlink: move validate_linkmsg out of do_setlink This patch moves validate_linkmsg() out of do_setlink() to its callers and deletes the early validate_linkmsg() call in __rtnl_newlink(), so that it will not call validate_linkmsg() twice in either of the paths: - __rtnl_newlink() -> do_setlink() - __rtnl_newlink() -> rtnl_newlink_create() -> rtnl_create_link() Additionally, as validate_linkmsg() is now only called with a real dev, we can remove the NULL check for dev in validate_linkmsg(). Note that we moved validate_linkmsg() check to the places where it has not done any changes to the dev, as Jakub suggested. Signed-off-by: Xin Long Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/cf2ef061e08251faf9e8be25ff0d61150c030475.1686585334.git.lucien.xin@gmail.com Signed-off-by: Jakub Kicinski --- net/core/rtnetlink.c | 83 ++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index d1815122298d..2c61fb912772 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2383,45 +2383,43 @@ static int rtnl_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[], struct netlink_ext_ack *extack) { - if (dev) { - if (tb[IFLA_ADDRESS] && - nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) - return -EINVAL; + if (tb[IFLA_ADDRESS] && + nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) + return -EINVAL; - if (tb[IFLA_BROADCAST] && - nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) - return -EINVAL; + if (tb[IFLA_BROADCAST] && + nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) + return -EINVAL; - if (tb[IFLA_GSO_MAX_SIZE] && - nla_get_u32(tb[IFLA_GSO_MAX_SIZE]) > dev->tso_max_size) { - NL_SET_ERR_MSG(extack, "too big gso_max_size"); - return -EINVAL; - } + if (tb[IFLA_GSO_MAX_SIZE] && + nla_get_u32(tb[IFLA_GSO_MAX_SIZE]) > dev->tso_max_size) { + NL_SET_ERR_MSG(extack, "too big gso_max_size"); + return -EINVAL; + } - if (tb[IFLA_GSO_MAX_SEGS] && - (nla_get_u32(tb[IFLA_GSO_MAX_SEGS]) > GSO_MAX_SEGS || - nla_get_u32(tb[IFLA_GSO_MAX_SEGS]) > dev->tso_max_segs)) { - NL_SET_ERR_MSG(extack, "too big gso_max_segs"); - return -EINVAL; - } + if (tb[IFLA_GSO_MAX_SEGS] && + (nla_get_u32(tb[IFLA_GSO_MAX_SEGS]) > GSO_MAX_SEGS || + nla_get_u32(tb[IFLA_GSO_MAX_SEGS]) > dev->tso_max_segs)) { + NL_SET_ERR_MSG(extack, "too big gso_max_segs"); + return -EINVAL; + } - if (tb[IFLA_GRO_MAX_SIZE] && - nla_get_u32(tb[IFLA_GRO_MAX_SIZE]) > GRO_MAX_SIZE) { - NL_SET_ERR_MSG(extack, "too big gro_max_size"); - return -EINVAL; - } + if (tb[IFLA_GRO_MAX_SIZE] && + nla_get_u32(tb[IFLA_GRO_MAX_SIZE]) > GRO_MAX_SIZE) { + NL_SET_ERR_MSG(extack, "too big gro_max_size"); + return -EINVAL; + } - if (tb[IFLA_GSO_IPV4_MAX_SIZE] && - nla_get_u32(tb[IFLA_GSO_IPV4_MAX_SIZE]) > dev->tso_max_size) { - NL_SET_ERR_MSG(extack, "too big gso_ipv4_max_size"); - return -EINVAL; - } + if (tb[IFLA_GSO_IPV4_MAX_SIZE] && + nla_get_u32(tb[IFLA_GSO_IPV4_MAX_SIZE]) > dev->tso_max_size) { + NL_SET_ERR_MSG(extack, "too big gso_ipv4_max_size"); + return -EINVAL; + } - if (tb[IFLA_GRO_IPV4_MAX_SIZE] && - nla_get_u32(tb[IFLA_GRO_IPV4_MAX_SIZE]) > GRO_MAX_SIZE) { - NL_SET_ERR_MSG(extack, "too big gro_ipv4_max_size"); - return -EINVAL; - } + if (tb[IFLA_GRO_IPV4_MAX_SIZE] && + nla_get_u32(tb[IFLA_GRO_IPV4_MAX_SIZE]) > GRO_MAX_SIZE) { + NL_SET_ERR_MSG(extack, "too big gro_ipv4_max_size"); + return -EINVAL; } if (tb[IFLA_AF_SPEC]) { @@ -2742,10 +2740,6 @@ static int do_setlink(const struct sk_buff *skb, char ifname[IFNAMSIZ]; int err; - err = validate_linkmsg(dev, tb, extack); - if (err < 0) - return err; - if (tb[IFLA_IFNAME]) nla_strscpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); else @@ -3162,6 +3156,10 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, goto errout; } + err = validate_linkmsg(dev, tb, extack); + if (err < 0) + goto errout; + err = do_setlink(skb, dev, ifm, extack, tb, 0); errout: return err; @@ -3405,6 +3403,9 @@ static int rtnl_group_changelink(const struct sk_buff *skb, for_each_netdev_safe(net, dev, aux) { if (dev->group == group) { + err = validate_linkmsg(dev, tb, extack); + if (err < 0) + return err; err = do_setlink(skb, dev, ifm, extack, tb, 0); if (err < 0) return err; @@ -3562,10 +3563,6 @@ replay: m_ops = master_dev->rtnl_link_ops; } - err = validate_linkmsg(dev, tb, extack); - if (err < 0) - return err; - if (tb[IFLA_LINKINFO]) { err = nla_parse_nested_deprecated(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO], @@ -3629,6 +3626,10 @@ replay: if (nlh->nlmsg_flags & NLM_F_REPLACE) return -EOPNOTSUPP; + err = validate_linkmsg(dev, tb, extack); + if (err < 0) + return err; + if (linkinfo[IFLA_INFO_DATA]) { if (!ops || ops != dev->rtnl_link_ops || !ops->changelink) -- cgit v1.2.3 From 70f7457ad6d655e65f1b93cbba2a519e4b11c946 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 12 Jun 2023 14:49:43 -0700 Subject: net: create device lookup API with reference tracking New users of dev_get_by_index() and dev_get_by_name() keep getting added and it would be nice to steer them towards the APIs with reference tracking. Add variants of those calls which allocate the reference tracker and use them in a couple of places. Signed-off-by: Jakub Kicinski Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 +++ net/core/dev.c | 63 +++++++++++++++++++++++++++++++++-------------- net/ethtool/netlink.c | 10 ++++---- net/ipv6/route.c | 12 ++++----- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2d6cb2bf2f05..acf706d49c2b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3124,6 +3124,10 @@ struct net_device *netdev_sk_get_lowest_dev(struct net_device *dev, struct sock *sk); struct net_device *dev_get_by_index(struct net *net, int ifindex); struct net_device *__dev_get_by_index(struct net *net, int ifindex); +struct net_device *netdev_get_by_index(struct net *net, int ifindex, + netdevice_tracker *tracker, gfp_t gfp); +struct net_device *netdev_get_by_name(struct net *net, const char *name, + netdevice_tracker *tracker, gfp_t gfp); struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex); struct net_device *dev_get_by_napi_id(unsigned int napi_id); int dev_restart(struct net_device *dev); diff --git a/net/core/dev.c b/net/core/dev.c index c2456b3667fe..63abb0463c24 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -758,29 +758,43 @@ struct net_device *dev_get_by_name_rcu(struct net *net, const char *name) } EXPORT_SYMBOL(dev_get_by_name_rcu); +/* Deprecated for new users, call netdev_get_by_name() instead */ +struct net_device *dev_get_by_name(struct net *net, const char *name) +{ + struct net_device *dev; + + rcu_read_lock(); + dev = dev_get_by_name_rcu(net, name); + dev_hold(dev); + rcu_read_unlock(); + return dev; +} +EXPORT_SYMBOL(dev_get_by_name); + /** - * dev_get_by_name - find a device by its name + * netdev_get_by_name() - find a device by its name * @net: the applicable net namespace * @name: name to find + * @tracker: tracking object for the acquired reference + * @gfp: allocation flags for the tracker * * Find an interface by name. This can be called from any * context and does its own locking. The returned handle has - * the usage count incremented and the caller must use dev_put() to + * the usage count incremented and the caller must use netdev_put() to * release it when it is no longer needed. %NULL is returned if no * matching device is found. */ - -struct net_device *dev_get_by_name(struct net *net, const char *name) +struct net_device *netdev_get_by_name(struct net *net, const char *name, + netdevice_tracker *tracker, gfp_t gfp) { struct net_device *dev; - rcu_read_lock(); - dev = dev_get_by_name_rcu(net, name); - dev_hold(dev); - rcu_read_unlock(); + dev = dev_get_by_name(net, name); + if (dev) + netdev_tracker_alloc(dev, tracker, gfp); return dev; } -EXPORT_SYMBOL(dev_get_by_name); +EXPORT_SYMBOL(netdev_get_by_name); /** * __dev_get_by_index - find a device by its ifindex @@ -831,29 +845,42 @@ struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex) } EXPORT_SYMBOL(dev_get_by_index_rcu); +/* Deprecated for new users, call netdev_get_by_index() instead */ +struct net_device *dev_get_by_index(struct net *net, int ifindex) +{ + struct net_device *dev; + + rcu_read_lock(); + dev = dev_get_by_index_rcu(net, ifindex); + dev_hold(dev); + rcu_read_unlock(); + return dev; +} +EXPORT_SYMBOL(dev_get_by_index); /** - * dev_get_by_index - find a device by its ifindex + * netdev_get_by_index() - find a device by its ifindex * @net: the applicable net namespace * @ifindex: index of device + * @tracker: tracking object for the acquired reference + * @gfp: allocation flags for the tracker * * Search for an interface by index. Returns NULL if the device * is not found or a pointer to the device. The device returned has * had a reference added and the pointer is safe until the user calls - * dev_put to indicate they have finished with it. + * netdev_put() to indicate they have finished with it. */ - -struct net_device *dev_get_by_index(struct net *net, int ifindex) +struct net_device *netdev_get_by_index(struct net *net, int ifindex, + netdevice_tracker *tracker, gfp_t gfp) { struct net_device *dev; - rcu_read_lock(); - dev = dev_get_by_index_rcu(net, ifindex); - dev_hold(dev); - rcu_read_unlock(); + dev = dev_get_by_index(net, ifindex); + if (dev) + netdev_tracker_alloc(dev, tracker, gfp); return dev; } -EXPORT_SYMBOL(dev_get_by_index); +EXPORT_SYMBOL(netdev_get_by_index); /** * dev_get_by_napi_id - find a device by napi_id diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 5dd5e8222c45..39a459b0111b 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -115,7 +115,8 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) { u32 ifindex = nla_get_u32(tb[ETHTOOL_A_HEADER_DEV_INDEX]); - dev = dev_get_by_index(net, ifindex); + dev = netdev_get_by_index(net, ifindex, &req_info->dev_tracker, + GFP_KERNEL); if (!dev) { NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_HEADER_DEV_INDEX], @@ -125,13 +126,14 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, /* if both ifindex and ifname are passed, they must match */ if (devname_attr && strncmp(dev->name, nla_data(devname_attr), IFNAMSIZ)) { - dev_put(dev); + netdev_put(dev, &req_info->dev_tracker); NL_SET_ERR_MSG_ATTR(extack, header, "ifindex and name do not match"); return -ENODEV; } } else if (devname_attr) { - dev = dev_get_by_name(net, nla_data(devname_attr)); + dev = netdev_get_by_name(net, nla_data(devname_attr), + &req_info->dev_tracker, GFP_KERNEL); if (!dev) { NL_SET_ERR_MSG_ATTR(extack, devname_attr, "no device matches name"); @@ -144,8 +146,6 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, } req_info->dev = dev; - if (dev) - netdev_tracker_alloc(dev, &req_info->dev_tracker, GFP_KERNEL); req_info->flags = flags; return 0; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 392aaa373b66..e510a4162ef8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3503,6 +3503,7 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, struct fib6_config *cfg, gfp_t gfp_flags, struct netlink_ext_ack *extack) { + netdevice_tracker *dev_tracker = &fib6_nh->fib_nh_dev_tracker; struct net_device *dev = NULL; struct inet6_dev *idev = NULL; int addr_type; @@ -3520,7 +3521,8 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, err = -ENODEV; if (cfg->fc_ifindex) { - dev = dev_get_by_index(net, cfg->fc_ifindex); + dev = netdev_get_by_index(net, cfg->fc_ifindex, + dev_tracker, gfp_flags); if (!dev) goto out; idev = in6_dev_get(dev); @@ -3554,11 +3556,11 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, /* hold loopback dev/idev if we haven't done so. */ if (dev != net->loopback_dev) { if (dev) { - dev_put(dev); + netdev_put(dev, dev_tracker); in6_dev_put(idev); } dev = net->loopback_dev; - dev_hold(dev); + netdev_hold(dev, dev_tracker, gfp_flags); idev = in6_dev_get(dev); if (!idev) { err = -ENODEV; @@ -3610,8 +3612,6 @@ pcpu_alloc: } fib6_nh->fib_nh_dev = dev; - netdev_tracker_alloc(dev, &fib6_nh->fib_nh_dev_tracker, gfp_flags); - fib6_nh->fib_nh_oif = dev->ifindex; err = 0; out: @@ -3621,7 +3621,7 @@ out: if (err) { lwtstate_put(fib6_nh->fib_nh_lws); fib6_nh->fib_nh_lws = NULL; - dev_put(dev); + netdev_put(dev, dev_tracker); } return err; -- cgit v1.2.3 From 48eed027d310326052655c5ac14588855663087b Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 12 Jun 2023 14:49:44 -0700 Subject: netpoll: allocate netdev tracker right away Commit 5fa5ae605821 ("netpoll: add net device refcount tracker to struct netpoll") was part of one of the initial netdev tracker introduction patches. It added an explicit netdev_tracker_alloc() for netpoll, presumably because the flow of the function is somewhat odd. After most of the core networking stack was converted to use the tracking hold() variants, netpoll's call to old dev_hold() stands out a bit. np is allocated by the caller and ready to use, we can use netdev_hold() here, even tho np->ndev will only be set to ndev inside __netpoll_setup(). Reviewed-by: Eric Dumazet Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- net/core/netpoll.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index e6a739b1afa9..543007f159f9 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -690,7 +690,7 @@ int netpoll_setup(struct netpoll *np) err = -ENODEV; goto unlock; } - dev_hold(ndev); + netdev_hold(ndev, &np->dev_tracker, GFP_KERNEL); if (netdev_master_upper_dev_get(ndev)) { np_err(np, "%s is a slave device, aborting\n", np->dev_name); @@ -783,12 +783,11 @@ put_noaddr: err = __netpoll_setup(np, ndev); if (err) goto put; - netdev_tracker_alloc(ndev, &np->dev_tracker, GFP_KERNEL); rtnl_unlock(); return 0; put: - dev_put(ndev); + netdev_put(ndev, &np->dev_tracker); unlock: rtnl_unlock(); return err; -- cgit v1.2.3 From 5b32c61a2dac17db3f87c65cada74c9d7f31f4fb Mon Sep 17 00:00:00 2001 From: Pranavi Somisetty Date: Mon, 12 Jun 2023 23:43:39 -0600 Subject: dt-bindings: net: cdns,macb: Add rx-watermark property watermark value is the minimum amount of packet data required to activate the forwarding process. The watermark implementation and maximum size is dependent on the device where Cadence MACB/GEM is used. Signed-off-by: Pranavi Somisetty Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/cdns,macb.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/net/cdns,macb.yaml b/Documentation/devicetree/bindings/net/cdns,macb.yaml index bef5e0f895be..bf8894a0257e 100644 --- a/Documentation/devicetree/bindings/net/cdns,macb.yaml +++ b/Documentation/devicetree/bindings/net/cdns,macb.yaml @@ -109,6 +109,16 @@ properties: power-domains: maxItems: 1 + cdns,rx-watermark: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + When the receive partial store and forward mode is activated, + the receiver will only begin to forward the packet to the external + AHB or AXI slave when enough packet data is stored in the SRAM packet buffer. + rx-watermark corresponds to the number of SRAM buffer locations, + that need to be filled, before the forwarding process is activated. + Width of the SRAM is platform dependent, and can be 4, 8 or 16 bytes. + '#address-cells': const: 1 @@ -166,6 +176,7 @@ examples: compatible = "cdns,macb"; reg = <0xfffc4000 0x4000>; interrupts = <21>; + cdns,rx-watermark = <0x44>; phy-mode = "rmii"; local-mac-address = [3a 0e 03 04 05 06]; clock-names = "pclk", "hclk", "tx_clk"; -- cgit v1.2.3 From cae4bc06b3e41bc6dfd7116a45c1006e50ffe153 Mon Sep 17 00:00:00 2001 From: Maulik Jodhani Date: Mon, 12 Jun 2023 23:43:40 -0600 Subject: net: macb: Add support for partial store and forward When the receive partial store and forward mode is activated, the receiver will only begin to forward the packet to the external AHB or AXI slave when enough packet data is stored in the packet buffer. The amount of packet data required to activate the forwarding process is programmable via watermark registers which are located at the same address as the partial store and forward enable bits. Adding support to read this rx-watermark value from device-tree, to program the watermark registers and enable partial store and forwarding. Signed-off-by: Maulik Jodhani Signed-off-by: Pranavi Somisetty Reviewed-by: Claudiu Beznea Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.h | 12 ++++++++++++ drivers/net/ethernet/cadence/macb_main.c | 27 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index b6d5bf8deb79..78c972bb1d96 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -82,6 +82,7 @@ #define GEM_NCFGR 0x0004 /* Network Config */ #define GEM_USRIO 0x000c /* User IO */ #define GEM_DMACFG 0x0010 /* DMA Configuration */ +#define GEM_PBUFRXCUT 0x0044 /* RX Partial Store and Forward */ #define GEM_JML 0x0048 /* Jumbo Max Length */ #define GEM_HS_MAC_CONFIG 0x0050 /* GEM high speed config */ #define GEM_HRB 0x0080 /* Hash Bottom */ @@ -347,6 +348,10 @@ #define GEM_ADDR64_SIZE 1 +/* Bitfields in PBUFRXCUT */ +#define GEM_ENCUTTHRU_OFFSET 31 /* Enable RX partial store and forward */ +#define GEM_ENCUTTHRU_SIZE 1 + /* Bitfields in NSR */ #define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */ #define MACB_NSR_LINK_SIZE 1 @@ -513,6 +518,8 @@ #define GEM_TX_PKT_BUFF_OFFSET 21 #define GEM_TX_PKT_BUFF_SIZE 1 +#define GEM_RX_PBUF_ADDR_OFFSET 22 +#define GEM_RX_PBUF_ADDR_SIZE 4 /* Bitfields in DCFG5. */ #define GEM_TSU_OFFSET 8 @@ -521,6 +528,8 @@ /* Bitfields in DCFG6. */ #define GEM_PBUF_LSO_OFFSET 27 #define GEM_PBUF_LSO_SIZE 1 +#define GEM_PBUF_CUTTHRU_OFFSET 25 +#define GEM_PBUF_CUTTHRU_SIZE 1 #define GEM_DAW64_OFFSET 23 #define GEM_DAW64_SIZE 1 @@ -1290,6 +1299,9 @@ struct macb { u32 wol; + /* holds value of rx watermark value for pbuf_rxcutthru register */ + u32 rx_watermark; + struct macb_ptp_info *ptp_info; /* macb-ptp interface */ struct phy *sgmii_phy; /* for ZynqMP SGMII mode */ diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 50a4b04315e9..2e35e200fdcb 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -2635,6 +2635,9 @@ static void macb_reset_hw(struct macb *bp) macb_writel(bp, TSR, -1); macb_writel(bp, RSR, -1); + /* Disable RX partial store and forward and reset watermark value */ + gem_writel(bp, PBUFRXCUT, 0); + /* Disable all interrupts */ for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { queue_writel(queue, IDR, -1); @@ -2792,6 +2795,10 @@ static void macb_init_hw(struct macb *bp) bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; macb_configure_dma(bp); + + /* Enable RX partial store and forward and set watermark */ + if (bp->rx_watermark) + gem_writel(bp, PBUFRXCUT, (bp->rx_watermark | GEM_BIT(ENCUTTHRU))); } /* The hash address register is 64 bits long and takes up two @@ -4946,6 +4953,7 @@ static int macb_probe(struct platform_device *pdev) phy_interface_t interface; struct net_device *dev; struct resource *regs; + u32 wtrmrk_rst_val; void __iomem *mem; struct macb *bp; int err, val; @@ -5025,6 +5033,25 @@ static int macb_probe(struct platform_device *pdev) bp->usrio = macb_config->usrio; + /* By default we set to partial store and forward mode for zynqmp. + * Disable if not set in devicetree. + */ + if (GEM_BFEXT(PBUF_CUTTHRU, gem_readl(bp, DCFG6))) { + err = of_property_read_u32(bp->pdev->dev.of_node, + "cdns,rx-watermark", + &bp->rx_watermark); + + if (!err) { + /* Disable partial store and forward in case of error or + * invalid watermark value + */ + wtrmrk_rst_val = (1 << (GEM_BFEXT(RX_PBUF_ADDR, gem_readl(bp, DCFG2)))) - 1; + if (bp->rx_watermark > wtrmrk_rst_val || !bp->rx_watermark) { + dev_info(&bp->pdev->dev, "Invalid watermark value\n"); + bp->rx_watermark = 0; + } + } + } spin_lock_init(&bp->lock); /* setup capabilities */ -- cgit v1.2.3 From 52818fce28b216ef90edbb2b8e134534cf6364c6 Mon Sep 17 00:00:00 2001 From: Deming Wang Date: Mon, 12 Jun 2023 07:46:12 -0400 Subject: wifi: rt2x00: fix the typo in comments Fix typo in the description of 'non-succesfull'. Signed-off-by: Deming Wang Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230612114612.1640-1-wangdeming@inspur.com --- drivers/net/wireless/ralink/rt2x00/rt2x00link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c index b052c96347d6..6cf7e7c997c2 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c @@ -192,7 +192,7 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev, return; /* - * Frame was received successfully since non-succesfull + * Frame was received successfully since non-successful * frames would have been dropped by the hardware. */ qual->rx_success++; -- cgit v1.2.3 From 7edbd53a58a86c1d389e474a4f318cf2fdffa5ce Mon Sep 17 00:00:00 2001 From: Azeem Shaikh Date: Tue, 13 Jun 2023 00:34:57 +0000 Subject: wifi: mt7601u: replace strlcpy() with strscpy() strlcpy() reads the entire source buffer first. This read may exceed the destination size limit. This is both inefficient and can lead to linear read overflows if a source string is not NUL-terminated [1]. In an effort to remove strlcpy() completely [2], replace strlcpy() here with strscpy(). Direct replacement is safe here since DEV_ASSIGN is only used by TRACE macros and the return values are ignored. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strlcpy [2] https://github.com/KSPP/linux/issues/89 Signed-off-by: Azeem Shaikh Reviewed-by: Kees Cook Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230613003458.3538812-1-azeemshaikh38@gmail.com --- drivers/net/wireless/mediatek/mt7601u/trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt7601u/trace.h b/drivers/net/wireless/mediatek/mt7601u/trace.h index 5a6ba015085f..07696b672161 100644 --- a/drivers/net/wireless/mediatek/mt7601u/trace.h +++ b/drivers/net/wireless/mediatek/mt7601u/trace.h @@ -16,7 +16,7 @@ #define MAXNAME 32 #define DEV_ENTRY __array(char, wiphy_name, 32) -#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ +#define DEV_ASSIGN strscpy(__entry->wiphy_name, \ wiphy_name(dev->hw->wiphy), MAXNAME) #define DEV_PR_FMT "%s " #define DEV_PR_ARG __entry->wiphy_name -- cgit v1.2.3 From 65a9140e38b6f3318af90860ab0128a47996aaa9 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 14 Jun 2023 11:15:53 +0300 Subject: wifi: rtw89: cleanup private data structures Remove a bunch of unused (and set but unused) fields from 'struct rtw89_btc_wl_nhm', 'struct rtw89_dle_info', 'struct rtw89_hal' and 'struct rtw89_env_monitor_info' driver-specific data structures, adjust related bits. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230614081555.91395-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtw89/core.h | 39 ------------------------------- drivers/net/wireless/realtek/rtw89/mac.c | 6 +---- drivers/net/wireless/realtek/rtw89/phy.c | 4 ---- 3 files changed, 1 insertion(+), 48 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 7e1e508956c8..a4958e280828 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -1405,7 +1405,6 @@ struct rtw89_btc_wl_nhm { u8 current_status; u8 refresh; bool start_flag; - u8 last_ccx_rpt_stamp; s8 pwr_max; s8 pwr_min; }; @@ -3301,7 +3300,6 @@ enum rtw89_hcifc_mode { struct rtw89_dle_info { enum rtw89_qta_mode qta_mode; - u16 wde_pg_size; u16 ple_pg_size; u16 c0_rx_qta; u16 c1_rx_qta; @@ -3484,7 +3482,6 @@ struct rtw89_hal { u32 rx_fltr; u8 cv; u8 acv; - u32 sw_amsdu_max_size; u32 antenna_tx; u32 antenna_rx; u8 tx_nss; @@ -3890,35 +3887,16 @@ enum rtw89_ccx_edcca_opt_bw_idx { #define RTW89_FAHM_RPT_NUM 12 #define RTW89_IFS_CLM_NUM 4 struct rtw89_env_monitor_info { - u32 ccx_trigger_time; - u64 start_time; - u8 ccx_rpt_stamp; u8 ccx_watchdog_result; bool ccx_ongoing; u8 ccx_rac_lv; bool ccx_manual_ctrl; - u8 ccx_pre_rssi; - u16 clm_mntr_time; - u16 nhm_mntr_time; u16 ifs_clm_mntr_time; enum rtw89_ifs_clm_application ifs_clm_app; - u16 fahm_mntr_time; - u16 edcca_clm_mntr_time; u16 ccx_period; u8 ccx_unit_idx; - enum rtw89_ccx_edcca_opt_bw_idx ccx_edcca_opt_bw_idx; - u8 nhm_th[RTW89_NHM_TH_NUM]; u16 ifs_clm_th_l[RTW89_IFS_CLM_NUM]; u16 ifs_clm_th_h[RTW89_IFS_CLM_NUM]; - u8 fahm_numer_opt; - u8 fahm_denom_opt; - u8 fahm_th[RTW89_FAHM_TH_NUM]; - u16 clm_result; - u16 nhm_result[RTW89_NHM_RPT_NUM]; - u8 nhm_wgt[RTW89_NHM_RPT_NUM]; - u16 nhm_tx_cnt; - u16 nhm_cca_cnt; - u16 nhm_idle_cnt; u16 ifs_clm_tx; u16 ifs_clm_edcca_excl_cca; u16 ifs_clm_ofdmfa; @@ -3929,17 +3907,6 @@ struct rtw89_env_monitor_info { u8 ifs_clm_his[RTW89_IFS_CLM_NUM]; u16 ifs_clm_avg[RTW89_IFS_CLM_NUM]; u16 ifs_clm_cca[RTW89_IFS_CLM_NUM]; - u16 fahm_result[RTW89_FAHM_RPT_NUM]; - u16 fahm_denom_result; - u16 edcca_clm_result; - u8 clm_ratio; - u8 nhm_rpt[RTW89_NHM_RPT_NUM]; - u8 nhm_tx_ratio; - u8 nhm_cca_ratio; - u8 nhm_idle_ratio; - u8 nhm_ratio; - u16 nhm_result_sum; - u8 nhm_pwr; u8 ifs_clm_tx_ratio; u8 ifs_clm_edcca_excl_cca_ratio; u8 ifs_clm_cck_fa_ratio; @@ -3950,12 +3917,6 @@ struct rtw89_env_monitor_info { u16 ifs_clm_ofdm_fa_permil; u32 ifs_clm_ifs_avg[RTW89_IFS_CLM_NUM]; u32 ifs_clm_cca_avg[RTW89_IFS_CLM_NUM]; - u8 fahm_rpt[RTW89_FAHM_RPT_NUM]; - u16 fahm_result_sum; - u8 fahm_ratio; - u8 fahm_denom_ratio; - u8 fahm_pwr; - u8 edcca_clm_ratio; }; enum rtw89_ser_rcvy_step { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 49d593468265..b114babec698 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -758,11 +758,8 @@ static int hfc_reset_param(struct rtw89_dev *rtwdev) if (param_ini.pub_cfg) param->pub_cfg = *param_ini.pub_cfg; - if (param_ini.prec_cfg) { + if (param_ini.prec_cfg) param->prec_cfg = *param_ini.prec_cfg; - rtwdev->hal.sw_amsdu_max_size = - param->prec_cfg.wp_ch07_prec * HFC_PAGE_UNIT; - } if (param_ini.ch_cfg) param->ch_cfg = param_ini.ch_cfg; @@ -1541,7 +1538,6 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, return NULL; } - mac->dle_info.wde_pg_size = cfg->wde_size->pge_size; mac->dle_info.ple_pg_size = cfg->ple_size->pge_size; mac->dle_info.qta_mode = mode; mac->dle_info.c0_rx_qta = cfg->ple_min_qt->cma0_dma; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index e2eb9422a6bb..e94390b24824 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -3188,11 +3188,8 @@ static void rtw89_phy_ccx_top_setting_init(struct rtw89_dev *rtwdev) env->ccx_manual_ctrl = false; env->ccx_ongoing = false; env->ccx_rac_lv = RTW89_RAC_RELEASE; - env->ccx_rpt_stamp = 0; env->ccx_period = 0; env->ccx_unit_idx = RTW89_CCX_32_US; - env->ccx_trigger_time = 0; - env->ccx_edcca_opt_bw_idx = RTW89_CCX_EDCCA_BW20_0; rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_EN_MSK, 1); rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_CCX_TRIG_OPT_MSK, 1); @@ -3400,7 +3397,6 @@ static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev) rtw89_phy_set_phy_regs(rtwdev, R_IFS_COUNTER, B_IFS_COUNTER_CLR_MSK, 1); rtw89_phy_set_phy_regs(rtwdev, R_CCX, B_MEASUREMENT_TRIG_MSK, 1); - env->ccx_rpt_stamp++; env->ccx_ongoing = true; } -- cgit v1.2.3 From 686317a246cd10e343f8ca519a54e6a51a3eb142 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 14 Jun 2023 11:15:54 +0300 Subject: wifi: rtw89: cleanup rtw89_iqk_info and related code Drop useless '_iqk_track()' and 'rtw8852a_iqk_track()' (they just change 'thermal_rek_en' field which is set but unused and so removed as well) functions, set but unused 'kcount' field of 'struct rtw89_iqk_info', and convert 'thermal' to local variables where appropriate (it doesn't need to have longer storage duration because it is actually used for the debugging purposes only). Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230614081555.91395-2-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtw89/core.h | 3 -- drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 2 -- drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 - drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c | 36 ++--------------------- drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.h | 1 - drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c | 6 ---- drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c | 9 ++---- 7 files changed, 4 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index a4958e280828..0f7ca12e4b34 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3610,7 +3610,6 @@ struct rtw89_iqk_info { u8 iqk_band[RTW89_IQK_PATH_NR]; u8 iqk_ch[RTW89_IQK_PATH_NR]; u8 iqk_bw[RTW89_IQK_PATH_NR]; - u8 kcount; u8 iqk_times; u8 version; u32 nb_txcfir[RTW89_IQK_PATH_NR]; @@ -3625,8 +3624,6 @@ struct rtw89_iqk_info { bool iqk_xym_en; bool iqk_sram_en; bool iqk_cfir_en; - u8 thermal[RTW89_IQK_PATH_NR]; - bool thermal_rek_en; u32 syn1to2; u8 iqk_mcc_ch[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR]; u8 iqk_table_idx[RTW89_IQK_PATH_NR]; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 1899a5d69a81..466fa8e406da 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -1560,7 +1560,6 @@ static void _iqk_init(struct rtw89_dev *rtwdev) iqk_info->iqk_sram_en = false; iqk_info->iqk_cfir_en = false; iqk_info->iqk_xym_en = false; - iqk_info->thermal_rek_en = false; iqk_info->iqk_times = 0x0; for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { @@ -1589,7 +1588,6 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]==========IQK strat!!!!!==========\n"); iqk_info->iqk_times++; - iqk_info->kcount = 0; iqk_info->version = RTW8851B_IQK_VER; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]Test Ver 0x%x\n", iqk_info->version); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 559835ce86bb..6257414a3b4b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -1338,7 +1338,6 @@ static void rtw8852a_rfk_scan(struct rtw89_dev *rtwdev, bool start) static void rtw8852a_rfk_track(struct rtw89_dev *rtwdev) { rtw8852a_dpk_track(rtwdev); - rtw8852a_iqk_track(rtwdev); rtw8852a_tssi_track(rtwdev); } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c index cd6c39b7f802..d86429e4a35f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.c @@ -1284,11 +1284,8 @@ static void _iqk_info_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 tmp = 0x0; bool flag = 0x0; - iqk_info->thermal[path] = - ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); - iqk_info->thermal_rek_en = false; - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d_thermal = %d\n", path, - iqk_info->thermal[path]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d_thermal = %lu\n", path, + ewma_thermal_read(&rtwdev->phystat.avg_thermal[path])); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d_LOK_COR_fail= %d\n", path, iqk_info->lok_cor_fail[0][path]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d_LOK_FIN_fail= %d\n", path, @@ -1536,28 +1533,6 @@ static void _iqk_dbcc(struct rtw89_dev *rtwdev, u8 path) _iqk_afebb_restore(rtwdev, phy_idx, path); } -static void _iqk_track(struct rtw89_dev *rtwdev) -{ - struct rtw89_iqk_info *iqk = &rtwdev->iqk; - u8 path = 0x0; - u8 cur_ther; - - if (iqk->iqk_band[0] == RTW89_BAND_2G) - return; - if (iqk->iqk_bw[0] < RTW89_CHANNEL_WIDTH_80) - return; - - /* only check path 0 */ - for (path = 0; path < 1; path++) { - cur_ther = ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); - - if (abs(cur_ther - iqk->thermal[path]) > RTW8852A_IQK_THR_REK) - iqk->thermal_rek_en = true; - else - iqk->thermal_rek_en = false; - } -} - static void _rck(struct rtw89_dev *rtwdev, enum rtw89_rf_path path) { u32 rf_reg5, rck_val = 0; @@ -1616,7 +1591,6 @@ static void _iqk_init(struct rtw89_dev *rtwdev) iqk_info->iqk_sram_en = false; iqk_info->iqk_cfir_en = false; iqk_info->iqk_xym_en = false; - iqk_info->thermal_rek_en = false; iqk_info->iqk_times = 0x0; for (ch = 0; ch < RTW89_IQK_CHS_NR; ch++) { @@ -1645,7 +1619,6 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]==========IQK start!!!!!==========\n"); iqk_info->iqk_times++; - iqk_info->kcount = 0; iqk_info->version = RTW8852A_IQK_VER; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]Test Ver 0x%x\n", iqk_info->version); @@ -3655,11 +3628,6 @@ void rtw8852a_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_STOP); } -void rtw8852a_iqk_track(struct rtw89_dev *rtwdev) -{ - _iqk_track(rtwdev); -} - void rtw8852a_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool is_afe) { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.h index ea36553a76b7..fa058ccc8616 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a_rfk.h @@ -10,7 +10,6 @@ void rtw8852a_rck(struct rtw89_dev *rtwdev); void rtw8852a_dack(struct rtw89_dev *rtwdev); void rtw8852a_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); -void rtw8852a_iqk_track(struct rtw89_dev *rtwdev); void rtw8852a_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool is_afe); void rtw8852a_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index 722ae34b09c1..3107eed52f15 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -1317,10 +1317,6 @@ static void _iqk_info_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 tmp; bool flag; - iqk_info->thermal[path] = - ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); - iqk_info->thermal_rek_en = false; - flag = iqk_info->lok_cor_fail[0][path]; rtw89_phy_write32_mask(rtwdev, R_IQKINF, B_IQKINF_FCOR << (path * 4), flag); flag = iqk_info->lok_fin_fail[0][path]; @@ -1568,7 +1564,6 @@ static void _iqk_init(struct rtw89_dev *rtwdev) iqk_info->iqk_sram_en = false; iqk_info->iqk_cfir_en = false; iqk_info->iqk_xym_en = false; - iqk_info->thermal_rek_en = false; iqk_info->iqk_times = 0x0; for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { @@ -1624,7 +1619,6 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]==========IQK strat!!!!!==========\n"); iqk_info->iqk_times++; - iqk_info->kcount = 0; iqk_info->version = RTW8852B_IQK_VER; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]Test Ver 0x%x\n", iqk_info->version); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c index 2c0bc3a4ab3b..3423bdacc23c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c @@ -1261,11 +1261,8 @@ static void _iqk_info_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u32 tmp; bool flag; - iqk_info->thermal[path] = - ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]); - iqk_info->thermal_rek_en = false; - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d_thermal = %d\n", path, - iqk_info->thermal[path]); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d_thermal = %lu\n", path, + ewma_thermal_read(&rtwdev->phystat.avg_thermal[path])); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d_LOK_COR_fail= %d\n", path, iqk_info->lok_cor_fail[0][path]); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%d_LOK_FIN_fail= %d\n", path, @@ -1502,7 +1499,6 @@ static void _iqk_init(struct rtw89_dev *rtwdev) iqk_info->iqk_sram_en = false; iqk_info->iqk_cfir_en = false; iqk_info->iqk_xym_en = false; - iqk_info->thermal_rek_en = false; iqk_info->iqk_times = 0x0; for (ch = 0; ch < RTW89_IQK_CHS_NR; ch++) { @@ -1531,7 +1527,6 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]==========IQK strat!!!!!==========\n"); iqk_info->iqk_times++; - iqk_info->kcount = 0; iqk_info->version = RTW8852C_IQK_VER; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]Test Ver 0x%x\n", iqk_info->version); -- cgit v1.2.3 From 5bc9a34ce87bee0ca53b86ff1a5ca340a62c2117 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 14 Jun 2023 11:15:55 +0300 Subject: wifi: rtw89: fix spelling typo of IQK debug messages Fix spelling typo of IQK debug messages. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230614081555.91395-3-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c | 2 +- drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 466fa8e406da..48f1bcc46eda 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -1586,7 +1586,7 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, BTC_WRFK_ONESHOT_START); rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]==========IQK strat!!!!!==========\n"); + "[IQK]==========IQK start!!!!!==========\n"); iqk_info->iqk_times++; iqk_info->version = RTW8851B_IQK_VER; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index 3107eed52f15..fa018e1f499b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -1617,7 +1617,7 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]==========IQK strat!!!!!==========\n"); + "[IQK]==========IQK start!!!!!==========\n"); iqk_info->iqk_times++; iqk_info->version = RTW8852B_IQK_VER; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c index 3423bdacc23c..de7714f871d5 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c @@ -1525,7 +1525,7 @@ static void _doiqk(struct rtw89_dev *rtwdev, bool force, rtw89_btc_ntfy_wl_rfk(rtwdev, phy_map, BTC_WRFKT_IQK, BTC_WRFK_ONESHOT_START); rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]==========IQK strat!!!!!==========\n"); + "[IQK]==========IQK start!!!!!==========\n"); iqk_info->iqk_times++; iqk_info->version = RTW8852C_IQK_VER; -- cgit v1.2.3 From ed3c9a2fcab3b60b0766eb5d7566fd3b10df9a8e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 13 Jun 2023 13:50:06 -0700 Subject: net: tls: make the offload check helper take skb not socket All callers of tls_is_sk_tx_device_offloaded() currently do an equivalent of: if (skb->sk && tls_is_skb_tx_device_offloaded(skb->sk)) Have the helper accept skb and do the skb->sk check locally. Two drivers have local static inlines with similar wrappers already. While at it change the ifdef condition to TLS_DEVICE. Only TLS_DEVICE selects SOCK_VALIDATE_XMIT, so the two are equivalent. This makes removing the duplicated IS_ENABLED() check in funeth more obviously correct. Signed-off-by: Jakub Kicinski Acked-by: Maxim Mikityanskiy Reviewed-by: Simon Horman Acked-by: Tariq Toukan Acked-by: Dimitris Michailidis Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 4 ++-- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 5 ----- drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 +- drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c | 2 +- drivers/net/ethernet/fungible/funeth/funeth_tx.c | 3 +-- drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h | 5 ----- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 4 ++-- include/net/tls.h | 8 +++++--- net/tls/tls_device.c | 4 ++-- 12 files changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 007cec23a92f..16405b84dc2f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5442,7 +5442,7 @@ static netdev_tx_t bond_tls_device_xmit(struct bonding *bond, struct sk_buff *sk { struct net_device *tls_netdev = rcu_dereference(tls_get_ctx(skb->sk)->netdev); - /* tls_netdev might become NULL, even if tls_is_sk_tx_device_offloaded + /* tls_netdev might become NULL, even if tls_is_skb_tx_device_offloaded * was true, if tls_device_down is running in parallel, but it's OK, * because bond_get_slave_by_dev has a NULL check. */ @@ -5461,7 +5461,7 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev return NETDEV_TX_OK; #if IS_ENABLED(CONFIG_TLS_DEVICE) - if (skb->sk && tls_is_sk_tx_device_offloaded(skb->sk)) + if (tls_is_skb_tx_device_offloaded(skb)) return bond_tls_device_xmit(bond, skb, dev); #endif diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index f0bc7396ce2b..2eb33a727bba 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1175,7 +1175,7 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, txq = netdev_pick_tx(dev, skb, sb_dev); if (xfrm_offload(skb) || is_ptp_enabled(skb, dev) || skb->encapsulation || - cxgb4_is_ktls_skb(skb) || + tls_is_skb_tx_device_offloaded(skb) || (proto != IPPROTO_TCP && proto != IPPROTO_UDP)) txq = txq % pi->nqsets; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 34546f5312ee..a9599ba26975 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -497,11 +497,6 @@ struct cxgb4_uld_info { #endif }; -static inline bool cxgb4_is_ktls_skb(struct sk_buff *skb) -{ - return skb->sk && tls_is_sk_tx_device_offloaded(skb->sk); -} - void cxgb4_uld_enable(struct adapter *adap); void cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p); int cxgb4_unregister_uld(enum cxgb4_uld type); diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 46809e2d94ee..98dd78551d89 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -1530,7 +1530,7 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) #endif /* CHELSIO_IPSEC_INLINE */ #if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE) - if (cxgb4_is_ktls_skb(skb) && + if (tls_is_skb_tx_device_offloaded(skb) && (skb->len - skb_tcp_all_headers(skb))) return adap->uld[CXGB4_ULD_KTLS].tx_handler(skb, dev); #endif /* CHELSIO_TLS_DEVICE */ diff --git a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c index 1a5fdd755e9e..bcdc7fc2f427 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c @@ -1946,7 +1946,7 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev) tls_ctx = tls_get_ctx(skb->sk); tls_netdev = rcu_dereference_bh(tls_ctx->netdev); /* Don't quit on NULL: if tls_device_down is running in parallel, - * netdev might become NULL, even if tls_is_sk_tx_device_offloaded was + * netdev might become NULL, even if tls_is_skb_tx_device_offloaded was * true. Rather continue processing this packet. */ if (unlikely(tls_netdev && tls_netdev != dev)) diff --git a/drivers/net/ethernet/fungible/funeth/funeth_tx.c b/drivers/net/ethernet/fungible/funeth/funeth_tx.c index 706d81e39a54..8ddefd3ec15b 100644 --- a/drivers/net/ethernet/fungible/funeth/funeth_tx.c +++ b/drivers/net/ethernet/fungible/funeth/funeth_tx.c @@ -348,8 +348,7 @@ netdev_tx_t fun_start_xmit(struct sk_buff *skb, struct net_device *netdev) unsigned int tls_len = 0; unsigned int ndesc; - if (IS_ENABLED(CONFIG_TLS_DEVICE) && skb->sk && - tls_is_sk_tx_device_offloaded(skb->sk)) { + if (tls_is_skb_tx_device_offloaded(skb)) { skb = fun_tls_tx(skb, q, &tls_len); if (unlikely(!skb)) goto dropped; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h index c964644ee866..bac4717548c6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/en_accel.h @@ -125,7 +125,7 @@ static inline bool mlx5e_accel_tx_begin(struct net_device *dev, #ifdef CONFIG_MLX5_EN_TLS /* May send WQEs. */ - if (mlx5e_ktls_skb_offloaded(skb)) + if (tls_is_skb_tx_device_offloaded(skb)) if (unlikely(!mlx5e_ktls_handle_tx_skb(dev, sq, skb, &state->tls))) return false; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c index 0e4c0a093293..efb2cf74ad6a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c @@ -846,7 +846,7 @@ bool mlx5e_ktls_handle_tx_skb(struct net_device *netdev, struct mlx5e_txqsq *sq, tls_ctx = tls_get_ctx(skb->sk); tls_netdev = rcu_dereference_bh(tls_ctx->netdev); /* Don't WARN on NULL: if tls_device_down is running in parallel, - * netdev might become NULL, even if tls_is_sk_tx_device_offloaded was + * netdev might become NULL, even if tls_is_skb_tx_device_offloaded was * true. Rather continue processing this packet. */ if (WARN_ON_ONCE(tls_netdev && tls_netdev != netdev)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h index 2dd78dd4ad65..f87b65c560ea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_txrx.h @@ -49,11 +49,6 @@ mlx5e_ktls_rx_pending_resync_list(struct mlx5e_channel *c, int budget) return budget && test_bit(MLX5E_SQ_STATE_PENDING_TLS_RX_RESYNC, &c->async_icosq.state); } -static inline bool mlx5e_ktls_skb_offloaded(struct sk_buff *skb) -{ - return skb->sk && tls_is_sk_tx_device_offloaded(skb->sk); -} - static inline void mlx5e_ktls_handle_tx_wqe(struct mlx5_wqe_ctrl_seg *cseg, struct mlx5e_accel_tx_tls_state *state) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index b7cce746b5c0..49f2f081ebb5 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -598,7 +598,7 @@ nfp_net_tls_tx(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, if (likely(!dp->ktls_tx)) return skb; - if (!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk)) + if (!tls_is_skb_tx_device_offloaded(skb)) return skb; datalen = skb->len - skb_tcp_all_headers(skb); @@ -666,7 +666,7 @@ void nfp_net_tls_tx_undo(struct sk_buff *skb, u64 tls_handle) if (!tls_handle) return; - if (WARN_ON_ONCE(!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk))) + if (WARN_ON_ONCE(!tls_is_skb_tx_device_offloaded(skb))) return; datalen = skb->len - skb_tcp_all_headers(skb); diff --git a/include/net/tls.h b/include/net/tls.h index b7d0f1e3058b..5e71dd3df8ca 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -370,10 +370,12 @@ struct sk_buff * tls_validate_xmit_skb_sw(struct sock *sk, struct net_device *dev, struct sk_buff *skb); -static inline bool tls_is_sk_tx_device_offloaded(struct sock *sk) +static inline bool tls_is_skb_tx_device_offloaded(const struct sk_buff *skb) { -#ifdef CONFIG_SOCK_VALIDATE_XMIT - return sk_fullsock(sk) && +#ifdef CONFIG_TLS_DEVICE + struct sock *sk = skb->sk; + + return sk && sk_fullsock(sk) && (smp_load_acquire(&sk->sk_validate_xmit_skb) == &tls_validate_xmit_skb); #else diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index b4864d55900f..b82770f68807 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -1219,7 +1219,7 @@ int tls_set_device_offload(struct sock *sk, struct tls_context *ctx) tls_device_attach(ctx, sk, netdev); up_read(&device_offload_lock); - /* following this assignment tls_is_sk_tx_device_offloaded + /* following this assignment tls_is_skb_tx_device_offloaded * will return true and the context might be accessed * by the netdev's xmit function. */ @@ -1372,7 +1372,7 @@ static int tls_device_down(struct net_device *netdev) list_for_each_entry_safe(ctx, tmp, &list, list) { /* Stop offloaded TX and switch to the fallback. - * tls_is_sk_tx_device_offloaded will return false. + * tls_is_skb_tx_device_offloaded will return false. */ WRITE_ONCE(ctx->sk->sk_validate_xmit_skb, tls_validate_xmit_skb_sw); -- cgit v1.2.3 From f0ec58d557d65838974035ffd8a8862cf8166a81 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 13 Jun 2023 17:28:00 -0700 Subject: tools: ynl: work around stale system headers The inability to include the uAPI headers directly in tools/ is one of the bigger annoyances of compiling user space code. Most projects trade the pain for smaller inconvenience of having to copy the headers under tools/include. In case of netlink headers I think that we can avoid both. Netlink family headers are simple and should be self-contained. We can try to twiddle the Makefile a little to force-include just the family header, and use system headers for the rest. This works fairly well. There are two warts - for some reason if we specify -include $path/family.h as a compilation flag, the #ifdef header guard does not seem to work. So we need to throw the guard in on the command line as well. Seems like GCC detects that the header is different and tries to include both. Second problem is that make wants hash sign to be escaped or not depending on the version. Sigh. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- tools/net/ynl/Makefile.deps | 28 ++++++++++++++++++++++++++++ tools/net/ynl/generated/Makefile | 6 ++++-- tools/net/ynl/samples/Makefile | 4 +++- 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 tools/net/ynl/Makefile.deps diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps new file mode 100644 index 000000000000..524fc4bb586b --- /dev/null +++ b/tools/net/ynl/Makefile.deps @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Try to include uAPI headers from the kernel uapi/ path. +# Most code under tools/ requires the respective kernel uAPI headers +# to be copied to tools/include. The duplication is annoying. +# All the family headers should be self-contained. We avoid the copying +# by selectively including just the uAPI header of the family directly +# from the kernel sources. + +UAPI_PATH:=../../../../include/uapi/ + +# If the header does not exist at all in the system path - let the +# compiler fall back to the kernel header via -Idirafter. +# GCC seems to ignore header guard if the header is different, so we need +# to specify the -D$(hdr_guard). +# And we need to define HASH indirectly because GNU Make 4.2 wants it escaped +# and Gnu Make 4.4 wants it without escaping. + +HASH := \# + +get_hdr_inc=$(if $(shell echo "$(HASH)include " | \ + cpp >>/dev/null 2>/dev/null && echo yes),\ + -D$(1) -include $(UAPI_PATH)/linux/$(2)) + +CFLAGS_devlink:=$(call get_hdr_inc,_UAPI_LINUX_DEVLINK_H_,devlink.h) +CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) +CFLAGS_handshake:=$(call get_hdr_inc,_UAPI_LINUX_HANDSHAKE_H,handshake.h) +CFLAGS_netdev:=$(call get_hdr_inc,_UAPI_LINUX_NETDEV_H,netdev.h) diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index f15c24893296..f8817d2e56e4 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -2,11 +2,13 @@ CC=gcc CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ - -I../lib/ + -I../lib/ -idirafter $(UAPI_PATH) ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan endif +include ../Makefile.deps + YNL_GEN_ARG_ethtool:=--user-header linux/ethtool_netlink.h \ --exclude-op stats-get @@ -33,7 +35,7 @@ protos.a: $(OBJS) %-user.o: %-user.c %-user.h @echo -e "\tCC $@" - @$(COMPILE.c) -c -o $@ $< + @$(COMPILE.c) $(CFLAGS_$*) -o $@ $< clean: rm -f *.o diff --git a/tools/net/ynl/samples/Makefile b/tools/net/ynl/samples/Makefile index 714316cad45f..f2db8bb78309 100644 --- a/tools/net/ynl/samples/Makefile +++ b/tools/net/ynl/samples/Makefile @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 +include ../Makefile.deps + CC=gcc CFLAGS=-std=gnu11 -O2 -W -Wall -Wextra -Wno-unused-parameter -Wshadow \ - -I../lib/ -I../generated/ + -I../lib/ -I../generated/ -idirafter $(UAPI_PATH) ifeq ("$(DEBUG)","1") CFLAGS += -g -fsanitize=address -fsanitize=leak -static-libasan endif -- cgit v1.2.3 From 97c5209b3d374a25ebdb4c2ea9e9c1b121768da0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 Jun 2023 10:03:59 +0300 Subject: leds: trigger: netdev: uninitialized variable in netdev_trig_activate() The qca8k_cled_hw_control_get() function which implements ->hw_control_get sets the appropriate bits but does not clear them. This leads to an uninitialized variable bug. Fix this by setting mode to zero at the start. Fixes: e0256648c831 ("net: dsa: qca8k: implement hw_control ops") Signed-off-by: Dan Carpenter Reviewed-by: Andrew Lunn Acked-by: Lee Jones Signed-off-by: David S. Miller --- drivers/leds/trigger/ledtrig-netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index b0a6f2749552..2311dae7f070 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -445,7 +445,7 @@ static void netdev_trig_work(struct work_struct *work) static int netdev_trig_activate(struct led_classdev *led_cdev) { struct led_netdev_data *trigger_data; - unsigned long mode; + unsigned long mode = 0; struct device *dev; int rc; -- cgit v1.2.3 From 3a5d50f8eb4fcf3c69ae858020c49877e4eeaf05 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 13 Jun 2023 12:19:45 +0300 Subject: wifi: ath12k: fix conf_mutex in ath12k_mac_op_unassign_vif_chanctx() "mutex_unlock(&ar->conf_mutex);" is always called at end of function ath12k_mac_op_unassign_vif_chanctx(), so delete this unlock to make sure lock/unlock is paired. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4 Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230608104444.3134-1-quic_wgong@quicinc.com --- drivers/net/wireless/ath/ath12k/mac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index a344211f5b53..1bb9802ef569 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5928,7 +5928,6 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, } arvif->is_started = false; - mutex_unlock(&ar->conf_mutex); } ret = ath12k_mac_vdev_stop(arvif); -- cgit v1.2.3 From 16e0077e14a73866e9b0f4a6bf4ad3d4a5cb0f2a Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Tue, 13 Jun 2023 12:19:40 +0300 Subject: wifi: ath11k: Add missing check for ioremap Add check for ioremap() and return the error if it fails in order to guarantee the success of ioremap(), same as in ath11k_qmi_load_file_target_mem(). Fixes: 6ac04bdc5edb ("ath11k: Use reserved host DDR addresses from DT for PCI devices") Signed-off-by: Jiasheng Jiang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230608022858.27405-1-jiasheng@iscas.ac.cn --- drivers/net/wireless/ath/ath11k/qmi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 5da4c7663b45..5d1c03b7befe 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2058,6 +2058,9 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) ab->qmi.target_mem[idx].iaddr = ioremap(ab->qmi.target_mem[idx].paddr, ab->qmi.target_mem[i].size); + if (!ab->qmi.target_mem[idx].iaddr) + return -EIO; + ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; host_ddr_sz = ab->qmi.target_mem[i].size; ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; @@ -2083,6 +2086,8 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) ab->qmi.target_mem[idx].iaddr = ioremap(ab->qmi.target_mem[idx].paddr, ab->qmi.target_mem[i].size); + if (!ab->qmi.target_mem[idx].iaddr) + return -EIO; } else { ab->qmi.target_mem[idx].paddr = ATH11K_QMI_CALDB_ADDRESS; -- cgit v1.2.3 From e1d001fa5b477c4da46a29be1fcece91db7c7c6f Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 9 Jun 2023 08:27:42 -0700 Subject: net: ioctl: Use kernel memory on protocol ioctl callbacks Most of the ioctls to net protocols operates directly on userspace argument (arg). Usually doing get_user()/put_user() directly in the ioctl callback. This is not flexible, because it is hard to reuse these functions without passing userspace buffers. Change the "struct proto" ioctls to avoid touching userspace memory and operate on kernel buffers, i.e., all protocol's ioctl callbacks is adapted to operate on a kernel memory other than on userspace (so, no more {put,get}_user() and friends being called in the ioctl callback). This changes the "struct proto" ioctl format in the following way: int (*ioctl)(struct sock *sk, int cmd, - unsigned long arg); + int *karg); (Important to say that this patch does not touch the "struct proto_ops" protocols) So, the "karg" argument, which is passed to the ioctl callback, is a pointer allocated to kernel space memory (inside a function wrapper). This buffer (karg) may contain input argument (copied from userspace in a prep function) and it might return a value/buffer, which is copied back to userspace if necessary. There is not one-size-fits-all format (that is I am using 'may' above), but basically, there are three type of ioctls: 1) Do not read from userspace, returns a result to userspace 2) Read an input parameter from userspace, and does not return anything to userspace 3) Read an input from userspace, and return a buffer to userspace. The default case (1) (where no input parameter is given, and an "int" is returned to userspace) encompasses more than 90% of the cases, but there are two other exceptions. Here is a list of exceptions: * Protocol RAW: * cmd = SIOCGETVIFCNT: * input and output = struct sioc_vif_req * cmd = SIOCGETSGCNT * input and output = struct sioc_sg_req * Explanation: for the SIOCGETVIFCNT case, userspace passes the input argument, which is struct sioc_vif_req. Then the callback populates the struct, which is copied back to userspace. * Protocol RAW6: * cmd = SIOCGETMIFCNT_IN6 * input and output = struct sioc_mif_req6 * cmd = SIOCGETSGCNT_IN6 * input and output = struct sioc_sg_req6 * Protocol PHONET: * cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE * input int (4 bytes) * Nothing is copied back to userspace. For the exception cases, functions sock_sk_ioctl_inout() will copy the userspace input, and copy it back to kernel space. The wrapper that prepare the buffer and put the buffer back to user is sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now calls sk_ioctl(), which will handle all cases. Signed-off-by: Breno Leitao Reviewed-by: Willem de Bruijn Reviewed-by: David Ahern Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org Signed-off-by: Jakub Kicinski --- include/linux/icmpv6.h | 6 +++++ include/linux/mroute.h | 22 ++++++++++++++-- include/linux/mroute6.h | 31 ++++++++++++++++++++-- include/net/phonet/phonet.h | 21 +++++++++++++++ include/net/sock.h | 5 +++- include/net/tcp.h | 2 +- include/net/udp.h | 2 +- net/core/sock.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ net/dccp/dccp.h | 2 +- net/dccp/proto.c | 12 ++++----- net/ieee802154/socket.c | 15 +++++------ net/ipv4/af_inet.c | 2 +- net/ipv4/ipmr.c | 63 +++++++++++++++++++++++++++----------------- net/ipv4/raw.c | 16 ++++++------ net/ipv4/tcp.c | 5 ++-- net/ipv4/udp.c | 12 ++++----- net/ipv6/af_inet6.c | 2 +- net/ipv6/ip6mr.c | 44 +++++++++++++------------------ net/ipv6/raw.c | 16 ++++++------ net/l2tp/l2tp_core.h | 2 +- net/l2tp/l2tp_ip.c | 9 +++---- net/mptcp/protocol.c | 11 ++++---- net/phonet/datagram.c | 11 +++----- net/phonet/pep.c | 11 ++++---- net/phonet/socket.c | 2 +- net/sctp/socket.c | 8 +++--- 26 files changed, 267 insertions(+), 129 deletions(-) diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index db0f4fcfdaf4..1fe33e6741cc 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -111,4 +111,10 @@ static inline bool icmpv6_is_err(int type) return false; } +static inline int sk_is_icmpv6(struct sock *sk) +{ + return sk->sk_family == AF_INET6 && + inet_sk(sk)->inet_num == IPPROTO_ICMPV6; +} + #endif diff --git a/include/linux/mroute.h b/include/linux/mroute.h index 80b8400ab8b2..94c6e6f549f0 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -16,12 +16,19 @@ static inline int ip_mroute_opt(int opt) return opt >= MRT_BASE && opt <= MRT_MAX; } +static inline int sk_is_ipmr(struct sock *sk) +{ + return sk->sk_family == AF_INET && + inet_sk(sk)->inet_num == IPPROTO_IGMP; +} + int ip_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int); int ip_mroute_getsockopt(struct sock *, int, sockptr_t, sockptr_t); -int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); +int ipmr_ioctl(struct sock *sk, int cmd, void *arg); int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); int ip_mr_init(void); bool ipmr_rule_default(const struct fib_rule *rule); +int ipmr_sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); #else static inline int ip_mroute_setsockopt(struct sock *sock, int optname, sockptr_t optval, unsigned int optlen) @@ -35,7 +42,7 @@ static inline int ip_mroute_getsockopt(struct sock *sk, int optname, return -ENOPROTOOPT; } -static inline int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) +static inline int ipmr_ioctl(struct sock *sk, int cmd, void *arg) { return -ENOIOCTLCMD; } @@ -50,10 +57,21 @@ static inline int ip_mroute_opt(int opt) return 0; } +static inline int sk_is_ipmr(struct sock *sk) +{ + return 0; +} + static inline bool ipmr_rule_default(const struct fib_rule *rule) { return true; } + +static inline int ipmr_sk_ioctl(struct sock *sk, unsigned int cmd, + void __user *arg) +{ + return 1; +} #endif #define VIFF_STATIC 0x8000 diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index 8f2b307fb124..2f95d5b4e47a 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -29,10 +29,10 @@ struct sock; extern int ip6_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int); extern int ip6_mroute_getsockopt(struct sock *, int, sockptr_t, sockptr_t); extern int ip6_mr_input(struct sk_buff *skb); -extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); extern int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); extern int ip6_mr_init(void); extern void ip6_mr_cleanup(void); +int ip6mr_ioctl(struct sock *sk, int cmd, void *arg); #else static inline int ip6_mroute_setsockopt(struct sock *sock, int optname, sockptr_t optval, unsigned int optlen) @@ -48,7 +48,7 @@ int ip6_mroute_getsockopt(struct sock *sock, } static inline -int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) +int ip6mr_ioctl(struct sock *sk, int cmd, void *arg) { return -ENOIOCTLCMD; } @@ -100,6 +100,27 @@ extern int ip6mr_get_route(struct net *net, struct sk_buff *skb, #ifdef CONFIG_IPV6_MROUTE bool mroute6_is_socket(struct net *net, struct sk_buff *skb); extern int ip6mr_sk_done(struct sock *sk); +static inline int ip6mr_sk_ioctl(struct sock *sk, unsigned int cmd, + void __user *arg) +{ + switch (cmd) { + /* These userspace buffers will be consumed by ip6mr_ioctl() */ + case SIOCGETMIFCNT_IN6: { + struct sioc_mif_req6 buffer; + + return sock_ioctl_inout(sk, cmd, arg, &buffer, + sizeof(buffer)); + } + case SIOCGETSGCNT_IN6: { + struct sioc_mif_req6 buffer; + + return sock_ioctl_inout(sk, cmd, arg, &buffer, + sizeof(buffer)); + } + } + + return 1; +} #else static inline bool mroute6_is_socket(struct net *net, struct sk_buff *skb) { @@ -109,5 +130,11 @@ static inline int ip6mr_sk_done(struct sock *sk) { return 0; } + +static inline int ip6mr_sk_ioctl(struct sock *sk, unsigned int cmd, + void __user *arg) +{ + return 1; +} #endif #endif diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h index 862f1719b523..cf5ecae4a2fc 100644 --- a/include/net/phonet/phonet.h +++ b/include/net/phonet/phonet.h @@ -109,4 +109,25 @@ void phonet_sysctl_exit(void); int isi_register(void); void isi_unregister(void); +static inline bool sk_is_phonet(struct sock *sk) +{ + return sk->sk_family == PF_PHONET; +} + +static inline int phonet_sk_ioctl(struct sock *sk, unsigned int cmd, + void __user *arg) +{ + int karg; + + switch (cmd) { + case SIOCPNADDRESOURCE: + case SIOCPNDELRESOURCE: + if (get_user(karg, (int __user *)arg)) + return -EFAULT; + + return sk->sk_prot->ioctl(sk, cmd, &karg); + } + /* A positive return value means that the ioctl was not processed */ + return 1; +} #endif diff --git a/include/net/sock.h b/include/net/sock.h index 2790133b4b76..62a1b99da349 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1258,7 +1258,7 @@ struct proto { bool kern); int (*ioctl)(struct sock *sk, int cmd, - unsigned long arg); + int *karg); int (*init)(struct sock *sk); void (*destroy)(struct sock *sk); void (*shutdown)(struct sock *sk, int how); @@ -2974,6 +2974,9 @@ int sock_get_timeout(long timeo, void *optval, bool old_timeval); int sock_copy_user_timeval(struct __kernel_sock_timeval *tv, sockptr_t optval, int optlen, bool old_timeval); +int sock_ioctl_inout(struct sock *sk, unsigned int cmd, + void __user *arg, void *karg, size_t size); +int sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); static inline bool sk_is_readable(struct sock *sk) { if (sk->sk_prot->sock_is_readable) diff --git a/include/net/tcp.h b/include/net/tcp.h index bf9f56225821..9c08eab647a2 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -340,7 +340,7 @@ void tcp_release_cb(struct sock *sk); void tcp_wfree(struct sk_buff *skb); void tcp_write_timer_handler(struct sock *sk); void tcp_delack_timer_handler(struct sock *sk); -int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); +int tcp_ioctl(struct sock *sk, int cmd, int *karg); int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb); void tcp_rcv_established(struct sock *sk, struct sk_buff *skb); void tcp_rcv_space_adjust(struct sock *sk); diff --git a/include/net/udp.h b/include/net/udp.h index e01340a27155..4d13424f8f72 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -285,7 +285,7 @@ void udp_flush_pending_frames(struct sock *sk); int udp_cmsg_send(struct sock *sk, struct msghdr *msg, u16 *gso_size); void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst); int udp_rcv(struct sk_buff *skb); -int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); +int udp_ioctl(struct sock *sk, int cmd, int *karg); int udp_init_sock(struct sock *sk); int udp_pre_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); int __udp_disconnect(struct sock *sk, int flags); diff --git a/net/core/sock.c b/net/core/sock.c index ea66b1afadd0..cff3e82514d1 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -114,6 +114,9 @@ #include #include #include +#include +#include +#include #include @@ -138,6 +141,7 @@ #include #include +#include #include @@ -4150,3 +4154,63 @@ int sock_bind_add(struct sock *sk, struct sockaddr *addr, int addr_len) return sk->sk_prot->bind_add(sk, addr, addr_len); } EXPORT_SYMBOL(sock_bind_add); + +/* Copy 'size' bytes from userspace and return `size` back to userspace */ +int sock_ioctl_inout(struct sock *sk, unsigned int cmd, + void __user *arg, void *karg, size_t size) +{ + int ret; + + if (copy_from_user(karg, arg, size)) + return -EFAULT; + + ret = READ_ONCE(sk->sk_prot)->ioctl(sk, cmd, karg); + if (ret) + return ret; + + if (copy_to_user(arg, karg, size)) + return -EFAULT; + + return 0; +} +EXPORT_SYMBOL(sock_ioctl_inout); + +/* This is the most common ioctl prep function, where the result (4 bytes) is + * copied back to userspace if the ioctl() returns successfully. No input is + * copied from userspace as input argument. + */ +static int sock_ioctl_out(struct sock *sk, unsigned int cmd, void __user *arg) +{ + int ret, karg = 0; + + ret = READ_ONCE(sk->sk_prot)->ioctl(sk, cmd, &karg); + if (ret) + return ret; + + return put_user(karg, (int __user *)arg); +} + +/* A wrapper around sock ioctls, which copies the data from userspace + * (depending on the protocol/ioctl), and copies back the result to userspace. + * The main motivation for this function is to pass kernel memory to the + * protocol ioctl callbacks, instead of userspace memory. + */ +int sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) +{ + int rc = 1; + + if (sk_is_ipmr(sk)) + rc = ipmr_sk_ioctl(sk, cmd, arg); + else if (sk_is_icmpv6(sk)) + rc = ip6mr_sk_ioctl(sk, cmd, arg); + else if (sk_is_phonet(sk)) + rc = phonet_sk_ioctl(sk, cmd, arg); + + /* If ioctl was processed, returns its value */ + if (rc <= 0) + return rc; + + /* Otherwise call the default handler */ + return sock_ioctl_out(sk, cmd, arg); +} +EXPORT_SYMBOL(sk_ioctl); diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 9ddc3a9e89e4..1f748ed1279d 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -292,7 +292,7 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); int dccp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, unsigned int optlen); -int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); +int dccp_ioctl(struct sock *sk, int cmd, int *karg); int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); int dccp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index b0ebf853cb07..f331e5977a84 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -362,7 +362,7 @@ __poll_t dccp_poll(struct file *file, struct socket *sock, EXPORT_SYMBOL_GPL(dccp_poll); -int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) +int dccp_ioctl(struct sock *sk, int cmd, int *karg) { int rc = -ENOTCONN; @@ -373,17 +373,17 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) switch (cmd) { case SIOCOUTQ: { - int amount = sk_wmem_alloc_get(sk); + *karg = sk_wmem_alloc_get(sk); /* Using sk_wmem_alloc here because sk_wmem_queued is not used by DCCP and * always 0, comparably to UDP. */ - rc = put_user(amount, (int __user *)arg); + rc = 0; } break; case SIOCINQ: { struct sk_buff *skb; - unsigned long amount = 0; + *karg = 0; skb = skb_peek(&sk->sk_receive_queue); if (skb != NULL) { @@ -391,9 +391,9 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) * We will only return the amount of this packet since * that is all that will be read. */ - amount = skb->len; + *karg = skb->len; } - rc = put_user(amount, (int __user *)arg); + rc = 0; } break; default: diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index 1fa2fe041ec0..9c124705120d 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c @@ -162,7 +162,7 @@ static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, default: if (!sk->sk_prot->ioctl) return -ENOIOCTLCMD; - return sk->sk_prot->ioctl(sk, cmd, arg); + return sk_ioctl(sk, cmd, (void __user *)arg); } } @@ -531,22 +531,21 @@ out: return err; } -static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) +static int dgram_ioctl(struct sock *sk, int cmd, int *karg) { switch (cmd) { case SIOCOUTQ: { - int amount = sk_wmem_alloc_get(sk); + *karg = sk_wmem_alloc_get(sk); - return put_user(amount, (int __user *)arg); + return 0; } case SIOCINQ: { struct sk_buff *skb; - unsigned long amount; - amount = 0; + *karg = 0; spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); if (skb) { @@ -554,10 +553,10 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) * of this packet since that is all * that will be read. */ - amount = skb->len - ieee802154_hdr_length(skb); + *karg = skb->len - ieee802154_hdr_length(skb); } spin_unlock_bh(&sk->sk_receive_queue.lock); - return put_user(amount, (int __user *)arg); + return 0; } } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 0e16ac8282c5..38e649fb4474 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -998,7 +998,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; default: if (sk->sk_prot->ioctl) - err = sk->sk_prot->ioctl(sk, cmd, arg); + err = sk_ioctl(sk, cmd, (void __user *)arg); else err = -ENOIOCTLCMD; break; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index eec1f6df80d8..3f0c6d602fb7 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1547,6 +1547,28 @@ out: return ret; } +/* Execute if this ioctl is a special mroute ioctl */ +int ipmr_sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) +{ + switch (cmd) { + /* These userspace buffers will be consumed by ipmr_ioctl() */ + case SIOCGETVIFCNT: { + struct sioc_vif_req buffer; + + return sock_ioctl_inout(sk, cmd, arg, &buffer, + sizeof(buffer)); + } + case SIOCGETSGCNT: { + struct sioc_sg_req buffer; + + return sock_ioctl_inout(sk, cmd, arg, &buffer, + sizeof(buffer)); + } + } + /* return code > 0 means that the ioctl was not executed */ + return 1; +} + /* Getsock opt support for the multicast routing system. */ int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval, sockptr_t optlen) @@ -1593,13 +1615,13 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval, } /* The IP multicast ioctl support routines. */ -int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) +int ipmr_ioctl(struct sock *sk, int cmd, void *arg) { - struct sioc_sg_req sr; - struct sioc_vif_req vr; struct vif_device *vif; struct mfc_cache *c; struct net *net = sock_net(sk); + struct sioc_vif_req *vr; + struct sioc_sg_req *sr; struct mr_table *mrt; mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); @@ -1608,40 +1630,33 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) switch (cmd) { case SIOCGETVIFCNT: - if (copy_from_user(&vr, arg, sizeof(vr))) - return -EFAULT; - if (vr.vifi >= mrt->maxvif) + vr = (struct sioc_vif_req *)arg; + if (vr->vifi >= mrt->maxvif) return -EINVAL; - vr.vifi = array_index_nospec(vr.vifi, mrt->maxvif); + vr->vifi = array_index_nospec(vr->vifi, mrt->maxvif); rcu_read_lock(); - vif = &mrt->vif_table[vr.vifi]; - if (VIF_EXISTS(mrt, vr.vifi)) { - vr.icount = READ_ONCE(vif->pkt_in); - vr.ocount = READ_ONCE(vif->pkt_out); - vr.ibytes = READ_ONCE(vif->bytes_in); - vr.obytes = READ_ONCE(vif->bytes_out); + vif = &mrt->vif_table[vr->vifi]; + if (VIF_EXISTS(mrt, vr->vifi)) { + vr->icount = READ_ONCE(vif->pkt_in); + vr->ocount = READ_ONCE(vif->pkt_out); + vr->ibytes = READ_ONCE(vif->bytes_in); + vr->obytes = READ_ONCE(vif->bytes_out); rcu_read_unlock(); - if (copy_to_user(arg, &vr, sizeof(vr))) - return -EFAULT; return 0; } rcu_read_unlock(); return -EADDRNOTAVAIL; case SIOCGETSGCNT: - if (copy_from_user(&sr, arg, sizeof(sr))) - return -EFAULT; + sr = (struct sioc_sg_req *)arg; rcu_read_lock(); - c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr); + c = ipmr_cache_find(mrt, sr->src.s_addr, sr->grp.s_addr); if (c) { - sr.pktcnt = c->_c.mfc_un.res.pkt; - sr.bytecnt = c->_c.mfc_un.res.bytes; - sr.wrong_if = c->_c.mfc_un.res.wrong_if; + sr->pktcnt = c->_c.mfc_un.res.pkt; + sr->bytecnt = c->_c.mfc_un.res.bytes; + sr->wrong_if = c->_c.mfc_un.res.wrong_if; rcu_read_unlock(); - - if (copy_to_user(arg, &sr, sizeof(sr))) - return -EFAULT; return 0; } rcu_read_unlock(); diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 9aacce9db7b9..7782ff5e6539 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -856,29 +856,29 @@ static int raw_getsockopt(struct sock *sk, int level, int optname, return do_raw_getsockopt(sk, level, optname, optval, optlen); } -static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) +static int raw_ioctl(struct sock *sk, int cmd, int *karg) { switch (cmd) { case SIOCOUTQ: { - int amount = sk_wmem_alloc_get(sk); - - return put_user(amount, (int __user *)arg); + *karg = sk_wmem_alloc_get(sk); + return 0; } case SIOCINQ: { struct sk_buff *skb; - int amount = 0; spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); if (skb) - amount = skb->len; + *karg = skb->len; + else + *karg = 0; spin_unlock_bh(&sk->sk_receive_queue.lock); - return put_user(amount, (int __user *)arg); + return 0; } default: #ifdef CONFIG_IP_MROUTE - return ipmr_ioctl(sk, cmd, (void __user *)arg); + return ipmr_ioctl(sk, cmd, karg); #else return -ENOIOCTLCMD; #endif diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index fba6578bc98f..0e21ea92dc1d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -599,7 +599,7 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait) } EXPORT_SYMBOL(tcp_poll); -int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) +int tcp_ioctl(struct sock *sk, int cmd, int *karg) { struct tcp_sock *tp = tcp_sk(sk); int answ; @@ -641,7 +641,8 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) return -ENOIOCTLCMD; } - return put_user(answ, (int __user *)arg); + *karg = answ; + return 0; } EXPORT_SYMBOL(tcp_ioctl); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7e0542c10471..48fdcd3cad9c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1692,21 +1692,19 @@ static int first_packet_length(struct sock *sk) * IOCTL requests applicable to the UDP protocol */ -int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) +int udp_ioctl(struct sock *sk, int cmd, int *karg) { switch (cmd) { case SIOCOUTQ: { - int amount = sk_wmem_alloc_get(sk); - - return put_user(amount, (int __user *)arg); + *karg = sk_wmem_alloc_get(sk); + return 0; } case SIOCINQ: { - int amount = max_t(int, 0, first_packet_length(sk)); - - return put_user(amount, (int __user *)arg); + *karg = max_t(int, 0, first_packet_length(sk)); + return 0; } default: diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 564942bee067..b3451cf47d29 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -579,7 +579,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) prot = READ_ONCE(sk->sk_prot); if (!prot->ioctl) return -ENOIOCTLCMD; - return prot->ioctl(sk, cmd, arg); + return sk_ioctl(sk, cmd, (void __user *)arg); } /*NOTREACHED*/ return 0; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 51cf37abd142..cc3d5ad17257 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1879,11 +1879,10 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval, /* * The IP multicast ioctl support routines. */ - -int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) +int ip6mr_ioctl(struct sock *sk, int cmd, void *arg) { - struct sioc_sg_req6 sr; - struct sioc_mif_req6 vr; + struct sioc_sg_req6 *sr; + struct sioc_mif_req6 *vr; struct vif_device *vif; struct mfc6_cache *c; struct net *net = sock_net(sk); @@ -1895,40 +1894,33 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) switch (cmd) { case SIOCGETMIFCNT_IN6: - if (copy_from_user(&vr, arg, sizeof(vr))) - return -EFAULT; - if (vr.mifi >= mrt->maxvif) + vr = (struct sioc_mif_req6 *)arg; + if (vr->mifi >= mrt->maxvif) return -EINVAL; - vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif); + vr->mifi = array_index_nospec(vr->mifi, mrt->maxvif); rcu_read_lock(); - vif = &mrt->vif_table[vr.mifi]; - if (VIF_EXISTS(mrt, vr.mifi)) { - vr.icount = READ_ONCE(vif->pkt_in); - vr.ocount = READ_ONCE(vif->pkt_out); - vr.ibytes = READ_ONCE(vif->bytes_in); - vr.obytes = READ_ONCE(vif->bytes_out); + vif = &mrt->vif_table[vr->mifi]; + if (VIF_EXISTS(mrt, vr->mifi)) { + vr->icount = READ_ONCE(vif->pkt_in); + vr->ocount = READ_ONCE(vif->pkt_out); + vr->ibytes = READ_ONCE(vif->bytes_in); + vr->obytes = READ_ONCE(vif->bytes_out); rcu_read_unlock(); - - if (copy_to_user(arg, &vr, sizeof(vr))) - return -EFAULT; return 0; } rcu_read_unlock(); return -EADDRNOTAVAIL; case SIOCGETSGCNT_IN6: - if (copy_from_user(&sr, arg, sizeof(sr))) - return -EFAULT; + sr = (struct sioc_sg_req6 *)arg; rcu_read_lock(); - c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr); + c = ip6mr_cache_find(mrt, &sr->src.sin6_addr, + &sr->grp.sin6_addr); if (c) { - sr.pktcnt = c->_c.mfc_un.res.pkt; - sr.bytecnt = c->_c.mfc_un.res.bytes; - sr.wrong_if = c->_c.mfc_un.res.wrong_if; + sr->pktcnt = c->_c.mfc_un.res.pkt; + sr->bytecnt = c->_c.mfc_un.res.bytes; + sr->wrong_if = c->_c.mfc_un.res.wrong_if; rcu_read_unlock(); - - if (copy_to_user(arg, &sr, sizeof(sr))) - return -EFAULT; return 0; } rcu_read_unlock(); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 44ee7a2e72ac..c9caeb5a43ed 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1118,29 +1118,29 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, return do_rawv6_getsockopt(sk, level, optname, optval, optlen); } -static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) +static int rawv6_ioctl(struct sock *sk, int cmd, int *karg) { switch (cmd) { case SIOCOUTQ: { - int amount = sk_wmem_alloc_get(sk); - - return put_user(amount, (int __user *)arg); + *karg = sk_wmem_alloc_get(sk); + return 0; } case SIOCINQ: { struct sk_buff *skb; - int amount = 0; spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); if (skb) - amount = skb->len; + *karg = skb->len; + else + *karg = 0; spin_unlock_bh(&sk->sk_receive_queue.lock); - return put_user(amount, (int __user *)arg); + return 0; } default: #ifdef CONFIG_IPV6_MROUTE - return ip6mr_ioctl(sk, cmd, (void __user *)arg); + return ip6mr_ioctl(sk, cmd, karg); #else return -ENOIOCTLCMD; #endif diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index a88e070b431d..91ebf0a3f499 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -272,7 +272,7 @@ int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type); /* IOCTL helper for IP encap modules. */ -int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg); +int l2tp_ioctl(struct sock *sk, int cmd, int *karg); /* Extract the tunnel structure from a socket's sk_user_data pointer, * validating the tunnel magic feather. diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 41a74fc84ca1..2b795c1064f5 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -562,19 +562,18 @@ out: return err ? err : copied; } -int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg) +int l2tp_ioctl(struct sock *sk, int cmd, int *karg) { struct sk_buff *skb; - int amount; switch (cmd) { case SIOCOUTQ: - amount = sk_wmem_alloc_get(sk); + *karg = sk_wmem_alloc_get(sk); break; case SIOCINQ: spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); - amount = skb ? skb->len : 0; + *karg = skb ? skb->len : 0; spin_unlock_bh(&sk->sk_receive_queue.lock); break; @@ -582,7 +581,7 @@ int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg) return -ENOIOCTLCMD; } - return put_user(amount, (int __user *)arg); + return 0; } EXPORT_SYMBOL_GPL(l2tp_ioctl); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 5df5cc0ffedc..992b89c75631 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3570,11 +3570,10 @@ static int mptcp_ioctl_outq(const struct mptcp_sock *msk, u64 v) return (int)delta; } -static int mptcp_ioctl(struct sock *sk, int cmd, unsigned long arg) +static int mptcp_ioctl(struct sock *sk, int cmd, int *karg) { struct mptcp_sock *msk = mptcp_sk(sk); bool slow; - int answ; switch (cmd) { case SIOCINQ: @@ -3583,24 +3582,24 @@ static int mptcp_ioctl(struct sock *sk, int cmd, unsigned long arg) lock_sock(sk); __mptcp_move_skbs(msk); - answ = mptcp_inq_hint(sk); + *karg = mptcp_inq_hint(sk); release_sock(sk); break; case SIOCOUTQ: slow = lock_sock_fast(sk); - answ = mptcp_ioctl_outq(msk, READ_ONCE(msk->snd_una)); + *karg = mptcp_ioctl_outq(msk, READ_ONCE(msk->snd_una)); unlock_sock_fast(sk, slow); break; case SIOCOUTQNSD: slow = lock_sock_fast(sk); - answ = mptcp_ioctl_outq(msk, msk->snd_nxt); + *karg = mptcp_ioctl_outq(msk, msk->snd_nxt); unlock_sock_fast(sk, slow); break; default: return -ENOIOCTLCMD; } - return put_user(answ, (int __user *)arg); + return 0; } static void mptcp_subflow_early_fallback(struct mptcp_sock *msk, diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c index ff5f49ab236e..3aa50dc7535b 100644 --- a/net/phonet/datagram.c +++ b/net/phonet/datagram.c @@ -28,24 +28,21 @@ static void pn_sock_close(struct sock *sk, long timeout) sk_common_release(sk); } -static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg) +static int pn_ioctl(struct sock *sk, int cmd, int *karg) { struct sk_buff *skb; - int answ; switch (cmd) { case SIOCINQ: lock_sock(sk); skb = skb_peek(&sk->sk_receive_queue); - answ = skb ? skb->len : 0; + *karg = skb ? skb->len : 0; release_sock(sk); - return put_user(answ, (int __user *)arg); + return 0; case SIOCPNADDRESOURCE: case SIOCPNDELRESOURCE: { - u32 res; - if (get_user(res, (u32 __user *)arg)) - return -EFAULT; + u32 res = *karg; if (res >= 256) return -EINVAL; if (cmd == SIOCPNADDRESOURCE) diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 83ea13a50690..faba31f2eff2 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -917,10 +917,9 @@ static int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len) return 0; } -static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) +static int pep_ioctl(struct sock *sk, int cmd, int *karg) { struct pep_sock *pn = pep_sk(sk); - int answ; int ret = -ENOIOCTLCMD; switch (cmd) { @@ -933,13 +932,13 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) lock_sock(sk); if (sock_flag(sk, SOCK_URGINLINE) && !skb_queue_empty(&pn->ctrlreq_queue)) - answ = skb_peek(&pn->ctrlreq_queue)->len; + *karg = skb_peek(&pn->ctrlreq_queue)->len; else if (!skb_queue_empty(&sk->sk_receive_queue)) - answ = skb_peek(&sk->sk_receive_queue)->len; + *karg = skb_peek(&sk->sk_receive_queue)->len; else - answ = 0; + *karg = 0; release_sock(sk); - ret = put_user(answ, (int __user *)arg); + ret = 0; break; case SIOCPNENABLEPIPE: diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 71e2caf6ab85..967f9b4dc026 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -387,7 +387,7 @@ static int pn_socket_ioctl(struct socket *sock, unsigned int cmd, return put_user(handle, (__u16 __user *)arg); } - return sk->sk_prot->ioctl(sk, cmd, arg); + return sk_ioctl(sk, cmd, (void __user *)arg); } static int pn_socket_listen(struct socket *sock, int backlog) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a68e1d541b12..6554a357fe33 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4895,7 +4895,7 @@ out: } /* The SCTP ioctl handler. */ -static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) +static int sctp_ioctl(struct sock *sk, int cmd, int *karg) { int rc = -ENOTCONN; @@ -4911,7 +4911,7 @@ static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) switch (cmd) { case SIOCINQ: { struct sk_buff *skb; - unsigned int amount = 0; + *karg = 0; skb = skb_peek(&sk->sk_receive_queue); if (skb != NULL) { @@ -4919,9 +4919,9 @@ static int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) * We will only return the amount of this packet since * that is all that will be read. */ - amount = skb->len; + *karg = skb->len; } - rc = put_user(amount, (int __user *)arg); + rc = 0; break; } default: -- cgit v1.2.3 From f7d625adeb7bc6a9ec83d32d9615889969d64484 Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Mon, 12 Jun 2023 12:14:48 +0000 Subject: net: ena: Add dynamic recycling mechanism for rx buffers The current implementation allocates page-sized rx buffers. As traffic may consist of different types and sizes of packets, in various cases, buffers are not fully used. This change (Dynamic RX Buffers - DRB) uses part of the allocated rx page needed for the incoming packet, and returns the rest of the unused page to be used again as an rx buffer for future packets. A threshold of 2K for unused space has been set in order to declare whether the remainder of the page can be reused again as an rx buffer. As a page may be reused, dma_sync_single_for_cpu() is added in order to sync the memory to the CPU side after it was owned by the HW. In addition, when the rx page can no longer be reused, it is being unmapped using dma_page_unmap(), which implicitly syncs and then unmaps the entire page. In case the kernel still handles the skbs pointing to the previous buffers from that rx page, it may access garbage pointers, caused by the implicit sync overwriting them. The implicit dma sync is removed by replacing dma_page_unmap() with dma_unmap_page_attrs() with DMA_ATTR_SKIP_CPU_SYNC flag. The functionality is disabled for XDP traffic to avoid handling several descriptors per packet. Signed-off-by: Arthur Kiyanovski Signed-off-by: Shay Agroskin Signed-off-by: David Arinzon Link: https://lore.kernel.org/r/20230612121448.28829-1-darinzon@amazon.com Signed-off-by: Jakub Kicinski --- .../device_drivers/ethernet/amazon/ena.rst | 32 +++++ drivers/net/ethernet/amazon/ena/ena_admin_defs.h | 6 +- drivers/net/ethernet/amazon/ena/ena_netdev.c | 136 ++++++++++++++------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 4 + 4 files changed, 136 insertions(+), 42 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst index 8bcb173e0353..491492677632 100644 --- a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst +++ b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst @@ -205,6 +205,7 @@ Adaptive coalescing can be switched on/off through `ethtool(8)`'s More information about Adaptive Interrupt Moderation (DIM) can be found in Documentation/networking/net_dim.rst +.. _`RX copybreak`: RX copybreak ============ The rx_copybreak is initialized by default to ENA_DEFAULT_RX_COPYBREAK @@ -315,3 +316,34 @@ Rx - The new SKB is updated with the necessary information (protocol, checksum hw verify result, etc), and then passed to the network stack, using the NAPI interface function :code:`napi_gro_receive()`. + +Dynamic RX Buffers (DRB) +------------------------ + +Each RX descriptor in the RX ring is a single memory page (which is either 4KB +or 16KB long depending on system's configurations). +To reduce the memory allocations required when dealing with a high rate of small +packets, the driver tries to reuse the remaining RX descriptor's space if more +than 2KB of this page remain unused. + +A simple example of this mechanism is the following sequence of events: + +:: + + 1. Driver allocates page-sized RX buffer and passes it to hardware + +----------------------+ + |4KB RX Buffer | + +----------------------+ + + 2. A 300Bytes packet is received on this buffer + + 3. The driver increases the ref count on this page and returns it back to + HW as an RX buffer of size 4KB - 300Bytes = 3796 Bytes + +----+--------------------+ + |****|3796 Bytes RX Buffer| + +----+--------------------+ + +This mechanism isn't used when an XDP program is loaded, or when the +RX packet is less than rx_copybreak bytes (in which case the packet is +copied out of the RX buffer into the linear part of a new skb allocated +for it and the RX buffer remains the same size, see `RX copybreak`_). diff --git a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h index 466ad9470d1f..6de0d590be34 100644 --- a/drivers/net/ethernet/amazon/ena/ena_admin_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_admin_defs.h @@ -869,7 +869,9 @@ struct ena_admin_host_info { * 2 : interrupt_moderation * 3 : rx_buf_mirroring * 4 : rss_configurable_function_key - * 31:5 : reserved + * 5 : reserved + * 6 : rx_page_reuse + * 31:7 : reserved */ u32 driver_supported_features; }; @@ -1184,6 +1186,8 @@ struct ena_admin_ena_mmio_req_read_less_resp { #define ENA_ADMIN_HOST_INFO_RX_BUF_MIRRORING_MASK BIT(3) #define ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_SHIFT 4 #define ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK BIT(4) +#define ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_SHIFT 6 +#define ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_MASK BIT(6) /* aenq_common_desc */ #define ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK BIT(0) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index e6a6efaeb87c..d19593fae226 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1023,7 +1023,7 @@ static int ena_alloc_rx_buffer(struct ena_ring *rx_ring, int tailroom; /* restore page offset value in case it has been changed by device */ - rx_info->page_offset = headroom; + rx_info->buf_offset = headroom; /* if previous allocated page is not used */ if (unlikely(rx_info->page)) @@ -1040,6 +1040,8 @@ static int ena_alloc_rx_buffer(struct ena_ring *rx_ring, tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); rx_info->page = page; + rx_info->dma_addr = dma; + rx_info->page_offset = 0; ena_buf = &rx_info->ena_buf; ena_buf->paddr = dma + headroom; ena_buf->len = ENA_PAGE_SIZE - headroom - tailroom; @@ -1047,14 +1049,12 @@ static int ena_alloc_rx_buffer(struct ena_ring *rx_ring, return 0; } -static void ena_unmap_rx_buff(struct ena_ring *rx_ring, - struct ena_rx_buffer *rx_info) +static void ena_unmap_rx_buff_attrs(struct ena_ring *rx_ring, + struct ena_rx_buffer *rx_info, + unsigned long attrs) { - struct ena_com_buf *ena_buf = &rx_info->ena_buf; - - dma_unmap_page(rx_ring->dev, ena_buf->paddr - rx_ring->rx_headroom, - ENA_PAGE_SIZE, - DMA_BIDIRECTIONAL); + dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, + DMA_BIDIRECTIONAL, attrs); } static void ena_free_rx_page(struct ena_ring *rx_ring, @@ -1068,7 +1068,7 @@ static void ena_free_rx_page(struct ena_ring *rx_ring, return; } - ena_unmap_rx_buff(rx_ring, rx_info); + ena_unmap_rx_buff_attrs(rx_ring, rx_info, 0); __free_page(page); rx_info->page = NULL; @@ -1406,14 +1406,14 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) return tx_pkts; } -static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, void *first_frag) +static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, void *first_frag, u16 len) { struct sk_buff *skb; if (!first_frag) - skb = napi_alloc_skb(rx_ring->napi, rx_ring->rx_copybreak); + skb = napi_alloc_skb(rx_ring->napi, len); else - skb = napi_build_skb(first_frag, ENA_PAGE_SIZE); + skb = napi_build_skb(first_frag, len); if (unlikely(!skb)) { ena_increase_stat(&rx_ring->rx_stats.skb_alloc_fail, 1, @@ -1422,24 +1422,47 @@ static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, void *first_frag) netif_dbg(rx_ring->adapter, rx_err, rx_ring->netdev, "Failed to allocate skb. first_frag %s\n", first_frag ? "provided" : "not provided"); - return NULL; } return skb; } +static bool ena_try_rx_buf_page_reuse(struct ena_rx_buffer *rx_info, u16 buf_len, + u16 len, int pkt_offset) +{ + struct ena_com_buf *ena_buf = &rx_info->ena_buf; + + /* More than ENA_MIN_RX_BUF_SIZE left in the reused buffer + * for data + headroom + tailroom. + */ + if (SKB_DATA_ALIGN(len + pkt_offset) + ENA_MIN_RX_BUF_SIZE <= ena_buf->len) { + page_ref_inc(rx_info->page); + rx_info->page_offset += buf_len; + ena_buf->paddr += buf_len; + ena_buf->len -= buf_len; + return true; + } + + return false; +} + static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, struct ena_com_rx_buf_info *ena_bufs, u32 descs, u16 *next_to_clean) { + int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + bool is_xdp_loaded = ena_xdp_present_ring(rx_ring); struct ena_rx_buffer *rx_info; struct ena_adapter *adapter; + int page_offset, pkt_offset; + dma_addr_t pre_reuse_paddr; u16 len, req_id, buf = 0; + bool reuse_rx_buf_page; struct sk_buff *skb; - void *page_addr; - u32 page_offset; - void *data_addr; + void *buf_addr; + int buf_offset; + u16 buf_len; len = ena_bufs[buf].len; req_id = ena_bufs[buf].req_id; @@ -1459,34 +1482,30 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, "rx_info %p page %p\n", rx_info, rx_info->page); - /* save virt address of first buffer */ - page_addr = page_address(rx_info->page); + buf_offset = rx_info->buf_offset; + pkt_offset = buf_offset - rx_ring->rx_headroom; page_offset = rx_info->page_offset; - data_addr = page_addr + page_offset; - - prefetch(data_addr); + buf_addr = page_address(rx_info->page) + page_offset; if (len <= rx_ring->rx_copybreak) { - skb = ena_alloc_skb(rx_ring, NULL); + skb = ena_alloc_skb(rx_ring, NULL, len); if (unlikely(!skb)) return NULL; - netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, - "RX allocated small packet. len %d. data_len %d\n", - skb->len, skb->data_len); - /* sync this buffer for CPU use */ dma_sync_single_for_cpu(rx_ring->dev, - dma_unmap_addr(&rx_info->ena_buf, paddr), + dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset, len, DMA_FROM_DEVICE); - skb_copy_to_linear_data(skb, data_addr, len); + skb_copy_to_linear_data(skb, buf_addr + buf_offset, len); dma_sync_single_for_device(rx_ring->dev, - dma_unmap_addr(&rx_info->ena_buf, paddr), + dma_unmap_addr(&rx_info->ena_buf, paddr) + pkt_offset, len, DMA_FROM_DEVICE); skb_put(skb, len); + netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, + "RX allocated small packet. len %d.\n", skb->len); skb->protocol = eth_type_trans(skb, rx_ring->netdev); rx_ring->free_ids[*next_to_clean] = req_id; *next_to_clean = ENA_RX_RING_IDX_ADD(*next_to_clean, descs, @@ -1494,14 +1513,28 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, return skb; } - ena_unmap_rx_buff(rx_ring, rx_info); + buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom); + + pre_reuse_paddr = dma_unmap_addr(&rx_info->ena_buf, paddr); + + /* If XDP isn't loaded try to reuse part of the RX buffer */ + reuse_rx_buf_page = !is_xdp_loaded && + ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset); - skb = ena_alloc_skb(rx_ring, page_addr); + dma_sync_single_for_cpu(rx_ring->dev, + pre_reuse_paddr + pkt_offset, + len, + DMA_FROM_DEVICE); + + if (!reuse_rx_buf_page) + ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC); + + skb = ena_alloc_skb(rx_ring, buf_addr, buf_len); if (unlikely(!skb)) return NULL; /* Populate skb's linear part */ - skb_reserve(skb, page_offset); + skb_reserve(skb, buf_offset); skb_put(skb, len); skb->protocol = eth_type_trans(skb, rx_ring->netdev); @@ -1510,7 +1543,8 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, "RX skb updated. len %d. data_len %d\n", skb->len, skb->data_len); - rx_info->page = NULL; + if (!reuse_rx_buf_page) + rx_info->page = NULL; rx_ring->free_ids[*next_to_clean] = req_id; *next_to_clean = @@ -1525,10 +1559,28 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, rx_info = &rx_ring->rx_buffer_info[req_id]; - ena_unmap_rx_buff(rx_ring, rx_info); + /* rx_info->buf_offset includes rx_ring->rx_headroom */ + buf_offset = rx_info->buf_offset; + pkt_offset = buf_offset - rx_ring->rx_headroom; + buf_len = SKB_DATA_ALIGN(len + buf_offset + tailroom); + page_offset = rx_info->page_offset; + + pre_reuse_paddr = dma_unmap_addr(&rx_info->ena_buf, paddr); + + reuse_rx_buf_page = !is_xdp_loaded && + ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset); + + dma_sync_single_for_cpu(rx_ring->dev, + pre_reuse_paddr + pkt_offset, + len, + DMA_FROM_DEVICE); + + if (!reuse_rx_buf_page) + ena_unmap_rx_buff_attrs(rx_ring, rx_info, + DMA_ATTR_SKIP_CPU_SYNC); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page, - rx_info->page_offset, len, ENA_PAGE_SIZE); + page_offset + buf_offset, len, buf_len); } while (1); @@ -1626,7 +1678,7 @@ static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp) rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id]; xdp_prepare_buff(xdp, page_address(rx_info->page), - rx_info->page_offset, + rx_info->buf_offset, rx_ring->ena_bufs[0].len, false); /* If for some reason we received a bigger packet than * we expect, then we simply drop it @@ -1638,7 +1690,7 @@ static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp) /* The xdp program might expand the headers */ if (ret == ENA_XDP_PASS) { - rx_info->page_offset = xdp->data - xdp->data_hard_start; + rx_info->buf_offset = xdp->data - xdp->data_hard_start; rx_ring->ena_bufs[0].len = xdp->data_end - xdp->data; } @@ -1693,7 +1745,7 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, /* First descriptor might have an offset set by the device */ rx_info = &rx_ring->rx_buffer_info[rx_ring->ena_bufs[0].req_id]; - rx_info->page_offset += ena_rx_ctx.pkt_offset; + rx_info->buf_offset += ena_rx_ctx.pkt_offset; netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, "rx_poll: q %d got packet from ena. descs #: %d l3 proto %d l4 proto %d hash: %x\n", @@ -1723,8 +1775,9 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, * from RX side. */ if (xdp_verdict & ENA_XDP_FORWARDED) { - ena_unmap_rx_buff(rx_ring, - &rx_ring->rx_buffer_info[req_id]); + ena_unmap_rx_buff_attrs(rx_ring, + &rx_ring->rx_buffer_info[req_id], + 0); rx_ring->rx_buffer_info[req_id].page = NULL; } } @@ -3233,7 +3286,8 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pd ENA_ADMIN_HOST_INFO_RX_OFFSET_MASK | ENA_ADMIN_HOST_INFO_INTERRUPT_MODERATION_MASK | ENA_ADMIN_HOST_INFO_RX_BUF_MIRRORING_MASK | - ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK; + ENA_ADMIN_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY_MASK | + ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_MASK; rc = ena_com_set_host_attributes(ena_dev); if (rc) { diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 5a0d4ee76172..248b715b4d68 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -51,6 +51,8 @@ #define ENA_DEFAULT_RING_SIZE (1024) #define ENA_MIN_RING_SIZE (256) +#define ENA_MIN_RX_BUF_SIZE (2048) + #define ENA_MIN_NUM_IO_QUEUES (1) #define ENA_TX_WAKEUP_THRESH (MAX_SKB_FRAGS + 2) @@ -175,7 +177,9 @@ struct ena_tx_buffer { struct ena_rx_buffer { struct sk_buff *skb; struct page *page; + dma_addr_t dma_addr; u32 page_offset; + u32 buf_offset; struct ena_com_buf ena_buf; } ____cacheline_aligned; -- cgit v1.2.3 From d9ffa069e006fa2873b94fbf2387546942d4f85b Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 13 Jun 2023 16:46:39 +1000 Subject: sunvnet: fix sparc64 build error after gso code split After merging the net-next tree, today's linux-next build (sparc64 defconfig) failed like this: drivers/net/ethernet/sun/sunvnet_common.c: In function 'vnet_handle_offloads': drivers/net/ethernet/sun/sunvnet_common.c:1277:16: error: implicit declaration of function 'skb_gso_segment'; did you mean 'skb_gso_reset'? [-Werror=implicit-function-declaration] 1277 | segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO); | ^~~~~~~~~~~~~~~ | skb_gso_reset drivers/net/ethernet/sun/sunvnet_common.c:1277:14: warning: assignment to 'struct sk_buff *' from 'int' makes pointer from integer without a cast [-Wint-conversion] 1277 | segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO); | ^ Fixes: d457a0e329b0 ("net: move gso declarations and functions to their own files") Signed-off-by: Stephen Rothwell Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230613164639.164b2991@canb.auug.org.au Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sun/sunvnet_common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/sun/sunvnet_common.c b/drivers/net/ethernet/sun/sunvnet_common.c index a6211b95ed17..3525d5c0d694 100644 --- a/drivers/net/ethernet/sun/sunvnet_common.c +++ b/drivers/net/ethernet/sun/sunvnet_common.c @@ -25,6 +25,7 @@ #endif #include +#include #include #include -- cgit v1.2.3 From ca2d49f77ce4531c74ba207b1e07b55f5ced5ab4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 14 Jun 2023 11:09:48 +0100 Subject: splice, net: Fix splice_to_socket() to handle pipe bufs larger than a page splice_to_socket() assumes that a pipe_buffer won't hold more than a single page of data - but this assumption can be violated by skb_splice_bits() when it splices from a socket into a pipe. The problem is that splice_to_socket() doesn't advance the pipe_buffer length and offset when transcribing from the pipe buf into a bio_vec, so if the buf is >PAGE_SIZE, it keeps repeating the same initial chunk and doesn't advance the tail index. It then subtracts this from "remain" and overcounts the amount of data to be sent. The cleanup phase then tries to overclean the pipe, hits an unused pipe buf and a NULL-pointer dereference occurs. Fix this by not restricting the bio_vec size to PAGE_SIZE and instead transcribing the entirety of each pipe_buffer into a single bio_vec and advancing the tail index if remain hasn't hit zero yet. Large bio_vecs will then be split up by iterator functions such as iov_iter_extract_pages(). This resulted in a KASAN report looking like: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] PREEMPT SMP KASAN KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] ... RIP: 0010:pipe_buf_release include/linux/pipe_fs_i.h:203 [inline] RIP: 0010:splice_to_socket+0xa91/0xe30 fs/splice.c:933 Fixes: 2dc334f1a63a ("splice, net: Use sendmsg(MSG_SPLICE_PAGES) rather than ->sendpage()") Reported-by: syzbot+f9e28a23426ac3b24f20@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/0000000000000900e905fdeb8e39@google.com/ Tested-by: syzbot+f9e28a23426ac3b24f20@syzkaller.appspotmail.com Signed-off-by: David Howells cc: Willem de Bruijn cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox cc: Christian Brauner cc: Alexander Viro Link: https://lore.kernel.org/r/1428985.1686737388@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- fs/splice.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 67ddaac1f5c5..17d692449e83 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -886,7 +886,6 @@ ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out, } seg = min_t(size_t, remain, buf->len); - seg = min_t(size_t, seg, PAGE_SIZE); ret = pipe_buf_confirm(pipe, buf); if (unlikely(ret)) { @@ -897,10 +896,9 @@ ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out, bvec_set_page(&bvec[bc++], buf->page, seg, buf->offset); remain -= seg; - if (seg >= buf->len) - tail++; - if (bc >= ARRAY_SIZE(bvec)) + if (remain == 0 || bc >= ARRAY_SIZE(bvec)) break; + tail++; } if (!bc) -- cgit v1.2.3 From 8f72fb1578a910571b3f25457e3b7855edfac6cf Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 14 Jun 2023 20:52:31 -0700 Subject: eth: fs_enet: fix print format for resource size Randy reported that linux-next build warns on PowerPC: drivers/net/ethernet/freescale/fs_enet/mii-fec.c: In function 'fs_enet_mdio_probe': drivers/net/ethernet/freescale/fs_enet/mii-fec.c:130:50: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'resource_size_t' {aka 'long long unsigned int'} [-Wformat=] 130 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); | ~^ ~~~~~~~~~ | | | | | resource_size_t {aka long long unsigned int} | unsigned int | %llx Use the right print format. Link: https://lore.kernel.org/all/8f9f8d38-d9c7-9f1b-feb0-103d76902d14@infradead.org/ Reported-by: Randy Dunlap Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Link: https://lore.kernel.org/r/20230615035231.2184880-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fs_enet/mii-fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c index d37d7a19a759..59a8f0bd0f5c 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c @@ -127,7 +127,7 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev) if (ret) goto out_res; - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%pap", &res.start); fec->fecp = ioremap(res.start, resource_size(&res)); if (!fec->fecp) { -- cgit v1.2.3 From ad72c4a06acc6762e84994ac2f722da7a07df34e Mon Sep 17 00:00:00 2001 From: Piotr Gardocki Date: Wed, 14 Jun 2023 16:53:00 +0200 Subject: net: add check for current MAC address in dev_set_mac_address In some cases it is possible for kernel to come with request to change primary MAC address to the address that is already set on the given interface. Add proper check to return fast from the function in these cases. An example of such case is adding an interface to bonding channel in balance-alb mode: modprobe bonding mode=balance-alb miimon=100 max_bonds=1 ip link set bond0 up ifenslave bond0 Signed-off-by: Piotr Gardocki Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- net/core/dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/dev.c b/net/core/dev.c index 63abb0463c24..e4ff0adf5523 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8781,6 +8781,8 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa, return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; + if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) + return 0; err = dev_pre_changeaddr_notify(dev, sa->sa_data, extack); if (err) return err; -- cgit v1.2.3 From c45a6d1a23c50b97afd7d767b86e28ea5722e7b7 Mon Sep 17 00:00:00 2001 From: Piotr Gardocki Date: Wed, 14 Jun 2023 16:53:01 +0200 Subject: i40e: remove unnecessary check for old MAC == new MAC The check has been moved to core. The ndo_set_mac_address callback is not being called with new MAC address equal to the old one anymore. Signed-off-by: Piotr Gardocki Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_main.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b847bd105b16..29ad1797adce 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1788,12 +1788,6 @@ static int i40e_set_mac(struct net_device *netdev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) { - netdev_info(netdev, "already using mac address %pM\n", - addr->sa_data); - return 0; - } - if (test_bit(__I40E_DOWN, pf->state) || test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) return -EADDRNOTAVAIL; -- cgit v1.2.3 From 96868cca7971a5a3887717fdacd44b281fb87cc9 Mon Sep 17 00:00:00 2001 From: Piotr Gardocki Date: Wed, 14 Jun 2023 16:53:02 +0200 Subject: ice: remove unnecessary check for old MAC == new MAC The check has been moved to core. The ndo_set_mac_address callback is not being called with new MAC address equal to the old one anymore. Signed-off-by: Piotr Gardocki Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index a0283b5bf65f..65bf399a0efc 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -5624,11 +5624,6 @@ static int ice_set_mac_address(struct net_device *netdev, void *pi) if (!is_valid_ether_addr(mac)) return -EADDRNOTAVAIL; - if (ether_addr_equal(netdev->dev_addr, mac)) { - netdev_dbg(netdev, "already using mac %pM\n", mac); - return 0; - } - if (test_bit(ICE_DOWN, pf->state) || ice_is_reset_in_progress(pf->state)) { netdev_err(netdev, "can't set mac %pM. device not ready\n", -- cgit v1.2.3 From 18da174d865a87d47d2f33f5b0a322efcf067728 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Thu, 15 Jun 2023 00:20:35 +0800 Subject: net: ethernet: litex: add support for 64 bit stats Implement 64 bit per cpu stats to fix the overflow of netdev->stats on 32 bit platforms. To simplify the code, we use net core pcpu_sw_netstats infrastructure. One small drawback is some memory overhead because litex uses just one queue, but we allocate the counters per cpu. Signed-off-by: Jisheng Zhang Reviewed-by: Simon Horman Acked-by: Gabriel Somlo Link: https://lore.kernel.org/r/20230614162035.300-1-jszhang@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/litex/litex_liteeth.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/litex/litex_liteeth.c b/drivers/net/ethernet/litex/litex_liteeth.c index 35f24e0f0934..ffa96059079c 100644 --- a/drivers/net/ethernet/litex/litex_liteeth.c +++ b/drivers/net/ethernet/litex/litex_liteeth.c @@ -78,8 +78,7 @@ static int liteeth_rx(struct net_device *netdev) memcpy_fromio(data, priv->rx_base + rx_slot * priv->slot_size, len); skb->protocol = eth_type_trans(skb, netdev); - netdev->stats.rx_packets++; - netdev->stats.rx_bytes += len; + dev_sw_netstats_rx_add(netdev, len); return netif_rx(skb); @@ -185,8 +184,7 @@ static netdev_tx_t liteeth_start_xmit(struct sk_buff *skb, litex_write16(priv->base + LITEETH_READER_LENGTH, skb->len); litex_write8(priv->base + LITEETH_READER_START, 1); - netdev->stats.tx_bytes += skb->len; - netdev->stats.tx_packets++; + dev_sw_netstats_tx_add(netdev, 1, skb->len); priv->tx_slot = (priv->tx_slot + 1) % priv->num_tx_slots; dev_kfree_skb_any(skb); @@ -194,9 +192,17 @@ static netdev_tx_t liteeth_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } +static void +liteeth_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) +{ + netdev_stats_to_stats64(stats, &netdev->stats); + dev_fetch_sw_netstats(stats, netdev->tstats); +} + static const struct net_device_ops liteeth_netdev_ops = { .ndo_open = liteeth_open, .ndo_stop = liteeth_stop, + .ndo_get_stats64 = liteeth_get_stats64, .ndo_start_xmit = liteeth_start_xmit, }; @@ -242,6 +248,11 @@ static int liteeth_probe(struct platform_device *pdev) priv->netdev = netdev; priv->dev = &pdev->dev; + netdev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, + struct pcpu_sw_netstats); + if (!netdev->tstats) + return -ENOMEM; + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; -- cgit v1.2.3 From 1282723361209d06fb1466ffb90e63b1161320b6 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 15 Jun 2023 15:21:52 -0700 Subject: s390/net: lcs: use IS_ENABLED() for kconfig detection When CONFIG_ETHERNET=m or CONFIG_FDDI=m, lcs.s has build errors or warnings: ../drivers/s390/net/lcs.c:40:2: error: #error Cannot compile lcs.c without some net devices switched on. 40 | #error Cannot compile lcs.c without some net devices switched on. ../drivers/s390/net/lcs.c: In function 'lcs_startlan_auto': ../drivers/s390/net/lcs.c:1601:13: warning: unused variable 'rc' [-Wunused-variable] 1601 | int rc; Solve this by using IS_ENABLED(CONFIG_symbol) instead of ifdef CONFIG_symbol. The latter only works for builtin (=y) values while IS_ENABLED() works for builtin or modular values. Signed-off-by: Randy Dunlap Cc: Alexandra Winter Cc: Wenjia Zhang Cc: linux-s390@vger.kernel.org Cc: netdev@vger.kernel.org Cc: Heiko Carstens Cc: Vasily Gorbik Cc: Alexander Gordeev Cc: Christian Borntraeger Cc: Sven Schnelle Signed-off-by: David S. Miller --- drivers/s390/net/lcs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 38f312664ce7..bb1092775dcc 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -36,7 +36,7 @@ #include "lcs.h" -#if !defined(CONFIG_ETHERNET) && !defined(CONFIG_FDDI) +#if !IS_ENABLED(CONFIG_ETHERNET) && !IS_ENABLED(CONFIG_FDDI) #error Cannot compile lcs.c without some net devices switched on. #endif @@ -1601,14 +1601,14 @@ lcs_startlan_auto(struct lcs_card *card) int rc; LCS_DBF_TEXT(2, trace, "strtauto"); -#ifdef CONFIG_ETHERNET +#if IS_ENABLED(CONFIG_ETHERNET) card->lan_type = LCS_FRAME_TYPE_ENET; rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); if (rc == 0) return 0; #endif -#ifdef CONFIG_FDDI +#if IS_ENABLED(CONFIG_FDDI) card->lan_type = LCS_FRAME_TYPE_FDDI; rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); if (rc == 0) @@ -2139,13 +2139,13 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) goto netdev_out; } switch (card->lan_type) { -#ifdef CONFIG_ETHERNET +#if IS_ENABLED(CONFIG_ETHERNET) case LCS_FRAME_TYPE_ENET: card->lan_type_trans = eth_type_trans; dev = alloc_etherdev(0); break; #endif -#ifdef CONFIG_FDDI +#if IS_ENABLED(CONFIG_FDDI) case LCS_FRAME_TYPE_FDDI: card->lan_type_trans = fddi_type_trans; dev = alloc_fddidev(0); -- cgit v1.2.3 From c08afcdcf95288c627267bb20002e8baaf3394e1 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Thu, 15 Jun 2023 22:52:43 +0100 Subject: sfc: do not try to call tc functions when CONFIG_SFC_SRIOV=n Functions efx_tc_netdev_event and efx_tc_netevent_event do not exist in that case as object files tc_bindings.o and tc_encap_actions.o are not built, so the calls to them from ef100_netdev_event and ef100_netevent_event cause link errors. Wrap the corresponding header files (tc_bindings.h, tc_encap_actions.h) with #if IS_ENABLED(CONFIG_SFC_SRIOV), and add an #else with static inline stubs for these two functions. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202306102026.ISK5JfUQ-lkp@intel.com/ Fixes: 7e5e7d800011 ("sfc: neighbour lookup for TC encap action offload") Signed-off-by: Edward Cree Reviewed-by: Martin Habets Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/tc_bindings.h | 12 ++++++++++++ drivers/net/ethernet/sfc/tc_encap_actions.h | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/drivers/net/ethernet/sfc/tc_bindings.h b/drivers/net/ethernet/sfc/tc_bindings.h index 095ddeb59eb3..a326d23d322b 100644 --- a/drivers/net/ethernet/sfc/tc_bindings.h +++ b/drivers/net/ethernet/sfc/tc_bindings.h @@ -12,6 +12,7 @@ #define EFX_TC_BINDINGS_H #include "net_driver.h" +#if IS_ENABLED(CONFIG_SFC_SRIOV) #include struct efx_rep; @@ -28,4 +29,15 @@ int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch, void (*cleanup)(struct flow_block_cb *block_cb)); int efx_tc_netdev_event(struct efx_nic *efx, unsigned long event, struct net_device *net_dev); + +#else /* CONFIG_SFC_SRIOV */ + +static inline int efx_tc_netdev_event(struct efx_nic *efx, unsigned long event, + struct net_device *net_dev) +{ + return NOTIFY_DONE; +} + +#endif /* CONFIG_SFC_SRIOV */ + #endif /* EFX_TC_BINDINGS_H */ diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.h b/drivers/net/ethernet/sfc/tc_encap_actions.h index 4d755fb92daf..c3c7904ad7ff 100644 --- a/drivers/net/ethernet/sfc/tc_encap_actions.h +++ b/drivers/net/ethernet/sfc/tc_encap_actions.h @@ -12,6 +12,7 @@ #define EFX_TC_ENCAP_ACTIONS_H #include "net_driver.h" +#if IS_ENABLED(CONFIG_SFC_SRIOV) #include #include @@ -100,4 +101,14 @@ void efx_tc_unregister_egdev(struct efx_nic *efx, struct net_device *net_dev); int efx_tc_netevent_event(struct efx_nic *efx, unsigned long event, void *ptr); +#else /* CONFIG_SFC_SRIOV */ + +static inline int efx_tc_netevent_event(struct efx_nic *efx, + unsigned long event, void *ptr) +{ + return NOTIFY_DONE; +} + +#endif /* CONFIG_SFC_SRIOV */ + #endif /* EFX_TC_ENCAP_ACTIONS_H */ -- cgit v1.2.3 From 56714e5f1255fc318b65b6b338a0d8ebc44c920c Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 13 Jun 2023 17:09:15 +0300 Subject: wifi: brcmfmac: fix gnu_printf warnings With GCC 13.1 and W=1 brcmfmac has warnings like this: ./include/trace/perf.h:26:16: warning: function 'perf_trace_brcmf_dbg' might be a candidate for 'gnu_printf' format attribute [-Wsuggest-attribute=format] Add a workaround which disables -Wsuggest-attribute=format in tracepoint.h. I see similar workarounds in other drivers as well. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230613140918.389690-2-kvalo@kernel.org --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h index 5a139d7ed47a..5d66e94c806d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/tracepoint.h @@ -28,6 +28,11 @@ static inline void trace_ ## name(proto) {} #define MAX_MSG_LEN 100 +#pragma GCC diagnostic push +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +#endif + TRACE_EVENT(brcmf_err, TP_PROTO(const char *func, struct va_format *vaf), TP_ARGS(func, vaf), @@ -123,6 +128,8 @@ TRACE_EVENT(brcmf_sdpcm_hdr, __entry->len, ((u8 *)__get_dynamic_array(hdr))[4]) ); +#pragma GCC diagnostic pop + #ifdef CONFIG_BRCM_TRACING #undef TRACE_INCLUDE_PATH -- cgit v1.2.3 From 4b6ec74ec476c775b44d49ecd8cd48334db8e798 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 13 Jun 2023 17:09:16 +0300 Subject: wifi: brcmsmac: fix gnu_printf warnings With GCC 13.1 and W=1 brcmsmac has warnings like this: ./include/trace/stages/stage5_get_offsets.h:23:31: warning: function 'trace_event_get_offsets_brcms_dbg' might be a candidate for 'gnu_printf' format attribute [-Wsuggest-attribute=format] Add a workaround which disables -Wsuggest-attribute=format in brcms_trace_brcmsmac_msg.h. I see similar workarounds in other drivers as well. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230613140918.389690-3-kvalo@kernel.org --- .../broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h index 488456420353..42b0a91656c4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/brcms_trace_brcmsmac_msg.h @@ -24,6 +24,11 @@ #define MAX_MSG_LEN 100 +#pragma GCC diagnostic push +#ifndef __clang__ +#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" +#endif + DECLARE_EVENT_CLASS(brcms_msg_event, TP_PROTO(struct va_format *vaf), TP_ARGS(vaf), @@ -71,6 +76,9 @@ TRACE_EVENT(brcms_dbg, ), TP_printk("%s: %s", __get_str(func), __get_str(msg)) ); + +#pragma GCC diagnostic pop + #endif /* __TRACE_BRCMSMAC_MSG_H */ #ifdef CONFIG_BRCM_TRACING -- cgit v1.2.3 From 5ea0c313090046d84064dc556983d8ed7e6065dd Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 13 Jun 2023 17:09:17 +0300 Subject: wifi: hostap: fix stringop-truncations GCC warning With GCC 13.1 and W=1 hostap has a warning: drivers/net/wireless/intersil/hostap/hostap_ioctl.c:3633:17: warning: 'strncpy' specified bound 16 equals destination size [-Wstringop-truncation] fortify-string.h recommends not to use strncpy() so use strscpy() which fixes the warning. Also now it's guarenteed that the string is NUL-terminated. Compile tested only. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230613140918.389690-4-kvalo@kernel.org --- drivers/net/wireless/intersil/hostap/hostap_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c index 26287b129d18..b4adfc190ae8 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c @@ -3630,7 +3630,7 @@ static int prism2_ioctl_get_encryption(local_info_t *local, param->u.crypt.key_len = 0; param->u.crypt.idx = 0xff; } else { - strncpy(param->u.crypt.alg, (*crypt)->ops->name, + strscpy(param->u.crypt.alg, (*crypt)->ops->name, HOSTAP_CRYPT_ALG_NAME_LEN); param->u.crypt.key_len = 0; -- cgit v1.2.3 From 707a13c7e488785170a5e7f2467f2823824651e2 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Tue, 13 Jun 2023 17:09:18 +0300 Subject: wifi: ray_cs: fix stringop-truncation GCC warning GCC 12.2 with W=1 warns: drivers/net/wireless/legacy/ray_cs.c:630:17: warning: 'strncpy' specified bound 32 equals destination size [-Wstringop-truncation] The driver uses SSID as a string which is just wrong, it should be treated as a byte array instead. But as the driver is ancient and most likely there are no users so convert it to use strscpy(). This makes sure that the string is NUL-terminated and also the warning is fixed. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230613140918.389690-5-kvalo@kernel.org --- drivers/net/wireless/legacy/ray_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c index 4b53a9c70e7e..8ace797ce951 100644 --- a/drivers/net/wireless/legacy/ray_cs.c +++ b/drivers/net/wireless/legacy/ray_cs.c @@ -627,7 +627,7 @@ static void init_startup_params(ray_dev_t *local) local->sparm.b4.a_acting_as_ap_status = TYPE_STA; if (essid != NULL) - strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE); + strscpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE); } /* init_startup_params */ /*===========================================================================*/ -- cgit v1.2.3 From 469ddb20cae61cad9c4f208a4c8682305905a511 Mon Sep 17 00:00:00 2001 From: Ziyang Huang Date: Thu, 15 Jun 2023 14:41:47 +0300 Subject: wifi: ath11k: Add missing ops config for IPQ5018 in ath11k_ahb_probe() Without this patch, the IPQ5018 WiFi will fail and print the following logs: [ 11.033179] ath11k c000000.wifi: unsupported device type 7 [ 11.033223] ath11k: probe of c000000.wifi failed with error -95 Fixes: 25edca7bb18a ("wifi: ath11k: add ipq5018 device support") Signed-off-by: Ziyang Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/TYZPR01MB5556D7AA10ABEDDDD2D8F39EC953A@TYZPR01MB5556.apcprd01.prod.exchangelabs.com --- drivers/net/wireless/ath/ath11k/ahb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index ddd27e05ede4..1cebba7889d7 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1127,6 +1127,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev) switch (hw_rev) { case ATH11K_HW_IPQ8074: case ATH11K_HW_IPQ6018_HW10: + case ATH11K_HW_IPQ5018_HW10: hif_ops = &ath11k_ahb_hif_ops_ipq8074; pci_ops = NULL; break; -- cgit v1.2.3 From 80c5390e1f5e5b16d820512265530ef26073d8e0 Mon Sep 17 00:00:00 2001 From: Ziyang Huang Date: Thu, 15 Jun 2023 14:41:48 +0300 Subject: wifi: ath11k: Restart firmware after cold boot calibration for IPQ5018 Restart is required after cold boot calibration on IPQ5018. Otherwise, we get the following exception: [ 14.412829] qcom-q6-mpd cd00000.remoteproc: fatal error received: err_smem_ver.2.1: [ 14.412829] QC Image Version : QC_IMAGE_VERSION_STRING=WLAN.HK.2.6.0.1-00974-QCAHKSWPL_SILICONZ-1 [ 14.412829] Image Variant : IMAGE_VARIANT_STRING=5018.wlanfw2.map_spr_spr_evalQ [ 14.412829] DALSysLogEvent.c:174 Assertion 0 failed param0 :zero,param1 :zero,param2 :zero [ 14.412829] Thread ID : 0x00000048 Thread name : WLAN RT0 Process ID : 0x00000001 Process name :wlan0 [ 14.412829] [ 14.412829] Registers: [ 14.412829] SP : 0x4c81c120 [ 14.412829] FP : 0x4c81c138 [ 14.412829] PC : 0xb022c590 [ 14.412829] SSR : 0x00000000 [ 14.412829] BADVA : 0x00000000 [ 14.412829] LR : 0xb0008490 [ 14.412829] [ 14.412829] StackDump [ 14.412829] from:0x4c81c120 [ 14.412829] to: 0x00000000: [ 14.412829] [ 14.463006] remoteproc remoteproc0: crash detected in cd00000.remoteproc: type fatal error Fixes: 8dfe875aa24a ("wifi: ath11k: update hw params for IPQ5018") Signed-off-by: Ziyang Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/TYZPR01MB55566969818BD4B49E770445C953A@TYZPR01MB5556.apcprd01.prod.exchangelabs.com --- drivers/net/wireless/ath/ath11k/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 147395e622b9..bebfd342e28b 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -668,6 +668,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .hal_params = &ath11k_hw_hal_params_ipq8074, .single_pdev_only = false, .cold_boot_calib = true, + .cbcal_restart_fw = true, .fix_l1ss = true, .supports_dynamic_smps_6ghz = false, .alloc_cacheable_memory = true, -- cgit v1.2.3 From ce282d8de71f07f0056ea319541141152c65f552 Mon Sep 17 00:00:00 2001 From: Ziyang Huang Date: Thu, 15 Jun 2023 14:41:48 +0300 Subject: wifi: ath11k: Add missing hw_ops->get_ring_selector() for IPQ5018 During sending data after clients connected, hw_ops->get_ring_selector() will be called. But for IPQ5018, this member isn't set, and the following NULL pointer exception will be occurred: [ 38.840478] 8<--- cut here --- [ 38.840517] Unable to handle kernel NULL pointer dereference at virtual address 00000000 ... [ 38.923161] PC is at 0x0 [ 38.927930] LR is at ath11k_dp_tx+0x70/0x730 [ath11k] ... [ 39.063264] Process hostapd (pid: 1034, stack limit = 0x801ceb3d) [ 39.068994] Stack: (0x856a9a68 to 0x856aa000) ... [ 39.438467] [<7f323804>] (ath11k_dp_tx [ath11k]) from [<7f314e6c>] (ath11k_mac_op_tx+0x80/0x190 [ath11k]) [ 39.446607] [<7f314e6c>] (ath11k_mac_op_tx [ath11k]) from [<7f17dbe0>] (ieee80211_handle_wake_tx_queue+0x7c/0xc0 [mac80211]) [ 39.456162] [<7f17dbe0>] (ieee80211_handle_wake_tx_queue [mac80211]) from [<7f174450>] (ieee80211_probereq_get+0x584/0x704 [mac80211]) [ 39.467443] [<7f174450>] (ieee80211_probereq_get [mac80211]) from [<7f178c40>] (ieee80211_tx_prepare_skb+0x1f8/0x248 [mac80211]) [ 39.479334] [<7f178c40>] (ieee80211_tx_prepare_skb [mac80211]) from [<7f179e28>] (__ieee80211_subif_start_xmit+0x32c/0x3d4 [mac80211]) [ 39.491053] [<7f179e28>] (__ieee80211_subif_start_xmit [mac80211]) from [<7f17af08>] (ieee80211_tx_control_port+0x19c/0x288 [mac80211]) [ 39.502946] [<7f17af08>] (ieee80211_tx_control_port [mac80211]) from [<7f0fc704>] (nl80211_tx_control_port+0x174/0x1d4 [cfg80211]) [ 39.515017] [<7f0fc704>] (nl80211_tx_control_port [cfg80211]) from [<808ceac4>] (genl_rcv_msg+0x154/0x340) [ 39.526814] [<808ceac4>] (genl_rcv_msg) from [<808cdb74>] (netlink_rcv_skb+0xb8/0x11c) [ 39.536446] [<808cdb74>] (netlink_rcv_skb) from [<808ce1d0>] (genl_rcv+0x28/0x34) [ 39.544344] [<808ce1d0>] (genl_rcv) from [<808cd234>] (netlink_unicast+0x174/0x274) [ 39.551895] [<808cd234>] (netlink_unicast) from [<808cd510>] (netlink_sendmsg+0x1dc/0x440) [ 39.559362] [<808cd510>] (netlink_sendmsg) from [<808596e0>] (____sys_sendmsg+0x1a8/0x1fc) [ 39.567697] [<808596e0>] (____sys_sendmsg) from [<8085b1a8>] (___sys_sendmsg+0xa4/0xdc) [ 39.575941] [<8085b1a8>] (___sys_sendmsg) from [<8085b310>] (sys_sendmsg+0x44/0x74) [ 39.583841] [<8085b310>] (sys_sendmsg) from [<80300060>] (ret_fast_syscall+0x0/0x40) ... [ 39.620734] Code: bad PC value [ 39.625869] ---[ end trace 8aef983ad3cbc032 ]--- Fixes: ba60f2793d3a ("wifi: ath11k: initialize hw_ops for IPQ5018") Signed-off-by: Ziyang Huang Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/TYZPR01MB5556D6E3F63EAB5129D11420C953A@TYZPR01MB5556.apcprd01.prod.exchangelabs.com --- drivers/net/wireless/ath/ath11k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 3b5181e054d3..d7b5ec6e6904 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -1178,7 +1178,7 @@ const struct ath11k_hw_ops ipq5018_ops = { .mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid, .rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid, .rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2, - + .get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector, }; #define ATH11K_TX_RING_MASK_0 BIT(0) -- cgit v1.2.3 From 7f6ee56ca0df0484338d12cd142fb5ebde8875a9 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 15 Jun 2023 14:41:53 +0300 Subject: dt-bindings: net: wireless: ath10k: add ieee80211-freq-limit property This is an existing optional property that ieee80211.yaml/cfg80211 provides. It's useful to further restrict supported frequencies for a specified device through device-tree. For testing the addition, I added the ieee80211-freq-limit property with values from an OpenMesh A62 device. This is because the OpenMesh A62 has "special filters in front of the RX+TX paths to the 5GHz PHYs. These filtered channel can in theory still be used by the hardware but the signal strength is reduced so much that it makes no sense." The driver supported this since ~2018 by commit 34d5629d2ca8 ("ath10k: limit available channels via DT ieee80211-freq-limit") Link: https://git.openwrt.org/?p=openwrt/openwrt.git;a=commit;h=e3b8ae2b09e137ce2eae33551923daf302293a0c Signed-off-by: Christian Lamparter Acked-by: Krzysztof Kozlowski Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/c33c928b7c6c9bb4e7abe84eb8df9f440add275b.1686486464.git.chunkeey@gmail.com --- Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml index c85ed330426d..7758a55dd328 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.yaml @@ -84,6 +84,8 @@ properties: required: - iommus + ieee80211-freq-limit: true + qcom,ath10k-calibration-data: $ref: /schemas/types.yaml#/definitions/uint8-array description: @@ -164,6 +166,7 @@ required: additionalProperties: false allOf: + - $ref: ieee80211.yaml# - if: properties: compatible: @@ -355,4 +358,5 @@ examples: "msi14", "msi15", "legacy"; + ieee80211-freq-limit = <5470000 5875000>; }; -- cgit v1.2.3 From ab5d47bd41b1db82c295b0e751e2b822b43a4b5a Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 14 Jun 2023 10:34:30 +0200 Subject: bpf: Remove in_atomic() from bpf_link_put(). bpf_free_inode() is invoked as a RCU callback. Usually RCU callbacks are invoked within softirq context. By setting rcutree.use_softirq=0 boot option the RCU callbacks will be invoked in a per-CPU kthread with bottom halves disabled which implies a RCU read section. On PREEMPT_RT the context remains fully preemptible. The RCU read section however does not allow schedule() invocation. The latter happens in mutex_lock() performed by bpf_trampoline_unlink_prog() originated from bpf_link_put(). It was pointed out that the bpf_link_put() invocation should not be delayed if originated from close(). It was also pointed out that other invocations from within a syscall should also avoid the workqueue. Everyone else should use workqueue by default to remain safe in the future (while auditing the code, every caller was preemptible except for the RCU case). Let bpf_link_put() use the worker unconditionally. Add bpf_link_put_direct() which will directly free the resources and is used by close() and from within __sys_bpf(). Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20230614083430.oENawF8f@linutronix.de --- kernel/bpf/syscall.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 92a57efc77de..12955415d376 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2793,28 +2793,31 @@ static void bpf_link_put_deferred(struct work_struct *work) bpf_link_free(link); } -/* bpf_link_put can be called from atomic context, but ensures that resources - * are freed from process context +/* bpf_link_put might be called from atomic context. It needs to be called + * from sleepable context in order to acquire sleeping locks during the process. */ void bpf_link_put(struct bpf_link *link) { if (!atomic64_dec_and_test(&link->refcnt)) return; - if (in_atomic()) { - INIT_WORK(&link->work, bpf_link_put_deferred); - schedule_work(&link->work); - } else { - bpf_link_free(link); - } + INIT_WORK(&link->work, bpf_link_put_deferred); + schedule_work(&link->work); } EXPORT_SYMBOL(bpf_link_put); +static void bpf_link_put_direct(struct bpf_link *link) +{ + if (!atomic64_dec_and_test(&link->refcnt)) + return; + bpf_link_free(link); +} + static int bpf_link_release(struct inode *inode, struct file *filp) { struct bpf_link *link = filp->private_data; - bpf_link_put(link); + bpf_link_put_direct(link); return 0; } @@ -4787,7 +4790,7 @@ out_put_progs: if (ret) bpf_prog_put(new_prog); out_put_link: - bpf_link_put(link); + bpf_link_put_direct(link); return ret; } @@ -4810,7 +4813,7 @@ static int link_detach(union bpf_attr *attr) else ret = -EOPNOTSUPP; - bpf_link_put(link); + bpf_link_put_direct(link); return ret; } @@ -4880,7 +4883,7 @@ static int bpf_link_get_fd_by_id(const union bpf_attr *attr) fd = bpf_link_new_fd(link); if (fd < 0) - bpf_link_put(link); + bpf_link_put_direct(link); return fd; } @@ -4957,7 +4960,7 @@ static int bpf_iter_create(union bpf_attr *attr) return PTR_ERR(link); err = bpf_iter_new_fd(link); - bpf_link_put(link); + bpf_link_put_direct(link); return err; } -- cgit v1.2.3 From 5a6f6873606e03a0a95afe40ba5e84bb6e28a26f Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 14 Jun 2023 09:04:16 +0100 Subject: ip, ip6: Fix splice to raw and ping sockets Splicing to SOCK_RAW sockets may set MSG_SPLICE_PAGES, but in such a case, __ip_append_data() will call skb_splice_from_iter() to access the 'from' data, assuming it to point to a msghdr struct with an iter, instead of using the provided getfrag function to access it. In the case of raw_sendmsg(), however, this is not the case and 'from' will point to a raw_frag_vec struct and raw_getfrag() will be the frag-getting function. A similar issue may occur with rawv6_sendmsg(). Fix this by ignoring MSG_SPLICE_PAGES if getfrag != ip_generic_getfrag as ip_generic_getfrag() expects "from" to be a msghdr*, but the other getfrags don't. Note that this will prevent MSG_SPLICE_PAGES from being effective for udplite. This likely affects ping sockets too. udplite looks like it should be okay as it expects "from" to be a msghdr. Signed-off-by: David Howells Reported-by: syzbot+d8486855ef44506fd675@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000ae4cbf05fdeb8349@google.com/ Fixes: 2dc334f1a63a ("splice, net: Use sendmsg(MSG_SPLICE_PAGES) rather than ->sendpage()") Tested-by: syzbot+d8486855ef44506fd675@syzkaller.appspotmail.com cc: David Ahern cc: Jens Axboe cc: Matthew Wilcox Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/1410156.1686729856@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- net/ipv4/ip_output.c | 3 ++- net/ipv6/ip6_output.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 457598dfa128..6e70839257f7 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1041,7 +1041,8 @@ static int __ip_append_data(struct sock *sk, } else if ((flags & MSG_SPLICE_PAGES) && length) { if (inet->hdrincl) return -EPERM; - if (rt->dst.dev->features & NETIF_F_SG) + if (rt->dst.dev->features & NETIF_F_SG && + getfrag == ip_generic_getfrag) /* We need an empty buffer to attach stuff to */ paged = true; else diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c06ff7519f19..1e8c90e97608 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1593,7 +1593,8 @@ emsgsize: } else if ((flags & MSG_SPLICE_PAGES) && length) { if (inet_sk(sk)->hdrincl) return -EPERM; - if (rt->dst.dev->features & NETIF_F_SG) + if (rt->dst.dev->features & NETIF_F_SG && + getfrag == ip_generic_getfrag) /* We need an empty buffer to attach stuff to */ paged = true; else -- cgit v1.2.3 From 92501fa6e4217aa0b85b092f91b2649b3c214a75 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Sat, 20 May 2023 11:33:14 +0300 Subject: net/mlx5: Ack on sync_reset_request only if PF can do reset_now Verify at reset_request stage that PF is capable to do reset_now. In case PF is not capable, notify the firmware that the sync reset can not happen and so firmware will abort the sync reset at early stage and will not send reset_now event to any PF. Signed-off-by: Moshe Shemesh Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c | 57 +++++++++++++++++----- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 50022e7565f1..952cc340b510 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -276,6 +276,44 @@ static void mlx5_fw_live_patch_event(struct work_struct *work) mlx5_core_err(dev, "Failed to reload FW tracer\n"); } +static int mlx5_check_dev_ids(struct mlx5_core_dev *dev, u16 dev_id) +{ + struct pci_bus *bridge_bus = dev->pdev->bus; + struct pci_dev *sdev; + u16 sdev_id; + int err; + + /* Check that all functions under the pci bridge are PFs of + * this device otherwise fail this function. + */ + list_for_each_entry(sdev, &bridge_bus->devices, bus_list) { + err = pci_read_config_word(sdev, PCI_DEVICE_ID, &sdev_id); + if (err) + return err; + if (sdev_id != dev_id) { + mlx5_core_warn(dev, "unrecognized dev_id (0x%x)\n", sdev_id); + return -EPERM; + } + } + return 0; +} + +static bool mlx5_is_reset_now_capable(struct mlx5_core_dev *dev) +{ + u16 dev_id; + int err; + + if (!MLX5_CAP_GEN(dev, fast_teardown)) { + mlx5_core_warn(dev, "fast teardown is not supported by firmware\n"); + return -EOPNOTSUPP; + } + + err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id); + if (err) + return false; + return (!mlx5_check_dev_ids(dev, dev_id)); +} + static void mlx5_sync_reset_request_event(struct work_struct *work) { struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset, @@ -283,7 +321,8 @@ static void mlx5_sync_reset_request_event(struct work_struct *work) struct mlx5_core_dev *dev = fw_reset->dev; int err; - if (test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags)) { + if (test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags) || + !mlx5_is_reset_now_capable(dev)) { err = mlx5_fw_reset_set_reset_sync_nack(dev); mlx5_core_warn(dev, "PCI Sync FW Update Reset Nack %s", err ? "Failed" : "Sent"); @@ -303,26 +342,18 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev) { struct pci_bus *bridge_bus = dev->pdev->bus; struct pci_dev *bridge = bridge_bus->self; - u16 reg16, dev_id, sdev_id; unsigned long timeout; struct pci_dev *sdev; + u16 reg16, dev_id; int cap, err; u32 reg32; - /* Check that all functions under the pci bridge are PFs of - * this device otherwise fail this function. - */ err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id); if (err) return err; - list_for_each_entry(sdev, &bridge_bus->devices, bus_list) { - err = pci_read_config_word(sdev, PCI_DEVICE_ID, &sdev_id); - if (err) - return err; - if (sdev_id != dev_id) - return -EPERM; - } - + err = mlx5_check_dev_ids(dev, dev_id); + if (err) + return err; cap = pci_find_capability(bridge, PCI_CAP_ID_EXP); if (!cap) return -EOPNOTSUPP; -- cgit v1.2.3 From 8bb42ed4210e342631f63d32f7ed87b722968da6 Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Wed, 17 May 2023 11:53:50 +0300 Subject: net/mlx5: Expose timeout for sync reset unload stage Expose new timoueout in Default Timeouts Register to be used on sync reset flow running on smart NIC. In this flow the driver should know how much time to wait from getting unload request till firmware will ask the PF to continue to next stage of the flow. Signed-off-by: Moshe Shemesh Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c | 4 +++- drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h | 1 + include/linux/mlx5/mlx5_ifc.h | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c index 696e45e2bd06..a87d0178ebf3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c @@ -24,7 +24,8 @@ static const u32 tout_def_sw_val[MAX_TIMEOUT_TYPES] = { [MLX5_TO_TEARDOWN_MS] = 3000, [MLX5_TO_FSM_REACTIVATE_MS] = 5000, [MLX5_TO_RECLAIM_PAGES_MS] = 5000, - [MLX5_TO_RECLAIM_VFS_PAGES_MS] = 120000 + [MLX5_TO_RECLAIM_VFS_PAGES_MS] = 120000, + [MLX5_TO_RESET_UNLOAD_MS] = 300000 }; static void tout_set(struct mlx5_core_dev *dev, u64 val, enum mlx5_timeouts_types type) @@ -146,6 +147,7 @@ static int tout_query_dtor(struct mlx5_core_dev *dev) MLX5_TIMEOUT_FILL(fsm_reactivate_to, out, dev, MLX5_TO_FSM_REACTIVATE_MS, 0); MLX5_TIMEOUT_FILL(reclaim_pages_to, out, dev, MLX5_TO_RECLAIM_PAGES_MS, 0); MLX5_TIMEOUT_FILL(reclaim_vfs_pages_to, out, dev, MLX5_TO_RECLAIM_VFS_PAGES_MS, 0); + MLX5_TIMEOUT_FILL(reset_unload_to, out, dev, MLX5_TO_RESET_UNLOAD_MS, 0); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h index bc9e9aeda847..99e0a05526fe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.h @@ -26,6 +26,7 @@ enum mlx5_timeouts_types { MLX5_TO_FSM_REACTIVATE_MS, MLX5_TO_RECLAIM_PAGES_MS, MLX5_TO_RECLAIM_VFS_PAGES_MS, + MLX5_TO_RESET_UNLOAD_MS, MAX_TIMEOUT_TYPES }; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 1f4f62cb9f34..14892e795808 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -3117,7 +3117,9 @@ struct mlx5_ifc_dtor_reg_bits { struct mlx5_ifc_default_timeout_bits reclaim_vfs_pages_to; - u8 reserved_at_1c0[0x40]; + struct mlx5_ifc_default_timeout_bits reset_unload_to; + + u8 reserved_at_1c0[0x20]; }; enum { -- cgit v1.2.3 From 6f8551f8d9e44894ea9ca0748b5523767d7aeacb Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Wed, 14 Jun 2023 06:47:58 +0300 Subject: net/mlx5: Check DTOR entry value is not zero The Default Timeout Register (DTOR) provides timeout values to driver for flows that are device dependent. Zero value for DTOR entry is not valid and should not be used. In case of reading zero value from DTOR, the driver should use the hard coded SW default value instead. Signed-off-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c index a87d0178ebf3..e223e0e46433 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/tout.c @@ -119,7 +119,8 @@ u64 _mlx5_tout_ms(struct mlx5_core_dev *dev, enum mlx5_timeouts_types type) #define MLX5_TIMEOUT_FILL(fld, reg_out, dev, to_type, to_extra) \ ({ \ u64 fw_to = MLX5_TIMEOUT_QUERY(fld, reg_out); \ - tout_set(dev, fw_to + (to_extra), to_type); \ + if (fw_to) \ + tout_set(dev, fw_to + (to_extra), to_type); \ fw_to; \ }) -- cgit v1.2.3 From 7a9770f1bfeaeddf5afabd3244e2c4c4966be37d Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Wed, 17 May 2023 16:07:40 +0300 Subject: net/mlx5: Handle sync reset unload event Added a new event handler to firmware sync reset, which is used to support firmware sync reset flow on smart NIC. Adding this new stage to the flow enables the firmware to ensure host PFs unload before ECPFs unload, to avoid race of PFs recovery. If firmware sends sync_reset_unload event to driver the driver should unload and close all HW resources of the function. Once the driver finishes unloading part, it can't get any more events from firmware as event queues are closed, so it polls the reset state field to know when to continue to next stage of the sync reset flow. Added capability bit for supporting sync_reset_unload event. Signed-off-by: Moshe Shemesh Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c | 103 ++++++++++++++++++++- drivers/net/ethernet/mellanox/mlx5/core/main.c | 3 + include/linux/mlx5/device.h | 1 + include/linux/mlx5/mlx5_ifc.h | 3 +- 4 files changed, 104 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 952cc340b510..7af2b14ab5d8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -21,6 +21,7 @@ struct mlx5_fw_reset { struct workqueue_struct *wq; struct work_struct fw_live_patch_work; struct work_struct reset_request_work; + struct work_struct reset_unload_work; struct work_struct reset_reload_work; struct work_struct reset_now_work; struct work_struct reset_abort_work; @@ -30,6 +31,26 @@ struct mlx5_fw_reset { int ret; }; +enum { + MLX5_FW_RST_STATE_IDLE = 0, + MLX5_FW_RST_STATE_TOGGLE_REQ = 4, +}; + +enum { + MLX5_RST_STATE_BIT_NUM = 12, + MLX5_RST_ACK_BIT_NUM = 22, +}; + +static u8 mlx5_get_fw_rst_state(struct mlx5_core_dev *dev) +{ + return (ioread32be(&dev->iseg->initializing) >> MLX5_RST_STATE_BIT_NUM) & 0xF; +} + +static void mlx5_set_fw_rst_ack(struct mlx5_core_dev *dev) +{ + iowrite32be(BIT(MLX5_RST_ACK_BIT_NUM), &dev->iseg->initializing); +} + static int mlx5_fw_reset_enable_remote_dev_reset_set(struct devlink *devlink, u32 id, struct devlink_param_gset_ctx *ctx) { @@ -155,7 +176,7 @@ int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev) return mlx5_reg_mfrl_set(dev, MLX5_MFRL_REG_RESET_LEVEL0, 0, 0, false); } -static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev) +static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unloaded) { struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset; @@ -163,7 +184,8 @@ static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev) if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) { complete(&fw_reset->done); } else { - mlx5_unload_one(dev, false); + if (!unloaded) + mlx5_unload_one(dev, false); if (mlx5_health_wait_pci_up(dev)) mlx5_core_err(dev, "reset reload flow aborted, PCI reads still not working\n"); else @@ -204,7 +226,7 @@ static void mlx5_sync_reset_reload_work(struct work_struct *work) mlx5_sync_reset_clear_reset_requested(dev, false); mlx5_enter_error_state(dev, true); - mlx5_fw_reset_complete_reload(dev); + mlx5_fw_reset_complete_reload(dev, false); } #define MLX5_RESET_POLL_INTERVAL (HZ / 10) @@ -458,7 +480,70 @@ static void mlx5_sync_reset_now_event(struct work_struct *work) mlx5_enter_error_state(dev, true); done: fw_reset->ret = err; - mlx5_fw_reset_complete_reload(dev); + mlx5_fw_reset_complete_reload(dev, false); +} + +static void mlx5_sync_reset_unload_event(struct work_struct *work) +{ + struct mlx5_fw_reset *fw_reset; + struct mlx5_core_dev *dev; + unsigned long timeout; + bool reset_action; + u8 rst_state; + int err; + + fw_reset = container_of(work, struct mlx5_fw_reset, reset_unload_work); + dev = fw_reset->dev; + + if (mlx5_sync_reset_clear_reset_requested(dev, false)) + return; + + mlx5_core_warn(dev, "Sync Reset Unload. Function is forced down.\n"); + + err = mlx5_cmd_fast_teardown_hca(dev); + if (err) + mlx5_core_warn(dev, "Fast teardown failed, unloading, err %d\n", err); + else + mlx5_enter_error_state(dev, true); + + if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) + mlx5_unload_one_devl_locked(dev, false); + else + mlx5_unload_one(dev, false); + + mlx5_set_fw_rst_ack(dev); + mlx5_core_warn(dev, "Sync Reset Unload done, device reset expected\n"); + + reset_action = false; + timeout = jiffies + msecs_to_jiffies(mlx5_tout_ms(dev, RESET_UNLOAD)); + do { + rst_state = mlx5_get_fw_rst_state(dev); + if (rst_state == MLX5_FW_RST_STATE_TOGGLE_REQ || + rst_state == MLX5_FW_RST_STATE_IDLE) { + reset_action = true; + break; + } + msleep(20); + } while (!time_after(jiffies, timeout)); + + if (!reset_action) { + mlx5_core_err(dev, "Got timeout waiting for sync reset action, state = %u\n", + rst_state); + fw_reset->ret = -ETIMEDOUT; + goto done; + } + + mlx5_core_warn(dev, "Sync Reset, got reset action. rst_state = %u\n", rst_state); + if (rst_state == MLX5_FW_RST_STATE_TOGGLE_REQ) { + err = mlx5_pci_link_toggle(dev); + if (err) { + mlx5_core_warn(dev, "mlx5_pci_link_toggle failed, err %d\n", err); + fw_reset->ret = err; + } + } + +done: + mlx5_fw_reset_complete_reload(dev, true); } static void mlx5_sync_reset_abort_event(struct work_struct *work) @@ -483,6 +568,9 @@ static void mlx5_sync_reset_events_handle(struct mlx5_fw_reset *fw_reset, struct case MLX5_SYNC_RST_STATE_RESET_REQUEST: queue_work(fw_reset->wq, &fw_reset->reset_request_work); break; + case MLX5_SYNC_RST_STATE_RESET_UNLOAD: + queue_work(fw_reset->wq, &fw_reset->reset_unload_work); + break; case MLX5_SYNC_RST_STATE_RESET_NOW: queue_work(fw_reset->wq, &fw_reset->reset_now_work); break; @@ -517,10 +605,13 @@ static int fw_reset_event_notifier(struct notifier_block *nb, unsigned long acti int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev) { unsigned long pci_sync_update_timeout = mlx5_tout_ms(dev, PCI_SYNC_UPDATE); - unsigned long timeout = msecs_to_jiffies(pci_sync_update_timeout); struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset; + unsigned long timeout; int err; + if (MLX5_CAP_GEN(dev, pci_sync_for_fw_update_with_driver_unload)) + pci_sync_update_timeout += mlx5_tout_ms(dev, RESET_UNLOAD); + timeout = msecs_to_jiffies(pci_sync_update_timeout); if (!wait_for_completion_timeout(&fw_reset->done, timeout)) { mlx5_core_warn(dev, "FW sync reset timeout after %lu seconds\n", pci_sync_update_timeout / 1000); @@ -557,6 +648,7 @@ void mlx5_drain_fw_reset(struct mlx5_core_dev *dev) set_bit(MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, &fw_reset->reset_flags); cancel_work_sync(&fw_reset->fw_live_patch_work); cancel_work_sync(&fw_reset->reset_request_work); + cancel_work_sync(&fw_reset->reset_unload_work); cancel_work_sync(&fw_reset->reset_reload_work); cancel_work_sync(&fw_reset->reset_now_work); cancel_work_sync(&fw_reset->reset_abort_work); @@ -595,6 +687,7 @@ int mlx5_fw_reset_init(struct mlx5_core_dev *dev) INIT_WORK(&fw_reset->fw_live_patch_work, mlx5_fw_live_patch_event); INIT_WORK(&fw_reset->reset_request_work, mlx5_sync_reset_request_event); + INIT_WORK(&fw_reset->reset_unload_work, mlx5_sync_reset_unload_event); INIT_WORK(&fw_reset->reset_reload_work, mlx5_sync_reset_reload_work); INIT_WORK(&fw_reset->reset_now_work, mlx5_sync_reset_now_event); INIT_WORK(&fw_reset->reset_abort_work, mlx5_sync_reset_abort_event); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 6fa314f8e5ee..88dbea6631d5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -619,6 +619,9 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx) if (MLX5_CAP_GEN_MAX(dev, pci_sync_for_fw_update_event)) MLX5_SET(cmd_hca_cap, set_hca_cap, pci_sync_for_fw_update_event, 1); + if (MLX5_CAP_GEN_MAX(dev, pci_sync_for_fw_update_with_driver_unload)) + MLX5_SET(cmd_hca_cap, set_hca_cap, + pci_sync_for_fw_update_with_driver_unload, 1); if (MLX5_CAP_GEN_MAX(dev, num_vhca_ports)) MLX5_SET(cmd_hca_cap, diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index c0af74efd3cb..80cc12a9a531 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -716,6 +716,7 @@ enum sync_rst_state_type { MLX5_SYNC_RST_STATE_RESET_REQUEST = 0x0, MLX5_SYNC_RST_STATE_RESET_NOW = 0x1, MLX5_SYNC_RST_STATE_RESET_ABORT = 0x2, + MLX5_SYNC_RST_STATE_RESET_UNLOAD = 0x3, }; struct mlx5_eqe_sync_fw_update { diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 14892e795808..d61dcb5d7cd5 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1755,7 +1755,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 reserved_at_328[0x2]; u8 relaxed_ordering_read[0x1]; u8 log_max_pd[0x5]; - u8 reserved_at_330[0x7]; + u8 reserved_at_330[0x6]; + u8 pci_sync_for_fw_update_with_driver_unload[0x1]; u8 vnic_env_cnt_steering_fail[0x1]; u8 reserved_at_338[0x1]; u8 q_counter_aggregation[0x1]; -- cgit v1.2.3 From f405787a0abaf14e332aa6d1d924e75970332e68 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Thu, 1 Jun 2023 09:34:35 +0200 Subject: net/mlx5: Create eswitch debugfs root directory Following patch in series uses the new directory for bridge FDB debugfs. The new directory is intended for all future eswitch-specific debugfs files. Signed-off-by: Vlad Buslov Reviewed-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 4 ++++ drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 2af9c4646bc7..5aaedbf71783 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -31,6 +31,7 @@ */ #include +#include #include #include #include @@ -1765,6 +1766,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) esw->manager_vport = mlx5_eswitch_manager_vport(dev); esw->first_host_vport = mlx5_eswitch_first_host_vport_num(dev); + esw->debugfs_root = debugfs_create_dir("esw", mlx5_debugfs_get_dev_root(dev)); esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq"); if (!esw->work_queue) { err = -ENOMEM; @@ -1818,6 +1820,7 @@ reps_err: abort: if (esw->work_queue) destroy_workqueue(esw->work_queue); + debugfs_remove_recursive(esw->debugfs_root); kfree(esw); unregister_param: devl_params_unregister(priv_to_devlink(dev), mlx5_eswitch_params, @@ -1844,6 +1847,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) mutex_destroy(&esw->offloads.decap_tbl_lock); esw_offloads_cleanup(esw); mlx5_esw_vports_cleanup(esw); + debugfs_remove_recursive(esw->debugfs_root); kfree(esw); devl_params_unregister(priv_to_devlink(esw->dev), mlx5_eswitch_params, ARRAY_SIZE(mlx5_eswitch_params)); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 266b60fefe25..bcbab06759c4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -304,6 +304,8 @@ enum { MLX5_ESW_FDB_CREATED = BIT(0), }; +struct dentry; + struct mlx5_eswitch { struct mlx5_core_dev *dev; struct mlx5_nb nb; @@ -312,6 +314,7 @@ struct mlx5_eswitch { struct hlist_head mc_table[MLX5_L2_ADDR_HASH_SIZE]; struct esw_mc_addr mc_promisc; /* end of legacy */ + struct dentry *debugfs_root; struct workqueue_struct *work_queue; struct xarray vports; u32 flags; -- cgit v1.2.3 From ade19f0d6a3a395e7936227811acbf897ee186fc Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Fri, 26 May 2023 08:55:15 +0200 Subject: net/mlx5: Bridge, pass net device when linking vport to bridge Following patch requires access to additional data in bridge net_device. Pass the whole structure down the stack instead of adding necessary fields as function arguments one-by-one. Signed-off-by: Vlad Buslov Reviewed-by: Gal Pressman Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/en/rep/bridge.c | 9 +++--- .../net/ethernet/mellanox/mlx5/core/esw/bridge.c | 35 ++++++++++++---------- .../net/ethernet/mellanox/mlx5/core/esw/bridge.h | 10 ++++--- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c index fd191925ab4b..560800246573 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/bridge.c @@ -136,7 +136,6 @@ static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr struct mlx5_eswitch *esw = br_offloads->esw; u16 vport_num, esw_owner_vhca_id; struct netlink_ext_ack *extack; - int ifindex = upper->ifindex; int err = 0; if (!netif_is_bridge_master(upper)) @@ -150,15 +149,15 @@ static int mlx5_esw_bridge_port_changeupper(struct notifier_block *nb, void *ptr if (mlx5_esw_bridge_is_local(dev, rep, esw)) err = info->linking ? - mlx5_esw_bridge_vport_link(ifindex, vport_num, esw_owner_vhca_id, + mlx5_esw_bridge_vport_link(upper, vport_num, esw_owner_vhca_id, br_offloads, extack) : - mlx5_esw_bridge_vport_unlink(ifindex, vport_num, esw_owner_vhca_id, + mlx5_esw_bridge_vport_unlink(upper, vport_num, esw_owner_vhca_id, br_offloads, extack); else if (mlx5_esw_bridge_dev_same_hw(rep, esw)) err = info->linking ? - mlx5_esw_bridge_vport_peer_link(ifindex, vport_num, esw_owner_vhca_id, + mlx5_esw_bridge_vport_peer_link(upper, vport_num, esw_owner_vhca_id, br_offloads, extack) : - mlx5_esw_bridge_vport_peer_unlink(ifindex, vport_num, esw_owner_vhca_id, + mlx5_esw_bridge_vport_peer_unlink(upper, vport_num, esw_owner_vhca_id, br_offloads, extack); return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c index bea7cc645461..eaa9b328abd5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c @@ -834,7 +834,7 @@ mlx5_esw_bridge_egress_miss_flow_create(struct mlx5_flow_table *egress_ft, return handle; } -static struct mlx5_esw_bridge *mlx5_esw_bridge_create(int ifindex, +static struct mlx5_esw_bridge *mlx5_esw_bridge_create(struct net_device *br_netdev, struct mlx5_esw_bridge_offloads *br_offloads) { struct mlx5_esw_bridge *bridge; @@ -858,7 +858,7 @@ static struct mlx5_esw_bridge *mlx5_esw_bridge_create(int ifindex, goto err_mdb_ht; INIT_LIST_HEAD(&bridge->fdb_list); - bridge->ifindex = ifindex; + bridge->ifindex = br_netdev->ifindex; bridge->refcnt = 1; bridge->ageing_time = clock_t_to_jiffies(BR_DEFAULT_AGEING_TIME); bridge->vlan_proto = ETH_P_8021Q; @@ -898,14 +898,14 @@ static void mlx5_esw_bridge_put(struct mlx5_esw_bridge_offloads *br_offloads, } static struct mlx5_esw_bridge * -mlx5_esw_bridge_lookup(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads) +mlx5_esw_bridge_lookup(struct net_device *br_netdev, struct mlx5_esw_bridge_offloads *br_offloads) { struct mlx5_esw_bridge *bridge; ASSERT_RTNL(); list_for_each_entry(bridge, &br_offloads->bridges, list) { - if (bridge->ifindex == ifindex) { + if (bridge->ifindex == br_netdev->ifindex) { mlx5_esw_bridge_get(bridge); return bridge; } @@ -918,7 +918,7 @@ mlx5_esw_bridge_lookup(int ifindex, struct mlx5_esw_bridge_offloads *br_offloads return ERR_PTR(err); } - bridge = mlx5_esw_bridge_create(ifindex, br_offloads); + bridge = mlx5_esw_bridge_create(br_netdev, br_offloads); if (IS_ERR(bridge) && list_empty(&br_offloads->bridges)) mlx5_esw_bridge_ingress_table_cleanup(br_offloads); return bridge; @@ -1601,15 +1601,15 @@ static int mlx5_esw_bridge_vport_cleanup(struct mlx5_esw_bridge_offloads *br_off return 0; } -static int mlx5_esw_bridge_vport_link_with_flags(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, - u16 flags, +static int mlx5_esw_bridge_vport_link_with_flags(struct net_device *br_netdev, u16 vport_num, + u16 esw_owner_vhca_id, u16 flags, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack) { struct mlx5_esw_bridge *bridge; int err; - bridge = mlx5_esw_bridge_lookup(ifindex, br_offloads); + bridge = mlx5_esw_bridge_lookup(br_netdev, br_offloads); if (IS_ERR(bridge)) { NL_SET_ERR_MSG_MOD(extack, "Error checking for existing bridge with same ifindex"); return PTR_ERR(bridge); @@ -1627,15 +1627,16 @@ err_vport: return err; } -int mlx5_esw_bridge_vport_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, +int mlx5_esw_bridge_vport_link(struct net_device *br_netdev, u16 vport_num, u16 esw_owner_vhca_id, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack) { - return mlx5_esw_bridge_vport_link_with_flags(ifindex, vport_num, esw_owner_vhca_id, 0, + return mlx5_esw_bridge_vport_link_with_flags(br_netdev, vport_num, esw_owner_vhca_id, 0, br_offloads, extack); } -int mlx5_esw_bridge_vport_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, +int mlx5_esw_bridge_vport_unlink(struct net_device *br_netdev, u16 vport_num, + u16 esw_owner_vhca_id, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack) { @@ -1647,7 +1648,7 @@ int mlx5_esw_bridge_vport_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_ NL_SET_ERR_MSG_MOD(extack, "Port is not attached to any bridge"); return -EINVAL; } - if (port->bridge->ifindex != ifindex) { + if (port->bridge->ifindex != br_netdev->ifindex) { NL_SET_ERR_MSG_MOD(extack, "Port is attached to another bridge"); return -EINVAL; } @@ -1658,23 +1659,25 @@ int mlx5_esw_bridge_vport_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_ return err; } -int mlx5_esw_bridge_vport_peer_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, +int mlx5_esw_bridge_vport_peer_link(struct net_device *br_netdev, u16 vport_num, + u16 esw_owner_vhca_id, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack) { if (!MLX5_CAP_ESW(br_offloads->esw->dev, merged_eswitch)) return 0; - return mlx5_esw_bridge_vport_link_with_flags(ifindex, vport_num, esw_owner_vhca_id, + return mlx5_esw_bridge_vport_link_with_flags(br_netdev, vport_num, esw_owner_vhca_id, MLX5_ESW_BRIDGE_PORT_FLAG_PEER, br_offloads, extack); } -int mlx5_esw_bridge_vport_peer_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, +int mlx5_esw_bridge_vport_peer_unlink(struct net_device *br_netdev, u16 vport_num, + u16 esw_owner_vhca_id, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack) { - return mlx5_esw_bridge_vport_unlink(ifindex, vport_num, esw_owner_vhca_id, br_offloads, + return mlx5_esw_bridge_vport_unlink(br_netdev, vport_num, esw_owner_vhca_id, br_offloads, extack); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h index a9dd18c73d6a..2f7ad3bdba5e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h @@ -43,16 +43,18 @@ struct mlx5_esw_bridge_offloads { struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw); void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw); -int mlx5_esw_bridge_vport_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, +int mlx5_esw_bridge_vport_link(struct net_device *br_netdev, u16 vport_num, u16 esw_owner_vhca_id, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack); -int mlx5_esw_bridge_vport_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, +int mlx5_esw_bridge_vport_unlink(struct net_device *br_netdev, u16 vport_num, u16 esw_owner_vhca_id, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack); -int mlx5_esw_bridge_vport_peer_link(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, +int mlx5_esw_bridge_vport_peer_link(struct net_device *br_netdev, u16 vport_num, + u16 esw_owner_vhca_id, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack); -int mlx5_esw_bridge_vport_peer_unlink(int ifindex, u16 vport_num, u16 esw_owner_vhca_id, +int mlx5_esw_bridge_vport_peer_unlink(struct net_device *br_netdev, u16 vport_num, + u16 esw_owner_vhca_id, struct mlx5_esw_bridge_offloads *br_offloads, struct netlink_ext_ack *extack); void mlx5_esw_bridge_fdb_update_used(struct net_device *dev, u16 vport_num, u16 esw_owner_vhca_id, -- cgit v1.2.3 From 791eb78285e8b81bc09bfc6bd928b981eaefb082 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Thu, 25 May 2023 15:19:00 +0200 Subject: net/mlx5: Bridge, expose FDB state via debugfs For debugging purposes expose offloaded FDB state (flags, counters, etc.) via debugfs inside 'esw' root directory. Example debugfs file output: $ cat mlx5/0000\:08\:00.0/esw/bridge/bridge1/fdb DEV MAC VLAN PACKETS BYTES LASTUSE FLAGS enp8s0f0_1 e4:0a:05:08:00:06 2 2 204 4295567112 0x0 enp8s0f0_0 e4:0a:05:08:00:03 2 3 278 4295567112 0x0 Signed-off-by: Vlad Buslov Reviewed-by: Tariq Toukan Reviewed-by: Gal Pressman Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 3 +- .../net/ethernet/mellanox/mlx5/core/esw/bridge.c | 4 + .../net/ethernet/mellanox/mlx5/core/esw/bridge.h | 2 + .../mellanox/mlx5/core/esw/bridge_debugfs.c | 89 ++++++++++++++++++++++ .../ethernet/mellanox/mlx5/core/esw/bridge_priv.h | 6 ++ 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index ddf1e352f51d..35f00700a4d6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -75,7 +75,8 @@ mlx5_core-$(CONFIG_MLX5_ESWITCH) += esw/acl/helper.o \ esw/acl/egress_lgcy.o esw/acl/egress_ofld.o \ esw/acl/ingress_lgcy.o esw/acl/ingress_ofld.o -mlx5_core-$(CONFIG_MLX5_BRIDGE) += esw/bridge.o esw/bridge_mcast.o en/rep/bridge.o +mlx5_core-$(CONFIG_MLX5_BRIDGE) += esw/bridge.o esw/bridge_mcast.o esw/bridge_debugfs.o \ + en/rep/bridge.o mlx5_core-$(CONFIG_THERMAL) += thermal.o mlx5_core-$(CONFIG_MLX5_MPFS) += lib/mpfs.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c index eaa9b328abd5..f4fe1daa4afd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.c @@ -863,6 +863,7 @@ static struct mlx5_esw_bridge *mlx5_esw_bridge_create(struct net_device *br_netd bridge->ageing_time = clock_t_to_jiffies(BR_DEFAULT_AGEING_TIME); bridge->vlan_proto = ETH_P_8021Q; list_add(&bridge->list, &br_offloads->bridges); + mlx5_esw_bridge_debugfs_init(br_netdev, bridge); return bridge; @@ -886,6 +887,7 @@ static void mlx5_esw_bridge_put(struct mlx5_esw_bridge_offloads *br_offloads, if (--bridge->refcnt) return; + mlx5_esw_bridge_debugfs_cleanup(bridge); mlx5_esw_bridge_egress_table_cleanup(bridge); mlx5_esw_bridge_mcast_disable(bridge); list_del(&bridge->list); @@ -1904,6 +1906,7 @@ struct mlx5_esw_bridge_offloads *mlx5_esw_bridge_init(struct mlx5_eswitch *esw) xa_init(&br_offloads->ports); br_offloads->esw = esw; esw->br_offloads = br_offloads; + mlx5_esw_bridge_debugfs_offloads_init(br_offloads); return br_offloads; } @@ -1919,6 +1922,7 @@ void mlx5_esw_bridge_cleanup(struct mlx5_eswitch *esw) mlx5_esw_bridge_flush(br_offloads); WARN_ON(!xa_empty(&br_offloads->ports)); + mlx5_esw_bridge_debugfs_offloads_cleanup(br_offloads); esw->br_offloads = NULL; kvfree(br_offloads); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h index 2f7ad3bdba5e..c2c7c70d99eb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge.h @@ -10,6 +10,7 @@ #include #include "eswitch.h" +struct dentry; struct mlx5_flow_table; struct mlx5_flow_group; @@ -17,6 +18,7 @@ struct mlx5_esw_bridge_offloads { struct mlx5_eswitch *esw; struct list_head bridges; struct xarray ports; + struct dentry *debugfs_root; struct notifier_block netdev_nb; struct notifier_block nb_blk; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c new file mode 100644 index 000000000000..b6a45eff28f5 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_debugfs.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB +/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#include +#include "bridge.h" +#include "bridge_priv.h" + +static void *mlx5_esw_bridge_debugfs_start(struct seq_file *seq, loff_t *pos); +static void *mlx5_esw_bridge_debugfs_next(struct seq_file *seq, void *v, loff_t *pos); +static void mlx5_esw_bridge_debugfs_stop(struct seq_file *seq, void *v); +static int mlx5_esw_bridge_debugfs_show(struct seq_file *seq, void *v); + +static const struct seq_operations mlx5_esw_bridge_debugfs_sops = { + .start = mlx5_esw_bridge_debugfs_start, + .next = mlx5_esw_bridge_debugfs_next, + .stop = mlx5_esw_bridge_debugfs_stop, + .show = mlx5_esw_bridge_debugfs_show, +}; +DEFINE_SEQ_ATTRIBUTE(mlx5_esw_bridge_debugfs); + +static void *mlx5_esw_bridge_debugfs_start(struct seq_file *seq, loff_t *pos) +{ + struct mlx5_esw_bridge *bridge = seq->private; + + rtnl_lock(); + return *pos ? seq_list_start(&bridge->fdb_list, *pos - 1) : SEQ_START_TOKEN; +} + +static void *mlx5_esw_bridge_debugfs_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct mlx5_esw_bridge *bridge = seq->private; + + return seq_list_next(v == SEQ_START_TOKEN ? &bridge->fdb_list : v, &bridge->fdb_list, pos); +} + +static void mlx5_esw_bridge_debugfs_stop(struct seq_file *seq, void *v) +{ + rtnl_unlock(); +} + +static int mlx5_esw_bridge_debugfs_show(struct seq_file *seq, void *v) +{ + struct mlx5_esw_bridge_fdb_entry *entry; + u64 packets, bytes, lastuse; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "%-16s %-17s %4s %20s %20s %20s %5s\n", + "DEV", "MAC", "VLAN", "PACKETS", "BYTES", "LASTUSE", "FLAGS"); + return 0; + } + + entry = list_entry(v, struct mlx5_esw_bridge_fdb_entry, list); + mlx5_fc_query_cached_raw(entry->ingress_counter, &bytes, &packets, &lastuse); + seq_printf(seq, "%-16s %-17pM %4d %20llu %20llu %20llu %#5x\n", + entry->dev->name, entry->key.addr, entry->key.vid, packets, bytes, lastuse, + entry->flags); + return 0; +} + +void mlx5_esw_bridge_debugfs_init(struct net_device *br_netdev, struct mlx5_esw_bridge *bridge) +{ + if (!bridge->br_offloads->debugfs_root) + return; + + bridge->debugfs_dir = debugfs_create_dir(br_netdev->name, + bridge->br_offloads->debugfs_root); + debugfs_create_file("fdb", 0444, bridge->debugfs_dir, bridge, + &mlx5_esw_bridge_debugfs_fops); +} + +void mlx5_esw_bridge_debugfs_cleanup(struct mlx5_esw_bridge *bridge) +{ + debugfs_remove_recursive(bridge->debugfs_dir); + bridge->debugfs_dir = NULL; +} + +void mlx5_esw_bridge_debugfs_offloads_init(struct mlx5_esw_bridge_offloads *br_offloads) +{ + if (!br_offloads->esw->debugfs_root) + return; + + br_offloads->debugfs_root = debugfs_create_dir("bridge", br_offloads->esw->debugfs_root); +} + +void mlx5_esw_bridge_debugfs_offloads_cleanup(struct mlx5_esw_bridge_offloads *br_offloads) +{ + debugfs_remove_recursive(br_offloads->debugfs_root); + br_offloads->debugfs_root = NULL; +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h index c9595801bdb4..4911cc32161b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_priv.h @@ -199,6 +199,7 @@ struct mlx5_esw_bridge { int refcnt; struct list_head list; struct mlx5_esw_bridge_offloads *br_offloads; + struct dentry *debugfs_dir; struct list_head fdb_list; struct rhashtable fdb_ht; @@ -241,4 +242,9 @@ void mlx5_esw_bridge_port_mdb_vlan_flush(struct mlx5_esw_bridge_port *port, struct mlx5_esw_bridge_vlan *vlan); void mlx5_esw_bridge_mdb_flush(struct mlx5_esw_bridge *bridge); +void mlx5_esw_bridge_debugfs_offloads_init(struct mlx5_esw_bridge_offloads *br_offloads); +void mlx5_esw_bridge_debugfs_offloads_cleanup(struct mlx5_esw_bridge_offloads *br_offloads); +void mlx5_esw_bridge_debugfs_init(struct net_device *br_netdev, struct mlx5_esw_bridge *bridge); +void mlx5_esw_bridge_debugfs_cleanup(struct mlx5_esw_bridge *bridge); + #endif /* _MLX5_ESW_BRIDGE_PRIVATE_ */ -- cgit v1.2.3 From 8a955da230d39932869e7a6835143be9889b0a45 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Wed, 7 Jun 2023 14:12:10 -0700 Subject: net/mlx5: E-Switch, remove redundant else statements These else statement blocks are redundant since the if block already jumps to the function abort label. Signed-off-by: Saeed Mahameed Reviewed-by: Rahul Rameshbabu --- drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c index fabe49a35a5c..255bc8b749f9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c @@ -285,9 +285,8 @@ static int _mlx5_eswitch_set_vepa_locked(struct mlx5_eswitch *esw, if (IS_ERR(flow_rule)) { err = PTR_ERR(flow_rule); goto out; - } else { - esw->fdb_table.legacy.vepa_uplink_rule = flow_rule; } + esw->fdb_table.legacy.vepa_uplink_rule = flow_rule; /* Star rule to forward all traffic to uplink vport */ memset(&dest, 0, sizeof(dest)); @@ -299,9 +298,8 @@ static int _mlx5_eswitch_set_vepa_locked(struct mlx5_eswitch *esw, if (IS_ERR(flow_rule)) { err = PTR_ERR(flow_rule); goto out; - } else { - esw->fdb_table.legacy.vepa_star_rule = flow_rule; } + esw->fdb_table.legacy.vepa_star_rule = flow_rule; out: kvfree(spec); -- cgit v1.2.3 From 559f4c32ebff40a25199b5178d58c9283ac5eb9c Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Sun, 23 Apr 2023 14:29:26 +0300 Subject: net/mlx5e: Remove mlx5e_dbg() and msglvl support The msglvl support was implemented using the mlx5e_dbg() macro which is rarely used in the driver, and is not very useful when you can just use dynamic debug instead. Remove mlx5e_dbg() and convert its usages to netdev_dbg(). Signed-off-by: Gal Pressman Reviewed-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 10 ----- .../ethernet/mellanox/mlx5/core/en/port_buffer.c | 44 +++++++++++----------- drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c | 8 ++-- drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c | 26 ++++++------- .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 18 ++------- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 5 +-- 6 files changed, 45 insertions(+), 66 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index ceabe57c511a..b1807bfb815f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -165,15 +165,6 @@ struct page_pool; #define MLX5E_MAX_KLM_PER_WQE(mdev) \ MLX5E_KLM_ENTRIES_PER_WQE(MLX5_SEND_WQE_BB * mlx5e_get_max_sq_aligned_wqebbs(mdev)) -#define MLX5E_MSG_LEVEL NETIF_MSG_LINK - -#define mlx5e_dbg(mlevel, priv, format, ...) \ -do { \ - if (NETIF_MSG_##mlevel & (priv)->msglevel) \ - netdev_warn(priv->netdev, format, \ - ##__VA_ARGS__); \ -} while (0) - #define mlx5e_state_dereference(priv, p) \ rcu_dereference_protected((p), lockdep_is_held(&(priv)->state_lock)) @@ -880,7 +871,6 @@ struct mlx5e_priv { #endif /* priv data path fields - end */ - u32 msglevel; unsigned long state; struct mutex state_lock; /* Protects Interface state */ struct mlx5e_rq drop_rq; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c index 7e8e96cc5cd0..8e25f4ef5ccc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c @@ -65,12 +65,13 @@ int mlx5e_port_query_buffer(struct mlx5e_priv *priv, MLX5_GET(bufferx_reg, buffer, xoff_threshold) * port_buff_cell_sz; total_used += port_buffer->buffer[i].size; - mlx5e_dbg(HW, priv, "buffer %d: size=%d, xon=%d, xoff=%d, epsb=%d, lossy=%d\n", i, - port_buffer->buffer[i].size, - port_buffer->buffer[i].xon, - port_buffer->buffer[i].xoff, - port_buffer->buffer[i].epsb, - port_buffer->buffer[i].lossy); + netdev_dbg(priv->netdev, "buffer %d: size=%d, xon=%d, xoff=%d, epsb=%d, lossy=%d\n", + i, + port_buffer->buffer[i].size, + port_buffer->buffer[i].xon, + port_buffer->buffer[i].xoff, + port_buffer->buffer[i].epsb, + port_buffer->buffer[i].lossy); } port_buffer->internal_buffers_size = 0; @@ -87,11 +88,11 @@ int mlx5e_port_query_buffer(struct mlx5e_priv *priv, port_buffer->internal_buffers_size - port_buffer->headroom_size; - mlx5e_dbg(HW, priv, - "total buffer size=%u, headroom buffer size=%u, internal buffers size=%u, spare buffer size=%u\n", - port_buffer->port_buffer_size, port_buffer->headroom_size, - port_buffer->internal_buffers_size, - port_buffer->spare_buffer_size); + netdev_dbg(priv->netdev, + "total buffer size=%u, headroom buffer size=%u, internal buffers size=%u, spare buffer size=%u\n", + port_buffer->port_buffer_size, port_buffer->headroom_size, + port_buffer->internal_buffers_size, + port_buffer->spare_buffer_size); out: kfree(out); return err; @@ -352,7 +353,7 @@ static u32 calculate_xoff(struct mlx5e_priv *priv, unsigned int mtu) xoff = (301 + 216 * priv->dcbx.cable_len / 100) * speed / 1000 + 272 * mtu / 100; - mlx5e_dbg(HW, priv, "%s: xoff=%d\n", __func__, xoff); + netdev_dbg(priv->netdev, "%s: xoff=%d\n", __func__, xoff); return xoff; } @@ -484,6 +485,7 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, u8 *prio2buffer) { u16 port_buff_cell_sz = priv->dcbx.port_buff_cell_sz; + struct net_device *netdev = priv->netdev; struct mlx5e_port_buffer port_buffer; u32 xoff = calculate_xoff(priv, mtu); bool update_prio2buffer = false; @@ -495,7 +497,7 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, int err; int i; - mlx5e_dbg(HW, priv, "%s: change=%x\n", __func__, change); + netdev_dbg(netdev, "%s: change=%x\n", __func__, change); max_mtu = max_t(unsigned int, priv->netdev->max_mtu, MINIMUM_MAX_MTU); err = mlx5e_port_query_buffer(priv, &port_buffer); @@ -510,8 +512,8 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, } if (change & MLX5E_PORT_BUFFER_PFC) { - mlx5e_dbg(HW, priv, "%s: requested PFC per priority bitmask: 0x%x\n", - __func__, pfc->pfc_en); + netdev_dbg(netdev, "%s: requested PFC per priority bitmask: 0x%x\n", + __func__, pfc->pfc_en); err = mlx5e_port_query_priority2buffer(priv->mdev, buffer); if (err) return err; @@ -526,8 +528,8 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) { update_prio2buffer = true; for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) - mlx5e_dbg(HW, priv, "%s: requested to map prio[%d] to buffer %d\n", - __func__, i, prio2buffer[i]); + netdev_dbg(priv->netdev, "%s: requested to map prio[%d] to buffer %d\n", + __func__, i, prio2buffer[i]); err = fill_pfc_en(priv->mdev, &curr_pfc_en); if (err) @@ -541,10 +543,10 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, if (change & MLX5E_PORT_BUFFER_SIZE) { for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) { - mlx5e_dbg(HW, priv, "%s: buffer[%d]=%d\n", __func__, i, buffer_size[i]); + netdev_dbg(priv->netdev, "%s: buffer[%d]=%d\n", __func__, i, buffer_size[i]); if (!port_buffer.buffer[i].lossy && !buffer_size[i]) { - mlx5e_dbg(HW, priv, "%s: lossless buffer[%d] size cannot be zero\n", - __func__, i); + netdev_dbg(priv->netdev, "%s: lossless buffer[%d] size cannot be zero\n", + __func__, i); return -EINVAL; } @@ -552,7 +554,7 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, total_used += buffer_size[i]; } - mlx5e_dbg(HW, priv, "%s: total buffer requested=%d\n", __func__, total_used); + netdev_dbg(priv->netdev, "%s: total buffer requested=%d\n", __func__, total_used); if (total_used > port_buffer.headroom_size && (total_used - port_buffer.headroom_size) > diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c index bed0c2d043e7..933a7772a7a3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c @@ -570,10 +570,10 @@ static struct mlx5_flow_handle *arfs_add_rule(struct mlx5e_priv *priv, if (IS_ERR(rule)) { err = PTR_ERR(rule); priv->channel_stats[arfs_rule->rxq]->rq.arfs_err++; - mlx5e_dbg(HW, priv, - "%s: add rule(filter id=%d, rq idx=%d, ip proto=0x%x) failed,err=%d\n", - __func__, arfs_rule->filter_id, arfs_rule->rxq, - tuple->ip_proto, err); + netdev_dbg(priv->netdev, + "%s: add rule(filter id=%d, rq idx=%d, ip proto=0x%x) failed,err=%d\n", + __func__, arfs_rule->filter_id, arfs_rule->rxq, + tuple->ip_proto, err); } out: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c index ebee52a8361a..8705cffc747f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c @@ -275,10 +275,10 @@ static int mlx5e_dcbnl_ieee_setets_core(struct mlx5e_priv *priv, struct ieee_ets memcpy(priv->dcbx.tc_tsa, ets->tc_tsa, sizeof(ets->tc_tsa)); for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { - mlx5e_dbg(HW, priv, "%s: prio_%d <=> tc_%d\n", - __func__, i, ets->prio_tc[i]); - mlx5e_dbg(HW, priv, "%s: tc_%d <=> tx_bw_%d%%, group_%d\n", - __func__, i, tc_tx_bw[i], tc_group[i]); + netdev_dbg(priv->netdev, "%s: prio_%d <=> tc_%d\n", + __func__, i, ets->prio_tc[i]); + netdev_dbg(priv->netdev, "%s: tc_%d <=> tx_bw_%d%%, group_%d\n", + __func__, i, tc_tx_bw[i], tc_group[i]); } return err; @@ -399,9 +399,9 @@ static int mlx5e_dcbnl_ieee_setpfc(struct net_device *dev, } if (!ret) { - mlx5e_dbg(HW, priv, - "%s: PFC per priority bit mask: 0x%x\n", - __func__, pfc->pfc_en); + netdev_dbg(dev, + "%s: PFC per priority bit mask: 0x%x\n", + __func__, pfc->pfc_en); } return ret; } @@ -611,8 +611,8 @@ static int mlx5e_dcbnl_ieee_setmaxrate(struct net_device *netdev, } for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { - mlx5e_dbg(HW, priv, "%s: tc_%d <=> max_bw %d Gbps\n", - __func__, i, max_bw_value[i]); + netdev_dbg(netdev, "%s: tc_%d <=> max_bw %d Gbps\n", + __func__, i, max_bw_value[i]); } return mlx5_modify_port_ets_rate_limit(mdev, max_bw_value, max_bw_unit); @@ -640,10 +640,10 @@ static u8 mlx5e_dcbnl_setall(struct net_device *netdev) ets.tc_rx_bw[i] = cee_cfg->pg_bw_pct[i]; ets.tc_tsa[i] = IEEE_8021QAZ_TSA_ETS; ets.prio_tc[i] = cee_cfg->prio_to_pg_map[i]; - mlx5e_dbg(HW, priv, - "%s: Priority group %d: tx_bw %d, rx_bw %d, prio_tc %d\n", - __func__, i, ets.tc_tx_bw[i], ets.tc_rx_bw[i], - ets.prio_tc[i]); + netdev_dbg(netdev, + "%s: Priority group %d: tx_bw %d, rx_bw %d, prio_tc %d\n", + __func__, i, ets.tc_tx_bw[i], ets.tc_rx_bw[i], + ets.prio_tc[i]); } err = mlx5e_dbcnl_validate_ets(netdev, &ets, true); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 1f5a2110d31f..27861b68ced5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -1689,16 +1689,6 @@ static int mlx5e_set_fecparam(struct net_device *netdev, return 0; } -static u32 mlx5e_get_msglevel(struct net_device *dev) -{ - return ((struct mlx5e_priv *)netdev_priv(dev))->msglevel; -} - -static void mlx5e_set_msglevel(struct net_device *dev, u32 val) -{ - ((struct mlx5e_priv *)netdev_priv(dev))->msglevel = val; -} - static int mlx5e_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) { @@ -1952,9 +1942,9 @@ int mlx5e_modify_rx_cqe_compression_locked(struct mlx5e_priv *priv, bool new_val if (err) return err; - mlx5e_dbg(DRV, priv, "MLX5E: RxCqeCmprss was turned %s\n", - MLX5E_GET_PFLAG(&priv->channels.params, - MLX5E_PFLAG_RX_CQE_COMPRESS) ? "ON" : "OFF"); + netdev_dbg(priv->netdev, "MLX5E: RxCqeCmprss was turned %s\n", + MLX5E_GET_PFLAG(&priv->channels.params, + MLX5E_PFLAG_RX_CQE_COMPRESS) ? "ON" : "OFF"); return 0; } @@ -2444,8 +2434,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = { .get_priv_flags = mlx5e_get_priv_flags, .set_priv_flags = mlx5e_set_priv_flags, .self_test = mlx5e_self_test, - .get_msglevel = mlx5e_get_msglevel, - .set_msglevel = mlx5e_set_msglevel, .get_fec_stats = mlx5e_get_fec_stats, .get_fecparam = mlx5e_get_fecparam, .set_fecparam = mlx5e_set_fecparam, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index a7c526ee5024..c564ac86ff8a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2401,7 +2401,7 @@ static int mlx5e_channel_stats_alloc(struct mlx5e_priv *priv, int ix, int cpu) /* Asymmetric dynamic memory allocation. * Freed in mlx5e_priv_arrays_free, not on channel closure. */ - mlx5e_dbg(DRV, priv, "Creating channel stats %d\n", ix); + netdev_dbg(priv->netdev, "Creating channel stats %d\n", ix); priv->channel_stats[ix] = kvzalloc_node(sizeof(**priv->channel_stats), GFP_KERNEL, cpu_to_node(cpu)); if (!priv->channel_stats[ix]) @@ -2779,7 +2779,7 @@ int mlx5e_update_tx_netdev_queues(struct mlx5e_priv *priv) if (MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_TX_PORT_TS)) num_txqs += ntc; - mlx5e_dbg(DRV, priv, "Setting num_txqs %d\n", num_txqs); + netdev_dbg(priv->netdev, "Setting num_txqs %d\n", num_txqs); err = netif_set_real_num_tx_queues(priv->netdev, num_txqs); if (err) netdev_warn(priv->netdev, "netif_set_real_num_tx_queues failed, %d\n", err); @@ -5585,7 +5585,6 @@ int mlx5e_priv_init(struct mlx5e_priv *priv, /* priv init */ priv->mdev = mdev; priv->netdev = netdev; - priv->msglevel = MLX5E_MSG_LEVEL; priv->max_nch = nch; priv->max_opened_tc = 1; -- cgit v1.2.3 From 0bd2e6fc78fddf83b9a71a61bdf0c4caca83abe7 Mon Sep 17 00:00:00 2001 From: Or Har-Toov Date: Thu, 23 Mar 2023 17:52:03 +0200 Subject: net/mlx5: Expose bits for local loopback counter Add needed HW bits for querying local loopback counter and the HCA capability for it. Signed-off-by: Or Har-Toov Reviewed-by: Avihai Horon Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- include/linux/mlx5/mlx5_ifc.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index d61dcb5d7cd5..354c7e326eab 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1758,7 +1758,7 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 reserved_at_330[0x6]; u8 pci_sync_for_fw_update_with_driver_unload[0x1]; u8 vnic_env_cnt_steering_fail[0x1]; - u8 reserved_at_338[0x1]; + u8 vport_counter_local_loopback[0x1]; u8 q_counter_aggregation[0x1]; u8 q_counter_other_vport[0x1]; u8 log_max_xrcd[0x5]; @@ -5190,7 +5190,9 @@ struct mlx5_ifc_query_vport_counter_out_bits { struct mlx5_ifc_traffic_counter_bits transmitted_eth_multicast; - u8 reserved_at_680[0xa00]; + struct mlx5_ifc_traffic_counter_bits local_loopback; + + u8 reserved_at_700[0x980]; }; enum { -- cgit v1.2.3 From c8013a1f714f6d9f2d8d673177a824c6b9653218 Mon Sep 17 00:00:00 2001 From: Or Har-Toov Date: Thu, 23 Mar 2023 18:11:50 +0200 Subject: net/mlx5e: Add local loopback counter to vport stats Add counter for number of unicast, multicast and broadcast packets/ octets that were loopback. Signed-off-by: Or Har-Toov Reviewed-by: Avihai Horon Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/counters.rst | 10 ++++++++++ drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 23 +++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/counters.rst b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/counters.rst index 6b2d1fe74ecf..a395df9c2751 100644 --- a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/counters.rst +++ b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/counters.rst @@ -797,6 +797,16 @@ Counters on the NIC port that is connected to a eSwitch. RoCE/UD/RC traffic) [#accel]_. - Acceleration + * - `vport_loopback_packets` + - Unicast, multicast and broadcast packets that were loop-back (received + and transmitted), IB/Eth [#accel]_. + - Acceleration + + * - `vport_loopback_bytes` + - Unicast, multicast and broadcast bytes that were loop-back (received + and transmitted), IB/Eth [#accel]_. + - Acceleration + * - `rx_steer_missed_packets` - Number of packets that was received by the NIC, however was discarded because it did not match any flow in the NIC flow table. diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index f1d9596905c6..25a6c596300d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -748,11 +748,22 @@ static const struct counter_desc vport_stats_desc[] = { VPORT_COUNTER_OFF(transmitted_ib_multicast.octets) }, }; +static const struct counter_desc vport_loopback_stats_desc[] = { + { "vport_loopback_packets", + VPORT_COUNTER_OFF(local_loopback.packets) }, + { "vport_loopback_bytes", + VPORT_COUNTER_OFF(local_loopback.octets) }, +}; + #define NUM_VPORT_COUNTERS ARRAY_SIZE(vport_stats_desc) +#define NUM_VPORT_LOOPBACK_COUNTERS(dev) \ + (MLX5_CAP_GEN(dev, vport_counter_local_loopback) ? \ + ARRAY_SIZE(vport_loopback_stats_desc) : 0) static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(vport) { - return NUM_VPORT_COUNTERS; + return NUM_VPORT_COUNTERS + + NUM_VPORT_LOOPBACK_COUNTERS(priv->mdev); } static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(vport) @@ -761,6 +772,11 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(vport) for (i = 0; i < NUM_VPORT_COUNTERS; i++) strcpy(data + (idx++) * ETH_GSTRING_LEN, vport_stats_desc[i].format); + + for (i = 0; i < NUM_VPORT_LOOPBACK_COUNTERS(priv->mdev); i++) + strcpy(data + (idx++) * ETH_GSTRING_LEN, + vport_loopback_stats_desc[i].format); + return idx; } @@ -771,6 +787,11 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(vport) for (i = 0; i < NUM_VPORT_COUNTERS; i++) data[idx++] = MLX5E_READ_CTR64_BE(priv->stats.vport.query_vport_out, vport_stats_desc, i); + + for (i = 0; i < NUM_VPORT_LOOPBACK_COUNTERS(priv->mdev); i++) + data[idx++] = MLX5E_READ_CTR64_BE(priv->stats.vport.query_vport_out, + vport_loopback_stats_desc, i); + return idx; } -- cgit v1.2.3 From b3bd68925ebb20942d448405351cf43cac9676a7 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 13 Jun 2023 22:26:43 +0300 Subject: net/mlx5: Fix the macro for accessing EC VF vports The last value is not set correctly. This results in representors not being created for all EC VFs when the base value is higher than 0. Fixes: a7719b29a821 ("net/mlx5: Add management of EC VF vports") Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index bcbab06759c4..7064609f4998 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -668,6 +668,7 @@ void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw); index, \ vport, \ MLX5_CAP_GEN_2((esw->dev), ec_vf_vport_base), \ + MLX5_CAP_GEN_2((esw->dev), ec_vf_vport_base) +\ (last) - 1) struct mlx5_eswitch *mlx5_devlink_eswitch_get(struct devlink *devlink); -- cgit v1.2.3 From 8bbe544e03809514e441994b4b849fdbeadd0068 Mon Sep 17 00:00:00 2001 From: Daniel Jurgens Date: Tue, 13 Jun 2023 22:30:49 +0300 Subject: net/mlx5: DR, update query of HCA caps for EC VFs This change is needed to use EC VFs with metadata based steering. There was an assumption that vport was equal to function ID. That's not the case for EC VF functions. Adjust to function ID and set the ec_vf_function bit accordingly. Fixes: 9ac0b128248e ("net/mlx5: Update vport caps query/set for EC VFs") Signed-off-by: Daniel Jurgens Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 7 +++++++ drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c | 4 +++- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 6 ------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 60673f98de2b..c4be257c043d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -358,4 +358,11 @@ static inline bool mlx5_core_is_ec_vf_vport(const struct mlx5_core_dev *dev, u16 return (vport_num >= base_vport && vport_num < max_vport); } + +static inline int mlx5_vport_to_func_id(const struct mlx5_core_dev *dev, u16 vport, bool ec_vf_func) +{ + return ec_vf_func ? vport - mlx5_core_ec_vf_vport_base(dev) + : vport; +} + #endif /* __MLX5_CORE_H__ */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c index 1aa525e509f1..7491911ebcb5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c @@ -34,6 +34,7 @@ int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev, int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport, u16 vport_number, u16 *gvmi) { + bool ec_vf_func = other_vport ? mlx5_core_is_ec_vf_vport(mdev, vport_number) : false; u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {}; int out_size; void *out; @@ -46,7 +47,8 @@ int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport, MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP); MLX5_SET(query_hca_cap_in, in, other_function, other_vport); - MLX5_SET(query_hca_cap_in, in, function_id, vport_number); + MLX5_SET(query_hca_cap_in, in, function_id, mlx5_vport_to_func_id(mdev, vport_number, ec_vf_func)); + MLX5_SET(query_hca_cap_in, in, ec_vf_function, ec_vf_func); MLX5_SET(query_hca_cap_in, in, op_mod, MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 | HCA_CAP_OPMOD_GET_CUR); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 6d3984dd5b21..5a31fb47ffa5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -1161,12 +1161,6 @@ u64 mlx5_query_nic_system_image_guid(struct mlx5_core_dev *mdev) } EXPORT_SYMBOL_GPL(mlx5_query_nic_system_image_guid); -static int mlx5_vport_to_func_id(const struct mlx5_core_dev *dev, u16 vport, bool ec_vf_func) -{ - return ec_vf_func ? vport - mlx5_core_ec_vf_vport_base(dev) - : vport; -} - int mlx5_vport_get_other_func_cap(struct mlx5_core_dev *dev, u16 vport, void *out, u16 opmod) { -- cgit v1.2.3 From 2bd3b292955fe0a7eb2f768f36a767eddaedd6da Mon Sep 17 00:00:00 2001 From: Juhee Kang Date: Mon, 5 Jun 2023 16:51:36 +0900 Subject: net/mlx5: Add header file for events Separate the event API defined in the generic mlx5.h header into a dedicated header. And remove the TODO comment in commit 69c1280b1f3b ("net/mlx5: Device events, Use async events chain"). Signed-off-by: Juhee Kang Reviewed-by: Larysa Zaremba Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/events.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/health.c | 1 + drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c | 2 +- .../net/ethernet/mellanox/mlx5/core/lag/mpesw.c | 2 +- .../net/ethernet/mellanox/mlx5/core/lib/events.h | 40 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h | 34 ------------------ 7 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 drivers/net/ethernet/mellanox/mlx5/core/lib/events.h diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c index 25a6c596300d..4d77055abd4b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c @@ -30,7 +30,7 @@ * SOFTWARE. */ -#include "lib/mlx5.h" +#include "lib/events.h" #include "en.h" #include "en_accel/ktls.h" #include "en_accel/en_accel.h" diff --git a/drivers/net/ethernet/mellanox/mlx5/core/events.c b/drivers/net/ethernet/mellanox/mlx5/core/events.c index 718cf09c28ce..3ec892d51f57 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/events.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/events.c @@ -5,7 +5,7 @@ #include "mlx5_core.h" #include "lib/eq.h" -#include "lib/mlx5.h" +#include "lib/events.h" struct mlx5_event_nb { struct mlx5_nb nb; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 210100a4064a..187cb2c464f8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -39,6 +39,7 @@ #include "mlx5_core.h" #include "lib/eq.h" #include "lib/mlx5.h" +#include "lib/events.h" #include "lib/pci_vsc.h" #include "lib/tout.h" #include "diag/fw_tracer.h" diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c index 976caa8e6922..b1aa494c76ba 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mp.c @@ -7,7 +7,7 @@ #include "lag/mp.h" #include "mlx5_core.h" #include "eswitch.h" -#include "lib/mlx5.h" +#include "lib/events.h" static bool __mlx5_lag_is_multipath(struct mlx5_lag *ldev) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c index 0e869a76dfe4..4bf15391525c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c @@ -6,7 +6,7 @@ #include "lag/lag.h" #include "eswitch.h" #include "esw/acl/ofld.h" -#include "lib/mlx5.h" +#include "lib/events.h" static void mlx5_mpesw_metadata_cleanup(struct mlx5_lag *ldev) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/events.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/events.h new file mode 100644 index 000000000000..a0f7faea317b --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/events.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ +/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ + +#ifndef __LIB_EVENTS_H__ +#define __LIB_EVENTS_H__ + +#include "mlx5_core.h" + +#define PORT_MODULE_EVENT_MODULE_STATUS_MASK 0xF +#define PORT_MODULE_EVENT_ERROR_TYPE_MASK 0xF + +enum port_module_event_status_type { + MLX5_MODULE_STATUS_PLUGGED = 0x1, + MLX5_MODULE_STATUS_UNPLUGGED = 0x2, + MLX5_MODULE_STATUS_ERROR = 0x3, + MLX5_MODULE_STATUS_DISABLED = 0x4, + MLX5_MODULE_STATUS_NUM, +}; + +enum port_module_event_error_type { + MLX5_MODULE_EVENT_ERROR_POWER_BUDGET_EXCEEDED = 0x0, + MLX5_MODULE_EVENT_ERROR_LONG_RANGE_FOR_NON_MLNX = 0x1, + MLX5_MODULE_EVENT_ERROR_BUS_STUCK = 0x2, + MLX5_MODULE_EVENT_ERROR_NO_EEPROM_RETRY_TIMEOUT = 0x3, + MLX5_MODULE_EVENT_ERROR_ENFORCE_PART_NUMBER_LIST = 0x4, + MLX5_MODULE_EVENT_ERROR_UNKNOWN_IDENTIFIER = 0x5, + MLX5_MODULE_EVENT_ERROR_HIGH_TEMPERATURE = 0x6, + MLX5_MODULE_EVENT_ERROR_BAD_CABLE = 0x7, + MLX5_MODULE_EVENT_ERROR_PCIE_POWER_SLOT_EXCEEDED = 0xc, + MLX5_MODULE_EVENT_ERROR_NUM, +}; + +struct mlx5_pme_stats { + u64 status_counters[MLX5_MODULE_STATUS_NUM]; + u64 error_counters[MLX5_MODULE_EVENT_ERROR_NUM]; +}; + +void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats); +int mlx5_notifier_call_chain(struct mlx5_events *events, unsigned int event, void *data); +#endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h index ccf12f7db6f0..2b5826a785c4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h @@ -45,40 +45,6 @@ int mlx5_crdump_enable(struct mlx5_core_dev *dev); void mlx5_crdump_disable(struct mlx5_core_dev *dev); int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data); -/* TODO move to lib/events.h */ - -#define PORT_MODULE_EVENT_MODULE_STATUS_MASK 0xF -#define PORT_MODULE_EVENT_ERROR_TYPE_MASK 0xF - -enum port_module_event_status_type { - MLX5_MODULE_STATUS_PLUGGED = 0x1, - MLX5_MODULE_STATUS_UNPLUGGED = 0x2, - MLX5_MODULE_STATUS_ERROR = 0x3, - MLX5_MODULE_STATUS_DISABLED = 0x4, - MLX5_MODULE_STATUS_NUM, -}; - -enum port_module_event_error_type { - MLX5_MODULE_EVENT_ERROR_POWER_BUDGET_EXCEEDED = 0x0, - MLX5_MODULE_EVENT_ERROR_LONG_RANGE_FOR_NON_MLNX = 0x1, - MLX5_MODULE_EVENT_ERROR_BUS_STUCK = 0x2, - MLX5_MODULE_EVENT_ERROR_NO_EEPROM_RETRY_TIMEOUT = 0x3, - MLX5_MODULE_EVENT_ERROR_ENFORCE_PART_NUMBER_LIST = 0x4, - MLX5_MODULE_EVENT_ERROR_UNKNOWN_IDENTIFIER = 0x5, - MLX5_MODULE_EVENT_ERROR_HIGH_TEMPERATURE = 0x6, - MLX5_MODULE_EVENT_ERROR_BAD_CABLE = 0x7, - MLX5_MODULE_EVENT_ERROR_PCIE_POWER_SLOT_EXCEEDED = 0xc, - MLX5_MODULE_EVENT_ERROR_NUM, -}; - -struct mlx5_pme_stats { - u64 status_counters[MLX5_MODULE_STATUS_NUM]; - u64 error_counters[MLX5_MODULE_EVENT_ERROR_NUM]; -}; - -void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats); -int mlx5_notifier_call_chain(struct mlx5_events *events, unsigned int event, void *data); - static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev) { return devlink_net(priv_to_devlink(dev)); -- cgit v1.2.3 From 5f2cf757f9c56255470c23a2a4a5574a34edad4b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 2 Jun 2023 15:34:00 +0200 Subject: net/mlx5: Remove unused ecpu field from struct mlx5_sf_table "ecpu" field in struct mlx5_sf_table is not used anywhere. Remove it. Signed-off-by: Jiri Pirko Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c index 9c02e5ea797c..6a3fa30b2bf2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c @@ -28,7 +28,6 @@ struct mlx5_sf_table { struct mutex sf_state_lock; /* Serializes sf state among user cmds & vhca event handler. */ struct notifier_block esw_nb; struct notifier_block vhca_nb; - u8 ecpu: 1; }; static struct mlx5_sf * -- cgit v1.2.3 From 9f8d0dc0ec4a4b5b78c0be83238c4511ff5f1ae0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 15 Jun 2023 12:32:02 +0100 Subject: kcm: Fix unnecessary psock unreservation. kcm_write_msgs() calls unreserve_psock() to release its hold on the underlying TCP socket if it has run out of things to transmit, but if we have nothing in the write queue on entry (e.g. because someone did a zero-length sendmsg), we don't actually go into the transmission loop and as a consequence don't call reserve_psock(). Fix this by skipping the call to unreserve_psock() if we didn't reserve a psock. Fixes: c31a25e1db48 ("kcm: Send multiple frags in one sendmsg()") Reported-by: syzbot+dd1339599f1840e4cc65@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000a61ffe05fe0c3d08@google.com/ Signed-off-by: David Howells Tested-by: syzbot+dd1339599f1840e4cc65@syzkaller.appspotmail.com cc: Tom Herbert cc: Tom Herbert cc: Jens Axboe cc: Matthew Wilcox Link: https://lore.kernel.org/r/20787.1686828722@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- net/kcm/kcmsock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index d75d775e9462..d0537c1c8cd7 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -661,6 +661,7 @@ retry: kcm_abort_tx_psock(psock, ret ? -ret : EPIPE, true); unreserve_psock(kcm); + psock = NULL; txm->started_tx = false; kcm_report_tx_retry(kcm); @@ -696,7 +697,8 @@ out: if (!head) { /* Done with all queued messages. */ WARN_ON(!skb_queue_empty(&sk->sk_write_queue)); - unreserve_psock(kcm); + if (psock) + unreserve_psock(kcm); } /* Check if write space is available */ -- cgit v1.2.3 From e16ad981e2a1e4a9afd1ce0d7a47cd9d8f09feda Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Jun 2023 20:48:10 +0800 Subject: net: sched: Remove unused qdisc_l2t() This is unused since switch to psched_l2t_ns(). Signed-off-by: YueHaibing Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230615124810.34020-1-yuehaibing@huawei.com Signed-off-by: Jakub Kicinski --- include/net/sch_generic.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 12eadecf8cd0..e92f73bb3198 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -1190,20 +1190,6 @@ static inline int qdisc_drop_all(struct sk_buff *skb, struct Qdisc *sch, return NET_XMIT_DROP; } -/* Length to Time (L2T) lookup in a qdisc_rate_table, to determine how - long it will take to send a packet given its size. - */ -static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen) -{ - int slot = pktlen + rtab->rate.cell_align + rtab->rate.overhead; - if (slot < 0) - slot = 0; - slot >>= rtab->rate.cell_log; - if (slot > 255) - return rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF]; - return rtab->data[slot]; -} - struct psched_ratecfg { u64 rate_bytes_ps; /* bytes per second */ u32 mult; -- cgit v1.2.3 From 6907217a8054b8afc47b3944afc7d77ad5caf824 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Thu, 15 Jun 2023 16:14:05 +0100 Subject: netlink: specs: fixup openvswitch specs for code generation Refine the ovs_* specs to align exactly with the ovs netlink UAPI definitions to enable code generation. Signed-off-by: Donald Hunter Link: https://lore.kernel.org/r/20230615151405.77649-1-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/ovs_datapath.yaml | 30 ++++++++---- Documentation/netlink/specs/ovs_flow.yaml | 68 ++++++++++++++++++++++----- Documentation/netlink/specs/ovs_vport.yaml | 13 ++++- 3 files changed, 87 insertions(+), 24 deletions(-) diff --git a/Documentation/netlink/specs/ovs_datapath.yaml b/Documentation/netlink/specs/ovs_datapath.yaml index 6d71db8c4416..f709c26c3e92 100644 --- a/Documentation/netlink/specs/ovs_datapath.yaml +++ b/Documentation/netlink/specs/ovs_datapath.yaml @@ -3,6 +3,7 @@ name: ovs_datapath version: 2 protocol: genetlink-legacy +uapi-header: linux/openvswitch.h doc: OVS datapath configuration over generic netlink. @@ -18,6 +19,7 @@ definitions: - name: user-features type: flags + name-prefix: ovs-dp-f- entries: - name: unaligned @@ -33,35 +35,37 @@ definitions: doc: Allow per-cpu dispatch of upcalls - name: datapath-stats + enum-name: ovs-dp-stats type: struct members: - - name: hit + name: n-hit type: u64 - - name: missed + name: n-missed type: u64 - - name: lost + name: n-lost type: u64 - - name: flows + name: n-flows type: u64 - name: megaflow-stats + enum-name: ovs-dp-megaflow-stats type: struct members: - - name: mask-hit + name: n-mask-hit type: u64 - - name: masks + name: n-masks type: u32 - name: padding type: u32 - - name: cache-hits + name: n-cache-hit type: u64 - name: pad1 @@ -70,6 +74,8 @@ definitions: attribute-sets: - name: datapath + name-prefix: ovs-dp-attr- + enum-name: ovs-datapath-attrs attributes: - name: name @@ -101,12 +107,16 @@ attribute-sets: name: per-cpu-pids type: binary sub-type: u32 + - + name: ifindex + type: u32 operations: fixed-header: ovs-header + name-prefix: ovs-dp-cmd- list: - - name: dp-get + name: get doc: Get / dump OVS data path configuration and state value: 3 attribute-set: datapath @@ -125,7 +135,7 @@ operations: - per-cpu-pids dump: *dp-get-op - - name: dp-new + name: new doc: Create new OVS data path value: 1 attribute-set: datapath @@ -137,7 +147,7 @@ operations: - upcall-pid - user-features - - name: dp-del + name: del doc: Delete existing OVS data path value: 2 attribute-set: datapath diff --git a/Documentation/netlink/specs/ovs_flow.yaml b/Documentation/netlink/specs/ovs_flow.yaml index 3b0624c87074..1ecbcd117385 100644 --- a/Documentation/netlink/specs/ovs_flow.yaml +++ b/Documentation/netlink/specs/ovs_flow.yaml @@ -3,6 +3,7 @@ name: ovs_flow version: 1 protocol: genetlink-legacy +uapi-header: linux/openvswitch.h doc: OVS flow configuration over generic netlink. @@ -67,6 +68,7 @@ definitions: enum: ovs-frag-type - name: ovs-frag-type + name-prefix: ovs-frag-type- type: enum entries: - @@ -166,6 +168,7 @@ definitions: doc: Tag control identifier (TCI) to push. - name: ovs-ufid-flags + name-prefix: ovs-ufid-f- type: flags entries: - omit-key @@ -176,7 +179,7 @@ definitions: type: struct members: - - name: hash-algorithm + name: hash-alg type: u32 doc: Algorithm used to compute hash prior to recirculation. - @@ -198,13 +201,13 @@ definitions: type: struct members: - - name: lse + name: mpls-lse type: u32 byte-order: big-endian doc: | MPLS label stack entry to push - - name: ethertype + name: mpls-ethertype type: u32 byte-order: big-endian doc: | @@ -216,13 +219,13 @@ definitions: type: struct members: - - name: lse + name: mpls-lse type: u32 byte-order: big-endian doc: | MPLS label stack entry to push - - name: ethertype + name: mpls-ethertype type: u32 byte-order: big-endian doc: | @@ -237,6 +240,7 @@ definitions: - name: ct-state-flags type: flags + name-prefix: ovs-cs-f- entries: - name: new @@ -266,6 +270,8 @@ definitions: attribute-sets: - name: flow-attrs + enum-name: ovs-flow-attr + name-prefix: ovs-flow-attr- attributes: - name: key @@ -352,6 +358,8 @@ attribute-sets: - name: key-attrs + enum-name: ovs-key-attr + name-prefix: ovs-key-attr- attributes: - name: encap @@ -481,6 +489,8 @@ attribute-sets: doc: struct ovs_key_ipv6_exthdr - name: action-attrs + enum-name: ovs-action-attr + name-prefix: ovs-action-attr- attributes: - name: output @@ -608,6 +618,8 @@ attribute-sets: nested-attributes: dec-ttl-attrs - name: tunnel-key-attrs + enum-name: ovs-tunnel-key-attr + name-prefix: ovs-tunnel-key-attr- attributes: - name: id @@ -676,6 +688,8 @@ attribute-sets: type: flag - name: check-pkt-len-attrs + enum-name: ovs-check-pkt-len-attr + name-prefix: ovs-check-pkt-len-attr- attributes: - name: pkt-len @@ -690,6 +704,8 @@ attribute-sets: nested-attributes: action-attrs - name: sample-attrs + enum-name: ovs-sample-attr + name-prefix: ovs-sample-attr- attributes: - name: probability @@ -700,6 +716,8 @@ attribute-sets: nested-attributes: action-attrs - name: userspace-attrs + enum-name: ovs-userspace-attr + name-prefix: ovs-userspace-attr- attributes: - name: pid @@ -715,6 +733,8 @@ attribute-sets: type: flag - name: ovs-nsh-key-attrs + enum-name: ovs-nsh-key-attr + name-prefix: ovs-nsh-key-attr- attributes: - name: base @@ -727,6 +747,8 @@ attribute-sets: type: binary - name: ct-attrs + enum-name: ovs-ct-attr + name-prefix: ovs-ct-attr- attributes: - name: commit @@ -758,13 +780,15 @@ attribute-sets: type: string - name: nat-attrs + enum-name: ovs-nat-attr + name-prefix: ovs-nat-attr- attributes: - name: src - type: binary + type: flag - name: dst - type: binary + type: flag - name: ip-min type: binary @@ -773,21 +797,23 @@ attribute-sets: type: binary - name: proto-min - type: binary + type: u16 - name: proto-max - type: binary + type: u16 - name: persistent - type: binary + type: flag - name: proto-hash - type: binary + type: flag - name: proto-random - type: binary + type: flag - name: dec-ttl-attrs + enum-name: ovs-dec-ttl-attr + name-prefix: ovs-dec-ttl-attr- attributes: - name: action @@ -795,16 +821,19 @@ attribute-sets: nested-attributes: action-attrs - name: vxlan-ext-attrs + enum-name: ovs-vxlan-ext- + name-prefix: ovs-vxlan-ext- attributes: - name: gbp type: u32 operations: + name-prefix: ovs-flow-cmd- fixed-header: ovs-header list: - - name: flow-get + name: get doc: Get / dump OVS flow configuration and state value: 3 attribute-set: flow-attrs @@ -824,6 +853,19 @@ operations: - stats - actions dump: *flow-get-op + - + name: new + doc: Create OVS flow configuration in a data path + value: 1 + attribute-set: flow-attrs + do: + request: + attributes: + - dp-ifindex + - key + - ufid + - mask + - actions mcast-groups: list: diff --git a/Documentation/netlink/specs/ovs_vport.yaml b/Documentation/netlink/specs/ovs_vport.yaml index 8e55622ddf11..17336455bec1 100644 --- a/Documentation/netlink/specs/ovs_vport.yaml +++ b/Documentation/netlink/specs/ovs_vport.yaml @@ -3,6 +3,7 @@ name: ovs_vport version: 2 protocol: genetlink-legacy +uapi-header: linux/openvswitch.h doc: OVS vport configuration over generic netlink. @@ -18,10 +19,13 @@ definitions: - name: vport-type type: enum + enum-name: ovs-vport-type + name-prefix: ovs-vport-type- entries: [ unspec, netdev, internal, gre, vxlan, geneve ] - name: vport-stats type: struct + enum-name: ovs-vport-stats members: - name: rx-packets @@ -51,6 +55,8 @@ definitions: attribute-sets: - name: vport-options + enum-name: ovs-vport-options + name-prefix: ovs-tunnel-attr- attributes: - name: dst-port @@ -60,6 +66,8 @@ attribute-sets: type: u32 - name: upcall-stats + enum-name: ovs-vport-upcall-attr + name-prefix: ovs-vport-upcall-attr- attributes: - name: success @@ -70,6 +78,8 @@ attribute-sets: type: u64 - name: vport + name-prefix: ovs-vport-attr- + enum-name: ovs-vport-attr attributes: - name: port-no @@ -108,9 +118,10 @@ attribute-sets: nested-attributes: upcall-stats operations: + name-prefix: ovs-vport-cmd- list: - - name: vport-get + name: get doc: Get / dump OVS vport configuration and state value: 3 attribute-set: vport -- cgit v1.2.3 From f60ce8a48b97eb970bfbec1f26c914b9017c4a46 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Thu, 15 Jun 2023 23:22:40 +0800 Subject: net: mctp: remove redundant RTN_UNICAST check Current mctp_newroute() contains two exactly same check against rtm->rtm_type static int mctp_newroute(...) { ... if (rtm->rtm_type != RTN_UNICAST) { // (1) NL_SET_ERR_MSG(extack, "rtm_type must be RTN_UNICAST"); return -EINVAL; } ... if (rtm->rtm_type != RTN_UNICAST) // (2) return -EINVAL; ... } This commits removes the (2) check as it is redundant. Signed-off-by: Lin Ma Reviewed-by: Pavan Chebbi Acked-by: Jeremy Kerr Link: https://lore.kernel.org/r/20230615152240.1749428-1-linma@zju.edu.cn Signed-off-by: Jakub Kicinski --- net/mctp/route.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mctp/route.c b/net/mctp/route.c index f51a05ec7162..ab62fe447038 100644 --- a/net/mctp/route.c +++ b/net/mctp/route.c @@ -1249,9 +1249,6 @@ static int mctp_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, mtu = nla_get_u32(tbx[RTAX_MTU]); } - if (rtm->rtm_type != RTN_UNICAST) - return -EINVAL; - rc = mctp_route_add(mdev, daddr_start, rtm->rtm_dst_len, mtu, rtm->rtm_type); return rc; -- cgit v1.2.3 From a52305a81d6bb74b90b400dfa56455d37872fe4b Mon Sep 17 00:00:00 2001 From: Petr Oros Date: Thu, 15 Jun 2023 11:54:47 +0200 Subject: devlink: report devlink_port_type_warn source device devlink_port_type_warn is scheduled for port devlink and warning when the port type is not set. But from this warning it is not easy found out which device (driver) has no devlink port set. [ 3709.975552] Type was not set for devlink port. [ 3709.975579] WARNING: CPU: 1 PID: 13092 at net/devlink/leftover.c:6775 devlink_port_type_warn+0x11/0x20 [ 3709.993967] Modules linked in: openvswitch nf_conncount nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nfnetlink bluetooth rpcsec_gss_krb5 auth_rpcgss nfsv4 dns_resolver nfs lockd grace fscache netfs vhost_net vhost vhost_iotlb tap tun bridge stp llc qrtr intel_rapl_msr intel_rapl_common i10nm_edac nfit libnvdimm x86_pkg_temp_thermal mlx5_ib intel_powerclamp coretemp dell_wmi ledtrig_audio sparse_keymap ipmi_ssif kvm_intel ib_uverbs rfkill ib_core video kvm iTCO_wdt acpi_ipmi intel_vsec irqbypass ipmi_si iTCO_vendor_support dcdbas ipmi_devintf mei_me ipmi_msghandler rapl mei intel_cstate isst_if_mmio isst_if_mbox_pci dell_smbios intel_uncore isst_if_common i2c_i801 dell_wmi_descriptor wmi_bmof i2c_smbus intel_pch_thermal pcspkr acpi_power_meter xfs libcrc32c sd_mod sg nvme_tcp mgag200 i2c_algo_bit nvme_fabrics drm_shmem_helper drm_kms_helper nvme syscopyarea ahci sysfillrect sysimgblt nvme_core fb_sys_fops crct10dif_pclmul libahci mlx5_core sfc crc32_pclmul nvme_common drm [ 3709.994030] crc32c_intel mtd t10_pi mlxfw libata tg3 mdio megaraid_sas psample ghash_clmulni_intel pci_hyperv_intf wmi dm_multipath sunrpc dm_mirror dm_region_hash dm_log dm_mod be2iscsi bnx2i cnic uio cxgb4i cxgb4 tls libcxgbi libcxgb qla4xxx iscsi_boot_sysfs iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi fuse [ 3710.108431] CPU: 1 PID: 13092 Comm: kworker/1:1 Kdump: loaded Not tainted 5.14.0-319.el9.x86_64 #1 [ 3710.108435] Hardware name: Dell Inc. PowerEdge R750/0PJ80M, BIOS 1.8.2 09/14/2022 [ 3710.108437] Workqueue: events devlink_port_type_warn [ 3710.108440] RIP: 0010:devlink_port_type_warn+0x11/0x20 [ 3710.108443] Code: 84 76 fe ff ff 48 c7 03 20 0e 1a ad 31 c0 e9 96 fd ff ff 66 0f 1f 44 00 00 0f 1f 44 00 00 48 c7 c7 18 24 4e ad e8 ef 71 62 ff <0f> 0b c3 cc cc cc cc 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 f6 87 [ 3710.108445] RSP: 0018:ff3b6d2e8b3c7e90 EFLAGS: 00010282 [ 3710.108447] RAX: 0000000000000000 RBX: ff366d6580127080 RCX: 0000000000000027 [ 3710.108448] RDX: 0000000000000027 RSI: 00000000ffff86de RDI: ff366d753f41f8c8 [ 3710.108449] RBP: ff366d658ff5a0c0 R08: ff366d753f41f8c0 R09: ff3b6d2e8b3c7e18 [ 3710.108450] R10: 0000000000000001 R11: 0000000000000023 R12: ff366d753f430600 [ 3710.108451] R13: ff366d753f436900 R14: 0000000000000000 R15: ff366d753f436905 [ 3710.108452] FS: 0000000000000000(0000) GS:ff366d753f400000(0000) knlGS:0000000000000000 [ 3710.108453] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3710.108454] CR2: 00007f1c57bc74e0 CR3: 000000111d26a001 CR4: 0000000000773ee0 [ 3710.108456] PKRU: 55555554 [ 3710.108457] Call Trace: [ 3710.108458] [ 3710.108459] process_one_work+0x1e2/0x3b0 [ 3710.108466] ? rescuer_thread+0x390/0x390 [ 3710.108468] worker_thread+0x50/0x3a0 [ 3710.108471] ? rescuer_thread+0x390/0x390 [ 3710.108473] kthread+0xdd/0x100 [ 3710.108477] ? kthread_complete_and_exit+0x20/0x20 [ 3710.108479] ret_from_fork+0x1f/0x30 [ 3710.108485] [ 3710.108486] ---[ end trace 1b4b23cd0c65d6a0 ]--- After patch: [ 402.473064] ice 0000:41:00.0: Type was not set for devlink port. [ 402.473064] ice 0000:41:00.1: Type was not set for devlink port. Signed-off-by: Petr Oros Reviewed-by: Pavan Chebbi Reviewed-by: Jakub Kicinski Link: https://lore.kernel.org/r/20230615095447.8259-1-poros@redhat.com Signed-off-by: Jakub Kicinski --- net/devlink/leftover.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/devlink/leftover.c b/net/devlink/leftover.c index 649a9701eb6a..1f00f874471f 100644 --- a/net/devlink/leftover.c +++ b/net/devlink/leftover.c @@ -6737,7 +6737,10 @@ void devlink_notify_unregister(struct devlink *devlink) static void devlink_port_type_warn(struct work_struct *work) { - WARN(true, "Type was not set for devlink port."); + struct devlink_port *port = container_of(to_delayed_work(work), + struct devlink_port, + type_warn_dw); + dev_warn(port->devlink->dev, "Type was not set for devlink port."); } static bool devlink_port_type_should_warn(struct devlink_port *devlink_port) -- cgit v1.2.3 From b650d953cd391595e536153ce30b4aab385643ac Mon Sep 17 00:00:00 2001 From: "mfreemon@cloudflare.com" Date: Sun, 11 Jun 2023 22:05:24 -0500 Subject: tcp: enforce receive buffer memory limits by allowing the tcp window to shrink Under certain circumstances, the tcp receive buffer memory limit set by autotuning (sk_rcvbuf) is increased due to incoming data packets as a result of the window not closing when it should be. This can result in the receive buffer growing all the way up to tcp_rmem[2], even for tcp sessions with a low BDP. To reproduce: Connect a TCP session with the receiver doing nothing and the sender sending small packets (an infinite loop of socket send() with 4 bytes of payload with a sleep of 1 ms in between each send()). This will cause the tcp receive buffer to grow all the way up to tcp_rmem[2]. As a result, a host can have individual tcp sessions with receive buffers of size tcp_rmem[2], and the host itself can reach tcp_mem limits, causing the host to go into tcp memory pressure mode. The fundamental issue is the relationship between the granularity of the window scaling factor and the number of byte ACKed back to the sender. This problem has previously been identified in RFC 7323, appendix F [1]. The Linux kernel currently adheres to never shrinking the window. In addition to the overallocation of memory mentioned above, the current behavior is functionally incorrect, because once tcp_rmem[2] is reached when no remediations remain (i.e. tcp collapse fails to free up any more memory and there are no packets to prune from the out-of-order queue), the receiver will drop in-window packets resulting in retransmissions and an eventual timeout of the tcp session. A receive buffer full condition should instead result in a zero window and an indefinite wait. In practice, this problem is largely hidden for most flows. It is not applicable to mice flows. Elephant flows can send data fast enough to "overrun" the sk_rcvbuf limit (in a single ACK), triggering a zero window. But this problem does show up for other types of flows. Examples are websockets and other type of flows that send small amounts of data spaced apart slightly in time. In these cases, we directly encounter the problem described in [1]. RFC 7323, section 2.4 [2], says there are instances when a retracted window can be offered, and that TCP implementations MUST ensure that they handle a shrinking window, as specified in RFC 1122, section 4.2.2.16 [3]. All prior RFCs on the topic of tcp window management have made clear that sender must accept a shrunk window from the receiver, including RFC 793 [4] and RFC 1323 [5]. This patch implements the functionality to shrink the tcp window when necessary to keep the right edge within the memory limit by autotuning (sk_rcvbuf). This new functionality is enabled with the new sysctl: net.ipv4.tcp_shrink_window Additional information can be found at: https://blog.cloudflare.com/unbounded-memory-usage-by-tcp-for-receive-buffers-and-how-we-fixed-it/ [1] https://www.rfc-editor.org/rfc/rfc7323#appendix-F [2] https://www.rfc-editor.org/rfc/rfc7323#section-2.4 [3] https://www.rfc-editor.org/rfc/rfc1122#page-91 [4] https://www.rfc-editor.org/rfc/rfc793 [5] https://www.rfc-editor.org/rfc/rfc1323 Signed-off-by: Mike Freemon Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.rst | 15 +++++++++ include/net/netns/ipv4.h | 1 + net/ipv4/sysctl_net_ipv4.c | 9 +++++ net/ipv4/tcp_ipv4.c | 2 ++ net/ipv4/tcp_output.c | 60 +++++++++++++++++++++++++++++----- 5 files changed, 78 insertions(+), 9 deletions(-) diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 366e2a5097d9..4a010a7cde7f 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -981,6 +981,21 @@ tcp_tw_reuse - INTEGER tcp_window_scaling - BOOLEAN Enable window scaling as defined in RFC1323. +tcp_shrink_window - BOOLEAN + This changes how the TCP receive window is calculated. + + RFC 7323, section 2.4, says there are instances when a retracted + window can be offered, and that TCP implementations MUST ensure + that they handle a shrinking window, as specified in RFC 1122. + + - 0 - Disabled. The window is never shrunk. + - 1 - Enabled. The window is shrunk when necessary to remain within + the memory limit set by autotuning (sk_rcvbuf). + This only occurs if a non-zero receive window + scaling factor is also in effect. + + Default: 0 + tcp_wmem - vector of 3 INTEGERs: min, default, max min: Amount of memory reserved for send buffers for TCP sockets. Each TCP socket has rights to use it due to fact of its birth. diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index a4efb7a2796c..f00374718159 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -65,6 +65,7 @@ struct netns_ipv4 { #endif bool fib_has_custom_local_routes; bool fib_offload_disabled; + u8 sysctl_tcp_shrink_window; #ifdef CONFIG_IP_ROUTE_CLASSID atomic_t fib_num_tclassid_users; #endif diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 356afe54951c..2afb0870648b 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -1480,6 +1480,15 @@ static struct ctl_table ipv4_net_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = &tcp_syn_linear_timeouts_max, }, + { + .procname = "tcp_shrink_window", + .data = &init_net.ipv4.sysctl_tcp_shrink_window, + .maxlen = sizeof(u8), + .mode = 0644, + .proc_handler = proc_dou8vec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, { } }; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 84a5d557dc1a..9213804b034f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3281,6 +3281,8 @@ static int __net_init tcp_sk_init(struct net *net) net->ipv4.tcp_congestion_control = &tcp_reno; net->ipv4.sysctl_tcp_syn_linear_timeouts = 4; + net->ipv4.sysctl_tcp_shrink_window = 0; + return 0; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 660eac4bf2a7..2cb39b6dad02 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -260,8 +260,8 @@ static u16 tcp_select_window(struct sock *sk) u32 old_win = tp->rcv_wnd; u32 cur_win = tcp_receive_window(tp); u32 new_win = __tcp_select_window(sk); + struct net *net = sock_net(sk); - /* Never shrink the offered window */ if (new_win < cur_win) { /* Danger Will Robinson! * Don't update rcv_wup/rcv_wnd here or else @@ -270,11 +270,14 @@ static u16 tcp_select_window(struct sock *sk) * * Relax Will Robinson. */ - if (new_win == 0) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPWANTZEROWINDOWADV); - new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale); + if (!READ_ONCE(net->ipv4.sysctl_tcp_shrink_window) || !tp->rx_opt.rcv_wscale) { + /* Never shrink the offered window */ + if (new_win == 0) + NET_INC_STATS(net, LINUX_MIB_TCPWANTZEROWINDOWADV); + new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale); + } } + tp->rcv_wnd = new_win; tp->rcv_wup = tp->rcv_nxt; @@ -282,7 +285,7 @@ static u16 tcp_select_window(struct sock *sk) * scaled window. */ if (!tp->rx_opt.rcv_wscale && - READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_workaround_signed_windows)) + READ_ONCE(net->ipv4.sysctl_tcp_workaround_signed_windows)) new_win = min(new_win, MAX_TCP_WINDOW); else new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale)); @@ -294,10 +297,9 @@ static u16 tcp_select_window(struct sock *sk) if (new_win == 0) { tp->pred_flags = 0; if (old_win) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPTOZEROWINDOWADV); + NET_INC_STATS(net, LINUX_MIB_TCPTOZEROWINDOWADV); } else if (old_win == 0) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFROMZEROWINDOWADV); + NET_INC_STATS(net, LINUX_MIB_TCPFROMZEROWINDOWADV); } return new_win; @@ -2987,6 +2989,7 @@ u32 __tcp_select_window(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); + struct net *net = sock_net(sk); /* MSS for the peer's data. Previous versions used mss_clamp * here. I don't know if the value based on our guesses * of peer's MSS is better for the performance. It's more correct @@ -3008,6 +3011,15 @@ u32 __tcp_select_window(struct sock *sk) if (mss <= 0) return 0; } + + /* Only allow window shrink if the sysctl is enabled and we have + * a non-zero scaling factor in effect. + */ + if (READ_ONCE(net->ipv4.sysctl_tcp_shrink_window) && tp->rx_opt.rcv_wscale) + goto shrink_window_allowed; + + /* do not allow window to shrink */ + if (free_space < (full_space >> 1)) { icsk->icsk_ack.quick = 0; @@ -3062,6 +3074,36 @@ u32 __tcp_select_window(struct sock *sk) } return window; + +shrink_window_allowed: + /* new window should always be an exact multiple of scaling factor */ + free_space = round_down(free_space, 1 << tp->rx_opt.rcv_wscale); + + if (free_space < (full_space >> 1)) { + icsk->icsk_ack.quick = 0; + + if (tcp_under_memory_pressure(sk)) + tcp_adjust_rcv_ssthresh(sk); + + /* if free space is too low, return a zero window */ + if (free_space < (allowed_space >> 4) || free_space < mss || + free_space < (1 << tp->rx_opt.rcv_wscale)) + return 0; + } + + if (free_space > tp->rcv_ssthresh) { + free_space = tp->rcv_ssthresh; + /* new window should always be an exact multiple of scaling factor + * + * For this case, we ALIGN "up" (increase free_space) because + * we know free_space is not zero here, it has been reduced from + * the memory-based limit, and rcv_ssthresh is not a hard limit + * (unlike sk_rcvbuf). + */ + free_space = ALIGN(free_space, (1 << tp->rx_opt.rcv_wscale)); + } + + return free_space; } void tcp_skb_collapse_tstamp(struct sk_buff *skb, -- cgit v1.2.3 From 7a7f094635349a7d0314364ad50bdeb770b6df4f Mon Sep 17 00:00:00 2001 From: Arjun Roy Date: Fri, 16 Jun 2023 12:34:27 -0700 Subject: tcp: Use per-vma locking for receive zerocopy Per-VMA locking allows us to lock a struct vm_area_struct without taking the process-wide mmap lock in read mode. Consider a process workload where the mmap lock is taken constantly in write mode. In this scenario, all zerocopy receives are periodically blocked during that period of time - though in principle, the memory ranges being used by TCP are not touched by the operations that need the mmap write lock. This results in performance degradation. Now consider another workload where the mmap lock is never taken in write mode, but there are many TCP connections using receive zerocopy that are concurrently receiving. These connections all take the mmap lock in read mode, but this does induce a lot of contention and atomic ops for this process-wide lock. This results in additional CPU overhead caused by contending on the cache line for this lock. However, with per-vma locking, both of these problems can be avoided. As a test, I ran an RPC-style request/response workload with 4KB payloads and receive zerocopy enabled, with 100 simultaneous TCP connections. I measured perf cycles within the find_tcp_vma/mmap_read_lock/mmap_read_unlock codepath, with and without per-vma locking enabled. When using process-wide mmap semaphore read locking, about 1% of measured perf cycles were within this path. With per-VMA locking, this value dropped to about 0.45%. Signed-off-by: Arjun Roy Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- MAINTAINERS | 1 + include/linux/net_mm.h | 17 +++++++++++++++++ include/net/tcp.h | 1 + mm/memory.c | 7 ++++--- net/ipv4/tcp.c | 45 +++++++++++++++++++++++++++++++++++++-------- 5 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 include/linux/net_mm.h diff --git a/MAINTAINERS b/MAINTAINERS index 7322963b0670..cb14589d14ab 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14743,6 +14743,7 @@ NETWORKING [TCP] M: Eric Dumazet L: netdev@vger.kernel.org S: Maintained +F: include/linux/net_mm.h F: include/linux/tcp.h F: include/net/tcp.h F: include/trace/events/tcp.h diff --git a/include/linux/net_mm.h b/include/linux/net_mm.h new file mode 100644 index 000000000000..b298998bd5a0 --- /dev/null +++ b/include/linux/net_mm.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifdef CONFIG_MMU + +#ifdef CONFIG_INET +extern const struct vm_operations_struct tcp_vm_ops; +static inline bool vma_is_tcp(const struct vm_area_struct *vma) +{ + return vma->vm_ops == &tcp_vm_ops; +} +#else +static inline bool vma_is_tcp(const struct vm_area_struct *vma) +{ + return false; +} +#endif /* CONFIG_INET*/ + +#endif /* CONFIG_MMU */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 9c08eab647a2..31b534370787 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -45,6 +45,7 @@ #include #include #include +#include extern struct inet_hashinfo tcp_hashinfo; diff --git a/mm/memory.c b/mm/memory.c index f69fbc251198..3e46b4d881dc 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -77,6 +77,7 @@ #include #include #include +#include #include @@ -5280,12 +5281,12 @@ retry: if (!vma) goto inval; - /* Only anonymous vmas are supported for now */ - if (!vma_is_anonymous(vma)) + /* Only anonymous and tcp vmas are supported for now */ + if (!vma_is_anonymous(vma) && !vma_is_tcp(vma)) goto inval; /* find_mergeable_anon_vma uses adjacent vmas which are not locked */ - if (!vma->anon_vma) + if (!vma->anon_vma && !vma_is_tcp(vma)) goto inval; if (!vma_start_read(vma)) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 0e21ea92dc1d..71b42eef9dbf 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1774,7 +1774,7 @@ void tcp_update_recv_tstamps(struct sk_buff *skb, } #ifdef CONFIG_MMU -static const struct vm_operations_struct tcp_vm_ops = { +const struct vm_operations_struct tcp_vm_ops = { }; int tcp_mmap(struct file *file, struct socket *sock, @@ -2073,6 +2073,34 @@ static void tcp_zc_finalize_rx_tstamp(struct sock *sk, } } +static struct vm_area_struct *find_tcp_vma(struct mm_struct *mm, + unsigned long address, + bool *mmap_locked) +{ + struct vm_area_struct *vma = NULL; + +#ifdef CONFIG_PER_VMA_LOCK + vma = lock_vma_under_rcu(mm, address); +#endif + if (vma) { + if (!vma_is_tcp(vma)) { + vma_end_read(vma); + return NULL; + } + *mmap_locked = false; + return vma; + } + + mmap_read_lock(mm); + vma = vma_lookup(mm, address); + if (!vma || !vma_is_tcp(vma)) { + mmap_read_unlock(mm); + return NULL; + } + *mmap_locked = true; + return vma; +} + #define TCP_ZEROCOPY_PAGE_BATCH_SIZE 32 static int tcp_zerocopy_receive(struct sock *sk, struct tcp_zerocopy_receive *zc, @@ -2090,6 +2118,7 @@ static int tcp_zerocopy_receive(struct sock *sk, u32 seq = tp->copied_seq; u32 total_bytes_to_map; int inq = tcp_inq(sk); + bool mmap_locked; int ret; zc->copybuf_len = 0; @@ -2114,13 +2143,10 @@ static int tcp_zerocopy_receive(struct sock *sk, return 0; } - mmap_read_lock(current->mm); - - vma = vma_lookup(current->mm, address); - if (!vma || vma->vm_ops != &tcp_vm_ops) { - mmap_read_unlock(current->mm); + vma = find_tcp_vma(current->mm, address, &mmap_locked); + if (!vma) return -EINVAL; - } + vma_len = min_t(unsigned long, zc->length, vma->vm_end - address); avail_len = min_t(u32, vma_len, inq); total_bytes_to_map = avail_len & ~(PAGE_SIZE - 1); @@ -2194,7 +2220,10 @@ static int tcp_zerocopy_receive(struct sock *sk, zc, total_bytes_to_map); } out: - mmap_read_unlock(current->mm); + if (mmap_locked) + mmap_read_unlock(current->mm); + else + vma_end_read(vma); /* Try to copy straggler data. */ if (!ret) copylen = tcp_zc_handle_leftover(zc, sk, skb, &seq, copybuf_len, tss); -- cgit v1.2.3 From 4380499218c6a1aa77e80e3bf6da107dd8babf62 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 15 Jun 2023 22:08:54 +0100 Subject: crypto: Fix af_alg_sendmsg(MSG_SPLICE_PAGES) sglist limit When af_alg_sendmsg() calls extract_iter_to_sg(), it passes MAX_SGL_ENTS as the maximum number of elements that may be written to, but some of the elements may already have been used (as recorded in sgl->cur), so extract_iter_to_sg() may end up overrunning the scatterlist. Fix this to limit the number of elements to "MAX_SGL_ENTS - sgl->cur". Note: It probably makes sense in future to alter the behaviour of extract_iter_to_sg() to stop if "sgtable->nents >= sg_max" instead, but this is a smaller fix for now. The bug causes errors looking something like: BUG: KASAN: slab-out-of-bounds in sg_assign_page include/linux/scatterlist.h:109 [inline] BUG: KASAN: slab-out-of-bounds in sg_set_page include/linux/scatterlist.h:139 [inline] BUG: KASAN: slab-out-of-bounds in extract_bvec_to_sg lib/scatterlist.c:1183 [inline] BUG: KASAN: slab-out-of-bounds in extract_iter_to_sg lib/scatterlist.c:1352 [inline] BUG: KASAN: slab-out-of-bounds in extract_iter_to_sg+0x17a6/0x1960 lib/scatterlist.c:1339 Fixes: bf63e250c4b1 ("crypto: af_alg: Support MSG_SPLICE_PAGES") Reported-by: syzbot+6efc50cc1f8d718d6cb7@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000b2585a05fdeb8379@google.com/ Signed-off-by: David Howells Tested-by: syzbot+6efc50cc1f8d718d6cb7@syzkaller.appspotmail.com cc: Herbert Xu cc: "David S. Miller" cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Jens Axboe cc: Matthew Wilcox cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org Acked-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/af_alg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 7d4b6016b83d..cdb1dcc5dd1a 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1043,7 +1043,7 @@ int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, }; plen = extract_iter_to_sg(&msg->msg_iter, len, &sgtable, - MAX_SGL_ENTS, 0); + MAX_SGL_ENTS - sgl->cur, 0); if (plen < 0) { err = plen; goto unlock; -- cgit v1.2.3 From 3515440df461359762d447b5068f148611bb4d42 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 16 Jun 2023 08:57:52 +0000 Subject: ipv6: also use netdev_hold() in ip6_route_check_nh() In blamed commit, we missed the fact that ip6_validate_gw() could change dev under us from ip6_route_check_nh() In this fix, I use GFP_ATOMIC in order to not pass too many additional arguments to ip6_validate_gw() and ip6_route_check_nh() only for a rarely used debug feature. syzbot reported: refcount_t: decrement hit 0; leaking memory. WARNING: CPU: 0 PID: 5006 at lib/refcount.c:31 refcount_warn_saturate+0x1d7/0x1f0 lib/refcount.c:31 Modules linked in: CPU: 0 PID: 5006 Comm: syz-executor403 Not tainted 6.4.0-rc5-syzkaller-01229-g97c5209b3d37 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/27/2023 RIP: 0010:refcount_warn_saturate+0x1d7/0x1f0 lib/refcount.c:31 Code: 05 fb 8e 51 0a 01 e8 98 95 38 fd 0f 0b e9 d3 fe ff ff e8 ac d9 70 fd 48 c7 c7 00 d3 a6 8a c6 05 d8 8e 51 0a 01 e8 79 95 38 fd <0f> 0b e9 b4 fe ff ff 48 89 ef e8 1a d7 c3 fd e9 5c fe ff ff 0f 1f RSP: 0018:ffffc900039df6b8 EFLAGS: 00010282 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 RDX: ffff888026d71dc0 RSI: ffffffff814c03b7 RDI: 0000000000000001 RBP: ffff888146a505fc R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000001 R11: 0000000000000001 R12: 1ffff9200073bedc R13: 00000000ffffffef R14: ffff888146a505fc R15: ffff8880284eb5a8 FS: 0000555556c88300(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000004585c0 CR3: 000000002b1b1000 CR4: 00000000003506f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: __refcount_dec include/linux/refcount.h:344 [inline] refcount_dec include/linux/refcount.h:359 [inline] ref_tracker_free+0x539/0x820 lib/ref_tracker.c:236 netdev_tracker_free include/linux/netdevice.h:4097 [inline] netdev_put include/linux/netdevice.h:4114 [inline] netdev_put include/linux/netdevice.h:4110 [inline] fib6_nh_init+0xb96/0x1bd0 net/ipv6/route.c:3624 ip6_route_info_create+0x10f3/0x1980 net/ipv6/route.c:3791 ip6_route_add+0x28/0x150 net/ipv6/route.c:3835 ipv6_route_ioctl+0x3fc/0x570 net/ipv6/route.c:4459 inet6_ioctl+0x246/0x290 net/ipv6/af_inet6.c:569 sock_do_ioctl+0xcc/0x230 net/socket.c:1189 sock_ioctl+0x1f8/0x680 net/socket.c:1306 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x197/0x210 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] Fixes: 70f7457ad6d6 ("net: create device lookup API with reference tracking") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Jakub Kicinski Cc: David Ahern Reviewed-by: Jakub Kicinski Reviewed-by: David Ahern Signed-off-by: David S. Miller --- net/ipv6/route.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e510a4162ef8..64e873f5895f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3360,6 +3360,7 @@ static int ip6_route_check_nh_onlink(struct net *net, static int ip6_route_check_nh(struct net *net, struct fib6_config *cfg, struct net_device **_dev, + netdevice_tracker *dev_tracker, struct inet6_dev **idev) { const struct in6_addr *gw_addr = &cfg->fc_gateway; @@ -3404,7 +3405,7 @@ static int ip6_route_check_nh(struct net *net, err = -EHOSTUNREACH; } else { *_dev = dev = res.nh->fib_nh_dev; - dev_hold(dev); + netdev_hold(dev, dev_tracker, GFP_ATOMIC); *idev = in6_dev_get(dev); } @@ -3412,7 +3413,9 @@ static int ip6_route_check_nh(struct net *net, } static int ip6_validate_gw(struct net *net, struct fib6_config *cfg, - struct net_device **_dev, struct inet6_dev **idev, + struct net_device **_dev, + netdevice_tracker *dev_tracker, + struct inet6_dev **idev, struct netlink_ext_ack *extack) { const struct in6_addr *gw_addr = &cfg->fc_gateway; @@ -3453,7 +3456,8 @@ static int ip6_validate_gw(struct net *net, struct fib6_config *cfg, if (cfg->fc_flags & RTNH_F_ONLINK) err = ip6_route_check_nh_onlink(net, cfg, dev, extack); else - err = ip6_route_check_nh(net, cfg, _dev, idev); + err = ip6_route_check_nh(net, cfg, _dev, dev_tracker, + idev); rcu_read_unlock(); @@ -3571,7 +3575,8 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, } if (cfg->fc_flags & RTF_GATEWAY) { - err = ip6_validate_gw(net, cfg, &dev, &idev, extack); + err = ip6_validate_gw(net, cfg, &dev, dev_tracker, + &idev, extack); if (err) goto out; -- cgit v1.2.3 From 264879fdbea0c3093057d48f3dcc7afeea433fb7 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 16 Jun 2023 12:45:57 +0200 Subject: dt-bindings: net: phy: gpy2xx: more precise description Mention that the interrupt line is just asserted for a random period of time, not the entire time. Suggested-by: Rob Herring Signed-off-by: Michael Walle Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml b/Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml index d71fa9de2b64..8a3713abd1ca 100644 --- a/Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml +++ b/Documentation/devicetree/bindings/net/maxlinear,gpy2xx.yaml @@ -17,11 +17,12 @@ properties: maxlinear,use-broken-interrupts: description: | Interrupts are broken on some GPY2xx PHYs in that they keep the - interrupt line asserted even after the interrupt status register is - cleared. Thus it is blocking the interrupt line which is usually bad - for shared lines. By default interrupts are disabled for this PHY and - polling mode is used. If one can live with the consequences, this - property can be used to enable interrupt handling. + interrupt line asserted for a random amount of time even after the + interrupt status register is cleared. Thus it is blocking the + interrupt line which is usually bad for shared lines. By default, + interrupts are disabled for this PHY and polling mode is used. If one + can live with the consequences, this property can be used to enable + interrupt handling. Affected PHYs (as far as known) are GPY215B and GPY215C. type: boolean -- cgit v1.2.3 From 988e8d90b3dc482637532e61bc2d58bfc4af5167 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 17 Jun 2023 16:24:37 +0200 Subject: net: phy: at803x: Use devm_regulator_get_enable_optional() Use devm_regulator_get_enable_optional() instead of hand writing it. It saves some line of code. Signed-off-by: Christophe JAILLET Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 44 +++++++------------------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 656136628ffd..c1f307d90518 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -304,7 +304,6 @@ struct at803x_priv { bool is_1000basex; struct regulator_dev *vddio_rdev; struct regulator_dev *vddh_rdev; - struct regulator *vddio; u64 stats[ARRAY_SIZE(at803x_hw_stats)]; }; @@ -824,11 +823,11 @@ static int at803x_parse_dt(struct phy_device *phydev) if (ret < 0) return ret; - priv->vddio = devm_regulator_get_optional(&phydev->mdio.dev, - "vddio"); - if (IS_ERR(priv->vddio)) { + ret = devm_regulator_get_enable_optional(&phydev->mdio.dev, + "vddio"); + if (ret) { phydev_err(phydev, "failed to get VDDIO regulator\n"); - return PTR_ERR(priv->vddio); + return ret; } /* Only AR8031/8033 support 1000Base-X for SFP modules */ @@ -856,12 +855,6 @@ static int at803x_probe(struct phy_device *phydev) if (ret) return ret; - if (priv->vddio) { - ret = regulator_enable(priv->vddio); - if (ret < 0) - return ret; - } - if (phydev->drv->phy_id == ATH8031_PHY_ID) { int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); int mode_cfg; @@ -869,10 +862,8 @@ static int at803x_probe(struct phy_device *phydev) .wolopts = 0, }; - if (ccr < 0) { - ret = ccr; - goto err; - } + if (ccr < 0) + return ccr; mode_cfg = ccr & AT803X_MODE_CFG_MASK; switch (mode_cfg) { @@ -890,25 +881,11 @@ static int at803x_probe(struct phy_device *phydev) ret = at803x_set_wol(phydev, &wol); if (ret < 0) { phydev_err(phydev, "failed to disable WOL on probe: %d\n", ret); - goto err; + return ret; } } return 0; - -err: - if (priv->vddio) - regulator_disable(priv->vddio); - - return ret; -} - -static void at803x_remove(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - if (priv->vddio) - regulator_disable(priv->vddio); } static int at803x_get_features(struct phy_device *phydev) @@ -2021,7 +1998,6 @@ static struct phy_driver at803x_driver[] = { .name = "Qualcomm Atheros AR8035", .flags = PHY_POLL_CABLE_TEST, .probe = at803x_probe, - .remove = at803x_remove, .config_aneg = at803x_config_aneg, .config_init = at803x_config_init, .soft_reset = genphy_soft_reset, @@ -2043,7 +2019,6 @@ static struct phy_driver at803x_driver[] = { .name = "Qualcomm Atheros AR8030", .phy_id_mask = AT8030_PHY_ID_MASK, .probe = at803x_probe, - .remove = at803x_remove, .config_init = at803x_config_init, .link_change_notify = at803x_link_change_notify, .set_wol = at803x_set_wol, @@ -2059,7 +2034,6 @@ static struct phy_driver at803x_driver[] = { .name = "Qualcomm Atheros AR8031/AR8033", .flags = PHY_POLL_CABLE_TEST, .probe = at803x_probe, - .remove = at803x_remove, .config_init = at803x_config_init, .config_aneg = at803x_config_aneg, .soft_reset = genphy_soft_reset, @@ -2082,7 +2056,6 @@ static struct phy_driver at803x_driver[] = { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID), .name = "Qualcomm Atheros AR8032", .probe = at803x_probe, - .remove = at803x_remove, .flags = PHY_POLL_CABLE_TEST, .config_init = at803x_config_init, .link_change_notify = at803x_link_change_notify, @@ -2100,7 +2073,6 @@ static struct phy_driver at803x_driver[] = { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), .name = "Qualcomm Atheros AR9331 built-in PHY", .probe = at803x_probe, - .remove = at803x_remove, .suspend = at803x_suspend, .resume = at803x_resume, .flags = PHY_POLL_CABLE_TEST, @@ -2117,7 +2089,6 @@ static struct phy_driver at803x_driver[] = { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID), .name = "Qualcomm Atheros QCA9561 built-in PHY", .probe = at803x_probe, - .remove = at803x_remove, .suspend = at803x_suspend, .resume = at803x_resume, .flags = PHY_POLL_CABLE_TEST, @@ -2183,7 +2154,6 @@ static struct phy_driver at803x_driver[] = { .name = "Qualcomm QCA8081", .flags = PHY_POLL_CABLE_TEST, .probe = at803x_probe, - .remove = at803x_remove, .config_intr = at803x_config_intr, .handle_interrupt = at803x_handle_interrupt, .get_tunable = at803x_get_tunable, -- cgit v1.2.3 From 2dc6af8be002d16715485372ce1e02b65faf9283 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 16 Jun 2023 13:49:39 -0700 Subject: gro: move the tc_ext comparison to a helper The double ifdefs (one for the variable declaration and one around the code) are quite aesthetically displeasing. Factor this code out into a helper for easier wrapping. This will become even more ugly when another skb ext comparison is added in the future. The resulting machine code looks the same, the compiler seems to try to use %rax more and some blocks more around but I haven't spotted minor differences. Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- net/core/gro.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/net/core/gro.c b/net/core/gro.c index dca800068e41..0759277dc14e 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -304,6 +304,24 @@ void napi_gro_flush(struct napi_struct *napi, bool flush_old) } EXPORT_SYMBOL(napi_gro_flush); +static unsigned long gro_list_prepare_tc_ext(const struct sk_buff *skb, + const struct sk_buff *p, + unsigned long diffs) +{ +#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT) + struct tc_skb_ext *skb_ext; + struct tc_skb_ext *p_ext; + + skb_ext = skb_ext_find(skb, TC_SKB_EXT); + p_ext = skb_ext_find(p, TC_SKB_EXT); + + diffs |= (!!p_ext) ^ (!!skb_ext); + if (!diffs && unlikely(skb_ext)) + diffs |= p_ext->chain ^ skb_ext->chain; +#endif + return diffs; +} + static void gro_list_prepare(const struct list_head *head, const struct sk_buff *skb) { @@ -338,23 +356,11 @@ static void gro_list_prepare(const struct list_head *head, * avoid trying too hard to skip each of them individually */ if (!diffs && unlikely(skb->slow_gro | p->slow_gro)) { -#if IS_ENABLED(CONFIG_SKB_EXTENSIONS) && IS_ENABLED(CONFIG_NET_TC_SKB_EXT) - struct tc_skb_ext *skb_ext; - struct tc_skb_ext *p_ext; -#endif - diffs |= p->sk != skb->sk; diffs |= skb_metadata_dst_cmp(p, skb); diffs |= skb_get_nfct(p) ^ skb_get_nfct(skb); -#if IS_ENABLED(CONFIG_SKB_EXTENSIONS) && IS_ENABLED(CONFIG_NET_TC_SKB_EXT) - skb_ext = skb_ext_find(skb, TC_SKB_EXT); - p_ext = skb_ext_find(p, TC_SKB_EXT); - - diffs |= (!!p_ext) ^ (!!skb_ext); - if (!diffs && unlikely(skb_ext)) - diffs |= p_ext->chain ^ skb_ext->chain; -#endif + diffs |= gro_list_prepare_tc_ext(skb, p, diffs); } NAPI_GRO_CB(p)->same_flow = !diffs; -- cgit v1.2.3 From 6d543b34dbcf6ec30064ae62a88faf60dbff4f8a Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 8 Jun 2023 16:36:11 +0300 Subject: wifi: mac80211: Support disabled links during association When the association is complete, do not configure disabled links, and track them as part of the interface data. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230608163202.c194fabeb81a.Iaefdef5ba0492afe9a5ede14c68060a4af36e444@changeid Signed-off-by: Johannes Berg --- include/net/mac80211.h | 6 ++++-- net/mac80211/cfg.c | 4 ++-- net/mac80211/ieee80211_i.h | 4 +++- net/mac80211/link.c | 38 +++++++++++++++++++++++--------------- net/mac80211/mlme.c | 35 ++++++++++++++++++++++------------- 5 files changed, 54 insertions(+), 33 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2ecc8d0c6ef4..914448cb0ecf 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1846,6 +1846,8 @@ struct ieee80211_vif_cfg { * @active_links: The bitmap of active links, or 0 for non-MLO. * The driver shouldn't change this directly, but use the * API calls meant for that purpose. + * @dormant_links: bitmap of valid but disabled links, or 0 for non-MLO. + * Must be a subset of valid_links. * @addr: address of this interface * @p2p: indicates whether this AP or STA interface is a p2p * interface, i.e. a GO or p2p-sta respectively @@ -1883,7 +1885,7 @@ struct ieee80211_vif { struct ieee80211_vif_cfg cfg; struct ieee80211_bss_conf bss_conf; struct ieee80211_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; - u16 valid_links, active_links; + u16 valid_links, active_links, dormant_links; u8 addr[ETH_ALEN] __aligned(2); bool p2p; @@ -1916,7 +1918,7 @@ struct ieee80211_vif { */ static inline u16 ieee80211_vif_usable_links(const struct ieee80211_vif *vif) { - return vif->valid_links; + return vif->valid_links & ~vif->dormant_links; } /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ca6d53d5751d..359589d525d5 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -4868,7 +4868,7 @@ static int ieee80211_add_intf_link(struct wiphy *wiphy, return -EOPNOTSUPP; mutex_lock(&sdata->local->mtx); - res = ieee80211_vif_set_links(sdata, wdev->valid_links); + res = ieee80211_vif_set_links(sdata, wdev->valid_links, 0); mutex_unlock(&sdata->local->mtx); return res; @@ -4881,7 +4881,7 @@ static void ieee80211_del_intf_link(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); mutex_lock(&sdata->local->mtx); - ieee80211_vif_set_links(sdata, wdev->valid_links); + ieee80211_vif_set_links(sdata, wdev->valid_links, 0); mutex_unlock(&sdata->local->mtx); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7a98fa26ec92..4afd5095366c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -410,6 +410,8 @@ struct ieee80211_mgd_assoc_data { ieee80211_conn_flags_t conn_flags; u16 status; + + bool disabled; } link[IEEE80211_MLD_MAX_NUM_LINKS]; u8 ap_addr[ETH_ALEN] __aligned(2); @@ -2019,7 +2021,7 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *link_conf); void ieee80211_link_stop(struct ieee80211_link_data *link); int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, - u16 new_links); + u16 new_links, u16 dormant_links); void ieee80211_vif_clear_links(struct ieee80211_sub_if_data *sdata); /* tx handling */ diff --git a/net/mac80211/link.c b/net/mac80211/link.c index 55cba3760ef5..d090ecc41ea2 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -142,25 +142,34 @@ static int ieee80211_check_dup_link_addrs(struct ieee80211_sub_if_data *sdata) } static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata, - u16 links) + u16 valid_links, u16 dormant_links) { - sdata->vif.valid_links = links; - - if (!links) { + sdata->vif.valid_links = valid_links; + sdata->vif.dormant_links = dormant_links; + + if (!valid_links || + WARN((~valid_links & dormant_links) || + !(valid_links & ~dormant_links), + "Invalid links: valid=0x%x, dormant=0x%x", + valid_links, dormant_links)) { sdata->vif.active_links = 0; + sdata->vif.dormant_links = 0; return; } switch (sdata->vif.type) { case NL80211_IFTYPE_AP: /* in an AP all links are always active */ - sdata->vif.active_links = links; + sdata->vif.active_links = valid_links; + + /* AP links are not expected to be disabled */ + WARN_ON(dormant_links); break; case NL80211_IFTYPE_STATION: if (sdata->vif.active_links) break; - WARN_ON(hweight16(links) > 1); - sdata->vif.active_links = links; + sdata->vif.active_links = valid_links & ~dormant_links; + WARN_ON(hweight16(sdata->vif.active_links) > 1); break; default: WARN_ON(1); @@ -169,7 +178,7 @@ static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata, static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata, struct link_container **to_free, - u16 new_links) + u16 new_links, u16 dormant_links) { u16 old_links = sdata->vif.valid_links; u16 old_active = sdata->vif.active_links; @@ -245,7 +254,7 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata, /* for keys we will not be able to undo this */ ieee80211_tear_down_links(sdata, to_free, rem); - ieee80211_set_vif_links_bitmaps(sdata, new_links); + ieee80211_set_vif_links_bitmaps(sdata, new_links, dormant_links); /* tell the driver */ ret = drv_change_vif_links(sdata->local, sdata, @@ -258,7 +267,7 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata, /* restore config */ memcpy(sdata->link, old_data, sizeof(old_data)); memcpy(sdata->vif.link_conf, old, sizeof(old)); - ieee80211_set_vif_links_bitmaps(sdata, old_links); + ieee80211_set_vif_links_bitmaps(sdata, old_links, dormant_links); /* and free (only) the newly allocated links */ memset(to_free, 0, sizeof(links)); goto free; @@ -282,12 +291,13 @@ deinit: } int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, - u16 new_links) + u16 new_links, u16 dormant_links) { struct link_container *links[IEEE80211_MLD_MAX_NUM_LINKS]; int ret; - ret = ieee80211_vif_update_links(sdata, links, new_links); + ret = ieee80211_vif_update_links(sdata, links, new_links, + dormant_links); ieee80211_free_links(sdata, links); return ret; @@ -304,7 +314,7 @@ void ieee80211_vif_clear_links(struct ieee80211_sub_if_data *sdata) */ sdata_lock(sdata); - ieee80211_vif_update_links(sdata, links, 0); + ieee80211_vif_update_links(sdata, links, 0, 0); sdata_unlock(sdata); ieee80211_free_links(sdata, links); @@ -328,7 +338,6 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata, if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EINVAL; - /* cannot activate links that don't exist */ if (active_links & ~ieee80211_vif_usable_links(&sdata->vif)) return -EINVAL; @@ -484,7 +493,6 @@ void ieee80211_set_active_links_async(struct ieee80211_vif *vif, if (sdata->vif.type != NL80211_IFTYPE_STATION) return; - /* cannot activate links that don't exist */ if (active_links & ~ieee80211_vif_usable_links(&sdata->vif)) return; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 959695ed7649..738822b82d3e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2818,6 +2818,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, assoc_data->link[link_id].status != WLAN_STATUS_SUCCESS) continue; + if (ieee80211_vif_is_mld(&sdata->vif) && + !(ieee80211_vif_usable_links(&sdata->vif) & BIT(link_id))) + continue; + link = sdata_dereference(sdata->link[link_id], sdata); if (WARN_ON(!link)) return; @@ -2844,6 +2848,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, struct cfg80211_bss *cbss = assoc_data->link[link_id].bss; if (!cbss || + !(BIT(link_id) & + ieee80211_vif_usable_links(&sdata->vif)) || assoc_data->link[link_id].status != WLAN_STATUS_SUCCESS) continue; @@ -3058,7 +3064,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(sdata->vif.bss_conf.tx_pwr_env, 0, sizeof(sdata->vif.bss_conf.tx_pwr_env)); - ieee80211_vif_set_links(sdata, 0); + ieee80211_vif_set_links(sdata, 0, 0); } static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) @@ -3511,7 +3517,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, mutex_lock(&sdata->local->mtx); ieee80211_link_release_channel(&sdata->deflink); - ieee80211_vif_set_links(sdata, 0); + ieee80211_vif_set_links(sdata, 0, 0); mutex_unlock(&sdata->local->mtx); } @@ -3570,7 +3576,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, mutex_lock(&sdata->local->mtx); ieee80211_link_release_channel(&sdata->deflink); - ieee80211_vif_set_links(sdata, 0); + ieee80211_vif_set_links(sdata, 0, 0); mutex_unlock(&sdata->local->mtx); } @@ -4979,7 +4985,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, unsigned int link_id; struct sta_info *sta; u64 changed[IEEE80211_MLD_MAX_NUM_LINKS] = {}; - u16 valid_links = 0; + u16 valid_links = 0, dormant_links = 0; int err; mutex_lock(&sdata->local->sta_mtx); @@ -4995,16 +5001,18 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { if (!assoc_data->link[link_id].bss) continue; - valid_links |= BIT(link_id); - if (link_id != assoc_data->assoc_link_id) { + valid_links |= BIT(link_id); + if (assoc_data->link[link_id].disabled) { + dormant_links |= BIT(link_id); + } else if (link_id != assoc_data->assoc_link_id) { err = ieee80211_sta_allocate_link(sta, link_id); if (err) goto out_err; } } - ieee80211_vif_set_links(sdata, valid_links); + ieee80211_vif_set_links(sdata, valid_links, dormant_links); } for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { @@ -5012,7 +5020,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, struct ieee80211_link_data *link; struct link_sta_info *link_sta; - if (!cbss) + if (!cbss || assoc_data->link[link_id].disabled) continue; link = sdata_dereference(sdata->link[link_id], sdata); @@ -5084,7 +5092,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, } /* links might have changed due to rejected ones, set them again */ - ieee80211_vif_set_links(sdata, valid_links); + ieee80211_vif_set_links(sdata, valid_links, dormant_links); rate_control_rate_init(sta); @@ -6627,12 +6635,12 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, mlo = true; if (WARN_ON(!ap_mld_addr)) return -EINVAL; - err = ieee80211_vif_set_links(sdata, BIT(link_id)); + err = ieee80211_vif_set_links(sdata, BIT(link_id), 0); } else { if (WARN_ON(ap_mld_addr)) return -EINVAL; ap_mld_addr = cbss->bssid; - err = ieee80211_vif_set_links(sdata, 0); + err = ieee80211_vif_set_links(sdata, 0, 0); link_id = 0; mlo = false; } @@ -6784,7 +6792,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, out_err: ieee80211_link_release_channel(&sdata->deflink); - ieee80211_vif_set_links(sdata, 0); + ieee80211_vif_set_links(sdata, 0, 0); return err; } @@ -7324,10 +7332,11 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, for (i = 0; i < ARRAY_SIZE(assoc_data->link); i++) { assoc_data->link[i].conn_flags = conn_flags; assoc_data->link[i].bss = req->links[i].bss; + assoc_data->link[i].disabled = req->links[i].disabled; } /* if there was no authentication, set up the link */ - err = ieee80211_vif_set_links(sdata, BIT(assoc_link_id)); + err = ieee80211_vif_set_links(sdata, BIT(assoc_link_id), 0); if (err) goto err_clear; } else { -- cgit v1.2.3 From a8df1f580ff24d2d00bf7839551697a0235d16dc Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 11 Jun 2023 12:14:26 +0300 Subject: wifi: mac80211: Add debugfs entry to report dormant links Add debugfs entry to report dormant (valid but disabled) links. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230611121219.7fa5f022adfb.Iff6fa3e1a3b00ae726612f9d5a31f7fe2fcbfc68@changeid Signed-off-by: Johannes Berg --- net/mac80211/debugfs_netdev.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 1b9293379c1e..63250286dc8b 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -693,6 +693,19 @@ IEEE80211_IF_FILE(dot11MeshConnectedToAuthServer, debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \ sdata, &name##_ops) +#define DEBUGFS_ADD_X(_bits, _name, _mode) \ + debugfs_create_x##_bits(#_name, _mode, sdata->vif.debugfs_dir, \ + &sdata->vif._name) + +#define DEBUGFS_ADD_X8(_name, _mode) \ + DEBUGFS_ADD_X(8, _name, _mode) + +#define DEBUGFS_ADD_X16(_name, _mode) \ + DEBUGFS_ADD_X(16, _name, _mode) + +#define DEBUGFS_ADD_X32(_name, _mode) \ + DEBUGFS_ADD_X(32, _name, _mode) + #define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400) static void add_common_files(struct ieee80211_sub_if_data *sdata) @@ -722,6 +735,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD_MODE(tdls_wider_bw, 0600); DEBUGFS_ADD_MODE(valid_links, 0400); DEBUGFS_ADD_MODE(active_links, 0600); + DEBUGFS_ADD_X16(dormant_links, 0400); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) -- cgit v1.2.3 From edcda51d99a7ae67d1cb4019b2d33d8d5defc6fe Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 14:59:05 +0300 Subject: wifi: iwlwifi: mvm: remove new checksum code The hardware isn't going to get fixed, so this mode cannot work in the foreseeable future. Remove it. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614145722.ddbc16c4affe.Ia6921e4b8a9624d4f57489ac775105ed0e400313@changeid [restore original subject] Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/tx.h | 13 +---- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 -- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 14 ------ drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 60 +++-------------------- 4 files changed, 7 insertions(+), 84 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 97edf5477ba7..842360b1e995 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_tx_h__ @@ -177,17 +177,6 @@ enum iwl_tx_offload_assist_flags_pos { #define IWL_TX_CMD_OFFLD_MH_MASK 0x1f #define IWL_TX_CMD_OFFLD_IP_HDR_MASK 0x3f -enum iwl_tx_offload_assist_bz { - IWL_TX_CMD_OFFLD_BZ_RESULT_OFFS = 0x000003ff, - IWL_TX_CMD_OFFLD_BZ_START_OFFS = 0x001ff800, - IWL_TX_CMD_OFFLD_BZ_MH_LEN = 0x07c00000, - IWL_TX_CMD_OFFLD_BZ_MH_PAD = 0x08000000, - IWL_TX_CMD_OFFLD_BZ_AMSDU = 0x10000000, - IWL_TX_CMD_OFFLD_BZ_ZERO2ONES = 0x20000000, - IWL_TX_CMD_OFFLD_BZ_ENABLE_CSUM = 0x40000000, - IWL_TX_CMD_OFFLD_BZ_PARTIAL_CSUM = 0x80000000, -}; - /* TODO: complete documentation for try_cnt and btkill_cnt */ /** * struct iwl_tx_cmd - TX command struct to FW diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index ee838dd60f4e..4c0a9cc9ff7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -6142,10 +6142,6 @@ static bool iwl_mvm_mac_can_aggregate(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - if (iwl_mvm_has_new_tx_csum(mvm)) - return iwl_mvm_tx_csum_bz(mvm, head, true) == - iwl_mvm_tx_csum_bz(mvm, skb, true); - /* For now don't aggregate IPv6 in AMSDU */ if (skb->protocol != htons(ETH_P_IP)) return false; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b452c35443d2..bcfe4af9fcb6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1540,19 +1540,6 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CTDP_SUPPORT); } -static inline bool iwl_mvm_has_new_tx_csum(struct iwl_mvm *mvm) -{ - if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ) - return false; - - if (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_BZ && - CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && - mvm->trans->hw_rev_step <= SILICON_B_STEP) - return false; - - return true; -} - extern const u8 iwl_mvm_ac_to_tx_fifo[]; extern const u8 iwl_mvm_ac_to_gen2_tx_fifo[]; @@ -1630,7 +1617,6 @@ void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq); unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, struct ieee80211_sta *sta, unsigned int tid); -u32 iwl_mvm_tx_csum_bz(struct iwl_mvm *mvm, struct sk_buff *skb, bool amsdu); #ifdef CONFIG_IWLWIFI_DEBUG const char *iwl_mvm_get_tx_fail_reason(u32 status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index bacc3045ea16..c0001ee3d9fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -40,8 +40,9 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr, #define OPT_HDR(type, skb, off) \ (type *)(skb_network_header(skb) + (off)) -static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_tx_info *info, bool amsdu) +static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb, + struct ieee80211_tx_info *info, + bool amsdu) { struct ieee80211_hdr *hdr = (void *)skb->data; u16 mh_len = ieee80211_hdrlen(hdr->frame_control); @@ -141,54 +142,6 @@ out: return offload_assist; } -u32 iwl_mvm_tx_csum_bz(struct iwl_mvm *mvm, struct sk_buff *skb, bool amsdu) -{ - struct ieee80211_hdr *hdr = (void *)skb->data; - u32 offload_assist = IWL_TX_CMD_OFFLD_BZ_PARTIAL_CSUM; - unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); - unsigned int csum_start = skb_checksum_start_offset(skb); - - offload_assist |= u32_encode_bits(hdrlen / 2, - IWL_TX_CMD_OFFLD_BZ_MH_LEN); - if (amsdu) - offload_assist |= IWL_TX_CMD_OFFLD_BZ_AMSDU; - else if (hdrlen % 4) - /* padding is inserted later in transport */ - offload_assist |= IWL_TX_CMD_OFFLD_BZ_MH_PAD; - - if (skb->ip_summed != CHECKSUM_PARTIAL) - return offload_assist; - - offload_assist |= IWL_TX_CMD_OFFLD_BZ_ENABLE_CSUM | - IWL_TX_CMD_OFFLD_BZ_ZERO2ONES; - - /* - * mac80211 will always calculate checksum in software for - * non-fast-xmit, and so we can only do offloaded checksum - * for fast-xmit frames. In this case, we always have the - * RFC 1042 header present. skb_checksum_start_offset() - * returns the offset from the beginning, but the hardware - * needs it from after the header & SNAP header. - */ - csum_start -= hdrlen + 8; - - offload_assist |= u32_encode_bits(csum_start, - IWL_TX_CMD_OFFLD_BZ_START_OFFS); - offload_assist |= u32_encode_bits(csum_start + skb->csum_offset, - IWL_TX_CMD_OFFLD_BZ_RESULT_OFFS); - - return offload_assist; -} - -static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_tx_info *info, - bool amsdu) -{ - if (!iwl_mvm_has_new_tx_csum(mvm)) - return iwl_mvm_tx_csum_pre_bz(mvm, skb, info, amsdu); - return iwl_mvm_tx_csum_bz(mvm, skb, amsdu); -} - /* * Sets most of the Tx cmd's fields */ @@ -288,7 +241,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd->sta_id = sta_id; tx_cmd->offload_assist = - cpu_to_le16(iwl_mvm_tx_csum_pre_bz(mvm, skb, info, amsdu)); + cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, info, amsdu)); } static u32 iwl_mvm_get_tx_ant(struct iwl_mvm *mvm, @@ -612,9 +565,8 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, cmd->rate_n_flags = cpu_to_le32(rate_n_flags); } else { struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload; - u16 offload_assist = iwl_mvm_tx_csum_pre_bz(mvm, skb, - info, - amsdu); + u16 offload_assist = iwl_mvm_tx_csum(mvm, skb, + info, amsdu); cmd->offload_assist = cpu_to_le16(offload_assist); -- cgit v1.2.3 From 7dd50fd5478056929a012c6bf8b3c6f87c7e9e87 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Wed, 14 Jun 2023 15:50:08 +0300 Subject: wifi: iwlwifi: mvm: Add NULL check before dereferencing the pointer While vif pointers are protected by the corresponding "*active" fields, static checkers can get confused sometimes. Add an explicit check. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614154951.78749ae91fb5.Id3c05d13eeee6638f0930f750e93fb928d5c9dee@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index ac1dae52556f..19839cc44eb3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -647,30 +647,32 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm, return; /* enable PM on bss if bss stand alone */ - if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) { + if (bss_mvmvif && vifs->bss_active && !vifs->p2p_active && + !vifs->ap_active) { bss_mvmvif->pm_enabled = true; return; } /* enable PM on p2p if p2p stand alone */ - if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) { + if (p2p_mvmvif && vifs->p2p_active && !vifs->bss_active && + !vifs->ap_active) { p2p_mvmvif->pm_enabled = true; return; } - if (vifs->bss_active && vifs->p2p_active) + if (p2p_mvmvif && bss_mvmvif && vifs->bss_active && vifs->p2p_active) client_same_channel = iwl_mvm_have_links_same_channel(bss_mvmvif, p2p_mvmvif); - if (vifs->bss_active && vifs->ap_active) + if (bss_mvmvif && ap_mvmvif && vifs->bss_active && vifs->ap_active) ap_same_channel = iwl_mvm_have_links_same_channel(bss_mvmvif, ap_mvmvif); /* clients are not stand alone: enable PM if DCM */ if (!(client_same_channel || ap_same_channel)) { - if (vifs->bss_active) + if (bss_mvmvif && vifs->bss_active) bss_mvmvif->pm_enabled = true; - if (vifs->p2p_active) + if (p2p_mvmvif && vifs->p2p_active) p2p_mvmvif->pm_enabled = true; return; } -- cgit v1.2.3 From f912959875761084fda351e1257dcfa9d1fa3037 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:18 +0300 Subject: wifi: iwlwifi: mvm: correctly access HE/EHT sband capa We can't just dereference the sband->iftype_data pointer, that's an array so we need to access the right entry. Use the previously introduced helper functions to do that. There are also cases, e.g. when loading with disable_11ax=1, where the pointer might be NULL but we still attempt to use it, causing a crash. Fixes: 529281bdf0fc ("iwlwifi: mvm: limit TLC according to our HE capabilities") Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.a1f2b17ee39b.I8808120be744be8804815ce9e3e24ce6d2b424e3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 46 +++++++++++++++----------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 7c6eff4fa58a..2382725f25bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -63,12 +63,11 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_link_sta *link_sta) static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, - struct ieee80211_supported_band *sband) + const struct ieee80211_sta_he_cap *sband_he_cap) { struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; - const struct ieee80211_sta_he_cap *sband_he_cap; bool vht_ena = vht_cap->vht_supported; u16 flags = 0; @@ -94,7 +93,6 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm, IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; - sband_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); if (sband_he_cap && !(sband_he_cap->he_cap_elem.phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) @@ -196,16 +194,14 @@ static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs) static void rs_fw_he_set_enabled_rates(const struct ieee80211_link_sta *link_sta, - struct ieee80211_supported_band *sband, + const struct ieee80211_sta_he_cap *sband_he_cap, struct iwl_tlc_config_cmd_v4 *cmd) { const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); - u16 tx_mcs_80 = - le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80); - u16 tx_mcs_160 = - le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160); + u16 tx_mcs_80 = le16_to_cpu(sband_he_cap->he_mcs_nss_supp.tx_mcs_80); + u16 tx_mcs_160 = le16_to_cpu(sband_he_cap->he_mcs_nss_supp.tx_mcs_160); int i; u8 nss = link_sta->rx_nss; @@ -288,7 +284,8 @@ rs_fw_rs_mcs2eht_mcs(enum IWL_TLC_MCS_PER_BW bw, static void rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif, const struct ieee80211_link_sta *link_sta, - struct ieee80211_supported_band *sband, + const struct ieee80211_sta_he_cap *sband_he_cap, + const struct ieee80211_sta_eht_cap *sband_eht_cap, struct iwl_tlc_config_cmd_v4 *cmd) { /* peer RX mcs capa */ @@ -296,7 +293,7 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif, &link_sta->eht_cap.eht_mcs_nss_supp; /* our TX mcs capa */ const struct ieee80211_eht_mcs_nss_supp *eht_tx_mcs = - &sband->iftype_data->eht_cap.eht_mcs_nss_supp; + &sband_eht_cap->eht_mcs_nss_supp; enum IWL_TLC_MCS_PER_BW bw; struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_rx_20; @@ -315,7 +312,7 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif, } /* nic is 20Mhz only */ - if (!(sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[0] & + if (!(sband_he_cap->he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { mcs_tx_20 = eht_tx_mcs->only_20mhz; } else { @@ -369,6 +366,8 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif, static void rs_fw_set_supp_rates(struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, struct ieee80211_supported_band *sband, + const struct ieee80211_sta_he_cap *sband_he_cap, + const struct ieee80211_sta_eht_cap *sband_eht_cap, struct iwl_tlc_config_cmd_v4 *cmd) { int i; @@ -387,12 +386,13 @@ static void rs_fw_set_supp_rates(struct ieee80211_vif *vif, cmd->mode = IWL_TLC_MNG_MODE_NON_HT; /* HT/VHT rates */ - if (link_sta->eht_cap.has_eht) { + if (link_sta->eht_cap.has_eht && sband_he_cap && sband_eht_cap) { cmd->mode = IWL_TLC_MNG_MODE_EHT; - rs_fw_eht_set_enabled_rates(vif, link_sta, sband, cmd); - } else if (he_cap->has_he) { + rs_fw_eht_set_enabled_rates(vif, link_sta, sband_he_cap, + sband_eht_cap, cmd); + } else if (he_cap->has_he && sband_he_cap) { cmd->mode = IWL_TLC_MNG_MODE_HE; - rs_fw_he_set_enabled_rates(link_sta, sband, cmd); + rs_fw_he_set_enabled_rates(link_sta, sband_he_cap, cmd); } else if (vht_cap->vht_supported) { cmd->mode = IWL_TLC_MNG_MODE_VHT; rs_fw_vht_set_enabled_rates(link_sta, vht_cap, cmd); @@ -575,13 +575,17 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD); struct ieee80211_supported_band *sband = hw->wiphy->bands[band]; u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta, link_conf, link_sta); + const struct ieee80211_sta_he_cap *sband_he_cap = + ieee80211_get_he_iftype_cap_vif(sband, vif); + const struct ieee80211_sta_eht_cap *sband_eht_cap = + ieee80211_get_eht_iftype_cap_vif(sband, vif); struct iwl_mvm_link_sta *mvm_link_sta; struct iwl_lq_sta_rs_fw *lq_sta; struct iwl_tlc_config_cmd_v4 cfg_cmd = { .max_ch_width = mvmsta->authorized ? rs_fw_bw_from_sta_bw(link_sta) : IWL_TLC_MNG_CH_WIDTH_20MHZ, .flags = cpu_to_le16(rs_fw_get_config_flags(mvm, vif, link_sta, - sband)), + sband_he_cap)), .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)), .sgi_ch_width_supp = rs_fw_sgi_cw_support(link_sta), .max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ? @@ -595,9 +599,9 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, * mutual support by AP and client */ if (CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && - sband->iftype_data->eht_cap.has_eht && - sband->iftype_data->eht_cap.eht_cap_elem.phy_cap_info[5] & - IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF && + sband_eht_cap && + sband_eht_cap->eht_cap_elem.phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF && link_sta->eht_cap.has_eht && link_sta->eht_cap.eht_cap_elem.phy_cap_info[5] & IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF) { @@ -623,7 +627,9 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm, #ifdef CONFIG_IWLWIFI_DEBUGFS iwl_mvm_reset_frame_stats(mvm); #endif - rs_fw_set_supp_rates(vif, link_sta, sband, &cfg_cmd); + rs_fw_set_supp_rates(vif, link_sta, sband, + sband_he_cap, sband_eht_cap, + &cfg_cmd); /* * since TLC offload works with one mode we can assume -- cgit v1.2.3 From 84969e0fc801fe72fe9f5d523b0e897ff640c583 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 14 Jun 2023 12:41:19 +0300 Subject: wifi: iwlwifi: Correctly indicate support for VHT TX STBC If HT STBC is not supported, do not indicate support for VHT TX STBC. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.b24b5fba6fab.I116617875eb4a9d520df23a8c49a6594f9d8b2c6@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index fad71f490313..d79d5453c2dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2022 Intel Corporation + * Copyright (C) 2005-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -516,7 +516,7 @@ static void iwl_init_vht_hw_capab(struct iwl_trans *trans, num_tx_ants = 1; } - if (num_tx_ants > 1) + if (trans->cfg->ht_params->stbc && num_tx_ants > 1) vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; else vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; -- cgit v1.2.3 From 09396a4f68f08fc1b31f7cf9a1e429fbdbde3c46 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:20 +0300 Subject: wifi: iwlwifi: fw: make some ACPI functions static iwl_acpi_get_wifi_pkg_range(), iwl_acpi_get_wifi_pkg() and iwl_acpi_get_object() need not be exported etc., they're used only within the same file. Make them static. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.e866032e4106.Ifede7f7c25b17a8215b154ce01da513b75384325@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 27 +++++++++++++++-------- drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 32 +--------------------------- 2 files changed, 19 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 4e4048310f0f..6345ac454e80 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2019-2022 Intel Corporation + * Copyright (C) 2019-2023 Intel Corporation */ #include #include @@ -94,7 +94,7 @@ static int iwl_acpi_get_handle(struct device *dev, acpi_string method, return 0; } -void *iwl_acpi_get_object(struct device *dev, acpi_string method) +static void *iwl_acpi_get_object(struct device *dev, acpi_string method) { struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_handle handle; @@ -115,7 +115,6 @@ void *iwl_acpi_get_object(struct device *dev, acpi_string method) } return buf.pointer; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_object); /* * Generic function for evaluating a method defined in the device specific @@ -237,11 +236,12 @@ int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, } IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32); -union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev, - union acpi_object *data, - int min_data_size, - int max_data_size, - int *tbl_rev) +static union acpi_object * +iwl_acpi_get_wifi_pkg_range(struct device *dev, + union acpi_object *data, + int min_data_size, + int max_data_size, + int *tbl_rev) { int i; union acpi_object *wifi_pkg; @@ -292,7 +292,16 @@ union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev, found: return wifi_pkg; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg_range); + +static union acpi_object * +iwl_acpi_get_wifi_pkg(struct device *dev, + union acpi_object *data, + int data_size, int *tbl_rev) +{ + return iwl_acpi_get_wifi_pkg_range(dev, data, data_size, data_size, + tbl_rev); +} + int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, union iwl_tas_config_cmd *cmd, int fw_ver) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 6f361c59106f..e9c533cf7f93 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #ifndef __iwl_fw_acpi__ #define __iwl_fw_acpi__ @@ -168,19 +168,12 @@ struct iwl_fw_runtime; extern const guid_t iwl_guid; extern const guid_t iwl_rfi_guid; -void *iwl_acpi_get_object(struct device *dev, acpi_string method); - int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, const guid_t *guid, u8 *value); int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, const guid_t *guid, u32 *value); -union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev, - union acpi_object *data, - int min_data_size, - int max_data_size, - int *tbl_rev); /** * iwl_acpi_get_mcc - read MCC from ACPI, if available * @@ -234,11 +227,6 @@ bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt); #else /* CONFIG_ACPI */ -static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method) -{ - return ERR_PTR(-ENOENT); -} - static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func, union acpi_object *args) { @@ -257,15 +245,6 @@ static inline int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, return -ENOENT; } -static inline union acpi_object * -iwl_acpi_get_wifi_pkg_range(struct device *dev, - union acpi_object *data, - int min_data_size, int max_data_size, - int *tbl_rev) -{ - return ERR_PTR(-ENOENT); -} - static inline int iwl_acpi_get_mcc(struct device *dev, char *mcc) { return -ENOENT; @@ -337,13 +316,4 @@ static inline bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) #endif /* CONFIG_ACPI */ -static inline union acpi_object * -iwl_acpi_get_wifi_pkg(struct device *dev, - union acpi_object *data, - int data_size, int *tbl_rev) -{ - return iwl_acpi_get_wifi_pkg_range(dev, data, data_size, data_size, - tbl_rev); -} - #endif /* __iwl_fw_acpi__ */ -- cgit v1.2.3 From c4fbf6537ab0204904c43eac8eb877aaadd93e2c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:21 +0300 Subject: wifi: iwlwifi: mvm: use iwl_mvm_is_vendor_in_approved_list() We have this helper now instead of open-coding the check for the dmi_tas_approved_list, so use it even here. It was added for debugfs use, but it's better to be consistent. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.f3741f5cdef4.I5e0bf522189dc595ee38d05e93994211d32ec0f4@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index ed9370aac1b6..8d8277d94f56 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1182,7 +1182,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) if (ret == 0) return; - if (!dmi_check_system(dmi_tas_approved_list)) { + if (!iwl_mvm_is_vendor_in_approved_list()) { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n", dmi_get_system_info(DMI_SYS_VENDOR)); -- cgit v1.2.3 From 96fb6f47db24a712d650b0a9b9074873f273fb0e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:22 +0300 Subject: wifi: iwlwifi: pull from TXQs with softirqs disabled In mac80211, it's required that we pull from TXQs by calling ieee80211_tx_dequeue() only with softirqs disabled. However, in iwl_mvm_queue_state_change() we're often called with them enabled, e.g. from flush if anything was flushed, triggering a mac80211 warning. Fix that by disabling the softirqs across the TX call. Fixes: cfbc6c4c5b91 ("iwlwifi: mvm: support mac80211 TXQs model") Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.0feef7fa81db.I4dd62542d955b40dd8f0af34fa4accb9d0d17c7e@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 430642576f5d..cc04d7cad715 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1740,8 +1740,11 @@ static void iwl_mvm_queue_state_change(struct iwl_op_mode *op_mode, else set_bit(IWL_MVM_TXQ_STATE_STOP_FULL, &mvmtxq->state); - if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST) + if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST) { + local_bh_disable(); iwl_mvm_mac_itxq_xmit(mvm->hw, txq); + local_bh_enable(); + } } out: -- cgit v1.2.3 From c2a1c8c10f18e9416013db3dbfa67808d7ab03d8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:23 +0300 Subject: wifi: iwlwifi: pcie: double-check ACK interrupt after timeout There are evidently cases where the firmware completes the reset but the interrupt isn't received correctly, so check for the interrupt again after the timeout, and don't dump the firmware error log if the right bit is set. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.00cc2d9b88c3.I429bfe800f17c624e50c0b0c10dd2cd7d885f199@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index 73b395841ca8..fa46dad5fd68 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include "iwl-trans.h" #include "iwl-prph.h" @@ -117,9 +117,14 @@ static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans) trans_pcie->fw_reset_state != FW_RESET_REQUESTED, FW_RESET_TIMEOUT); if (!ret || trans_pcie->fw_reset_state == FW_RESET_ERROR) { - IWL_INFO(trans, - "firmware didn't ACK the reset - continue anyway\n"); - iwl_trans_fw_error(trans, true); + u32 inta_hw = iwl_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD); + + IWL_ERR(trans, + "timeout waiting for FW reset ACK (inta_hw=0x%x)\n", + inta_hw); + + if (!(inta_hw & MSIX_HW_INT_CAUSES_REG_RESET_DONE)) + iwl_trans_fw_error(trans, true); } trans_pcie->fw_reset_state = FW_RESET_IDLE; -- cgit v1.2.3 From c53c339d9a337732193c3b783f7bd80539fea259 Mon Sep 17 00:00:00 2001 From: Ariel Malamud Date: Wed, 14 Jun 2023 12:41:24 +0300 Subject: wifi: iwlwifi: fw: Add new FSEQ defines to fw dump On fw error dump, dmesg prints FSEQ register data. Add 4 additional prints in order to match those being dumped by Windows driver. Allows fw infra to correctly detect version mismatch. Signed-off-by: Ariel Malamud Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.f40dc9c810a8.I26227900d0b7e9a71fefe5cbf57cf6b46ee44413@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dump.c | 6 +++++- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index 23388261e97f..5876f917e536 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -467,6 +467,10 @@ static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt) FSEQ_REG(CNVR_AUX_MISC_CHIP), FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM), FSEQ_REG(CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR), + FSEQ_REG(FSEQ_PREV_CNVIO_INIT_VERSION), + FSEQ_REG(FSEQ_WIFI_FSEQ_VERSION), + FSEQ_REG(FSEQ_BT_FSEQ_VERSION), + FSEQ_REG(FSEQ_CLASS_TP_VERSION), }; if (!iwl_trans_grab_nic_access(trans)) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 0dfe00eae05d..6dd381ff0f9e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2022 Intel Corporation + * Copyright (C) 2005-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -486,6 +486,10 @@ enum { #define FSEQ_ALIVE_TOKEN 0xA340F0 #define FSEQ_CNVI_ID 0xA3408C #define FSEQ_CNVR_ID 0xA34090 +#define FSEQ_PREV_CNVIO_INIT_VERSION 0xA34084 +#define FSEQ_WIFI_FSEQ_VERSION 0xA34040 +#define FSEQ_BT_FSEQ_VERSION 0xA34044 +#define FSEQ_CLASS_TP_VERSION 0xA34078 #define IWL_D3_SLEEP_STATUS_SUSPEND 0xD3 #define IWL_D3_SLEEP_STATUS_RESUME 0xD0 -- cgit v1.2.3 From 38e721009d302f39ad5c744560a3f96ecbae6bfc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:25 +0300 Subject: wifi: iwlwifi: mvm: add a NULL pointer check We've observed that in some botched firmware restart scenarios when the firmware crashes again while we're reconfiguring, we can hit NULL pointer crashes here. The underlying issue is the botched restart which we need to fix separately, but until we can do that, don't crash hard here. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.e47b0192c78f.I67fa9f07cd1c8b3bdc8db25f5e31c1c680c49745@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 6 +++++- drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 059ede6f7b65..954ea9ac8e5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -1111,6 +1111,10 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, beacon_cmd.flags = cpu_to_le16(flags); beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len); + + if (WARN_ON(!mvmvif->link[link_conf->link_id])) + return -EINVAL; + if (iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD, 0) > 12) beacon_cmd.link_id = cpu_to_le32(mvmvif->link[link_conf->link_id]->fw_link_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index bb8868cd4396..524852cf5cd2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022-2023 Intel Corporation */ #include "mvm.h" #include "time-sync.h" @@ -369,6 +369,9 @@ int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); + if (WARN_ON(!link)) + return -EIO; + switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: @@ -398,6 +401,9 @@ int iwl_mvm_mld_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); + if (WARN_ON(!link)) + return -EIO; + return iwl_mvm_mld_rm_int_sta(mvm, &link->mcast_sta, true, 0, &link->cab_queue); } -- cgit v1.2.3 From df6791e74fe7baafe3c9ec1eabfd45a5b0b62595 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:26 +0300 Subject: wifi: iwlwifi: mvm: check link during TX Again, during some (botched) FW restart scenarios we can end up with a NULL link in the driver but mac80211 thinking all is still going OK. If we try to TX at the same time, we can crash there. Fix that by checking for a NULL link during TX. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.cee48479deec.I4eef58f7b67afafb7b3294adbeb6e0067b68419d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index c0001ee3d9fd..6f34208a6307 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -757,6 +757,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) } link = mvmvif->link[link_id]; + if (WARN_ON(!link)) + return -1; if (!ieee80211_is_data(hdr->frame_control)) sta_id = link->bcast_sta.sta_id; -- cgit v1.2.3 From 33acbe6aa459feb8c765944e2e78a7b0338108e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:28 +0300 Subject: wifi: iwlwifi: mvm: store WMM params per link We have the data structure set up to store the parameters per link, but weren't using them. Fix that and store them in the right link. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.332c4949a1be.Icae03975d578b0cc82279911a1ea7cbc313046d6@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 13 +++++++++---- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 8 ++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 954ea9ac8e5b..61c1ec46a2fb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -470,19 +470,24 @@ void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_ac_qos *ac, __le32 *qos_flags) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *mvm_link = + mvmvif->link[link_conf->link_id]; int i; + if (!mvm_link) + return; + for (i = 0; i < IEEE80211_NUM_ACS; i++) { u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i); u8 ucode_ac = iwl_mvm_mac80211_ac_to_ucode_ac(i); ac[ucode_ac].cw_min = - cpu_to_le16(mvmvif->deflink.queue_params[i].cw_min); + cpu_to_le16(mvm_link->queue_params[i].cw_min); ac[ucode_ac].cw_max = - cpu_to_le16(mvmvif->deflink.queue_params[i].cw_max); + cpu_to_le16(mvm_link->queue_params[i].cw_max); ac[ucode_ac].edca_txop = - cpu_to_le16(mvmvif->deflink.queue_params[i].txop * 32); - ac[ucode_ac].aifsn = mvmvif->deflink.queue_params[i].aifs; + cpu_to_le16(mvm_link->queue_params[i].txop * 32); + ac[ucode_ac].aifsn = mvm_link->queue_params[i].aifs; ac[ucode_ac].fifos_mask = BIT(txf); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index cb4df8c6f9de..8cd03357ce79 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022-2023 Intel Corporation */ #include "mvm.h" @@ -820,8 +820,12 @@ iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id]; - mvmvif->deflink.queue_params[ac] = *params; + if (!mvm_link) + return -EINVAL; + + mvm_link->queue_params[ac] = *params; /* No need to update right away, we'll get BSS_CHANGED_QOS * The exception is P2P_DEVICE interface which needs immediate update. -- cgit v1.2.3 From 77e1f3f369e5f89235d539059bf6c7fa1645f350 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:29 +0300 Subject: wifi: iwlwifi: use array as array argument When calling iwl_mvm_set_fw_qos_params() we explicitly pass a pointer to the first array element, but the function will treat it as an array. Simplify and clarify the code and pass the array instead. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.6fb4a9743b1b.I801007d207f6539a9e0996366ec593e2038b1f90@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index dc31f8de7d1d..af9ace787ec5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -183,7 +183,7 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &cmd.protection_flags, ht_flag, LINK_PROT_FLG_TGG_PROTECT); - iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, &cmd.ac[0], + iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, cmd.ac, &cmd.qos_flags); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 61c1ec46a2fb..a2583d045525 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -563,7 +563,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, cmd->filter_flags = 0; - iwl_mvm_set_fw_qos_params(mvm, vif, &vif->bss_conf, &cmd->ac[0], + iwl_mvm_set_fw_qos_params(mvm, vif, &vif->bss_conf, cmd->ac, &cmd->qos_flags); /* The fw does not distinguish between ht and fat */ -- cgit v1.2.3 From ed0c34333dfb2e4a6bd9e25613040aaf9d48fb9d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:30 +0300 Subject: wifi: iwlwifi: mvm: always send spec link ID in link commands The firmware technically only needs this when the link is newly added, but it's much easier for debugging if it's always available, so include it. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.daecd0e626f7.I0f8a16a6d80a283c9f947c9bb0fc50a7c6853948@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index af9ace787ec5..563396dfd3cd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -245,6 +245,7 @@ send_cmd: cmd.modify_mask = cpu_to_le32(changes); cmd.flags = cpu_to_le32(flags); cmd.flags_mask = cpu_to_le32(flags_mask); + cmd.spec_link_id = link_conf->link_id; ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY); if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE)) @@ -271,6 +272,7 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd.link_id = cpu_to_le32(link_info->fw_link_id); iwl_mvm_release_fw_link_id(mvm, link_info->fw_link_id); link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; + cmd.spec_link_id = link_conf->link_id; ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE); -- cgit v1.2.3 From 568db7fd27fad183d186742dc7ae6ca211ba51ff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:31 +0300 Subject: wifi: iwlwifi: add some FW misbehaviour check infrastructure When the firmware misbehaves (according to the driver), we often either ignore that, or WARN_ON, which is very noisy but doesn't really help. Add a little helper macro IWL_FW_CHECK() that can be used in place of WARN_ON() in conditions, and make it take a message that's printed in this case. We can also add more behaviour to this in the future. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.2e12ac670cea.Ia0198036b7a626876d836bd41a4b2d2b1e65c5ca@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 16 +++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 +++- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 10 ++++++---- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 15 ++++++++++++--- 4 files changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index be7806407de8..dcba0eefe70d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2019, 2021-2022 Intel Corporation + * Copyright (C) 2005-2014, 2018-2019, 2021-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -327,4 +327,18 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt); void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt, u32 timepoint, u32 timepoint_data); + +#define IWL_FW_CHECK_FAILED(_obj, _fmt, ...) \ + IWL_ERR_LIMIT(_obj, _fmt, __VA_ARGS__) + +#define IWL_FW_CHECK(_obj, _cond, _fmt, ...) \ + ({ \ + bool __cond = (_cond); \ + \ + if (unlikely(__cond)) \ + IWL_FW_CHECK_FAILED(_obj, _fmt, __VA_ARGS__); \ + \ + unlikely(__cond); \ + }) + #endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index cc04d7cad715..5336a4afde4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1601,7 +1601,9 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm, if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) continue; - if (unlikely(pkt_len < rx_h->min_size)) + if (IWL_FW_CHECK(mvm, pkt_len < rx_h->min_size, + "unexpected notification 0x%04x size %d, need %d\n", + rx_h->cmd_id, pkt_len, rx_h->min_size)) return; if (rx_h->context == RX_HANDLER_SYNC) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 9d8d9def9391..5c06839b87c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -985,10 +985,12 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1); rcu_read_unlock(); - if (WARN(tid != baid_data->tid || - !(sta_mask & baid_data->sta_mask), - "baid 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n", - baid, baid_data->sta_mask, baid_data->tid, sta_mask, tid)) + if (IWL_FW_CHECK(mvm, + tid != baid_data->tid || + !(sta_mask & baid_data->sta_mask), + "baid 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n", + baid, baid_data->sta_mask, baid_data->tid, + sta_mask, tid)) return false; nssn = reorder & IWL_RX_MPDU_REORDER_NSSN_MASK; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 6f34208a6307..f88636a73c8a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -2075,7 +2075,8 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) u16 tfd_cnt; int i; - if (unlikely(sizeof(*ba_res) > pkt_len)) + if (IWL_FW_CHECK(mvm, sizeof(*ba_res) > pkt_len, + "short BA notification (%d)\n", pkt_len)) return; sta_id = ba_res->sta_id; @@ -2087,7 +2088,13 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) (void *)(uintptr_t)ba_res->reduced_txp; tfd_cnt = le16_to_cpu(ba_res->tfd_cnt); - if (!tfd_cnt || struct_size(ba_res, tfd, tfd_cnt) > pkt_len) + if (!tfd_cnt) + return; + + if (IWL_FW_CHECK(mvm, + struct_size(ba_res, tfd, tfd_cnt) > pkt_len, + "short BA notification (tfds:%d, size:%d)\n", + tfd_cnt, pkt_len)) return; rcu_read_lock(); @@ -2145,7 +2152,9 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) rcu_read_lock(); mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id); - if (WARN_ON_ONCE(!mvmsta)) { + if (IWL_FW_CHECK(mvm, !mvmsta, + "invalid STA ID %d in BA notif\n", + sta_id)) { rcu_read_unlock(); return; } -- cgit v1.2.3 From 1902f1953b8ba100ee8705cb8a6f1a9795550eca Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Wed, 14 Jun 2023 12:41:32 +0300 Subject: wifi: iwlwifi: pcie: fix NULL pointer dereference in iwl_pcie_irq_rx_msix_handler() rxq can be NULL only when trans_pcie->rxq is NULL and entry->entry is zero. For the case when entry->entry is not equal to 0, rxq won't be NULL even if trans_pcie->rxq is NULL. Modify checker to check for trans_pcie->rxq. Fixes: abc599efa67b ("iwlwifi: pcie: don't crash when rx queues aren't allocated in interrupt") Signed-off-by: Anjaneyulu Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123446.5a5eb3889a4a.I375a1d58f16b48cd2044e7b7caddae512d7c86fd@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 4ee4886babcb..da1a27b1d8b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1636,14 +1636,14 @@ irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id) struct msix_entry *entry = dev_id; struct iwl_trans_pcie *trans_pcie = iwl_pcie_get_trans_pcie(entry); struct iwl_trans *trans = trans_pcie->trans; - struct iwl_rxq *rxq = &trans_pcie->rxq[entry->entry]; + struct iwl_rxq *rxq; trace_iwlwifi_dev_irq_msix(trans->dev, entry, false, 0, 0); if (WARN_ON(entry->entry >= trans->num_rx_queues)) return IRQ_NONE; - if (!rxq) { + if (!trans_pcie->rxq) { if (net_ratelimit()) IWL_ERR(trans, "[%d] Got MSI-X interrupt before we have Rx queues\n", @@ -1651,6 +1651,7 @@ irqreturn_t iwl_pcie_irq_rx_msix_handler(int irq, void *dev_id) return IRQ_NONE; } + rxq = &trans_pcie->rxq[entry->entry]; lock_map_acquire(&trans->sync_cmd_lockdep_map); IWL_DEBUG_ISR(trans, "[%d] Got interrupt\n", entry->entry); -- cgit v1.2.3 From c4c954547755927807aaca981025847821dd2d0c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:33 +0300 Subject: wifi: iwlwifi: implement WPFC ACPI table loading We skipped this in the past, but now we will need it for some platforms. Implement loading the PHY filter configuration IDs from the WPFC ACPI table. Note that the firmware must also be aware of the right filter configuration IDs (they're just the IDs of a filter configuration, not the actual configuration). Remove the useless hardcoded zeroes while at it. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123447.035026ea3169.I3a1fc1fe644fefa0d818ee1926c5fc331d68e8a3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 37 +++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 11 ++++++ drivers/net/wireless/intel/iwlwifi/fw/api/config.h | 15 +++----- drivers/net/wireless/intel/iwlwifi/mvm/constants.h | 6 +-- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 43 ++++------------------ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 ++ 6 files changed, 65 insertions(+), 51 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 6345ac454e80..dfe8357036eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -1248,3 +1248,40 @@ bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) return true; } IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved); + +void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, + struct iwl_phy_specific_cfg *filters) +{ + struct iwl_phy_specific_cfg tmp = {}; + union acpi_object *wifi_pkg, *data; + int tbl_rev, i; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_WPFC_METHOD); + if (IS_ERR(data)) + return; + + /* try to read wtas table revision 1 or revision 0*/ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WPFC_WIFI_DATA_SIZE, + &tbl_rev); + if (IS_ERR(wifi_pkg)) + goto out_free; + + if (tbl_rev != 0) + goto out_free; + + BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != ACPI_WPFC_WIFI_DATA_SIZE); + + for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) { + if (wifi_pkg->package.elements[i].type != ACPI_TYPE_INTEGER) + return; + tmp.filter_cfg_chains[i] = + cpu_to_le32(wifi_pkg->package.elements[i].integer.value); + } + + IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n"); + *filters = tmp; +out_free: + kfree(data); +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index e9c533cf7f93..c36c62d6414d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -11,6 +11,7 @@ #include "fw/api/power.h" #include "fw/api/phy.h" #include "fw/api/nvm-reg.h" +#include "fw/api/config.h" #include "fw/img.h" #include "iwl-trans.h" @@ -23,6 +24,7 @@ #define ACPI_ECKV_METHOD "ECKV" #define ACPI_PPAG_METHOD "PPAG" #define ACPI_WTAS_METHOD "WTAS" +#define ACPI_WPFC_METHOD "WPFC" #define ACPI_WIFI_DOMAIN (0x07) @@ -54,6 +56,7 @@ #define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ ACPI_SAR_NUM_CHAINS_REV2 * \ ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) +#define ACPI_WPFC_WIFI_DATA_SIZE 4 /* 4 filter config words */ /* revision 0 and 1 are identical, except for the semantics in the FW */ #define ACPI_GEO_NUM_BANDS_REV0 2 @@ -225,6 +228,9 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt); +void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, + struct iwl_phy_specific_cfg *filters); + #else /* CONFIG_ACPI */ static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev, @@ -314,6 +320,11 @@ static inline bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) return false; } +static inline void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, + struct iwl_phy_specific_cfg *filters) +{ +} + #endif /* CONFIG_ACPI */ #endif /* __iwl_fw_acpi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h index 087354b3c308..4419631604b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2019 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -67,17 +67,12 @@ enum iwl_calib_cfg { * Sent as part of the phy configuration command (v3) to configure specific FW * defined PHY filters that can be applied to each antenna. * - * @filter_cfg_chain_a: filter config id for LMAC1 chain A - * @filter_cfg_chain_b: filter config id for LMAC1 chain B - * @filter_cfg_chain_c: filter config id for LMAC2 chain A - * @filter_cfg_chain_d: filter config id for LMAC2 chain B - * values: 0 - no filter; 0xffffffff - reserved; otherwise - filter id + * @filter_cfg_chains: filter config id for LMAC1 chain A, LMAC1 chain B, + * LMAC2 chain A, LMAC2 chain B (in that order) + * values: 0: no filter; 0xffffffff: reserved; otherwise: filter id */ struct iwl_phy_specific_cfg { - __le32 filter_cfg_chain_a; - __le32 filter_cfg_chain_b; - __le32 filter_cfg_chain_c; - __le32 filter_cfg_chain_d; + __le32 filter_cfg_chains[4]; } __packed; /* PHY_SPECIFIC_CONFIGURATION_API_VER_1*/ /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index c604f9f39b24..243eccc68cb0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2013-2014, 2018-2021 Intel Corporation + * Copyright (C) 2013-2014, 2018-2023 Intel Corporation * Copyright (C) 2015 Intel Deutschland GmbH */ #ifndef __MVM_CONSTANTS_H @@ -109,10 +109,6 @@ #define IWL_MVM_USE_TWT true #define IWL_MVM_AMPDU_CONSEC_DROPS_DELBA 20 #define IWL_MVM_USE_NSSN_SYNC 0 -#define IWL_MVM_PHY_FILTER_CHAIN_A 0 -#define IWL_MVM_PHY_FILTER_CHAIN_B 0 -#define IWL_MVM_PHY_FILTER_CHAIN_C 0 -#define IWL_MVM_PHY_FILTER_CHAIN_D 0 #define IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH false #define IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA 40 /* 20016 pSec is 6 meter RTT, meaning 3 meter range */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 8d8277d94f56..77cdfb4a5ba3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -478,40 +478,13 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, return 0; } -#ifdef CONFIG_ACPI static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, struct iwl_phy_specific_cfg *phy_filters) { - /* - * TODO: read specific phy config from BIOS - * ACPI table for this feature has not been defined yet, - * so for now we use hardcoded values. - */ - - if (IWL_MVM_PHY_FILTER_CHAIN_A) { - phy_filters->filter_cfg_chain_a = - cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_A); - } - if (IWL_MVM_PHY_FILTER_CHAIN_B) { - phy_filters->filter_cfg_chain_b = - cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_B); - } - if (IWL_MVM_PHY_FILTER_CHAIN_C) { - phy_filters->filter_cfg_chain_c = - cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_C); - } - if (IWL_MVM_PHY_FILTER_CHAIN_D) { - phy_filters->filter_cfg_chain_d = - cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_D); - } -} -#else /* CONFIG_ACPI */ - -static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, - struct iwl_phy_specific_cfg *phy_filters) -{ -} +#ifdef CONFIG_ACPI + *phy_filters = mvm->phy_filters; #endif /* CONFIG_ACPI */ +} #if defined(CONFIG_ACPI) && defined(CONFIG_EFI) static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) @@ -560,7 +533,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) u32 cmd_id = PHY_CONFIGURATION_CMD; struct iwl_phy_cfg_cmd_v3 phy_cfg_cmd; enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img; - struct iwl_phy_specific_cfg phy_filters = {}; u8 cmd_ver; size_t cmd_size; @@ -591,11 +563,8 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, IWL_FW_CMD_VER_UNKNOWN); - if (cmd_ver == 3) { - iwl_mvm_phy_filter_init(mvm, &phy_filters); - memcpy(&phy_cfg_cmd.phy_specific_cfg, &phy_filters, - sizeof(struct iwl_phy_specific_cfg)); - } + if (cmd_ver >= 3) + iwl_mvm_phy_filter_init(mvm, &phy_cfg_cmd.phy_specific_cfg); IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n", phy_cfg_cmd.phy_cfg); @@ -1380,6 +1349,8 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) /* we don't fail if the table is not available */ } } + + iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters); } #else /* CONFIG_ACPI */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index bcfe4af9fcb6..ee2a526541d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1179,6 +1179,10 @@ struct iwl_mvm { __le16 cur_aid; u8 cur_bssid[ETH_ALEN]; +#ifdef CONFIG_ACPI + struct iwl_phy_specific_cfg phy_filters; +#endif + unsigned long last_6ghz_passive_scan_jiffies; unsigned long last_reset_or_resume_time_jiffies; -- cgit v1.2.3 From 4670d8dca8af0824b82010b7ad478fd505572006 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Jun 2023 12:41:34 +0300 Subject: wifi: iwlwifi: mvm: track u-APSD misbehaving AP by AP address If the AP is an AP MLD, then we shouldn't track just the BSSID but the MLD address. Just generally use ap_addr since it has the BSSID in the non-MLD case. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123447.b6a4f7edd10c.Ie5a8029ed686b9441620ba06596d430432f65559@changeid Signed-off-by: Johannes Berg --- .../net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 6 ++-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 35 ++++++++++++++-------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 3613b1fdc5d9..cb4ecad6103f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -554,7 +554,7 @@ static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file, char buf[20]; int len; - len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid); + len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_ap_addr); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -567,7 +567,7 @@ static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif, bool ret; mutex_lock(&mvm->mutex); - ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid); + ret = mac_pton(buf, mvmvif->uapsd_misbehaving_ap_addr); mutex_unlock(&mvm->mutex); return ret ? count : -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ee2a526541d7..de7aa4713c93 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -418,7 +418,7 @@ struct iwl_mvm_vif { #endif /* FW identified misbehaving AP */ - u8 uapsd_misbehaving_bssid[ETH_ALEN]; + u8 uapsd_misbehaving_ap_addr[ETH_ALEN] __aligned(2); struct delayed_work uapsd_nonagg_detected_wk; bool csa_countdown; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 19839cc44eb3..34d4b7a94d82 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2021-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -237,8 +237,8 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid, - ETH_ALEN)) + if (ether_addr_equal(mvmvif->uapsd_misbehaving_ap_addr, + vif->cfg.ap_addr)) return false; /* @@ -502,9 +502,9 @@ void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid, - ETH_ALEN)) - eth_zero_addr(mvmvif->uapsd_misbehaving_bssid); + if (!ether_addr_equal(mvmvif->uapsd_misbehaving_ap_addr, + vif->cfg.ap_addr)) + eth_zero_addr(mvmvif->uapsd_misbehaving_ap_addr); } static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac, @@ -512,14 +512,23 @@ static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac, { u8 *ap_sta_id = _data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; - /* The ap_sta_id is not expected to change during current association - * so no explicit protection is needed - */ - if (mvmvif->deflink.ap_sta_id == *ap_sta_id) - memcpy(mvmvif->uapsd_misbehaving_bssid, - vif->bss_conf.bssid, - ETH_ALEN); + rcu_read_lock(); + for_each_vif_active_link(vif, link_conf, link_id) { + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; + + /* The ap_sta_id is not expected to change during current + * association so no explicit protection is needed + */ + if (link_info->ap_sta_id == *ap_sta_id) { + ether_addr_copy(mvmvif->uapsd_misbehaving_ap_addr, + vif->cfg.ap_addr); + break; + } + } + rcu_read_unlock(); } void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, -- cgit v1.2.3 From aedb2b38adf4d9f4f30ebd8b507051498ad4a1f2 Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Wed, 14 Jun 2023 12:41:35 +0300 Subject: wifi: iwlwifi: mvm: Validate tid is in valid range before using it Validate tid is less then MAX TID when it is used to access corresponding arrays. Signed-off-by: Anjaneyulu Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123447.cea75e1f57e7.I03bc0a81d2c1bdbf4784c12c4c62b8538892ccba@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 10 +++++++--- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 9 ++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index b38b24246675..542c192698a4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -213,8 +213,12 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm, }; u16 thr; - if (ieee80211_is_data_qos(hdr->frame_control)) - ac = tid_to_mac80211_ac[ieee80211_get_tid(hdr)]; + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 tid = ieee80211_get_tid(hdr); + + if (tid < IWL_MAX_TID_COUNT) + ac = tid_to_mac80211_ac[tid]; + } mvmsta = iwl_mvm_sta_from_mac80211(sta); mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 5c06839b87c2..9dbe71d299ae 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -484,7 +484,7 @@ static void iwl_mvm_rx_csum(struct iwl_mvm *mvm, } /* - * returns true if a packet is a duplicate and should be dropped. + * returns true if a packet is a duplicate or invalid tid and should be dropped. * Updates AMSDU PN tracking info */ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, @@ -513,11 +513,14 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue, return false; } - if (ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) { /* frame has qos control */ tid = ieee80211_get_tid(hdr); - else + if (tid >= IWL_MAX_TID_COUNT) + return true; + } else { tid = IWL_MAX_TID_COUNT; + } /* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */ sub_frame_idx = desc->amsdu_info & -- cgit v1.2.3 From 2e0ce1de206f8ad27bf07d08238f14c1c2c9ebe8 Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Wed, 14 Jun 2023 12:41:36 +0300 Subject: wifi: iwlwifi: Validate slots_num before allocating memory Verify slots_num is valid in iwl_txq_alloc() Signed-off-by: Anjaneyulu Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123447.90be48017c1b.I880e451e137c5cd688d5f38b573b0dbf352762b3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/queue/tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c index d1c39c214f95..245bff01b4f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2020-2022 Intel Corporation + * Copyright (C) 2020-2023 Intel Corporation */ #include #include @@ -1027,6 +1027,9 @@ int iwl_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, int slots_num, size_t tb0_buf_sz; int i; + if (WARN_ONCE(slots_num <= 0, "Invalid slots num:%d\n", slots_num)) + return -EINVAL; + if (WARN_ON(txq->entries || txq->tfds)) return -EINVAL; -- cgit v1.2.3 From efbe8f81952fe469d38655744627d860879dcde8 Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Wed, 14 Jun 2023 12:41:37 +0300 Subject: wifi: iwlwifi: add a few rate index validity checks Validate index before access iwl_rate_mcs to keep rate->index inside the valid boundaries. Use MCS_0_INDEX if index is less than MCS_0_INDEX and MCS_9_INDEX if index is greater then MCS_9_INDEX. Signed-off-by: Anjaneyulu Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230614123447.79f16b3aef32.If1137f894775d6d07b78cbf3a6163ffce6399507@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 9 ++++++--- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 11 +++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c index 687c906a9d72..4b1f006c105b 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2019 - 2020, 2022 Intel Corporation + * Copyright (C) 2019 - 2020, 2022 - 2023 Intel Corporation *****************************************************************************/ #include #include @@ -125,7 +125,7 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) return idx; } - return -1; + return IWL_RATE_INVALID; } static void rs_rate_scale_perform(struct iwl_priv *priv, @@ -3146,7 +3146,10 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { index = iwl_hwrate_to_plcp_idx( le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); - if (is_legacy(tbl->lq_type)) { + if (index == IWL_RATE_INVALID) { + desc += sprintf(buff + desc, " rate[%d] 0x%X invalid rate\n", + i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); + } else if (is_legacy(tbl->lq_type)) { desc += sprintf(buff+desc, " rate[%d] 0x%X %smbps\n", i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags), iwl_rate_mcs[index].mbps); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 9a20468345e4..481d68cbbbd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** * - * Copyright(c) 2005 - 2014, 2018 - 2022 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014, 2018 - 2023 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH *****************************************************************************/ @@ -1070,10 +1070,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta, rate->bw = RATE_MCS_CHAN_WIDTH_20; - WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX || - rate->index > IWL_RATE_MCS_9_INDEX); + if (WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX)) + rate->index = rs_ht_to_legacy[IWL_RATE_MCS_0_INDEX]; + else if (WARN_ON_ONCE(rate->index > IWL_RATE_MCS_9_INDEX)) + rate->index = rs_ht_to_legacy[IWL_RATE_MCS_9_INDEX]; + else + rate->index = rs_ht_to_legacy[rate->index]; - rate->index = rs_ht_to_legacy[rate->index]; rate->ldpc = false; } else { /* Downgrade to SISO with same MCS if in MIMO */ -- cgit v1.2.3 From 6e21e7b8cd897193cee3c2649640efceb3004ba5 Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Wed, 14 Jun 2023 15:26:48 +0200 Subject: wifi: mac80211: Remove "Missing iftype sband data/EHT cap" spam In mesh mode, ieee80211_chandef_he_6ghz_oper() is called by mesh_matches_local() for every received mesh beacon. On a 6 GHz mesh of a HE-only phy, this spams that the hardware does not have EHT capabilities, even if the received mesh beacon does not have an EHT element. Unlike HE, not supporting EHT in the 6 GHz band is not an error so do not print anything in this case. Fixes: 5dca295dd767 ("mac80211: Add initial support for EHT and 320 MHz channels") Signed-off-by: Nicolas Cavallari Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230614132648.28995-1-nicolas.cavallari@green-communications.fr Signed-off-by: Johannes Berg --- net/mac80211/util.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 2fc07717bcad..ab60a530198b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3880,10 +3880,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata, } eht_cap = ieee80211_get_eht_iftype_cap(sband, iftype); - if (!eht_cap) { - sdata_info(sdata, "Missing iftype sband data/EHT cap"); + if (!eht_cap) eht_oper = NULL; - } he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); -- cgit v1.2.3 From 823a970831c73ca2910da1f5c827c9ce4efa0c02 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 15 Jun 2023 09:47:16 +0300 Subject: wifi: iwlwifi: fix max number of fw active links The max active links that are supported by the FW is hard coded. This is wrong since this value is HW-dependent. Fix this by determining according to the actual HW. Also remove a redundant check that the number of active links doesn't exceeds the maximum. Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230615094410.e78ad74c6715.I68b26911c0a312d72eaf25344b448d03b1c61f4e@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 18 ------------------ .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 6 ++---- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 22 ++++++++++++++++++++++ 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 563396dfd3cd..69ebd844de2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -118,24 +118,6 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (!link_info->phy_ctxt) return 0; - /* check there aren't too many active links */ - if (!link_info->active && active) { - int i, count = 0; - - /* link with phy_ctxt is active in FW */ - for_each_mvm_vif_valid_link(mvmvif, i) - if (mvmvif->link[i]->phy_ctxt) - count++; - - if (vif->type == NL80211_IFTYPE_AP) { - if (count > mvm->fw->ucode_capa.num_beacons) - return -EOPNOTSUPP; - /* this should be per HW or such */ - } else if (count >= IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM) { - return -EOPNOTSUPP; - } - } - /* Catch early if driver tries to activate or deactivate a link * twice. */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 8cd03357ce79..37b5b7f1f153 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -900,9 +900,7 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, u16 added = new_links & ~old_links; int err, i; - if (hweight16(new_links) > 2) { - return -EOPNOTSUPP; - } else if (hweight16(new_links) > 1) { + if (hweight16(new_links) > 1) { unsigned int n_active = 0; for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { @@ -917,7 +915,7 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_AP) { if (n_active > mvm->fw->ucode_capa.num_beacons) return -EOPNOTSUPP; - } else if (n_active > 1) { + } else if (n_active > iwl_mvm_max_active_links(mvm)) { return -EOPNOTSUPP; } } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index de7aa4713c93..35cf0015b362 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1544,6 +1544,28 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CTDP_SUPPORT); } +static inline bool iwl_mvm_is_esr_supported(struct iwl_trans *trans) +{ + if ((CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM) && + !CSR_HW_RFID_IS_CDB(trans->hw_rf_id)) + /* Step A doesn't support eSR */ + return CSR_HW_RFID_STEP(trans->hw_rf_id); + + return false; +} + +static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm) +{ + struct iwl_trans *trans = mvm->fwrt.trans; + + if (iwl_mvm_is_esr_supported(trans) || + (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM && + CSR_HW_RFID_IS_CDB(trans->hw_rf_id))) + return IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM; + + return 1; +} + extern const u8 iwl_mvm_ac_to_tx_fifo[]; extern const u8 iwl_mvm_ac_to_gen2_tx_fifo[]; -- cgit v1.2.3 From 12bacfc2c065319d87a0580cd65375cea8204aba Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Thu, 15 Jun 2023 09:47:17 +0300 Subject: wifi: iwlwifi: handle eSR transitions There several transitions to handle in eSR mode: * SMPS should be disabled when in eSR mode * indicate to the fw whether the new added link should use the listen lmac or the main lmac * RLC is offloaded when in eSR mode; adjust RLC command accordingly Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230615094410.fb6409f44aca.I502460dec15e0b76035ad3cd809afa4ac16e9fe1@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 7 +- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 150 ++++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 12 +- drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 13 +- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 6 +- 5 files changed, 155 insertions(+), 33 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 69ebd844de2a..5fdebb911f7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -89,6 +89,8 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid) memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN); + cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); + return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD); } @@ -149,10 +151,6 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid) memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN); - /* TODO: set a value to cmd.listen_lmac when system requiremens - * will define it - */ - iwl_mvm_set_fw_basic_rates(mvm, vif, link_conf, &cmd.cck_rates, &cmd.ofdm_rates); @@ -228,6 +226,7 @@ send_cmd: cmd.flags = cpu_to_le32(flags); cmd.flags_mask = cpu_to_le32(flags_mask); cmd.spec_link_id = link_conf->link_id; + cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY); if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 37b5b7f1f153..636ad2b76428 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -215,6 +215,53 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&mvm->mutex); } +static unsigned int iwl_mvm_mld_count_active_links(struct ieee80211_vif *vif) +{ + unsigned int n_active = 0; + int i; + + for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { + struct ieee80211_bss_conf *link_conf; + + link_conf = link_conf_dereference_protected(vif, i); + if (link_conf && + rcu_access_pointer(link_conf->chanctx_conf)) + n_active++; + } + + return n_active; +} + +static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int link_id, ret = 0; + + mvmvif->esr_active = true; + + /* Disable SMPS overrideing by user */ + vif->driver_flags |= IEEE80211_VIF_DISABLE_SMPS_OVERRIDE; + + iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW, + IEEE80211_SMPS_OFF); + + for_each_mvm_vif_valid_link(mvmvif, link_id) { + struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id]; + + if (!link->phy_ctxt) + continue; + + ret = iwl_mvm_phy_send_rlc(mvm, link->phy_ctxt, 2, 2); + if (ret) + break; + + link->phy_ctxt->rlc_disabled = true; + } + + return ret; +} + static int __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -224,10 +271,18 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, { u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; + unsigned int n_active = iwl_mvm_mld_count_active_links(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); unsigned int link_id = link_conf->link_id; int ret; + /* if the assigned one was not counted yet, count it now */ + if (!rcu_access_pointer(link_conf->chanctx_conf)) + n_active++; + + if (n_active > iwl_mvm_max_active_links(mvm, vif)) + return -EOPNOTSUPP; + if (WARN_ON_ONCE(!mvmvif->link[link_id])) return -EINVAL; @@ -243,6 +298,15 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, } } + if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) { + mvmvif->link[link_id]->listen_lmac = true; + ret = iwl_mvm_esr_mode_active(mvm, vif); + if (ret) { + IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret); + return ret; + } + } + mvmvif->link[link_id]->phy_ctxt = phy_ctxt; if (switching_chanctx) { @@ -326,14 +390,62 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw, return ret; } +static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_bss_conf *link_conf; + int link_id, ret = 0; + + mvmvif->esr_active = false; + + vif->driver_flags &= ~IEEE80211_VIF_DISABLE_SMPS_OVERRIDE; + + iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW, + IEEE80211_SMPS_AUTOMATIC); + + for_each_vif_active_link(vif, link_conf, link_id) { + struct ieee80211_chanctx_conf *chanctx_conf; + struct iwl_mvm_phy_ctxt *phy_ctxt; + u8 static_chains, dynamic_chains; + + mvmvif->link[link_id]->listen_lmac = false; + + rcu_read_lock(); + + chanctx_conf = rcu_dereference(link_conf->chanctx_conf); + phy_ctxt = mvmvif->link[link_id]->phy_ctxt; + + if (!chanctx_conf || !phy_ctxt) { + rcu_read_unlock(); + continue; + } + + phy_ctxt->rlc_disabled = false; + static_chains = chanctx_conf->rx_chains_static; + dynamic_chains = chanctx_conf->rx_chains_dynamic; + + rcu_read_unlock(); + + ret = iwl_mvm_phy_send_rlc(mvm, phy_ctxt, static_chains, + dynamic_chains); + if (ret) + break; + } + + return ret; +} + static void __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx, bool switching_chanctx) + { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + unsigned int n_active = iwl_mvm_mld_count_active_links(vif); unsigned int link_id = link_conf->link_id; /* shouldn't happen, but verify link_id is valid before accessing */ @@ -352,6 +464,14 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, mvmvif->ap_ibss_active = false; } + if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) { + int ret = iwl_mvm_esr_mode_inactive(mvm, vif); + + if (ret) + IWL_ERR(mvm, "failed to deactivate ESR mode (%d)\n", + ret); + } + if (vif->type == NL80211_IFTYPE_MONITOR) iwl_mvm_mld_rm_snif_sta(mvm, vif); @@ -894,31 +1014,16 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) { struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {}; + unsigned int n_active = iwl_mvm_mld_count_active_links(vif); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); u16 removed = old_links & ~new_links; u16 added = new_links & ~old_links; int err, i; - if (hweight16(new_links) > 1) { - unsigned int n_active = 0; - - for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { - struct ieee80211_bss_conf *link_conf; - - link_conf = link_conf_dereference_protected(vif, i); - if (link_conf && - rcu_access_pointer(link_conf->chanctx_conf)) - n_active++; - } - - if (vif->type == NL80211_IFTYPE_AP) { - if (n_active > mvm->fw->ucode_capa.num_beacons) - return -EOPNOTSUPP; - } else if (n_active > iwl_mvm_max_active_links(mvm)) { - return -EOPNOTSUPP; - } - } + if (hweight16(new_links) > 1 && + n_active > iwl_mvm_max_active_links(mvm, vif)) + return -EOPNOTSUPP; for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { int r; @@ -962,9 +1067,7 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, goto out_err; kfree(mvmvif->link[i]); mvmvif->link[i] = NULL; - } - - if (added & BIT(i)) { + } else if (added & BIT(i)) { struct ieee80211_bss_conf *link_conf; link_conf = link_conf_dereference_protected(vif, i); @@ -981,6 +1084,9 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, } } + if (err) + goto out_err; + err = 0; if (new_links == 0) { mvmvif->link[0] = &mvmvif->deflink; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 35cf0015b362..11de81b58515 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -104,6 +104,7 @@ struct iwl_mvm_phy_ctxt { /* track for RLC config command */ u32 center_freq1; + bool rlc_disabled; }; struct iwl_mvm_time_event_data { @@ -301,6 +302,7 @@ struct iwl_probe_resp_data { * @queue_params: QoS params for this MAC * @mgmt_queue: queue number for unbufferable management frames * @igtk: the current IGTK programmed into the firmware + * @listen_lmac: indicates this link is allocated to the listen LMAC */ struct iwl_mvm_vif_link_info { u8 bssid[ETH_ALEN]; @@ -322,6 +324,7 @@ struct iwl_mvm_vif_link_info { bool he_ru_2mhz_block; bool active; + bool listen_lmac; u16 cab_queue; /* Assigned while mac80211 has the link in a channel context, @@ -373,6 +376,7 @@ struct iwl_mvm_vif { bool ap_ibss_active; bool pm_enabled; bool monitor_active; + bool esr_active; u8 low_latency: 6; u8 low_latency_actual: 1; @@ -1554,10 +1558,14 @@ static inline bool iwl_mvm_is_esr_supported(struct iwl_trans *trans) return false; } -static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm) +static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) { struct iwl_trans *trans = mvm->fwrt.trans; + if (vif->type == NL80211_IFTYPE_AP) + return mvm->fw->ucode_capa.num_beacons; + if (iwl_mvm_is_esr_supported(trans) || (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM && CSR_HW_RFID_IS_CDB(trans->hw_rf_id))) @@ -1777,6 +1785,8 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm); u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef); u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef); +int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, + u8 chains_static, u8 chains_dynamic); /* MAC (virtual interface) programming */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 55541e90770a..a5b432bc9e2f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -163,15 +163,18 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, chains_static, chains_dynamic); } -static int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, - struct iwl_mvm_phy_ctxt *ctxt, - u8 chains_static, u8 chains_dynamic) +int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, + u8 chains_static, u8 chains_dynamic) { struct iwl_rlc_config_cmd cmd = { .phy_id = cpu_to_le32(ctxt->id), }; - if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(DATA_PATH_GROUP, RLC_CONFIG_CMD), 0) < 2) + if (ctxt->rlc_disabled) + return 0; + + if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(DATA_PATH_GROUP, + RLC_CONFIG_CMD), 0) < 2) return 0; BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_DRIVER_FORCE != diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 2a10d851d2e4..48016b4343d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -312,6 +312,10 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, smps_mode = IEEE80211_SMPS_DYNAMIC; } + /* SMPS is disabled in eSR */ + if (mvmvif->esr_active) + smps_mode = IEEE80211_SMPS_OFF; + ieee80211_request_smps(vif, link_id, smps_mode); } -- cgit v1.2.3 From 98d8a00327b2b651f2a00d6d16c6df886fdbf101 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 15 Jun 2023 09:47:18 +0300 Subject: wifi: iwlwifi: mvm: Don't access vif valid links directly And instead use the vif getter functions, as a preparation for supporting disabled/dormant links. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230615094410.61ca688cbbf1.Ic1b4049cf156238ff16e6c57959004da911cb5c8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index a2583d045525..b8143ae8b403 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -893,7 +893,7 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm, u8 rate; u32 i; - if (link_id == IEEE80211_LINK_UNSPECIFIED && vif->valid_links) { + if (link_id == IEEE80211_LINK_UNSPECIFIED && ieee80211_vif_is_mld(vif)) { for (i = 0; i < ARRAY_SIZE(mvmvif->link); i++) { if (!mvmvif->link[i]) continue; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index b27f6a70f8d1..2c9f2f71b083 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c @@ -42,7 +42,7 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm, * Of course the same can be done during add as well, but we must do * it during remove, since we don't have the mvmvif->ap_sta pointer. */ - if (!sta && (keyconf->link_id >= 0 || !vif->valid_links)) + if (!sta && (keyconf->link_id >= 0 || !ieee80211_vif_is_mld(vif))) return BIT(link_info->ap_sta_id); /* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 0ff99deb0ae7..f313a8d771e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 Intel Corporation + * Copyright (C) 2022 - 2023 Intel Corporation */ #include "mvm.h" @@ -50,7 +50,7 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, * the association response successfully, so just skip all that * and enable both when we have MLO. */ - if (vif->valid_links) { + if (ieee80211_vif_is_mld(vif)) { iwl_mvm_mld_set_he_support(mvm, vif, cmd); cmd->eht_support = cpu_to_le32(1); return; -- cgit v1.2.3 From e98b23d0d7b85e883216e44b12b2a8fe9a8264ff Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Thu, 15 Jun 2023 09:47:19 +0300 Subject: wifi: iwlwifi: mvm: Add support for SCAN API version 16 Scan API version 16 use link ID for reporting the TSF of scan results (instead of MAC ID used in previous versions). Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230615094410.05bf3e612297.Ie3075f7068af38c335d26778ab7d0ec4b1c026c3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 23 ++++++------ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 46 ++++++++++++++++++------ 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index ec96ba053a5c..9cbeef16cfe5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1003,7 +1003,8 @@ struct iwl_scan_channel_params_v6 { * struct iwl_scan_general_params_v11 * @flags: &enum iwl_umac_scan_general_flags_v2 * @reserved: reserved for future - * @scan_start_mac_id: report the scan start TSF time according to this mac TSF + * @scan_start_mac_or_link_id: report the scan start TSF time according to this + * mac (up to verion 11) or link (starting with version 12) TSF * @active_dwell: dwell time for active scan per LMAC * @adwell_default_2g: adaptive dwell default number of APs * for 2.4GHz channel @@ -1026,7 +1027,7 @@ struct iwl_scan_channel_params_v6 { struct iwl_scan_general_params_v11 { __le16 flags; u8 reserved; - u8 scan_start_mac_id; + u8 scan_start_mac_or_link_id; u8 active_dwell[SCAN_TWO_LMACS]; u8 adwell_default_2g; u8 adwell_default_5g; @@ -1038,7 +1039,7 @@ struct iwl_scan_general_params_v11 { __le32 scan_priority; u8 passive_dwell[SCAN_TWO_LMACS]; u8 num_of_fragments[SCAN_TWO_LMACS]; -} __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_11 and *_VER_10 */ +} __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_12, *_VER_11 and *_VER_10 */ /** * struct iwl_scan_periodic_parms_v1 @@ -1067,18 +1068,18 @@ struct iwl_scan_req_params_v12 { } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_12 */ /** - * struct iwl_scan_req_params_v15 + * struct iwl_scan_req_params_v16 * @general_params: &struct iwl_scan_general_params_v11 * @channel_params: &struct iwl_scan_channel_params_v6 * @periodic_params: &struct iwl_scan_periodic_parms_v1 * @probe_params: &struct iwl_scan_probe_params_v4 */ -struct iwl_scan_req_params_v15 { +struct iwl_scan_req_params_v16 { struct iwl_scan_general_params_v11 general_params; struct iwl_scan_channel_params_v6 channel_params; struct iwl_scan_periodic_parms_v1 periodic_params; struct iwl_scan_probe_params_v4 probe_params; -} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_15 and *_VER_14 */ +} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_16, *_VER_15 and *_VER_14 */ /** * struct iwl_scan_req_umac_v12 @@ -1093,16 +1094,16 @@ struct iwl_scan_req_umac_v12 { } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_12 */ /** - * struct iwl_scan_req_umac_v15 + * struct iwl_scan_req_umac_v16 * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @scan_params: scan parameters */ -struct iwl_scan_req_umac_v15 { +struct iwl_scan_req_umac_v16 { __le32 uid; __le32 ooc_priority; - struct iwl_scan_req_params_v15 scan_params; -} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_15 and *_VER_14 */ + struct iwl_scan_req_params_v16 scan_params; +} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_16, *_VER_15 and *_VER_14 */ /** * struct iwl_umac_scan_abort diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index d7ac9ddbcfba..b2154e9fcf01 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -2292,11 +2292,12 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, } static void -iwl_mvm_scan_umac_fill_general_p_v11(struct iwl_mvm *mvm, +iwl_mvm_scan_umac_fill_general_p_v12(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif, struct iwl_scan_general_params_v11 *gp, - u16 gen_flags, u8 gen_flags2) + u16 gen_flags, u8 gen_flags2, + u32 version) { struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); @@ -2313,7 +2314,23 @@ iwl_mvm_scan_umac_fill_general_p_v11(struct iwl_mvm *mvm, if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; - gp->scan_start_mac_id = scan_vif->id; + if (version < 12) { + gp->scan_start_mac_or_link_id = scan_vif->id; + } else { + struct iwl_mvm_vif_link_info *link_info; + u8 link_id = 0; + + /* Use one of the active link (if any). In the future it would + * be possible that the link ID would be part of the scan + * request coming from upper layers so we would need to use it. + */ + if (vif->active_links) + link_id = ffs(vif->active_links) - 1; + + link_info = scan_vif->link[link_id]; + if (!WARN_ON(!link_info)) + gp->scan_start_mac_or_link_id = link_info->fw_link_id; + } } static void @@ -2408,9 +2425,9 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->uid = cpu_to_le32(uid); gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); - iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif, + iwl_mvm_scan_umac_fill_general_p_v12(mvm, params, vif, &scan_p->general_params, - gen_flags, 0); + gen_flags, 0, 12); ret = iwl_mvm_fill_scan_sched_params(params, scan_p->periodic_params.schedule, @@ -2430,8 +2447,8 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, int type, int uid, u32 version) { - struct iwl_scan_req_umac_v15 *cmd = mvm->scan_cmd; - struct iwl_scan_req_params_v15 *scan_p = &cmd->scan_params; + struct iwl_scan_req_umac_v16 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v16 *scan_p = &cmd->scan_params; struct iwl_scan_channel_params_v6 *cp = &scan_p->channel_params; struct iwl_scan_probe_params_v4 *pb = &scan_p->probe_params; int ret; @@ -2451,9 +2468,9 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, else gen_flags2 = 0; - iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif, + iwl_mvm_scan_umac_fill_general_p_v12(mvm, params, vif, &scan_p->general_params, - gen_flags, gen_flags2); + gen_flags, gen_flags2, version); ret = iwl_mvm_fill_scan_sched_params(params, scan_p->periodic_params.schedule, @@ -2507,6 +2524,13 @@ static int iwl_mvm_scan_umac_v15(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 15); } +static int iwl_mvm_scan_umac_v16(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 16); +} + static int iwl_mvm_num_scans(struct iwl_mvm *mvm) { return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); @@ -2622,6 +2646,7 @@ struct iwl_scan_umac_handler { static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { /* set the newest version first to shorten the list traverse time */ + IWL_SCAN_UMAC_HANDLER(16), IWL_SCAN_UMAC_HANDLER(15), IWL_SCAN_UMAC_HANDLER(14), IWL_SCAN_UMAC_HANDLER(12), @@ -3210,7 +3235,8 @@ static size_t iwl_scan_req_umac_get_size(u8 scan_ver) return sizeof(struct iwl_scan_req_umac_v12); case 14: case 15: - return sizeof(struct iwl_scan_req_umac_v15); + case 16: + return sizeof(struct iwl_scan_req_umac_v16); } return 0; -- cgit v1.2.3 From dd5ff2aa84170d3b55874385ca54ee5715b56cbb Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Thu, 15 Jun 2023 09:47:20 +0300 Subject: wifi: iwlwifi: bump FW API to 81 for AX devices Start supporting API version 81 for AX devices. Signed-off-by: Gregory Greenman Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230615094410.e61fdc474d89.I3d9823231fa7fc47158b8aa3561b43822c8c86cd@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 29dded1531a0..5ac9416331de 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include #include @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 79 +#define IWL_22000_UCODE_API_MAX 81 #define IWL_22500_UCODE_API_MAX 77 /* Lowest firmware API version supported */ -- cgit v1.2.3 From 71e7552c90db2a2767f5c17c7ec72296b0d92061 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 15 Jun 2023 12:04:07 -0600 Subject: wifi: wext-core: Fix -Wstringop-overflow warning in ioctl_standard_iw_point() -Wstringop-overflow is legitimately warning us about extra_size pontentially being zero at some point, hence potenially ending up _allocating_ zero bytes of memory for extra pointer and then trying to access such object in a call to copy_from_user(). Fix this by adding a sanity check to ensure we never end up trying to allocate zero bytes of data for extra pointer, before continue executing the rest of the code in the function. Address the following -Wstringop-overflow warning seen when built m68k architecture with allyesconfig configuration: from net/wireless/wext-core.c:11: In function '_copy_from_user', inlined from 'copy_from_user' at include/linux/uaccess.h:183:7, inlined from 'ioctl_standard_iw_point' at net/wireless/wext-core.c:825:7: arch/m68k/include/asm/string.h:48:25: warning: '__builtin_memset' writing 1 or more bytes into a region of size 0 overflows the destination [-Wstringop-overflow=] 48 | #define memset(d, c, n) __builtin_memset(d, c, n) | ^~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/uaccess.h:153:17: note: in expansion of macro 'memset' 153 | memset(to + (n - res), 0, res); | ^~~~~~ In function 'kmalloc', inlined from 'kzalloc' at include/linux/slab.h:694:9, inlined from 'ioctl_standard_iw_point' at net/wireless/wext-core.c:819:10: include/linux/slab.h:577:16: note: at offset 1 into destination object of size 0 allocated by '__kmalloc' 577 | return __kmalloc(size, flags); | ^~~~~~~~~~~~~~~~~~~~~~ This help with the ongoing efforts to globally enable -Wstringop-overflow. Link: https://github.com/KSPP/linux/issues/315 Signed-off-by: Gustavo A. R. Silva Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/ZItSlzvIpjdjNfd8@work Signed-off-by: Johannes Berg --- net/wireless/wext-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index a125fd1fa134..a161c64d1765 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -815,6 +815,12 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, } } + /* Sanity-check to ensure we never end up _allocating_ zero + * bytes of data for extra. + */ + if (extra_size <= 0) + return -EFAULT; + /* kzalloc() ensures NULL-termination for essid_compat. */ extra = kzalloc(extra_size, GFP_KERNEL); if (!extra) -- cgit v1.2.3 From c6112046b1a9c130c455ab0bbe74c3f41138693c Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Fri, 16 Jun 2023 09:53:50 +0300 Subject: wifi: cfg80211: make TDLS management link-aware For multi-link operation(MLO) TDLS management frames need to be transmitted on a specific link. The TDLS setup request will add BSSID along with peer address and userspace will pass the link-id based on BSSID value to the driver(or mac80211). Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.cb3d87c22812.Ia3d15ac4a9a182145bf2d418bcb3ddf4539cd0a7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 8 ++++---- include/net/cfg80211.h | 7 ++++--- net/mac80211/ieee80211_i.h | 8 ++++---- net/mac80211/tdls.c | 10 +++++----- net/wireless/nl80211.c | 7 +++++-- net/wireless/rdev-ops.h | 15 ++++++++------- net/wireless/trace.h | 13 ++++++++----- 7 files changed, 38 insertions(+), 30 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index bcd564dc3554..1ef89cdcaa59 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3753,10 +3753,10 @@ static int mwifiex_cfg80211_set_coalesce(struct wiphy *wiphy, */ static int mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, u32 peer_capability, - bool initiator, const u8 *extra_ies, - size_t extra_ies_len) + const u8 *peer, int link_id, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *extra_ies, size_t extra_ies_len) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int ret; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 388f2a3851a2..3ca581845206 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4607,9 +4607,10 @@ struct cfg80211_ops { struct cfg80211_gtk_rekey_data *data); int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, u32 peer_capability, - bool initiator, const u8 *buf, size_t len); + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *buf, size_t len); int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4afd5095366c..ca8a1e1c8bbd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2565,10 +2565,10 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, /* TDLS */ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, u32 peer_capability, - bool initiator, const u8 *extra_ies, - size_t extra_ies_len); + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *extra_ies, size_t extra_ies_len); int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper); void ieee80211_tdls_peer_del_work(struct work_struct *wk); diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 52c47674a554..6575b2801676 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -6,7 +6,7 @@ * Copyright 2014, Intel Corporation * Copyright 2014 Intel Mobile Communications GmbH * Copyright 2015 - 2016 Intel Deutschland GmbH - * Copyright (C) 2019, 2021-2022 Intel Corporation + * Copyright (C) 2019, 2021-2023 Intel Corporation */ #include @@ -1185,10 +1185,10 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, } int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, - u16 status_code, u32 peer_capability, - bool initiator, const u8 *extra_ies, - size_t extra_ies_len) + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *extra_ies, size_t extra_ies_len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); int ret; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ec7d467cb096..7b547aeb52f1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12262,6 +12262,7 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) u32 peer_capability = 0; u16 status_code; u8 *peer; + int link_id; bool initiator; if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) || @@ -12283,8 +12284,9 @@ static int nl80211_tdls_mgmt(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]) peer_capability = nla_get_u32(info->attrs[NL80211_ATTR_TDLS_PEER_CAPABILITY]); + link_id = nl80211_link_id_or_invalid(info->attrs); - return rdev_tdls_mgmt(rdev, dev, peer, action_code, + return rdev_tdls_mgmt(rdev, dev, peer, link_id, action_code, dialog_token, status_code, peer_capability, initiator, nla_data(info->attrs[NL80211_ATTR_IE]), @@ -17151,7 +17153,8 @@ static const struct genl_small_ops nl80211_small_ops[] = { .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, .doit = nl80211_tdls_mgmt, .flags = GENL_UNS_ADMIN_PERM, - .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP), + .internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP | + NL80211_FLAG_MLO_VALID_LINK_ID), }, { .cmd = NL80211_CMD_TDLS_OPER, diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 69b508743e57..f8c310849438 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -899,17 +899,18 @@ static inline int rdev_set_rekey_data(struct cfg80211_registered_device *rdev, static inline int rdev_tdls_mgmt(struct cfg80211_registered_device *rdev, struct net_device *dev, u8 *peer, - u8 action_code, u8 dialog_token, - u16 status_code, u32 peer_capability, - bool initiator, const u8 *buf, size_t len) + int link_id, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *buf, size_t len) { int ret; - trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, action_code, + trace_rdev_tdls_mgmt(&rdev->wiphy, dev, peer, link_id, action_code, dialog_token, status_code, peer_capability, initiator, buf, len); - ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, action_code, - dialog_token, status_code, peer_capability, - initiator, buf, len); + ret = rdev->ops->tdls_mgmt(&rdev->wiphy, dev, peer, link_id, + action_code, dialog_token, status_code, + peer_capability, initiator, buf, len); trace_rdev_return_int(&rdev->wiphy, ret); return ret; } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index a00da3ebfed5..73a4f8f57438 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1779,15 +1779,16 @@ DEFINE_EVENT(wiphy_netdev_id_evt, rdev_sched_scan_stop, TRACE_EVENT(rdev_tdls_mgmt, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, - u8 *peer, u8 action_code, u8 dialog_token, + u8 *peer, int link_id, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, bool initiator, const u8 *buf, size_t len), - TP_ARGS(wiphy, netdev, peer, action_code, dialog_token, status_code, - peer_capability, initiator, buf, len), + TP_ARGS(wiphy, netdev, peer, link_id, action_code, dialog_token, + status_code, peer_capability, initiator, buf, len), TP_STRUCT__entry( WIPHY_ENTRY NETDEV_ENTRY MAC_ENTRY(peer) + __field(int, link_id) __field(u8, action_code) __field(u8, dialog_token) __field(u16, status_code) @@ -1799,6 +1800,7 @@ TRACE_EVENT(rdev_tdls_mgmt, WIPHY_ASSIGN; NETDEV_ASSIGN; MAC_ASSIGN(peer, peer); + __entry->link_id = link_id; __entry->action_code = action_code; __entry->dialog_token = dialog_token; __entry->status_code = status_code; @@ -1806,11 +1808,12 @@ TRACE_EVENT(rdev_tdls_mgmt, __entry->initiator = initiator; memcpy(__get_dynamic_array(buf), buf, len); ), - TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", %pM, action_code: %u, " + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", %pM" + ", link_id: %d, action_code: %u " "dialog_token: %u, status_code: %u, peer_capability: %u " "initiator: %s buf: %#.2x ", WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->peer, - __entry->action_code, __entry->dialog_token, + __entry->link_id, __entry->action_code, __entry->dialog_token, __entry->status_code, __entry->peer_capability, BOOL_TO_STR(__entry->initiator), ((u8 *)__get_dynamic_array(buf))[0]) -- cgit v1.2.3 From 78a7ea370d5f0eb6f3e774e7f6afece1c3a6860f Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Fri, 16 Jun 2023 09:53:51 +0300 Subject: wifi: mac80211: handle TDLS negotiation with MLO Userspace can now select the link to use for TDLS management frames (indicating e.g. which BSSID should be used), use the link_id received from cfg80211 to build the frames. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.ce1fc230b505.Ie773c5679805001f5a52680d68d9ce0232c57648@changeid [Benjamin fixed some locking] Co-developed-by: Benjamin Berg Signed-off-by: Benjamin Berg [fix sta mutex locking too] Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 163 +++++++++++++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 72 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 6575b2801676..a920e2a7a978 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -39,9 +39,10 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) mutex_unlock(&local->mtx); } -static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata, +static void ieee80211_tdls_add_ext_capab(struct ieee80211_link_data *link, struct sk_buff *skb) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; bool chan_switch = local->hw.wiphy->features & @@ -50,7 +51,7 @@ static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata, !ifmgd->tdls_wider_bw_prohibited; bool buffer_sta = ieee80211_hw_check(&local->hw, SUPPORTS_TDLS_BUFFER_STA); - struct ieee80211_supported_band *sband = ieee80211_get_sband(sdata); + struct ieee80211_supported_band *sband = ieee80211_get_link_sband(link); bool vht = sband && sband->vht_cap.vht_supported; u8 *pos = skb_put(skb, 10); @@ -152,13 +153,13 @@ ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata, *pos = 2 * subband_cnt; } -static void ieee80211_tdls_add_oper_classes(struct ieee80211_sub_if_data *sdata, +static void ieee80211_tdls_add_oper_classes(struct ieee80211_link_data *link, struct sk_buff *skb) { u8 *pos; u8 op_class; - if (!ieee80211_chandef_to_operating_class(&sdata->vif.bss_conf.chandef, + if (!ieee80211_chandef_to_operating_class(&link->conf->chandef, &op_class)) return; @@ -180,7 +181,7 @@ static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) *pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST; } -static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, +static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_link_data *link, u16 status_code) { struct ieee80211_supported_band *sband; @@ -189,7 +190,8 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, if (status_code != 0) return 0; - sband = ieee80211_get_sband(sdata); + sband = ieee80211_get_link_sband(link); + if (sband && sband->band == NL80211_BAND_2GHZ) { return WLAN_CAPABILITY_SHORT_SLOT_TIME | WLAN_CAPABILITY_SHORT_PREAMBLE; @@ -198,10 +200,11 @@ static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, return 0; } -static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, +static void ieee80211_tdls_add_link_ie(struct ieee80211_link_data *link, struct sk_buff *skb, const u8 *peer, bool initiator) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_tdls_lnkie *lnkid; const u8 *init_addr, *rsp_addr; @@ -218,7 +221,7 @@ static void ieee80211_tdls_add_link_ie(struct ieee80211_sub_if_data *sdata, lnkid->ie_type = WLAN_EID_LINK_ID; lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2; - memcpy(lnkid->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN); + memcpy(lnkid->bssid, link->u.mgd.bssid, ETH_ALEN); memcpy(lnkid->init_sta, init_addr, ETH_ALEN); memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN); } @@ -359,11 +362,12 @@ ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, } static void -ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, +ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, struct sk_buff *skb, const u8 *peer, u8 action_code, bool initiator, const u8 *extra_ies, size_t extra_ies_len) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_supported_band *sband; struct ieee80211_local *local = sdata->local; struct ieee80211_sta_ht_cap ht_cap; @@ -372,8 +376,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, size_t offset = 0, noffset; u8 *pos; - sband = ieee80211_get_sband(sdata); - if (!sband) + sband = ieee80211_get_link_sband(link); + if (WARN_ON_ONCE(!sband)) return; ieee80211_add_srates_ie(sdata, skb, false, sband->band); @@ -397,7 +401,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, offset = noffset; } - ieee80211_tdls_add_ext_capab(sdata, skb); + ieee80211_tdls_add_ext_capab(link, skb); /* add the QoS element if we support it */ if (local->hw.queues >= IEEE80211_NUM_ACS && @@ -426,20 +430,16 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, offset = noffset; } - mutex_lock(&local->sta_mtx); - /* we should have the peer STA if we're already responding */ if (action_code == WLAN_TDLS_SETUP_RESPONSE) { sta = sta_info_get(sdata, peer); - if (WARN_ON_ONCE(!sta)) { - mutex_unlock(&local->sta_mtx); + if (WARN_ON_ONCE(!sta)) return; - } - sta->tdls_chandef = sdata->vif.bss_conf.chandef; + sta->tdls_chandef = link->conf->chandef; } - ieee80211_tdls_add_oper_classes(sdata, skb); + ieee80211_tdls_add_oper_classes(link, skb); /* * with TDLS we can switch channels, and HT-caps are not necessarily @@ -472,7 +472,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, (ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) ieee80211_tdls_add_bss_coex_ie(skb); - ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); + ieee80211_tdls_add_link_ie(link, skb, peer, initiator); /* add any custom IEs that go before VHT capabilities */ if (extra_ies_len) { @@ -529,8 +529,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_chandef_vht_upgrade(sdata, sta); } - mutex_unlock(&local->sta_mtx); - /* add any remaining IEs */ if (extra_ies_len) { noffset = extra_ies_len; @@ -540,31 +538,29 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, } static void -ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, +ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_link_data *link, struct sk_buff *skb, const u8 *peer, bool initiator, const u8 *extra_ies, size_t extra_ies_len) { + struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_local *local = sdata->local; size_t offset = 0, noffset; struct sta_info *sta, *ap_sta; struct ieee80211_supported_band *sband; u8 *pos; - sband = ieee80211_get_sband(sdata); - if (!sband) + sband = ieee80211_get_link_sband(link); + if (WARN_ON_ONCE(!sband)) return; - mutex_lock(&local->sta_mtx); - sta = sta_info_get(sdata, peer); - ap_sta = sta_info_get(sdata, sdata->deflink.u.mgd.bssid); - if (WARN_ON_ONCE(!sta || !ap_sta)) { - mutex_unlock(&local->sta_mtx); + ap_sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr); + + if (WARN_ON_ONCE(!sta || !ap_sta)) return; - } - sta->tdls_chandef = sdata->vif.bss_conf.chandef; + sta->tdls_chandef = link->conf->chandef; /* add any custom IEs that go before the QoS IE */ if (extra_ies_len) { @@ -610,11 +606,11 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); ieee80211_ie_build_ht_oper(pos, &sta->sta.deflink.ht_cap, - &sdata->vif.bss_conf.chandef, prot, + &link->conf->chandef, prot, true); } - ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); + ieee80211_tdls_add_link_ie(link, skb, peer, initiator); /* only include VHT-operation if not on the 2.4GHz band */ if (sband->band != NL80211_BAND_2GHZ && @@ -631,8 +627,6 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, &sta->tdls_chandef); } - mutex_unlock(&local->sta_mtx); - /* add any remaining IEs */ if (extra_ies_len) { noffset = extra_ies_len; @@ -641,7 +635,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, } static void -ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, +ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_link_data *link, struct sk_buff *skb, const u8 *peer, bool initiator, const u8 *extra_ies, size_t extra_ies_len, u8 oper_class, @@ -670,7 +664,7 @@ ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, offset = noffset; } - ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); + ieee80211_tdls_add_link_ie(link, skb, peer, initiator); /* add any remaining IEs */ if (extra_ies_len) { @@ -680,20 +674,20 @@ ieee80211_tdls_add_chan_switch_req_ies(struct ieee80211_sub_if_data *sdata, } static void -ieee80211_tdls_add_chan_switch_resp_ies(struct ieee80211_sub_if_data *sdata, +ieee80211_tdls_add_chan_switch_resp_ies(struct ieee80211_link_data *link, struct sk_buff *skb, const u8 *peer, u16 status_code, bool initiator, const u8 *extra_ies, size_t extra_ies_len) { if (status_code == 0) - ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); + ieee80211_tdls_add_link_ie(link, skb, peer, initiator); if (extra_ies_len) skb_put_data(skb, extra_ies, extra_ies_len); } -static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, +static void ieee80211_tdls_add_ies(struct ieee80211_link_data *link, struct sk_buff *skb, const u8 *peer, u8 action_code, u16 status_code, bool initiator, const u8 *extra_ies, @@ -705,7 +699,8 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, case WLAN_TDLS_SETUP_RESPONSE: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: if (status_code == 0) - ieee80211_tdls_add_setup_start_ies(sdata, skb, peer, + ieee80211_tdls_add_setup_start_ies(link, + skb, peer, action_code, initiator, extra_ies, @@ -713,7 +708,7 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, break; case WLAN_TDLS_SETUP_CONFIRM: if (status_code == 0) - ieee80211_tdls_add_setup_cfm_ies(sdata, skb, peer, + ieee80211_tdls_add_setup_cfm_ies(link, skb, peer, initiator, extra_ies, extra_ies_len); break; @@ -722,16 +717,17 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, if (extra_ies_len) skb_put_data(skb, extra_ies, extra_ies_len); if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN) - ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); + ieee80211_tdls_add_link_ie(link, skb, + peer, initiator); break; case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: - ieee80211_tdls_add_chan_switch_req_ies(sdata, skb, peer, + ieee80211_tdls_add_chan_switch_req_ies(link, skb, peer, initiator, extra_ies, extra_ies_len, oper_class, chandef); break; case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: - ieee80211_tdls_add_chan_switch_resp_ies(sdata, skb, peer, + ieee80211_tdls_add_chan_switch_resp_ies(link, skb, peer, status_code, initiator, extra_ies, extra_ies_len); @@ -742,6 +738,7 @@ static void ieee80211_tdls_add_ies(struct ieee80211_sub_if_data *sdata, static int ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_link_data *link, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, struct sk_buff *skb) { @@ -766,7 +763,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, skb_put(skb, sizeof(tf->u.setup_req)); tf->u.setup_req.dialog_token = dialog_token; tf->u.setup_req.capability = - cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, + cpu_to_le16(ieee80211_get_tdls_sta_capab(link, status_code)); break; case WLAN_TDLS_SETUP_RESPONSE: @@ -777,7 +774,7 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_resp.status_code = cpu_to_le16(status_code); tf->u.setup_resp.dialog_token = dialog_token; tf->u.setup_resp.capability = - cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, + cpu_to_le16(ieee80211_get_tdls_sta_capab(link, status_code)); break; case WLAN_TDLS_SETUP_CONFIRM: @@ -824,7 +821,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, static int ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, + const u8 *peer, struct ieee80211_link_data *link, + u8 action_code, u8 dialog_token, u16 status_code, struct sk_buff *skb) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -833,8 +831,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, mgmt = skb_put_zero(skb, 24); memcpy(mgmt->da, peer, ETH_ALEN); memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); - memcpy(mgmt->bssid, sdata->deflink.u.mgd.bssid, ETH_ALEN); - + memcpy(mgmt->bssid, link->u.mgd.bssid, ETH_ALEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); @@ -847,7 +844,7 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, mgmt->u.action.u.tdls_discover_resp.dialog_token = dialog_token; mgmt->u.action.u.tdls_discover_resp.capability = - cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata, + cpu_to_le16(ieee80211_get_tdls_sta_capab(link, status_code)); break; default: @@ -859,15 +856,23 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, static struct sk_buff * ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, - const u8 *peer, u8 action_code, - u8 dialog_token, u16 status_code, - bool initiator, const u8 *extra_ies, - size_t extra_ies_len, u8 oper_class, + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, + u16 status_code, bool initiator, + const u8 *extra_ies, size_t extra_ies_len, + u8 oper_class, struct cfg80211_chan_def *chandef) { struct ieee80211_local *local = sdata->local; struct sk_buff *skb; int ret; + struct ieee80211_link_data *link; + + link_id = link_id >= 0 ? link_id : 0; + rcu_read_lock(); + link = rcu_dereference(sdata->link[link_id]); + if (WARN_ON(!link)) + goto unlock; skb = netdev_alloc_skb(sdata->dev, local->hw.extra_tx_headroom + @@ -887,7 +892,7 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, extra_ies_len + sizeof(struct ieee80211_tdls_lnkie)); if (!skb) - return NULL; + goto unlock; skb_reserve(skb, local->hw.extra_tx_headroom); @@ -900,13 +905,13 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, case WLAN_TDLS_CHANNEL_SWITCH_REQUEST: case WLAN_TDLS_CHANNEL_SWITCH_RESPONSE: ret = ieee80211_prep_tdls_encap_data(local->hw.wiphy, - sdata->dev, peer, + sdata->dev, link, peer, action_code, dialog_token, status_code, skb); break; case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: ret = ieee80211_prep_tdls_direct(local->hw.wiphy, sdata->dev, - peer, action_code, + peer, link, action_code, dialog_token, status_code, skb); break; @@ -918,19 +923,23 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, if (ret < 0) goto fail; - ieee80211_tdls_add_ies(sdata, skb, peer, action_code, status_code, + ieee80211_tdls_add_ies(link, skb, peer, action_code, status_code, initiator, extra_ies, extra_ies_len, oper_class, chandef); + rcu_read_unlock(); return skb; fail: dev_kfree_skb(skb); +unlock: + rcu_read_unlock(); return NULL; } static int ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, bool initiator, const u8 *extra_ies, size_t extra_ies_len, u8 oper_class, @@ -988,7 +997,8 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, if (ret < 0) goto fail; - skb = ieee80211_tdls_build_mgmt_packet_data(sdata, peer, action_code, + skb = ieee80211_tdls_build_mgmt_packet_data(sdata, peer, + link_id, action_code, dialog_token, status_code, initiator, extra_ies, extra_ies_len, oper_class, @@ -999,7 +1009,7 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev, } if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { - ieee80211_tx_skb(sdata, skb); + ieee80211_tx_skb_tid(sdata, skb, 7, link_id); return 0; } @@ -1066,7 +1076,8 @@ fail: static int ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, bool initiator, const u8 *extra_ies, size_t extra_ies_len) { @@ -1115,7 +1126,8 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, mutex_unlock(&local->mtx); /* we cannot take the mutex while preparing the setup packet */ - ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, + ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, + link_id, action_code, dialog_token, status_code, peer_capability, initiator, extra_ies, extra_ies_len, 0, @@ -1139,7 +1151,8 @@ out_unlock: static int ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, - const u8 *peer, u8 action_code, u8 dialog_token, + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capability, bool initiator, const u8 *extra_ies, size_t extra_ies_len) @@ -1159,7 +1172,8 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev, IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN); ieee80211_flush_queues(local, sdata, false); - ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code, + ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, + link_id, action_code, dialog_token, status_code, peer_capability, initiator, extra_ies, extra_ies_len, 0, @@ -1204,13 +1218,14 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, switch (action_code) { case WLAN_TDLS_SETUP_REQUEST: case WLAN_TDLS_SETUP_RESPONSE: - ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, action_code, + ret = ieee80211_tdls_mgmt_setup(wiphy, dev, peer, + link_id, action_code, dialog_token, status_code, peer_capability, initiator, extra_ies, extra_ies_len); break; case WLAN_TDLS_TEARDOWN: - ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer, + ret = ieee80211_tdls_mgmt_teardown(wiphy, dev, peer, link_id, action_code, dialog_token, status_code, peer_capability, initiator, @@ -1228,7 +1243,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: /* no special handling */ ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, - action_code, + link_id, action_code, dialog_token, status_code, peer_capability, @@ -1240,8 +1255,8 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, break; } - tdls_dbg(sdata, "TDLS mgmt action %d peer %pM status %d\n", - action_code, peer, ret); + tdls_dbg(sdata, "TDLS mgmt action %d peer %pM link_id %d status %d\n", + action_code, peer, link_id, ret); return ret; } @@ -1497,6 +1512,7 @@ ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class, int extra_ies_len = 2 + sizeof(struct ieee80211_ch_switch_timing); u8 *pos = extra_ies; struct sk_buff *skb; + int link_id = sta->sta.valid_links ? ffs(sta->sta.valid_links) - 1 : 0; /* * if chandef points to a wide channel add a Secondary-Channel @@ -1524,6 +1540,7 @@ ieee80211_tdls_ch_sw_tmpl_get(struct sta_info *sta, u8 oper_class, iee80211_tdls_add_ch_switch_timing(pos, 0, 0); skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, + link_id, WLAN_TDLS_CHANNEL_SWITCH_REQUEST, 0, 0, !sta->sta.tdls_initiator, extra_ies, extra_ies_len, @@ -1644,11 +1661,13 @@ ieee80211_tdls_ch_sw_resp_tmpl_get(struct sta_info *sta, struct ieee80211_sub_if_data *sdata = sta->sdata; struct sk_buff *skb; u8 extra_ies[2 + sizeof(struct ieee80211_ch_switch_timing)]; + int link_id = sta->sta.valid_links ? ffs(sta->sta.valid_links) - 1 : 0; /* initial timing are always zero in the template */ iee80211_tdls_add_ch_switch_timing(extra_ies, 0, 0); skb = ieee80211_tdls_build_mgmt_packet_data(sdata, sta->sta.addr, + link_id, WLAN_TDLS_CHANNEL_SWITCH_RESPONSE, 0, 0, !sta->sta.tdls_initiator, extra_ies, sizeof(extra_ies), 0, NULL); -- cgit v1.2.3 From 8cc07265b69141f8ed9597d0f27185239c241c80 Mon Sep 17 00:00:00 2001 From: Abhishek Naik Date: Fri, 16 Jun 2023 09:53:52 +0300 Subject: wifi: mac80211: handle TDLS data frames with MLO If the device is associated with an AP MLD, then TDLS data frames should have - A1 = peer address, - A2 = own MLD address (since the peer may now know about MLO), and - A3 = BSSID. Change the code to do that. Signed-off-by: Abhishek Naik Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.4bf648b63dfd.I98ef1dabd14b74a92120750f7746a7a512011701@changeid Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index d8460a14b6bd..b5183f6365aa 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2753,10 +2753,20 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER); if (tdls_peer) { + /* For TDLS only one link can be valid with peer STA */ + int tdls_link_id = sta->sta.valid_links ? + __ffs(sta->sta.valid_links) : 0; + struct ieee80211_link_data *link; + /* DA SA BSSID */ memcpy(hdr.addr1, skb->data, ETH_ALEN); memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); - memcpy(hdr.addr3, sdata->deflink.u.mgd.bssid, ETH_ALEN); + link = rcu_dereference(sdata->link[tdls_link_id]); + if (WARN_ON_ONCE(!link)) { + ret = -EINVAL; + goto free; + } + memcpy(hdr.addr3, link->u.mgd.bssid, ETH_ALEN); hdrlen = 24; } else if (sdata->u.mgd.use_4addr && cpu_to_be16(ethertype) != sdata->control_port_protocol) { @@ -3066,10 +3076,18 @@ void ieee80211_check_fast_xmit(struct sta_info *sta) break; case NL80211_IFTYPE_STATION: if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { + /* For TDLS only one link can be valid with peer STA */ + int tdls_link_id = sta->sta.valid_links ? + __ffs(sta->sta.valid_links) : 0; + struct ieee80211_link_data *link; + /* DA SA BSSID */ build.da_offs = offsetof(struct ieee80211_hdr, addr1); build.sa_offs = offsetof(struct ieee80211_hdr, addr2); - memcpy(hdr->addr3, sdata->deflink.u.mgd.bssid, ETH_ALEN); + link = rcu_dereference(sdata->link[tdls_link_id]); + if (WARN_ON_ONCE(!link)) + break; + memcpy(hdr->addr3, link->u.mgd.bssid, ETH_ALEN); build.hdr_len = 24; break; } -- cgit v1.2.3 From 71b3b7ac3eb8ceae582608dda0566e95c1108708 Mon Sep 17 00:00:00 2001 From: Abhishek Naik Date: Fri, 16 Jun 2023 09:53:53 +0300 Subject: wifi: mac80211: Add HE and EHT capa elements in TDLS frames Add HE and EHT capabilities IE in TDLS setup request, response, confirm and discovery response frames. Signed-off-by: Abhishek Naik Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.c77128828b0d.Ied2d8800847c759718c2c35e8f6c0902afd6bca1@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/tdls.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/util.c | 2 +- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ca8a1e1c8bbd..f8d5f37ebe9a 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2426,6 +2426,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, const u8 *da, const u8 *bssid, u16 stype, u16 reason, bool send_frame, u8 *frame_buf); +u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end); enum { IEEE80211_PROBE_FLAG_DIRECTED = BIT(0), diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index a920e2a7a978..a90404d0cd78 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -372,6 +372,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, struct ieee80211_local *local = sdata->local; struct ieee80211_sta_ht_cap ht_cap; struct ieee80211_sta_vht_cap vht_cap; + const struct ieee80211_sta_he_cap *he_cap; + const struct ieee80211_sta_eht_cap *eht_cap; struct sta_info *sta = NULL; size_t offset = 0, noffset; u8 *pos; @@ -529,6 +531,83 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, ieee80211_tdls_chandef_vht_upgrade(sdata, sta); } + /* add any custom IEs that go before HE capabilities */ + if (extra_ies_len) { + static const u8 before_he_cap[] = { + WLAN_EID_EXTENSION, + WLAN_EID_EXT_FILS_REQ_PARAMS, + WLAN_EID_AP_CSN, + }; + noffset = ieee80211_ie_split(extra_ies, extra_ies_len, + before_he_cap, + ARRAY_SIZE(before_he_cap), + offset); + skb_put_data(skb, extra_ies + offset, noffset - offset); + offset = noffset; + } + + /* build the HE-cap from sband */ + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + if (he_cap && + (action_code == WLAN_TDLS_SETUP_REQUEST || + action_code == WLAN_TDLS_SETUP_RESPONSE || + action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES)) { + __le16 he_6ghz_capa; + u8 cap_size; + + cap_size = + 2 + 1 + sizeof(he_cap->he_cap_elem) + + ieee80211_he_mcs_nss_size(&he_cap->he_cap_elem) + + ieee80211_he_ppe_size(he_cap->ppe_thres[0], + he_cap->he_cap_elem.phy_cap_info); + pos = skb_put(skb, cap_size); + pos = ieee80211_ie_build_he_cap(0, pos, he_cap, pos + cap_size); + + /* Build HE 6Ghz capa IE from sband */ + if (sband->band == NL80211_BAND_6GHZ) { + cap_size = 2 + 1 + sizeof(struct ieee80211_he_6ghz_capa); + pos = skb_put(skb, cap_size); + he_6ghz_capa = + ieee80211_get_he_6ghz_capa_vif(sband, &sdata->vif); + pos = ieee80211_write_he_6ghz_cap(pos, he_6ghz_capa, + pos + cap_size); + } + } + + /* add any custom IEs that go before EHT capabilities */ + if (extra_ies_len) { + static const u8 before_he_cap[] = { + WLAN_EID_EXTENSION, + WLAN_EID_EXT_FILS_REQ_PARAMS, + WLAN_EID_AP_CSN, + }; + + noffset = ieee80211_ie_split(extra_ies, extra_ies_len, + before_he_cap, + ARRAY_SIZE(before_he_cap), + offset); + skb_put_data(skb, extra_ies + offset, noffset - offset); + offset = noffset; + } + + /* build the EHT-cap from sband */ + eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); + if (he_cap && eht_cap && + (action_code == WLAN_TDLS_SETUP_REQUEST || + action_code == WLAN_TDLS_SETUP_RESPONSE || + action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES)) { + u8 cap_size; + + cap_size = + 2 + 1 + sizeof(eht_cap->eht_cap_elem) + + ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem, + &eht_cap->eht_cap_elem, false) + + ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0], + eht_cap->eht_cap_elem.phy_cap_info); + pos = skb_put(skb, cap_size); + ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + cap_size, false); + } + /* add any remaining IEs */ if (extra_ies_len) { noffset = extra_ies_len; @@ -885,6 +964,13 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, sizeof(struct ieee80211_ht_operation)) + 2 + max(sizeof(struct ieee80211_vht_cap), sizeof(struct ieee80211_vht_operation)) + + 2 + 1 + sizeof(struct ieee80211_he_cap_elem) + + sizeof(struct ieee80211_he_mcs_nss_supp) + + IEEE80211_HE_PPE_THRES_MAX_LEN + + 2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) + + 2 + 1 + sizeof(struct ieee80211_eht_cap_elem) + + sizeof(struct ieee80211_eht_mcs_nss_supp) + + IEEE80211_EHT_PPE_THRES_MAX_LEN + 50 + /* supported channels */ 3 + /* 40/20 BSS coex */ 4 + /* AID */ diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ab60a530198b..a0407baa6cd3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1918,7 +1918,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, } } -static u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end) +u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end) { if ((end - pos) < 5) return pos; -- cgit v1.2.3 From 05995d05aab399fcb1fba579397bff216dbf3e86 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Fri, 16 Jun 2023 09:53:54 +0300 Subject: wifi: mac80211: Extend AID element addition for TDLS frames Extend AID element addition in TDLS setup request and response frames to add it when HE or EHT capabilities are supported. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.483bf44ce684.Ia2387eb24c06fa41febc213923160bedafce2085@changeid Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index a90404d0cd78..a4af3b7675ef 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -499,17 +499,21 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, offset = noffset; } - /* build the VHT-cap similarly to the HT-cap */ + /* add AID if VHT, HE or EHT capabilities supported */ memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap)); + he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); + if ((vht_cap.vht_supported || he_cap || eht_cap) && + (action_code == WLAN_TDLS_SETUP_REQUEST || + action_code == WLAN_TDLS_SETUP_RESPONSE)) + ieee80211_tdls_add_aid(sdata, skb); + + /* build the VHT-cap similarly to the HT-cap */ if ((action_code == WLAN_TDLS_SETUP_REQUEST || action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) && vht_cap.vht_supported) { ieee80211_apply_vhtcap_overrides(sdata, &vht_cap); - /* the AID is present only when VHT is implemented */ - if (action_code == WLAN_TDLS_SETUP_REQUEST) - ieee80211_tdls_add_aid(sdata, skb); - pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap); } else if (action_code == WLAN_TDLS_SETUP_RESPONSE && @@ -517,9 +521,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, /* the peer caps are already intersected with our own */ memcpy(&vht_cap, &sta->sta.deflink.vht_cap, sizeof(vht_cap)); - /* the AID is present only when VHT is implemented */ - ieee80211_tdls_add_aid(sdata, skb); - pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap); @@ -547,7 +548,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, } /* build the HE-cap from sband */ - he_cap = ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); if (he_cap && (action_code == WLAN_TDLS_SETUP_REQUEST || action_code == WLAN_TDLS_SETUP_RESPONSE || @@ -591,7 +591,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, } /* build the EHT-cap from sband */ - eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); if (he_cap && eht_cap && (action_code == WLAN_TDLS_SETUP_REQUEST || action_code == WLAN_TDLS_SETUP_RESPONSE || -- cgit v1.2.3 From 276311d5814f98b113b68302c96500fd316c2cbf Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:53:55 +0300 Subject: wifi: mac80211: stop passing cbss to parser In both of these cases (config_link, prep_channel) it is not needed to parse the MBSSID data for a nontransmitted BSS. In the config_link case the frame does not contain any MBSSID element and inheritance rules are only needed for the ML STA profile. While in the prep_channel case the IEs have already been processed by cfg80211 and are already exploded. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.66d2605ff0ad.I7cdd1d390e7b0735c46204231a9e636d45b7f1e4@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 738822b82d3e..171ba9d237c2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4709,7 +4709,6 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ; struct ieee80211_bss *bss = (void *)cbss->priv; struct ieee80211_elems_parse_params parse_params = { - .bss = cbss, .link_id = -1, .from_ap = true, }; -- cgit v1.2.3 From 05050a2bc0c1599e95ef15a6ae34cb68ceabb06a Mon Sep 17 00:00:00 2001 From: Anjaneyulu Date: Fri, 16 Jun 2023 09:53:56 +0300 Subject: wifi: mac80211: add consistency check for compat chandef Add NULL check for compat variable to avoid crash in cfg80211_chandef_compatible() if it got called with some mixed up channel context where not all the users compatible with each other, which shouldn't happen. Signed-off-by: Anjaneyulu Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.ae0f10dfd36b.Iea98c74aeb87bf6ef49f6d0c8687bba0dbea2abd@changeid Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 168bf3edd4b4..68952752b599 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -802,6 +802,11 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, } } + if (WARN_ON_ONCE(!compat)) { + rcu_read_unlock(); + return; + } + /* TDLS peers can sometimes affect the chandef width */ list_for_each_entry_rcu(sta, &local->sta_list, list) { if (!sta->uploaded || -- cgit v1.2.3 From 40e38c8dfce1cf543c8bd06e2c1c03a36bc22fe4 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 16 Jun 2023 09:53:57 +0300 Subject: wifi: mac80211: feed the link_id to cfg80211_ch_switch_started_notify For now, fix this only in station mode. We'll need to fix the AP mode later. Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.41e662ba1d68.I8faae5acb45c58cfeeb6bc6247aedbdaf9249d32@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 171ba9d237c2..1fc66f09cbb8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1981,8 +1981,9 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link, IEEE80211_QUEUE_STOP_REASON_CSA); mutex_unlock(&local->mtx); - cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, 0, - csa_ie.count, csa_ie.mode, 0); + cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, + link->link_id, csa_ie.count, + csa_ie.mode, 0); if (local->ops->channel_switch) { /* use driver's channel switch callback */ -- cgit v1.2.3 From c2edd3013266801d9c8595433c6eea462511f872 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:53:58 +0300 Subject: wifi: cfg80211: move regulatory_hint_found_beacon to be earlier These calls do not require any locking, so move them in preparation for the next patches. A minor change/bugfix is to not hint a beacon for nontransmitted BSSes Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.a5bf3558eae9.I33c7465d983c8bef19deb7a533ee475a16f91774@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index ce2104dc05c6..19e7014f8bc3 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1971,6 +1971,18 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator; } else { ts = jiffies; + + if (channel->band == NL80211_BAND_60GHZ) { + bss_type = capability & WLAN_CAPABILITY_DMG_TYPE_MASK; + if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || + bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) + regulatory_hint_found_beacon(wiphy, channel, + gfp); + } else { + if (capability & WLAN_CAPABILITY_ESS) + regulatory_hint_found_beacon(wiphy, channel, + gfp); + } } /* @@ -2007,16 +2019,6 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, if (!res) return NULL; - if (channel->band == NL80211_BAND_60GHZ) { - bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK; - if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || - bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) - regulatory_hint_found_beacon(wiphy, channel, gfp); - } else { - if (res->pub.capability & WLAN_CAPABILITY_ESS) - regulatory_hint_found_beacon(wiphy, channel, gfp); - } - if (non_tx_data) { /* this is a nontransmitting bss, we need to add it to * transmitting bss' list if it is not there @@ -2445,6 +2447,16 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); } + if (channel->band == NL80211_BAND_60GHZ) { + bss_type = capability & WLAN_CAPABILITY_DMG_TYPE_MASK; + if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || + bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + } else { + if (capability & WLAN_CAPABILITY_ESS) + regulatory_hint_found_beacon(wiphy, channel, gfp); + } + ies = kzalloc(sizeof(*ies) + ielen, gfp); if (!ies) return NULL; @@ -2478,16 +2490,6 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, if (!res) return NULL; - if (channel->band == NL80211_BAND_60GHZ) { - bss_type = res->pub.capability & WLAN_CAPABILITY_DMG_TYPE_MASK; - if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || - bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) - regulatory_hint_found_beacon(wiphy, channel, gfp); - } else { - if (res->pub.capability & WLAN_CAPABILITY_ESS) - regulatory_hint_found_beacon(wiphy, channel, gfp); - } - trace_cfg80211_return_bss(&res->pub); /* cfg80211_bss_update gives us a referenced result */ return &res->pub; -- cgit v1.2.3 From 6b7c93c1439c8833ada9068f612df2de0571fd00 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:53:59 +0300 Subject: wifi: cfg80211: keep bss_lock held when informing It is reasonable to hold bss_lock for a little bit longer after cfg80211_bss_update is done. Right now, this does not make any big difference, but doing so in preparation for the next patch which adds a call to the driver. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094948.61701884ff0d.I3358228209eb6766202aff04d1bae0b8fdff611f@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 66 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 19e7014f8bc3..8984f74da891 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1701,10 +1701,10 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev, } /* Returned bss is reference counted and must be cleaned up appropriately. */ -struct cfg80211_internal_bss * -cfg80211_bss_update(struct cfg80211_registered_device *rdev, - struct cfg80211_internal_bss *tmp, - bool signal_valid, unsigned long ts) +static struct cfg80211_internal_bss * +__cfg80211_bss_update(struct cfg80211_registered_device *rdev, + struct cfg80211_internal_bss *tmp, + bool signal_valid, unsigned long ts) { struct cfg80211_internal_bss *found = NULL; @@ -1713,10 +1713,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, tmp->ts = ts; - spin_lock_bh(&rdev->bss_lock); - if (WARN_ON(!rcu_access_pointer(tmp->pub.ies))) { - spin_unlock_bh(&rdev->bss_lock); return NULL; } @@ -1724,7 +1721,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, if (found) { if (!cfg80211_update_known_bss(rdev, found, tmp, signal_valid)) - goto drop; + return NULL; } else { struct cfg80211_internal_bss *new; struct cfg80211_internal_bss *hidden; @@ -1744,7 +1741,7 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, ies = (void *)rcu_dereference(tmp->pub.proberesp_ies); if (ies) kfree_rcu(ies, rcu_head); - goto drop; + return NULL; } memcpy(new, tmp, sizeof(*new)); new->refcount = 1; @@ -1775,14 +1772,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, */ if (!cfg80211_combine_bsses(rdev, new)) { bss_ref_put(rdev, new); - goto drop; + return NULL; } } if (rdev->bss_entries >= bss_entries_limit && !cfg80211_bss_expire_oldest(rdev)) { bss_ref_put(rdev, new); - goto drop; + return NULL; } /* This must be before the call to bss_ref_get */ @@ -1799,12 +1796,22 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, rdev->bss_generation++; bss_ref_get(rdev, found); - spin_unlock_bh(&rdev->bss_lock); return found; - drop: +} + +struct cfg80211_internal_bss * +cfg80211_bss_update(struct cfg80211_registered_device *rdev, + struct cfg80211_internal_bss *tmp, + bool signal_valid, unsigned long ts) +{ + struct cfg80211_internal_bss *res; + + spin_lock_bh(&rdev->bss_lock); + res = __cfg80211_bss_update(rdev, tmp, signal_valid, ts); spin_unlock_bh(&rdev->bss_lock); - return NULL; + + return res; } int cfg80211_get_ies_channel_number(const u8 *ie, size_t ielen, @@ -2015,15 +2022,15 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, rcu_assign_pointer(tmp.pub.ies, ies); signal_valid = data->chan == channel; - res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, ts); + spin_lock_bh(&rdev->bss_lock); + res = __cfg80211_bss_update(rdev, &tmp, signal_valid, ts); if (!res) - return NULL; + goto drop; if (non_tx_data) { /* this is a nontransmitting bss, we need to add it to * transmitting bss' list if it is not there */ - spin_lock_bh(&rdev->bss_lock); if (cfg80211_add_nontrans_list(non_tx_data->tx_bss, &res->pub)) { if (__cfg80211_unlink_bss(rdev, res)) { @@ -2031,15 +2038,19 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, res = NULL; } } - spin_unlock_bh(&rdev->bss_lock); if (!res) - return NULL; + goto drop; } + spin_unlock_bh(&rdev->bss_lock); trace_cfg80211_return_bss(&res->pub); - /* cfg80211_bss_update gives us a referenced result */ + /* __cfg80211_bss_update gives us a referenced result */ return &res->pub; + +drop: + spin_unlock_bh(&rdev->bss_lock); + return NULL; } static const struct element @@ -2376,6 +2387,7 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len, gfp_t gfp) { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_internal_bss tmp = {}, *res; struct cfg80211_bss_ies *ies; struct ieee80211_channel *channel; @@ -2485,14 +2497,20 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, ether_addr_copy(tmp.parent_bssid, data->parent_bssid); signal_valid = data->chan == channel; - res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid, - jiffies); + spin_lock_bh(&rdev->bss_lock); + res = __cfg80211_bss_update(rdev, &tmp, signal_valid, jiffies); if (!res) - return NULL; + goto drop; + + spin_unlock_bh(&rdev->bss_lock); trace_cfg80211_return_bss(&res->pub); - /* cfg80211_bss_update gives us a referenced result */ + /* __cfg80211_bss_update gives us a referenced result */ return &res->pub; + +drop: + spin_unlock_bh(&rdev->bss_lock); + return NULL; } struct cfg80211_bss * -- cgit v1.2.3 From 5db25290b77b4efcf26c2b25f288ca3f13ff2fc5 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:54:00 +0300 Subject: wifi: cfg80211: add inform_bss op to update BSS This new function is called from within the inform_bss(_frame)_data functions in order for the driver to update data that it is tracking. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.8d7781b0f965.I80041183072b75c081996a1a5a230b34aff5c668@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 13 +++++++++++++ net/wireless/rdev-ops.h | 12 ++++++++++++ net/wireless/scan.c | 4 ++++ net/wireless/trace.h | 17 +++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3ca581845206..e912b7cd3093 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2720,6 +2720,7 @@ enum cfg80211_signal_type { * the BSS that requested the scan in which the beacon/probe was received. * @chains: bitmask for filled values in @chain_signal. * @chain_signal: per-chain signal strength of last received BSS in dBm. + * @drv_data: Data to be passed through to @inform_bss */ struct cfg80211_inform_bss { struct ieee80211_channel *chan; @@ -2730,6 +2731,8 @@ struct cfg80211_inform_bss { u8 parent_bssid[ETH_ALEN] __aligned(2); u8 chains; s8 chain_signal[IEEE80211_MAX_CHAINS]; + + void *drv_data; }; /** @@ -4101,6 +4104,13 @@ struct mgmt_frame_regs { * * @change_bss: Modify parameters for a given BSS. * + * @inform_bss: Called by cfg80211 while being informed about new BSS data + * for every BSS found within the reported data or frame. This is called + * from within the cfg8011 inform_bss handlers while holding the bss_lock. + * The data parameter is passed through from drv_data inside + * struct cfg80211_inform_bss. + * The new IE data for the BSS is explicitly passed. + * * @set_txq_params: Set TX queue parameters * * @libertas_set_mesh_channel: Only for backward compatibility for libertas, @@ -4488,6 +4498,9 @@ struct cfg80211_ops { int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params); + void (*inform_bss)(struct wiphy *wiphy, struct cfg80211_bss *bss, + const struct cfg80211_bss_ies *ies, void *data); + int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_txq_params *params); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index f8c310849438..90bb7ac4b930 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -407,6 +407,18 @@ static inline int rdev_change_bss(struct cfg80211_registered_device *rdev, return ret; } +static inline void rdev_inform_bss(struct cfg80211_registered_device *rdev, + struct cfg80211_bss *bss, + const struct cfg80211_bss_ies *ies, + void *drv_data) + +{ + trace_rdev_inform_bss(&rdev->wiphy, bss); + if (rdev->ops->inform_bss) + rdev->ops->inform_bss(&rdev->wiphy, bss, ies, drv_data); + trace_rdev_return_void(&rdev->wiphy); +} + static inline int rdev_set_txq_params(struct cfg80211_registered_device *rdev, struct net_device *dev, struct ieee80211_txq_params *params) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 8984f74da891..d9abbf123ad1 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2027,6 +2027,8 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, if (!res) goto drop; + rdev_inform_bss(rdev, &res->pub, ies, data->drv_data); + if (non_tx_data) { /* this is a nontransmitting bss, we need to add it to * transmitting bss' list if it is not there @@ -2502,6 +2504,8 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, if (!res) goto drop; + rdev_inform_bss(rdev, &res->pub, ies, data->drv_data); + spin_unlock_bh(&rdev->bss_lock); trace_cfg80211_return_bss(&res->pub); diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 73a4f8f57438..e63990b81249 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -1159,6 +1159,23 @@ TRACE_EVENT(rdev_change_bss, __entry->ap_isolate, __entry->ht_opmode) ); +TRACE_EVENT(rdev_inform_bss, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_bss *bss), + TP_ARGS(wiphy, bss), + TP_STRUCT__entry( + WIPHY_ENTRY + MAC_ENTRY(bssid) + CHAN_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + MAC_ASSIGN(bssid, bss->bssid); + CHAN_ASSIGN(bss->channel); + ), + TP_printk(WIPHY_PR_FMT ", %pM, " CHAN_PR_FMT, + WIPHY_PR_ARG, __entry->bssid, CHAN_PR_ARG) +); + TRACE_EVENT(rdev_set_txq_params, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, struct ieee80211_txq_params *params), -- cgit v1.2.3 From 108d202298bf03ce8d7e28bb94d23555c8385582 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:54:01 +0300 Subject: wifi: mac80211: use new inform_bss callback Doing this simplifies the code somewhat, as iteration over the nontransmitted BSSs is not required anymore. Also, mac80211 should not be iterating over the nontrans_list as it should only be accessed while the bss_lock is held. It also simplifies parsing of the IEs somewhat, as cfg80211 already extracts the IEs and passes them to the callback. Note that the only user left requiring parsing a specific BSS is the association code if a beacon is required by the hardware. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.39ebfe2f9e59.Ia012b08e0feed8ec431b666888b459f6366f7bd1@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 1 + net/mac80211/ieee80211_i.h | 3 ++ net/mac80211/scan.c | 93 +++++++++++++++++++--------------------------- 3 files changed, 42 insertions(+), 55 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 359589d525d5..eea7028a46a7 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -5050,6 +5050,7 @@ const struct cfg80211_ops mac80211_config_ops = { .join_ocb = ieee80211_join_ocb, .leave_ocb = ieee80211_leave_ocb, .change_bss = ieee80211_change_bss, + .inform_bss = ieee80211_inform_bss, .set_txq_params = ieee80211_set_txq_params, .set_monitor_channel = ieee80211_set_monitor_channel, .suspend = ieee80211_suspend, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f8d5f37ebe9a..b05dfdcfff11 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1929,6 +1929,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local); void ieee80211_run_deferred_scan(struct ieee80211_local *local); void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb); +void ieee80211_inform_bss(struct wiphy *wiphy, struct cfg80211_bss *bss, + const struct cfg80211_bss_ies *ies, void *data); + void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); struct ieee80211_bss * ieee80211_bss_info_update(struct ieee80211_local *local, diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index ea5383136fff..0805aa8603c6 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -9,7 +9,7 @@ * Copyright 2007, Michael Wu * Copyright 2013-2015 Intel Mobile Communications GmbH * Copyright 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #include @@ -55,27 +55,45 @@ static bool is_uapsd_supported(struct ieee802_11_elems *elems) return qos_info & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD; } -static void -ieee80211_update_bss_from_elems(struct ieee80211_local *local, - struct ieee80211_bss *bss, - struct ieee802_11_elems *elems, - struct ieee80211_rx_status *rx_status, - bool beacon) +struct inform_bss_update_data { + struct ieee80211_rx_status *rx_status; + bool beacon; +}; + +void ieee80211_inform_bss(struct wiphy *wiphy, + struct cfg80211_bss *cbss, + const struct cfg80211_bss_ies *ies, + void *data) { + struct ieee80211_local *local = wiphy_priv(wiphy); + struct inform_bss_update_data *update_data = data; + struct ieee80211_bss *bss = (void *)cbss->priv; + struct ieee80211_rx_status *rx_status; + struct ieee802_11_elems *elems; int clen, srlen; - if (beacon) + /* This happens while joining an IBSS */ + if (!update_data) + return; + + elems = ieee802_11_parse_elems(ies->data, ies->len, false, NULL); + if (!elems) + return; + + rx_status = update_data->rx_status; + + if (update_data->beacon) bss->device_ts_beacon = rx_status->device_timestamp; else bss->device_ts_presp = rx_status->device_timestamp; if (elems->parse_error) { - if (beacon) + if (update_data->beacon) bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; else bss->corrupt_data |= IEEE80211_BSS_CORRUPT_PROBE_RESP; } else { - if (beacon) + if (update_data->beacon) bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_BEACON; else bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_PROBE_RESP; @@ -124,7 +142,7 @@ ieee80211_update_bss_from_elems(struct ieee80211_local *local, bss->valid_data |= IEEE80211_BSS_VALID_WMM; } - if (beacon) { + if (update_data->beacon) { struct ieee80211_supported_band *sband = local->hw.wiphy->bands[rx_status->band]; if (!(rx_status->encoding == RX_ENC_HT) && @@ -138,6 +156,8 @@ ieee80211_update_bss_from_elems(struct ieee80211_local *local, le32_to_cpu(elems->vht_cap_elem->vht_cap_info); else bss->vht_cap_info = 0; + + kfree(elems); } struct ieee80211_bss * @@ -148,16 +168,17 @@ ieee80211_bss_info_update(struct ieee80211_local *local, { bool beacon = ieee80211_is_beacon(mgmt->frame_control) || ieee80211_is_s1g_beacon(mgmt->frame_control); - struct cfg80211_bss *cbss, *non_tx_cbss; - struct ieee80211_bss *bss, *non_tx_bss; + struct cfg80211_bss *cbss; + struct inform_bss_update_data update_data = { + .rx_status = rx_status, + .beacon = beacon, + }; struct cfg80211_inform_bss bss_meta = { .boottime_ns = rx_status->boottime_ns, + .drv_data = (void *)&update_data, }; bool signal_valid; struct ieee80211_sub_if_data *scan_sdata; - struct ieee802_11_elems *elems; - size_t baselen; - u8 *elements; if (rx_status->flag & RX_FLAG_NO_SIGNAL_VAL) bss_meta.signal = 0; /* invalid signal indication */ @@ -192,50 +213,12 @@ ieee80211_bss_info_update(struct ieee80211_local *local, if (!cbss) return NULL; - if (ieee80211_is_probe_resp(mgmt->frame_control)) { - elements = mgmt->u.probe_resp.variable; - baselen = offsetof(struct ieee80211_mgmt, - u.probe_resp.variable); - } else if (ieee80211_is_s1g_beacon(mgmt->frame_control)) { - struct ieee80211_ext *ext = (void *) mgmt; - - baselen = offsetof(struct ieee80211_ext, u.s1g_beacon.variable); - elements = ext->u.s1g_beacon.variable; - } else { - baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); - elements = mgmt->u.beacon.variable; - } - - if (baselen > len) - return NULL; - - elems = ieee802_11_parse_elems(elements, len - baselen, false, cbss); - if (!elems) - return NULL; - /* In case the signal is invalid update the status */ signal_valid = channel == cbss->channel; if (!signal_valid) rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; - bss = (void *)cbss->priv; - ieee80211_update_bss_from_elems(local, bss, elems, rx_status, beacon); - kfree(elems); - - list_for_each_entry(non_tx_cbss, &cbss->nontrans_list, nontrans_list) { - non_tx_bss = (void *)non_tx_cbss->priv; - - elems = ieee802_11_parse_elems(elements, len - baselen, false, - non_tx_cbss); - if (!elems) - continue; - - ieee80211_update_bss_from_elems(local, non_tx_bss, elems, - rx_status, beacon); - kfree(elems); - } - - return bss; + return (void *)cbss->priv; } static bool ieee80211_scan_accept_presp(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3 From 03e7e493f1a3697eba115f3f69e296f7e47500ee Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:54:02 +0300 Subject: wifi: cfg80211: ignore invalid TBTT info field types The TBTT information field type must be zero. This is only changed in the 802.11be draft specification where the value 1 is used to indicate that only the MLD parameters are included. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.7865606ffe94.I7ff28afb875d1b4c39acd497df8490a7d3628e3f@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 2 ++ net/wireless/scan.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 5dfed1a6625c..47ddc65b443b 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4481,6 +4481,8 @@ static inline bool for_each_element_completed(const struct element *element, #define IEEE80211_AP_INFO_TBTT_HDR_FILTERED 0x04 #define IEEE80211_AP_INFO_TBTT_HDR_COLOC 0x08 #define IEEE80211_AP_INFO_TBTT_HDR_COUNT 0xF0 +#define IEEE80211_TBTT_INFO_TYPE_TBTT 0 +#define IEEE80211_TBTT_INFO_TYPE_MLD 1 #define IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM 9 #define IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM 13 diff --git a/net/wireless/scan.c b/net/wireless/scan.c index d9abbf123ad1..2212e6d24204 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -629,6 +629,13 @@ static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, if (end - pos < count * length) break; + if (u8_get_bits(ap_info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_TYPE) != + IEEE80211_TBTT_INFO_TYPE_TBTT) { + pos += count * length; + continue; + } + /* * TBTT info must include bss param + BSSID + * (short SSID or same_ssid bit to be set). -- cgit v1.2.3 From dfd9aa3e7a456d57b18021d66472ab7ff8373ab7 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:54:03 +0300 Subject: wifi: cfg80211: rewrite merging of inherited elements The cfg80211_gen_new_ie function merges the IEs using inheritance rules. Rewrite this function to fix issues around inheritance rules. In particular, vendor elements do not require any special handling, as they are either all inherited or overridden by the subprofile. Also, add fragmentation handling as this may be needed in some cases. This also changes the function to not require making a copy. The new version could be optimized a bit by explicitly tracking which IEs have been handled already rather than looking that up again every time. Note that a small behavioural change is the removal of the SSID special handling. This should be fine for the MBSSID element, as the SSID must be included in the subelement. Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.bc6152e146db.I2b5f3bc45085e1901e5b5192a674436adaf94748@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 213 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 124 insertions(+), 89 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 2212e6d24204..b9eb91f485f8 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -259,117 +259,152 @@ bool cfg80211_is_element_inherited(const struct element *elem, } EXPORT_SYMBOL(cfg80211_is_element_inherited); -static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, - const u8 *subelement, size_t subie_len, - u8 *new_ie, gfp_t gfp) +static size_t cfg80211_copy_elem_with_frags(const struct element *elem, + const u8 *ie, size_t ie_len, + u8 **pos, u8 *buf, size_t buf_len) { - u8 *pos, *tmp; - const u8 *tmp_old, *tmp_new; - const struct element *non_inherit_elem; - u8 *sub_copy; + if (WARN_ON((u8 *)elem < ie || elem->data > ie + ie_len || + elem->data + elem->datalen > ie + ie_len)) + return 0; - /* copy subelement as we need to change its content to - * mark an ie after it is processed. - */ - sub_copy = kmemdup(subelement, subie_len, gfp); - if (!sub_copy) + if (elem->datalen + 2 > buf + buf_len - *pos) return 0; - pos = &new_ie[0]; + memcpy(*pos, elem, elem->datalen + 2); + *pos += elem->datalen + 2; - /* set new ssid */ - tmp_new = cfg80211_find_ie(WLAN_EID_SSID, sub_copy, subie_len); - if (tmp_new) { - memcpy(pos, tmp_new, tmp_new[1] + 2); - pos += (tmp_new[1] + 2); + /* Finish if it is not fragmented */ + if (elem->datalen != 255) + return *pos - buf; + + ie_len = ie + ie_len - elem->data - elem->datalen; + ie = (const u8 *)elem->data + elem->datalen; + + for_each_element(elem, ie, ie_len) { + if (elem->id != WLAN_EID_FRAGMENT) + break; + + if (elem->datalen + 2 > buf + buf_len - *pos) + return 0; + + memcpy(*pos, elem, elem->datalen + 2); + *pos += elem->datalen + 2; + + if (elem->datalen != 255) + break; } - /* get non inheritance list if exists */ - non_inherit_elem = - cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, - sub_copy, subie_len); + return *pos - buf; +} - /* go through IEs in ie (skip SSID) and subelement, - * merge them into new_ie +static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen, + const u8 *subie, size_t subie_len, + u8 *new_ie, size_t new_ie_len) +{ + const struct element *non_inherit_elem, *parent, *sub; + u8 *pos = new_ie; + u8 id, ext_id; + unsigned int match_len; + + non_inherit_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE, + subie, subie_len); + + /* We copy the elements one by one from the parent to the generated + * elements. + * If they are not inherited (included in subie or in the non + * inheritance element), then we copy all occurrences the first time + * we see this element type. */ - tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); - tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie; - - while (tmp_old + 2 - ie <= ielen && - tmp_old + tmp_old[1] + 2 - ie <= ielen) { - if (tmp_old[0] == 0) { - tmp_old++; + for_each_element(parent, ie, ielen) { + if (parent->id == WLAN_EID_FRAGMENT) continue; + + if (parent->id == WLAN_EID_EXTENSION) { + if (parent->datalen < 1) + continue; + + id = WLAN_EID_EXTENSION; + ext_id = parent->data[0]; + match_len = 1; + } else { + id = parent->id; + match_len = 0; } - if (tmp_old[0] == WLAN_EID_EXTENSION) - tmp = (u8 *)cfg80211_find_ext_ie(tmp_old[2], sub_copy, - subie_len); - else - tmp = (u8 *)cfg80211_find_ie(tmp_old[0], sub_copy, - subie_len); + /* Find first occurrence in subie */ + sub = cfg80211_find_elem_match(id, subie, subie_len, + &ext_id, match_len, 0); - if (!tmp) { - const struct element *old_elem = (void *)tmp_old; + /* Copy from parent if not in subie and inherited */ + if (!sub && + cfg80211_is_element_inherited(parent, non_inherit_elem)) { + if (!cfg80211_copy_elem_with_frags(parent, + ie, ielen, + &pos, new_ie, + new_ie_len)) + return 0; - /* ie in old ie but not in subelement */ - if (cfg80211_is_element_inherited(old_elem, - non_inherit_elem)) { - memcpy(pos, tmp_old, tmp_old[1] + 2); - pos += tmp_old[1] + 2; - } - } else { - /* ie in transmitting ie also in subelement, - * copy from subelement and flag the ie in subelement - * as copied (by setting eid field to WLAN_EID_SSID, - * which is skipped anyway). - * For vendor ie, compare OUI + type + subType to - * determine if they are the same ie. - */ - if (tmp_old[0] == WLAN_EID_VENDOR_SPECIFIC) { - if (tmp_old[1] >= 5 && tmp[1] >= 5 && - !memcmp(tmp_old + 2, tmp + 2, 5)) { - /* same vendor ie, copy from - * subelement - */ - memcpy(pos, tmp, tmp[1] + 2); - pos += tmp[1] + 2; - tmp[0] = WLAN_EID_SSID; - } else { - memcpy(pos, tmp_old, tmp_old[1] + 2); - pos += tmp_old[1] + 2; - } - } else { - /* copy ie from subelement into new ie */ - memcpy(pos, tmp, tmp[1] + 2); - pos += tmp[1] + 2; - tmp[0] = WLAN_EID_SSID; - } + continue; } - if (tmp_old + tmp_old[1] + 2 - ie == ielen) - break; + /* Already copied if an earlier element had the same type */ + if (cfg80211_find_elem_match(id, ie, (u8 *)parent - ie, + &ext_id, match_len, 0)) + continue; - tmp_old += tmp_old[1] + 2; + /* Not inheriting, copy all similar elements from subie */ + while (sub) { + if (!cfg80211_copy_elem_with_frags(sub, + subie, subie_len, + &pos, new_ie, + new_ie_len)) + return 0; + + sub = cfg80211_find_elem_match(id, + sub->data + sub->datalen, + subie_len + subie - + (sub->data + + sub->datalen), + &ext_id, match_len, 0); + } } - /* go through subelement again to check if there is any ie not - * copied to new ie, skip ssid, capability, bssid-index ie + /* The above misses elements that are included in subie but not in the + * parent, so do a pass over subie and append those. + * Skip the non-tx BSSID caps and non-inheritance element. */ - tmp_new = sub_copy; - while (tmp_new + 2 - sub_copy <= subie_len && - tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) { - if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP || - tmp_new[0] == WLAN_EID_SSID)) { - memcpy(pos, tmp_new, tmp_new[1] + 2); - pos += tmp_new[1] + 2; + for_each_element(sub, subie, subie_len) { + if (sub->id == WLAN_EID_NON_TX_BSSID_CAP) + continue; + + if (sub->id == WLAN_EID_FRAGMENT) + continue; + + if (sub->id == WLAN_EID_EXTENSION) { + if (sub->datalen < 1) + continue; + + id = WLAN_EID_EXTENSION; + ext_id = sub->data[0]; + match_len = 1; + + if (ext_id == WLAN_EID_EXT_NON_INHERITANCE) + continue; + } else { + id = sub->id; + match_len = 0; } - if (tmp_new + tmp_new[1] + 2 - sub_copy == subie_len) - break; - tmp_new += tmp_new[1] + 2; + + /* Processed if one was included in the parent */ + if (cfg80211_find_elem_match(id, ie, ielen, + &ext_id, match_len, 0)) + continue; + + if (!cfg80211_copy_elem_with_frags(sub, subie, subie_len, + &pos, new_ie, new_ie_len)) + return 0; } - kfree(sub_copy); return pos - new_ie; } @@ -2228,7 +2263,7 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, new_ie_len = cfg80211_gen_new_ie(ie, ielen, profile, profile_len, new_ie, - gfp); + IEEE80211_MAX_DATA_LEN); if (!new_ie_len) continue; -- cgit v1.2.3 From 39432f8a3752a87a53fd8d5e51824a43aaae5cab Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:54:04 +0300 Subject: wifi: cfg80211: drop incorrect nontransmitted BSS update code The removed code ran for any BSS that was not included in the MBSSID element in order to update it. However, instead of using the correct inheritance rules, it would simply copy the elements from the transmitting AP. The result is that we would report incorrect elements in this case. After some discussions, it seems that there are likely not even APs actually using this feature. Either way, removing the code decreases complexity and makes the cfg80211 behaviour more correct. Fixes: 0b8fb8235be8 ("cfg80211: Parsing of Multiple BSSID information in scanning") Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.cfd6d8db1f26.Ia1044902b86cd7d366400a4bfb93691b8f05d68c@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 154 ++++------------------------------------------------ 1 file changed, 11 insertions(+), 143 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index b9eb91f485f8..75e6e032bb3a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2312,118 +2312,6 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, } EXPORT_SYMBOL(cfg80211_inform_bss_data); -static void -cfg80211_parse_mbssid_frame_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - struct ieee80211_mgmt *mgmt, size_t len, - struct cfg80211_non_tx_bss *non_tx_data, - gfp_t gfp) -{ - enum cfg80211_bss_frame_type ftype; - const u8 *ie = mgmt->u.probe_resp.variable; - size_t ielen = len - offsetof(struct ieee80211_mgmt, - u.probe_resp.variable); - - ftype = ieee80211_is_beacon(mgmt->frame_control) ? - CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP; - - cfg80211_parse_mbssid_data(wiphy, data, ftype, mgmt->bssid, - le64_to_cpu(mgmt->u.probe_resp.timestamp), - le16_to_cpu(mgmt->u.probe_resp.beacon_int), - ie, ielen, non_tx_data, gfp); -} - -static void -cfg80211_update_notlisted_nontrans(struct wiphy *wiphy, - struct cfg80211_bss *nontrans_bss, - struct ieee80211_mgmt *mgmt, size_t len) -{ - u8 *ie, *new_ie, *pos; - const struct element *nontrans_ssid; - const u8 *trans_ssid, *mbssid; - size_t ielen = len - offsetof(struct ieee80211_mgmt, - u.probe_resp.variable); - size_t new_ie_len; - struct cfg80211_bss_ies *new_ies; - const struct cfg80211_bss_ies *old; - size_t cpy_len; - - lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock); - - ie = mgmt->u.probe_resp.variable; - - new_ie_len = ielen; - trans_ssid = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen); - if (!trans_ssid) - return; - new_ie_len -= trans_ssid[1]; - mbssid = cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen); - /* - * It's not valid to have the MBSSID element before SSID - * ignore if that happens - the code below assumes it is - * after (while copying things inbetween). - */ - if (!mbssid || mbssid < trans_ssid) - return; - new_ie_len -= mbssid[1]; - - nontrans_ssid = ieee80211_bss_get_elem(nontrans_bss, WLAN_EID_SSID); - if (!nontrans_ssid) - return; - - new_ie_len += nontrans_ssid->datalen; - - /* generate new ie for nontrans BSS - * 1. replace SSID with nontrans BSS' SSID - * 2. skip MBSSID IE - */ - new_ie = kzalloc(new_ie_len, GFP_ATOMIC); - if (!new_ie) - return; - - new_ies = kzalloc(sizeof(*new_ies) + new_ie_len, GFP_ATOMIC); - if (!new_ies) - goto out_free; - - pos = new_ie; - - /* copy the nontransmitted SSID */ - cpy_len = nontrans_ssid->datalen + 2; - memcpy(pos, nontrans_ssid, cpy_len); - pos += cpy_len; - /* copy the IEs between SSID and MBSSID */ - cpy_len = trans_ssid[1] + 2; - memcpy(pos, (trans_ssid + cpy_len), (mbssid - (trans_ssid + cpy_len))); - pos += (mbssid - (trans_ssid + cpy_len)); - /* copy the IEs after MBSSID */ - cpy_len = mbssid[1] + 2; - memcpy(pos, mbssid + cpy_len, ((ie + ielen) - (mbssid + cpy_len))); - - /* update ie */ - new_ies->len = new_ie_len; - new_ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); - new_ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control); - memcpy(new_ies->data, new_ie, new_ie_len); - if (ieee80211_is_probe_resp(mgmt->frame_control)) { - old = rcu_access_pointer(nontrans_bss->proberesp_ies); - rcu_assign_pointer(nontrans_bss->proberesp_ies, new_ies); - rcu_assign_pointer(nontrans_bss->ies, new_ies); - if (old) - kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); - } else { - old = rcu_access_pointer(nontrans_bss->beacon_ies); - rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies); - cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss), - new_ies, old); - rcu_assign_pointer(nontrans_bss->ies, new_ies); - if (old) - kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); - } - -out_free: - kfree(new_ie); -} - /* cfg80211_inform_bss_width_frame helper */ static struct cfg80211_bss * cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, @@ -2565,51 +2453,31 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len, gfp_t gfp) { - struct cfg80211_bss *res, *tmp_bss; + struct cfg80211_bss *res; const u8 *ie = mgmt->u.probe_resp.variable; - const struct cfg80211_bss_ies *ies1, *ies2; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + enum cfg80211_bss_frame_type ftype; struct cfg80211_non_tx_bss non_tx_data = {}; res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt, len, gfp); + if (!res) + return NULL; /* don't do any further MBSSID handling for S1G */ if (ieee80211_is_s1g_beacon(mgmt->frame_control)) return res; - if (!res || !wiphy->support_mbssid || - !cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID, ie, ielen)) - return res; - if (wiphy->support_only_he_mbssid && - !cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen)) - return res; - + ftype = ieee80211_is_beacon(mgmt->frame_control) ? + CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP; non_tx_data.tx_bss = res; - /* process each non-transmitting bss */ - cfg80211_parse_mbssid_frame_data(wiphy, data, mgmt, len, - &non_tx_data, gfp); - - spin_lock_bh(&wiphy_to_rdev(wiphy)->bss_lock); - /* check if the res has other nontransmitting bss which is not - * in MBSSID IE - */ - ies1 = rcu_access_pointer(res->ies); - - /* go through nontrans_list, if the timestamp of the BSS is - * earlier than the timestamp of the transmitting BSS then - * update it - */ - list_for_each_entry(tmp_bss, &res->nontrans_list, - nontrans_list) { - ies2 = rcu_access_pointer(tmp_bss->ies); - if (ies2->tsf < ies1->tsf) - cfg80211_update_notlisted_nontrans(wiphy, tmp_bss, - mgmt, len); - } - spin_unlock_bh(&wiphy_to_rdev(wiphy)->bss_lock); + /* process each non-transmitting bss */ + cfg80211_parse_mbssid_data(wiphy, data, ftype, mgmt->bssid, + le64_to_cpu(mgmt->u.probe_resp.timestamp), + le16_to_cpu(mgmt->u.probe_resp.beacon_int), + ie, ielen, &non_tx_data, gfp); return res; } -- cgit v1.2.3 From f837a653a09700daa136a3db49c0c97d7295ca30 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:54:05 +0300 Subject: wifi: cfg80211: add element defragmentation helper This is already needed within mac80211 and support is also needed by cfg80211 to parse ML elements. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.29c3ebeed10d.I009c049289dd0162c2e858ed8b68d2875a672ed6@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 22 ++++++++++++++++++ net/wireless/scan.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e912b7cd3093..9972de114d73 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6676,6 +6676,28 @@ cfg80211_find_vendor_ie(unsigned int oui, int oui_type, return (const void *)cfg80211_find_vendor_elem(oui, oui_type, ies, len); } +/** + * cfg80211_defragment_element - Defrag the given element data into a buffer + * + * @elem: the element to defragment + * @ies: elements where @elem is contained + * @ieslen: length of @ies + * @data: buffer to store element data + * @data_len: length of @data + * @frag_id: the element ID of fragments + * + * Return: length of @data, or -EINVAL on error + * + * Copy out all data from an element that may be fragmented into @data, while + * skipping all headers. + * + * The function uses memmove() internally. It is acceptable to defragment an + * element in-place. + */ +ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies, + size_t ieslen, u8 *data, size_t data_len, + u8 frag_id); + /** * cfg80211_send_layer2_update - send layer 2 update frame * diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 75e6e032bb3a..dc71c6ac5bf5 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -2288,6 +2288,66 @@ out: kfree(profile); } +ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies, + size_t ieslen, u8 *data, size_t data_len, + u8 frag_id) +{ + const struct element *next; + ssize_t copied; + u8 elem_datalen; + + if (!elem) + return -EINVAL; + + /* elem might be invalid after the memmove */ + next = (void *)(elem->data + elem->datalen); + + elem_datalen = elem->datalen; + if (elem->id == WLAN_EID_EXTENSION) { + copied = elem->datalen - 1; + if (copied > data_len) + return -ENOSPC; + + memmove(data, elem->data + 1, copied); + } else { + copied = elem->datalen; + if (copied > data_len) + return -ENOSPC; + + memmove(data, elem->data, copied); + } + + /* Fragmented elements must have 255 bytes */ + if (elem_datalen < 255) + return copied; + + for (elem = next; + elem->data < ies + ieslen && + elem->data + elem->datalen < ies + ieslen; + elem = next) { + /* elem might be invalid after the memmove */ + next = (void *)(elem->data + elem->datalen); + + if (elem->id != frag_id) + break; + + elem_datalen = elem->datalen; + + if (copied + elem_datalen > data_len) + return -ENOSPC; + + memmove(data + copied, elem->data, elem_datalen); + copied += elem_datalen; + + /* Only the last fragment may be short */ + if (elem_datalen != 255) + break; + } + + return copied; +} +EXPORT_SYMBOL(cfg80211_defragment_element); + struct cfg80211_bss * cfg80211_inform_bss_data(struct wiphy *wiphy, struct cfg80211_inform_bss *data, -- cgit v1.2.3 From a76236de584ac15b2e495a613034a9e031449f7e Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 16 Jun 2023 09:54:06 +0300 Subject: wifi: mac80211: use cfg80211 defragmentation helper Use the shared functionality rather than copying it into mac80211. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.7dcbf82baade.Ic68d1f547cb75d66037abdbb0f066db20ff41ba3@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 + net/mac80211/util.c | 93 +++++++++++++++++----------------------------- 2 files changed, 37 insertions(+), 58 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b05dfdcfff11..4ae9c58d6a12 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1752,6 +1752,8 @@ struct ieee802_11_elems { /* mult-link element can be de-fragmented and thus u8 is not sufficient */ size_t multi_link_len; + /* The element in the original IEs */ + const struct element *multi_link_elem; /* * store the per station profile pointer and length in case that the diff --git a/net/mac80211/util.c b/net/mac80211/util.c index a0407baa6cd3..3752e90cda54 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -984,6 +984,7 @@ ieee80211_parse_extension_element(u32 *crc, break; case WLAN_EID_EXT_EHT_MULTI_LINK: if (ieee80211_mle_size_ok(data, len)) { + elems->multi_link_elem = (void *)elem; elems->multi_link = (void *)data; elems->multi_link_len = len; } @@ -1458,56 +1459,11 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, return found ? profile_len : 0; } -static void ieee80211_defragment_element(struct ieee802_11_elems *elems, - void **elem_ptr, size_t *len, - size_t total_len, u8 frag_id) -{ - u8 *data = *elem_ptr, *pos, *start; - const struct element *elem; - - /* - * Since 'data' points to the data of the element, not the element - * itself, allow 254 in case it was an extended element where the - * extended ID isn't part of the data we see here and thus not part of - * 'len' either. - */ - if (!data || (*len != 254 && *len != 255)) - return; - - start = elems->scratch_pos; - - if (WARN_ON(*len > (elems->scratch + elems->scratch_len - - elems->scratch_pos))) - return; - - memcpy(elems->scratch_pos, data, *len); - elems->scratch_pos += *len; - - pos = data + *len; - total_len -= *len; - for_each_element(elem, pos, total_len) { - if (elem->id != frag_id) - break; - - if (WARN_ON(elem->datalen > - (elems->scratch + elems->scratch_len - - elems->scratch_pos))) - return; - - memcpy(elems->scratch_pos, elem->data, elem->datalen); - elems->scratch_pos += elem->datalen; - - *len += elem->datalen; - } - - *elem_ptr = start; -} - static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, u8 link_id) { const struct ieee80211_multi_link_elem *ml = elems->multi_link; - size_t ml_len = elems->multi_link_len; + ssize_t ml_len = elems->multi_link_len; const struct element *sub; if (!ml || !ml_len) @@ -1519,6 +1475,7 @@ static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, for_each_mle_subelement(sub, (u8 *)ml, ml_len) { struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data; + ssize_t sta_prof_len; u16 control; if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) @@ -1536,14 +1493,23 @@ static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, if (!(control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE)) return; - elems->prof = prof; - elems->sta_prof_len = sub->datalen; - /* the sub element can be fragmented */ - ieee80211_defragment_element(elems, (void **)&elems->prof, - &elems->sta_prof_len, - ml_len - (sub->data - (u8 *)ml), - IEEE80211_MLE_SUBELEM_FRAGMENT); + sta_prof_len = + cfg80211_defragment_element(sub, + (u8 *)ml, ml_len, + elems->scratch_pos, + elems->scratch + + elems->scratch_len - + elems->scratch_pos, + IEEE80211_MLE_SUBELEM_FRAGMENT); + + if (sta_prof_len < 0) + return; + + elems->prof = (void *)elems->scratch_pos; + elems->sta_prof_len = sta_prof_len; + elems->scratch_pos += sta_prof_len; + return; } } @@ -1557,17 +1523,28 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, .from_ap = params->from_ap, .link_id = -1, }; + ssize_t ml_len = elems->multi_link_len; const struct element *non_inherit = NULL; const u8 *end; if (params->link_id == -1) return; - ieee80211_defragment_element(elems, (void **)&elems->multi_link, - &elems->multi_link_len, - elems->total_len - ((u8 *)elems->multi_link - - elems->ie_start), - WLAN_EID_FRAGMENT); + ml_len = cfg80211_defragment_element(elems->multi_link_elem, + elems->ie_start, + elems->total_len, + elems->scratch_pos, + elems->scratch + + elems->scratch_len - + elems->scratch_pos, + WLAN_EID_FRAGMENT); + + if (ml_len < 0) + return; + + elems->multi_link = (const void *)elems->scratch_pos; + elems->multi_link_len = ml_len; + elems->scratch_pos += ml_len; ieee80211_mle_get_sta_prof(elems, params->link_id); prof = elems->prof; -- cgit v1.2.3 From a286de1aa38f7ea6605c770278a1ebf4096c03a2 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Fri, 16 Jun 2023 09:54:07 +0300 Subject: wifi: mac80211: Rename multi_link As a preparation to support Reconfiguration Multi Link element, rename 'multi_link' and 'multi_link_len' fields in 'struct ieee802_11_elems' to 'ml_basic' and 'ml_basic_len'. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.b11370d3066a.I34280ae3728597056a6a2f313063962206c0d581@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 9 +++++---- net/mac80211/mlme.c | 8 ++++---- net/mac80211/util.c | 19 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 4ae9c58d6a12..554aeb2e20d9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1726,7 +1726,7 @@ struct ieee802_11_elems { const struct ieee80211_aid_response_ie *aid_resp; const struct ieee80211_eht_cap_elem *eht_cap; const struct ieee80211_eht_operation *eht_operation; - const struct ieee80211_multi_link_elem *multi_link; + const struct ieee80211_multi_link_elem *ml_basic; /* length of them, respectively */ u8 ext_capab_len; @@ -1751,9 +1751,10 @@ struct ieee802_11_elems { u8 eht_cap_len; /* mult-link element can be de-fragmented and thus u8 is not sufficient */ - size_t multi_link_len; - /* The element in the original IEs */ - const struct element *multi_link_elem; + size_t ml_basic_len; + + /* The basic Multi-Link element in the original IEs */ + const struct element *ml_basic_elem; /* * store the per station profile pointer and length in case that the diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1fc66f09cbb8..b8f8220cd9ff 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5277,24 +5277,24 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } if (ieee80211_vif_is_mld(&sdata->vif)) { - if (!elems->multi_link) { + if (!elems->ml_basic) { sdata_info(sdata, "MLO association with %pM but no multi-link element in response!\n", assoc_data->ap_addr); goto abandon_assoc; } - if (le16_get_bits(elems->multi_link->control, + if (le16_get_bits(elems->ml_basic->control, IEEE80211_ML_CONTROL_TYPE) != IEEE80211_ML_CONTROL_TYPE_BASIC) { sdata_info(sdata, "bad multi-link element (control=0x%x)\n", - le16_to_cpu(elems->multi_link->control)); + le16_to_cpu(elems->ml_basic->control)); goto abandon_assoc; } else { struct ieee80211_mle_basic_common_info *common; - common = (void *)elems->multi_link->variable; + common = (void *)elems->ml_basic->variable; if (memcmp(assoc_data->ap_addr, common->mld_mac_addr, ETH_ALEN)) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 3752e90cda54..8658c28d684f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -984,9 +984,9 @@ ieee80211_parse_extension_element(u32 *crc, break; case WLAN_EID_EXT_EHT_MULTI_LINK: if (ieee80211_mle_size_ok(data, len)) { - elems->multi_link_elem = (void *)elem; - elems->multi_link = (void *)data; - elems->multi_link_len = len; + elems->ml_basic_elem = (void *)elem; + elems->ml_basic = (void *)data; + elems->ml_basic_len = len; } break; } @@ -1462,8 +1462,8 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len, static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, u8 link_id) { - const struct ieee80211_multi_link_elem *ml = elems->multi_link; - ssize_t ml_len = elems->multi_link_len; + const struct ieee80211_multi_link_elem *ml = elems->ml_basic; + ssize_t ml_len = elems->ml_basic_len; const struct element *sub; if (!ml || !ml_len) @@ -1523,14 +1523,14 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, .from_ap = params->from_ap, .link_id = -1, }; - ssize_t ml_len = elems->multi_link_len; + ssize_t ml_len = elems->ml_basic_len; const struct element *non_inherit = NULL; const u8 *end; if (params->link_id == -1) return; - ml_len = cfg80211_defragment_element(elems->multi_link_elem, + ml_len = cfg80211_defragment_element(elems->ml_basic_elem, elems->ie_start, elems->total_len, elems->scratch_pos, @@ -1542,9 +1542,8 @@ static void ieee80211_mle_parse_link(struct ieee802_11_elems *elems, if (ml_len < 0) return; - elems->multi_link = (const void *)elems->scratch_pos; - elems->multi_link_len = ml_len; - elems->scratch_pos += ml_len; + elems->ml_basic = (const void *)elems->scratch_pos; + elems->ml_basic_len = ml_len; ieee80211_mle_get_sta_prof(elems, params->link_id); prof = elems->prof; -- cgit v1.2.3 From cf36cdef10e28df52d500a4829263d1b4d24bc44 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Fri, 16 Jun 2023 09:54:08 +0300 Subject: wifi: mac80211: Add support for parsing Reconfiguration Multi Link element Parse Reconfiguration Multi Link IE. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.6eeb6c9a4a6e.I1cb137da9b3c712fc7c7949a6dec9e314b5d7f63@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 5 +++++ net/mac80211/util.c | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 554aeb2e20d9..be3294719cb4 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1727,6 +1727,7 @@ struct ieee802_11_elems { const struct ieee80211_eht_cap_elem *eht_cap; const struct ieee80211_eht_operation *eht_operation; const struct ieee80211_multi_link_elem *ml_basic; + const struct ieee80211_multi_link_elem *ml_reconf; /* length of them, respectively */ u8 ext_capab_len; @@ -1752,10 +1753,14 @@ struct ieee802_11_elems { /* mult-link element can be de-fragmented and thus u8 is not sufficient */ size_t ml_basic_len; + size_t ml_reconf_len; /* The basic Multi-Link element in the original IEs */ const struct element *ml_basic_elem; + /* The reconfiguration Multi-Link element in the original IEs */ + const struct element *ml_reconf_elem; + /* * store the per station profile pointer and length in case that the * parsing also handled Multi-Link element parsing for a specific link diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8658c28d684f..8da6bc43735a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -984,9 +984,24 @@ ieee80211_parse_extension_element(u32 *crc, break; case WLAN_EID_EXT_EHT_MULTI_LINK: if (ieee80211_mle_size_ok(data, len)) { - elems->ml_basic_elem = (void *)elem; - elems->ml_basic = (void *)data; - elems->ml_basic_len = len; + const struct ieee80211_multi_link_elem *mle = + (void *)data; + + switch (le16_get_bits(mle->control, + IEEE80211_ML_CONTROL_TYPE)) { + case IEEE80211_ML_CONTROL_TYPE_BASIC: + elems->ml_basic_elem = (void *)elem; + elems->ml_basic = data; + elems->ml_basic_len = len; + break; + case IEEE80211_ML_CONTROL_TYPE_RECONF: + elems->ml_reconf_elem = (void *)elem; + elems->ml_reconf = data; + elems->ml_reconf_len = len; + break; + default: + break; + } } break; } -- cgit v1.2.3 From e2efec97c3ad503042db27baaf7c8cb5d1348a83 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Fri, 16 Jun 2023 09:54:09 +0300 Subject: wifi: mac80211: Rename ieee80211_mle_sta_prof_size_ok() Rename it to ieee80211_mle_basic_sta_prof_size_ok() as it validates the size of the station profile included in Basic Multi-Link element. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230616094949.9bdfd263974f.I7bebd26894f33716e93cc7da576ef3215e0ba727@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 6 ++++-- net/mac80211/util.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 47ddc65b443b..aeedd49e5101 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4798,11 +4798,13 @@ struct ieee80211_mle_per_sta_profile { } __packed; /** - * ieee80211_mle_sta_prof_size_ok - validate multi-link element sta profile size + * ieee80211_mle_basic_sta_prof_size_ok - validate basic multi-link element sta + * profile size * @data: pointer to the sub element data * @len: length of the containing sub element */ -static inline bool ieee80211_mle_sta_prof_size_ok(const u8 *data, size_t len) +static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, + size_t len) { const struct ieee80211_mle_per_sta_profile *prof = (const void *)data; u16 control; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 8da6bc43735a..ef53d3baece7 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1496,7 +1496,8 @@ static void ieee80211_mle_get_sta_prof(struct ieee802_11_elems *elems, if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) continue; - if (!ieee80211_mle_sta_prof_size_ok(sub->data, sub->datalen)) + if (!ieee80211_mle_basic_sta_prof_size_ok(sub->data, + sub->datalen)) return; control = le16_to_cpu(prof->control); -- cgit v1.2.3 From b22552fcaf1970360005c805d7fba4046cf2ab4a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jun 2023 22:28:44 +0200 Subject: wifi: cfg80211: fix regulatory disconnect for non-MLO The multi-link loop here broke disconnect when multi-link operation (MLO) isn't active for a given interface, since in that case valid_links is 0 (indicating no links, i.e. no MLO.) Fix this by taking that into account properly and skipping the link only if there are valid_links in the first place. Cc: stable@vger.kernel.org Fixes: 7b0a0e3c3a88 ("wifi: cfg80211: do some rework towards MLO link APIs") Signed-off-by: Johannes Berg Link: https://lore.kernel.org/r/20230616222844.eb073d650c75.I72739923ef80919889ea9b50de9e4ba4baa836ae@changeid Signed-off-by: Johannes Berg --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 26f11e4746c0..f5ea1f373ab7 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2352,7 +2352,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) if (!wdev->valid_links && link > 0) break; - if (!(wdev->valid_links & BIT(link))) + if (wdev->valid_links && !(wdev->valid_links & BIT(link))) continue; switch (iftype) { case NL80211_IFTYPE_AP: -- cgit v1.2.3 From e8c2af660ba0790afd14d5cbc2fd05c6dc85e207 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Jun 2023 22:28:45 +0200 Subject: wifi: cfg80211: fix regulatory disconnect with OCB/NAN Since regulatory disconnect was added, OCB and NAN interface types were added, which made it completely unusable for any driver that allowed OCB/NAN. Add OCB/NAN (though NAN doesn't do anything, we don't have any info) and also remove all the logic that opts out, so it won't be broken again if/when new interface types are added. Fixes: 6e0bd6c35b02 ("cfg80211: 802.11p OCB mode handling") Fixes: cb3b7d87652a ("cfg80211: add start / stop NAN commands") Signed-off-by: Johannes Berg Link: https://lore.kernel.org/r/20230616222844.2794d1625a26.I8e78a3789a29e6149447b3139df724a6f1b46fc3@changeid Signed-off-by: Johannes Berg --- include/net/regulatory.h | 13 +------------ net/wireless/core.c | 16 ---------------- net/wireless/reg.c | 14 ++++++++++---- 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/include/net/regulatory.h b/include/net/regulatory.h index 896191f420d5..b2cb4a9eb04d 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -140,17 +140,6 @@ struct regulatory_request { * otherwise initiating radiation is not allowed. This will enable the * relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration * option - * @REGULATORY_IGNORE_STALE_KICKOFF: the regulatory core will _not_ make sure - * all interfaces on this wiphy reside on allowed channels. If this flag - * is not set, upon a regdomain change, the interfaces are given a grace - * period (currently 60 seconds) to disconnect or move to an allowed - * channel. Interfaces on forbidden channels are forcibly disconnected. - * Currently these types of interfaces are supported for enforcement: - * NL80211_IFTYPE_ADHOC, NL80211_IFTYPE_STATION, NL80211_IFTYPE_AP, - * NL80211_IFTYPE_AP_VLAN, NL80211_IFTYPE_MONITOR, - * NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_P2P_GO, - * NL80211_IFTYPE_P2P_DEVICE. The flag will be set by default if a device - * includes any modes unsupported for enforcement checking. * @REGULATORY_WIPHY_SELF_MANAGED: for devices that employ wiphy-specific * regdom management. These devices will ignore all regdom changes not * originating from their own wiphy. @@ -177,7 +166,7 @@ enum ieee80211_regulatory_flags { REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3), REGULATORY_COUNTRY_IE_IGNORE = BIT(4), REGULATORY_ENABLE_RELAX_NO_IR = BIT(5), - REGULATORY_IGNORE_STALE_KICKOFF = BIT(6), + /* reuse bit 6 next time */ REGULATORY_WIPHY_SELF_MANAGED = BIT(7), }; diff --git a/net/wireless/core.c b/net/wireless/core.c index fc449bea39a1..25bc2e50a061 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -756,22 +756,6 @@ int wiphy_register(struct wiphy *wiphy) return -EINVAL; } - /* - * if a wiphy has unsupported modes for regulatory channel enforcement, - * opt-out of enforcement checking - */ - if (wiphy->interface_modes & ~(BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_MESH_POINT) | - BIT(NL80211_IFTYPE_P2P_GO) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_P2P_DEVICE) | - BIT(NL80211_IFTYPE_NAN) | - BIT(NL80211_IFTYPE_AP_VLAN) | - BIT(NL80211_IFTYPE_MONITOR))) - wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF; - if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) && (wiphy->regulatory_flags & (REGULATORY_CUSTOM_REG | diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f5ea1f373ab7..f9e03850d71b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2391,9 +2391,17 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) case NL80211_IFTYPE_P2P_DEVICE: /* no enforcement required */ break; + case NL80211_IFTYPE_OCB: + if (!wdev->u.ocb.chandef.chan) + continue; + chandef = wdev->u.ocb.chandef; + break; + case NL80211_IFTYPE_NAN: + /* we have no info, but NAN is also pretty universal */ + continue; default: /* others not implemented for now */ - WARN_ON(1); + WARN_ON_ONCE(1); break; } @@ -2452,9 +2460,7 @@ static void reg_check_chans_work(struct work_struct *work) rtnl_lock(); list_for_each_entry(rdev, &cfg80211_rdev_list, list) - if (!(rdev->wiphy.regulatory_flags & - REGULATORY_IGNORE_STALE_KICKOFF)) - reg_leave_invalid_chans(&rdev->wiphy); + reg_leave_invalid_chans(&rdev->wiphy); rtnl_unlock(); } -- cgit v1.2.3 From dbd396636870b30c2c11c098bfc30e124198d29f Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 18 Jun 2023 21:49:44 +0300 Subject: wifi: mac80211: Include Multi-Link in CRC calculation Include the Multi-Link elements found in beacon frames in the CRC calculation, as these elements are intended to reflect changes in the AP MLD state. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214435.ae8246b93d85.Ia64b45198de90ff7f70abcc997841157f148ea40@changeid Signed-off-by: Johannes Berg --- net/mac80211/util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ef53d3baece7..6c52c597c187 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -987,6 +987,10 @@ ieee80211_parse_extension_element(u32 *crc, const struct ieee80211_multi_link_elem *mle = (void *)data; + if (crc) + *crc = crc32_be(*crc, (void *)elem, + elem->datalen + 2); + switch (le16_get_bits(mle->control, IEEE80211_ML_CONTROL_TYPE)) { case IEEE80211_ML_CONTROL_TYPE_BASIC: -- cgit v1.2.3 From ce6e1f600b0cfc563a7d607de702262a58cd835d Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 18 Jun 2023 21:49:45 +0300 Subject: wifi: ieee80211: Fix the common size calculation for reconfiguration ML The common information length is found in the first octet of the common information. Fixes: 0f48b8b88aa9 ("wifi: ieee80211: add definitions for multi-link element") Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214435.3c7ed4817338.I42ef706cb827b4dade6e4ffbb6e7f341eaccd398@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index aeedd49e5101..97edc3b404dd 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4617,15 +4617,12 @@ static inline u8 ieee80211_mle_common_size(const u8 *data) case IEEE80211_ML_CONTROL_TYPE_BASIC: case IEEE80211_ML_CONTROL_TYPE_PREQ: case IEEE80211_ML_CONTROL_TYPE_TDLS: + case IEEE80211_ML_CONTROL_TYPE_RECONF: /* * The length is the first octet pointed by mle->variable so no * need to add anything */ break; - case IEEE80211_ML_CONTROL_TYPE_RECONF: - if (control & IEEE80211_MLC_RECONF_PRES_MLD_MAC_ADDR) - common += ETH_ALEN; - return common; case IEEE80211_ML_CONTROL_TYPE_PRIO_ACCESS: if (control & IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR) common += ETH_ALEN; -- cgit v1.2.3 From eeec7574ec3c03c69adc99492df74dc1cc0ebd63 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:46 +0300 Subject: wifi: ieee80211: add helper to validate ML element type and size The helper functions to retrieve the EML capabilities and medium synchronization delay both assume that the type is correct. Instead of assuming the length is correct and still checking the type, add a new helper to check both and don't do any verification. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214435.1b50e7a3b3cf.I9385514d8eb6d6d3c82479a6fa732ef65313e554@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 50 +++++++++++++++++++++++++++++------------------ net/mac80211/mlme.c | 3 ++- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 97edc3b404dd..b107f21e1233 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4639,10 +4639,10 @@ static inline u8 ieee80211_mle_common_size(const u8 *data) * ieee80211_mle_get_eml_sync_delay - returns the medium sync delay * @data: pointer to the multi link EHT IE * - * The element is assumed to be big enough. This must be checked by - * ieee80211_mle_size_ok(). - * If the medium synchronization can't be found (the type is not basic, or - * the medium sync presence bit is clear), 0 will be returned. + * The element is assumed to be of the correct type (BASIC) and big enough, + * this must be checked using ieee80211_mle_type_ok(). + * + * If the medium synchronization is not present, then 0 is returned. */ static inline u16 ieee80211_mle_get_eml_med_sync_delay(const u8 *data) { @@ -4650,13 +4650,7 @@ static inline u16 ieee80211_mle_get_eml_med_sync_delay(const u8 *data) u16 control = le16_to_cpu(mle->control); const u8 *common = mle->variable; - if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) != - IEEE80211_ML_CONTROL_TYPE_BASIC) - return 0; - - /* common points now at the beginning of - * ieee80211_mle_basic_common_info - */ + /* common points now at the beginning of ieee80211_mle_basic_common_info */ common += sizeof(struct ieee80211_mle_basic_common_info); if (!(control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) @@ -4674,10 +4668,10 @@ static inline u16 ieee80211_mle_get_eml_med_sync_delay(const u8 *data) * ieee80211_mle_get_eml_cap - returns the EML capability * @data: pointer to the multi link EHT IE * - * The element is assumed to be big enough. This must be checked by - * ieee80211_mle_size_ok(). - * If the EML capability can't be found (the type is not basic, or - * the EML capability presence bit is clear), 0 will be returned. + * The element is assumed to be of the correct type (BASIC) and big enough, + * this must be checked using ieee80211_mle_type_ok(). + * + * If the EML capability is not present, 0 will be returned. */ static inline u16 ieee80211_mle_get_eml_cap(const u8 *data) { @@ -4685,10 +4679,6 @@ static inline u16 ieee80211_mle_get_eml_cap(const u8 *data) u16 control = le16_to_cpu(mle->control); const u8 *common = mle->variable; - if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) != - IEEE80211_ML_CONTROL_TYPE_BASIC) - return 0; - /* common points now at the beginning of ieee80211_mle_basic_common_info */ common += sizeof(struct ieee80211_mle_basic_common_info); @@ -4773,6 +4763,28 @@ static inline bool ieee80211_mle_size_ok(const u8 *data, size_t len) return mle->variable[0] >= common; } +/** + * ieee80211_mle_type_ok - validate multi-link element type and size + * @data: pointer to the element data + * @type: expected type of the element + * @len: length of the containing element + */ +static inline bool ieee80211_mle_type_ok(const u8 *data, u8 type, size_t len) +{ + const struct ieee80211_multi_link_elem *mle = (const void *)data; + u16 control; + + if (!ieee80211_mle_size_ok(data, len)) + return false; + + control = le16_to_cpu(mle->control); + + if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) == type) + return true; + + return false; +} + enum ieee80211_mle_subelems { IEEE80211_MLE_SUBELEM_PER_STA_PROFILE = 0, IEEE80211_MLE_SUBELEM_FRAGMENT = 254, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b8f8220cd9ff..30588703ffd3 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4852,7 +4852,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, /* data + 1 / datalen - 1 since it's an extended element */ if (eht_ml_elem && - ieee80211_mle_size_ok(eht_ml_elem->data + 1, + ieee80211_mle_type_ok(eht_ml_elem->data + 1, + IEEE80211_ML_CONTROL_TYPE_BASIC, eht_ml_elem->datalen - 1)) { sdata->vif.cfg.eml_cap = ieee80211_mle_get_eml_cap(eht_ml_elem->data + 1); -- cgit v1.2.3 From 39bcc5b8e16e75cfccc36fca3d425c64eef3df04 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:47 +0300 Subject: wifi: ieee80211: use default for medium synchronization delay Default values are defined for the information included in the Medium Synchronization Delay Information subfield. The spec says to initialize the values to these defaults and only change them when included. Return the default value instead of zero so that the defaults are used when the field is not included in the association response. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214435.a7725bef3795.I2d3528cf4af021c5b37f97fbe64ae9116ce9bef1@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index b107f21e1233..251998be24d0 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4535,6 +4535,14 @@ struct ieee80211_multi_link_elem { #define IEEE80211_MED_SYNC_DELAY_SYNC_OFDM_ED_THRESH 0x0f00 #define IEEE80211_MED_SYNC_DELAY_SYNC_MAX_NUM_TXOPS 0xf000 +/* + * Described in P802.11be_D3.0 + * dot11MSDTimerDuration should default to 5484 (i.e. 171.375) + * dot11MSDOFDMEDthreshold defaults to -72 (i.e. 0) + * dot11MSDTXOPMAX defaults to 1 + */ +#define IEEE80211_MED_SYNC_DELAY_DEFAULT 0x10ac + #define IEEE80211_EML_CAP_EMLSR_SUPP 0x0001 #define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY 0x000e #define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_0US 0 @@ -4642,7 +4650,8 @@ static inline u8 ieee80211_mle_common_size(const u8 *data) * The element is assumed to be of the correct type (BASIC) and big enough, * this must be checked using ieee80211_mle_type_ok(). * - * If the medium synchronization is not present, then 0 is returned. + * If the medium synchronization is not present, then the default value is + * returned. */ static inline u16 ieee80211_mle_get_eml_med_sync_delay(const u8 *data) { @@ -4654,7 +4663,7 @@ static inline u16 ieee80211_mle_get_eml_med_sync_delay(const u8 *data) common += sizeof(struct ieee80211_mle_basic_common_info); if (!(control & IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) - return 0; + return IEEE80211_MED_SYNC_DELAY_DEFAULT; if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) common += 1; -- cgit v1.2.3 From 891d4d5831ee4c5e45a3ccba11577cdc6e57a726 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:48 +0300 Subject: wifi: cfg80211: Always ignore ML element The element should never be inherited, so always exclude it. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214435.c0e17989b4ed.I7cecb5ab7cd6919e61839b50ce5156904b41d7d8@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index dc71c6ac5bf5..095dc9db8750 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -218,6 +218,10 @@ bool cfg80211_is_element_inherited(const struct element *elem, if (elem->id == WLAN_EID_MULTIPLE_BSSID) return false; + if (elem->id == WLAN_EID_EXTENSION && elem->datalen > 1 && + elem->data[0] == WLAN_EID_EXT_EHT_MULTI_LINK) + return false; + if (!non_inherit_elem || non_inherit_elem->datalen < 2) return true; -- cgit v1.2.3 From 66d9c573fbb992f11d29a907c339792ee0de82ee Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:49 +0300 Subject: wifi: ieee80211: add definitions for RNR MLD params Add the definitions necessary to parse the MLD parameters included in an RNR element. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.9999842237c0.I80f00a90cb4e43071432b4158f206c73ba799618@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 251998be24d0..7afd08d2de2f 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4485,6 +4485,7 @@ static inline bool for_each_element_completed(const struct element *element, #define IEEE80211_TBTT_INFO_TYPE_MLD 1 #define IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM 9 #define IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM 13 +#define IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM_MLD_PARAM 16 #define IEEE80211_RNR_TBTT_PARAMS_OCT_RECOMMENDED 0x01 #define IEEE80211_RNR_TBTT_PARAMS_SAME_SSID 0x02 @@ -4508,6 +4509,20 @@ enum ieee80211_range_params_max_total_ltf { IEEE80211_RANGE_PARAMS_MAX_TOTAL_LTF_UNSPECIFIED, }; +/* + * reduced neighbor report, based on Draft P802.11be_D3.0, + * section 9.4.2.170.2. + */ +struct ieee80211_rnr_mld_params { + u8 mld_id; + __le16 params; +} __packed; + +#define IEEE80211_RNR_MLD_PARAMS_LINK_ID 0x000F +#define IEEE80211_RNR_MLD_PARAMS_BSS_CHANGE_COUNT 0x0FF0 +#define IEEE80211_RNR_MLD_PARAMS_UPDATES_INCLUDED 0x1000 +#define IEEE80211_RNR_MLD_PARAMS_DISABLED_LINK 0x2000 + /* multi-link device */ #define IEEE80211_MLD_MAX_NUM_LINKS 15 -- cgit v1.2.3 From eb142608e2c4ea0acefefb00025af523195d30d3 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:50 +0300 Subject: wifi: cfg80211: use a struct for inform_single_bss data The argument is getting quite large, so use a struct internally to pass around the information. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.831ab8a87b6f.I3bcc83d90f41d6f8a47b39528575dad0a9ec3564@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 209 ++++++++++++++++++++++++++++------------------------ 1 file changed, 112 insertions(+), 97 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 095dc9db8750..974a6a8240dd 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1644,12 +1644,6 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, return true; } -struct cfg80211_non_tx_bss { - struct cfg80211_bss *tx_bss; - u8 max_bssid_indicator; - u8 bssid_index; -}; - static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known, const struct cfg80211_bss_ies *new_ies, const struct cfg80211_bss_ies *old_ies) @@ -1977,17 +1971,30 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, return alt_channel; } +struct cfg80211_inform_single_bss_data { + struct cfg80211_inform_bss *drv_data; + enum cfg80211_bss_frame_type ftype; + u8 bssid[ETH_ALEN]; + u64 tsf; + u16 capability; + u16 beacon_interval; + const u8 *ie; + size_t ielen; + + /* Set for nontransmitted BSSIDs */ + struct cfg80211_bss *source_bss; + u8 max_bssid_indicator; + u8 bssid_index; +}; + /* Returned bss is reference counted and must be cleaned up appropriately. */ static struct cfg80211_bss * cfg80211_inform_single_bss_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - enum cfg80211_bss_frame_type ftype, - const u8 *bssid, u64 tsf, u16 capability, - u16 beacon_interval, const u8 *ie, size_t ielen, - struct cfg80211_non_tx_bss *non_tx_data, + struct cfg80211_inform_single_bss_data *data, gfp_t gfp) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + struct cfg80211_inform_bss *drv_data = data->drv_data; struct cfg80211_bss_ies *ies; struct ieee80211_channel *channel; struct cfg80211_internal_bss tmp = {}, *res; @@ -1999,40 +2006,41 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, return NULL; if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && - (data->signal < 0 || data->signal > 100))) + (drv_data->signal < 0 || drv_data->signal > 100))) return NULL; - channel = cfg80211_get_bss_channel(wiphy, ie, ielen, data->chan, - data->scan_width); + channel = cfg80211_get_bss_channel(wiphy, data->ie, data->ielen, + drv_data->chan, drv_data->scan_width); if (!channel) return NULL; - memcpy(tmp.pub.bssid, bssid, ETH_ALEN); + memcpy(tmp.pub.bssid, data->bssid, ETH_ALEN); tmp.pub.channel = channel; - tmp.pub.scan_width = data->scan_width; - tmp.pub.signal = data->signal; - tmp.pub.beacon_interval = beacon_interval; - tmp.pub.capability = capability; - tmp.ts_boottime = data->boottime_ns; - tmp.parent_tsf = data->parent_tsf; - ether_addr_copy(tmp.parent_bssid, data->parent_bssid); - - if (non_tx_data) { - tmp.pub.transmitted_bss = non_tx_data->tx_bss; - ts = bss_from_pub(non_tx_data->tx_bss)->ts; - tmp.pub.bssid_index = non_tx_data->bssid_index; - tmp.pub.max_bssid_indicator = non_tx_data->max_bssid_indicator; + tmp.pub.scan_width = drv_data->scan_width; + tmp.pub.signal = drv_data->signal; + tmp.pub.beacon_interval = data->beacon_interval; + tmp.pub.capability = data->capability; + tmp.ts_boottime = drv_data->boottime_ns; + tmp.parent_tsf = drv_data->parent_tsf; + ether_addr_copy(tmp.parent_bssid, drv_data->parent_bssid); + + if (data->source_bss) { + tmp.pub.transmitted_bss = data->source_bss; + ts = bss_from_pub(data->source_bss)->ts; + tmp.pub.bssid_index = data->bssid_index; + tmp.pub.max_bssid_indicator = data->max_bssid_indicator; } else { ts = jiffies; if (channel->band == NL80211_BAND_60GHZ) { - bss_type = capability & WLAN_CAPABILITY_DMG_TYPE_MASK; + bss_type = data->capability & + WLAN_CAPABILITY_DMG_TYPE_MASK; if (bss_type == WLAN_CAPABILITY_DMG_TYPE_AP || bss_type == WLAN_CAPABILITY_DMG_TYPE_PBSS) regulatory_hint_found_beacon(wiphy, channel, gfp); } else { - if (capability & WLAN_CAPABILITY_ESS) + if (data->capability & WLAN_CAPABILITY_ESS) regulatory_hint_found_beacon(wiphy, channel, gfp); } @@ -2046,15 +2054,15 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, * override the IEs pointer should we have received an earlier * indication of Probe Response data. */ - ies = kzalloc(sizeof(*ies) + ielen, gfp); + ies = kzalloc(sizeof(*ies) + data->ielen, gfp); if (!ies) return NULL; - ies->len = ielen; - ies->tsf = tsf; + ies->len = data->ielen; + ies->tsf = data->tsf; ies->from_beacon = false; - memcpy(ies->data, ie, ielen); + memcpy(ies->data, data->ie, data->ielen); - switch (ftype) { + switch (data->ftype) { case CFG80211_BSS_FTYPE_BEACON: ies->from_beacon = true; fallthrough; @@ -2067,7 +2075,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, } rcu_assign_pointer(tmp.pub.ies, ies); - signal_valid = data->chan == channel; + signal_valid = drv_data->chan == channel; spin_lock_bh(&rdev->bss_lock); res = __cfg80211_bss_update(rdev, &tmp, signal_valid, ts); if (!res) @@ -2075,12 +2083,11 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, rdev_inform_bss(rdev, &res->pub, ies, data->drv_data); - if (non_tx_data) { + if (data->source_bss) { /* this is a nontransmitting bss, we need to add it to * transmitting bss' list if it is not there */ - if (cfg80211_add_nontrans_list(non_tx_data->tx_bss, - &res->pub)) { + if (cfg80211_add_nontrans_list(data->source_bss, &res->pub)) { if (__cfg80211_unlink_bss(rdev, res)) { rdev->bss_generation++; res = NULL; @@ -2173,43 +2180,47 @@ size_t cfg80211_merge_profile(const u8 *ie, size_t ielen, } EXPORT_SYMBOL(cfg80211_merge_profile); -static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, - struct cfg80211_inform_bss *data, - enum cfg80211_bss_frame_type ftype, - const u8 *bssid, u64 tsf, - u16 beacon_interval, const u8 *ie, - size_t ielen, - struct cfg80211_non_tx_bss *non_tx_data, - gfp_t gfp) -{ +static void +cfg80211_parse_mbssid_data(struct wiphy *wiphy, + struct cfg80211_inform_single_bss_data *tx_data, + struct cfg80211_bss *source_bss, + gfp_t gfp) +{ + struct cfg80211_inform_single_bss_data data = { + .drv_data = tx_data->drv_data, + .ftype = tx_data->ftype, + .tsf = tx_data->tsf, + .beacon_interval = tx_data->beacon_interval, + .source_bss = source_bss, + }; const u8 *mbssid_index_ie; const struct element *elem, *sub; - size_t new_ie_len; - u8 new_bssid[ETH_ALEN]; u8 *new_ie, *profile; u64 seen_indices = 0; - u16 capability; struct cfg80211_bss *bss; - if (!non_tx_data) + if (!source_bss) return; - if (!cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID, ie, ielen)) + if (!cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID, + tx_data->ie, tx_data->ielen)) return; if (!wiphy->support_mbssid) return; if (wiphy->support_only_he_mbssid && - !cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, ie, ielen)) + !cfg80211_find_ext_elem(WLAN_EID_EXT_HE_CAPABILITY, + tx_data->ie, tx_data->ielen)) return; new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp); if (!new_ie) return; - profile = kmalloc(ielen, gfp); + profile = kmalloc(tx_data->ielen, gfp); if (!profile) goto out; - for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) { + for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, + tx_data->ie, tx_data->ielen) { if (elem->datalen < 4) continue; if (elem->data[0] < 1 || (int)elem->data[0] > 8) @@ -2231,12 +2242,13 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, continue; } - memset(profile, 0, ielen); - profile_len = cfg80211_merge_profile(ie, ielen, + memset(profile, 0, tx_data->ielen); + profile_len = cfg80211_merge_profile(tx_data->ie, + tx_data->ielen, elem, sub, profile, - ielen); + tx_data->ielen); /* found a Nontransmitted BSSID Profile */ mbssid_index_ie = cfg80211_find_ie @@ -2256,31 +2268,27 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy, seen_indices |= BIT_ULL(mbssid_index_ie[2]); - non_tx_data->bssid_index = mbssid_index_ie[2]; - non_tx_data->max_bssid_indicator = elem->data[0]; + data.bssid_index = mbssid_index_ie[2]; + data.max_bssid_indicator = elem->data[0]; + + cfg80211_gen_new_bssid(tx_data->bssid, + data.max_bssid_indicator, + data.bssid_index, + data.bssid); - cfg80211_gen_new_bssid(bssid, - non_tx_data->max_bssid_indicator, - non_tx_data->bssid_index, - new_bssid); memset(new_ie, 0, IEEE80211_MAX_DATA_LEN); - new_ie_len = cfg80211_gen_new_ie(ie, ielen, + data.ie = new_ie; + data.ielen = cfg80211_gen_new_ie(tx_data->ie, + tx_data->ielen, profile, - profile_len, new_ie, + profile_len, + new_ie, IEEE80211_MAX_DATA_LEN); - if (!new_ie_len) + if (!data.ielen) continue; - capability = get_unaligned_le16(profile + 2); - bss = cfg80211_inform_single_bss_data(wiphy, data, - ftype, - new_bssid, tsf, - capability, - beacon_interval, - new_ie, - new_ie_len, - non_tx_data, - gfp); + data.capability = get_unaligned_le16(profile + 2); + bss = cfg80211_inform_single_bss_data(wiphy, &data, gfp); if (!bss) break; cfg80211_put_bss(wiphy, bss); @@ -2360,18 +2368,24 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, u16 beacon_interval, const u8 *ie, size_t ielen, gfp_t gfp) { + struct cfg80211_inform_single_bss_data inform_data = { + .drv_data = data, + .ftype = ftype, + .tsf = tsf, + .capability = capability, + .beacon_interval = beacon_interval, + .ie = ie, + .ielen = ielen, + }; struct cfg80211_bss *res; - struct cfg80211_non_tx_bss non_tx_data; - res = cfg80211_inform_single_bss_data(wiphy, data, ftype, bssid, tsf, - capability, beacon_interval, ie, - ielen, NULL, gfp); + memcpy(inform_data.bssid, bssid, ETH_ALEN); + + res = cfg80211_inform_single_bss_data(wiphy, &inform_data, gfp); if (!res) return NULL; - non_tx_data.tx_bss = res; - cfg80211_parse_mbssid_data(wiphy, data, ftype, bssid, tsf, - beacon_interval, ie, ielen, &non_tx_data, - gfp); + + cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); return res; } EXPORT_SYMBOL(cfg80211_inform_bss_data); @@ -2517,12 +2531,13 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, struct ieee80211_mgmt *mgmt, size_t len, gfp_t gfp) { + struct cfg80211_inform_single_bss_data inform_data = { + .drv_data = data, + .ie = mgmt->u.probe_resp.variable, + .ielen = len - offsetof(struct ieee80211_mgmt, + u.probe_resp.variable), + }; struct cfg80211_bss *res; - const u8 *ie = mgmt->u.probe_resp.variable; - size_t ielen = len - offsetof(struct ieee80211_mgmt, - u.probe_resp.variable); - enum cfg80211_bss_frame_type ftype; - struct cfg80211_non_tx_bss non_tx_data = {}; res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt, len, gfp); @@ -2533,15 +2548,15 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, if (ieee80211_is_s1g_beacon(mgmt->frame_control)) return res; - ftype = ieee80211_is_beacon(mgmt->frame_control) ? + inform_data.ftype = ieee80211_is_beacon(mgmt->frame_control) ? CFG80211_BSS_FTYPE_BEACON : CFG80211_BSS_FTYPE_PRESP; - non_tx_data.tx_bss = res; + memcpy(inform_data.bssid, mgmt->bssid, ETH_ALEN); + inform_data.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); + inform_data.beacon_interval = + le16_to_cpu(mgmt->u.probe_resp.beacon_int); /* process each non-transmitting bss */ - cfg80211_parse_mbssid_data(wiphy, data, ftype, mgmt->bssid, - le64_to_cpu(mgmt->u.probe_resp.timestamp), - le16_to_cpu(mgmt->u.probe_resp.beacon_int), - ie, ielen, &non_tx_data, gfp); + cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); return res; } -- cgit v1.2.3 From 50181fe4f59dcfae391523def6f62e32d86c46b1 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:51 +0300 Subject: wifi: ieee80211: add structs for TBTT information access The TBTT information can have various lengths with different elements thare are present. Add definitions for the two types that we are interested in (i.e. the ones that contain the BSSID). Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.2a6f8766a3ec.Ic962e28492212cc8ee1eb602b8f07a4ea172fc4a@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 7afd08d2de2f..5a27c232afdb 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4523,6 +4523,28 @@ struct ieee80211_rnr_mld_params { #define IEEE80211_RNR_MLD_PARAMS_UPDATES_INCLUDED 0x1000 #define IEEE80211_RNR_MLD_PARAMS_DISABLED_LINK 0x2000 +/* Format of the TBTT information element if it has 7, 8 or 9 bytes */ +struct ieee80211_tbtt_info_7_8_9 { + u8 tbtt_offset; + u8 bssid[ETH_ALEN]; + + /* The following element is optional, structure may not grow */ + u8 bss_params; + u8 psd_20; +} __packed; + +/* Format of the TBTT information element if it has >= 11 bytes */ +struct ieee80211_tbtt_info_ge_11 { + u8 tbtt_offset; + u8 bssid[ETH_ALEN]; + __le32 short_ssid; + + /* The following elements are optional, structure may grow */ + u8 bss_params; + u8 psd_20; + struct ieee80211_rnr_mld_params mld_params; +} __packed; + /* multi-link device */ #define IEEE80211_MLD_MAX_NUM_LINKS 15 -- cgit v1.2.3 From dc92e54c30c4bc9d30e674a445dfe1afdca991cf Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:52 +0300 Subject: wifi: cfg80211: use structs for TBTT information access Make the data access a bit nicer overall by using structs. There is a small change here to also accept a TBTT information length of eight bytes as we do not require the 20 MHz PSD information. This also fixes a bug reading the short SSID on big endian machines. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.4c3f8901c1bc.Ic3e94fd6e1bccff7948a252ad3bb87e322690a17@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 3 --- net/wireless/scan.c | 61 +++++++++++++++++++++++++---------------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 5a27c232afdb..e145af7448a3 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4483,9 +4483,6 @@ static inline bool for_each_element_completed(const struct element *element, #define IEEE80211_AP_INFO_TBTT_HDR_COUNT 0xF0 #define IEEE80211_TBTT_INFO_TYPE_TBTT 0 #define IEEE80211_TBTT_INFO_TYPE_MLD 1 -#define IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM 9 -#define IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM 13 -#define IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM_MLD_PARAM 16 #define IEEE80211_RNR_TBTT_PARAMS_OCT_RECOMMENDED 0x01 #define IEEE80211_RNR_TBTT_PARAMS_SAME_SSID 0x02 diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 974a6a8240dd..f0b4d7671d17 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -574,39 +574,41 @@ static void cfg80211_free_coloc_ap_list(struct list_head *coloc_ap_list) static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, const u8 *pos, u8 length, const struct element *ssid_elem, - int s_ssid_tmp) + u32 s_ssid_tmp) { - /* skip the TBTT offset */ - pos++; + u8 bss_params; - /* ignore entries with invalid BSSID */ - if (!is_valid_ether_addr(pos)) - return -EINVAL; - - memcpy(entry->bssid, pos, ETH_ALEN); - pos += ETH_ALEN; + /* The length is already verified by the caller to contain bss_params */ + if (length > sizeof(struct ieee80211_tbtt_info_7_8_9)) { + struct ieee80211_tbtt_info_ge_11 *tbtt_info = (void *)pos; - if (length >= IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM) { - memcpy(&entry->short_ssid, pos, - sizeof(entry->short_ssid)); + memcpy(entry->bssid, tbtt_info->bssid, ETH_ALEN); + entry->short_ssid = le32_to_cpu(tbtt_info->short_ssid); entry->short_ssid_valid = true; - pos += 4; + + bss_params = tbtt_info->bss_params; + } else { + struct ieee80211_tbtt_info_7_8_9 *tbtt_info = (void *)pos; + + memcpy(entry->bssid, tbtt_info->bssid, ETH_ALEN); + + bss_params = tbtt_info->bss_params; } + /* ignore entries with invalid BSSID */ + if (!is_valid_ether_addr(entry->bssid)) + return -EINVAL; + /* skip non colocated APs */ - if (!cfg80211_parse_bss_param(*pos, entry)) + if (!cfg80211_parse_bss_param(bss_params, entry)) return -EINVAL; - pos++; - if (length == IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM) { - /* - * no information about the short ssid. Consider the entry valid - * for now. It would later be dropped in case there are explicit - * SSIDs that need to be matched - */ - if (!entry->same_ssid) - return 0; - } + /* no information about the short ssid. Consider the entry valid + * for now. It would later be dropped in case there are explicit + * SSIDs that need to be matched + */ + if (!entry->same_ssid && !entry->short_ssid_valid) + return 0; if (entry->same_ssid) { entry->short_ssid = s_ssid_tmp; @@ -617,10 +619,10 @@ static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, * cfg80211_parse_colocated_ap(), before calling this * function. */ - memcpy(&entry->ssid, &ssid_elem->data, - ssid_elem->datalen); + memcpy(&entry->ssid, &ssid_elem->data, ssid_elem->datalen); entry->ssid_len = ssid_elem->datalen; } + return 0; } @@ -682,8 +684,11 @@ static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, * next AP info */ if (band != NL80211_BAND_6GHZ || - (length != IEEE80211_TBTT_INFO_OFFSET_BSSID_BSS_PARAM && - length < IEEE80211_TBTT_INFO_OFFSET_BSSID_SSSID_BSS_PARAM)) { + !(length == offsetofend(struct ieee80211_tbtt_info_7_8_9, + bss_params) || + length == sizeof(struct ieee80211_tbtt_info_7_8_9) || + length >= offsetofend(struct ieee80211_tbtt_info_ge_11, + bss_params))) { pos += count * length; continue; } -- cgit v1.2.3 From 2481b5da9c6b2ee1fde55a1c29eb2ca377145a10 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:53 +0300 Subject: wifi: cfg80211: handle BSS data contained in ML probe responses The basic multi-link element within an multi-link probe response will contain full information about BSSes that are part of an MLD AP. This BSS information may be used to associate with a link of an MLD AP without having received a beacon from the BSS itself. This patch adds parsing of the data and adding/updating the BSS using the received elements. Doing this means that userspace can discover the BSSes using an ML probe request and request association on these links. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.29593bd0ae1f.Ic9a67b8f022360aa202b870a932897a389171b14@changeid [swap loop conditions smatch complained about] Signed-off-by: Johannes Berg --- net/wireless/scan.c | 361 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 354 insertions(+), 7 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index f0b4d7671d17..2e7787b0828b 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1979,6 +1979,7 @@ cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen, struct cfg80211_inform_single_bss_data { struct cfg80211_inform_bss *drv_data; enum cfg80211_bss_frame_type ftype; + struct ieee80211_channel *channel; u8 bssid[ETH_ALEN]; u64 tsf; u16 capability; @@ -1986,7 +1987,12 @@ struct cfg80211_inform_single_bss_data { const u8 *ie; size_t ielen; - /* Set for nontransmitted BSSIDs */ + enum { + BSS_SOURCE_DIRECT = 0, + BSS_SOURCE_MBSSID, + BSS_SOURCE_STA_PROFILE, + } bss_source; + /* Set if reporting bss_source != BSS_SOURCE_DIRECT */ struct cfg80211_bss *source_bss; u8 max_bssid_indicator; u8 bssid_index; @@ -2014,22 +2020,31 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, (drv_data->signal < 0 || drv_data->signal > 100))) return NULL; - channel = cfg80211_get_bss_channel(wiphy, data->ie, data->ielen, - drv_data->chan, drv_data->scan_width); + if (WARN_ON(data->bss_source != BSS_SOURCE_DIRECT && !data->source_bss)) + return NULL; + + channel = data->channel; + if (!channel) + channel = cfg80211_get_bss_channel(wiphy, data->ie, data->ielen, + drv_data->chan, + drv_data->scan_width); if (!channel) return NULL; memcpy(tmp.pub.bssid, data->bssid, ETH_ALEN); tmp.pub.channel = channel; tmp.pub.scan_width = drv_data->scan_width; - tmp.pub.signal = drv_data->signal; + if (data->bss_source != BSS_SOURCE_STA_PROFILE) + tmp.pub.signal = drv_data->signal; + else + tmp.pub.signal = 0; tmp.pub.beacon_interval = data->beacon_interval; tmp.pub.capability = data->capability; tmp.ts_boottime = drv_data->boottime_ns; tmp.parent_tsf = drv_data->parent_tsf; ether_addr_copy(tmp.parent_bssid, drv_data->parent_bssid); - if (data->source_bss) { + if (data->bss_source != BSS_SOURCE_DIRECT) { tmp.pub.transmitted_bss = data->source_bss; ts = bss_from_pub(data->source_bss)->ts; tmp.pub.bssid_index = data->bssid_index; @@ -2088,7 +2103,7 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, rdev_inform_bss(rdev, &res->pub, ies, data->drv_data); - if (data->source_bss) { + if (data->bss_source == BSS_SOURCE_MBSSID) { /* this is a nontransmitting bss, we need to add it to * transmitting bss' list if it is not there */ @@ -2197,6 +2212,7 @@ cfg80211_parse_mbssid_data(struct wiphy *wiphy, .tsf = tx_data->tsf, .beacon_interval = tx_data->beacon_interval, .source_bss = source_bss, + .bss_source = BSS_SOURCE_MBSSID, }; const u8 *mbssid_index_ie; const struct element *elem, *sub; @@ -2365,6 +2381,332 @@ ssize_t cfg80211_defragment_element(const struct element *elem, const u8 *ies, } EXPORT_SYMBOL(cfg80211_defragment_element); +struct cfg80211_mle { + struct ieee80211_multi_link_elem *mle; + struct ieee80211_mle_per_sta_profile + *sta_prof[IEEE80211_MLD_MAX_NUM_LINKS]; + ssize_t sta_prof_len[IEEE80211_MLD_MAX_NUM_LINKS]; + + u8 data[]; +}; + +static struct cfg80211_mle * +cfg80211_defrag_mle(const struct element *mle, const u8 *ie, size_t ielen, + gfp_t gfp) +{ + const struct element *elem; + struct cfg80211_mle *res; + size_t buf_len; + ssize_t mle_len; + u8 common_size, idx; + + if (!mle || !ieee80211_mle_size_ok(mle->data + 1, mle->datalen - 1)) + return NULL; + + /* Required length for first defragmentation */ + buf_len = mle->datalen - 1; + for_each_element(elem, mle->data + mle->datalen, + ielen - sizeof(*mle) + mle->datalen) { + if (elem->id != WLAN_EID_FRAGMENT) + break; + + buf_len += elem->datalen; + } + + res = kzalloc(struct_size(res, data, buf_len), gfp); + if (!res) + return NULL; + + mle_len = cfg80211_defragment_element(mle, ie, ielen, + res->data, buf_len, + WLAN_EID_FRAGMENT); + if (mle_len < 0) + goto error; + + res->mle = (void *)res->data; + + /* Find the sub-element area in the buffer */ + common_size = ieee80211_mle_common_size((u8 *)res->mle); + ie = res->data + common_size; + ielen = mle_len - common_size; + + idx = 0; + for_each_element_id(elem, IEEE80211_MLE_SUBELEM_PER_STA_PROFILE, + ie, ielen) { + res->sta_prof[idx] = (void *)elem->data; + res->sta_prof_len[idx] = elem->datalen; + + idx++; + if (idx >= IEEE80211_MLD_MAX_NUM_LINKS) + break; + } + if (!for_each_element_completed(elem, ie, ielen)) + goto error; + + /* Defragment sta_info in-place */ + for (idx = 0; idx < IEEE80211_MLD_MAX_NUM_LINKS && res->sta_prof[idx]; + idx++) { + if (res->sta_prof_len[idx] < 255) + continue; + + elem = (void *)res->sta_prof[idx] - 2; + + if (idx + 1 < ARRAY_SIZE(res->sta_prof) && + res->sta_prof[idx + 1]) + buf_len = (u8 *)res->sta_prof[idx + 1] - + (u8 *)res->sta_prof[idx]; + else + buf_len = ielen + ie - (u8 *)elem; + + res->sta_prof_len[idx] = + cfg80211_defragment_element(elem, + (u8 *)elem, buf_len, + (u8 *)res->sta_prof[idx], + buf_len, + IEEE80211_MLE_SUBELEM_FRAGMENT); + if (res->sta_prof_len[idx] < 0) + goto error; + } + + return res; + +error: + kfree(res); + return NULL; +} + +static bool +cfg80211_tbtt_info_for_mld_ap(const u8 *ie, size_t ielen, u8 mld_id, u8 link_id, + const struct ieee80211_neighbor_ap_info **ap_info, + const u8 **tbtt_info) +{ + const struct ieee80211_neighbor_ap_info *info; + const struct element *rnr; + const u8 *pos, *end; + + for_each_element_id(rnr, WLAN_EID_REDUCED_NEIGHBOR_REPORT, ie, ielen) { + pos = rnr->data; + end = rnr->data + rnr->datalen; + + /* RNR IE may contain more than one NEIGHBOR_AP_INFO */ + while (sizeof(*info) <= end - pos) { + const struct ieee80211_rnr_mld_params *mld_params; + u16 params; + u8 length, i, count, mld_params_offset; + u8 type, lid; + + info = (void *)pos; + count = u8_get_bits(info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1; + length = info->tbtt_info_len; + + pos += sizeof(*info); + + if (count * length > end - pos) + return false; + + type = u8_get_bits(info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_TYPE); + + /* Only accept full TBTT information. NSTR mobile APs + * use the shortened version, but we ignore them here. + */ + if (type == IEEE80211_TBTT_INFO_TYPE_TBTT && + length >= + offsetofend(struct ieee80211_tbtt_info_ge_11, + mld_params)) { + mld_params_offset = + offsetof(struct ieee80211_tbtt_info_ge_11, mld_params); + } else { + pos += count * length; + continue; + } + + for (i = 0; i < count; i++) { + mld_params = (void *)pos + mld_params_offset; + params = le16_to_cpu(mld_params->params); + + lid = u16_get_bits(params, + IEEE80211_RNR_MLD_PARAMS_LINK_ID); + + if (mld_id == mld_params->mld_id && + link_id == lid) { + *ap_info = info; + *tbtt_info = pos; + + return true; + } + + pos += length; + } + } + } + + return false; +} + +static void cfg80211_parse_ml_sta_data(struct wiphy *wiphy, + struct cfg80211_inform_single_bss_data *tx_data, + struct cfg80211_bss *source_bss, + gfp_t gfp) +{ + struct cfg80211_inform_single_bss_data data = { + .drv_data = tx_data->drv_data, + .ftype = tx_data->ftype, + .source_bss = source_bss, + .bss_source = BSS_SOURCE_STA_PROFILE, + }; + struct ieee80211_multi_link_elem *ml_elem; + const struct element *elem; + struct cfg80211_mle *mle; + u16 control; + u8 *new_ie; + struct cfg80211_bss *bss; + int mld_id; + u16 seen_links = 0; + const u8 *pos; + u8 i; + + if (!source_bss) + return; + + if (tx_data->ftype != CFG80211_BSS_FTYPE_PRESP) + return; + + elem = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK, + tx_data->ie, tx_data->ielen); + if (!elem || !ieee80211_mle_size_ok(elem->data + 1, elem->datalen - 1)) + return; + + ml_elem = (void *)elem->data + 1; + control = le16_to_cpu(ml_elem->control); + if (u16_get_bits(control, IEEE80211_ML_CONTROL_TYPE) != + IEEE80211_ML_CONTROL_TYPE_BASIC) + return; + + /* Must be present when transmitted by an AP (in a probe response) */ + if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT) || + !(control & IEEE80211_MLC_BASIC_PRES_LINK_ID) || + !(control & IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP)) + return; + + /* length + MLD MAC address + link ID info + BSS Params Change Count */ + pos = ml_elem->variable + 1 + 6 + 1 + 1; + + if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MED_SYNC_DELAY)) + pos += 2; + if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_EML_CAPA)) + pos += 2; + + /* MLD capabilities and operations */ + pos += 2; + + /* Not included when the (nontransmitted) AP is responding itself, + * but defined to zero then (Draft P802.11be_D3.0, 9.4.2.170.2) + */ + if (u16_get_bits(control, IEEE80211_MLC_BASIC_PRES_MLD_ID)) { + mld_id = *pos; + pos += 1; + } else { + mld_id = 0; + } + + /* Extended MLD capabilities and operations */ + pos += 2; + + /* Fully defrag the ML element for sta information/profile iteration */ + mle = cfg80211_defrag_mle(elem, tx_data->ie, tx_data->ielen, gfp); + if (!mle) + return; + + new_ie = kmalloc(IEEE80211_MAX_DATA_LEN, gfp); + if (!new_ie) + goto out; + + for (i = 0; i < ARRAY_SIZE(mle->sta_prof) && mle->sta_prof[i]; i++) { + const struct ieee80211_neighbor_ap_info *ap_info; + enum nl80211_band band; + u32 freq; + const u8 *profile; + const u8 *tbtt_info; + ssize_t profile_len; + u8 link_id; + + if (!ieee80211_mle_basic_sta_prof_size_ok((u8 *)mle->sta_prof[i], + mle->sta_prof_len[i])) + continue; + + control = le16_to_cpu(mle->sta_prof[i]->control); + + if (!(control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE)) + continue; + + link_id = u16_get_bits(control, + IEEE80211_MLE_STA_CONTROL_LINK_ID); + if (seen_links & BIT(link_id)) + break; + seen_links |= BIT(link_id); + + if (!(control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT) || + !(control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT) || + !(control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT)) + continue; + + memcpy(data.bssid, mle->sta_prof[i]->variable, ETH_ALEN); + data.beacon_interval = + get_unaligned_le16(mle->sta_prof[i]->variable + 6); + data.tsf = tx_data->tsf + + get_unaligned_le64(mle->sta_prof[i]->variable + 8); + + /* sta_info_len counts itself */ + profile = mle->sta_prof[i]->variable + + mle->sta_prof[i]->sta_info_len - 1; + profile_len = (u8 *)mle->sta_prof[i] + mle->sta_prof_len[i] - + profile; + + if (profile_len < 2) + continue; + + data.capability = get_unaligned_le16(profile); + profile += 2; + profile_len -= 2; + + /* Find in RNR to look up channel information */ + if (!cfg80211_tbtt_info_for_mld_ap(tx_data->ie, tx_data->ielen, + mld_id, link_id, + &ap_info, &tbtt_info)) + continue; + + /* We could sanity check the BSSID is included */ + + if (!ieee80211_operating_class_to_band(ap_info->op_class, + &band)) + continue; + + freq = ieee80211_channel_to_freq_khz(ap_info->channel, band); + data.channel = ieee80211_get_channel_khz(wiphy, freq); + + /* Generate new elements */ + memset(new_ie, 0, IEEE80211_MAX_DATA_LEN); + data.ie = new_ie; + data.ielen = cfg80211_gen_new_ie(tx_data->ie, tx_data->ielen, + profile, profile_len, + new_ie, + IEEE80211_MAX_DATA_LEN); + if (!data.ielen) + continue; + + bss = cfg80211_inform_single_bss_data(wiphy, &data, gfp); + if (!bss) + break; + cfg80211_put_bss(wiphy, bss); + } + +out: + kfree(new_ie); + kfree(mle); +} + struct cfg80211_bss * cfg80211_inform_bss_data(struct wiphy *wiphy, struct cfg80211_inform_bss *data, @@ -2391,6 +2733,9 @@ cfg80211_inform_bss_data(struct wiphy *wiphy, return NULL; cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); + + cfg80211_parse_ml_sta_data(wiphy, &inform_data, res, gfp); + return res; } EXPORT_SYMBOL(cfg80211_inform_bss_data); @@ -2549,7 +2894,7 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, if (!res) return NULL; - /* don't do any further MBSSID handling for S1G */ + /* don't do any further MBSSID/ML handling for S1G */ if (ieee80211_is_s1g_beacon(mgmt->frame_control)) return res; @@ -2563,6 +2908,8 @@ cfg80211_inform_bss_frame_data(struct wiphy *wiphy, /* process each non-transmitting bss */ cfg80211_parse_mbssid_data(wiphy, &inform_data, res, gfp); + cfg80211_parse_ml_sta_data(wiphy, &inform_data, res, gfp); + return res; } EXPORT_SYMBOL(cfg80211_inform_bss_frame_data); -- cgit v1.2.3 From a0ed50112b98fa8e9bc85dbeafc82fd97ee06716 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:49:54 +0300 Subject: wifi: cfg80211: do not scan disabled links on 6GHz If a link is disabled on 6GHz, we should not send a probe request on the channel to resolve it. Simply skip such RNR entries so that the link is ignored. Userspace can still see the link in the RNR and may generate an ML probe request in order to associate to the (currently) disabled link. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.4f7384006471.Iff8f1081e76a298bd25f9468abb3a586372cddaa@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 2e7787b0828b..df868662e1e0 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -587,6 +587,13 @@ static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, entry->short_ssid_valid = true; bss_params = tbtt_info->bss_params; + + /* Ignore disabled links */ + if (length >= offsetofend(typeof(*tbtt_info), mld_params)) { + if (le16_get_bits(tbtt_info->mld_params.params, + IEEE80211_RNR_MLD_PARAMS_DISABLED_LINK)) + return -EINVAL; + } } else { struct ieee80211_tbtt_info_7_8_9 *tbtt_info = (void *)pos; -- cgit v1.2.3 From 065563b20a664a6575dc158688dfb0e121c25b38 Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Fri, 17 Mar 2023 19:51:53 +0530 Subject: wifi: cfg80211/nl80211: Add support to indicate STA MLD setup links removal STA MLD setup links may get removed if AP MLD remove the corresponding affiliated APs with Multi-Link reconfiguration as described in P802.11be_D3.0, section 35.3.6.2.2 Removing affiliated APs. Currently, there is no support to notify such operation to cfg80211 and userspace. Add support for the drivers to indicate STA MLD setup links removal to cfg80211 and notify the same to userspace. Upon receiving such indication from the driver, clear the MLO links information of the removed links in the WDEV. Signed-off-by: Veerendranath Jakkam Link: https://lore.kernel.org/r/20230317142153.237900-1-quic_vjakkam@quicinc.com [rename function and attribute, fix kernel-doc] Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 13 ++++++++ include/uapi/linux/nl80211.h | 7 +++++ net/wireless/core.h | 1 + net/wireless/nl80211.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ net/wireless/sme.c | 15 ++++++++++ net/wireless/trace.h | 15 ++++++++++ 6 files changed, 121 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9972de114d73..3a736f9286b0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -9205,4 +9205,17 @@ static inline int cfg80211_color_change_notify(struct net_device *dev) bool cfg80211_valid_disable_subchannel_bitmap(u16 *bitmap, const struct cfg80211_chan_def *chandef); +/** + * cfg80211_links_removed - Notify about removed STA MLD setup links. + * @dev: network device. + * @link_mask: BIT mask of removed STA MLD setup link IDs. + * + * Inform cfg80211 and the userspace about removed STA MLD setup links due to + * AP MLD removing the corresponding affiliated APs with Multi-Link + * reconfiguration. Note that it's not valid to remove all links, in this + * case disconnect instead. + * Also note that the wdev mutex must be held. + */ +void cfg80211_links_removed(struct net_device *dev, u16 link_mask); + #endif /* __NET_CFG80211_H */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 03939bdb0e48..3190d34269ef 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1309,6 +1309,11 @@ * The number of peers that HW timestamping can be enabled for concurrently * is indicated by %NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS. * + * @NL80211_CMD_LINKS_REMOVED: Notify userspace about the removal of STA MLD + * setup links due to AP MLD removing the corresponding affiliated APs with + * Multi-Link reconfiguration. %NL80211_ATTR_MLO_LINKS is used to provide + * information about the removed STA MLD setup links. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1562,6 +1567,8 @@ enum nl80211_commands { NL80211_CMD_SET_HW_TIMESTAMP, + NL80211_CMD_LINKS_REMOVED, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/net/wireless/core.h b/net/wireless/core.h index 291c6d83d56f..8a807b609ef7 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -576,5 +576,6 @@ void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id); void cfg80211_remove_links(struct wireless_dev *wdev); int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); +void cfg80211_wdev_release_link_bsses(struct wireless_dev *wdev, u16 link_mask); #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7b547aeb52f1..0da2e6a2a7ea 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -18288,6 +18288,76 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, nlmsg_free(msg); } +void cfg80211_links_removed(struct net_device *dev, u16 link_mask) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + struct sk_buff *msg; + struct nlattr *links; + void *hdr; + + ASSERT_WDEV_LOCK(wdev); + trace_cfg80211_links_removed(dev, link_mask); + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) + return; + + if (WARN_ON(!wdev->valid_links || !link_mask || + (wdev->valid_links & link_mask) != link_mask || + wdev->valid_links == link_mask)) + return; + + cfg80211_wdev_release_link_bsses(wdev, link_mask); + wdev->valid_links &= ~link_mask; + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_LINKS_REMOVED); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) + goto nla_put_failure; + + links = nla_nest_start(msg, NL80211_ATTR_MLO_LINKS); + if (!links) + goto nla_put_failure; + + while (link_mask) { + struct nlattr *link; + int link_id = __ffs(link_mask); + + link = nla_nest_start(msg, link_id + 1); + if (!link) + goto nla_put_failure; + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) + goto nla_put_failure; + + nla_nest_end(msg, link); + link_mask &= ~(1 << link_id); + } + + nla_nest_end(msg, links); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, GFP_KERNEL); + return; + + nla_put_failure: + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_links_removed); + void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, gfp_t gfp) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 247369004aaa..9bba233b5a6e 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -491,6 +491,21 @@ static void cfg80211_wdev_release_bsses(struct wireless_dev *wdev) } } +void cfg80211_wdev_release_link_bsses(struct wireless_dev *wdev, u16 link_mask) +{ + unsigned int link; + + for_each_valid_link(wdev, link) { + if (!wdev->links[link].client.current_bss || + !(link_mask & BIT(link))) + continue; + cfg80211_unhold_bss(wdev->links[link].client.current_bss); + cfg80211_put_bss(wdev->wiphy, + &wdev->links[link].client.current_bss->pub); + wdev->links[link].client.current_bss = NULL; + } +} + static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev, const u8 *ies, size_t ies_len, const u8 **out_ies, size_t *out_ies_len) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index e63990b81249..617c0d0dfa96 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -3966,6 +3966,21 @@ TRACE_EVENT(rdev_set_hw_timestamp, __entry->enable) ); +TRACE_EVENT(cfg80211_links_removed, + TP_PROTO(struct net_device *netdev, u16 link_mask), + TP_ARGS(netdev, link_mask), + TP_STRUCT__entry( + NETDEV_ENTRY + __field(u16, link_mask) + ), + TP_fast_assign( + NETDEV_ASSIGN; + __entry->link_mask = link_mask; + ), + TP_printk(NETDEV_PR_FMT ", link_mask:%u", NETDEV_PR_ARG, + __entry->link_mask) +); + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH -- cgit v1.2.3 From ff32b4506f3ef2228aab601f6d4b37840d05ffaf Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 6 Jun 2023 17:43:26 +0200 Subject: wifi: mac80211: add ___ieee80211_disconnect variant not locking sdata There are cases where keeping sdata locked for an operation. Add a variant that does not take sdata lock to permit these usecases. Signed-off-by: Benjamin Berg Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 30588703ffd3..5c881d14b1a2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3353,18 +3353,15 @@ static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, drv_event_callback(sdata->local, sdata, &event); } -static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) +static void ___ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN]; bool tx; - sdata_lock(sdata); - if (!ifmgd->associated) { - sdata_unlock(sdata); + if (!ifmgd->associated) return; - } /* in MLO assume we have a link where we can TX the frame */ tx = ieee80211_vif_is_mld(&sdata->vif) || @@ -3413,7 +3410,12 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, ifmgd->reconnect); ifmgd->reconnect = false; +} +static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) +{ + sdata_lock(sdata); + ___ieee80211_disconnect(sdata); sdata_unlock(sdata); } -- cgit v1.2.3 From 79973d5cfdc15134d08036796a372d7ec8a1d51e Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Thu, 11 May 2023 13:13:21 +0200 Subject: wifi: mac80211: add set_active_links variant not locking sdata There are cases where keeping sdata locked for an operation. Add a variant that does not take sdata lock to permit these usecases. Signed-off-by: Benjamin Berg Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/link.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index be3294719cb4..49461350f909 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2034,6 +2034,7 @@ void ieee80211_link_stop(struct ieee80211_link_data *link); int ieee80211_vif_set_links(struct ieee80211_sub_if_data *sdata, u16 new_links, u16 dormant_links); void ieee80211_vif_clear_links(struct ieee80211_sub_if_data *sdata); +int __ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links); /* tx handling */ void ieee80211_clear_tx_pending(struct ieee80211_local *local); diff --git a/net/mac80211/link.c b/net/mac80211/link.c index d090ecc41ea2..6148208b320e 100644 --- a/net/mac80211/link.c +++ b/net/mac80211/link.c @@ -447,14 +447,14 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata, return 0; } -int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links) +int __ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_local *local = sdata->local; u16 old_active; int ret; - sdata_lock(sdata); + sdata_assert_lock(sdata); mutex_lock(&local->sta_mtx); mutex_lock(&local->mtx); mutex_lock(&local->key_mtx); @@ -476,6 +476,17 @@ int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links) mutex_unlock(&local->key_mtx); mutex_unlock(&local->mtx); mutex_unlock(&local->sta_mtx); + + return ret; +} + +int ieee80211_set_active_links(struct ieee80211_vif *vif, u16 active_links) +{ + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + int ret; + + sdata_lock(sdata); + ret = __ieee80211_set_active_links(vif, active_links); sdata_unlock(sdata); return ret; -- cgit v1.2.3 From 8eb8dd2ffbbb6b0b8843b66754ee9f129f1b2d6c Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Sun, 18 Jun 2023 21:49:55 +0300 Subject: wifi: mac80211: Support link removal using Reconfiguration ML element Add support for handling link removal indicated by the Reconfiguration Multi-Link element. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.d8a046dc0c1a.I4dcf794da2a2d9f4e5f63a4b32158075d27c0660@changeid [use cfg80211_links_removed() API instead] Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 33 +++++++++ net/mac80211/ieee80211_i.h | 3 + net/mac80211/mlme.c | 169 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index e145af7448a3..98223b665456 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4891,6 +4891,39 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, fixed + prof->sta_info_len <= len; } +#define IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID 0x000f +#define IEEE80211_MLE_STA_RECONF_CONTROL_COMPLETE_PROFILE 0x0010 +#define IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT 0x0020 +#define IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT 0x0040 + +/** + * ieee80211_mle_reconf_sta_prof_size_ok - validate reconfiguration multi-link + * element sta profile size. + * @data: pointer to the sub element data + * @len: length of the containing sub element + */ +static inline bool ieee80211_mle_reconf_sta_prof_size_ok(const u8 *data, + size_t len) +{ + const struct ieee80211_mle_per_sta_profile *prof = (const void *)data; + u16 control; + u8 fixed = sizeof(*prof); + u8 info_len = 1; + + if (len < fixed) + return false; + + control = le16_to_cpu(prof->control); + + if (control & IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT) + info_len += ETH_ALEN; + if (control & IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT) + info_len += 2; + + return prof->sta_info_len >= info_len && + fixed + prof->sta_info_len - 1 <= len; +} + #define for_each_mle_subelement(_elem, _data, _len) \ if (ieee80211_mle_size_ok(_data, _len)) \ for_each_element(_elem, \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 49461350f909..2f7665998da0 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -551,6 +551,9 @@ struct ieee80211_if_managed { */ u8 *assoc_req_ies; size_t assoc_req_ies_len; + + struct wiphy_delayed_work ml_reconf_work; + u16 removed_links; }; struct ieee80211_if_ibss { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5c881d14b1a2..b60f99cf1be0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5608,6 +5608,169 @@ static bool ieee80211_config_puncturing(struct ieee80211_link_data *link, return true; } +static void ieee80211_ml_reconf_work(struct wiphy *wiphy, + struct wiphy_work *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, + u.mgd.ml_reconf_work.work); + u16 new_valid_links, new_active_links, new_dormant_links; + int ret; + + sdata_lock(sdata); + if (!sdata->u.mgd.removed_links) { + sdata_unlock(sdata); + return; + } + + sdata_info(sdata, + "MLO Reconfiguration: work: valid=0x%x, removed=0x%x\n", + sdata->vif.valid_links, sdata->u.mgd.removed_links); + + new_valid_links = sdata->vif.valid_links & ~sdata->u.mgd.removed_links; + if (new_valid_links == sdata->vif.valid_links) { + sdata_unlock(sdata); + return; + } + + if (!new_valid_links || + !(new_valid_links & ~sdata->vif.dormant_links)) { + sdata_info(sdata, "No valid links after reconfiguration\n"); + ret = -EINVAL; + goto out; + } + + new_active_links = sdata->vif.active_links & ~sdata->u.mgd.removed_links; + if (new_active_links != sdata->vif.active_links) { + if (!new_active_links) + new_active_links = + BIT(ffs(new_valid_links & + ~sdata->vif.dormant_links) - 1); + + ret = __ieee80211_set_active_links(&sdata->vif, + new_active_links); + if (ret) { + sdata_info(sdata, + "Failed setting active links\n"); + goto out; + } + } + + new_dormant_links = sdata->vif.dormant_links & ~sdata->u.mgd.removed_links; + + ret = ieee80211_vif_set_links(sdata, new_valid_links, + new_dormant_links); + if (ret) + sdata_info(sdata, "Failed setting valid links\n"); + +out: + if (!ret) + cfg80211_links_removed(sdata->dev, sdata->u.mgd.removed_links); + else + ___ieee80211_disconnect(sdata); + + sdata->u.mgd.removed_links = 0; + + sdata_unlock(sdata); +} + +static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata, + struct ieee802_11_elems *elems) +{ + const struct ieee80211_multi_link_elem *ml; + const struct element *sub; + size_t ml_len; + unsigned long removed_links = 0; + u16 link_removal_timeout[IEEE80211_MLD_MAX_NUM_LINKS] = {}; + u8 link_id; + u32 delay; + + if (!ieee80211_vif_is_mld(&sdata->vif) || !elems->ml_reconf) + return; + + ml_len = cfg80211_defragment_element(elems->ml_reconf_elem, + elems->ie_start, + elems->total_len, + elems->scratch_pos, + elems->scratch + elems->scratch_len - + elems->scratch_pos, + WLAN_EID_FRAGMENT); + + elems->ml_reconf = (const void *)elems->scratch_pos; + elems->ml_reconf_len = ml_len; + ml = elems->ml_reconf; + + /* Directly parse the sub elements as the common information doesn't + * hold any useful information. + */ + for_each_mle_subelement(sub, (u8 *)ml, ml_len) { + struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data; + u8 *pos = prof->variable; + u16 control; + + if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) + continue; + + if (!ieee80211_mle_reconf_sta_prof_size_ok(sub->data, + sub->datalen)) + return; + + control = le16_to_cpu(prof->control); + link_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID; + + removed_links |= BIT(link_id); + + /* the MAC address should not be included, but handle it */ + if (control & + IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT) + pos += 6; + + /* According to Draft P802.11be_D3.0, the control should + * include the AP Removal Timer present. If the AP Removal Timer + * is not present assume immediate removal. + */ + if (control & + IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT) + link_removal_timeout[link_id] = le16_to_cpu(*(__le16 *)pos); + } + + removed_links &= sdata->vif.valid_links; + if (!removed_links) { + /* In case the removal was cancelled, abort it */ + if (sdata->u.mgd.removed_links) { + sdata->u.mgd.removed_links = 0; + wiphy_delayed_work_cancel(sdata->local->hw.wiphy, + &sdata->u.mgd.ml_reconf_work); + } + return; + } + + delay = 0; + for_each_set_bit(link_id, &removed_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf = + sdata_dereference(sdata->vif.link_conf[link_id], sdata); + u32 link_delay; + + if (!link_conf) { + removed_links &= ~BIT(link_id); + continue; + } + + link_delay = link_conf->beacon_int * + link_removal_timeout[link_id]; + + if (!delay) + delay = link_delay; + else + delay = min(delay, link_delay); + } + + sdata->u.mgd.removed_links = removed_links; + wiphy_delayed_work_queue(sdata->local->hw.wiphy, + &sdata->u.mgd.ml_reconf_work, + TU_TO_JIFFIES(delay)); +} + static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, struct ieee80211_hdr *hdr, size_t len, struct ieee80211_rx_status *rx_status) @@ -5937,6 +6100,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link, } } + ieee80211_ml_reconfiguration(sdata, elems); + ieee80211_link_info_change_notify(sdata, link, changed); free: kfree(elems); @@ -6563,6 +6728,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) ieee80211_csa_connection_drop_work); INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work, ieee80211_tdls_peer_del_work); + wiphy_delayed_work_init(&ifmgd->ml_reconf_work, + ieee80211_ml_reconf_work); timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0); timer_setup(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 0); timer_setup(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, 0); @@ -7575,6 +7742,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata) wiphy_work_cancel(sdata->local->hw.wiphy, &ifmgd->csa_connection_drop_work); cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work); + wiphy_delayed_work_cancel(sdata->local->hw.wiphy, + &ifmgd->ml_reconf_work); sdata_lock(sdata); if (ifmgd->assoc_data) -- cgit v1.2.3 From 888a325fe0a7d149828600c663869636ffdbe81f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Jun 2023 21:49:56 +0300 Subject: wifi: ieee80211: reorder presence checks in MLE per-STA profile In ieee80211_mle_sta_prof_size_ok(), the presence checks aren't ordered by field order, so that's a bit confusing. Reorder them. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.fdbf17320a37.I517cf27fdc3f6e5d6a2615182da47ba4bdf14039@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 98223b665456..fc3c26f1b718 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4876,9 +4876,6 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, info_len += 8; if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT) info_len += 2; - if (control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT) - info_len += 1; - if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE && control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) { if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) @@ -4886,6 +4883,8 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, else info_len += 1; } + if (control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT) + info_len += 1; return prof->sta_info_len >= info_len && fixed + prof->sta_info_len <= len; -- cgit v1.2.3 From 6f2db6588b8189caeeb8249727b8344eba991250 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Jun 2023 21:49:57 +0300 Subject: wifi: mac80211: agg-tx: add a few locking assertions This is all true today, but difficult to understand since the callers are in other files etc. Add two new lockdep assertions to make things easier to read. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.7f03dec6a90b.I762c11e95da005b80fa0184cb1173b99ec362acf@changeid Signed-off-by: Johannes Berg --- net/mac80211/agg-tx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 3b651e7f5a73..118ad2e24dbb 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -9,7 +9,7 @@ * Copyright 2007, Michael Wu * Copyright 2007-2010, Intel Corporation * Copyright(c) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2022 Intel Corporation + * Copyright (C) 2018 - 2023 Intel Corporation */ #include @@ -457,6 +457,8 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta, u8 tid = tid_tx->tid; u16 buf_size; + lockdep_assert_held(&sta->ampdu_mlme.mtx); + /* activate the timer for the recipient's addBA response */ mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n", @@ -795,6 +797,8 @@ void ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid, struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_local *local = sdata->local; + lockdep_assert_held(&sta->ampdu_mlme.mtx); + if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))) return; -- cgit v1.2.3 From 92bf4dd35801b4e3e73d3cc4beb5c929f75e0da6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Jun 2023 21:49:58 +0300 Subject: wifi: mac80211: agg-tx: prevent start/stop race There were crashes reported in this code, and the timer_shutdown() warning in one of the previous patches indicates that the timeout timer for the AP response (addba_resp_timer) is still armed while we're stopping the aggregation session. After a very long deliberation of the code, so far the only way I could find that might cause this would be the following sequence: - session start requested - session start indicated to driver, but driver returns IEEE80211_AMPDU_TX_START_DELAY_ADDBA - session stop requested, sets HT_AGG_STATE_WANT_STOP - session stop worker runs ___ieee80211_stop_tx_ba_session(), sets HT_AGG_STATE_STOPPING From here on, the order doesn't matter exactly, but: 1. driver calls ieee80211_start_tx_ba_cb_irqsafe(), setting HT_AGG_STATE_START_CB 2. driver calls ieee80211_stop_tx_ba_cb_irqsafe(), setting HT_AGG_STATE_STOP_CB 3. the worker will run ieee80211_start_tx_ba_cb() for HT_AGG_STATE_START_CB 4. the worker will run ieee80211_stop_tx_ba_cb() for HT_AGG_STATE_STOP_CB (the order could also be 1./3./2./4.) This will cause ieee80211_start_tx_ba_cb() to send out the AddBA request frame to the AP and arm the timer, but we're already in the middle of stopping and so the ieee80211_stop_tx_ba_cb() will no longer assume it needs to stop anything. Prevent this by checking for WANT_STOP/STOPPING in the start CB, and warn if we're sending a frame on a stopping session. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.e5b52777462a.I0b2ed6658e81804279f5d7c9c1918cb1f6626bf2@changeid Signed-off-by: Johannes Berg --- net/mac80211/agg-tx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 118ad2e24dbb..b6b772685881 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -457,6 +457,10 @@ static void ieee80211_send_addba_with_timeout(struct sta_info *sta, u8 tid = tid_tx->tid; u16 buf_size; + if (WARN_ON_ONCE(test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state) || + test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state))) + return; + lockdep_assert_held(&sta->ampdu_mlme.mtx); /* activate the timer for the recipient's addBA response */ @@ -802,6 +806,10 @@ void ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid, if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))) return; + if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state) || + test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state)) + return; + if (!test_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)) { ieee80211_send_addba_with_timeout(sta, tid_tx); /* RESPONSE_RECEIVED state whould trigger the flow again */ -- cgit v1.2.3 From c870d66f1b7f51fa3401771ff6c41fd78adb869e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Jun 2023 21:49:59 +0300 Subject: wifi: update multi-link element STA reconfig Update the MLE STA reconfig sub-type to 802.11be D3.0 format, which includes the operation update field. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.2e1383b31f07.I8055a111c8fcf22e833e60f5587a4d8d21caca5b@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 8 ++++++-- net/mac80211/mlme.c | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index fc3c26f1b718..d2025c986b0f 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4893,7 +4893,9 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, #define IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID 0x000f #define IEEE80211_MLE_STA_RECONF_CONTROL_COMPLETE_PROFILE 0x0010 #define IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT 0x0020 -#define IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT 0x0040 +#define IEEE80211_MLE_STA_RECONF_CONTROL_AP_REM_TIMER_PRESENT 0x0040 +#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_UPDATE_TYPE 0x0780 +#define IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_PARAMS_PRESENT 0x0800 /** * ieee80211_mle_reconf_sta_prof_size_ok - validate reconfiguration multi-link @@ -4916,7 +4918,9 @@ static inline bool ieee80211_mle_reconf_sta_prof_size_ok(const u8 *data, if (control & IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT) info_len += ETH_ALEN; - if (control & IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT) + if (control & IEEE80211_MLE_STA_RECONF_CONTROL_AP_REM_TIMER_PRESENT) + info_len += 2; + if (control & IEEE80211_MLE_STA_RECONF_CONTROL_OPERATION_PARAMS_PRESENT) info_len += 2; return prof->sta_info_len >= info_len && diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b60f99cf1be0..15e3decc59db 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5730,7 +5730,7 @@ static void ieee80211_ml_reconfiguration(struct ieee80211_sub_if_data *sdata, * is not present assume immediate removal. */ if (control & - IEEE80211_MLE_STA_RECONF_CONTROL_DELETE_TIMER_PRESENT) + IEEE80211_MLE_STA_RECONF_CONTROL_AP_REM_TIMER_PRESENT) link_removal_timeout[link_id] = le16_to_cpu(*(__le16 *)pos); } -- cgit v1.2.3 From 8dcc91c446687727f88997a2e177cdab740ef092 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:50:00 +0300 Subject: wifi: cfg80211: stop parsing after allocation failure The error handling code would break out of the loop incorrectly, causing the rest of the message to be misinterpreted. Fix this by also jumping out of the surrounding while loop, which will trigger the error detection code. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.0ffac98475cf.I6f5c08a09f5c9fced01497b95a9841ffd1b039f8@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index df868662e1e0..91671698aaec 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -707,7 +707,7 @@ static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, GFP_ATOMIC); if (!entry) - break; + goto error; entry->center_freq = freq; @@ -723,6 +723,7 @@ static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, } } +error: if (pos != end) { cfg80211_free_coloc_ap_list(&ap_list); return 0; -- cgit v1.2.3 From 5461707a529c94f6f556847c25c21da5990488ba Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jun 2023 21:50:01 +0300 Subject: wifi: cfg80211: search all RNR elements for colocated APs An AP reporting colocated APs may send more than one reduced neighbor report element. As such, iterate all elements instead of only parsing the first one when looking for colocated APs. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.ffe2c014f478.I372a4f96c88f7ea28ac39e94e0abfc465b5330d4@changeid Signed-off-by: Johannes Berg --- net/wireless/scan.c | 127 ++++++++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 64 deletions(-) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 91671698aaec..ede95caecb34 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -643,90 +643,89 @@ static int cfg80211_parse_colocated_ap(const struct cfg80211_bss_ies *ies, int n_coloc = 0, ret; LIST_HEAD(ap_list); - elem = cfg80211_find_elem(WLAN_EID_REDUCED_NEIGHBOR_REPORT, ies->data, - ies->len); - if (!elem) - return 0; - - pos = elem->data; - end = pos + elem->datalen; - ret = cfg80211_calc_short_ssid(ies, &ssid_elem, &s_ssid_tmp); if (ret) return ret; - /* RNR IE may contain more than one NEIGHBOR_AP_INFO */ - while (pos + sizeof(*ap_info) <= end) { - enum nl80211_band band; - int freq; - u8 length, i, count; + for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT, + ies->data, ies->len) { + pos = elem->data; + end = elem->data + elem->datalen; - ap_info = (void *)pos; - count = u8_get_bits(ap_info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1; - length = ap_info->tbtt_info_len; + /* RNR IE may contain more than one NEIGHBOR_AP_INFO */ + while (pos + sizeof(*ap_info) <= end) { + enum nl80211_band band; + int freq; + u8 length, i, count; - pos += sizeof(*ap_info); + ap_info = (void *)pos; + count = u8_get_bits(ap_info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_COUNT) + 1; + length = ap_info->tbtt_info_len; - if (!ieee80211_operating_class_to_band(ap_info->op_class, - &band)) - break; + pos += sizeof(*ap_info); - freq = ieee80211_channel_to_frequency(ap_info->channel, band); + if (!ieee80211_operating_class_to_band(ap_info->op_class, + &band)) + break; - if (end - pos < count * length) - break; + freq = ieee80211_channel_to_frequency(ap_info->channel, + band); - if (u8_get_bits(ap_info->tbtt_info_hdr, - IEEE80211_AP_INFO_TBTT_HDR_TYPE) != - IEEE80211_TBTT_INFO_TYPE_TBTT) { - pos += count * length; - continue; - } + if (end - pos < count * length) + break; - /* - * TBTT info must include bss param + BSSID + - * (short SSID or same_ssid bit to be set). - * ignore other options, and move to the - * next AP info - */ - if (band != NL80211_BAND_6GHZ || - !(length == offsetofend(struct ieee80211_tbtt_info_7_8_9, - bss_params) || - length == sizeof(struct ieee80211_tbtt_info_7_8_9) || - length >= offsetofend(struct ieee80211_tbtt_info_ge_11, - bss_params))) { - pos += count * length; - continue; - } + if (u8_get_bits(ap_info->tbtt_info_hdr, + IEEE80211_AP_INFO_TBTT_HDR_TYPE) != + IEEE80211_TBTT_INFO_TYPE_TBTT) { + pos += count * length; + continue; + } - for (i = 0; i < count; i++) { - struct cfg80211_colocated_ap *entry; + /* TBTT info must include bss param + BSSID + + * (short SSID or same_ssid bit to be set). + * ignore other options, and move to the + * next AP info + */ + if (band != NL80211_BAND_6GHZ || + !(length == offsetofend(struct ieee80211_tbtt_info_7_8_9, + bss_params) || + length == sizeof(struct ieee80211_tbtt_info_7_8_9) || + length >= offsetofend(struct ieee80211_tbtt_info_ge_11, + bss_params))) { + pos += count * length; + continue; + } - entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN, - GFP_ATOMIC); + for (i = 0; i < count; i++) { + struct cfg80211_colocated_ap *entry; - if (!entry) - goto error; + entry = kzalloc(sizeof(*entry) + IEEE80211_MAX_SSID_LEN, + GFP_ATOMIC); - entry->center_freq = freq; + if (!entry) + goto error; - if (!cfg80211_parse_ap_info(entry, pos, length, - ssid_elem, s_ssid_tmp)) { - n_coloc++; - list_add_tail(&entry->list, &ap_list); - } else { - kfree(entry); - } + entry->center_freq = freq; + + if (!cfg80211_parse_ap_info(entry, pos, length, + ssid_elem, + s_ssid_tmp)) { + n_coloc++; + list_add_tail(&entry->list, &ap_list); + } else { + kfree(entry); + } - pos += length; + pos += length; + } } - } error: - if (pos != end) { - cfg80211_free_coloc_ap_list(&ap_list); - return 0; + if (pos != end) { + cfg80211_free_coloc_ap_list(&ap_list); + return 0; + } } list_splice_tail(&ap_list, list); -- cgit v1.2.3 From cf0b045ebf6bba7764151e1759c874c43964445a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 18 Jun 2023 21:50:02 +0300 Subject: wifi: mac80211: check EHT basic MCS/NSS set Check that all the NSS in the EHT basic MCS/NSS set are actually supported, otherwise disable EHT for the connection. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230618214436.737827c906c9.I0c11a3cd46ab4dcb774c11a5bbc30aecfb6fce11@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 28 ++++++++++----- net/mac80211/mlme.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 9 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index d2025c986b0f..fa679613c562 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1996,12 +1996,18 @@ struct ieee80211_mu_edca_param_set { * @rx_tx_mcs13_max_nss: indicates the maximum number of spatial streams * supported for reception and the maximum number of spatial streams * supported for transmission for MCS 12 - 13. + * @rx_tx_max_nss: array of the previous fields for easier loop access */ struct ieee80211_eht_mcs_nss_supp_20mhz_only { - u8 rx_tx_mcs7_max_nss; - u8 rx_tx_mcs9_max_nss; - u8 rx_tx_mcs11_max_nss; - u8 rx_tx_mcs13_max_nss; + union { + struct { + u8 rx_tx_mcs7_max_nss; + u8 rx_tx_mcs9_max_nss; + u8 rx_tx_mcs11_max_nss; + u8 rx_tx_mcs13_max_nss; + }; + u8 rx_tx_max_nss[4]; + }; }; /** @@ -2021,11 +2027,17 @@ struct ieee80211_eht_mcs_nss_supp_20mhz_only { * @rx_tx_mcs13_max_nss: indicates the maximum number of spatial streams * supported for reception and the maximum number of spatial streams * supported for transmission for MCS 12 - 13. + * @rx_tx_max_nss: array of the previous fields for easier loop access */ struct ieee80211_eht_mcs_nss_supp_bw { - u8 rx_tx_mcs9_max_nss; - u8 rx_tx_mcs11_max_nss; - u8 rx_tx_mcs13_max_nss; + union { + struct { + u8 rx_tx_mcs9_max_nss; + u8 rx_tx_mcs11_max_nss; + u8 rx_tx_mcs13_max_nss; + }; + u8 rx_tx_max_nss[3]; + }; }; /** @@ -2078,7 +2090,7 @@ struct ieee80211_eht_cap_elem { */ struct ieee80211_eht_operation { u8 params; - __le32 basic_mcs_nss; + struct ieee80211_eht_mcs_nss_supp_20mhz_only basic_mcs_nss; u8 optional[]; } __packed; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 15e3decc59db..cf15089e95f1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4694,6 +4694,89 @@ ieee80211_verify_sta_he_mcs_support(struct ieee80211_sub_if_data *sdata, return false; } +static u8 +ieee80211_get_eht_cap_mcs_nss(const struct ieee80211_sta_he_cap *sta_he_cap, + const struct ieee80211_sta_eht_cap *sta_eht_cap, + unsigned int idx, int bw) +{ + u8 he_phy_cap0 = sta_he_cap->he_cap_elem.phy_cap_info[0]; + u8 eht_phy_cap0 = sta_eht_cap->eht_cap_elem.phy_cap_info[0]; + + /* handle us being a 20 MHz-only EHT STA - with four values + * for MCS 0-7, 8-9, 10-11, 12-13. + */ + if (!(he_phy_cap0 & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) + return sta_eht_cap->eht_mcs_nss_supp.only_20mhz.rx_tx_max_nss[idx]; + + /* the others have MCS 0-9 together, rather than separately from 0-7 */ + if (idx > 0) + idx--; + + switch (bw) { + case 0: + return sta_eht_cap->eht_mcs_nss_supp.bw._80.rx_tx_max_nss[idx]; + case 1: + if (!(he_phy_cap0 & + (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G))) + return 0xff; /* pass check */ + return sta_eht_cap->eht_mcs_nss_supp.bw._160.rx_tx_max_nss[idx]; + case 2: + if (!(eht_phy_cap0 & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ)) + return 0xff; /* pass check */ + return sta_eht_cap->eht_mcs_nss_supp.bw._320.rx_tx_max_nss[idx]; + } + + WARN_ON(1); + return 0; +} + +static bool +ieee80211_verify_sta_eht_mcs_support(struct ieee80211_sub_if_data *sdata, + struct ieee80211_supported_band *sband, + const struct ieee80211_eht_operation *eht_op) +{ + const struct ieee80211_sta_he_cap *sta_he_cap = + ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif); + const struct ieee80211_sta_eht_cap *sta_eht_cap = + ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif); + const struct ieee80211_eht_mcs_nss_supp_20mhz_only *req; + unsigned int i; + + if (!sta_he_cap || !sta_eht_cap || !eht_op) + return false; + + req = &eht_op->basic_mcs_nss; + + for (i = 0; i < ARRAY_SIZE(req->rx_tx_max_nss); i++) { + u8 req_rx_nss, req_tx_nss; + unsigned int bw; + + req_rx_nss = u8_get_bits(req->rx_tx_max_nss[i], + IEEE80211_EHT_MCS_NSS_RX); + req_tx_nss = u8_get_bits(req->rx_tx_max_nss[i], + IEEE80211_EHT_MCS_NSS_TX); + + for (bw = 0; bw < 3; bw++) { + u8 have, have_rx_nss, have_tx_nss; + + have = ieee80211_get_eht_cap_mcs_nss(sta_he_cap, + sta_eht_cap, + i, bw); + have_rx_nss = u8_get_bits(have, + IEEE80211_EHT_MCS_NSS_RX); + have_tx_nss = u8_get_bits(have, + IEEE80211_EHT_MCS_NSS_TX); + + if (req_rx_nss > have_rx_nss || + req_tx_nss > have_tx_nss) + return false; + } + } + + return true; +} + static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, struct ieee80211_link_data *link, struct cfg80211_bss *cbss, @@ -4849,11 +4932,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, else eht_oper = NULL; + if (!ieee80211_verify_sta_eht_mcs_support(sdata, sband, eht_oper)) + *conn_flags |= IEEE80211_CONN_DISABLE_EHT; + eht_ml_elem = cfg80211_find_ext_elem(WLAN_EID_EXT_EHT_MULTI_LINK, cbss_ies->data, cbss_ies->len); /* data + 1 / datalen - 1 since it's an extended element */ - if (eht_ml_elem && + if (!(*conn_flags & IEEE80211_CONN_DISABLE_EHT) && + eht_ml_elem && ieee80211_mle_type_ok(eht_ml_elem->data + 1, IEEE80211_ML_CONTROL_TYPE_BASIC, eht_ml_elem->datalen - 1)) { -- cgit v1.2.3 From 1d28635abcf1914425d6516e641978011984c58a Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 13 Jun 2023 15:35:30 -0700 Subject: bpf: Move unprivileged checks into map_create() and bpf_prog_load() Make each bpf() syscall command a bit more self-contained, making it easier to further enhance it. We move sysctl_unprivileged_bpf_disabled handling down to map_create() and bpf_prog_load(), two special commands in this regard. Also swap the order of checks, calling bpf_capable() only if sysctl_unprivileged_bpf_disabled is true, avoiding unnecessary audit messages. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230613223533.3689589-2-andrii@kernel.org --- kernel/bpf/syscall.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 12955415d376..7c41a623f405 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1157,6 +1157,15 @@ static int map_create(union bpf_attr *attr) !node_online(numa_node))) return -EINVAL; + /* Intent here is for unprivileged_bpf_disabled to block BPF map + * creation for unprivileged users; other actions depend + * on fd availability and access to bpffs, so are dependent on + * object creation success. Even with unprivileged BPF disabled, + * capability checks are still carried out. + */ + if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) + return -EPERM; + /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ map = find_and_alloc_map(attr); if (IS_ERR(map)) @@ -2532,6 +2541,16 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) /* eBPF programs must be GPL compatible to use GPL-ed functions */ is_gpl = license_is_gpl_compatible(license); + /* Intent here is for unprivileged_bpf_disabled to block BPF program + * creation for unprivileged users; other actions depend + * on fd availability and access to bpffs, so are dependent on + * object creation success. Even with unprivileged BPF disabled, + * capability checks are still carried out for these + * and other operations. + */ + if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) + return -EPERM; + if (attr->insn_cnt == 0 || attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) return -E2BIG; @@ -5030,23 +5049,8 @@ out_prog_put: static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) { union bpf_attr attr; - bool capable; int err; - capable = bpf_capable() || !sysctl_unprivileged_bpf_disabled; - - /* Intent here is for unprivileged_bpf_disabled to block key object - * creation commands for unprivileged users; other actions depend - * of fd availability and access to bpffs, so are dependent on - * object creation success. Capabilities are later verified for - * operations such as load and map create, so even with unprivileged - * BPF disabled, capability checks are still carried out for these - * and other operations. - */ - if (!capable && - (cmd == BPF_MAP_CREATE || cmd == BPF_PROG_LOAD)) - return -EPERM; - err = bpf_check_uarg_tail_zero(uattr, sizeof(attr), size); if (err) return err; -- cgit v1.2.3 From 22db41226b679768df8f0a4ff5de8e58f625f45b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 13 Jun 2023 15:35:31 -0700 Subject: bpf: Inline map creation logic in map_create() function Currently find_and_alloc_map() performs two separate functions: some argument sanity checking and partial map creation workflow hanling. Neither of those functions are self-sufficient and are augmented by further checks and initialization logic in the caller (map_create() function). So unify all the sanity checks, permission checks, and creation and initialization logic in one linear piece of code in map_create() instead. This also make it easier to further enhance permission checks and keep them located in one place. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230613223533.3689589-3-andrii@kernel.org --- kernel/bpf/syscall.c | 57 ++++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 7c41a623f405..6ef302709ab0 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -109,37 +109,6 @@ const struct bpf_map_ops bpf_map_offload_ops = { .map_mem_usage = bpf_map_offload_map_mem_usage, }; -static struct bpf_map *find_and_alloc_map(union bpf_attr *attr) -{ - const struct bpf_map_ops *ops; - u32 type = attr->map_type; - struct bpf_map *map; - int err; - - if (type >= ARRAY_SIZE(bpf_map_types)) - return ERR_PTR(-EINVAL); - type = array_index_nospec(type, ARRAY_SIZE(bpf_map_types)); - ops = bpf_map_types[type]; - if (!ops) - return ERR_PTR(-EINVAL); - - if (ops->map_alloc_check) { - err = ops->map_alloc_check(attr); - if (err) - return ERR_PTR(err); - } - if (attr->map_ifindex) - ops = &bpf_map_offload_ops; - if (!ops->map_mem_usage) - return ERR_PTR(-EINVAL); - map = ops->map_alloc(attr); - if (IS_ERR(map)) - return map; - map->ops = ops; - map->map_type = type; - return map; -} - static void bpf_map_write_active_inc(struct bpf_map *map) { atomic64_inc(&map->writecnt); @@ -1127,7 +1096,9 @@ free_map_tab: /* called via syscall */ static int map_create(union bpf_attr *attr) { + const struct bpf_map_ops *ops; int numa_node = bpf_map_attr_numa_node(attr); + u32 map_type = attr->map_type; struct bpf_map *map; int f_flags; int err; @@ -1157,6 +1128,25 @@ static int map_create(union bpf_attr *attr) !node_online(numa_node))) return -EINVAL; + /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ + map_type = attr->map_type; + if (map_type >= ARRAY_SIZE(bpf_map_types)) + return -EINVAL; + map_type = array_index_nospec(map_type, ARRAY_SIZE(bpf_map_types)); + ops = bpf_map_types[map_type]; + if (!ops) + return -EINVAL; + + if (ops->map_alloc_check) { + err = ops->map_alloc_check(attr); + if (err) + return err; + } + if (attr->map_ifindex) + ops = &bpf_map_offload_ops; + if (!ops->map_mem_usage) + return -EINVAL; + /* Intent here is for unprivileged_bpf_disabled to block BPF map * creation for unprivileged users; other actions depend * on fd availability and access to bpffs, so are dependent on @@ -1166,10 +1156,11 @@ static int map_create(union bpf_attr *attr) if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) return -EPERM; - /* find map type and init map: hashtable vs rbtree vs bloom vs ... */ - map = find_and_alloc_map(attr); + map = ops->map_alloc(attr); if (IS_ERR(map)) return PTR_ERR(map); + map->ops = ops; + map->map_type = map_type; err = bpf_obj_name_cpy(map->name, attr->map_name, sizeof(attr->map_name)); -- cgit v1.2.3 From 6c3eba1c5e283fd2bb1c076dbfcb47f569c3bfde Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 13 Jun 2023 15:35:32 -0700 Subject: bpf: Centralize permissions checks for all BPF map types This allows to do more centralized decisions later on, and generally makes it very explicit which maps are privileged and which are not (e.g., LRU_HASH and LRU_PERCPU_HASH, which are privileged HASH variants, as opposed to unprivileged HASH and HASH_PERCPU; now this is explicit and easy to verify). Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230613223533.3689589-4-andrii@kernel.org --- kernel/bpf/bloom_filter.c | 3 -- kernel/bpf/bpf_local_storage.c | 3 -- kernel/bpf/bpf_struct_ops.c | 3 -- kernel/bpf/cpumap.c | 4 -- kernel/bpf/devmap.c | 3 -- kernel/bpf/hashtab.c | 6 --- kernel/bpf/lpm_trie.c | 3 -- kernel/bpf/queue_stack_maps.c | 4 -- kernel/bpf/reuseport_array.c | 3 -- kernel/bpf/stackmap.c | 3 -- kernel/bpf/syscall.c | 47 ++++++++++++++++++++++ net/core/sock_map.c | 4 -- net/xdp/xskmap.c | 4 -- .../selftests/bpf/prog_tests/unpriv_bpf_disabled.c | 6 ++- 14 files changed, 52 insertions(+), 44 deletions(-) diff --git a/kernel/bpf/bloom_filter.c b/kernel/bpf/bloom_filter.c index 540331b610a9..addf3dd57b59 100644 --- a/kernel/bpf/bloom_filter.c +++ b/kernel/bpf/bloom_filter.c @@ -86,9 +86,6 @@ static struct bpf_map *bloom_map_alloc(union bpf_attr *attr) int numa_node = bpf_map_attr_numa_node(attr); struct bpf_bloom_filter *bloom; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - if (attr->key_size != 0 || attr->value_size == 0 || attr->max_entries == 0 || attr->map_flags & ~BLOOM_CREATE_FLAG_MASK || diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c index 47d9948d768f..b5149cfce7d4 100644 --- a/kernel/bpf/bpf_local_storage.c +++ b/kernel/bpf/bpf_local_storage.c @@ -723,9 +723,6 @@ int bpf_local_storage_map_alloc_check(union bpf_attr *attr) !attr->btf_key_type_id || !attr->btf_value_type_id) return -EINVAL; - if (!bpf_capable()) - return -EPERM; - if (attr->value_size > BPF_LOCAL_STORAGE_MAX_VALUE_SIZE) return -E2BIG; diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c index d3f0a4825fa6..116a0ce378ec 100644 --- a/kernel/bpf/bpf_struct_ops.c +++ b/kernel/bpf/bpf_struct_ops.c @@ -655,9 +655,6 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr) const struct btf_type *t, *vt; struct bpf_map *map; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - st_ops = bpf_struct_ops_find_value(attr->btf_vmlinux_value_type_id); if (!st_ops) return ERR_PTR(-ENOTSUPP); diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c index 8ec18faa74ac..8a33e8747a0e 100644 --- a/kernel/bpf/cpumap.c +++ b/kernel/bpf/cpumap.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -89,9 +88,6 @@ static struct bpf_map *cpu_map_alloc(union bpf_attr *attr) u32 value_size = attr->value_size; struct bpf_cpu_map *cmap; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - /* check sanity of attributes */ if (attr->max_entries == 0 || attr->key_size != 4 || (value_size != offsetofend(struct bpf_cpumap_val, qsize) && diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c index 802692fa3905..49cc0b5671c6 100644 --- a/kernel/bpf/devmap.c +++ b/kernel/bpf/devmap.c @@ -160,9 +160,6 @@ static struct bpf_map *dev_map_alloc(union bpf_attr *attr) struct bpf_dtab *dtab; int err; - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); - dtab = bpf_map_area_alloc(sizeof(*dtab), NUMA_NO_NODE); if (!dtab) return ERR_PTR(-ENOMEM); diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index 9901efee4339..56d3da7d0bc6 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -422,12 +422,6 @@ static int htab_map_alloc_check(union bpf_attr *attr) BUILD_BUG_ON(offsetof(struct htab_elem, fnode.next) != offsetof(struct htab_elem, hash_node.pprev)); - if (lru && !bpf_capable()) - /* LRU implementation is much complicated than other - * maps. Hence, limit to CAP_BPF. - */ - return -EPERM; - if (zero_seed && !capable(CAP_SYS_ADMIN)) /* Guard against local DoS, and discourage production use. */ return -EPERM; diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c index e0d3ddf2037a..17c7e7782a1f 100644 --- a/kernel/bpf/lpm_trie.c +++ b/kernel/bpf/lpm_trie.c @@ -544,9 +544,6 @@ static struct bpf_map *trie_alloc(union bpf_attr *attr) { struct lpm_trie *trie; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - /* check sanity of attributes */ if (attr->max_entries == 0 || !(attr->map_flags & BPF_F_NO_PREALLOC) || diff --git a/kernel/bpf/queue_stack_maps.c b/kernel/bpf/queue_stack_maps.c index 601609164ef3..8d2ddcb7566b 100644 --- a/kernel/bpf/queue_stack_maps.c +++ b/kernel/bpf/queue_stack_maps.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include "percpu_freelist.h" @@ -46,9 +45,6 @@ static bool queue_stack_map_is_full(struct bpf_queue_stack *qs) /* Called from syscall */ static int queue_stack_map_alloc_check(union bpf_attr *attr) { - if (!bpf_capable()) - return -EPERM; - /* check sanity of attributes */ if (attr->max_entries == 0 || attr->key_size != 0 || attr->value_size == 0 || diff --git a/kernel/bpf/reuseport_array.c b/kernel/bpf/reuseport_array.c index cbf2d8d784b8..4b4f9670f1a9 100644 --- a/kernel/bpf/reuseport_array.c +++ b/kernel/bpf/reuseport_array.c @@ -151,9 +151,6 @@ static struct bpf_map *reuseport_array_alloc(union bpf_attr *attr) int numa_node = bpf_map_attr_numa_node(attr); struct reuseport_array *array; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - /* allocate all map elements and zero-initialize them */ array = bpf_map_area_alloc(struct_size(array, ptrs, attr->max_entries), numa_node); if (!array) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index b25fce425b2c..458bb80b14d5 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -74,9 +74,6 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) u64 cost, n_buckets; int err; - if (!bpf_capable()) - return ERR_PTR(-EPERM); - if (attr->map_flags & ~STACK_CREATE_FLAG_MASK) return ERR_PTR(-EINVAL); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 6ef302709ab0..658d1154f221 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1156,6 +1156,53 @@ static int map_create(union bpf_attr *attr) if (sysctl_unprivileged_bpf_disabled && !bpf_capable()) return -EPERM; + /* check privileged map type permissions */ + switch (map_type) { + case BPF_MAP_TYPE_ARRAY: + case BPF_MAP_TYPE_PERCPU_ARRAY: + case BPF_MAP_TYPE_PROG_ARRAY: + case BPF_MAP_TYPE_PERF_EVENT_ARRAY: + case BPF_MAP_TYPE_CGROUP_ARRAY: + case BPF_MAP_TYPE_ARRAY_OF_MAPS: + case BPF_MAP_TYPE_HASH: + case BPF_MAP_TYPE_PERCPU_HASH: + case BPF_MAP_TYPE_HASH_OF_MAPS: + case BPF_MAP_TYPE_RINGBUF: + case BPF_MAP_TYPE_USER_RINGBUF: + case BPF_MAP_TYPE_CGROUP_STORAGE: + case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: + /* unprivileged */ + break; + case BPF_MAP_TYPE_SK_STORAGE: + case BPF_MAP_TYPE_INODE_STORAGE: + case BPF_MAP_TYPE_TASK_STORAGE: + case BPF_MAP_TYPE_CGRP_STORAGE: + case BPF_MAP_TYPE_BLOOM_FILTER: + case BPF_MAP_TYPE_LPM_TRIE: + case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: + case BPF_MAP_TYPE_STACK_TRACE: + case BPF_MAP_TYPE_QUEUE: + case BPF_MAP_TYPE_STACK: + case BPF_MAP_TYPE_LRU_HASH: + case BPF_MAP_TYPE_LRU_PERCPU_HASH: + case BPF_MAP_TYPE_STRUCT_OPS: + case BPF_MAP_TYPE_CPUMAP: + if (!bpf_capable()) + return -EPERM; + break; + case BPF_MAP_TYPE_SOCKMAP: + case BPF_MAP_TYPE_SOCKHASH: + case BPF_MAP_TYPE_DEVMAP: + case BPF_MAP_TYPE_DEVMAP_HASH: + case BPF_MAP_TYPE_XSKMAP: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + break; + default: + WARN(1, "unsupported map type %d", map_type); + return -EPERM; + } + map = ops->map_alloc(attr); if (IS_ERR(map)) return PTR_ERR(map); diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 00afb66cd095..19538d628714 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -32,8 +32,6 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr) { struct bpf_stab *stab; - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); if (attr->max_entries == 0 || attr->key_size != 4 || (attr->value_size != sizeof(u32) && @@ -1085,8 +1083,6 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) struct bpf_shtab *htab; int i, err; - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); if (attr->max_entries == 0 || attr->key_size == 0 || (attr->value_size != sizeof(u32) && diff --git a/net/xdp/xskmap.c b/net/xdp/xskmap.c index 2c1427074a3b..e1c526f97ce3 100644 --- a/net/xdp/xskmap.c +++ b/net/xdp/xskmap.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -68,9 +67,6 @@ static struct bpf_map *xsk_map_alloc(union bpf_attr *attr) int numa_node; u64 size; - if (!capable(CAP_NET_ADMIN)) - return ERR_PTR(-EPERM); - if (attr->max_entries == 0 || attr->key_size != 4 || attr->value_size != 4 || attr->map_flags & ~(BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY)) diff --git a/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c b/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c index 8383a99f610f..0adf8d9475cb 100644 --- a/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c +++ b/tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c @@ -171,7 +171,11 @@ static void test_unpriv_bpf_disabled_negative(struct test_unpriv_bpf_disabled *s prog_insns, prog_insn_cnt, &load_opts), -EPERM, "prog_load_fails"); - for (i = BPF_MAP_TYPE_HASH; i <= BPF_MAP_TYPE_BLOOM_FILTER; i++) + /* some map types require particular correct parameters which could be + * sanity-checked before enforcing -EPERM, so only validate that + * the simple ARRAY and HASH maps are failing with -EPERM + */ + for (i = BPF_MAP_TYPE_HASH; i <= BPF_MAP_TYPE_ARRAY; i++) ASSERT_EQ(bpf_map_create(i, NULL, sizeof(int), sizeof(int), 1, NULL), -EPERM, "map_create_fails"); -- cgit v1.2.3 From 7f6719f7a8662a40afed367a685516f9f34e7bc2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 13 Jun 2023 15:35:33 -0700 Subject: bpf: Keep BPF_PROG_LOAD permission checks clear of validations Move out flags validation and license checks out of the permission checks. They were intermingled, which makes subsequent changes harder. Clean this up: perform straightforward flag validation upfront, and fetch and check license later, right where we use it. Also consolidate capabilities check in one block, right after basic attribute sanity checks. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230613223533.3689589-5-andrii@kernel.org --- kernel/bpf/syscall.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 658d1154f221..a75c54b6f8a3 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2550,7 +2550,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) struct btf *attach_btf = NULL; int err; char license[128]; - bool is_gpl; if (CHECK_ATTR(BPF_PROG_LOAD)) return -EINVAL; @@ -2569,16 +2568,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) !bpf_capable()) return -EPERM; - /* copy eBPF program license from user space */ - if (strncpy_from_bpfptr(license, - make_bpfptr(attr->license, uattr.is_kernel), - sizeof(license) - 1) < 0) - return -EFAULT; - license[sizeof(license) - 1] = 0; - - /* eBPF programs must be GPL compatible to use GPL-ed functions */ - is_gpl = license_is_gpl_compatible(license); - /* Intent here is for unprivileged_bpf_disabled to block BPF program * creation for unprivileged users; other actions depend * on fd availability and access to bpffs, so are dependent on @@ -2671,12 +2660,20 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) make_bpfptr(attr->insns, uattr.is_kernel), bpf_prog_insn_size(prog)) != 0) goto free_prog_sec; + /* copy eBPF program license from user space */ + if (strncpy_from_bpfptr(license, + make_bpfptr(attr->license, uattr.is_kernel), + sizeof(license) - 1) < 0) + goto free_prog_sec; + license[sizeof(license) - 1] = 0; + + /* eBPF programs must be GPL compatible to use GPL-ed functions */ + prog->gpl_compatible = license_is_gpl_compatible(license) ? 1 : 0; prog->orig_prog = NULL; prog->jited = 0; atomic64_set(&prog->aux->refcnt, 1); - prog->gpl_compatible = is_gpl ? 1 : 0; if (bpf_prog_is_dev_bound(prog->aux)) { err = bpf_prog_dev_bound_init(prog, attr); -- cgit v1.2.3 From e2fa5c2068fbea59e648d1637040ba8494f45104 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 16 Jun 2023 14:28:00 +0800 Subject: xsk: Remove unused inline function xsk_buff_discard() commit f2f167583601 ("xsk: Remove unused xsk_buff_discard") left behind this, remove it. Signed-off-by: YueHaibing Signed-off-by: Daniel Borkmann Reviewed-by: Simon Horman Acked-by: Maciej Fijalkowski Link: https://lore.kernel.org/bpf/20230616062800.30780-1-yuehaibing@huawei.com --- include/net/xdp_sock_drv.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h index 9c0d860609ba..c243f906ebed 100644 --- a/include/net/xdp_sock_drv.h +++ b/include/net/xdp_sock_drv.h @@ -255,10 +255,6 @@ static inline void xsk_buff_free(struct xdp_buff *xdp) { } -static inline void xsk_buff_discard(struct xdp_buff *xdp) -{ -} - static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size) { } -- cgit v1.2.3 From 7ec2e4499e378768a985cd4679144713edb37035 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 19 Jun 2023 13:38:56 +0300 Subject: wifi: iwlwifi: dvm: fix -Wunused-const-variable gcc warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following gcc 13.1 warning observed with W=1: drivers/net/wireless/intel/iwlwifi/dvm/rs.c:207:39: warning: ‘iwl_rate_mcs’ defined but not used [-Wunused-const-variable=] This table is actually used in 'rs_sta_dbgfs_scale_table_read()' only if CONFIG_MAC80211_DEBUGFS is enabled, so the whole thing may be moved close to its actual use. Signed-off-by: Dmitry Antipov Link: https://lore.kernel.org/r/20230619103900.300628-1-dmantipov@yandex.ru Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c index 4b1f006c105b..f4a6f76cf193 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c @@ -203,23 +203,6 @@ static const u16 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { {0, 0, 0, 0, 277, 0, 478, 624, 737, 911, 1026, 1070, 1109}, /* AGG+SGI */ }; -/* mbps, mcs */ -static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { - { "1", "BPSK DSSS"}, - { "2", "QPSK DSSS"}, - {"5.5", "BPSK CCK"}, - { "11", "QPSK CCK"}, - { "6", "BPSK 1/2"}, - { "9", "BPSK 1/2"}, - { "12", "QPSK 1/2"}, - { "18", "QPSK 3/4"}, - { "24", "16QAM 1/2"}, - { "36", "16QAM 3/4"}, - { "48", "64QAM 2/3"}, - { "54", "64QAM 3/4"}, - { "60", "64QAM 5/6"}, -}; - #define MCS_INDEX_PER_STREAM (8) static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) @@ -3089,6 +3072,23 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, int index = 0; ssize_t ret; + /* mbps, mcs */ + static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { + { "1", "BPSK DSSS"}, + { "2", "QPSK DSSS"}, + {"5.5", "BPSK CCK"}, + { "11", "QPSK CCK"}, + { "6", "BPSK 1/2"}, + { "9", "BPSK 1/2"}, + { "12", "QPSK 1/2"}, + { "18", "QPSK 3/4"}, + { "24", "16QAM 1/2"}, + { "36", "16QAM 3/4"}, + { "48", "64QAM 2/3"}, + { "54", "64QAM 3/4"}, + { "60", "64QAM 5/6"}, + }; + struct iwl_lq_sta *lq_sta = file->private_data; struct iwl_priv *priv; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); -- cgit v1.2.3 From 5a0702aac020b2e81f778e3477095d8ed39ce523 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 17 May 2023 11:44:28 -0700 Subject: wifi: mac80211: add eht_capa debugfs field Output looks like this: [root@ct523c-0b29 ~]# cat /debug/ieee80211/wiphy6/netdev\:wlan6/stations/50\:28\:4a\:bd\:f4\:a7/eht_capa EHT supported MAC-CAP: 0x82 0x00 PHY-CAP: 0x0c 0x00 0x00 0x00 0x00 0x48 0x00 0x00 0x00 OM-CONTROL MAX-MPDU-LEN: 11454 242-TONE-RU-GT20MHZ NDP-4-EHT-LFT-32-GI BEAMFORMEE-80-NSS: 0 BEAMFORMEE-160-NSS: 0 BEAMFORMEE-320-NSS: 0 SOUNDING-DIM-80-NSS: 0 SOUNDING-DIM-160-NSS: 0 SOUNDING-DIM-320-NSS: 0 MAX_NC: 0 PPE_THRESHOLD_PRESENT NOMINAL_PKT_PAD: 0us MAX-NUM-SUPP-EHT-LTF: 1 SUPP-EXTRA-EHT-LTF MCS15-SUPP-MASK: 0 EHT bw <= 80 MHz, max NSS for MCS 8-9: Rx=2, Tx=2 EHT bw <= 80 MHz, max NSS for MCS 10-11: Rx=2, Tx=2 EHT bw <= 80 MHz, max NSS for MCS 12-13: Rx=2, Tx=2 EHT bw <= 160 MHz, max NSS for MCS 8-9: Rx=0, Tx=0 EHT bw <= 160 MHz, max NSS for MCS 10-11: Rx=0, Tx=0 EHT bw <= 160 MHz, max NSS for MCS 12-13: Rx=0, Tx=0 EHT bw <= 320 MHz, max NSS for MCS 8-9: Rx=0, Tx=0 EHT bw <= 320 MHz, max NSS for MCS 10-11: Rx=0, Tx=0 EHT bw <= 320 MHz, max NSS for MCS 12-13: Rx=0, Tx=0 EHT PPE Thresholds: 0xc1 0x0e 0xe0 0x00 0x00 Signed-off-by: Ben Greear Link: https://lore.kernel.org/r/20230517184428.999384-1-greearb@candelatech.com Signed-off-by: Johannes Berg --- net/mac80211/debugfs_sta.c | 185 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index f1914bf39f0e..5a97fb248c85 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -1035,6 +1035,190 @@ out: } LINK_STA_OPS(he_capa); +static ssize_t link_sta_eht_capa_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char *buf, *p; + size_t buf_sz = PAGE_SIZE; + struct link_sta_info *link_sta = file->private_data; + struct ieee80211_sta_eht_cap *bec = &link_sta->pub->eht_cap; + struct ieee80211_eht_cap_elem_fixed *fixed = &bec->eht_cap_elem; + struct ieee80211_eht_mcs_nss_supp *nss = &bec->eht_mcs_nss_supp; + u8 *cap; + int i; + ssize_t ret; + static const char *mcs_desc[] = { "0-7", "8-9", "10-11", "12-13"}; + + buf = kmalloc(buf_sz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + p = buf; + + p += scnprintf(p, buf_sz + buf - p, "EHT %ssupported\n", + bec->has_eht ? "" : "not "); + if (!bec->has_eht) + goto out; + + p += scnprintf(p, buf_sz + buf - p, + "MAC-CAP: %#.2x %#.2x\n", + fixed->mac_cap_info[0], fixed->mac_cap_info[1]); + p += scnprintf(p, buf_sz + buf - p, + "PHY-CAP: %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x %#.2x\n", + fixed->phy_cap_info[0], fixed->phy_cap_info[1], + fixed->phy_cap_info[2], fixed->phy_cap_info[3], + fixed->phy_cap_info[4], fixed->phy_cap_info[5], + fixed->phy_cap_info[6], fixed->phy_cap_info[7], + fixed->phy_cap_info[8]); + +#define PRINT(fmt, ...) \ + p += scnprintf(p, buf_sz + buf - p, "\t\t" fmt "\n", \ + ##__VA_ARGS__) + +#define PFLAG(t, n, a, b) \ + do { \ + if (cap[n] & IEEE80211_EHT_##t##_CAP##n##_##a) \ + PRINT("%s", b); \ + } while (0) + + cap = fixed->mac_cap_info; + PFLAG(MAC, 0, EPCS_PRIO_ACCESS, "EPCS-PRIO-ACCESS"); + PFLAG(MAC, 0, OM_CONTROL, "OM-CONTROL"); + PFLAG(MAC, 0, TRIG_TXOP_SHARING_MODE1, "TRIG-TXOP-SHARING-MODE1"); + PFLAG(MAC, 0, TRIG_TXOP_SHARING_MODE2, "TRIG-TXOP-SHARING-MODE2"); + PFLAG(MAC, 0, RESTRICTED_TWT, "RESTRICTED-TWT"); + PFLAG(MAC, 0, SCS_TRAFFIC_DESC, "SCS-TRAFFIC-DESC"); + switch ((cap[0] & 0xc0) >> 6) { + case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_3895: + PRINT("MAX-MPDU-LEN: 3985"); + break; + case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991: + PRINT("MAX-MPDU-LEN: 7991"); + break; + case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454: + PRINT("MAX-MPDU-LEN: 11454"); + break; + } + + cap = fixed->phy_cap_info; + PFLAG(PHY, 0, 320MHZ_IN_6GHZ, "320MHZ-IN-6GHZ"); + PFLAG(PHY, 0, 242_TONE_RU_GT20MHZ, "242-TONE-RU-GT20MHZ"); + PFLAG(PHY, 0, NDP_4_EHT_LFT_32_GI, "NDP-4-EHT-LFT-32-GI"); + PFLAG(PHY, 0, PARTIAL_BW_UL_MU_MIMO, "PARTIAL-BW-UL-MU-MIMO"); + PFLAG(PHY, 0, SU_BEAMFORMER, "SU-BEAMFORMER"); + PFLAG(PHY, 0, SU_BEAMFORMEE, "SU-BEAMFORMEE"); + i = cap[0] >> 7; + i |= (cap[1] & 0x3) << 1; + PRINT("BEAMFORMEE-80-NSS: %i", i); + PRINT("BEAMFORMEE-160-NSS: %i", (cap[1] >> 2) & 0x7); + PRINT("BEAMFORMEE-320-NSS: %i", (cap[1] >> 5) & 0x7); + PRINT("SOUNDING-DIM-80-NSS: %i", (cap[2] & 0x7)); + PRINT("SOUNDING-DIM-160-NSS: %i", (cap[2] >> 3) & 0x7); + i = cap[2] >> 6; + i |= (cap[3] & 0x1) << 3; + PRINT("SOUNDING-DIM-320-NSS: %i", i); + + PFLAG(PHY, 3, NG_16_SU_FEEDBACK, "NG-16-SU-FEEDBACK"); + PFLAG(PHY, 3, NG_16_MU_FEEDBACK, "NG-16-MU-FEEDBACK"); + PFLAG(PHY, 3, CODEBOOK_4_2_SU_FDBK, "CODEBOOK-4-2-SU-FDBK"); + PFLAG(PHY, 3, CODEBOOK_7_5_MU_FDBK, "CODEBOOK-7-5-MU-FDBK"); + PFLAG(PHY, 3, TRIG_SU_BF_FDBK, "TRIG-SU-BF-FDBK"); + PFLAG(PHY, 3, TRIG_MU_BF_PART_BW_FDBK, "TRIG-MU-BF-PART-BW-FDBK"); + PFLAG(PHY, 3, TRIG_CQI_FDBK, "TRIG-CQI-FDBK"); + + PFLAG(PHY, 4, PART_BW_DL_MU_MIMO, "PART-BW-DL-MU-MIMO"); + PFLAG(PHY, 4, PSR_SR_SUPP, "PSR-SR-SUPP"); + PFLAG(PHY, 4, POWER_BOOST_FACT_SUPP, "POWER-BOOST-FACT-SUPP"); + PFLAG(PHY, 4, EHT_MU_PPDU_4_EHT_LTF_08_GI, "EHT-MU-PPDU-4-EHT-LTF-08-GI"); + PRINT("MAX_NC: %i", cap[4] >> 4); + + PFLAG(PHY, 5, NON_TRIG_CQI_FEEDBACK, "NON-TRIG-CQI-FEEDBACK"); + PFLAG(PHY, 5, TX_LESS_242_TONE_RU_SUPP, "TX-LESS-242-TONE-RU-SUPP"); + PFLAG(PHY, 5, RX_LESS_242_TONE_RU_SUPP, "RX-LESS-242-TONE-RU-SUPP"); + PFLAG(PHY, 5, PPE_THRESHOLD_PRESENT, "PPE_THRESHOLD_PRESENT"); + switch (cap[5] >> 4 & 0x3) { + case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_0US: + PRINT("NOMINAL_PKT_PAD: 0us"); + break; + case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US: + PRINT("NOMINAL_PKT_PAD: 8us"); + break; + case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US: + PRINT("NOMINAL_PKT_PAD: 16us"); + break; + case IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US: + PRINT("NOMINAL_PKT_PAD: 20us"); + break; + } + i = cap[5] >> 6; + i |= cap[6] & 0x7; + PRINT("MAX-NUM-SUPP-EHT-LTF: %i", i); + PFLAG(PHY, 5, SUPP_EXTRA_EHT_LTF, "SUPP-EXTRA-EHT-LTF"); + + i = (cap[6] >> 3) & 0xf; + PRINT("MCS15-SUPP-MASK: %i", i); + PFLAG(PHY, 6, EHT_DUP_6GHZ_SUPP, "EHT-DUP-6GHZ-SUPP"); + + PFLAG(PHY, 7, 20MHZ_STA_RX_NDP_WIDER_BW, "20MHZ-STA-RX-NDP-WIDER-BW"); + PFLAG(PHY, 7, NON_OFDMA_UL_MU_MIMO_80MHZ, "NON-OFDMA-UL-MU-MIMO-80MHZ"); + PFLAG(PHY, 7, NON_OFDMA_UL_MU_MIMO_160MHZ, "NON-OFDMA-UL-MU-MIMO-160MHZ"); + PFLAG(PHY, 7, NON_OFDMA_UL_MU_MIMO_320MHZ, "NON-OFDMA-UL-MU-MIMO-320MHZ"); + PFLAG(PHY, 7, MU_BEAMFORMER_80MHZ, "MU-BEAMFORMER-80MHZ"); + PFLAG(PHY, 7, MU_BEAMFORMER_160MHZ, "MU-BEAMFORMER-160MHZ"); + PFLAG(PHY, 7, MU_BEAMFORMER_320MHZ, "MU-BEAMFORMER-320MHZ"); + PFLAG(PHY, 7, TB_SOUNDING_FDBK_RATE_LIMIT, "TB-SOUNDING-FDBK-RATE-LIMIT"); + + PFLAG(PHY, 8, RX_1024QAM_WIDER_BW_DL_OFDMA, "RX-1024QAM-WIDER-BW-DL-OFDMA"); + PFLAG(PHY, 8, RX_4096QAM_WIDER_BW_DL_OFDMA, "RX-4096QAM-WIDER-BW-DL-OFDMA"); + +#undef PFLAG + + PRINT(""); /* newline */ + if (!(link_sta->pub->he_cap.he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { + u8 *mcs_vals = (u8 *)(&nss->only_20mhz); + + for (i = 0; i < 4; i++) + PRINT("EHT bw=20 MHz, max NSS for MCS %s: Rx=%u, Tx=%u", + mcs_desc[i], + mcs_vals[i] & 0xf, mcs_vals[i] >> 4); + } else { + u8 *mcs_vals = (u8 *)(&nss->bw._80); + + for (i = 0; i < 3; i++) + PRINT("EHT bw <= 80 MHz, max NSS for MCS %s: Rx=%u, Tx=%u", + mcs_desc[i + 1], + mcs_vals[i] & 0xf, mcs_vals[i] >> 4); + + mcs_vals = (u8 *)(&nss->bw._160); + for (i = 0; i < 3; i++) + PRINT("EHT bw <= 160 MHz, max NSS for MCS %s: Rx=%u, Tx=%u", + mcs_desc[i + 1], + mcs_vals[i] & 0xf, mcs_vals[i] >> 4); + + mcs_vals = (u8 *)(&nss->bw._320); + for (i = 0; i < 3; i++) + PRINT("EHT bw <= 320 MHz, max NSS for MCS %s: Rx=%u, Tx=%u", + mcs_desc[i + 1], + mcs_vals[i] & 0xf, mcs_vals[i] >> 4); + } + + if (cap[5] & IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) { + u8 ppe_size = ieee80211_eht_ppe_size(bec->eht_ppe_thres[0], cap); + + p += scnprintf(p, buf_sz + buf - p, "EHT PPE Thresholds: "); + for (i = 0; i < ppe_size; i++) + p += scnprintf(p, buf_sz + buf - p, "0x%02x ", + bec->eht_ppe_thres[i]); + PRINT(""); /* newline */ + } + +out: + ret = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); + kfree(buf); + return ret; +} +LINK_STA_OPS(eht_capa); + #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, 0400, \ sta->debugfs_dir, sta, &sta_ ##name## _ops) @@ -1128,6 +1312,7 @@ void ieee80211_link_sta_debugfs_add(struct link_sta_info *link_sta) DEBUGFS_ADD(ht_capa); DEBUGFS_ADD(vht_capa); DEBUGFS_ADD(he_capa); + DEBUGFS_ADD(eht_capa); DEBUGFS_ADD_COUNTER(rx_duplicates, rx_stats.num_duplicates); DEBUGFS_ADD_COUNTER(rx_fragments, rx_stats.fragments); -- cgit v1.2.3 From ac9d8a66e41d553bf57fdffe88f59f1b1443191b Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 14 Jun 2023 16:01:03 -0700 Subject: ipv6: rpl: Remove pskb(_may)?_pull() in ipv6_rpl_srh_rcv(). As Eric Dumazet pointed out [0], ipv6_rthdr_rcv() pulls these data - Segment Routing Header : 8 - Hdr Ext Len : skb_transport_header(skb)[1] << 3 needed by ipv6_rpl_srh_rcv(). We can remove pskb_may_pull() and replace pskb_pull() with skb_pull() in ipv6_rpl_srh_rcv(). Link: https://lore.kernel.org/netdev/CANn89iLboLwLrHXeHJucAqBkEL_S0rJFog68t7wwwXO-aNf5Mg@mail.gmail.com/ [0] Signed-off-by: Kuniyuki Iwashima Signed-off-by: Jakub Kicinski --- include/net/rpl.h | 3 --- net/ipv6/exthdrs.c | 17 +---------------- net/ipv6/rpl.c | 7 ------- 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/include/net/rpl.h b/include/net/rpl.h index 30fe780d1e7c..74734191c458 100644 --- a/include/net/rpl.h +++ b/include/net/rpl.h @@ -23,9 +23,6 @@ static inline int rpl_init(void) static inline void rpl_exit(void) {} #endif -size_t ipv6_rpl_srh_size(unsigned char n, unsigned char cmpri, - unsigned char cmpre); - void ipv6_rpl_srh_decompress(struct ipv6_rpl_sr_hdr *outhdr, const struct ipv6_rpl_sr_hdr *inhdr, const struct in6_addr *daddr, unsigned char n); diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index a543df57801f..65adc11b59aa 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -517,11 +517,7 @@ looped_back: skb_postpull_rcsum(skb, skb_network_header(skb), skb_network_header_len(skb)); - - if (!pskb_pull(skb, offset)) { - kfree_skb(skb); - return -1; - } + skb_pull(skb, offset); skb_postpull_rcsum(skb, skb_transport_header(skb), offset); @@ -543,11 +539,6 @@ looped_back: return 1; } - if (!pskb_may_pull(skb, sizeof(*hdr))) { - kfree_skb(skb); - return -1; - } - n = (hdr->hdrlen << 3) - hdr->pad - (16 - hdr->cmpre); r = do_div(n, (16 - hdr->cmpri)); /* checks if calculation was without remainder and n fits into @@ -567,12 +558,6 @@ looped_back: return -1; } - if (!pskb_may_pull(skb, ipv6_rpl_srh_size(n, hdr->cmpri, - hdr->cmpre))) { - kfree_skb(skb); - return -1; - } - hdr->segments_left--; i = n - hdr->segments_left; diff --git a/net/ipv6/rpl.c b/net/ipv6/rpl.c index d1876f192225..e186998bfbf7 100644 --- a/net/ipv6/rpl.c +++ b/net/ipv6/rpl.c @@ -29,13 +29,6 @@ static void *ipv6_rpl_segdata_pos(const struct ipv6_rpl_sr_hdr *hdr, int i) return (void *)&hdr->rpl_segdata[i * IPV6_PFXTAIL_LEN(hdr->cmpri)]; } -size_t ipv6_rpl_srh_size(unsigned char n, unsigned char cmpri, - unsigned char cmpre) -{ - return sizeof(struct ipv6_rpl_sr_hdr) + (n * IPV6_PFXTAIL_LEN(cmpri)) + - IPV6_PFXTAIL_LEN(cmpre); -} - void ipv6_rpl_srh_decompress(struct ipv6_rpl_sr_hdr *outhdr, const struct ipv6_rpl_sr_hdr *inhdr, const struct in6_addr *daddr, unsigned char n) -- cgit v1.2.3 From 6facbca52da2c209ddffa0c9547769cbcaa268ef Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 14 Jun 2023 16:01:04 -0700 Subject: ipv6: rpl: Remove redundant multicast tests in ipv6_rpl_srh_rcv(). ipv6_rpl_srh_rcv() checks if ipv6_hdr(skb)->daddr or ohdr->rpl_segaddr[i] is the multicast address with ipv6_addr_type(). We have the same check for ipv6_hdr(skb)->daddr in ipv6_rthdr_rcv(), so we need not recheck it in ipv6_rpl_srh_rcv(). Also, we should use ipv6_addr_is_multicast() for ohdr->rpl_segaddr[i] instead of ipv6_addr_type(). Signed-off-by: Kuniyuki Iwashima Signed-off-by: Jakub Kicinski --- net/ipv6/exthdrs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 65adc11b59aa..6259e907f0d9 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -571,8 +571,7 @@ looped_back: ipv6_rpl_srh_decompress(ohdr, hdr, &ipv6_hdr(skb)->daddr, n); chdr = (struct ipv6_rpl_sr_hdr *)(buf + ((ohdr->hdrlen + 1) << 3)); - if ((ipv6_addr_type(&ipv6_hdr(skb)->daddr) & IPV6_ADDR_MULTICAST) || - (ipv6_addr_type(&ohdr->rpl_segaddr[i]) & IPV6_ADDR_MULTICAST)) { + if (ipv6_addr_is_multicast(&ohdr->rpl_segaddr[i])) { kfree_skb(skb); kfree(buf); return -1; -- cgit v1.2.3 From 0d2e27b858503472f8ed66910498205824b02f8a Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 14 Jun 2023 16:01:05 -0700 Subject: ipv6: exthdrs: Replace pskb_pull() with skb_pull() in ipv6_srh_rcv(). ipv6_rthdr_rcv() pulls these data - Segment Routing Header : 8 - Hdr Ext Len : skb_transport_header(skb)[1] << 3 needed by ipv6_srh_rcv(), so pskb_pull() in ipv6_srh_rcv() never fails and can be replaced with skb_pull(). Signed-off-by: Kuniyuki Iwashima Signed-off-by: Jakub Kicinski --- net/ipv6/exthdrs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 6259e907f0d9..e62e26ac99ef 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -402,11 +402,7 @@ looped_back: skb_postpull_rcsum(skb, skb_network_header(skb), skb_network_header_len(skb)); - - if (!pskb_pull(skb, offset)) { - kfree_skb(skb); - return -1; - } + skb_pull(skb, offset); skb_postpull_rcsum(skb, skb_transport_header(skb), offset); -- cgit v1.2.3 From b83d50f43165e8c21d580f40c57d8f6fe85adb59 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 14 Jun 2023 16:01:06 -0700 Subject: ipv6: exthdrs: Reload hdr only when needed in ipv6_srh_rcv(). We need not reload hdr in ipv6_srh_rcv() unless we call pskb_expand_head(). Signed-off-by: Kuniyuki Iwashima Signed-off-by: Jakub Kicinski --- net/ipv6/exthdrs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index e62e26ac99ef..dd23531387e3 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -440,9 +440,9 @@ looped_back: kfree_skb(skb); return -1; } - } - hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb); + hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb); + } hdr->segments_left--; addr = hdr->segments + hdr->segments_left; -- cgit v1.2.3 From 6db5dd2bf4817a415daaf6a0226beadef1473d30 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Wed, 14 Jun 2023 16:01:07 -0700 Subject: ipv6: exthdrs: Remove redundant skb_headlen() check in ip6_parse_tlv(). ipv6_destopt_rcv() and ipv6_parse_hopopts() pulls these data - Hop-by-Hop/Destination Options Header : 8 - Hdr Ext Len : skb_transport_header(skb)[1] << 3 and calls ip6_parse_tlv(), so it need not check if skb_headlen() is less than skb_transport_offset(skb) + (skb_transport_header(skb)[1] << 3). Signed-off-by: Kuniyuki Iwashima Signed-off-by: Jakub Kicinski --- net/ipv6/exthdrs.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index dd23531387e3..202fc3aaa83c 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -126,9 +126,6 @@ static bool ip6_parse_tlv(bool hopbyhop, max_count = -max_count; } - if (skb_transport_offset(skb) + len > skb_headlen(skb)) - goto bad; - off += 2; len -= 2; -- cgit v1.2.3 From 8ad663d3dfac95cbcc4121d0655bd18ad9de826f Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 13 Jun 2023 16:09:17 +0800 Subject: selftests/bpf: Use producer_cnt to allocate local counter array For count-local benchmark, use producer_cnt instead of consumer_cnt when allocating local counter array. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230613080921.1623219-2-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/benchs/bench_count.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/benchs/bench_count.c b/tools/testing/selftests/bpf/benchs/bench_count.c index 078972ce208e..3768945ad08e 100644 --- a/tools/testing/selftests/bpf/benchs/bench_count.c +++ b/tools/testing/selftests/bpf/benchs/bench_count.c @@ -40,7 +40,7 @@ static void count_local_setup(void) { struct count_local_ctx *ctx = &count_local_ctx; - ctx->hits = calloc(env.consumer_cnt, sizeof(*ctx->hits)); + ctx->hits = calloc(env.producer_cnt, sizeof(*ctx->hits)); if (!ctx->hits) exit(1); } -- cgit v1.2.3 From ea400d13fc92ec66578b068e661a162e01d4b641 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 13 Jun 2023 16:09:18 +0800 Subject: selftests/bpf: Output the correct error code for pthread APIs The return value of pthread API is the error code when the called API fails, so output the return value instead of errno. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230613080921.1623219-3-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bench.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/bpf/bench.c b/tools/testing/selftests/bpf/bench.c index d9c080ac1796..0b5d2b5303c9 100644 --- a/tools/testing/selftests/bpf/bench.c +++ b/tools/testing/selftests/bpf/bench.c @@ -441,12 +441,14 @@ static void setup_timer() static void set_thread_affinity(pthread_t thread, int cpu) { cpu_set_t cpuset; + int err; CPU_ZERO(&cpuset); CPU_SET(cpu, &cpuset); - if (pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset)) { + err = pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset); + if (err) { fprintf(stderr, "setting affinity to CPU #%d failed: %d\n", - cpu, errno); + cpu, -err); exit(1); } } @@ -605,7 +607,7 @@ static void setup_benchmark(void) bench->consumer_thread, (void *)(long)i); if (err) { fprintf(stderr, "failed to create consumer thread #%d: %d\n", - i, -errno); + i, -err); exit(1); } if (env.affinity) @@ -624,7 +626,7 @@ static void setup_benchmark(void) bench->producer_thread, (void *)(long)i); if (err) { fprintf(stderr, "failed to create producer thread #%d: %d\n", - i, -errno); + i, -err); exit(1); } if (env.affinity) -- cgit v1.2.3 From da77ae2b27ec73a644624a6d4bffc206e2df6bb8 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 13 Jun 2023 16:09:19 +0800 Subject: selftests/bpf: Ensure that next_cpu() returns a valid CPU number When using option -a without --prod-affinity or --cons-affinity, if the number of producers and consumers is greater than the number of online CPUs, the benchmark will fail to run as shown below: $ getconf _NPROCESSORS_ONLN 8 $ ./bench bpf-loop -a -p9 Setting up benchmark 'bpf-loop'... setting affinity to CPU #8 failed: -22 Fix it by returning the remainder of next_cpu divided by the number of online CPUs in next_cpu(). Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230613080921.1623219-4-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bench.c | 3 ++- tools/testing/selftests/bpf/bench.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/bench.c b/tools/testing/selftests/bpf/bench.c index 0b5d2b5303c9..56f1c166a57b 100644 --- a/tools/testing/selftests/bpf/bench.c +++ b/tools/testing/selftests/bpf/bench.c @@ -469,7 +469,7 @@ static int next_cpu(struct cpu_set *cpu_set) exit(1); } - return cpu_set->next_cpu++; + return cpu_set->next_cpu++ % env.nr_cpus; } static struct bench_state { @@ -659,6 +659,7 @@ static void collect_measurements(long delta_ns) { int main(int argc, char **argv) { + env.nr_cpus = get_nprocs(); parse_cmdline_args_init(argc, argv); if (env.list) { diff --git a/tools/testing/selftests/bpf/bench.h b/tools/testing/selftests/bpf/bench.h index 402729c6a3ac..7ff32be3d730 100644 --- a/tools/testing/selftests/bpf/bench.h +++ b/tools/testing/selftests/bpf/bench.h @@ -27,6 +27,7 @@ struct env { bool quiet; int consumer_cnt; int producer_cnt; + int nr_cpus; struct cpu_set prod_cpus; struct cpu_set cons_cpus; }; -- cgit v1.2.3 From 970308a7b544fa1c7ee98a2721faba3765be8dd8 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Tue, 13 Jun 2023 16:09:20 +0800 Subject: selftests/bpf: Set the default value of consumer_cnt as 0 Considering that only bench_ringbufs.c supports consumer, just set the default value of consumer_cnt as 0. After that, update the validity check of consumer_cnt, remove unused consumer_thread code snippets and set consumer_cnt as 1 in run_bench_ringbufs.sh accordingly. Signed-off-by: Hou Tao Link: https://lore.kernel.org/r/20230613080921.1623219-5-houtao@huaweicloud.com Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bench.c | 2 +- .../selftests/bpf/benchs/bench_bloom_filter_map.c | 14 ++---------- .../bpf/benchs/bench_bpf_hashmap_full_update.c | 10 ++------- .../bpf/benchs/bench_bpf_hashmap_lookup.c | 10 ++------- .../testing/selftests/bpf/benchs/bench_bpf_loop.c | 10 ++------- tools/testing/selftests/bpf/benchs/bench_count.c | 12 ---------- .../selftests/bpf/benchs/bench_local_storage.c | 12 ++-------- .../bpf/benchs/bench_local_storage_create.c | 8 +------ .../benchs/bench_local_storage_rcu_tasks_trace.c | 10 ++------- tools/testing/selftests/bpf/benchs/bench_rename.c | 15 ++----------- .../testing/selftests/bpf/benchs/bench_ringbufs.c | 2 +- tools/testing/selftests/bpf/benchs/bench_strncmp.c | 11 ++------- tools/testing/selftests/bpf/benchs/bench_trigger.c | 21 ++--------------- .../selftests/bpf/benchs/run_bench_ringbufs.sh | 26 ++++++++++++---------- 14 files changed, 35 insertions(+), 128 deletions(-) diff --git a/tools/testing/selftests/bpf/bench.c b/tools/testing/selftests/bpf/bench.c index 56f1c166a57b..41fe5a82b88b 100644 --- a/tools/testing/selftests/bpf/bench.c +++ b/tools/testing/selftests/bpf/bench.c @@ -17,7 +17,7 @@ struct env env = { .duration_sec = 5, .affinity = false, .quiet = false, - .consumer_cnt = 1, + .consumer_cnt = 0, .producer_cnt = 1, }; diff --git a/tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c b/tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c index 7c8ccc108313..e289dd1a14ee 100644 --- a/tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c +++ b/tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c @@ -107,9 +107,9 @@ const struct argp bench_bloom_map_argp = { static void validate(void) { - if (env.consumer_cnt != 1) { + if (env.consumer_cnt != 0) { fprintf(stderr, - "The bloom filter benchmarks do not support multi-consumer use\n"); + "The bloom filter benchmarks do not support consumer\n"); exit(1); } } @@ -421,18 +421,12 @@ static void measure(struct bench_res *res) last_false_hits = total_false_hits; } -static void *consumer(void *input) -{ - return NULL; -} - const struct bench bench_bloom_lookup = { .name = "bloom-lookup", .argp = &bench_bloom_map_argp, .validate = validate, .setup = bloom_lookup_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -444,7 +438,6 @@ const struct bench bench_bloom_update = { .validate = validate, .setup = bloom_update_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -456,7 +449,6 @@ const struct bench bench_bloom_false_positive = { .validate = validate, .setup = false_positive_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = false_hits_report_progress, .report_final = false_hits_report_final, @@ -468,7 +460,6 @@ const struct bench bench_hashmap_without_bloom = { .validate = validate, .setup = hashmap_no_bloom_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -480,7 +471,6 @@ const struct bench bench_hashmap_with_bloom = { .validate = validate, .setup = hashmap_with_bloom_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c index 75abe8137b6c..ee1dc12c5e5e 100644 --- a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c +++ b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c @@ -14,8 +14,8 @@ static struct ctx { static void validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } } @@ -30,11 +30,6 @@ static void *producer(void *input) return NULL; } -static void *consumer(void *input) -{ - return NULL; -} - static void measure(struct bench_res *res) { } @@ -88,7 +83,6 @@ const struct bench bench_bpf_hashmap_full_update = { .validate = validate, .setup = setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = NULL, .report_final = hashmap_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c index 8dbb02f75cff..279ff1b8b5b2 100644 --- a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c +++ b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c @@ -113,8 +113,8 @@ const struct argp bench_hashmap_lookup_argp = { static void validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } @@ -134,11 +134,6 @@ static void *producer(void *input) return NULL; } -static void *consumer(void *input) -{ - return NULL; -} - static void measure(struct bench_res *res) { } @@ -276,7 +271,6 @@ const struct bench bench_bpf_hashmap_lookup = { .validate = validate, .setup = setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = NULL, .report_final = hashmap_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_bpf_loop.c b/tools/testing/selftests/bpf/benchs/bench_bpf_loop.c index d8a0394e10b1..a705cfb2bccc 100644 --- a/tools/testing/selftests/bpf/benchs/bench_bpf_loop.c +++ b/tools/testing/selftests/bpf/benchs/bench_bpf_loop.c @@ -47,8 +47,8 @@ const struct argp bench_bpf_loop_argp = { static void validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } } @@ -62,11 +62,6 @@ static void *producer(void *input) return NULL; } -static void *consumer(void *input) -{ - return NULL; -} - static void measure(struct bench_res *res) { res->hits = atomic_swap(&ctx.skel->bss->hits, 0); @@ -99,7 +94,6 @@ const struct bench bench_bpf_loop = { .validate = validate, .setup = setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = ops_report_progress, .report_final = ops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_count.c b/tools/testing/selftests/bpf/benchs/bench_count.c index 3768945ad08e..ba89ed3936b7 100644 --- a/tools/testing/selftests/bpf/benchs/bench_count.c +++ b/tools/testing/selftests/bpf/benchs/bench_count.c @@ -18,11 +18,6 @@ static void *count_global_producer(void *input) return NULL; } -static void *count_global_consumer(void *input) -{ - return NULL; -} - static void count_global_measure(struct bench_res *res) { struct count_global_ctx *ctx = &count_global_ctx; @@ -56,11 +51,6 @@ static void *count_local_producer(void *input) return NULL; } -static void *count_local_consumer(void *input) -{ - return NULL; -} - static void count_local_measure(struct bench_res *res) { struct count_local_ctx *ctx = &count_local_ctx; @@ -74,7 +64,6 @@ static void count_local_measure(struct bench_res *res) const struct bench bench_count_global = { .name = "count-global", .producer_thread = count_global_producer, - .consumer_thread = count_global_consumer, .measure = count_global_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -84,7 +73,6 @@ const struct bench bench_count_local = { .name = "count-local", .setup = count_local_setup, .producer_thread = count_local_producer, - .consumer_thread = count_local_consumer, .measure = count_local_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_local_storage.c b/tools/testing/selftests/bpf/benchs/bench_local_storage.c index d4b2817306d4..452499428ceb 100644 --- a/tools/testing/selftests/bpf/benchs/bench_local_storage.c +++ b/tools/testing/selftests/bpf/benchs/bench_local_storage.c @@ -74,8 +74,8 @@ static void validate(void) fprintf(stderr, "benchmark doesn't support multi-producer!\n"); exit(1); } - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } @@ -230,11 +230,6 @@ static inline void trigger_bpf_program(void) syscall(__NR_getpgid); } -static void *consumer(void *input) -{ - return NULL; -} - static void *producer(void *input) { while (true) @@ -259,7 +254,6 @@ const struct bench bench_local_storage_cache_seq_get = { .validate = validate, .setup = local_storage_cache_get_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = local_storage_report_progress, .report_final = local_storage_report_final, @@ -271,7 +265,6 @@ const struct bench bench_local_storage_cache_interleaved_get = { .validate = validate, .setup = local_storage_cache_get_interleaved_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = local_storage_report_progress, .report_final = local_storage_report_final, @@ -283,7 +276,6 @@ const struct bench bench_local_storage_cache_hashmap_control = { .validate = validate, .setup = hashmap_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = local_storage_report_progress, .report_final = local_storage_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_local_storage_create.c b/tools/testing/selftests/bpf/benchs/bench_local_storage_create.c index cff703f90e95..b36de42ee4d9 100644 --- a/tools/testing/selftests/bpf/benchs/bench_local_storage_create.c +++ b/tools/testing/selftests/bpf/benchs/bench_local_storage_create.c @@ -71,7 +71,7 @@ const struct argp bench_local_storage_create_argp = { static void validate(void) { - if (env.consumer_cnt > 1) { + if (env.consumer_cnt != 0) { fprintf(stderr, "local-storage-create benchmark does not need consumer\n"); exit(1); @@ -143,11 +143,6 @@ static void measure(struct bench_res *res) res->drops = atomic_swap(&skel->bss->kmalloc_cnts, 0); } -static void *consumer(void *input) -{ - return NULL; -} - static void *sk_producer(void *input) { struct thread *t = &threads[(long)(input)]; @@ -257,7 +252,6 @@ const struct bench bench_local_storage_create = { .validate = validate, .setup = setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = report_progress, .report_final = report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c b/tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c index d5eb5587f2aa..edf0b00418c1 100644 --- a/tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c +++ b/tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c @@ -72,8 +72,8 @@ static void validate(void) fprintf(stderr, "benchmark doesn't support multi-producer!\n"); exit(1); } - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } @@ -197,11 +197,6 @@ static void measure(struct bench_res *res) ctx.prev_kthread_stime = ticks; } -static void *consumer(void *input) -{ - return NULL; -} - static void *producer(void *input) { while (true) @@ -262,7 +257,6 @@ const struct bench bench_local_storage_tasks_trace = { .validate = validate, .setup = local_storage_tasks_trace_setup, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = report_progress, .report_final = report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_rename.c b/tools/testing/selftests/bpf/benchs/bench_rename.c index 3c203b6d6a6e..bf66893c7a33 100644 --- a/tools/testing/selftests/bpf/benchs/bench_rename.c +++ b/tools/testing/selftests/bpf/benchs/bench_rename.c @@ -17,8 +17,8 @@ static void validate(void) fprintf(stderr, "benchmark doesn't support multi-producer!\n"); exit(1); } - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } } @@ -106,17 +106,11 @@ static void setup_fexit(void) attach_bpf(ctx.skel->progs.prog5); } -static void *consumer(void *input) -{ - return NULL; -} - const struct bench bench_rename_base = { .name = "rename-base", .validate = validate, .setup = setup_base, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -127,7 +121,6 @@ const struct bench bench_rename_kprobe = { .validate = validate, .setup = setup_kprobe, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -138,7 +131,6 @@ const struct bench bench_rename_kretprobe = { .validate = validate, .setup = setup_kretprobe, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -149,7 +141,6 @@ const struct bench bench_rename_rawtp = { .validate = validate, .setup = setup_rawtp, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -160,7 +151,6 @@ const struct bench bench_rename_fentry = { .validate = validate, .setup = setup_fentry, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -171,7 +161,6 @@ const struct bench bench_rename_fexit = { .validate = validate, .setup = setup_fexit, .producer_thread = producer, - .consumer_thread = consumer, .measure = measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_ringbufs.c b/tools/testing/selftests/bpf/benchs/bench_ringbufs.c index fc91fdac4faa..3ca14ad36607 100644 --- a/tools/testing/selftests/bpf/benchs/bench_ringbufs.c +++ b/tools/testing/selftests/bpf/benchs/bench_ringbufs.c @@ -96,7 +96,7 @@ static inline void bufs_trigger_batch(void) static void bufs_validate(void) { if (env.consumer_cnt != 1) { - fprintf(stderr, "rb-libbpf benchmark doesn't support multi-consumer!\n"); + fprintf(stderr, "rb-libbpf benchmark needs one consumer!\n"); exit(1); } diff --git a/tools/testing/selftests/bpf/benchs/bench_strncmp.c b/tools/testing/selftests/bpf/benchs/bench_strncmp.c index d3fad2ba6916..a5e1428fd7a0 100644 --- a/tools/testing/selftests/bpf/benchs/bench_strncmp.c +++ b/tools/testing/selftests/bpf/benchs/bench_strncmp.c @@ -50,8 +50,8 @@ const struct argp bench_strncmp_argp = { static void strncmp_validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "strncmp benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "strncmp benchmark doesn't support consumer!\n"); exit(1); } } @@ -128,11 +128,6 @@ static void *strncmp_producer(void *ctx) return NULL; } -static void *strncmp_consumer(void *ctx) -{ - return NULL; -} - static void strncmp_measure(struct bench_res *res) { res->hits = atomic_swap(&ctx.skel->bss->hits, 0); @@ -144,7 +139,6 @@ const struct bench bench_strncmp_no_helper = { .validate = strncmp_validate, .setup = strncmp_no_helper_setup, .producer_thread = strncmp_producer, - .consumer_thread = strncmp_consumer, .measure = strncmp_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -156,7 +150,6 @@ const struct bench bench_strncmp_helper = { .validate = strncmp_validate, .setup = strncmp_helper_setup, .producer_thread = strncmp_producer, - .consumer_thread = strncmp_consumer, .measure = strncmp_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/bench_trigger.c b/tools/testing/selftests/bpf/benchs/bench_trigger.c index 0c481de2833d..dbd362771d6a 100644 --- a/tools/testing/selftests/bpf/benchs/bench_trigger.c +++ b/tools/testing/selftests/bpf/benchs/bench_trigger.c @@ -13,8 +13,8 @@ static struct counter base_hits; static void trigger_validate(void) { - if (env.consumer_cnt != 1) { - fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); + if (env.consumer_cnt != 0) { + fprintf(stderr, "benchmark doesn't support consumer!\n"); exit(1); } } @@ -103,11 +103,6 @@ static void trigger_fmodret_setup(void) attach_bpf(ctx.skel->progs.bench_trigger_fmodret); } -static void *trigger_consumer(void *input) -{ - return NULL; -} - /* make sure call is not inlined and not avoided by compiler, so __weak and * inline asm volatile in the body of the function * @@ -205,7 +200,6 @@ const struct bench bench_trig_base = { .name = "trig-base", .validate = trigger_validate, .producer_thread = trigger_base_producer, - .consumer_thread = trigger_consumer, .measure = trigger_base_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -216,7 +210,6 @@ const struct bench bench_trig_tp = { .validate = trigger_validate, .setup = trigger_tp_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -227,7 +220,6 @@ const struct bench bench_trig_rawtp = { .validate = trigger_validate, .setup = trigger_rawtp_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -238,7 +230,6 @@ const struct bench bench_trig_kprobe = { .validate = trigger_validate, .setup = trigger_kprobe_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -249,7 +240,6 @@ const struct bench bench_trig_fentry = { .validate = trigger_validate, .setup = trigger_fentry_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -260,7 +250,6 @@ const struct bench bench_trig_fentry_sleep = { .validate = trigger_validate, .setup = trigger_fentry_sleep_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -271,7 +260,6 @@ const struct bench bench_trig_fmodret = { .validate = trigger_validate, .setup = trigger_fmodret_setup, .producer_thread = trigger_producer, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -281,7 +269,6 @@ const struct bench bench_trig_uprobe_base = { .name = "trig-uprobe-base", .setup = NULL, /* no uprobe/uretprobe is attached */ .producer_thread = uprobe_base_producer, - .consumer_thread = trigger_consumer, .measure = trigger_base_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -291,7 +278,6 @@ const struct bench bench_trig_uprobe_with_nop = { .name = "trig-uprobe-with-nop", .setup = uprobe_setup_with_nop, .producer_thread = uprobe_producer_with_nop, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -301,7 +287,6 @@ const struct bench bench_trig_uretprobe_with_nop = { .name = "trig-uretprobe-with-nop", .setup = uretprobe_setup_with_nop, .producer_thread = uprobe_producer_with_nop, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -311,7 +296,6 @@ const struct bench bench_trig_uprobe_without_nop = { .name = "trig-uprobe-without-nop", .setup = uprobe_setup_without_nop, .producer_thread = uprobe_producer_without_nop, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, @@ -321,7 +305,6 @@ const struct bench bench_trig_uretprobe_without_nop = { .name = "trig-uretprobe-without-nop", .setup = uretprobe_setup_without_nop, .producer_thread = uprobe_producer_without_nop, - .consumer_thread = trigger_consumer, .measure = trigger_measure, .report_progress = hits_drops_report_progress, .report_final = hits_drops_report_final, diff --git a/tools/testing/selftests/bpf/benchs/run_bench_ringbufs.sh b/tools/testing/selftests/bpf/benchs/run_bench_ringbufs.sh index ada028aa9007..91e3567962ff 100755 --- a/tools/testing/selftests/bpf/benchs/run_bench_ringbufs.sh +++ b/tools/testing/selftests/bpf/benchs/run_bench_ringbufs.sh @@ -4,46 +4,48 @@ source ./benchs/run_common.sh set -eufo pipefail +RUN_RB_BENCH="$RUN_BENCH -c1" + header "Single-producer, parallel producer" for b in rb-libbpf rb-custom pb-libbpf pb-custom; do - summarize $b "$($RUN_BENCH $b)" + summarize $b "$($RUN_RB_BENCH $b)" done header "Single-producer, parallel producer, sampled notification" for b in rb-libbpf rb-custom pb-libbpf pb-custom; do - summarize $b "$($RUN_BENCH --rb-sampled $b)" + summarize $b "$($RUN_RB_BENCH --rb-sampled $b)" done header "Single-producer, back-to-back mode" for b in rb-libbpf rb-custom pb-libbpf pb-custom; do - summarize $b "$($RUN_BENCH --rb-b2b $b)" - summarize $b-sampled "$($RUN_BENCH --rb-sampled --rb-b2b $b)" + summarize $b "$($RUN_RB_BENCH --rb-b2b $b)" + summarize $b-sampled "$($RUN_RB_BENCH --rb-sampled --rb-b2b $b)" done header "Ringbuf back-to-back, effect of sample rate" for b in 1 5 10 25 50 100 250 500 1000 2000 3000; do - summarize "rb-sampled-$b" "$($RUN_BENCH --rb-b2b --rb-batch-cnt $b --rb-sampled --rb-sample-rate $b rb-custom)" + summarize "rb-sampled-$b" "$($RUN_RB_BENCH --rb-b2b --rb-batch-cnt $b --rb-sampled --rb-sample-rate $b rb-custom)" done header "Perfbuf back-to-back, effect of sample rate" for b in 1 5 10 25 50 100 250 500 1000 2000 3000; do - summarize "pb-sampled-$b" "$($RUN_BENCH --rb-b2b --rb-batch-cnt $b --rb-sampled --rb-sample-rate $b pb-custom)" + summarize "pb-sampled-$b" "$($RUN_RB_BENCH --rb-b2b --rb-batch-cnt $b --rb-sampled --rb-sample-rate $b pb-custom)" done header "Ringbuf back-to-back, reserve+commit vs output" -summarize "reserve" "$($RUN_BENCH --rb-b2b rb-custom)" -summarize "output" "$($RUN_BENCH --rb-b2b --rb-use-output rb-custom)" +summarize "reserve" "$($RUN_RB_BENCH --rb-b2b rb-custom)" +summarize "output" "$($RUN_RB_BENCH --rb-b2b --rb-use-output rb-custom)" header "Ringbuf sampled, reserve+commit vs output" -summarize "reserve-sampled" "$($RUN_BENCH --rb-sampled rb-custom)" -summarize "output-sampled" "$($RUN_BENCH --rb-sampled --rb-use-output rb-custom)" +summarize "reserve-sampled" "$($RUN_RB_BENCH --rb-sampled rb-custom)" +summarize "output-sampled" "$($RUN_RB_BENCH --rb-sampled --rb-use-output rb-custom)" header "Single-producer, consumer/producer competing on the same CPU, low batch count" for b in rb-libbpf rb-custom pb-libbpf pb-custom; do - summarize $b "$($RUN_BENCH --rb-batch-cnt 1 --rb-sample-rate 1 --prod-affinity 0 --cons-affinity 0 $b)" + summarize $b "$($RUN_RB_BENCH --rb-batch-cnt 1 --rb-sample-rate 1 --prod-affinity 0 --cons-affinity 0 $b)" done header "Ringbuf, multi-producer contention" for b in 1 2 3 4 8 12 16 20 24 28 32 36 40 44 48 52; do - summarize "rb-libbpf nr_prod $b" "$($RUN_BENCH -p$b --rb-batch-cnt 50 rb-libbpf)" + summarize "rb-libbpf nr_prod $b" "$($RUN_RB_BENCH -p$b --rb-batch-cnt 50 rb-libbpf)" done -- cgit v1.2.3 From a05d070a6164bd0578991e42181a52b9c7cf630c Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:52 -0700 Subject: ptp: Clarify ptp_clock_info .adjphase expects an internal servo to be used .adjphase expects a PHC to use an internal servo algorithm to correct the provided phase offset target in the callback. Implementation of the internal servo algorithm are defined by the individual devices. Cc: Jakub Kicinski Cc: Richard Cochran Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- Documentation/driver-api/ptp.rst | 16 ++++++++++++++++ include/linux/ptp_clock_kernel.h | 6 ++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/ptp.rst b/Documentation/driver-api/ptp.rst index 664838ae7776..4552a1f20488 100644 --- a/Documentation/driver-api/ptp.rst +++ b/Documentation/driver-api/ptp.rst @@ -73,6 +73,22 @@ Writing clock drivers class driver, since the lock may also be needed by the clock driver's interrupt service routine. +PTP hardware clock requirements for '.adjphase' +----------------------------------------------- + + The 'struct ptp_clock_info' interface has a '.adjphase' function. + This function has a set of requirements from the PHC in order to be + implemented. + + * The PHC implements a servo algorithm internally that is used to + correct the offset passed in the '.adjphase' call. + * When other PTP adjustment functions are called, the PHC servo + algorithm is disabled. + + **NOTE:** '.adjphase' is not a simple time adjustment functionality + that 'jumps' the PHC clock time based on the provided offset. It + should correct the offset provided using an internal algorithm. + Supported hardware ================== diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h index fdffa6a98d79..f8e8443a8b35 100644 --- a/include/linux/ptp_clock_kernel.h +++ b/include/linux/ptp_clock_kernel.h @@ -77,8 +77,10 @@ struct ptp_system_timestamp { * nominal frequency in parts per million, but with a * 16 bit binary fractional field. * - * @adjphase: Adjusts the phase offset of the hardware clock. - * parameter delta: Desired change in nanoseconds. + * @adjphase: Indicates that the PHC should use an internal servo + * algorithm to correct the provided phase offset. + * parameter delta: PHC servo phase adjustment target + * in nanoseconds. * * @adjtime: Shifts the time of the hardware clock. * parameter delta: Desired change in nanoseconds. -- cgit v1.2.3 From fe3834cd0cf74b06847a1001ac44b7e2c035b5bc Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:53 -0700 Subject: docs: ptp.rst: Add information about NVIDIA Mellanox devices The mlx5_core driver has implemented ptp clock driver functionality but lacked documentation about the PTP devices. This patch adds information about the Mellanox device family. Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- Documentation/driver-api/ptp.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/driver-api/ptp.rst b/Documentation/driver-api/ptp.rst index 4552a1f20488..5e033c3b11b3 100644 --- a/Documentation/driver-api/ptp.rst +++ b/Documentation/driver-api/ptp.rst @@ -122,3 +122,16 @@ Supported hardware - LPF settings (bandwidth, phase limiting, automatic holdover, physical layer assist (per ITU-T G.8273.2)) - Programmable output PTP clocks, any frequency up to 1GHz (to other PHY/MAC time stampers, refclk to ASSPs/SoCs/FPGAs) - Lock to GNSS input, automatic switching between GNSS and user-space PHC control (optional) + + * NVIDIA Mellanox + + - GPIO + - Certain variants of ConnectX-6 Dx and later products support one + GPIO which can time stamp external triggers and one GPIO to produce + periodic signals. + - Certain variants of ConnectX-5 and older products support one GPIO, + configured to either time stamp external triggers or produce + periodic signals. + - PHC instances + - All ConnectX devices have a free-running counter + - ConnectX-6 Dx and later devices have a UTC format counter -- cgit v1.2.3 From 048f6d998eacabed143d6524395573f8868a4f34 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:54 -0700 Subject: testptp: Remove magic numbers related to nanosecond to second conversion Use existing NSEC_PER_SEC declaration in place of hardcoded magic numbers. Cc: Jakub Kicinski Cc: Shuah Khan Cc: Richard Cochran Cc: Maciek Machnikowski Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- tools/testing/selftests/ptp/testptp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c index cfa9562f3cd8..36a1ea3d48af 100644 --- a/tools/testing/selftests/ptp/testptp.c +++ b/tools/testing/selftests/ptp/testptp.c @@ -110,7 +110,7 @@ static long ppb_to_scaled_ppm(int ppb) static int64_t pctns(struct ptp_clock_time *t) { - return t->sec * 1000000000LL + t->nsec; + return t->sec * NSEC_PER_SEC + t->nsec; } static void usage(char *progname) @@ -317,7 +317,7 @@ int main(int argc, char *argv[]) tx.time.tv_usec = adjns; while (tx.time.tv_usec < 0) { tx.time.tv_sec -= 1; - tx.time.tv_usec += 1000000000; + tx.time.tv_usec += NSEC_PER_SEC; } if (clock_adjtime(clkid, &tx) < 0) { -- cgit v1.2.3 From 3a9a9a6139286584d1199f555fa4f96f592a3217 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:55 -0700 Subject: testptp: Add support for testing ptp_clock_info .adjphase callback Invoke clock_adjtime syscall with tx.modes set with ADJ_OFFSET when testptp is invoked with a phase adjustment offset value. Support seconds and nanoseconds for the offset value. Cc: Jakub Kicinski Cc: Shuah Khan Cc: Richard Cochran Cc: Maciek Machnikowski Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- tools/testing/selftests/ptp/testptp.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c index 36a1ea3d48af..cc535f76db99 100644 --- a/tools/testing/selftests/ptp/testptp.c +++ b/tools/testing/selftests/ptp/testptp.c @@ -134,6 +134,7 @@ static void usage(char *progname) " 1 - external time stamp\n" " 2 - periodic output\n" " -n val shift the ptp clock time by 'val' nanoseconds\n" + " -o val phase offset (in nanoseconds) to be provided to the PHC servo\n" " -p val enable output with a period of 'val' nanoseconds\n" " -H val set output phase to 'val' nanoseconds (requires -p)\n" " -w val set output pulse width to 'val' nanoseconds (requires -p)\n" @@ -167,6 +168,7 @@ int main(int argc, char *argv[]) int adjfreq = 0x7fffffff; int adjtime = 0; int adjns = 0; + int adjphase = 0; int capabilities = 0; int extts = 0; int flagtest = 0; @@ -188,7 +190,7 @@ int main(int argc, char *argv[]) progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; - while (EOF != (c = getopt(argc, argv, "cd:e:f:ghH:i:k:lL:n:p:P:sSt:T:w:z"))) { + while (EOF != (c = getopt(argc, argv, "cd:e:f:ghH:i:k:lL:n:o:p:P:sSt:T:w:z"))) { switch (c) { case 'c': capabilities = 1; @@ -228,6 +230,9 @@ int main(int argc, char *argv[]) case 'n': adjns = atoi(optarg); break; + case 'o': + adjphase = atoi(optarg); + break; case 'p': perout = atoll(optarg); break; @@ -327,6 +332,18 @@ int main(int argc, char *argv[]) } } + if (adjphase) { + memset(&tx, 0, sizeof(tx)); + tx.modes = ADJ_OFFSET | ADJ_NANO; + tx.offset = adjphase; + + if (clock_adjtime(clkid, &tx) < 0) { + perror("clock_adjtime"); + } else { + puts("phase adjustment okay"); + } + } + if (gettime) { if (clock_gettime(clkid, &ts)) { perror("clock_gettime"); -- cgit v1.2.3 From c3b60ab7a4dff6e6e608e685b70ddc3d6b2aca81 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:56 -0700 Subject: ptp: Add .getmaxphase callback to ptp_clock_info Enables advertisement of the maximum offset supported by the phase control functionality of PHCs. The callback is used to return an error if an offset not supported by the PHC is used in ADJ_OFFSET. The ioctls PTP_CLOCK_GETCAPS and PTP_CLOCK_GETCAPS2 now advertise the maximum offset a PHC's phase control functionality is capable of supporting. Introduce new sysfs node, max_phase_adjustment. Cc: Jakub Kicinski Cc: Shuah Khan Cc: Richard Cochran Cc: Maciek Machnikowski Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/ptp/ptp_chardev.c | 5 ++++- drivers/ptp/ptp_clock.c | 4 ++++ drivers/ptp/ptp_sysfs.c | 12 ++++++++++++ include/linux/ptp_clock_kernel.h | 5 +++++ include/uapi/linux/ptp_clock.h | 3 ++- tools/testing/selftests/ptp/testptp.c | 6 ++++-- 6 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index af3bc65c4595..362bf756e6b7 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -136,7 +136,10 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) caps.pps = ptp->info->pps; caps.n_pins = ptp->info->n_pins; caps.cross_timestamping = ptp->info->getcrosststamp != NULL; - caps.adjust_phase = ptp->info->adjphase != NULL; + caps.adjust_phase = ptp->info->adjphase != NULL && + ptp->info->getmaxphase != NULL; + if (caps.adjust_phase) + caps.max_phase_adj = ptp->info->getmaxphase(ptp->info); if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) err = -EFAULT; break; diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 790f9250b381..80f74e38c2da 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -135,11 +135,15 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) ptp->dialed_frequency = tx->freq; } else if (tx->modes & ADJ_OFFSET) { if (ops->adjphase) { + s32 max_phase_adj = ops->getmaxphase(ops); s32 offset = tx->offset; if (!(tx->modes & ADJ_NANO)) offset *= NSEC_PER_USEC; + if (offset > max_phase_adj || offset < -max_phase_adj) + return -ERANGE; + err = ops->adjphase(ops, offset); } } else if (tx->modes == 0) { diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c index f30b0a439470..77219cdcd683 100644 --- a/drivers/ptp/ptp_sysfs.c +++ b/drivers/ptp/ptp_sysfs.c @@ -18,6 +18,17 @@ static ssize_t clock_name_show(struct device *dev, } static DEVICE_ATTR_RO(clock_name); +static ssize_t max_phase_adjustment_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + struct ptp_clock *ptp = dev_get_drvdata(dev); + + return snprintf(page, PAGE_SIZE - 1, "%d\n", + ptp->info->getmaxphase(ptp->info)); +} +static DEVICE_ATTR_RO(max_phase_adjustment); + #define PTP_SHOW_INT(name, var) \ static ssize_t var##_show(struct device *dev, \ struct device_attribute *attr, char *page) \ @@ -309,6 +320,7 @@ static struct attribute *ptp_attrs[] = { &dev_attr_clock_name.attr, &dev_attr_max_adjustment.attr, + &dev_attr_max_phase_adjustment.attr, &dev_attr_n_alarms.attr, &dev_attr_n_external_timestamps.attr, &dev_attr_n_periodic_outputs.attr, diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h index f8e8443a8b35..1ef4e0f9bd2a 100644 --- a/include/linux/ptp_clock_kernel.h +++ b/include/linux/ptp_clock_kernel.h @@ -82,6 +82,10 @@ struct ptp_system_timestamp { * parameter delta: PHC servo phase adjustment target * in nanoseconds. * + * @getmaxphase: Advertises maximum offset that can be provided + * to the hardware clock's phase control functionality + * through adjphase. + * * @adjtime: Shifts the time of the hardware clock. * parameter delta: Desired change in nanoseconds. * @@ -171,6 +175,7 @@ struct ptp_clock_info { struct ptp_pin_desc *pin_config; int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm); int (*adjphase)(struct ptp_clock_info *ptp, s32 phase); + s32 (*getmaxphase)(struct ptp_clock_info *ptp); int (*adjtime)(struct ptp_clock_info *ptp, s64 delta); int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts); int (*gettimex64)(struct ptp_clock_info *ptp, struct timespec64 *ts, diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h index 1d108d597f66..05cc35fc94ac 100644 --- a/include/uapi/linux/ptp_clock.h +++ b/include/uapi/linux/ptp_clock.h @@ -95,7 +95,8 @@ struct ptp_clock_caps { int cross_timestamping; /* Whether the clock supports adjust phase */ int adjust_phase; - int rsv[12]; /* Reserved for future use. */ + int max_phase_adj; /* Maximum phase adjustment in nanoseconds. */ + int rsv[11]; /* Reserved for future use. */ }; struct ptp_extts_request { diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c index cc535f76db99..e9438a1862ad 100644 --- a/tools/testing/selftests/ptp/testptp.c +++ b/tools/testing/selftests/ptp/testptp.c @@ -292,7 +292,8 @@ int main(int argc, char *argv[]) " %d pulse per second\n" " %d programmable pins\n" " %d cross timestamping\n" - " %d adjust_phase\n", + " %d adjust_phase\n" + " %d maximum phase adjustment (ns)\n", caps.max_adj, caps.n_alarm, caps.n_ext_ts, @@ -300,7 +301,8 @@ int main(int argc, char *argv[]) caps.pps, caps.n_pins, caps.cross_timestamping, - caps.adjust_phase); + caps.adjust_phase, + caps.max_phase_adj); } } -- cgit v1.2.3 From 67ac72a599d833ff7d9b210186a66d46c13f0a18 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:57 -0700 Subject: net/mlx5: Add .getmaxphase ptp_clock_info callback Implement .getmaxphase callback of ptp_clock_info in mlx5 driver. No longer do a range check in .adjphase callback implementation. Handled by the ptp stack. Cc: Saeed Mahameed Signed-off-by: Rahul Rameshbabu Acked-by: Richard Cochran Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx5/core/lib/clock.c | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c index 932fbc843c69..973babfaff25 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c @@ -93,17 +93,23 @@ static bool mlx5_modify_mtutc_allowed(struct mlx5_core_dev *mdev) return MLX5_CAP_MCAM_FEATURE(mdev, ptpcyc2realtime_modify); } -static bool mlx5_is_mtutc_time_adj_cap(struct mlx5_core_dev *mdev, s64 delta) +static s32 mlx5_ptp_getmaxphase(struct ptp_clock_info *ptp) { - s64 min = MLX5_MTUTC_OPERATION_ADJUST_TIME_MIN; - s64 max = MLX5_MTUTC_OPERATION_ADJUST_TIME_MAX; + struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info); + struct mlx5_core_dev *mdev; - if (MLX5_CAP_MCAM_FEATURE(mdev, mtutc_time_adjustment_extended_range)) { - min = MLX5_MTUTC_OPERATION_ADJUST_TIME_EXTENDED_MIN; - max = MLX5_MTUTC_OPERATION_ADJUST_TIME_EXTENDED_MAX; - } + mdev = container_of(clock, struct mlx5_core_dev, clock); + + return MLX5_CAP_MCAM_FEATURE(mdev, mtutc_time_adjustment_extended_range) ? + MLX5_MTUTC_OPERATION_ADJUST_TIME_EXTENDED_MAX : + MLX5_MTUTC_OPERATION_ADJUST_TIME_MAX; +} + +static bool mlx5_is_mtutc_time_adj_cap(struct mlx5_core_dev *mdev, s64 delta) +{ + s64 max = mlx5_ptp_getmaxphase(&mdev->clock.ptp_info); - if (delta < min || delta > max) + if (delta < -max || delta > max) return false; return true; @@ -351,14 +357,6 @@ static int mlx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) static int mlx5_ptp_adjphase(struct ptp_clock_info *ptp, s32 delta) { - struct mlx5_clock *clock = container_of(ptp, struct mlx5_clock, ptp_info); - struct mlx5_core_dev *mdev; - - mdev = container_of(clock, struct mlx5_core_dev, clock); - - if (!mlx5_is_mtutc_time_adj_cap(mdev, delta)) - return -ERANGE; - return mlx5_ptp_adjtime(ptp, delta); } @@ -734,6 +732,7 @@ static const struct ptp_clock_info mlx5_ptp_clock_info = { .pps = 0, .adjfine = mlx5_ptp_adjfine, .adjphase = mlx5_ptp_adjphase, + .getmaxphase = mlx5_ptp_getmaxphase, .adjtime = mlx5_ptp_adjtime, .gettimex64 = mlx5_ptp_gettimex, .settime64 = mlx5_ptp_settime, -- cgit v1.2.3 From c066e74f34bc464bc1a077a688d7fa31a742d2d5 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:58 -0700 Subject: ptp: ptp_clockmatrix: Add .getmaxphase ptp_clock_info callback Advertise the maximum offset the .adjphase callback is capable of supporting in nanoseconds for IDT ClockMatrix devices. Depend on ptp_clock_adjtime for handling out-of-range offsets. ptp_clock_adjtime returns -ERANGE instead of clamping out-of-range offsets. Cc: Richard Cochran Cc: Vincent Cheng Signed-off-by: Rahul Rameshbabu Signed-off-by: David S. Miller --- drivers/ptp/ptp_clockmatrix.c | 36 +++++++++++++++++------------------- drivers/ptp/ptp_clockmatrix.h | 2 +- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/ptp/ptp_clockmatrix.c b/drivers/ptp/ptp_clockmatrix.c index c9d451bf89e2..f6f9d4adce04 100644 --- a/drivers/ptp/ptp_clockmatrix.c +++ b/drivers/ptp/ptp_clockmatrix.c @@ -1692,14 +1692,23 @@ static int initialize_dco_operating_mode(struct idtcm_channel *channel) /* PTP Hardware Clock interface */ /* - * Maximum absolute value for write phase offset in picoseconds - * - * @channel: channel - * @delta_ns: delta in nanoseconds + * Maximum absolute value for write phase offset in nanoseconds * * Destination signed register is 32-bit register in resolution of 50ps * - * 0x7fffffff * 50 = 2147483647 * 50 = 107374182350 + * 0x7fffffff * 50 = 2147483647 * 50 = 107374182350 ps + * Represent 107374182350 ps as 107374182 ns + */ +static s32 idtcm_getmaxphase(struct ptp_clock_info *ptp __always_unused) +{ + return MAX_ABS_WRITE_PHASE_NANOSECONDS; +} + +/* + * Internal function for implementing support for write phase offset + * + * @channel: channel + * @delta_ns: delta in nanoseconds */ static int _idtcm_adjphase(struct idtcm_channel *channel, s32 delta_ns) { @@ -1708,7 +1717,6 @@ static int _idtcm_adjphase(struct idtcm_channel *channel, s32 delta_ns) u8 i; u8 buf[4] = {0}; s32 phase_50ps; - s64 offset_ps; if (channel->mode != PTP_PLL_MODE_WRITE_PHASE) { err = channel->configure_write_phase(channel); @@ -1716,19 +1724,7 @@ static int _idtcm_adjphase(struct idtcm_channel *channel, s32 delta_ns) return err; } - offset_ps = (s64)delta_ns * 1000; - - /* - * Check for 32-bit signed max * 50: - * - * 0x7fffffff * 50 = 2147483647 * 50 = 107374182350 - */ - if (offset_ps > MAX_ABS_WRITE_PHASE_PICOSECONDS) - offset_ps = MAX_ABS_WRITE_PHASE_PICOSECONDS; - else if (offset_ps < -MAX_ABS_WRITE_PHASE_PICOSECONDS) - offset_ps = -MAX_ABS_WRITE_PHASE_PICOSECONDS; - - phase_50ps = div_s64(offset_ps, 50); + phase_50ps = div_s64((s64)delta_ns * 1000, 50); for (i = 0; i < 4; i++) { buf[i] = phase_50ps & 0xff; @@ -2048,6 +2044,7 @@ static const struct ptp_clock_info idtcm_caps = { .n_ext_ts = MAX_TOD, .n_pins = MAX_REF_CLK, .adjphase = &idtcm_adjphase, + .getmaxphase = &idtcm_getmaxphase, .adjfine = &idtcm_adjfine, .adjtime = &idtcm_adjtime, .gettime64 = &idtcm_gettime, @@ -2064,6 +2061,7 @@ static const struct ptp_clock_info idtcm_caps_deprecated = { .n_ext_ts = MAX_TOD, .n_pins = MAX_REF_CLK, .adjphase = &idtcm_adjphase, + .getmaxphase = &idtcm_getmaxphase, .adjfine = &idtcm_adjfine, .adjtime = &idtcm_adjtime_deprecated, .gettime64 = &idtcm_gettime, diff --git a/drivers/ptp/ptp_clockmatrix.h b/drivers/ptp/ptp_clockmatrix.h index bf1e49409844..7c17c4f7f573 100644 --- a/drivers/ptp/ptp_clockmatrix.h +++ b/drivers/ptp/ptp_clockmatrix.h @@ -18,7 +18,7 @@ #define MAX_PLL (8) #define MAX_REF_CLK (16) -#define MAX_ABS_WRITE_PHASE_PICOSECONDS (107374182350LL) +#define MAX_ABS_WRITE_PHASE_NANOSECONDS (107374182L) #define TOD_MASK_ADDR (0xFFA5) #define DEFAULT_TOD_MASK (0x04) -- cgit v1.2.3 From e156e4d2e43f8b57696ee155f8c3d026419d3363 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:14:59 -0700 Subject: ptp: idt82p33: Add .getmaxphase ptp_clock_info callback Advertise the maximum offset the .adjphase callback is capable of supporting in nanoseconds for IDT devices. Refactor the negation of the offset stored in the register to be after the boundary check of the offset value rather than before. Boundary check based on the intended value rather than its device-specific representation. Depend on ptp_clock_adjtime for handling out-of-range offsets. ptp_clock_adjtime returns -ERANGE instead of clamping out-of-range offsets. Cc: Richard Cochran Cc: Min Li Signed-off-by: Rahul Rameshbabu Signed-off-by: David S. Miller --- drivers/ptp/ptp_idt82p33.c | 18 +++++++++--------- drivers/ptp/ptp_idt82p33.h | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/ptp/ptp_idt82p33.c b/drivers/ptp/ptp_idt82p33.c index afc76c22271a..057190b9cd3d 100644 --- a/drivers/ptp/ptp_idt82p33.c +++ b/drivers/ptp/ptp_idt82p33.c @@ -978,24 +978,23 @@ static int idt82p33_enable(struct ptp_clock_info *ptp, return err; } +static s32 idt82p33_getmaxphase(__always_unused struct ptp_clock_info *ptp) +{ + return WRITE_PHASE_OFFSET_LIMIT; +} + static int idt82p33_adjwritephase(struct ptp_clock_info *ptp, s32 offset_ns) { struct idt82p33_channel *channel = container_of(ptp, struct idt82p33_channel, caps); struct idt82p33 *idt82p33 = channel->idt82p33; - s64 offset_regval, offset_fs; + s64 offset_regval; u8 val[4] = {0}; int err; - offset_fs = (s64)(-offset_ns) * 1000000; - - if (offset_fs > WRITE_PHASE_OFFSET_LIMIT) - offset_fs = WRITE_PHASE_OFFSET_LIMIT; - else if (offset_fs < -WRITE_PHASE_OFFSET_LIMIT) - offset_fs = -WRITE_PHASE_OFFSET_LIMIT; - /* Convert from phaseoffset_fs to register value */ - offset_regval = div_s64(offset_fs * 1000, IDT_T0DPLL_PHASE_RESOL); + offset_regval = div_s64((s64)(-offset_ns) * 1000000000ll, + IDT_T0DPLL_PHASE_RESOL); val[0] = offset_regval & 0xFF; val[1] = (offset_regval >> 8) & 0xFF; @@ -1175,6 +1174,7 @@ static void idt82p33_caps_init(u32 index, struct ptp_clock_info *caps, caps->n_ext_ts = MAX_PHC_PLL, caps->n_pins = max_pins, caps->adjphase = idt82p33_adjwritephase, + caps->getmaxphase = idt82p33_getmaxphase, caps->adjfine = idt82p33_adjfine; caps->adjtime = idt82p33_adjtime; caps->gettime64 = idt82p33_gettime; diff --git a/drivers/ptp/ptp_idt82p33.h b/drivers/ptp/ptp_idt82p33.h index 8fcb0b17d207..6a63c14b6966 100644 --- a/drivers/ptp/ptp_idt82p33.h +++ b/drivers/ptp/ptp_idt82p33.h @@ -43,9 +43,9 @@ #define DEFAULT_OUTPUT_MASK_PLL1 DEFAULT_OUTPUT_MASK_PLL0 /** - * @brief Maximum absolute value for write phase offset in femtoseconds + * @brief Maximum absolute value for write phase offset in nanoseconds */ -#define WRITE_PHASE_OFFSET_LIMIT (20000052084ll) +#define WRITE_PHASE_OFFSET_LIMIT (20000l) /** @brief Phase offset resolution * -- cgit v1.2.3 From d8ee5ca845b4f96cc2e74fb5dd1465c8ea3f5fa3 Mon Sep 17 00:00:00 2001 From: Rahul Rameshbabu Date: Mon, 12 Jun 2023 14:15:00 -0700 Subject: ptp: ocp: Add .getmaxphase ptp_clock_info callback Add a function that advertises a maximum offset of zero supported by ptp_clock_info .adjphase in the OCP null ptp implementation. Cc: Richard Cochran Cc: Jonathan Lemon Cc: Vadim Fedorenko Signed-off-by: Rahul Rameshbabu Acked-by: Vadim Fedorenko Signed-off-by: David S. Miller --- drivers/ptp/ptp_ocp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index ab8cab4d1560..20a974ced8d6 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -1124,6 +1124,12 @@ ptp_ocp_null_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) return -EOPNOTSUPP; } +static s32 +ptp_ocp_null_getmaxphase(struct ptp_clock_info *ptp_info) +{ + return 0; +} + static int ptp_ocp_null_adjphase(struct ptp_clock_info *ptp_info, s32 phase_ns) { @@ -1239,6 +1245,7 @@ static const struct ptp_clock_info ptp_ocp_clock_info = { .adjtime = ptp_ocp_adjtime, .adjfine = ptp_ocp_null_adjfine, .adjphase = ptp_ocp_null_adjphase, + .getmaxphase = ptp_ocp_null_getmaxphase, .enable = ptp_ocp_enable, .verify = ptp_ocp_verify, .pps = true, -- cgit v1.2.3 From 462a3daad679406eed5d31b6bed8a19c236e1352 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Jun 2023 11:29:54 +0200 Subject: net: phy: mediatek: fix compile-test dependencies The new phy driver attempts to select a driver from another subsystem, but that fails when the NVMEM subsystem is disabled: WARNING: unmet direct dependencies detected for NVMEM_MTK_EFUSE Depends on [n]: NVMEM [=n] && (ARCH_MEDIATEK [=n] || COMPILE_TEST [=y]) && HAS_IOMEM [=y] Selected by [y]: - MEDIATEK_GE_SOC_PHY [=y] && NETDEVICES [=y] && PHYLIB [=y] && (ARM64 && ARCH_MEDIATEK [=n] || COMPILE_TEST [=y]) I could not see an actual compile time dependency, so presumably this is only needed for for working correctly but not technically a dependency on that particular nvmem driver implementation, so it would likely be safe to remove the select for compile testing. To keep the spirit of the original 'select', just replace this with a 'depends on' that ensures that the driver will work but does not get in the way of build testing. Fixes: 98c485eaf509b ("net: phy: add driver for MediaTek SoC built-in GE PHYs") Signed-off-by: Arnd Bergmann Reviewed-by: Simon Horman Acked-by: Randy Dunlap Tested-by: Randy Dunlap # build-tested Reviewed-by: Daniel Golle Link: https://lore.kernel.org/r/20230616093009.3511692-1-arnd@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a40269c17597..78e6981650d9 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -239,7 +239,7 @@ config MEDIATEK_GE_PHY config MEDIATEK_GE_SOC_PHY tristate "MediaTek SoC Ethernet PHYs" depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST - select NVMEM_MTK_EFUSE + depends on NVMEM_MTK_EFUSE help Supports MediaTek SoC built-in Gigabit Ethernet PHYs. -- cgit v1.2.3 From b6d972f6898308fbe7e693bf8d44ebfdb1cd2dc4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 16 Jun 2023 12:10:32 +0100 Subject: crypto: af_alg/hash: Fix recvmsg() after sendmsg(MSG_MORE) If an AF_ALG socket bound to a hashing algorithm is sent a zero-length message with MSG_MORE set and then recvmsg() is called without first sending another message without MSG_MORE set to end the operation, an oops will occur because the crypto context and result doesn't now get set up in advance because hash_sendmsg() now defers that as long as possible in the hope that it can use crypto_ahash_digest() - and then because the message is zero-length, it the data wrangling loop is skipped. Fix this by handling zero-length sends at the top of the hash_sendmsg() function. If we're not continuing the previous sendmsg(), then just ignore the send (hash_recvmsg() will invent something when called); if we are continuing, then we finalise the request at this point if MSG_MORE is not set to get any error here, otherwise the send is of no effect and can be ignored. Whilst we're at it, remove the code to create a kvmalloc'd scatterlist if we get more than ALG_MAX_PAGES - this shouldn't happen. Fixes: c662b043cdca ("crypto: af_alg/hash: Support MSG_SPLICE_PAGES") Reported-by: syzbot+13a08c0bf4d212766c3c@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000b928f705fdeb873a@google.com/ Reported-by: syzbot+14234ccf6d0ef629ec1a@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000c047db05fdeb8790@google.com/ Reported-by: syzbot+4e2e47f32607d0f72d43@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000bcca3205fdeb87fb@google.com/ Reported-by: syzbot+472626bb5e7c59fb768f@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000b55d8805fdeb8385@google.com/ Signed-off-by: David Howells Reported-and-tested-by: syzbot+6efc50cc1f8d718d6cb7@syzkaller.appspotmail.com cc: Jens Axboe cc: Matthew Wilcox Acked-by: Herbert Xu Link: https://lore.kernel.org/r/427646.1686913832@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- crypto/algif_hash.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c index dfb048cefb60..0ab43e149f0e 100644 --- a/crypto/algif_hash.c +++ b/crypto/algif_hash.c @@ -76,13 +76,30 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, lock_sock(sk); if (!continuing) { - if ((msg->msg_flags & MSG_MORE)) - hash_free_result(sk, ctx); + /* Discard a previous request that wasn't marked MSG_MORE. */ + hash_free_result(sk, ctx); + if (!msg_data_left(msg)) + goto done; /* Zero-length; don't start new req */ need_init = true; + } else if (!msg_data_left(msg)) { + /* + * No data - finalise the prev req if MSG_MORE so any error + * comes out here. + */ + if (!(msg->msg_flags & MSG_MORE)) { + err = hash_alloc_result(sk, ctx); + if (err) + goto unlock_free; + ahash_request_set_crypt(&ctx->req, NULL, + ctx->result, 0); + err = crypto_wait_req(crypto_ahash_final(&ctx->req), + &ctx->wait); + if (err) + goto unlock_free; + } + goto done_more; } - ctx->more = false; - while (msg_data_left(msg)) { ctx->sgl.sgt.sgl = ctx->sgl.sgl; ctx->sgl.sgt.nents = 0; @@ -93,15 +110,6 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, if (npages == 0) goto unlock_free; - if (npages > ARRAY_SIZE(ctx->sgl.sgl)) { - err = -ENOMEM; - ctx->sgl.sgt.sgl = - kvmalloc(array_size(npages, - sizeof(*ctx->sgl.sgt.sgl)), - GFP_KERNEL); - if (!ctx->sgl.sgt.sgl) - goto unlock_free; - } sg_init_table(ctx->sgl.sgl, npages); ctx->sgl.need_unpin = iov_iter_extract_will_pin(&msg->msg_iter); @@ -150,7 +158,9 @@ static int hash_sendmsg(struct socket *sock, struct msghdr *msg, af_alg_free_sg(&ctx->sgl); } +done_more: ctx->more = msg->msg_flags & MSG_MORE; +done: err = 0; unlock: release_sock(sk); @@ -158,6 +168,8 @@ unlock: unlock_free: af_alg_free_sg(&ctx->sgl); + hash_free_result(sk, ctx); + ctx->more = false; goto unlock; } -- cgit v1.2.3 From 857922b16bb893d26d5ecd83acf9f20cb28eaea2 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 16 Jun 2023 21:18:32 +0200 Subject: net: fec: allow to build without PAGE_POOL_STATS Commit 6970ef27ff7f ("net: fec: add xdp and page pool statistics") selected CONFIG_PAGE_POOL_STATS from the FEC driver symbol, making it impossible to build without the page pool statistics when this driver is enabled. The help text of those statistics mentions increased overhead. Allow the user to choose between usefulness of the statistics and the added overhead. Signed-off-by: Lucas Stach Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230616191832.2944130-1-l.stach@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/Kconfig | 2 +- drivers/net/ethernet/freescale/fec_main.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 1c78f66a89da..75401d2a5fb4 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -29,7 +29,7 @@ config FEC select CRC32 select PHYLIB select PAGE_POOL - select PAGE_POOL_STATS + imply PAGE_POOL_STATS imply NET_SELFTESTS help Say Y here if you want to use the built-in 10/100 Fast ethernet diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 4d37a811ae15..8fbe47703d47 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2789,6 +2789,7 @@ static void fec_enet_get_xdp_stats(struct fec_enet_private *fep, u64 *data) static void fec_enet_page_pool_stats(struct fec_enet_private *fep, u64 *data) { +#ifdef CONFIG_PAGE_POOL_STATS struct page_pool_stats stats = {}; struct fec_enet_priv_rx_q *rxq; int i; @@ -2803,6 +2804,7 @@ static void fec_enet_page_pool_stats(struct fec_enet_private *fep, u64 *data) } page_pool_ethtool_stats_get(data, &stats); +#endif } static void fec_enet_get_ethtool_stats(struct net_device *dev, -- cgit v1.2.3 From 066768b7305b1524d261fdc543d25fd60d955254 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 18 Jun 2023 11:33:55 +0200 Subject: mctp: Reorder fields in 'struct mctp_route' Group some variables based on their sizes to reduce hole and avoid padding. On x86_64, this shrinks the size of 'struct mctp_route' from 72 to 64 bytes. It saves a few bytes of memory and is more cache-line friendly. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Acked-by: Jeremy Kerr Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/393ad1a5aef0aa28d839eeb3d7477da0e0eeb0b0.1687080803.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jakub Kicinski --- include/net/mctp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/mctp.h b/include/net/mctp.h index 82800d521c3d..da86e106c91d 100644 --- a/include/net/mctp.h +++ b/include/net/mctp.h @@ -234,9 +234,9 @@ struct mctp_flow { struct mctp_route { mctp_eid_t min, max; - struct mctp_dev *dev; - unsigned int mtu; unsigned char type; + unsigned int mtu; + struct mctp_dev *dev; int (*output)(struct mctp_route *route, struct sk_buff *skb); -- cgit v1.2.3 From 92b08290859b09a2ead2dc553aaaadb015748536 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 18 Jun 2023 11:46:46 +0200 Subject: mptcp: Reorder fields in 'struct mptcp_pm_add_entry' Group some variables based on their sizes to reduce hole and avoid padding. On x86_64, this shrinks the size of 'struct mptcp_pm_add_entry' from 136 to 128 bytes. It saves a few bytes of memory and is more cache-line friendly. Signed-off-by: Christophe JAILLET Reviewed-by: Matthieu Baerts Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/e47b71de54fd3e580544be56fc1bb2985c77b0f4.1687081558.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jakub Kicinski --- net/mptcp/pm_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index a12a87b780f6..a56718ffdd02 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -25,9 +25,9 @@ static int pm_nl_pernet_id; struct mptcp_pm_add_entry { struct list_head list; struct mptcp_addr_info addr; + u8 retrans_times; struct timer_list add_timer; struct mptcp_sock *sock; - u8 retrans_times; }; struct pm_nl_pernet { -- cgit v1.2.3 From f0d952646bcf186d6d1bea6ec89f96b7e57f3b83 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 18 Jun 2023 12:16:41 +0200 Subject: netlabel: Reorder fields in 'struct netlbl_domaddr6_map' Group some variables based on their sizes to reduce hole and avoid padding. On x86_64, this shrinks the size of 'struct netlbl_domaddr6_map' from 72 to 64 bytes. It saves a few bytes of memory and is more cache-line friendly. Signed-off-by: Christophe JAILLET Reviewed-by: Simon Horman Reviewed-by: Jiri Pirko Acked-by: Paul Moore Link: https://lore.kernel.org/r/aa109847260e51e174c823b6d1441f75be370f01.1687083361.git.christophe.jaillet@wanadoo.fr Signed-off-by: Jakub Kicinski --- net/netlabel/netlabel_domainhash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h index 9f80972ae39b..7eaa35fdd9bd 100644 --- a/net/netlabel/netlabel_domainhash.h +++ b/net/netlabel/netlabel_domainhash.h @@ -57,8 +57,8 @@ struct netlbl_domaddr6_map { struct netlbl_dom_map { char *domain; - u16 family; struct netlbl_dommap_def def; + u16 family; u32 valid; struct list_head list; -- cgit v1.2.3 From 365eb32e4b456064aea4db61adc0a65b8a09bc80 Mon Sep 17 00:00:00 2001 From: Ratheesh Kannoth Date: Mon, 19 Jun 2023 11:36:38 +0530 Subject: octeontx2-pf: TC flower offload support for rxqueue mapping TC rule support to offload rx queue mapping rules. Eg: tc filter add dev eth2 ingress protocol ip flower \ dst_ip 192.168.8.100 \ action skbedit queue_mapping 4 skip_sw action mirred ingress redirect dev eth5 Packets destined to 192.168.8.100 will be forwarded to rx queue 4 of eth5 interface. tc filter add dev eth2 ingress protocol ip flower \ dst_ip 192.168.8.100 \ action skbedit queue_mapping 9 skip_sw Packets destined to 192.168.8.100 will be forwarded to rx queue 4 of eth2 interface. Signed-off-by: Ratheesh Kannoth Link: https://lore.kernel.org/r/20230619060638.1032304-1-rkannoth@marvell.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c index 231c3f0efb60..8a13df592af6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c @@ -396,8 +396,12 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, return -EOPNOTSUPP; } req->vf = priv->pcifunc & RVU_PFVF_FUNC_MASK; - req->op = NIX_RX_ACTION_DEFAULT; - return 0; + + /* if op is already set; avoid overwriting the same */ + if (!req->op) + req->op = NIX_RX_ACTION_DEFAULT; + break; + case FLOW_ACTION_VLAN_POP: req->vtag0_valid = true; /* use RX_VTAG_TYPE7 which is initialized to strip vlan tag */ @@ -433,6 +437,12 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, case FLOW_ACTION_MARK: mark = act->mark; break; + + case FLOW_ACTION_RX_QUEUE_MAPPING: + req->op = NIX_RX_ACTIONOP_UCAST; + req->index = act->rx_queue; + break; + default: return -EOPNOTSUPP; } -- cgit v1.2.3 From 3a4f0edbb7939a16abb54668642ceed1decdbf4a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 19 Jun 2023 07:27:40 +0000 Subject: ipv6: fix a typo in ip6mr_sk_ioctl() SIOCGETSGCNT_IN6 uses a "struct sioc_sg_req6 buffer". Unfortunately the blamed commit made hard to ensure type safety. syzbot reported: BUG: KASAN: stack-out-of-bounds in ip6mr_ioctl+0xba3/0xcb0 net/ipv6/ip6mr.c:1917 Read of size 16 at addr ffffc900039afb68 by task syz-executor937/5008 CPU: 1 PID: 5008 Comm: syz-executor937 Not tainted 6.4.0-rc6-syzkaller-01304-gc08afcdcf952 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/27/2023 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xd9/0x150 lib/dump_stack.c:106 print_address_description.constprop.0+0x2c/0x3c0 mm/kasan/report.c:351 print_report mm/kasan/report.c:462 [inline] kasan_report+0x11c/0x130 mm/kasan/report.c:572 ip6mr_ioctl+0xba3/0xcb0 net/ipv6/ip6mr.c:1917 rawv6_ioctl+0x4e/0x1e0 net/ipv6/raw.c:1143 sock_ioctl_out net/core/sock.c:4186 [inline] sk_ioctl+0x151/0x440 net/core/sock.c:4214 inet6_ioctl+0x1b8/0x290 net/ipv6/af_inet6.c:582 sock_do_ioctl+0xcc/0x230 net/socket.c:1189 sock_ioctl+0x1f8/0x680 net/socket.c:1306 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x197/0x210 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f255849bad9 Code: 28 c3 e8 2a 14 00 00 66 2e 0f 1f 84 00 00 00 00 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 c0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffd06792778 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f255849bad9 RDX: 0000000000000000 RSI: 00000000000089e1 RDI: 0000000000000003 RBP: 00007f255845fc80 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f255845fd10 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 The buggy address belongs to stack of task syz-executor937/5008 and is located at offset 40 in frame: sk_ioctl+0x0/0x440 net/core/sock.c:4172 This frame has 2 objects: [32, 36) 'karg' [48, 88) 'buffer' Fixes: e1d001fa5b47 ("net: ioctl: Use kernel memory on protocol ioctl callbacks") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Cc: David Ahern Cc: Kuniyuki Iwashima Reviewed-by: Breno Leitao Link: https://lore.kernel.org/r/20230619072740.464528-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/linux/mroute6.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index 2f95d5b4e47a..63ef5191cc57 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -109,13 +109,13 @@ static inline int ip6mr_sk_ioctl(struct sock *sk, unsigned int cmd, struct sioc_mif_req6 buffer; return sock_ioctl_inout(sk, cmd, arg, &buffer, - sizeof(buffer)); + sizeof(buffer)); } case SIOCGETSGCNT_IN6: { - struct sioc_mif_req6 buffer; + struct sioc_sg_req6 buffer; return sock_ioctl_inout(sk, cmd, arg, &buffer, - sizeof(buffer)); + sizeof(buffer)); } } -- cgit v1.2.3 From 634236b34d7a8c9e11c12b0746b83b8942fc8f2e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 19 Jun 2023 12:43:35 +0000 Subject: net: remove sk_is_ipmr() and sk_is_icmpv6() helpers Blamed commit added these helpers for sake of detecting RAW sockets specific ioctl. syzbot complained about it [1]. Issue here is that RAW sockets could pretend there was no need to call ipmr_sk_ioctl() Regardless of inet_sk(sk)->inet_num, we must be prepared for ipmr_ioctl() being called later. This must happen from ipmr_sk_ioctl() context only. We could add a safety check in ipmr_ioctl() at the risk of breaking applications. Instead, remove sk_is_ipmr() and sk_is_icmpv6() because their name would be misleading, once we change their implementation. [1] BUG: KASAN: stack-out-of-bounds in ipmr_ioctl+0xb12/0xbd0 net/ipv4/ipmr.c:1654 Read of size 4 at addr ffffc90003aefae4 by task syz-executor105/5004 CPU: 0 PID: 5004 Comm: syz-executor105 Not tainted 6.4.0-rc6-syzkaller-01304-gc08afcdcf952 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/27/2023 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xd9/0x150 lib/dump_stack.c:106 print_address_description.constprop.0+0x2c/0x3c0 mm/kasan/report.c:351 print_report mm/kasan/report.c:462 [inline] kasan_report+0x11c/0x130 mm/kasan/report.c:572 ipmr_ioctl+0xb12/0xbd0 net/ipv4/ipmr.c:1654 raw_ioctl+0x4e/0x1e0 net/ipv4/raw.c:881 sock_ioctl_out net/core/sock.c:4186 [inline] sk_ioctl+0x151/0x440 net/core/sock.c:4214 inet_ioctl+0x18c/0x380 net/ipv4/af_inet.c:1001 sock_do_ioctl+0xcc/0x230 net/socket.c:1189 sock_ioctl+0x1f8/0x680 net/socket.c:1306 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x197/0x210 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f2944bf6ad9 Code: 28 c3 e8 2a 14 00 00 66 2e 0f 1f 84 00 00 00 00 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 c0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffd8897a028 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f2944bf6ad9 RDX: 0000000000000000 RSI: 00000000000089e1 RDI: 0000000000000003 RBP: 00007f2944bbac80 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f2944bbad10 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 The buggy address belongs to stack of task syz-executor105/5004 and is located at offset 36 in frame: sk_ioctl+0x0/0x440 net/core/sock.c:4172 This frame has 2 objects: [32, 36) 'karg' [48, 88) 'buffer' Fixes: e1d001fa5b47 ("net: ioctl: Use kernel memory on protocol ioctl callbacks") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Breno Leitao Cc: Kuniyuki Iwashima Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Reviewed-by: Willem de Bruijn Link: https://lore.kernel.org/r/20230619124336.651528-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- include/linux/icmpv6.h | 6 ------ include/linux/mroute.h | 11 ----------- net/core/sock.c | 4 ++-- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 1fe33e6741cc..db0f4fcfdaf4 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -111,10 +111,4 @@ static inline bool icmpv6_is_err(int type) return false; } -static inline int sk_is_icmpv6(struct sock *sk) -{ - return sk->sk_family == AF_INET6 && - inet_sk(sk)->inet_num == IPPROTO_ICMPV6; -} - #endif diff --git a/include/linux/mroute.h b/include/linux/mroute.h index 94c6e6f549f0..4c5003afee6c 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -16,12 +16,6 @@ static inline int ip_mroute_opt(int opt) return opt >= MRT_BASE && opt <= MRT_MAX; } -static inline int sk_is_ipmr(struct sock *sk) -{ - return sk->sk_family == AF_INET && - inet_sk(sk)->inet_num == IPPROTO_IGMP; -} - int ip_mroute_setsockopt(struct sock *, int, sockptr_t, unsigned int); int ip_mroute_getsockopt(struct sock *, int, sockptr_t, sockptr_t); int ipmr_ioctl(struct sock *sk, int cmd, void *arg); @@ -57,11 +51,6 @@ static inline int ip_mroute_opt(int opt) return 0; } -static inline int sk_is_ipmr(struct sock *sk) -{ - return 0; -} - static inline bool ipmr_rule_default(const struct fib_rule *rule) { return true; diff --git a/net/core/sock.c b/net/core/sock.c index cff3e82514d1..8ec8f4c9911f 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -4199,9 +4199,9 @@ int sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) { int rc = 1; - if (sk_is_ipmr(sk)) + if (sk->sk_type == SOCK_RAW && sk->sk_family == AF_INET) rc = ipmr_sk_ioctl(sk, cmd, arg); - else if (sk_is_icmpv6(sk)) + else if (sk->sk_type == SOCK_RAW && sk->sk_family == AF_INET6) rc = ip6mr_sk_ioctl(sk, cmd, arg); else if (sk_is_phonet(sk)) rc = phonet_sk_ioctl(sk, cmd, arg); -- cgit v1.2.3 From b7c31ccd60d1df4634670e3eb9902baa19b9517b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 20 Jun 2023 00:03:32 +0200 Subject: net: phy-c45: Fix genphy_c45_ethtool_set_eee description The text has been cut/paste from genphy_c45_ethtool_get_eee but not changed to reflect it performs set. Additionally, extend the comment. This function implements the logic that eee_enabled has global control over EEE. When eee_enabled is false, no link modes will be advertised, and as a result, the MAC should not transmit LPI. Signed-off-by: Andrew Lunn Link: https://lore.kernel.org/r/20230619220332.4038924-1-andrew@lunn.ch Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy-c45.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index fee514b96ab1..93ed07223377 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1425,12 +1425,15 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev, EXPORT_SYMBOL(genphy_c45_ethtool_get_eee); /** - * genphy_c45_ethtool_set_eee - get EEE supported and status + * genphy_c45_ethtool_set_eee - set EEE supported and status * @phydev: target phy_device struct * @data: ethtool_eee data * - * Description: it reportes the Supported/Advertisement/LP Advertisement - * capabilities. + * Description: sets the Supported/Advertisement/LP Advertisement + * capabilities. If eee_enabled is false, no links modes are + * advertised, but the previously advertised link modes are + * retained. This allows EEE to be enabled/disabled in a + * non-destructive way. */ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) -- cgit v1.2.3 From 40cba83370c2c97fd970cb0e273e76f99f0f2db6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 19 Jun 2023 11:12:09 +0200 Subject: sfc: add CONFIG_INET dependency for TC offload The driver now fails to link when CONFIG_INET is disabled, so add an explicit Kconfig dependency: ld.lld: error: undefined symbol: ip_route_output_flow >>> referenced by tc_encap_actions.c >>> drivers/net/ethernet/sfc/tc_encap_actions.o:(efx_tc_flower_create_encap_md) in archive vmlinux.a ld.lld: error: undefined symbol: ip_send_check >>> referenced by tc_encap_actions.c >>> drivers/net/ethernet/sfc/tc_encap_actions.o:(efx_gen_encap_header) in archive vmlinux.a >>> referenced by tc_encap_actions.c >>> drivers/net/ethernet/sfc/tc_encap_actions.o:(efx_gen_encap_header) in archive vmlinux.a ld.lld: error: undefined symbol: arp_tbl >>> referenced by tc_encap_actions.c >>> drivers/net/ethernet/sfc/tc_encap_actions.o:(efx_tc_netevent_event) in archive vmlinux.a >>> referenced by tc_encap_actions.c >>> drivers/net/ethernet/sfc/tc_encap_actions.o:(efx_tc_netevent_event) in archive vmlinux.a Fixes: a1e82162af0b8 ("sfc: generate encap headers for TC offload") Reviewed-by: Edward Cree Reviewed-by: Simon Horman Closes: https://lore.kernel.org/oe-kbuild-all/202306151656.yttECVTP-lkp@intel.com/ Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230619091215.2731541-1-arnd@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig index 4af36ba8906b..3eb55dcfa8a6 100644 --- a/drivers/net/ethernet/sfc/Kconfig +++ b/drivers/net/ethernet/sfc/Kconfig @@ -50,6 +50,7 @@ config SFC_MCDI_MON config SFC_SRIOV bool "Solarflare SFC9100-family SR-IOV support" depends on SFC && PCI_IOV + depends on INET default y help This enables support for the Single Root I/O Virtualization -- cgit v1.2.3 From f61d2d5cf142436cd1a02ddc78425e91116b8b0d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 19 Jun 2023 11:12:10 +0200 Subject: sfc: fix uninitialized variable use The new efx_bind_neigh() function contains a broken code path when IPV6 is disabled: drivers/net/ethernet/sfc/tc_encap_actions.c:144:7: error: variable 'n' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized] if (encap->type & EFX_ENCAP_FLAG_IPV6) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/ethernet/sfc/tc_encap_actions.c:184:8: note: uninitialized use occurs here if (!n) { ^ drivers/net/ethernet/sfc/tc_encap_actions.c:144:3: note: remove the 'if' if its condition is always false if (encap->type & EFX_ENCAP_FLAG_IPV6) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/net/ethernet/sfc/tc_encap_actions.c:141:22: note: initialize the variable 'n' to silence this warning struct neighbour *n; ^ = NULL Change it to use the existing error handling path here. Fixes: 7e5e7d800011a ("sfc: neighbour lookup for TC encap action offload") Suggested-by: Edward Cree Signed-off-by: Arnd Bergmann Reviewed-by: Edward Cree Link: https://lore.kernel.org/r/20230619091215.2731541-2-arnd@kernel.org Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/tc_encap_actions.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c index aac259528e73..7e8bcdb222ad 100644 --- a/drivers/net/ethernet/sfc/tc_encap_actions.c +++ b/drivers/net/ethernet/sfc/tc_encap_actions.c @@ -164,6 +164,7 @@ static int efx_bind_neigh(struct efx_nic *efx, */ rc = -EOPNOTSUPP; NL_SET_ERR_MSG_MOD(extack, "No IPv6 support (neigh bind)"); + goto out_free; #endif } else { rt = ip_route_output_key(net, &flow4); -- cgit v1.2.3 From 9fc68f23a6d3729ccbeb6ca7da6de0bc399f9ddb Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:49 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: shrink clock code with devres We can use a devm action to completely drop the remove callback and use stmmac_pltfr_remove() directly for remove. We can also drop one of the goto labels. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andrew Halaney Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index c801838fae2a..2da0738eed24 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -586,6 +586,11 @@ static int ethqos_clks_config(void *priv, bool enabled) return ret; } +static void ethqos_clks_disable(void *data) +{ + ethqos_clks_config(data, false); +} + static int qcom_ethqos_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -636,6 +641,10 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (ret) goto err_mem; + ret = devm_add_action_or_reset(&pdev->dev, ethqos_clks_disable, ethqos); + if (ret) + goto err_mem; + ethqos->speed = SPEED_1000; ethqos_update_rgmii_clk(ethqos, SPEED_1000); ethqos_set_func_clk_en(ethqos); @@ -653,27 +662,16 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) - goto err_clk; + goto err_mem; return ret; -err_clk: - ethqos_clks_config(ethqos, false); - err_mem: stmmac_remove_config_dt(pdev, plat_dat); return ret; } -static void qcom_ethqos_remove(struct platform_device *pdev) -{ - struct qcom_ethqos *ethqos = get_stmmac_bsp_priv(&pdev->dev); - - stmmac_pltfr_remove(pdev); - ethqos_clks_config(ethqos, false); -} - static const struct of_device_id qcom_ethqos_match[] = { { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data}, { .compatible = "qcom,sc8280xp-ethqos", .data = &emac_v3_0_0_data}, @@ -684,7 +682,7 @@ MODULE_DEVICE_TABLE(of, qcom_ethqos_match); static struct platform_driver qcom_ethqos_driver = { .probe = qcom_ethqos_probe, - .remove_new = qcom_ethqos_remove, + .remove_new = stmmac_pltfr_remove, .driver = { .name = "qcom-ethqos", .pm = &stmmac_pltfr_pm_ops, -- cgit v1.2.3 From 9bc580609139cfc1f559cdc4bfb2f4862b38503d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:50 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: rename a label in probe() The err_mem label's name is unclear. It actually should be reached on any error after stmmac_probe_config_dt() succeeds. Name it after the cleanup action that needs to be called before exiting. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andrew Halaney Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 2da0738eed24..16e856861558 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -615,14 +615,14 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos = devm_kzalloc(&pdev->dev, sizeof(*ethqos), GFP_KERNEL); if (!ethqos) { ret = -ENOMEM; - goto err_mem; + goto out_config_dt; } ethqos->pdev = pdev; ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii"); if (IS_ERR(ethqos->rgmii_base)) { ret = PTR_ERR(ethqos->rgmii_base); - goto err_mem; + goto out_config_dt; } data = of_device_get_match_data(&pdev->dev); @@ -634,16 +634,16 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->rgmii_clk = devm_clk_get(&pdev->dev, "rgmii"); if (IS_ERR(ethqos->rgmii_clk)) { ret = PTR_ERR(ethqos->rgmii_clk); - goto err_mem; + goto out_config_dt; } ret = ethqos_clks_config(ethqos, true); if (ret) - goto err_mem; + goto out_config_dt; ret = devm_add_action_or_reset(&pdev->dev, ethqos_clks_disable, ethqos); if (ret) - goto err_mem; + goto out_config_dt; ethqos->speed = SPEED_1000; ethqos_update_rgmii_clk(ethqos, SPEED_1000); @@ -662,11 +662,11 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) - goto err_mem; + goto out_config_dt; return ret; -err_mem: +out_config_dt: stmmac_remove_config_dt(pdev, plat_dat); return ret; -- cgit v1.2.3 From 7b5e64a9382528d5e3db0fe714b03090a4b1433b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:51 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: tweak the order of local variables Make sure we follow the reverse-xmas tree convention. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andrew Halaney Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 16e856861558..28d2514a8795 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -594,9 +594,9 @@ static void ethqos_clks_disable(void *data) static int qcom_ethqos_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + const struct ethqos_emac_driver_data *data; struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; - const struct ethqos_emac_driver_data *data; struct qcom_ethqos *ethqos; int ret; -- cgit v1.2.3 From 302555a0ae3362b38eddd1df9b8d4b176050fc92 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:52 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: use a helper variable for &pdev->dev Shrink code and avoid line breaks by using a helper variable for &pdev->dev. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andrew Halaney Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 49 ++++++++++++---------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 28d2514a8795..f0776ddea3ab 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -123,25 +123,26 @@ static void rgmii_updatel(struct qcom_ethqos *ethqos, static void rgmii_dump(void *priv) { struct qcom_ethqos *ethqos = priv; + struct device *dev = ðqos->pdev->dev; - dev_dbg(ðqos->pdev->dev, "Rgmii register dump\n"); - dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_CONFIG: %x\n", + dev_dbg(dev, "Rgmii register dump\n"); + dev_dbg(dev, "RGMII_IO_MACRO_CONFIG: %x\n", rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG)); - dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DLL_CONFIG: %x\n", + dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG: %x\n", rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG)); - dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DDR_CONFIG: %x\n", + dev_dbg(dev, "SDCC_HC_REG_DDR_CONFIG: %x\n", rgmii_readl(ethqos, SDCC_HC_REG_DDR_CONFIG)); - dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DLL_CONFIG2: %x\n", + dev_dbg(dev, "SDCC_HC_REG_DLL_CONFIG2: %x\n", rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG2)); - dev_dbg(ðqos->pdev->dev, "SDC4_STATUS: %x\n", + dev_dbg(dev, "SDC4_STATUS: %x\n", rgmii_readl(ethqos, SDC4_STATUS)); - dev_dbg(ðqos->pdev->dev, "SDCC_USR_CTL: %x\n", + dev_dbg(dev, "SDCC_USR_CTL: %x\n", rgmii_readl(ethqos, SDCC_USR_CTL)); - dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_CONFIG2: %x\n", + dev_dbg(dev, "RGMII_IO_MACRO_CONFIG2: %x\n", rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG2)); - dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_DEBUG1: %x\n", + dev_dbg(dev, "RGMII_IO_MACRO_DEBUG1: %x\n", rgmii_readl(ethqos, RGMII_IO_MACRO_DEBUG1)); - dev_dbg(ðqos->pdev->dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %x\n", + dev_dbg(dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %x\n", rgmii_readl(ethqos, EMAC_SYSTEM_LOW_POWER_DEBUG)); } @@ -242,6 +243,7 @@ static const struct ethqos_emac_driver_data emac_v3_0_0_data = { static int ethqos_dll_configure(struct qcom_ethqos *ethqos) { + struct device *dev = ðqos->pdev->dev; unsigned int val; int retry = 1000; @@ -279,7 +281,7 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) retry--; } while (retry > 0); if (!retry) - dev_err(ðqos->pdev->dev, "Clear CK_OUT_EN timedout\n"); + dev_err(dev, "Clear CK_OUT_EN timedout\n"); /* Set CK_OUT_EN */ rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, @@ -296,7 +298,7 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) retry--; } while (retry > 0); if (!retry) - dev_err(ðqos->pdev->dev, "Set CK_OUT_EN timedout\n"); + dev_err(dev, "Set CK_OUT_EN timedout\n"); /* Set DDR_CAL_EN */ rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, @@ -322,12 +324,13 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) { + struct device *dev = ðqos->pdev->dev; int phase_shift; int phy_mode; int loopback; /* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */ - phy_mode = device_get_phy_mode(ðqos->pdev->dev); + phy_mode = device_get_phy_mode(dev); if (phy_mode == PHY_INTERFACE_MODE_RGMII_ID || phy_mode == PHY_INTERFACE_MODE_RGMII_TXID) phase_shift = 0; @@ -468,8 +471,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) loopback, RGMII_IO_MACRO_CONFIG); break; default: - dev_err(ðqos->pdev->dev, - "Invalid speed %d\n", ethqos->speed); + dev_err(dev, "Invalid speed %d\n", ethqos->speed); return -EINVAL; } @@ -478,6 +480,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) static int ethqos_configure(struct qcom_ethqos *ethqos) { + struct device *dev = ðqos->pdev->dev; volatile unsigned int dll_lock; unsigned int i, retry = 1000; @@ -540,8 +543,7 @@ static int ethqos_configure(struct qcom_ethqos *ethqos) retry--; } while (retry > 0); if (!retry) - dev_err(ðqos->pdev->dev, - "Timeout while waiting for DLL lock\n"); + dev_err(dev, "Timeout while waiting for DLL lock\n"); } if (ethqos->speed == SPEED_1000) @@ -597,6 +599,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) const struct ethqos_emac_driver_data *data; struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; + struct device *dev = &pdev->dev; struct qcom_ethqos *ethqos; int ret; @@ -606,13 +609,13 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); if (IS_ERR(plat_dat)) { - dev_err(&pdev->dev, "dt configuration failed\n"); + dev_err(dev, "dt configuration failed\n"); return PTR_ERR(plat_dat); } plat_dat->clks_config = ethqos_clks_config; - ethqos = devm_kzalloc(&pdev->dev, sizeof(*ethqos), GFP_KERNEL); + ethqos = devm_kzalloc(dev, sizeof(*ethqos), GFP_KERNEL); if (!ethqos) { ret = -ENOMEM; goto out_config_dt; @@ -625,13 +628,13 @@ static int qcom_ethqos_probe(struct platform_device *pdev) goto out_config_dt; } - data = of_device_get_match_data(&pdev->dev); + data = of_device_get_match_data(dev); ethqos->por = data->por; ethqos->num_por = data->num_por; ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en; ethqos->has_emac3 = data->has_emac3; - ethqos->rgmii_clk = devm_clk_get(&pdev->dev, "rgmii"); + ethqos->rgmii_clk = devm_clk_get(dev, "rgmii"); if (IS_ERR(ethqos->rgmii_clk)) { ret = PTR_ERR(ethqos->rgmii_clk); goto out_config_dt; @@ -641,7 +644,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (ret) goto out_config_dt; - ret = devm_add_action_or_reset(&pdev->dev, ethqos_clks_disable, ethqos); + ret = devm_add_action_or_reset(dev, ethqos_clks_disable, ethqos); if (ret) goto out_config_dt; @@ -660,7 +663,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) plat_dat->rx_clk_runs_in_lpi = 1; - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + ret = stmmac_dvr_probe(dev, plat_dat, &stmmac_res); if (ret) goto out_config_dt; -- cgit v1.2.3 From ee8dacca2fd3ff437b787f83fb569197a89894fd Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:53 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: add missing include device_get_phy_mode() is declared in linux/property.h but this header is not included. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andrew Halaney Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index f0776ddea3ab..b66d64d138cb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "stmmac.h" #include "stmmac_platform.h" -- cgit v1.2.3 From 97f73bc59e1620c70635be68ab7ee91779bdf03e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:54 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: add a newline between headers Typically we use a newline between global and local headers so add it here as well. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andrew Halaney Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index b66d64d138cb..e3a9b785334d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -7,6 +7,7 @@ #include #include #include + #include "stmmac.h" #include "stmmac_platform.h" -- cgit v1.2.3 From f2b1758554eb026939407ed03e38dd5d43978cb4 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:55 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: remove stray space There's an unnecessary space in the rgmii_updatel() function, remove it. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andrew Halaney Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index e3a9b785334d..ec3bbd199501 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -117,7 +117,7 @@ static void rgmii_updatel(struct qcom_ethqos *ethqos, { unsigned int temp; - temp = rgmii_readl(ethqos, offset); + temp = rgmii_readl(ethqos, offset); temp = (temp & ~(mask)) | val; rgmii_writel(ethqos, temp, offset); } -- cgit v1.2.3 From 0dec3b48aa4edb653ba8ed8a62970bc0698f5bc1 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:56 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: add support for the optional serdes phy On sa8775p platforms, there's a SGMII SerDes PHY between the MAC and external PHY that we need to enable and configure. Signed-off-by: Bartosz Golaszewski Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index ec3bbd199501..042733b5e80b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "stmmac.h" @@ -93,6 +94,7 @@ struct qcom_ethqos { unsigned int rgmii_clk_rate; struct clk *rgmii_clk; + struct phy *serdes_phy; unsigned int speed; const struct ethqos_emac_por *por; @@ -565,6 +567,30 @@ static void ethqos_fix_mac_speed(void *priv, unsigned int speed) ethqos_configure(ethqos); } +static int qcom_ethqos_serdes_powerup(struct net_device *ndev, void *priv) +{ + struct qcom_ethqos *ethqos = priv; + int ret; + + ret = phy_init(ethqos->serdes_phy); + if (ret) + return ret; + + ret = phy_power_on(ethqos->serdes_phy); + if (ret) + return ret; + + return phy_set_speed(ethqos->serdes_phy, ethqos->speed); +} + +static void qcom_ethqos_serdes_powerdown(struct net_device *ndev, void *priv) +{ + struct qcom_ethqos *ethqos = priv; + + phy_power_off(ethqos->serdes_phy); + phy_exit(ethqos->serdes_phy); +} + static int ethqos_clks_config(void *priv, bool enabled) { struct qcom_ethqos *ethqos = priv; @@ -650,6 +676,12 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (ret) goto out_config_dt; + ethqos->serdes_phy = devm_phy_optional_get(dev, "serdes"); + if (IS_ERR(ethqos->serdes_phy)) { + ret = PTR_ERR(ethqos->serdes_phy); + goto out_config_dt; + } + ethqos->speed = SPEED_1000; ethqos_update_rgmii_clk(ethqos, SPEED_1000); ethqos_set_func_clk_en(ethqos); @@ -665,6 +697,11 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) plat_dat->rx_clk_runs_in_lpi = 1; + if (ethqos->serdes_phy) { + plat_dat->serdes_powerup = qcom_ethqos_serdes_powerup; + plat_dat->serdes_powerdown = qcom_ethqos_serdes_powerdown; + } + ret = stmmac_dvr_probe(dev, plat_dat, &stmmac_res); if (ret) goto out_config_dt; -- cgit v1.2.3 From feeb27165c46c1956c9ee002d306a2ed196fa5f0 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:57 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: add support for the phyaux clock On sa8775p, the EMAC revision is 4 and we use SGMII instead of RGMII. There's no "rgmii" clock but there's a fourth clock under a different name: "phyaux". Add a new field to the chip data struct that specifies the link clock name. Default to "rgmii" for backward compatibility. Signed-off-by: Bartosz Golaszewski Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 042733b5e80b..a739e1d5c046 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -85,6 +85,7 @@ struct ethqos_emac_driver_data { unsigned int num_por; bool rgmii_config_loopback_en; bool has_emac3; + const char *link_clk_name; struct dwmac4_addrs dwmac4_addrs; }; @@ -92,8 +93,8 @@ struct qcom_ethqos { struct platform_device *pdev; void __iomem *rgmii_base; - unsigned int rgmii_clk_rate; - struct clk *rgmii_clk; + unsigned int link_clk_rate; + struct clk *link_clk; struct phy *serdes_phy; unsigned int speed; @@ -156,23 +157,23 @@ static void rgmii_dump(void *priv) #define RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ (5 * 1000 * 1000UL) static void -ethqos_update_rgmii_clk(struct qcom_ethqos *ethqos, unsigned int speed) +ethqos_update_link_clk(struct qcom_ethqos *ethqos, unsigned int speed) { switch (speed) { case SPEED_1000: - ethqos->rgmii_clk_rate = RGMII_1000_NOM_CLK_FREQ; + ethqos->link_clk_rate = RGMII_1000_NOM_CLK_FREQ; break; case SPEED_100: - ethqos->rgmii_clk_rate = RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ; + ethqos->link_clk_rate = RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ; break; case SPEED_10: - ethqos->rgmii_clk_rate = RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ; + ethqos->link_clk_rate = RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ; break; } - clk_set_rate(ethqos->rgmii_clk, ethqos->rgmii_clk_rate); + clk_set_rate(ethqos->link_clk, ethqos->link_clk_rate); } static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos) @@ -563,7 +564,7 @@ static void ethqos_fix_mac_speed(void *priv, unsigned int speed) struct qcom_ethqos *ethqos = priv; ethqos->speed = speed; - ethqos_update_rgmii_clk(ethqos, speed); + ethqos_update_link_clk(ethqos, speed); ethqos_configure(ethqos); } @@ -597,9 +598,9 @@ static int ethqos_clks_config(void *priv, bool enabled) int ret = 0; if (enabled) { - ret = clk_prepare_enable(ethqos->rgmii_clk); + ret = clk_prepare_enable(ethqos->link_clk); if (ret) { - dev_err(ðqos->pdev->dev, "rgmii_clk enable failed\n"); + dev_err(ðqos->pdev->dev, "link_clk enable failed\n"); return ret; } @@ -610,7 +611,7 @@ static int ethqos_clks_config(void *priv, bool enabled) */ ethqos_set_func_clk_en(ethqos); } else { - clk_disable_unprepare(ethqos->rgmii_clk); + clk_disable_unprepare(ethqos->link_clk); } return ret; @@ -662,9 +663,9 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en; ethqos->has_emac3 = data->has_emac3; - ethqos->rgmii_clk = devm_clk_get(dev, "rgmii"); - if (IS_ERR(ethqos->rgmii_clk)) { - ret = PTR_ERR(ethqos->rgmii_clk); + ethqos->link_clk = devm_clk_get(dev, data->link_clk_name ?: "rgmii"); + if (IS_ERR(ethqos->link_clk)) { + ret = PTR_ERR(ethqos->link_clk); goto out_config_dt; } @@ -683,7 +684,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) } ethqos->speed = SPEED_1000; - ethqos_update_rgmii_clk(ethqos, SPEED_1000); + ethqos_update_link_clk(ethqos, SPEED_1000); ethqos_set_func_clk_en(ethqos); plat_dat->bsp_priv = ethqos; -- cgit v1.2.3 From 25c4a0769443d77c74fe73c80a978e28b08dc976 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:58 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: prepare the driver for more PHY modes In preparation for supporting SGMII, let's make the code a bit more generic. Add a new callback for MAC configuration so that we can assign a different variant of it in the future. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andrew Halaney Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 31 ++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index a739e1d5c046..0ececc951528 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -92,11 +92,13 @@ struct ethqos_emac_driver_data { struct qcom_ethqos { struct platform_device *pdev; void __iomem *rgmii_base; + int (*configure_func)(struct qcom_ethqos *ethqos); unsigned int link_clk_rate; struct clk *link_clk; struct phy *serdes_phy; unsigned int speed; + int phy_mode; const struct ethqos_emac_por *por; unsigned int num_por; @@ -331,13 +333,11 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) { struct device *dev = ðqos->pdev->dev; int phase_shift; - int phy_mode; int loopback; /* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */ - phy_mode = device_get_phy_mode(dev); - if (phy_mode == PHY_INTERFACE_MODE_RGMII_ID || - phy_mode == PHY_INTERFACE_MODE_RGMII_TXID) + if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID || + ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID) phase_shift = 0; else phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN; @@ -483,7 +483,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) return 0; } -static int ethqos_configure(struct qcom_ethqos *ethqos) +static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) { struct device *dev = ðqos->pdev->dev; volatile unsigned int dll_lock; @@ -559,6 +559,11 @@ static int ethqos_configure(struct qcom_ethqos *ethqos) return 0; } +static int ethqos_configure(struct qcom_ethqos *ethqos) +{ + return ethqos->configure_func(ethqos); +} + static void ethqos_fix_mac_speed(void *priv, unsigned int speed) { struct qcom_ethqos *ethqos = priv; @@ -650,6 +655,22 @@ static int qcom_ethqos_probe(struct platform_device *pdev) goto out_config_dt; } + ethqos->phy_mode = device_get_phy_mode(dev); + switch (ethqos->phy_mode) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + ethqos->configure_func = ethqos_configure_rgmii; + break; + case -ENODEV: + ret = -ENODEV; + goto out_config_dt; + default: + ret = -EINVAL; + goto out_config_dt; + } + ethqos->pdev = pdev; ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii"); if (IS_ERR(ethqos->rgmii_base)) { -- cgit v1.2.3 From 463120c31c58bbca0237dd6ae73d20f77609c749 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:23:59 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: add support for SGMII On sa8775p the MAC is connected to the external PHY over SGMII so add support for it to the driver. Signed-off-by: Bartosz Golaszewski Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 0ececc951528..bdf59a179f87 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -75,6 +75,10 @@ #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL BIT(6) #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN BIT(5) +/* MAC_CTRL_REG bits */ +#define ETHQOS_MAC_CTRL_SPEED_MODE BIT(14) +#define ETHQOS_MAC_CTRL_PORT_SEL BIT(15) + struct ethqos_emac_por { unsigned int offset; unsigned int value; @@ -92,6 +96,7 @@ struct ethqos_emac_driver_data { struct qcom_ethqos { struct platform_device *pdev; void __iomem *rgmii_base; + void __iomem *mac_base; int (*configure_func)(struct qcom_ethqos *ethqos); unsigned int link_clk_rate; @@ -559,6 +564,33 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) return 0; } +static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos) +{ + int val; + + val = readl(ethqos->mac_base + MAC_CTRL_REG); + + switch (ethqos->speed) { + case SPEED_1000: + val &= ~ETHQOS_MAC_CTRL_PORT_SEL; + rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, + RGMII_CONFIG2_RGMII_CLK_SEL_CFG, + RGMII_IO_MACRO_CONFIG2); + break; + case SPEED_100: + val |= ETHQOS_MAC_CTRL_PORT_SEL | ETHQOS_MAC_CTRL_SPEED_MODE; + break; + case SPEED_10: + val |= ETHQOS_MAC_CTRL_PORT_SEL; + val &= ~ETHQOS_MAC_CTRL_SPEED_MODE; + break; + } + + writel(val, ethqos->mac_base + MAC_CTRL_REG); + + return val; +} + static int ethqos_configure(struct qcom_ethqos *ethqos) { return ethqos->configure_func(ethqos); @@ -663,6 +695,9 @@ static int qcom_ethqos_probe(struct platform_device *pdev) case PHY_INTERFACE_MODE_RGMII_TXID: ethqos->configure_func = ethqos_configure_rgmii; break; + case PHY_INTERFACE_MODE_SGMII: + ethqos->configure_func = ethqos_configure_sgmii; + break; case -ENODEV: ret = -ENODEV; goto out_config_dt; @@ -678,6 +713,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) goto out_config_dt; } + ethqos->mac_base = stmmac_res.addr; + data = of_device_get_match_data(dev); ethqos->por = data->por; ethqos->num_por = data->num_por; -- cgit v1.2.3 From aa571b6275fb60da443c490ebeef021a6897d332 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:24:00 +0200 Subject: net: stmmac: add new switch to struct plat_stmmacenet_data On some platforms, the PCS can be integrated in the MAC so the driver will not see any PCS link activity. Add a switch that allows the platform drivers to let the core code know. Signed-off-by: Bartosz Golaszewski Reviewed-by: Jose Abreu Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- include/linux/stmmac.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5c645b6d5660..10e8a5606ba6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -5798,7 +5798,7 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) } /* PCS link status */ - if (priv->hw->pcs) { + if (priv->hw->pcs && !priv->plat->has_integrated_pcs) { if (priv->xstats.pcs_link) netif_carrier_on(priv->dev); else diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 225751a8fd8e..06090538fe2d 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -293,5 +293,6 @@ struct plat_stmmacenet_data { bool sph_disable; bool serdes_up_after_phy_linkup; const struct dwmac4_addrs *dwmac4_addrs; + bool has_integrated_pcs; }; #endif -- cgit v1.2.3 From d0e3d29f8771068a6f8df2a148080c449bc5b046 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:24:01 +0200 Subject: dt-bindings: net: qcom,ethqos: add description for sa8775p Add the compatible for the MAC controller on sa8775p platforms. This MAC works with a single interrupt so add minItems to the interrupts property. The fourth clock's name is different here so change it. Enable relevant PHY properties. Add the relevant compatibles to the binding document for snps,dwmac as well. Signed-off-by: Bartosz Golaszewski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/qcom,ethqos.yaml | 12 +++++++++++- Documentation/devicetree/bindings/net/snps,dwmac.yaml | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml index 60a38044fb19..7bdb412a0185 100644 --- a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml @@ -20,6 +20,7 @@ properties: compatible: enum: - qcom,qcs404-ethqos + - qcom,sa8775p-ethqos - qcom,sc8280xp-ethqos - qcom,sm8150-ethqos @@ -32,11 +33,13 @@ properties: - const: rgmii interrupts: + minItems: 1 items: - description: Combined signal for various interrupt events - description: The interrupt that occurs when Rx exits the LPI state interrupt-names: + minItems: 1 items: - const: macirq - const: eth_lpi @@ -49,11 +52,18 @@ properties: - const: stmmaceth - const: pclk - const: ptp_ref - - const: rgmii + - enum: + - rgmii + - phyaux iommus: maxItems: 1 + phys: true + + phy-names: + const: serdes + required: - compatible - clocks diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml index 363b3e3ea3a6..ddf9522a5dc2 100644 --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml @@ -67,6 +67,7 @@ properties: - loongson,ls2k-dwmac - loongson,ls7a-dwmac - qcom,qcs404-ethqos + - qcom,sa8775p-ethqos - qcom,sc8280xp-ethqos - qcom,sm8150-ethqos - renesas,r9a06g032-gmac @@ -582,6 +583,7 @@ allOf: - ingenic,x1600-mac - ingenic,x1830-mac - ingenic,x2000-mac + - qcom,sa8775p-ethqos - qcom,sc8280xp-ethqos - snps,dwmac-3.50a - snps,dwmac-4.10a @@ -638,6 +640,7 @@ allOf: - ingenic,x1830-mac - ingenic,x2000-mac - qcom,qcs404-ethqos + - qcom,sa8775p-ethqos - qcom,sc8280xp-ethqos - qcom,sm8150-ethqos - snps,dwmac-4.00 -- cgit v1.2.3 From 8c4d92e82d500a65e7dba101ea38e4f3499dc428 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 19 Jun 2023 11:24:02 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: add support for emac4 on sa8775p platforms sa8775p uses EMAC version 4, add the relevant defines, rename the has_emac3 switch to has_emac_ge_3 (has emac greater-or-equal than 3) and add the new compatible. Signed-off-by: Bartosz Golaszewski Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 65 +++++++++++++++++----- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index bdf59a179f87..fa0fc53c56a3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -88,8 +88,9 @@ struct ethqos_emac_driver_data { const struct ethqos_emac_por *por; unsigned int num_por; bool rgmii_config_loopback_en; - bool has_emac3; + bool has_emac_ge_3; const char *link_clk_name; + bool has_integrated_pcs; struct dwmac4_addrs dwmac4_addrs; }; @@ -108,7 +109,7 @@ struct qcom_ethqos { const struct ethqos_emac_por *por; unsigned int num_por; bool rgmii_config_loopback_en; - bool has_emac3; + bool has_emac_ge_3; }; static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) @@ -202,7 +203,7 @@ static const struct ethqos_emac_driver_data emac_v2_3_0_data = { .por = emac_v2_3_0_por, .num_por = ARRAY_SIZE(emac_v2_3_0_por), .rgmii_config_loopback_en = true, - .has_emac3 = false, + .has_emac_ge_3 = false, }; static const struct ethqos_emac_por emac_v2_1_0_por[] = { @@ -218,7 +219,7 @@ static const struct ethqos_emac_driver_data emac_v2_1_0_data = { .por = emac_v2_1_0_por, .num_por = ARRAY_SIZE(emac_v2_1_0_por), .rgmii_config_loopback_en = false, - .has_emac3 = false, + .has_emac_ge_3 = false, }; static const struct ethqos_emac_por emac_v3_0_0_por[] = { @@ -234,7 +235,41 @@ static const struct ethqos_emac_driver_data emac_v3_0_0_data = { .por = emac_v3_0_0_por, .num_por = ARRAY_SIZE(emac_v3_0_0_por), .rgmii_config_loopback_en = false, - .has_emac3 = true, + .has_emac_ge_3 = true, + .dwmac4_addrs = { + .dma_chan = 0x00008100, + .dma_chan_offset = 0x1000, + .mtl_chan = 0x00008000, + .mtl_chan_offset = 0x1000, + .mtl_ets_ctrl = 0x00008010, + .mtl_ets_ctrl_offset = 0x1000, + .mtl_txq_weight = 0x00008018, + .mtl_txq_weight_offset = 0x1000, + .mtl_send_slp_cred = 0x0000801c, + .mtl_send_slp_cred_offset = 0x1000, + .mtl_high_cred = 0x00008020, + .mtl_high_cred_offset = 0x1000, + .mtl_low_cred = 0x00008024, + .mtl_low_cred_offset = 0x1000, + }, +}; + +static const struct ethqos_emac_por emac_v4_0_0_por[] = { + { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x40c01343 }, + { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642c }, + { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x80040800 }, + { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, + { .offset = SDCC_USR_CTL, .value = 0x00010800 }, + { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, +}; + +static const struct ethqos_emac_driver_data emac_v4_0_0_data = { + .por = emac_v4_0_0_por, + .num_por = ARRAY_SIZE(emac_v3_0_0_por), + .rgmii_config_loopback_en = false, + .has_emac_ge_3 = true, + .link_clk_name = "phyaux", + .has_integrated_pcs = true, .dwmac4_addrs = { .dma_chan = 0x00008100, .dma_chan_offset = 0x1000, @@ -275,7 +310,7 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); - if (!ethqos->has_emac3) { + if (!ethqos->has_emac_ge_3) { rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, 0, SDCC_HC_REG_DLL_CONFIG); @@ -316,7 +351,7 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2); - if (!ethqos->has_emac3) { + if (!ethqos->has_emac_ge_3) { rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, 0, SDCC_HC_REG_DLL_CONFIG2); @@ -386,7 +421,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) /* PRG_RCLK_DLY = TCXO period * TCXO_CYCLES_CNT / 2 * RX delay ns, * in practice this becomes PRG_RCLK_DLY = 52 * 4 / 2 * RX delay ns */ - if (ethqos->has_emac3) { + if (ethqos->has_emac_ge_3) { /* 0.9 ns */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, 115, SDCC_HC_REG_DDR_CONFIG); @@ -421,7 +456,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - if (ethqos->has_emac3) + if (ethqos->has_emac_ge_3) rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2); @@ -461,7 +496,7 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - if (ethqos->has_emac3) + if (ethqos->has_emac_ge_3) rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2); @@ -510,7 +545,7 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG); - if (ethqos->has_emac3) { + if (ethqos->has_emac_ge_3) { if (ethqos->speed == SPEED_1000) { rgmii_writel(ethqos, 0x1800000, SDCC_TEST_CTL); rgmii_writel(ethqos, 0x2C010800, SDCC_USR_CTL); @@ -540,7 +575,7 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) SDCC_HC_REG_DLL_CONFIG); /* Set USR_CTL bit 26 with mask of 3 bits */ - if (!ethqos->has_emac3) + if (!ethqos->has_emac_ge_3) rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), SDCC_USR_CTL); @@ -719,7 +754,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->por = data->por; ethqos->num_por = data->num_por; ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en; - ethqos->has_emac3 = data->has_emac3; + ethqos->has_emac_ge_3 = data->has_emac_ge_3; ethqos->link_clk = devm_clk_get(dev, data->link_clk_name ?: "rgmii"); if (IS_ERR(ethqos->link_clk)) { @@ -749,12 +784,13 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->fix_mac_speed = ethqos_fix_mac_speed; plat_dat->dump_debug_regs = rgmii_dump; plat_dat->has_gmac4 = 1; - if (ethqos->has_emac3) + if (ethqos->has_emac_ge_3) plat_dat->dwmac4_addrs = &data->dwmac4_addrs; plat_dat->pmt = 1; plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) plat_dat->rx_clk_runs_in_lpi = 1; + plat_dat->has_integrated_pcs = data->has_integrated_pcs; if (ethqos->serdes_phy) { plat_dat->serdes_powerup = qcom_ethqos_serdes_powerup; @@ -775,6 +811,7 @@ out_config_dt: static const struct of_device_id qcom_ethqos_match[] = { { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data}, + { .compatible = "qcom,sa8775p-ethqos", .data = &emac_v4_0_0_data}, { .compatible = "qcom,sc8280xp-ethqos", .data = &emac_v3_0_0_data}, { .compatible = "qcom,sm8150-ethqos", .data = &emac_v2_1_0_data}, { } -- cgit v1.2.3 From d33ed97dcab3efd7baebfb68cd19ff12f6211448 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 09:16:26 +0200 Subject: wifi: mac80211: fix documentation config reference We shouldn't refer to CPTCFG_, that's for backports, in mainline that's just CONFIG_. Fix it. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 914448cb0ecf..3a8a2d2c58c3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3873,7 +3873,7 @@ struct ieee80211_prep_tx_info { * * @link_sta_add_debugfs: Drivers can use this callback to add debugfs files * when a link is added to a mac80211 station. This callback - * should be within a CPTCFG_MAC80211_DEBUGFS conditional. This + * should be within a CONFIG_MAC80211_DEBUGFS conditional. This * callback can sleep. * For non-MLO the callback will be called once for the deflink with the * station's directory rather than a separate subdirectory. -- cgit v1.2.3 From 2ce9a91fe8bfb0c8e647a6b7b88055881faf7502 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Thu, 15 Jun 2023 19:43:48 +0800 Subject: wifi: rtw88: Fix action frame transmission fail before association For combo chips, antennas were controlled by bluetooth only during power on. If WiFi wish to do transmission, notification to the coexistence module are required. Previously we only do this before authentication. To allow transmission before auth, such as management TX, now we start the initiation of coexistence earlier so antennas are shared between WiFi and bluetooth after set_channel(), and frames could then be sent. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230615114348.7193-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/ps.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 53933fb38a33..43e80a3a8136 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -18,6 +18,7 @@ static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) if (ret) rtw_err(rtwdev, "leave idle state failed\n"); + rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE); rtw_set_channel(rtwdev); return ret; @@ -63,8 +64,6 @@ int rtw_leave_ips(struct rtw_dev *rtwdev) rtw_iterate_vifs(rtwdev, rtw_restore_port_cfg_iter, rtwdev); - rtw_coex_ips_notify(rtwdev, COEX_IPS_LEAVE); - return 0; } -- cgit v1.2.3 From 67d7f24b194e6e8e82540aa4fe97580f6cfa0902 Mon Sep 17 00:00:00 2001 From: Chih-Kang Chang Date: Fri, 16 Jun 2023 11:17:13 +0800 Subject: wifi: rtw88: process VO packets without workqueue to avoid PTK rekey failed In the wpa_supplicant rekey flow, it sends an EAPOL packet 4/4 through nl80211_tx_control_port() and triggers wake_tx_queue() in the driver. Then, it sends nl80211_new_key() to configure a new key in mac80211. However, in wake_tx_queue(), a workqueue is used to process the tx packet, which might cause the driver to process the EAPOL packet later than nl80211_new_key(). As a result, the EAPOL 4/4 packet is dropped by mac80211 due to the rekey configuration being finished. The EAPOL packets belongs to VO packets that need high priority. Therefore, we process VO packets directly without workqueue to ensure that packets can process immediately. VO is normally used by voice application that is low traffic load and low latency, that doesn't affect user experience. We test iperf with VO packets(iperf3 -P4 -u -b 10000M -S 0xdf) before after TX throughput 162M 162M ping RTT 3.8ms 3.7ms Signed-off-by: Chih-Kang Chang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616031713.16769-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/mac80211.c | 6 +++++- drivers/net/wireless/realtek/rtw88/tx.c | 10 ++++++++-- drivers/net/wireless/realtek/rtw88/tx.h | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 09bcc2345bb0..424102790283 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -43,7 +43,11 @@ static void rtw_ops_wake_tx_queue(struct ieee80211_hw *hw, list_add_tail(&rtwtxq->list, &rtwdev->txqs); spin_unlock_bh(&rtwdev->txq_lock); - queue_work(rtwdev->tx_wq, &rtwdev->tx_work); + /* ensure to dequeue EAPOL (4/4) at the right time */ + if (txq->ac == IEEE80211_AC_VO) + __rtw_tx_work(rtwdev); + else + queue_work(rtwdev->tx_wq, &rtwdev->tx_work); } static int rtw_ops_start(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index bb5c7492c98b..b6c97a986a1a 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -635,9 +635,8 @@ static void rtw_txq_push(struct rtw_dev *rtwdev, rcu_read_unlock(); } -void rtw_tx_work(struct work_struct *w) +void __rtw_tx_work(struct rtw_dev *rtwdev) { - struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work); struct rtw_txq *rtwtxq, *tmp; spin_lock_bh(&rtwdev->txq_lock); @@ -658,6 +657,13 @@ void rtw_tx_work(struct work_struct *w) spin_unlock_bh(&rtwdev->txq_lock); } +void rtw_tx_work(struct work_struct *w) +{ + struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work); + + __rtw_tx_work(rtwdev); +} + void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) { struct rtw_txq *rtwtxq; diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 197d5868c8ad..544133643a1b 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -111,6 +111,7 @@ void rtw_tx(struct rtw_dev *rtwdev, void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq); void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq); void rtw_tx_work(struct work_struct *w); +void __rtw_tx_work(struct rtw_dev *rtwdev); void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, struct ieee80211_sta *sta, -- cgit v1.2.3 From 88b9d8e6cf9cf89be50ca2ee6cb9b3180b432172 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 16 Jun 2023 20:55:35 +0800 Subject: wifi: rtw88: use struct instead of macros to set TX desc Remove macros that set TX descriptors. Use struct and le32_encode_bits() with mask definitions. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616125540.36877-2-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/rtw8723d.c | 6 +- drivers/net/wireless/realtek/rtw88/tx.c | 79 +++++++++-------- drivers/net/wireless/realtek/rtw88/tx.h | 122 +++++++++++--------------- drivers/net/wireless/realtek/rtw88/usb.c | 12 ++- 4 files changed, 106 insertions(+), 113 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index cadf66f4e854..c575476a0020 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -1970,15 +1970,17 @@ static void rtw8723d_fill_txdesc_checksum(struct rtw_dev *rtwdev, size_t words = 32 / 2; /* calculate the first 32 bytes (16 words) */ __le16 chksum = 0; __le16 *data = (__le16 *)(txdesc); + struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)txdesc; - SET_TX_DESC_TXDESC_CHECKSUM(txdesc, 0x0000); + le32p_replace_bits(&tx_desc->w7, 0, RTW_TX_DESC_W7_TXDESC_CHECKSUM); while (words--) chksum ^= *data++; chksum = ~chksum; - SET_TX_DESC_TXDESC_CHECKSUM(txdesc, __le16_to_cpu(chksum)); + le32p_replace_bits(&tx_desc->w7, __le16_to_cpu(chksum), + RTW_TX_DESC_W7_TXDESC_CHECKSUM); } static struct rtw_chip_ops rtw8723d_ops = { diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index b6c97a986a1a..c34f53890fe6 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -34,43 +34,52 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) { - __le32 *txdesc = (__le32 *)skb->data; - - SET_TX_DESC_TXPKTSIZE(txdesc, pkt_info->tx_pkt_size); - SET_TX_DESC_OFFSET(txdesc, pkt_info->offset); - SET_TX_DESC_PKT_OFFSET(txdesc, pkt_info->pkt_offset); - SET_TX_DESC_QSEL(txdesc, pkt_info->qsel); - SET_TX_DESC_BMC(txdesc, pkt_info->bmc); - SET_TX_DESC_RATE_ID(txdesc, pkt_info->rate_id); - SET_TX_DESC_DATARATE(txdesc, pkt_info->rate); - SET_TX_DESC_DISDATAFB(txdesc, pkt_info->dis_rate_fallback); - SET_TX_DESC_USE_RATE(txdesc, pkt_info->use_rate); - SET_TX_DESC_SEC_TYPE(txdesc, pkt_info->sec_type); - SET_TX_DESC_DATA_BW(txdesc, pkt_info->bw); - SET_TX_DESC_SW_SEQ(txdesc, pkt_info->seq); - SET_TX_DESC_MAX_AGG_NUM(txdesc, pkt_info->ampdu_factor); - SET_TX_DESC_AMPDU_DENSITY(txdesc, pkt_info->ampdu_density); - SET_TX_DESC_DATA_STBC(txdesc, pkt_info->stbc); - SET_TX_DESC_DATA_LDPC(txdesc, pkt_info->ldpc); - SET_TX_DESC_AGG_EN(txdesc, pkt_info->ampdu_en); - SET_TX_DESC_LS(txdesc, pkt_info->ls); - SET_TX_DESC_DATA_SHORT(txdesc, pkt_info->short_gi); - SET_TX_DESC_SPE_RPT(txdesc, pkt_info->report); - SET_TX_DESC_SW_DEFINE(txdesc, pkt_info->sn); - SET_TX_DESC_USE_RTS(txdesc, pkt_info->rts); + struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; + + tx_desc->w0 = le32_encode_bits(pkt_info->tx_pkt_size, RTW_TX_DESC_W0_TXPKTSIZE) | + le32_encode_bits(pkt_info->offset, RTW_TX_DESC_W0_OFFSET) | + le32_encode_bits(pkt_info->bmc, RTW_TX_DESC_W0_BMC) | + le32_encode_bits(pkt_info->ls, RTW_TX_DESC_W0_LS) | + le32_encode_bits(pkt_info->dis_qselseq, RTW_TX_DESC_W0_DISQSELSEQ); + + tx_desc->w1 = le32_encode_bits(pkt_info->qsel, RTW_TX_DESC_W1_QSEL) | + le32_encode_bits(pkt_info->rate_id, RTW_TX_DESC_W1_RATE_ID) | + le32_encode_bits(pkt_info->sec_type, RTW_TX_DESC_W1_SEC_TYPE) | + le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET); + + tx_desc->w2 = le32_encode_bits(pkt_info->ampdu_en, RTW_TX_DESC_W2_AGG_EN) | + le32_encode_bits(pkt_info->report, RTW_TX_DESC_W2_SPE_RPT) | + le32_encode_bits(pkt_info->ampdu_density, RTW_TX_DESC_W2_AMPDU_DEN) | + le32_encode_bits(pkt_info->bt_null, RTW_TX_DESC_W2_BT_NULL); + + tx_desc->w3 = le32_encode_bits(pkt_info->hw_ssn_sel, RTW_TX_DESC_W3_HW_SSN_SEL) | + le32_encode_bits(pkt_info->use_rate, RTW_TX_DESC_W3_USE_RATE) | + le32_encode_bits(pkt_info->dis_rate_fallback, RTW_TX_DESC_W3_DISDATAFB) | + le32_encode_bits(pkt_info->rts, RTW_TX_DESC_W3_USE_RTS) | + le32_encode_bits(pkt_info->nav_use_hdr, RTW_TX_DESC_W3_NAVUSEHDR) | + le32_encode_bits(pkt_info->ampdu_factor, RTW_TX_DESC_W3_MAX_AGG_NUM); + + tx_desc->w4 = le32_encode_bits(pkt_info->rate, RTW_TX_DESC_W4_DATARATE); + + tx_desc->w5 = le32_encode_bits(pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) | + le32_encode_bits(pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) | + le32_encode_bits(pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) | + le32_encode_bits(pkt_info->stbc, RTW_TX_DESC_W5_DATA_STBC); + + tx_desc->w6 = le32_encode_bits(pkt_info->sn, RTW_TX_DESC_W6_SW_DEFINE); + + tx_desc->w8 = le32_encode_bits(pkt_info->en_hwseq, RTW_TX_DESC_W8_EN_HWSEQ); + + tx_desc->w9 = le32_encode_bits(pkt_info->seq, RTW_TX_DESC_W9_SW_SEQ); + if (pkt_info->rts) { - SET_TX_DESC_RTSRATE(txdesc, DESC_RATE24M); - SET_TX_DESC_DATA_RTS_SHORT(txdesc, 1); - } - SET_TX_DESC_DISQSELSEQ(txdesc, pkt_info->dis_qselseq); - SET_TX_DESC_EN_HWSEQ(txdesc, pkt_info->en_hwseq); - SET_TX_DESC_HW_SSN_SEL(txdesc, pkt_info->hw_ssn_sel); - SET_TX_DESC_NAVUSEHDR(txdesc, pkt_info->nav_use_hdr); - SET_TX_DESC_BT_NULL(txdesc, pkt_info->bt_null); - if (pkt_info->tim_offset) { - SET_TX_DESC_TIM_EN(txdesc, 1); - SET_TX_DESC_TIM_OFFSET(txdesc, pkt_info->tim_offset); + tx_desc->w4 |= le32_encode_bits(DESC_RATE24M, RTW_TX_DESC_W4_RTSRATE); + tx_desc->w5 |= le32_encode_bits(1, RTW_TX_DESC_W5_DATA_RTS_SHORT); } + + if (pkt_info->tim_offset) + tx_desc->w9 |= le32_encode_bits(1, RTW_TX_DESC_W9_TIM_EN) | + le32_encode_bits(pkt_info->tim_offset, RTW_TX_DESC_W9_TIM_OFFSET); } EXPORT_SYMBOL(rtw_tx_fill_tx_desc); diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 544133643a1b..75cde861e924 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -9,76 +9,52 @@ #define RTW_TX_PROBE_TIMEOUT msecs_to_jiffies(500) -#define SET_TX_DESC_TXPKTSIZE(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, GENMASK(15, 0)) -#define SET_TX_DESC_OFFSET(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, GENMASK(23, 16)) -#define SET_TX_DESC_PKT_OFFSET(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x01, value, GENMASK(28, 24)) -#define SET_TX_DESC_QSEL(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x01, value, GENMASK(12, 8)) -#define SET_TX_DESC_BMC(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, BIT(24)) -#define SET_TX_DESC_RATE_ID(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x01, value, GENMASK(20, 16)) -#define SET_TX_DESC_DATARATE(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x04, value, GENMASK(6, 0)) -#define SET_TX_DESC_DISDATAFB(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(10)) -#define SET_TX_DESC_USE_RATE(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(8)) -#define SET_TX_DESC_SEC_TYPE(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x01, value, GENMASK(23, 22)) -#define SET_TX_DESC_DATA_BW(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, GENMASK(6, 5)) -#define SET_TX_DESC_SW_SEQ(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x09, value, GENMASK(23, 12)) -#define SET_TX_DESC_TIM_EN(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x09, value, BIT(7)) -#define SET_TX_DESC_TIM_OFFSET(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x09, value, GENMASK(6, 0)) -#define SET_TX_DESC_MAX_AGG_NUM(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, GENMASK(21, 17)) -#define SET_TX_DESC_USE_RTS(tx_desc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(12)) -#define SET_TX_DESC_RTSRATE(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x04, value, GENMASK(28, 24)) -#define SET_TX_DESC_DATA_RTS_SHORT(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, BIT(12)) -#define SET_TX_DESC_AMPDU_DENSITY(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, GENMASK(22, 20)) -#define SET_TX_DESC_DATA_STBC(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, GENMASK(9, 8)) -#define SET_TX_DESC_DATA_LDPC(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, BIT(7)) -#define SET_TX_DESC_AGG_EN(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(12)) -#define SET_TX_DESC_LS(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, BIT(26)) -#define SET_TX_DESC_DATA_SHORT(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x05, value, BIT(4)) -#define SET_TX_DESC_SPE_RPT(tx_desc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(19)) -#define SET_TX_DESC_SW_DEFINE(tx_desc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x06, value, GENMASK(11, 0)) -#define SET_TX_DESC_DISQSELSEQ(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x00, value, BIT(31)) -#define SET_TX_DESC_EN_HWSEQ(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x08, value, BIT(15)) -#define SET_TX_DESC_HW_SSN_SEL(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, GENMASK(7, 6)) -#define SET_TX_DESC_NAVUSEHDR(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(15)) -#define SET_TX_DESC_BT_NULL(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(23)) -#define SET_TX_DESC_TXDESC_CHECKSUM(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x07, value, GENMASK(15, 0)) -#define SET_TX_DESC_DMA_TXAGG_NUM(txdesc, value) \ - le32p_replace_bits((__le32 *)(txdesc) + 0x07, value, GENMASK(31, 24)) -#define GET_TX_DESC_PKT_OFFSET(txdesc) \ - le32_get_bits(*((__le32 *)(txdesc) + 0x01), GENMASK(28, 24)) -#define GET_TX_DESC_QSEL(txdesc) \ - le32_get_bits(*((__le32 *)(txdesc) + 0x01), GENMASK(12, 8)) +struct rtw_tx_desc { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; +} __packed; + +#define RTW_TX_DESC_W0_TXPKTSIZE GENMASK(15, 0) +#define RTW_TX_DESC_W0_OFFSET GENMASK(23, 16) +#define RTW_TX_DESC_W0_BMC BIT(24) +#define RTW_TX_DESC_W0_LS BIT(26) +#define RTW_TX_DESC_W0_DISQSELSEQ BIT(31) +#define RTW_TX_DESC_W1_QSEL GENMASK(12, 8) +#define RTW_TX_DESC_W1_RATE_ID GENMASK(20, 16) +#define RTW_TX_DESC_W1_SEC_TYPE GENMASK(23, 22) +#define RTW_TX_DESC_W1_PKT_OFFSET GENMASK(28, 24) +#define RTW_TX_DESC_W2_AGG_EN BIT(12) +#define RTW_TX_DESC_W2_SPE_RPT BIT(19) +#define RTW_TX_DESC_W2_AMPDU_DEN GENMASK(22, 20) +#define RTW_TX_DESC_W2_BT_NULL BIT(23) +#define RTW_TX_DESC_W3_HW_SSN_SEL GENMASK(7, 6) +#define RTW_TX_DESC_W3_USE_RATE BIT(8) +#define RTW_TX_DESC_W3_DISDATAFB BIT(10) +#define RTW_TX_DESC_W3_USE_RTS BIT(12) +#define RTW_TX_DESC_W3_NAVUSEHDR BIT(15) +#define RTW_TX_DESC_W3_MAX_AGG_NUM GENMASK(21, 17) +#define RTW_TX_DESC_W4_DATARATE GENMASK(6, 0) +#define RTW_TX_DESC_W4_RTSRATE GENMASK(28, 24) +#define RTW_TX_DESC_W5_DATA_SHORT BIT(4) +#define RTW_TX_DESC_W5_DATA_BW GENMASK(6, 5) +#define RTW_TX_DESC_W5_DATA_LDPC BIT(7) +#define RTW_TX_DESC_W5_DATA_STBC GENMASK(9, 8) +#define RTW_TX_DESC_W5_DATA_RTS_SHORT BIT(12) +#define RTW_TX_DESC_W6_SW_DEFINE GENMASK(11, 0) +#define RTW_TX_DESC_W7_TXDESC_CHECKSUM GENMASK(15, 0) +#define RTW_TX_DESC_W7_DMA_TXAGG_NUM GENMASK(31, 24) +#define RTW_TX_DESC_W8_EN_HWSEQ BIT(15) +#define RTW_TX_DESC_W9_SW_SEQ GENMASK(23, 12) +#define RTW_TX_DESC_W9_TIM_EN BIT(7) +#define RTW_TX_DESC_W9_TIM_OFFSET GENMASK(6, 0) enum rtw_tx_desc_queue_select { TX_DESC_QSEL_TID0 = 0, @@ -140,13 +116,15 @@ void fill_txdesc_checksum_common(u8 *txdesc, size_t words) { __le16 chksum = 0; __le16 *data = (__le16 *)(txdesc); + struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)txdesc; - SET_TX_DESC_TXDESC_CHECKSUM(txdesc, 0x0000); + le32p_replace_bits(&tx_desc->w7, 0, RTW_TX_DESC_W7_TXDESC_CHECKSUM); while (words--) chksum ^= *data++; - SET_TX_DESC_TXDESC_CHECKSUM(txdesc, __le16_to_cpu(chksum)); + le32p_replace_bits(&tx_desc->w7, __le16_to_cpu(chksum), + RTW_TX_DESC_W7_TXDESC_CHECKSUM); } static inline void rtw_tx_fill_txdesc_checksum(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index 976eafa739a2..0529ae24f53b 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -24,11 +24,12 @@ struct rtw_usb_txcb { static void rtw_usb_fill_tx_checksum(struct rtw_usb *rtwusb, struct sk_buff *skb, int agg_num) { + struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; struct rtw_dev *rtwdev = rtwusb->rtwdev; struct rtw_tx_pkt_info pkt_info; - SET_TX_DESC_DMA_TXAGG_NUM(skb->data, agg_num); - pkt_info.pkt_offset = GET_TX_DESC_PKT_OFFSET(skb->data); + le32p_replace_bits(&tx_desc->w7, agg_num, RTW_TX_DESC_W7_DMA_TXAGG_NUM); + pkt_info.pkt_offset = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_PKT_OFFSET); rtw_tx_fill_txdesc_checksum(rtwdev, &pkt_info, skb->data); } @@ -306,11 +307,13 @@ static int rtw_usb_write_port(struct rtw_dev *rtwdev, u8 qsel, struct sk_buff *s static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list) { struct rtw_dev *rtwdev = rtwusb->rtwdev; + struct rtw_tx_desc *tx_desc; struct rtw_usb_txcb *txcb; struct sk_buff *skb_head; struct sk_buff *skb_iter; int agg_num = 0; unsigned int align_next = 0; + u8 qsel; if (skb_queue_empty(list)) return false; @@ -363,9 +366,10 @@ static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list queue: skb_queue_tail(&txcb->tx_ack_queue, skb_head); + tx_desc = (struct rtw_tx_desc *)skb_head->data; + qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL); - rtw_usb_write_port(rtwdev, GET_TX_DESC_QSEL(skb_head->data), skb_head, - rtw_usb_write_port_tx_complete, txcb); + rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb); return true; } -- cgit v1.2.3 From 076f786a0ae14a81f40314b96a2d815e264bc213 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 16 Jun 2023 20:55:36 +0800 Subject: wifi: rtw88: Fix AP mode incorrect DTIM behavior Broadcast and multicast packets in high queue should be transmitted all at once during DTIM. But without proper settings, hardware fails to recognize that there are multiple packets and fetches only one. Fix this by signaling hardware with more data bit set when there are packets in the high queue. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616125540.36877-3-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/mac80211.c | 2 ++ drivers/net/wireless/realtek/rtw88/reg.h | 1 + drivers/net/wireless/realtek/rtw88/tx.c | 7 ++++++- drivers/net/wireless/realtek/rtw88/tx.h | 1 + drivers/net/wireless/realtek/rtw88/usb.c | 3 +++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 424102790283..aacea2098df8 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -453,6 +453,7 @@ static int rtw_ops_start_ap(struct ieee80211_hw *hw, const struct rtw_chip_info *chip = rtwdev->chip; mutex_lock(&rtwdev->mutex); + rtw_write32_set(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD); rtwdev->ap_active = true; rtw_store_op_chan(rtwdev, true); chip->ops->phy_calibration(rtwdev); @@ -468,6 +469,7 @@ static void rtw_ops_stop_ap(struct ieee80211_hw *hw, struct rtw_dev *rtwdev = hw->priv; mutex_lock(&rtwdev->mutex); + rtw_write32_clr(rtwdev, REG_TCR, BIT_TCR_UPDATE_HGQMD); rtwdev->ap_active = false; if (!rtw_core_check_sta_active(rtwdev)) rtw_clear_op_chan(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 2a2ae2081f34..60de9de1cc7a 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -410,6 +410,7 @@ #define REG_TCR 0x0604 #define BIT_PWRMGT_HWDATA_EN BIT(7) #define BIT_TCR_UPDATE_TIMIE BIT(5) +#define BIT_TCR_UPDATE_HGQMD BIT(4) #define REG_RCR 0x0608 #define BIT_APP_FCS BIT(31) #define BIT_APP_MIC BIT(30) diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index c34f53890fe6..2821119dc930 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -35,6 +35,10 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) { struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; + bool more_data = false; + + if (pkt_info->qsel == TX_DESC_QSEL_HIGH) + more_data = true; tx_desc->w0 = le32_encode_bits(pkt_info->tx_pkt_size, RTW_TX_DESC_W0_TXPKTSIZE) | le32_encode_bits(pkt_info->offset, RTW_TX_DESC_W0_OFFSET) | @@ -45,7 +49,8 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) tx_desc->w1 = le32_encode_bits(pkt_info->qsel, RTW_TX_DESC_W1_QSEL) | le32_encode_bits(pkt_info->rate_id, RTW_TX_DESC_W1_RATE_ID) | le32_encode_bits(pkt_info->sec_type, RTW_TX_DESC_W1_SEC_TYPE) | - le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET); + le32_encode_bits(pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET) | + le32_encode_bits(more_data, RTW_TX_DESC_W1_MORE_DATA); tx_desc->w2 = le32_encode_bits(pkt_info->ampdu_en, RTW_TX_DESC_W2_AGG_EN) | le32_encode_bits(pkt_info->report, RTW_TX_DESC_W2_SPE_RPT) | diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 75cde861e924..324189606257 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -31,6 +31,7 @@ struct rtw_tx_desc { #define RTW_TX_DESC_W1_RATE_ID GENMASK(20, 16) #define RTW_TX_DESC_W1_SEC_TYPE GENMASK(23, 22) #define RTW_TX_DESC_W1_PKT_OFFSET GENMASK(28, 24) +#define RTW_TX_DESC_W1_MORE_DATA BIT(29) #define RTW_TX_DESC_W2_AGG_EN BIT(12) #define RTW_TX_DESC_W2_SPE_RPT BIT(19) #define RTW_TX_DESC_W2_AMPDU_DEN GENMASK(22, 20) diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index 0529ae24f53b..4a57efdba97b 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -469,6 +469,9 @@ static u8 rtw_usb_tx_queue_mapping_to_qsel(struct sk_buff *skb) if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) qsel = TX_DESC_QSEL_MGMT; + else if (is_broadcast_ether_addr(hdr->addr1) || + is_multicast_ether_addr(hdr->addr1)) + qsel = TX_DESC_QSEL_HIGH; else if (skb_get_queue_mapping(skb) <= IEEE80211_AC_BK) qsel = skb->priority; else -- cgit v1.2.3 From 9e09fbc5e90247fc6e77fb6ba72dcbf8088cf59a Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 16 Jun 2023 20:55:37 +0800 Subject: wifi: rtw88: Skip high queue in hci_flush The flush period may not always intersect with DTIM and when that happens, an error log "timed out to flush pci TX ring[6]" is shown. Bypass this since hardware will do proper transmission on the next DTIM period for broadcast/multicast packets in high queue. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616125540.36877-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/pci.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 672ddde80816..44a8fff34cdd 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -738,8 +738,9 @@ static void __rtw_pci_flush_queues(struct rtw_dev *rtwdev, u32 pci_queues, u8 q; for (q = 0; q < RTK_MAX_TX_QUEUE_NUM; q++) { - /* It may be not necessary to flush BCN and H2C tx queues. */ - if (q == RTW_TX_QUEUE_BCN || q == RTW_TX_QUEUE_H2C) + /* Unnecessary to flush BCN, H2C and HI tx queues. */ + if (q == RTW_TX_QUEUE_BCN || q == RTW_TX_QUEUE_H2C || + q == RTW_TX_QUEUE_HI0) continue; if (pci_queues & BIT(q)) -- cgit v1.2.3 From ad6741b1e0449ba8f4eb41dc28e269dc20ab9219 Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 16 Jun 2023 20:55:38 +0800 Subject: wifi: rtw88: Stop high queue during scan When traversing channel list, TX in high queue should be disabled along with beacon function, so packets won't be sent to incorrect channels. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616125540.36877-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/main.c | 7 +++++-- drivers/net/wireless/realtek/rtw88/reg.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 9447a3aae3b5..d55b041a6bb9 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -2403,10 +2403,13 @@ void rtw_core_enable_beacon(struct rtw_dev *rtwdev, bool enable) if (!rtwdev->ap_active) return; - if (enable) + if (enable) { rtw_write32_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); - else + rtw_write32_clr(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); + } else { rtw_write32_clr(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); + rtw_write32_set(rtwdev, REG_TXPAUSE, BIT_HIGH_QUEUE); + } } MODULE_AUTHOR("Realtek Corporation"); diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 60de9de1cc7a..7c6c11d50ff3 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -378,6 +378,7 @@ #define BIT_SIFS_BK_EN BIT(12) #define REG_TXPAUSE 0x0522 #define BIT_AC_QUEUE GENMASK(7, 0) +#define BIT_HIGH_QUEUE BIT(5) #define REG_RD_CTRL 0x0524 #define BIT_EDCCA_MSK_CNTDOWN_EN BIT(11) #define BIT_DIS_TXOP_CFE BIT(10) -- cgit v1.2.3 From 455afa45edb3f1dbc1371201c5ee486bb9a8cd1a Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 16 Jun 2023 20:55:39 +0800 Subject: wifi: rtw88: refine register based H2C command Since register based H2C commands don't need endian conversion. Introduce a new API that don't do conversion and send it directly. New caller are expected to encode with cpu order and gradually replace the old ones. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616125540.36877-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/fw.c | 51 +++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/fw.h | 5 ++++ 2 files changed, 56 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 2a8ccc8a7f60..5e329bb95bb8 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -308,6 +308,57 @@ void rtw_fw_c2h_cmd_isr(struct rtw_dev *rtwdev) } EXPORT_SYMBOL(rtw_fw_c2h_cmd_isr); +static void rtw_fw_send_h2c_command_register(struct rtw_dev *rtwdev, + struct rtw_h2c_register *h2c) +{ + u32 box_reg, box_ex_reg; + u8 box_state, box; + int ret; + + rtw_dbg(rtwdev, RTW_DBG_FW, "send H2C content %08x %08x\n", h2c->w0, + h2c->w1); + + lockdep_assert_held(&rtwdev->mutex); + + box = rtwdev->h2c.last_box_num; + switch (box) { + case 0: + box_reg = REG_HMEBOX0; + box_ex_reg = REG_HMEBOX0_EX; + break; + case 1: + box_reg = REG_HMEBOX1; + box_ex_reg = REG_HMEBOX1_EX; + break; + case 2: + box_reg = REG_HMEBOX2; + box_ex_reg = REG_HMEBOX2_EX; + break; + case 3: + box_reg = REG_HMEBOX3; + box_ex_reg = REG_HMEBOX3_EX; + break; + default: + WARN(1, "invalid h2c mail box number\n"); + return; + } + + ret = read_poll_timeout_atomic(rtw_read8, box_state, + !((box_state >> box) & 0x1), 100, 3000, + false, rtwdev, REG_HMETFR); + + if (ret) { + rtw_err(rtwdev, "failed to send h2c command\n"); + return; + } + + rtw_write32(rtwdev, box_ex_reg, h2c->w1); + rtw_write32(rtwdev, box_reg, h2c->w0); + + if (++rtwdev->h2c.last_box_num >= 4) + rtwdev->h2c.last_box_num = 0; +} + static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev, u8 *h2c) { diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 397cbc3f6af6..11a77d86cd14 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -81,6 +81,11 @@ struct rtw_c2h_adaptivity { u8 option; } __packed; +struct rtw_h2c_register { + u32 w0; + u32 w1; +} __packed; + struct rtw_h2c_cmd { __le32 msg; __le32 msg_ext; -- cgit v1.2.3 From 28c11c29494f1b34e39641eead9c60a8bd26170d Mon Sep 17 00:00:00 2001 From: Po-Hao Huang Date: Fri, 16 Jun 2023 20:55:40 +0800 Subject: wifi: rtw88: fix not entering PS mode after AP stops Without this patch, firmware only track beacons for port 0 and since we will always start AP on port 0, this results in misbehavior of power saving mode on other ports after AP stops. The "default port" H2C command is used to notify which port should firmware track. Update the correct settings to firmware so power saving mode can work properly. Signed-off-by: Po-Hao Huang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616125540.36877-7-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw88/fw.c | 17 +++++++++++++++++ drivers/net/wireless/realtek/rtw88/fw.h | 8 ++++++++ drivers/net/wireless/realtek/rtw88/mac80211.c | 1 + drivers/net/wireless/realtek/rtw88/main.c | 8 ++++++++ drivers/net/wireless/realtek/rtw88/main.h | 1 + 5 files changed, 35 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 5e329bb95bb8..567bbedd8ee0 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -519,6 +519,23 @@ void rtw_fw_query_bt_info(struct rtw_dev *rtwdev) rtw_fw_send_h2c_command(rtwdev, h2c_pkt); } +void rtw_fw_default_port(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) +{ + struct rtw_h2c_register h2c = {}; + + if (rtwvif->net_type != RTW_NET_MGD_LINKED) + return; + + /* Leave LPS before default port H2C so FW timer is correct */ + rtw_leave_lps(rtwdev); + + h2c.w0 = u32_encode_bits(H2C_CMD_DEFAULT_PORT, RTW_H2C_W0_CMDID) | + u32_encode_bits(rtwvif->port, RTW_H2C_DEFAULT_PORT_W0_PORTID) | + u32_encode_bits(rtwvif->mac_id, RTW_H2C_DEFAULT_PORT_W0_MACID); + + rtw_fw_send_h2c_command_register(rtwdev, &h2c); +} + void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw) { u8 h2c_pkt[H2C_PKT_SIZE] = {0}; diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 11a77d86cd14..43ccdf9965ac 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -86,6 +86,12 @@ struct rtw_h2c_register { u32 w1; } __packed; +#define RTW_H2C_W0_CMDID GENMASK(7, 0) + +/* H2C_CMD_DEFAULT_PORT command */ +#define RTW_H2C_DEFAULT_PORT_W0_PORTID GENMASK(15, 8) +#define RTW_H2C_DEFAULT_PORT_W0_MACID GENMASK(23, 16) + struct rtw_h2c_cmd { __le32 msg; __le32 msg_ext; @@ -535,6 +541,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) #define H2C_CMD_MEDIA_STATUS_RPT 0x01 #define H2C_CMD_SET_PWR_MODE 0x20 #define H2C_CMD_LPS_PG_INFO 0x2b +#define H2C_CMD_DEFAULT_PORT 0x2c #define H2C_CMD_RA_INFO 0x40 #define H2C_CMD_RSSI_MONITOR 0x42 #define H2C_CMD_BCN_FILTER_OFFLOAD_P0 0x56 @@ -806,6 +813,7 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset, void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb); void rtw_fw_send_general_info(struct rtw_dev *rtwdev); void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev); +void rtw_fw_default_port(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para); void rtw_fw_inform_rfk_status(struct rtw_dev *rtwdev, bool start); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index aacea2098df8..a99b53d44267 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -382,6 +382,7 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, rtw_fw_download_rsvd_page(rtwdev); rtw_send_rsvd_page_h2c(rtwdev); + rtw_fw_default_port(rtwdev, rtwvif); rtw_coex_media_status_notify(rtwdev, vif->cfg.assoc); if (rtw_bf_support) rtw_bf_assoc(rtwdev, vif, conf); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index d55b041a6bb9..c853e2f2d448 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -334,12 +334,15 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; int i; si->mac_id = rtw_acquire_macid(rtwdev); if (si->mac_id >= RTW_MAX_MAC_ID_NUM) return -ENOSPC; + if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc == 0) + rtwvif->mac_id = si->mac_id; si->rtwdev = rtwdev; si->sta = sta; si->vif = vif; @@ -2340,6 +2343,9 @@ static void rtw_port_switch_iter(void *data, u8 *mac, struct ieee80211_vif *vif) rtw_dbg(rtwdev, RTW_DBG_STATE, "AP port switch from %d -> %d\n", rtwvif_ap->port, rtwvif_target->port); + /* Leave LPS so the value swapped are not in PS mode */ + rtw_leave_lps(rtwdev); + reg1 = &rtwvif_ap->conf->net_type; reg2 = &rtwvif_target->conf->net_type; rtw_swap_reg_mask(rtwdev, reg1, reg2); @@ -2358,6 +2364,8 @@ static void rtw_port_switch_iter(void *data, u8 *mac, struct ieee80211_vif *vif) swap(rtwvif_target->port, rtwvif_ap->port); swap(rtwvif_target->conf, rtwvif_ap->conf); + + rtw_fw_default_port(rtwdev, rtwvif_target); } void rtw_core_port_switch(struct rtw_dev *rtwdev, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 9e841f6991a9..f9dd2ab941c8 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -803,6 +803,7 @@ struct rtw_bf_info { struct rtw_vif { enum rtw_net_type net_type; u16 aid; + u8 mac_id; /* for STA mode only */ u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; u8 port; -- cgit v1.2.3 From f5993f39f3a734ba8e84913dfd69d56d997e0aa1 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Jun 2023 21:04:38 +0800 Subject: wifi: rtw89: 8851b: update RF radio A parameters to R28 Update 8851b radio A parameters to R28 along with internal HALRF_029_00_103 Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230615130442.18116-2-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8851b_table.c | 28 +++++++++++++++++----- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index bb724140df4f..aeee246baba9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -1273,6 +1273,25 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_radioa_regs[] = { {0xF0010000, 0x00000000}, {0xF0020000, 0x00000001}, {0xF0030000, 0x00000002}, + {0xF0010001, 0x00000003}, + {0xF0020001, 0x00000004}, + {0xF0030001, 0x00000005}, + {0xF0040001, 0x00000006}, + {0xF0050001, 0x00000007}, + {0xF0060001, 0x00000008}, + {0x000, 0x00000000}, + {0x0EF, 0x00080000}, + {0x033, 0x00000003}, + {0x03E, 0x00000150}, + {0x03F, 0x0000D79C}, + {0x0EF, 0x00000000}, + {0x052, 0x000C3338}, + {0x053, 0x000608AF}, + {0x054, 0x00006C04}, + {0x063, 0x000FC082}, + {0x065, 0x00018122}, + {0x000, 0x00010000}, + {0x0FE, 0x0000005A}, {0x000, 0x00030000}, {0x018, 0x00013124}, {0x0EF, 0x00080000}, @@ -1834,8 +1853,6 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_radioa_regs[] = { {0x059, 0x00050033}, {0x061, 0x0005F48A}, {0x062, 0x00077435}, - {0x063, 0x000F80A2}, - {0x065, 0x00018F22}, {0x067, 0x00008060}, {0x07E, 0x0009780B}, {0x0EE, 0x00000004}, @@ -2074,9 +2091,6 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_radioa_regs[] = { {0x03F, 0x0001C3C3}, {0x0EF, 0x00000000}, {0x051, 0x0003D368}, - {0x052, 0x000A3338}, - {0x053, 0x000688AF}, - {0x054, 0x00012C04}, {0x058, 0x00084221}, {0x05B, 0x000EB000}, {0x100EE, 0x00002000}, @@ -2229,9 +2243,11 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_radioa_regs[] = { {0x033, 0x00000000}, {0x03F, 0x00000004}, {0x0EF, 0x00000000}, + {0x000, 0x00010000}, + {0x0FE, 0x0000005A}, {0x005, 0x00000001}, {0x10005, 0x00000001}, - {0x0FE, 0x00000022}, + {0x0FE, 0x00000028}, }; static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { -- cgit v1.2.3 From b067acb1325abe06159768c351f149b8b621392c Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Thu, 15 Jun 2023 21:04:39 +0800 Subject: wifi: rtw89: 8851b: update TX power tables to R28 Update 8851B TX power tables to RF version R28. TX power tables' changes: * TX power limit and TX power shape: update 5 GHz configurations for FCC and IC Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230615130442.18116-3-pkshih@realtek.com --- .../net/wireless/realtek/rtw89/rtw8851b_table.c | 220 ++++++++++----------- 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index aeee246baba9..bda68dbc8b7b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -3342,8 +3342,8 @@ const u8 rtw89_8851b_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] [1][1][RTW89_ACMA] = 0, [1][1][RTW89_CN] = 0, [1][1][RTW89_ETSI] = 0, - [1][1][RTW89_FCC] = 3, - [1][1][RTW89_IC] = 3, + [1][1][RTW89_FCC] = 1, + [1][1][RTW89_IC] = 1, [1][1][RTW89_KCC] = 0, [1][1][RTW89_MKK] = 0, [1][1][RTW89_UK] = 0, @@ -4896,9 +4896,9 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_WW][42] = 30, [0][0][1][0][RTW89_WW][44] = 30, [0][0][1][0][RTW89_WW][46] = 30, - [0][0][1][0][RTW89_WW][48] = 72, - [0][0][1][0][RTW89_WW][50] = 72, - [0][0][1][0][RTW89_WW][52] = 72, + [0][0][1][0][RTW89_WW][48] = 68, + [0][0][1][0][RTW89_WW][50] = 68, + [0][0][1][0][RTW89_WW][52] = 68, [0][1][1][0][RTW89_WW][0] = 0, [0][1][1][0][RTW89_WW][2] = 0, [0][1][1][0][RTW89_WW][4] = 0, @@ -4952,9 +4952,9 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_WW][42] = 30, [0][0][2][0][RTW89_WW][44] = 30, [0][0][2][0][RTW89_WW][46] = 30, - [0][0][2][0][RTW89_WW][48] = 74, - [0][0][2][0][RTW89_WW][50] = 76, - [0][0][2][0][RTW89_WW][52] = 76, + [0][0][2][0][RTW89_WW][48] = 70, + [0][0][2][0][RTW89_WW][50] = 72, + [0][0][2][0][RTW89_WW][52] = 72, [0][1][2][0][RTW89_WW][0] = 0, [0][1][2][0][RTW89_WW][2] = 0, [0][1][2][0][RTW89_WW][4] = 0, @@ -5011,11 +5011,11 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_WW][48] = 0, [0][1][2][1][RTW89_WW][50] = 0, [0][1][2][1][RTW89_WW][52] = 0, - [1][0][2][0][RTW89_WW][1] = 64, + [1][0][2][0][RTW89_WW][1] = 60, [1][0][2][0][RTW89_WW][5] = 62, [1][0][2][0][RTW89_WW][9] = 64, - [1][0][2][0][RTW89_WW][13] = 64, - [1][0][2][0][RTW89_WW][16] = 66, + [1][0][2][0][RTW89_WW][13] = 60, + [1][0][2][0][RTW89_WW][16] = 62, [1][0][2][0][RTW89_WW][20] = 66, [1][0][2][0][RTW89_WW][24] = 66, [1][0][2][0][RTW89_WW][28] = 66, @@ -5023,8 +5023,8 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_WW][36] = 76, [1][0][2][0][RTW89_WW][39] = 30, [1][0][2][0][RTW89_WW][43] = 30, - [1][0][2][0][RTW89_WW][47] = 84, - [1][0][2][0][RTW89_WW][51] = 84, + [1][0][2][0][RTW89_WW][47] = 80, + [1][0][2][0][RTW89_WW][51] = 80, [1][1][2][0][RTW89_WW][1] = 0, [1][1][2][0][RTW89_WW][5] = 0, [1][1][2][0][RTW89_WW][9] = 0, @@ -5053,13 +5053,13 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_WW][43] = 0, [1][1][2][1][RTW89_WW][47] = 0, [1][1][2][1][RTW89_WW][51] = 0, - [2][0][2][0][RTW89_WW][3] = 62, - [2][0][2][0][RTW89_WW][11] = 62, - [2][0][2][0][RTW89_WW][18] = 64, + [2][0][2][0][RTW89_WW][3] = 60, + [2][0][2][0][RTW89_WW][11] = 58, + [2][0][2][0][RTW89_WW][18] = 62, [2][0][2][0][RTW89_WW][26] = 64, [2][0][2][0][RTW89_WW][34] = 72, [2][0][2][0][RTW89_WW][41] = 30, - [2][0][2][0][RTW89_WW][49] = 74, + [2][0][2][0][RTW89_WW][49] = 70, [2][1][2][0][RTW89_WW][3] = 0, [2][1][2][0][RTW89_WW][11] = 0, [2][1][2][0][RTW89_WW][18] = 0, @@ -5083,7 +5083,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][1][2][1][RTW89_WW][7] = 0, [3][1][2][1][RTW89_WW][22] = 0, [3][1][2][1][RTW89_WW][45] = 0, - [0][0][1][0][RTW89_FCC][0] = 80, + [0][0][1][0][RTW89_FCC][0] = 76, [0][0][1][0][RTW89_ETSI][0] = 58, [0][0][1][0][RTW89_MKK][0] = 60, [0][0][1][0][RTW89_IC][0] = 62, @@ -5139,7 +5139,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][12] = 58, [0][0][1][0][RTW89_CN][12] = 60, [0][0][1][0][RTW89_UK][12] = 58, - [0][0][1][0][RTW89_FCC][14] = 78, + [0][0][1][0][RTW89_FCC][14] = 74, [0][0][1][0][RTW89_ETSI][14] = 58, [0][0][1][0][RTW89_MKK][14] = 60, [0][0][1][0][RTW89_IC][14] = 64, @@ -5147,10 +5147,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][14] = 58, [0][0][1][0][RTW89_CN][14] = 60, [0][0][1][0][RTW89_UK][14] = 58, - [0][0][1][0][RTW89_FCC][15] = 78, + [0][0][1][0][RTW89_FCC][15] = 74, [0][0][1][0][RTW89_ETSI][15] = 58, [0][0][1][0][RTW89_MKK][15] = 78, - [0][0][1][0][RTW89_IC][15] = 78, + [0][0][1][0][RTW89_IC][15] = 74, [0][0][1][0][RTW89_KCC][15] = 78, [0][0][1][0][RTW89_ACMA][15] = 58, [0][0][1][0][RTW89_CN][15] = 127, @@ -5227,10 +5227,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][33] = 60, [0][0][1][0][RTW89_CN][33] = 127, [0][0][1][0][RTW89_UK][33] = 60, - [0][0][1][0][RTW89_FCC][35] = 72, + [0][0][1][0][RTW89_FCC][35] = 68, [0][0][1][0][RTW89_ETSI][35] = 60, [0][0][1][0][RTW89_MKK][35] = 78, - [0][0][1][0][RTW89_IC][35] = 72, + [0][0][1][0][RTW89_IC][35] = 68, [0][0][1][0][RTW89_KCC][35] = 74, [0][0][1][0][RTW89_ACMA][35] = 60, [0][0][1][0][RTW89_CN][35] = 127, @@ -5283,7 +5283,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][46] = 78, [0][0][1][0][RTW89_CN][46] = 78, [0][0][1][0][RTW89_UK][46] = 58, - [0][0][1][0][RTW89_FCC][48] = 72, + [0][0][1][0][RTW89_FCC][48] = 68, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, [0][0][1][0][RTW89_IC][48] = 127, @@ -5291,7 +5291,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CN][48] = 127, [0][0][1][0][RTW89_UK][48] = 127, - [0][0][1][0][RTW89_FCC][50] = 72, + [0][0][1][0][RTW89_FCC][50] = 68, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, [0][0][1][0][RTW89_IC][50] = 127, @@ -5299,7 +5299,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CN][50] = 127, [0][0][1][0][RTW89_UK][50] = 127, - [0][0][1][0][RTW89_FCC][52] = 72, + [0][0][1][0][RTW89_FCC][52] = 68, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, [0][0][1][0][RTW89_IC][52] = 127, @@ -5531,7 +5531,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][52] = 127, [0][1][1][0][RTW89_CN][52] = 127, [0][1][1][0][RTW89_UK][52] = 127, - [0][0][2][0][RTW89_FCC][0] = 78, + [0][0][2][0][RTW89_FCC][0] = 74, [0][0][2][0][RTW89_ETSI][0] = 62, [0][0][2][0][RTW89_MKK][0] = 62, [0][0][2][0][RTW89_IC][0] = 64, @@ -5587,7 +5587,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][12] = 62, [0][0][2][0][RTW89_CN][12] = 62, [0][0][2][0][RTW89_UK][12] = 62, - [0][0][2][0][RTW89_FCC][14] = 76, + [0][0][2][0][RTW89_FCC][14] = 72, [0][0][2][0][RTW89_ETSI][14] = 62, [0][0][2][0][RTW89_MKK][14] = 62, [0][0][2][0][RTW89_IC][14] = 64, @@ -5595,10 +5595,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][14] = 62, [0][0][2][0][RTW89_CN][14] = 62, [0][0][2][0][RTW89_UK][14] = 62, - [0][0][2][0][RTW89_FCC][15] = 76, + [0][0][2][0][RTW89_FCC][15] = 72, [0][0][2][0][RTW89_ETSI][15] = 60, [0][0][2][0][RTW89_MKK][15] = 78, - [0][0][2][0][RTW89_IC][15] = 76, + [0][0][2][0][RTW89_IC][15] = 72, [0][0][2][0][RTW89_KCC][15] = 78, [0][0][2][0][RTW89_ACMA][15] = 60, [0][0][2][0][RTW89_CN][15] = 127, @@ -5675,10 +5675,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][33] = 62, [0][0][2][0][RTW89_CN][33] = 127, [0][0][2][0][RTW89_UK][33] = 62, - [0][0][2][0][RTW89_FCC][35] = 72, + [0][0][2][0][RTW89_FCC][35] = 68, [0][0][2][0][RTW89_ETSI][35] = 62, [0][0][2][0][RTW89_MKK][35] = 78, - [0][0][2][0][RTW89_IC][35] = 72, + [0][0][2][0][RTW89_IC][35] = 68, [0][0][2][0][RTW89_KCC][35] = 74, [0][0][2][0][RTW89_ACMA][35] = 62, [0][0][2][0][RTW89_CN][35] = 127, @@ -5731,7 +5731,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][46] = 78, [0][0][2][0][RTW89_CN][46] = 78, [0][0][2][0][RTW89_UK][46] = 60, - [0][0][2][0][RTW89_FCC][48] = 74, + [0][0][2][0][RTW89_FCC][48] = 70, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, [0][0][2][0][RTW89_IC][48] = 127, @@ -5739,7 +5739,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CN][48] = 127, [0][0][2][0][RTW89_UK][48] = 127, - [0][0][2][0][RTW89_FCC][50] = 76, + [0][0][2][0][RTW89_FCC][50] = 72, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, [0][0][2][0][RTW89_IC][50] = 127, @@ -5747,7 +5747,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CN][50] = 127, [0][0][2][0][RTW89_UK][50] = 127, - [0][0][2][0][RTW89_FCC][52] = 76, + [0][0][2][0][RTW89_FCC][52] = 72, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, [0][0][2][0][RTW89_IC][52] = 127, @@ -6203,10 +6203,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][52] = 127, [0][1][2][1][RTW89_CN][52] = 127, [0][1][2][1][RTW89_UK][52] = 127, - [1][0][2][0][RTW89_FCC][1] = 68, + [1][0][2][0][RTW89_FCC][1] = 64, [1][0][2][0][RTW89_ETSI][1] = 64, [1][0][2][0][RTW89_MKK][1] = 64, - [1][0][2][0][RTW89_IC][1] = 64, + [1][0][2][0][RTW89_IC][1] = 60, [1][0][2][0][RTW89_KCC][1] = 74, [1][0][2][0][RTW89_ACMA][1] = 64, [1][0][2][0][RTW89_CN][1] = 64, @@ -6227,18 +6227,18 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][9] = 64, [1][0][2][0][RTW89_CN][9] = 64, [1][0][2][0][RTW89_UK][9] = 64, - [1][0][2][0][RTW89_FCC][13] = 66, + [1][0][2][0][RTW89_FCC][13] = 62, [1][0][2][0][RTW89_ETSI][13] = 64, [1][0][2][0][RTW89_MKK][13] = 64, - [1][0][2][0][RTW89_IC][13] = 64, + [1][0][2][0][RTW89_IC][13] = 60, [1][0][2][0][RTW89_KCC][13] = 72, [1][0][2][0][RTW89_ACMA][13] = 64, [1][0][2][0][RTW89_CN][13] = 64, [1][0][2][0][RTW89_UK][13] = 64, - [1][0][2][0][RTW89_FCC][16] = 66, + [1][0][2][0][RTW89_FCC][16] = 62, [1][0][2][0][RTW89_ETSI][16] = 66, [1][0][2][0][RTW89_MKK][16] = 80, - [1][0][2][0][RTW89_IC][16] = 66, + [1][0][2][0][RTW89_IC][16] = 62, [1][0][2][0][RTW89_KCC][16] = 74, [1][0][2][0][RTW89_ACMA][16] = 66, [1][0][2][0][RTW89_CN][16] = 127, @@ -6246,7 +6246,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][20] = 80, [1][0][2][0][RTW89_ETSI][20] = 66, [1][0][2][0][RTW89_MKK][20] = 80, - [1][0][2][0][RTW89_IC][20] = 80, + [1][0][2][0][RTW89_IC][20] = 76, [1][0][2][0][RTW89_KCC][20] = 74, [1][0][2][0][RTW89_ACMA][20] = 66, [1][0][2][0][RTW89_CN][20] = 127, @@ -6267,10 +6267,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][28] = 127, [1][0][2][0][RTW89_CN][28] = 127, [1][0][2][0][RTW89_UK][28] = 66, - [1][0][2][0][RTW89_FCC][32] = 76, + [1][0][2][0][RTW89_FCC][32] = 72, [1][0][2][0][RTW89_ETSI][32] = 66, [1][0][2][0][RTW89_MKK][32] = 80, - [1][0][2][0][RTW89_IC][32] = 76, + [1][0][2][0][RTW89_IC][32] = 72, [1][0][2][0][RTW89_KCC][32] = 78, [1][0][2][0][RTW89_ACMA][32] = 66, [1][0][2][0][RTW89_CN][32] = 127, @@ -6286,7 +6286,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][39] = 84, [1][0][2][0][RTW89_ETSI][39] = 30, [1][0][2][0][RTW89_MKK][39] = 127, - [1][0][2][0][RTW89_IC][39] = 84, + [1][0][2][0][RTW89_IC][39] = 80, [1][0][2][0][RTW89_KCC][39] = 68, [1][0][2][0][RTW89_ACMA][39] = 80, [1][0][2][0][RTW89_CN][39] = 70, @@ -6299,7 +6299,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][43] = 80, [1][0][2][0][RTW89_CN][43] = 80, [1][0][2][0][RTW89_UK][43] = 64, - [1][0][2][0][RTW89_FCC][47] = 84, + [1][0][2][0][RTW89_FCC][47] = 80, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, [1][0][2][0][RTW89_IC][47] = 127, @@ -6307,7 +6307,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CN][47] = 127, [1][0][2][0][RTW89_UK][47] = 127, - [1][0][2][0][RTW89_FCC][51] = 84, + [1][0][2][0][RTW89_FCC][51] = 80, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, [1][0][2][0][RTW89_IC][51] = 127, @@ -6539,26 +6539,26 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][51] = 127, [1][1][2][1][RTW89_CN][51] = 127, [1][1][2][1][RTW89_UK][51] = 127, - [2][0][2][0][RTW89_FCC][3] = 76, + [2][0][2][0][RTW89_FCC][3] = 72, [2][0][2][0][RTW89_ETSI][3] = 64, [2][0][2][0][RTW89_MKK][3] = 62, - [2][0][2][0][RTW89_IC][3] = 64, + [2][0][2][0][RTW89_IC][3] = 60, [2][0][2][0][RTW89_KCC][3] = 72, [2][0][2][0][RTW89_ACMA][3] = 64, [2][0][2][0][RTW89_CN][3] = 64, [2][0][2][0][RTW89_UK][3] = 64, - [2][0][2][0][RTW89_FCC][11] = 64, + [2][0][2][0][RTW89_FCC][11] = 60, [2][0][2][0][RTW89_ETSI][11] = 64, [2][0][2][0][RTW89_MKK][11] = 64, - [2][0][2][0][RTW89_IC][11] = 62, + [2][0][2][0][RTW89_IC][11] = 58, [2][0][2][0][RTW89_KCC][11] = 72, [2][0][2][0][RTW89_ACMA][11] = 64, [2][0][2][0][RTW89_CN][11] = 64, [2][0][2][0][RTW89_UK][11] = 64, - [2][0][2][0][RTW89_FCC][18] = 66, + [2][0][2][0][RTW89_FCC][18] = 62, [2][0][2][0][RTW89_ETSI][18] = 64, [2][0][2][0][RTW89_MKK][18] = 72, - [2][0][2][0][RTW89_IC][18] = 66, + [2][0][2][0][RTW89_IC][18] = 62, [2][0][2][0][RTW89_KCC][18] = 72, [2][0][2][0][RTW89_ACMA][18] = 64, [2][0][2][0][RTW89_CN][18] = 127, @@ -6574,7 +6574,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][34] = 76, [2][0][2][0][RTW89_ETSI][34] = 127, [2][0][2][0][RTW89_MKK][34] = 72, - [2][0][2][0][RTW89_IC][34] = 76, + [2][0][2][0][RTW89_IC][34] = 72, [2][0][2][0][RTW89_KCC][34] = 72, [2][0][2][0][RTW89_ACMA][34] = 72, [2][0][2][0][RTW89_CN][34] = 127, @@ -6582,12 +6582,12 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][41] = 76, [2][0][2][0][RTW89_ETSI][41] = 30, [2][0][2][0][RTW89_MKK][41] = 127, - [2][0][2][0][RTW89_IC][41] = 76, + [2][0][2][0][RTW89_IC][41] = 72, [2][0][2][0][RTW89_KCC][41] = 64, [2][0][2][0][RTW89_ACMA][41] = 72, [2][0][2][0][RTW89_CN][41] = 72, [2][0][2][0][RTW89_UK][41] = 64, - [2][0][2][0][RTW89_FCC][49] = 74, + [2][0][2][0][RTW89_FCC][49] = 70, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, [2][0][2][0][RTW89_IC][49] = 127, @@ -10606,9 +10606,9 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_WW][42] = 30, [0][0][1][0][RTW89_WW][44] = 30, [0][0][1][0][RTW89_WW][46] = 30, - [0][0][1][0][RTW89_WW][48] = 72, - [0][0][1][0][RTW89_WW][50] = 72, - [0][0][1][0][RTW89_WW][52] = 72, + [0][0][1][0][RTW89_WW][48] = 68, + [0][0][1][0][RTW89_WW][50] = 68, + [0][0][1][0][RTW89_WW][52] = 68, [0][1][1][0][RTW89_WW][0] = 0, [0][1][1][0][RTW89_WW][2] = 0, [0][1][1][0][RTW89_WW][4] = 0, @@ -10662,9 +10662,9 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_WW][42] = 30, [0][0][2][0][RTW89_WW][44] = 30, [0][0][2][0][RTW89_WW][46] = 30, - [0][0][2][0][RTW89_WW][48] = 74, - [0][0][2][0][RTW89_WW][50] = 74, - [0][0][2][0][RTW89_WW][52] = 74, + [0][0][2][0][RTW89_WW][48] = 70, + [0][0][2][0][RTW89_WW][50] = 70, + [0][0][2][0][RTW89_WW][52] = 70, [0][1][2][0][RTW89_WW][0] = 0, [0][1][2][0][RTW89_WW][2] = 0, [0][1][2][0][RTW89_WW][4] = 0, @@ -10721,11 +10721,11 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_WW][48] = 0, [0][1][2][1][RTW89_WW][50] = 0, [0][1][2][1][RTW89_WW][52] = 0, - [1][0][2][0][RTW89_WW][1] = 64, + [1][0][2][0][RTW89_WW][1] = 60, [1][0][2][0][RTW89_WW][5] = 62, [1][0][2][0][RTW89_WW][9] = 64, - [1][0][2][0][RTW89_WW][13] = 64, - [1][0][2][0][RTW89_WW][16] = 66, + [1][0][2][0][RTW89_WW][13] = 60, + [1][0][2][0][RTW89_WW][16] = 62, [1][0][2][0][RTW89_WW][20] = 66, [1][0][2][0][RTW89_WW][24] = 66, [1][0][2][0][RTW89_WW][28] = 66, @@ -10733,8 +10733,8 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_WW][36] = 76, [1][0][2][0][RTW89_WW][39] = 30, [1][0][2][0][RTW89_WW][43] = 30, - [1][0][2][0][RTW89_WW][47] = 80, - [1][0][2][0][RTW89_WW][51] = 80, + [1][0][2][0][RTW89_WW][47] = 76, + [1][0][2][0][RTW89_WW][51] = 76, [1][1][2][0][RTW89_WW][1] = 0, [1][1][2][0][RTW89_WW][5] = 0, [1][1][2][0][RTW89_WW][9] = 0, @@ -10763,13 +10763,13 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_WW][43] = 0, [1][1][2][1][RTW89_WW][47] = 0, [1][1][2][1][RTW89_WW][51] = 0, - [2][0][2][0][RTW89_WW][3] = 62, - [2][0][2][0][RTW89_WW][11] = 62, - [2][0][2][0][RTW89_WW][18] = 64, + [2][0][2][0][RTW89_WW][3] = 60, + [2][0][2][0][RTW89_WW][11] = 58, + [2][0][2][0][RTW89_WW][18] = 62, [2][0][2][0][RTW89_WW][26] = 64, [2][0][2][0][RTW89_WW][34] = 68, [2][0][2][0][RTW89_WW][41] = 30, - [2][0][2][0][RTW89_WW][49] = 72, + [2][0][2][0][RTW89_WW][49] = 68, [2][1][2][0][RTW89_WW][3] = 0, [2][1][2][0][RTW89_WW][11] = 0, [2][1][2][0][RTW89_WW][18] = 0, @@ -10793,7 +10793,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [3][1][2][1][RTW89_WW][7] = 0, [3][1][2][1][RTW89_WW][22] = 0, [3][1][2][1][RTW89_WW][45] = 0, - [0][0][1][0][RTW89_FCC][0] = 78, + [0][0][1][0][RTW89_FCC][0] = 74, [0][0][1][0][RTW89_ETSI][0] = 58, [0][0][1][0][RTW89_MKK][0] = 60, [0][0][1][0][RTW89_IC][0] = 62, @@ -10849,7 +10849,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][12] = 58, [0][0][1][0][RTW89_CN][12] = 60, [0][0][1][0][RTW89_UK][12] = 58, - [0][0][1][0][RTW89_FCC][14] = 76, + [0][0][1][0][RTW89_FCC][14] = 72, [0][0][1][0][RTW89_ETSI][14] = 58, [0][0][1][0][RTW89_MKK][14] = 60, [0][0][1][0][RTW89_IC][14] = 62, @@ -10857,10 +10857,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][14] = 58, [0][0][1][0][RTW89_CN][14] = 60, [0][0][1][0][RTW89_UK][14] = 58, - [0][0][1][0][RTW89_FCC][15] = 76, + [0][0][1][0][RTW89_FCC][15] = 72, [0][0][1][0][RTW89_ETSI][15] = 58, [0][0][1][0][RTW89_MKK][15] = 74, - [0][0][1][0][RTW89_IC][15] = 76, + [0][0][1][0][RTW89_IC][15] = 72, [0][0][1][0][RTW89_KCC][15] = 74, [0][0][1][0][RTW89_ACMA][15] = 58, [0][0][1][0][RTW89_CN][15] = 127, @@ -10937,10 +10937,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][33] = 60, [0][0][1][0][RTW89_CN][33] = 127, [0][0][1][0][RTW89_UK][33] = 60, - [0][0][1][0][RTW89_FCC][35] = 70, + [0][0][1][0][RTW89_FCC][35] = 66, [0][0][1][0][RTW89_ETSI][35] = 60, [0][0][1][0][RTW89_MKK][35] = 74, - [0][0][1][0][RTW89_IC][35] = 70, + [0][0][1][0][RTW89_IC][35] = 66, [0][0][1][0][RTW89_KCC][35] = 74, [0][0][1][0][RTW89_ACMA][35] = 60, [0][0][1][0][RTW89_CN][35] = 127, @@ -10993,7 +10993,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][46] = 74, [0][0][1][0][RTW89_CN][46] = 74, [0][0][1][0][RTW89_UK][46] = 58, - [0][0][1][0][RTW89_FCC][48] = 72, + [0][0][1][0][RTW89_FCC][48] = 68, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, [0][0][1][0][RTW89_IC][48] = 127, @@ -11001,7 +11001,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CN][48] = 127, [0][0][1][0][RTW89_UK][48] = 127, - [0][0][1][0][RTW89_FCC][50] = 72, + [0][0][1][0][RTW89_FCC][50] = 68, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, [0][0][1][0][RTW89_IC][50] = 127, @@ -11009,7 +11009,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CN][50] = 127, [0][0][1][0][RTW89_UK][50] = 127, - [0][0][1][0][RTW89_FCC][52] = 72, + [0][0][1][0][RTW89_FCC][52] = 68, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, [0][0][1][0][RTW89_IC][52] = 127, @@ -11241,7 +11241,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_ACMA][52] = 127, [0][1][1][0][RTW89_CN][52] = 127, [0][1][1][0][RTW89_UK][52] = 127, - [0][0][2][0][RTW89_FCC][0] = 76, + [0][0][2][0][RTW89_FCC][0] = 72, [0][0][2][0][RTW89_ETSI][0] = 62, [0][0][2][0][RTW89_MKK][0] = 62, [0][0][2][0][RTW89_IC][0] = 64, @@ -11297,7 +11297,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][12] = 62, [0][0][2][0][RTW89_CN][12] = 62, [0][0][2][0][RTW89_UK][12] = 62, - [0][0][2][0][RTW89_FCC][14] = 74, + [0][0][2][0][RTW89_FCC][14] = 70, [0][0][2][0][RTW89_ETSI][14] = 62, [0][0][2][0][RTW89_MKK][14] = 62, [0][0][2][0][RTW89_IC][14] = 64, @@ -11305,10 +11305,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][14] = 62, [0][0][2][0][RTW89_CN][14] = 62, [0][0][2][0][RTW89_UK][14] = 62, - [0][0][2][0][RTW89_FCC][15] = 74, + [0][0][2][0][RTW89_FCC][15] = 70, [0][0][2][0][RTW89_ETSI][15] = 60, [0][0][2][0][RTW89_MKK][15] = 74, - [0][0][2][0][RTW89_IC][15] = 74, + [0][0][2][0][RTW89_IC][15] = 70, [0][0][2][0][RTW89_KCC][15] = 74, [0][0][2][0][RTW89_ACMA][15] = 60, [0][0][2][0][RTW89_CN][15] = 127, @@ -11385,10 +11385,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][33] = 62, [0][0][2][0][RTW89_CN][33] = 127, [0][0][2][0][RTW89_UK][33] = 62, - [0][0][2][0][RTW89_FCC][35] = 72, + [0][0][2][0][RTW89_FCC][35] = 68, [0][0][2][0][RTW89_ETSI][35] = 62, [0][0][2][0][RTW89_MKK][35] = 74, - [0][0][2][0][RTW89_IC][35] = 72, + [0][0][2][0][RTW89_IC][35] = 68, [0][0][2][0][RTW89_KCC][35] = 74, [0][0][2][0][RTW89_ACMA][35] = 62, [0][0][2][0][RTW89_CN][35] = 127, @@ -11441,7 +11441,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][46] = 74, [0][0][2][0][RTW89_CN][46] = 74, [0][0][2][0][RTW89_UK][46] = 60, - [0][0][2][0][RTW89_FCC][48] = 74, + [0][0][2][0][RTW89_FCC][48] = 70, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, [0][0][2][0][RTW89_IC][48] = 127, @@ -11449,7 +11449,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CN][48] = 127, [0][0][2][0][RTW89_UK][48] = 127, - [0][0][2][0][RTW89_FCC][50] = 74, + [0][0][2][0][RTW89_FCC][50] = 70, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, [0][0][2][0][RTW89_IC][50] = 127, @@ -11457,7 +11457,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CN][50] = 127, [0][0][2][0][RTW89_UK][50] = 127, - [0][0][2][0][RTW89_FCC][52] = 74, + [0][0][2][0][RTW89_FCC][52] = 70, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, [0][0][2][0][RTW89_IC][52] = 127, @@ -11913,10 +11913,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_ACMA][52] = 127, [0][1][2][1][RTW89_CN][52] = 127, [0][1][2][1][RTW89_UK][52] = 127, - [1][0][2][0][RTW89_FCC][1] = 66, + [1][0][2][0][RTW89_FCC][1] = 62, [1][0][2][0][RTW89_ETSI][1] = 64, [1][0][2][0][RTW89_MKK][1] = 64, - [1][0][2][0][RTW89_IC][1] = 64, + [1][0][2][0][RTW89_IC][1] = 60, [1][0][2][0][RTW89_KCC][1] = 74, [1][0][2][0][RTW89_ACMA][1] = 64, [1][0][2][0][RTW89_CN][1] = 64, @@ -11937,18 +11937,18 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][9] = 64, [1][0][2][0][RTW89_CN][9] = 64, [1][0][2][0][RTW89_UK][9] = 64, - [1][0][2][0][RTW89_FCC][13] = 64, + [1][0][2][0][RTW89_FCC][13] = 60, [1][0][2][0][RTW89_ETSI][13] = 64, [1][0][2][0][RTW89_MKK][13] = 64, - [1][0][2][0][RTW89_IC][13] = 64, + [1][0][2][0][RTW89_IC][13] = 60, [1][0][2][0][RTW89_KCC][13] = 72, [1][0][2][0][RTW89_ACMA][13] = 64, [1][0][2][0][RTW89_CN][13] = 64, [1][0][2][0][RTW89_UK][13] = 64, - [1][0][2][0][RTW89_FCC][16] = 66, + [1][0][2][0][RTW89_FCC][16] = 62, [1][0][2][0][RTW89_ETSI][16] = 66, [1][0][2][0][RTW89_MKK][16] = 76, - [1][0][2][0][RTW89_IC][16] = 66, + [1][0][2][0][RTW89_IC][16] = 62, [1][0][2][0][RTW89_KCC][16] = 74, [1][0][2][0][RTW89_ACMA][16] = 66, [1][0][2][0][RTW89_CN][16] = 127, @@ -11956,7 +11956,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][20] = 80, [1][0][2][0][RTW89_ETSI][20] = 66, [1][0][2][0][RTW89_MKK][20] = 76, - [1][0][2][0][RTW89_IC][20] = 80, + [1][0][2][0][RTW89_IC][20] = 76, [1][0][2][0][RTW89_KCC][20] = 74, [1][0][2][0][RTW89_ACMA][20] = 66, [1][0][2][0][RTW89_CN][20] = 127, @@ -11977,10 +11977,10 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][28] = 127, [1][0][2][0][RTW89_CN][28] = 127, [1][0][2][0][RTW89_UK][28] = 66, - [1][0][2][0][RTW89_FCC][32] = 74, + [1][0][2][0][RTW89_FCC][32] = 70, [1][0][2][0][RTW89_ETSI][32] = 66, [1][0][2][0][RTW89_MKK][32] = 76, - [1][0][2][0][RTW89_IC][32] = 74, + [1][0][2][0][RTW89_IC][32] = 70, [1][0][2][0][RTW89_KCC][32] = 76, [1][0][2][0][RTW89_ACMA][32] = 66, [1][0][2][0][RTW89_CN][32] = 127, @@ -11996,7 +11996,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][39] = 80, [1][0][2][0][RTW89_ETSI][39] = 30, [1][0][2][0][RTW89_MKK][39] = 127, - [1][0][2][0][RTW89_IC][39] = 80, + [1][0][2][0][RTW89_IC][39] = 76, [1][0][2][0][RTW89_KCC][39] = 68, [1][0][2][0][RTW89_ACMA][39] = 76, [1][0][2][0][RTW89_CN][39] = 70, @@ -12009,7 +12009,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][43] = 76, [1][0][2][0][RTW89_CN][43] = 76, [1][0][2][0][RTW89_UK][43] = 64, - [1][0][2][0][RTW89_FCC][47] = 80, + [1][0][2][0][RTW89_FCC][47] = 76, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, [1][0][2][0][RTW89_IC][47] = 127, @@ -12017,7 +12017,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CN][47] = 127, [1][0][2][0][RTW89_UK][47] = 127, - [1][0][2][0][RTW89_FCC][51] = 80, + [1][0][2][0][RTW89_FCC][51] = 76, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, [1][0][2][0][RTW89_IC][51] = 127, @@ -12249,26 +12249,26 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_ACMA][51] = 127, [1][1][2][1][RTW89_CN][51] = 127, [1][1][2][1][RTW89_UK][51] = 127, - [2][0][2][0][RTW89_FCC][3] = 72, + [2][0][2][0][RTW89_FCC][3] = 68, [2][0][2][0][RTW89_ETSI][3] = 64, [2][0][2][0][RTW89_MKK][3] = 62, - [2][0][2][0][RTW89_IC][3] = 64, + [2][0][2][0][RTW89_IC][3] = 60, [2][0][2][0][RTW89_KCC][3] = 68, [2][0][2][0][RTW89_ACMA][3] = 64, [2][0][2][0][RTW89_CN][3] = 64, [2][0][2][0][RTW89_UK][3] = 64, - [2][0][2][0][RTW89_FCC][11] = 62, + [2][0][2][0][RTW89_FCC][11] = 58, [2][0][2][0][RTW89_ETSI][11] = 64, [2][0][2][0][RTW89_MKK][11] = 64, - [2][0][2][0][RTW89_IC][11] = 62, + [2][0][2][0][RTW89_IC][11] = 58, [2][0][2][0][RTW89_KCC][11] = 68, [2][0][2][0][RTW89_ACMA][11] = 64, [2][0][2][0][RTW89_CN][11] = 64, [2][0][2][0][RTW89_UK][11] = 64, - [2][0][2][0][RTW89_FCC][18] = 66, + [2][0][2][0][RTW89_FCC][18] = 62, [2][0][2][0][RTW89_ETSI][18] = 64, [2][0][2][0][RTW89_MKK][18] = 68, - [2][0][2][0][RTW89_IC][18] = 66, + [2][0][2][0][RTW89_IC][18] = 62, [2][0][2][0][RTW89_KCC][18] = 68, [2][0][2][0][RTW89_ACMA][18] = 64, [2][0][2][0][RTW89_CN][18] = 127, @@ -12284,7 +12284,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][34] = 72, [2][0][2][0][RTW89_ETSI][34] = 127, [2][0][2][0][RTW89_MKK][34] = 68, - [2][0][2][0][RTW89_IC][34] = 72, + [2][0][2][0][RTW89_IC][34] = 68, [2][0][2][0][RTW89_KCC][34] = 68, [2][0][2][0][RTW89_ACMA][34] = 68, [2][0][2][0][RTW89_CN][34] = 127, @@ -12292,12 +12292,12 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][41] = 72, [2][0][2][0][RTW89_ETSI][41] = 30, [2][0][2][0][RTW89_MKK][41] = 127, - [2][0][2][0][RTW89_IC][41] = 72, + [2][0][2][0][RTW89_IC][41] = 68, [2][0][2][0][RTW89_KCC][41] = 64, [2][0][2][0][RTW89_ACMA][41] = 68, [2][0][2][0][RTW89_CN][41] = 68, [2][0][2][0][RTW89_UK][41] = 64, - [2][0][2][0][RTW89_FCC][49] = 72, + [2][0][2][0][RTW89_FCC][49] = 68, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, [2][0][2][0][RTW89_IC][49] = 127, -- cgit v1.2.3 From b686bc67e0437eb5791bca6ec89479470ef40513 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Jun 2023 21:04:40 +0800 Subject: wifi: rtw89: 8851b: rfk: add LCK track LCK is short for LC Tank calibration. To keep RF performance, do this calibration if difference of thermal value is over a threshold. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230615130442.18116-4-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 1 + drivers/net/wireless/realtek/rtw89/rtw8851b.c | 2 + drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 65 ++++++++++++++++++++++- drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h | 2 + 4 files changed, 69 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index b6ffa923133d..c515bc2a10af 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3834,6 +3834,7 @@ #define RR_LCKST_BIN BIT(0) #define RR_LCK_TRG 0xd3 #define RR_LCK_TRGSEL BIT(8) +#define RR_LCK_ST BIT(4) #define RR_MMD 0xd5 #define RR_MMD_RST_EN BIT(8) #define RR_MMD_RST_SYN BIT(6) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index c4254e051be0..3a912896031c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -1546,6 +1546,7 @@ static void rtw8851b_rfk_init(struct rtw89_dev *rtwdev) { rtwdev->is_tssi_mode[RF_PATH_A] = false; rtwdev->is_tssi_mode[RF_PATH_B] = false; + rtw8851b_lck_init(rtwdev); rtw8851b_dpk_init(rtwdev); rtw8851b_aack(rtwdev); @@ -1578,6 +1579,7 @@ static void rtw8851b_rfk_scan(struct rtw89_dev *rtwdev, bool start) static void rtw8851b_rfk_track(struct rtw89_dev *rtwdev) { rtw8851b_dpk_track(rtwdev); + rtw8851b_lck_track(rtwdev); } static u32 rtw8851b_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 48f1bcc46eda..25dda3ee27a6 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -118,6 +118,8 @@ static const u32 dpk_kip_reg[DPK_KIP_REG_NUM_8851B] = { 0x813c, 0x8124, 0xc0ec, 0xc0e8, 0xc0c4, 0xc0d4, 0xc0d8}; static const u32 dpk_rf_reg[DPK_RF_REG_NUM_8851B] = {0xde, 0x8f, 0x5, 0x10005}; +static void _set_ch(struct rtw89_dev *rtwdev, u32 val); + static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { return RF_A; @@ -3133,7 +3135,7 @@ void rtw8851b_dpk_init(struct rtw89_dev *rtwdev) void rtw8851b_aack(struct rtw89_dev *rtwdev) { - u32 tmp05, ib[4]; + u32 tmp05, tmpd3, ib[4]; u32 tmp; int ret; int rek; @@ -3142,8 +3144,10 @@ void rtw8851b_aack(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]DO AACK\n"); tmp05 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK); + tmpd3 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RFREG_MASK); rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_MASK, 0x3); rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_ST, 0x0); for (rek = 0; rek < 4; rek++) { rtw89_write_rf(rtwdev, RF_PATH_A, RR_AACK, RFREG_MASK, 0x8201e); @@ -3171,6 +3175,65 @@ void rtw8851b_aack(struct rtw89_dev *rtwdev) rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]AACK rek = %d\n", rek); rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, tmp05); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RFREG_MASK, tmpd3); +} + +static void _lck_keep_thermal(struct rtw89_dev *rtwdev) +{ + struct rtw89_lck_info *lck = &rtwdev->lck; + + lck->thermal[RF_PATH_A] = + ewma_thermal_read(&rtwdev->phystat.avg_thermal[RF_PATH_A]); + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[LCK] path=%d thermal=0x%x", RF_PATH_A, lck->thermal[RF_PATH_A]); +} + +static void rtw8851b_lck(struct rtw89_dev *rtwdev) +{ + u32 tmp05, tmp18, tmpd3; + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[LCK]DO LCK\n"); + + tmp05 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK); + tmp18 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK); + tmpd3 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RFREG_MASK); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_MASK, 0x3); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RR_LCK_TRGSEL, 0x1); + + _set_ch(rtwdev, tmp18); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LCK_TRG, RFREG_MASK, tmpd3); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RSV1, RFREG_MASK, tmp05); + + _lck_keep_thermal(rtwdev); +} + +#define RTW8851B_LCK_TH 8 + +void rtw8851b_lck_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_lck_info *lck = &rtwdev->lck; + u8 cur_thermal; + int delta; + + cur_thermal = + ewma_thermal_read(&rtwdev->phystat.avg_thermal[RF_PATH_A]); + delta = abs((int)cur_thermal - lck->thermal[RF_PATH_A]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK, + "[LCK] path=%d current thermal=0x%x delta=0x%x\n", + RF_PATH_A, cur_thermal, delta); + + if (delta >= RTW8851B_LCK_TH) { + rtw8851b_aack(rtwdev); + rtw8851b_lck(rtwdev); + } +} + +void rtw8851b_lck_init(struct rtw89_dev *rtwdev) +{ + _lck_keep_thermal(rtwdev); } void rtw8851b_rck(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h index bf0c79d58a71..b66a23d6d367 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.h @@ -8,6 +8,8 @@ #include "core.h" void rtw8851b_aack(struct rtw89_dev *rtwdev); +void rtw8851b_lck_init(struct rtw89_dev *rtwdev); +void rtw8851b_lck_track(struct rtw89_dev *rtwdev); void rtw8851b_rck(struct rtw89_dev *rtwdev); void rtw8851b_dack(struct rtw89_dev *rtwdev); void rtw8851b_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); -- cgit v1.2.3 From 76a7c7acaa78b1a4ab59868808fadbeb7a939b81 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Jun 2023 21:04:41 +0800 Subject: wifi: rtw89: 8851b: rfk: update IQK to version 0x8 The main change is to adjust RX calibration groups from {0,1,2,3} to {0,2} in 5 GHz, so reduce elements from 4 to 2, and use index to iterate them. Meanwhile, always do RX narrowband calibration (ID_NBRXK) for each group. NCTL is used to assist IQK, so also update NCTL to 0x6 along with internal tag HALRF_029_00_103. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230615130442.18116-5-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c | 115 +++++++++++---------- .../net/wireless/realtek/rtw89/rtw8851b_table.c | 2 +- 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index 25dda3ee27a6..a221f94627f5 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -17,6 +17,7 @@ #define DPK_RF_REG_NUM_8851B 4 #define DPK_KSET_NUM 4 #define RTW8851B_RXK_GROUP_NR 4 +#define RTW8851B_RXK_GROUP_IDX_NR 2 #define RTW8851B_TXK_GROUP_NR 1 #define RTW8851B_IQK_VER 0x2a #define RTW8851B_IQK_SS 1 @@ -95,9 +96,9 @@ static const u32 _tssi_de_mcs_10m[RF_PATH_NUM_8851B] = {0x5830}; static const u32 g_idxrxgain[RTW8851B_RXK_GROUP_NR] = {0x10e, 0x116, 0x28e, 0x296}; static const u32 g_idxattc2[RTW8851B_RXK_GROUP_NR] = {0x0, 0xf, 0x0, 0xf}; static const u32 g_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x0, 0x1, 0x2, 0x3}; -static const u32 a_idxrxgain[RTW8851B_RXK_GROUP_NR] = {0x10C, 0x112, 0x28c, 0x292}; -static const u32 a_idxattc2[RTW8851B_RXK_GROUP_NR] = {0xf, 0xf, 0xf, 0xf}; -static const u32 a_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x4, 0x5, 0x6, 0x7}; +static const u32 a_idxrxgain[RTW8851B_RXK_GROUP_IDX_NR] = {0x10C, 0x28c}; +static const u32 a_idxattc2[RTW8851B_RXK_GROUP_IDX_NR] = {0xf, 0xf}; +static const u32 a_idxrxagc[RTW8851B_RXK_GROUP_IDX_NR] = {0x4, 0x6}; static const u32 a_power_range[RTW8851B_TXK_GROUP_NR] = {0x0}; static const u32 a_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; static const u32 a_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x0a}; @@ -107,7 +108,7 @@ static const u32 g_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; static const u32 g_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x10}; static const u32 g_itqt[RTW8851B_TXK_GROUP_NR] = {0x12}; -static const u32 rtw8851b_backup_bb_regs[] = {0xc0ec, 0xc0e8}; +static const u32 rtw8851b_backup_bb_regs[] = {0xc0d4, 0xc0d8, 0xc0c4, 0xc0ec, 0xc0e8}; static const u32 rtw8851b_backup_rf_regs[] = { 0xef, 0xde, 0x0, 0x1e, 0x2, 0x85, 0x90, 0x5}; @@ -120,6 +121,17 @@ static const u32 dpk_rf_reg[DPK_RF_REG_NUM_8851B] = {0xde, 0x8f, 0x5, 0x10005}; static void _set_ch(struct rtw89_dev *rtwdev, u32 val); +static u8 _rxk_5ghz_group_from_idx(u8 idx) +{ + /* There are four RXK groups (RTW8851B_RXK_GROUP_NR), but only group 0 + * and 2 are used in 5 GHz band, so reduce elements to 2. + */ + if (idx < RTW8851B_RXK_GROUP_IDX_NR) + return idx * 2; + + return 0; +} + static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { return RF_A; @@ -786,17 +798,11 @@ static bool _rxk_2g_group_sel(struct rtw89_dev *rtwdev, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD), rtw89_read_rf(rtwdev, path, RR_MOD, 0x003e0)); - if (gp == 0x3) { - rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); - rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); - notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); - iqk_info->nb_rxcfir[path] = - rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; - - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, - rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); - } + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXK); @@ -834,15 +840,18 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, bool kfail = false; bool notready; u32 rf_0; + u8 idx; u8 gp; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0; gp < RTW8851B_RXK_GROUP_NR; gp++) { + for (idx = 0; idx < RTW8851B_RXK_GROUP_IDX_NR; idx++) { + gp = _rxk_5ghz_group_from_idx(idx); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, 0x03ff0, a_idxrxgain[gp]); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[idx]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[idx]); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); @@ -852,7 +861,7 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, fsleep(100); rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); - rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[idx]); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); @@ -861,17 +870,15 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD), rtw89_read_rf(rtwdev, path, RR_MOD, RR_MOD_RXB)); - if (gp == 0x3) { - rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); - rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); - notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); - iqk_info->nb_rxcfir[path] = - rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, - rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); - } + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXK); @@ -908,14 +915,17 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; bool kfail = false; bool notready; - u8 gp = 0x3; + u8 idx = 0x1; u32 rf_0; + u8 gp; + + gp = _rxk_5ghz_group_from_idx(idx); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[gp]); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[idx]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[idx]); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); @@ -925,7 +935,7 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, fsleep(100); rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); - rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[idx]); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); @@ -934,17 +944,15 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD), rtw89_read_rf(rtwdev, path, RR_MOD, 0x003e0)); - if (gp == 0x3) { - rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); - rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); - notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); - iqk_info->nb_rxcfir[path] = - rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, - rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); - } + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, WBRXK 0x8008 = 0x%x\n", path, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); @@ -998,17 +1006,15 @@ static bool _iqk_2g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, path, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD), rtw89_read_rf(rtwdev, path, RR_MOD, 0x003e0)); - if (gp == 0x3) { - rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); - rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); - notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); - iqk_info->nb_rxcfir[path] = - rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; + rtw89_write_rf(rtwdev, path, RR_RXKPLL, RR_RXKPLL_OFF, 0x13); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x011); + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBRXK); + iqk_info->nb_rxcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_RXIQC, MASKDWORD) | 0x2; - rtw89_debug(rtwdev, RTW89_DBG_RFK, - "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, - rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); - } + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[IQK]S%x, NBRXK 0x8008 = 0x%x\n", path, + rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, WBRXK 0x8008 = 0x%x\n", path, rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, MASKDWORD)); @@ -1516,6 +1522,9 @@ static void _iqk_restore(struct rtw89_dev *rtwdev, u8 path) fail = _iqk_check_cal(rtwdev, path); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] restore fail=%d\n", fail); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RR_LUTWE_LOK, 0x0); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTDBG, RR_LUTDBG_TIA, 0x0); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); rtw89_phy_write32_mask(rtwdev, R_NCTL_RPT, MASKDWORD, 0x00000000); rtw89_phy_write32_mask(rtwdev, R_KIP_SYSCFG, MASKDWORD, 0x80000000); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index bda68dbc8b7b..828beb0e5f7e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -2322,7 +2322,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8144, 0x0b040b03}, {0x8148, 0x07020b04}, {0x814c, 0x07020b04}, - {0x8150, 0xe4e40000}, + {0x8150, 0xa0a00000}, {0x8158, 0xffffffff}, {0x815c, 0xffffffff}, {0x8160, 0xffffffff}, -- cgit v1.2.3 From 076031a09ae9e9394a56805aab92973612763d7e Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Thu, 15 Jun 2023 21:04:42 +0800 Subject: wifi: rtw89: 8851b: configure to force 1 TX power value RTL8851B is a chip with only single RF path, and it must use 1 TX power value for transmission, so force 1 TX power value to prevent hardware logic gets wrong TX power values randomly in certain samples. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230615130442.18116-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/reg.h | 22 ++++++++++++++++++++++ drivers/net/wireless/realtek/rtw89/rtw8851b.c | 3 +++ 2 files changed, 25 insertions(+) diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index c515bc2a10af..55595fde7494 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -3333,6 +3333,28 @@ #define R_AX_PWR_UL_CTRL2 0xD248 #define B_AX_PWR_UL_CFO_MASK GENMASK(2, 0) #define B_AX_PWR_UL_CTRL2_MASK 0x07700007 + +#define R_AX_PWR_NORM_FORCE1 0xD260 +#define R_AX_PWR_NORM_FORCE1_C1 0xF260 +#define B_AX_TXAGC_BF_PWR_BOOST_FORCE_VAL_EN BIT(29) +#define B_AX_TXAGC_BF_PWR_BOOST_FORCE_VAL_MASK GENMASK(28, 24) +#define B_AX_FORCE_HE_ER_SU_EN_EN BIT(23) +#define B_AX_FORCE_HE_ER_SU_EN_VALUE BIT(22) +#define B_AX_FORCE_MACID_CCA_TH_EN_EN BIT(21) +#define B_AX_FORCE_MACID_CCA_TH_EN_VALUE BIT(20) +#define B_AX_FORCE_BT_GRANT_EN BIT(19) +#define B_AX_FORCE_BT_GRANT_VALUE BIT(18) +#define B_AX_FORCE_RX_LTE_EN BIT(17) +#define B_AX_FORCE_RX_LTE_VALUE BIT(16) +#define B_AX_FORCE_TXBF_EN_EN BIT(15) +#define B_AX_FORCE_TXBF_EN_VALUE BIT(14) +#define B_AX_FORCE_TXSC_EN BIT(13) +#define B_AX_FORCE_TXSC_VALUE_MASK GENMASK(12, 9) +#define B_AX_FORCE_NTX_EN BIT(6) +#define B_AX_FORCE_NTX_VALUE BIT(5) +#define B_AX_FORCE_PWR_MODE_EN BIT(3) +#define B_AX_FORCE_PWR_MODE_VALUE_MASK GENMASK(2, 0) + #define R_AX_PWR_UL_TB_CTRL 0xD288 #define B_AX_PWR_UL_TB_CTRL_EN BIT(31) #define R_AX_PWR_UL_TB_1T 0xD28C diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 3a912896031c..c3ffcb645ebf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -1442,6 +1442,9 @@ static void rtw8851b_bb_sethw(struct rtw89_dev *rtwdev) rtw8851b_bb_macid_ctrl_init(rtwdev, RTW89_PHY_0); rtw8851b_bb_gpio_init(rtwdev); + rtw89_write32_clr(rtwdev, R_AX_PWR_NORM_FORCE1, B_AX_FORCE_NTX_VALUE); + rtw89_write32_set(rtwdev, R_AX_PWR_NORM_FORCE1, B_AX_FORCE_NTX_EN); + /* read these registers after loading BB parameters */ gain->offset_base[RTW89_PHY_0] = rtw89_phy_read32_mask(rtwdev, R_P0_RPL1, B_P0_RPL1_BIAS_MASK); -- cgit v1.2.3 From b4a283fb6227fa01cdfb4bec891ded3e32b4a287 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Fri, 16 Jun 2023 14:05:23 +0800 Subject: wifi: rtw89: TX power stuffs replace confusing naming of _max with _num Some old declarations about TX power stuffs were named with confusing `_max`. But, they mean "the number of". So we change them to be named with `_num`. (No logic is changed.) Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616060523.28396-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 34 +++++++++--------- drivers/net/wireless/realtek/rtw89/phy.c | 40 +++++++++++----------- .../net/wireless/realtek/rtw89/rtw8851b_table.c | 2 +- .../net/wireless/realtek/rtw89/rtw8851b_table.h | 2 +- .../net/wireless/realtek/rtw89/rtw8852b_table.c | 2 +- .../net/wireless/realtek/rtw89/rtw8852b_table.h | 2 +- .../net/wireless/realtek/rtw89/rtw8852c_table.c | 2 +- .../net/wireless/realtek/rtw89/rtw8852c_table.h | 2 +- 8 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 0f7ca12e4b34..c09c4b99af94 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -251,7 +251,7 @@ enum rtw89_band { RTW89_BAND_2G = 0, RTW89_BAND_5G = 1, RTW89_BAND_6G = 2, - RTW89_BAND_MAX, + RTW89_BAND_NUM, }; enum rtw89_hw_rate { @@ -434,27 +434,27 @@ enum rtw89_rate_section { RTW89_RS_MCS, /* for HT/VHT/HE */ RTW89_RS_HEDCM, RTW89_RS_OFFSET, - RTW89_RS_MAX, + RTW89_RS_NUM, RTW89_RS_LMT_NUM = RTW89_RS_MCS + 1, RTW89_RS_TX_SHAPE_NUM = RTW89_RS_OFDM + 1, }; -enum rtw89_rate_max { - RTW89_RATE_CCK_MAX = 4, - RTW89_RATE_OFDM_MAX = 8, - RTW89_RATE_MCS_MAX = 12, - RTW89_RATE_HEDCM_MAX = 4, /* for HEDCM MCS0/1/3/4 */ - RTW89_RATE_OFFSET_MAX = 5, /* for HE(HEDCM)/VHT/HT/OFDM/CCK offset */ +enum rtw89_rate_num { + RTW89_RATE_CCK_NUM = 4, + RTW89_RATE_OFDM_NUM = 8, + RTW89_RATE_MCS_NUM = 12, + RTW89_RATE_HEDCM_NUM = 4, /* for HEDCM MCS0/1/3/4 */ + RTW89_RATE_OFFSET_NUM = 5, /* for HE(HEDCM)/VHT/HT/OFDM/CCK offset */ }; enum rtw89_nss { RTW89_NSS_1 = 0, RTW89_NSS_2 = 1, /* HE DCM only support 1ss and 2ss */ - RTW89_NSS_HEDCM_MAX = RTW89_NSS_2 + 1, + RTW89_NSS_HEDCM_NUM = RTW89_NSS_2 + 1, RTW89_NSS_3 = 2, RTW89_NSS_4 = 3, - RTW89_NSS_MAX, + RTW89_NSS_NUM, }; enum rtw89_ntx { @@ -512,11 +512,11 @@ enum rtw89_fw_pkt_ofld_type { }; struct rtw89_txpwr_byrate { - s8 cck[RTW89_RATE_CCK_MAX]; - s8 ofdm[RTW89_RATE_OFDM_MAX]; - s8 mcs[RTW89_NSS_MAX][RTW89_RATE_MCS_MAX]; - s8 hedcm[RTW89_NSS_HEDCM_MAX][RTW89_RATE_HEDCM_MAX]; - s8 offset[RTW89_RATE_OFFSET_MAX]; + s8 cck[RTW89_RATE_CCK_NUM]; + s8 ofdm[RTW89_RATE_OFDM_NUM]; + s8 mcs[RTW89_NSS_NUM][RTW89_RATE_MCS_NUM]; + s8 hedcm[RTW89_NSS_HEDCM_NUM][RTW89_RATE_HEDCM_NUM]; + s8 offset[RTW89_RATE_OFFSET_NUM]; }; enum rtw89_bandwidth_section_num { @@ -3815,7 +3815,7 @@ struct rtw89_power_trim_info { struct rtw89_regd { char alpha2[3]; - u8 txpwr_regd[RTW89_BAND_MAX]; + u8 txpwr_regd[RTW89_BAND_NUM]; }; struct rtw89_regulatory_info { @@ -4111,7 +4111,7 @@ struct rtw89_dev { bool is_bt_iqk_timeout; struct rtw89_fem_info fem; - struct rtw89_txpwr_byrate byr[RTW89_BAND_MAX]; + struct rtw89_txpwr_byrate byr[RTW89_BAND_NUM]; struct rtw89_tssi_info tssi; struct rtw89_power_trim_info pwr_trim; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index e94390b24824..fb15c852fdd4 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -1494,19 +1494,19 @@ void rtw89_phy_write_reg3_tbl(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_phy_write_reg3_tbl); -static const u8 rtw89_rs_idx_max[] = { - [RTW89_RS_CCK] = RTW89_RATE_CCK_MAX, - [RTW89_RS_OFDM] = RTW89_RATE_OFDM_MAX, - [RTW89_RS_MCS] = RTW89_RATE_MCS_MAX, - [RTW89_RS_HEDCM] = RTW89_RATE_HEDCM_MAX, - [RTW89_RS_OFFSET] = RTW89_RATE_OFFSET_MAX, +static const u8 rtw89_rs_idx_num[] = { + [RTW89_RS_CCK] = RTW89_RATE_CCK_NUM, + [RTW89_RS_OFDM] = RTW89_RATE_OFDM_NUM, + [RTW89_RS_MCS] = RTW89_RATE_MCS_NUM, + [RTW89_RS_HEDCM] = RTW89_RATE_HEDCM_NUM, + [RTW89_RS_OFFSET] = RTW89_RATE_OFFSET_NUM, }; -static const u8 rtw89_rs_nss_max[] = { +static const u8 rtw89_rs_nss_num[] = { [RTW89_RS_CCK] = 1, [RTW89_RS_OFDM] = 1, - [RTW89_RS_MCS] = RTW89_NSS_MAX, - [RTW89_RS_HEDCM] = RTW89_NSS_HEDCM_MAX, + [RTW89_RS_MCS] = RTW89_NSS_NUM, + [RTW89_RS_HEDCM] = RTW89_NSS_HEDCM_NUM, [RTW89_RS_OFFSET] = 1, }; @@ -1519,9 +1519,9 @@ static const u8 _byr_of_rs[] = { }; #define _byr_seek(rs, raw) ((s8 *)(raw) + _byr_of_rs[rs]) -#define _byr_idx(rs, nss, idx) ((nss) * rtw89_rs_idx_max[rs] + (idx)) +#define _byr_idx(rs, nss, idx) ((nss) * rtw89_rs_idx_num[rs] + (idx)) #define _byr_chk(rs, nss, idx) \ - ((nss) < rtw89_rs_nss_max[rs] && (idx) < rtw89_rs_idx_max[rs]) + ((nss) < rtw89_rs_nss_num[rs] && (idx) < rtw89_rs_idx_num[rs]) void rtw89_phy_load_txpwr_byrate(struct rtw89_dev *rtwdev, const struct rtw89_txpwr_table *tbl) @@ -2084,19 +2084,19 @@ void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr byrate with ch=%d\n", ch); - BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_CCK] % 4); - BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_OFDM] % 4); - BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_MCS] % 4); - BUILD_BUG_ON(rtw89_rs_idx_max[RTW89_RS_HEDCM] % 4); + BUILD_BUG_ON(rtw89_rs_idx_num[RTW89_RS_CCK] % 4); + BUILD_BUG_ON(rtw89_rs_idx_num[RTW89_RS_OFDM] % 4); + BUILD_BUG_ON(rtw89_rs_idx_num[RTW89_RS_MCS] % 4); + BUILD_BUG_ON(rtw89_rs_idx_num[RTW89_RS_HEDCM] % 4); addr = R_AX_PWR_BY_RATE; for (cur.nss = 0; cur.nss < max_nss_num; cur.nss++) { for (i = 0; i < ARRAY_SIZE(rs); i++) { - if (cur.nss >= rtw89_rs_nss_max[rs[i]]) + if (cur.nss >= rtw89_rs_nss_num[rs[i]]) continue; cur.rs = rs[i]; - for (cur.idx = 0; cur.idx < rtw89_rs_idx_max[rs[i]]; + for (cur.idx = 0; cur.idx < rtw89_rs_idx_num[rs[i]]; cur.idx++) { v[cur.idx % 4] = rtw89_phy_read_txpwr_byrate(rtwdev, @@ -2129,15 +2129,15 @@ void rtw89_phy_set_txpwr_offset(struct rtw89_dev *rtwdev, .rs = RTW89_RS_OFFSET, }; u8 band = chan->band_type; - s8 v[RTW89_RATE_OFFSET_MAX] = {}; + s8 v[RTW89_RATE_OFFSET_NUM] = {}; u32 val; rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr offset\n"); - for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_MAX; desc.idx++) + for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_NUM; desc.idx++) v[desc.idx] = rtw89_phy_read_txpwr_byrate(rtwdev, band, &desc); - BUILD_BUG_ON(RTW89_RATE_OFFSET_MAX != 5); + BUILD_BUG_ON(RTW89_RATE_OFFSET_NUM != 5); val = FIELD_PREP(GENMASK(3, 0), v[0]) | FIELD_PREP(GENMASK(7, 4), v[1]) | FIELD_PREP(GENMASK(11, 8), v[2]) | diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index 828beb0e5f7e..c447f91a4bd0 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -3321,7 +3321,7 @@ static const s8 _txpwr_track_delta_swingidx_2g_cck_a_p[] = { 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4 }; -const u8 rtw89_8851b_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] +const u8 rtw89_8851b_tx_shape[RTW89_BAND_NUM][RTW89_RS_TX_SHAPE_NUM] [RTW89_REGD_NUM] = { [0][0][RTW89_ACMA] = 0, [0][0][RTW89_CN] = 0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.h index f2e673ba39c8..a8737de02f66 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.h @@ -13,7 +13,7 @@ extern const struct rtw89_phy_table rtw89_8851b_phy_radioa_table; extern const struct rtw89_phy_table rtw89_8851b_phy_nctl_table; extern const struct rtw89_txpwr_table rtw89_8851b_byr_table; extern const struct rtw89_txpwr_track_cfg rtw89_8851b_trk_cfg; -extern const u8 rtw89_8851b_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] +extern const u8 rtw89_8851b_tx_shape[RTW89_BAND_NUM][RTW89_RS_TX_SHAPE_NUM] [RTW89_REGD_NUM]; extern const struct rtw89_rfe_parms rtw89_8851b_dflt_parms; extern const struct rtw89_rfe_parms_conf rtw89_8851b_rfe_parms_conf[]; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c index 904cdb9e56fa..17124d851a22 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c @@ -14666,7 +14666,7 @@ static const s8 _txpwr_track_delta_swingidx_2g_cck_a_p[] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; -const u8 rtw89_8852b_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] +const u8 rtw89_8852b_tx_shape[RTW89_BAND_NUM][RTW89_RS_TX_SHAPE_NUM] [RTW89_REGD_NUM] = { [0][0][RTW89_ACMA] = 0, [0][0][RTW89_CHILE] = 0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_table.h b/drivers/net/wireless/realtek/rtw89/rtw8852b_table.h index 5f4161496a58..7ef217629f46 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_table.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_table.h @@ -14,7 +14,7 @@ extern const struct rtw89_phy_table rtw89_8852b_phy_radiob_table; extern const struct rtw89_phy_table rtw89_8852b_phy_nctl_table; extern const struct rtw89_txpwr_table rtw89_8852b_byr_table; extern const struct rtw89_txpwr_track_cfg rtw89_8852b_trk_cfg; -extern const u8 rtw89_8852b_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] +extern const u8 rtw89_8852b_tx_shape[RTW89_BAND_NUM][RTW89_RS_TX_SHAPE_NUM] [RTW89_REGD_NUM]; extern const struct rtw89_rfe_parms rtw89_8852b_dflt_parms; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c index 8fda2c2e9833..4b272fdf1fd7 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.c @@ -31525,7 +31525,7 @@ static const s8 _txpwr_track_delta_swingidx_2g_cck_a_p[] = { 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5 }; -const u8 rtw89_8852c_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] +const u8 rtw89_8852c_tx_shape[RTW89_BAND_NUM][RTW89_RS_TX_SHAPE_NUM] [RTW89_REGD_NUM] = { [0][0][RTW89_ACMA] = 0, [0][0][RTW89_CHILE] = 0, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.h b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.h index 6da1849fb1fa..3eb0c4995174 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c_table.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c_table.h @@ -15,7 +15,7 @@ extern const struct rtw89_phy_table rtw89_8852c_phy_nctl_table; extern const struct rtw89_txpwr_table rtw89_8852c_byr_table; extern const struct rtw89_phy_tssi_dbw_table rtw89_8852c_tssi_dbw_table; extern const struct rtw89_txpwr_track_cfg rtw89_8852c_trk_cfg; -extern const u8 rtw89_8852c_tx_shape[RTW89_BAND_MAX][RTW89_RS_TX_SHAPE_NUM] +extern const u8 rtw89_8852c_tx_shape[RTW89_BAND_NUM][RTW89_RS_TX_SHAPE_NUM] [RTW89_REGD_NUM]; extern const struct rtw89_rfe_parms rtw89_8852c_dflt_parms; -- cgit v1.2.3 From f072eb39e4f2c1df60d8641f6260f11a42366abc Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Fri, 16 Jun 2023 14:06:01 +0800 Subject: wifi: rtw89: use struct to parse firmware header A firmware contains basic header, sections and optional dynamic header. Define them by a struct, so it will be easier to understand the layout, and also simply access these elements. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616060601.28460-1-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/core.h | 8 +-- drivers/net/wireless/realtek/rtw89/fw.c | 58 ++++++++--------- drivers/net/wireless/realtek/rtw89/fw.h | 101 ++++++++++++++++-------------- 3 files changed, 87 insertions(+), 80 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index c09c4b99af94..d2c67db97db1 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -3387,10 +3387,10 @@ struct rtw89_fw_suit { (mfw_hdr)->ver.idx) #define RTW89_FW_HDR_VER_CODE(fw_hdr) \ - RTW89_FW_VER_CODE(GET_FW_HDR_MAJOR_VERSION(fw_hdr), \ - GET_FW_HDR_MINOR_VERSION(fw_hdr), \ - GET_FW_HDR_SUBVERSION(fw_hdr), \ - GET_FW_HDR_SUBINDEX(fw_hdr)) + RTW89_FW_VER_CODE(le32_get_bits((fw_hdr)->w1, FW_HDR_W1_MAJOR_VERSION), \ + le32_get_bits((fw_hdr)->w1, FW_HDR_W1_MINOR_VERSION), \ + le32_get_bits((fw_hdr)->w1, FW_HDR_W1_SUBVERSION), \ + le32_get_bits((fw_hdr)->w1, FW_HDR_W1_SUBINDEX)) struct rtw89_fw_req_info { const struct firmware *firmware; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 65202f82e3be..9637f5e48d84 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -89,9 +89,11 @@ int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev) static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, struct rtw89_fw_bin_info *info) { + const struct rtw89_fw_hdr *fw_hdr = (const struct rtw89_fw_hdr *)fw; struct rtw89_fw_hdr_section_info *section_info; + const struct rtw89_fw_dynhdr_hdr *fwdynhdr; + const struct rtw89_fw_hdr_section *section; const u8 *fw_end = fw + len; - const u8 *fwdynhdr; const u8 *bin; u32 base_hdr_len; u32 mssc_len = 0; @@ -100,16 +102,15 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, if (!info) return -EINVAL; - info->section_num = GET_FW_HDR_SEC_NUM(fw); - base_hdr_len = RTW89_FW_HDR_SIZE + - info->section_num * RTW89_FW_SECTION_HDR_SIZE; - info->dynamic_hdr_en = GET_FW_HDR_DYN_HDR(fw); + info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_W6_SEC_NUM); + base_hdr_len = struct_size(fw_hdr, sections, info->section_num); + info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_W7_DYN_HDR); if (info->dynamic_hdr_en) { - info->hdr_len = GET_FW_HDR_LEN(fw); + info->hdr_len = le32_get_bits(fw_hdr->w3, FW_HDR_W3_LEN); info->dynamic_hdr_len = info->hdr_len - base_hdr_len; - fwdynhdr = fw + base_hdr_len; - if (GET_FW_DYNHDR_LEN(fwdynhdr) != info->dynamic_hdr_len) { + fwdynhdr = (const struct rtw89_fw_dynhdr_hdr *)(fw + base_hdr_len); + if (le32_to_cpu(fwdynhdr->hdr_len) != info->dynamic_hdr_len) { rtw89_err(rtwdev, "[ERR]invalid fw dynamic header len\n"); return -EINVAL; } @@ -121,26 +122,27 @@ static int rtw89_fw_hdr_parser(struct rtw89_dev *rtwdev, const u8 *fw, u32 len, bin = fw + info->hdr_len; /* jump to section header */ - fw += RTW89_FW_HDR_SIZE; section_info = info->section_info; for (i = 0; i < info->section_num; i++) { - section_info->type = GET_FWSECTION_HDR_SECTIONTYPE(fw); + section = &fw_hdr->sections[i]; + section_info->type = + le32_get_bits(section->w1, FWSECTION_HDR_W1_SECTIONTYPE); if (section_info->type == FWDL_SECURITY_SECTION_TYPE) { - section_info->mssc = GET_FWSECTION_HDR_MSSC(fw); + section_info->mssc = + le32_get_bits(section->w2, FWSECTION_HDR_W2_MSSC); mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN; } else { section_info->mssc = 0; } - section_info->len = GET_FWSECTION_HDR_SEC_SIZE(fw); - if (GET_FWSECTION_HDR_CHECKSUM(fw)) + section_info->len = le32_get_bits(section->w1, FWSECTION_HDR_W1_SEC_SIZE); + if (le32_get_bits(section->w1, FWSECTION_HDR_W1_CHECKSUM)) section_info->len += FWDL_SECTION_CHKSUM_LEN; - section_info->redl = GET_FWSECTION_HDR_REDL(fw); + section_info->redl = le32_get_bits(section->w1, FWSECTION_HDR_W1_REDL); section_info->dladdr = - GET_FWSECTION_HDR_DL_ADDR(fw) & 0x1fffffff; + le32_get_bits(section->w0, FWSECTION_HDR_W0_DL_ADDR) & 0x1fffffff; section_info->addr = bin; bin += section_info->len; - fw += RTW89_FW_SECTION_HDR_SIZE; section_info++; } @@ -195,18 +197,18 @@ static void rtw89_fw_update_ver(struct rtw89_dev *rtwdev, enum rtw89_fw_type type, struct rtw89_fw_suit *fw_suit) { - const u8 *hdr = fw_suit->data; - - fw_suit->major_ver = GET_FW_HDR_MAJOR_VERSION(hdr); - fw_suit->minor_ver = GET_FW_HDR_MINOR_VERSION(hdr); - fw_suit->sub_ver = GET_FW_HDR_SUBVERSION(hdr); - fw_suit->sub_idex = GET_FW_HDR_SUBINDEX(hdr); - fw_suit->build_year = GET_FW_HDR_YEAR(hdr); - fw_suit->build_mon = GET_FW_HDR_MONTH(hdr); - fw_suit->build_date = GET_FW_HDR_DATE(hdr); - fw_suit->build_hour = GET_FW_HDR_HOUR(hdr); - fw_suit->build_min = GET_FW_HDR_MIN(hdr); - fw_suit->cmd_ver = GET_FW_HDR_CMD_VERSERION(hdr); + const struct rtw89_fw_hdr *hdr = (const struct rtw89_fw_hdr *)fw_suit->data; + + fw_suit->major_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MAJOR_VERSION); + fw_suit->minor_ver = le32_get_bits(hdr->w1, FW_HDR_W1_MINOR_VERSION); + fw_suit->sub_ver = le32_get_bits(hdr->w1, FW_HDR_W1_SUBVERSION); + fw_suit->sub_idex = le32_get_bits(hdr->w1, FW_HDR_W1_SUBINDEX); + fw_suit->build_year = le32_get_bits(hdr->w5, FW_HDR_W5_YEAR); + fw_suit->build_mon = le32_get_bits(hdr->w4, FW_HDR_W4_MONTH); + fw_suit->build_date = le32_get_bits(hdr->w4, FW_HDR_W4_DATE); + fw_suit->build_hour = le32_get_bits(hdr->w4, FW_HDR_W4_HOUR); + fw_suit->build_min = le32_get_bits(hdr->w4, FW_HDR_W4_MIN); + fw_suit->cmd_ver = le32_get_bits(hdr->w7, FW_HDR_W7_CMD_VERSERION); rtw89_info(rtwdev, "Firmware version %u.%u.%u.%u, cmd version %u, type %u\n", diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 78d808f1e8c8..45f927dc212e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -528,50 +528,58 @@ static inline void RTW89_SET_EDCA_PARAM(void *cmd, u32 val) #define FWDL_SECURITY_SECTION_TYPE 9 #define FWDL_SECURITY_SIGLEN 512 -#define GET_FWSECTION_HDR_DL_ADDR(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr)), GENMASK(31, 0)) -#define GET_FWSECTION_HDR_SECTIONTYPE(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(27, 24)) -#define GET_FWSECTION_HDR_SEC_SIZE(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 0)) -#define GET_FWSECTION_HDR_CHECKSUM(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(28)) -#define GET_FWSECTION_HDR_REDL(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 1), BIT(29)) -#define GET_FWSECTION_HDR_MSSC(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 2), GENMASK(31, 0)) - -#define GET_FW_HDR_MAJOR_VERSION(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(7, 0)) -#define GET_FW_HDR_MINOR_VERSION(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(15, 8)) -#define GET_FW_HDR_SUBVERSION(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(23, 16)) -#define GET_FW_HDR_SUBINDEX(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 1), GENMASK(31, 24)) -#define GET_FW_HDR_LEN(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 3), GENMASK(23, 16)) -#define GET_FW_HDR_MONTH(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(7, 0)) -#define GET_FW_HDR_DATE(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(15, 8)) -#define GET_FW_HDR_HOUR(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(23, 16)) -#define GET_FW_HDR_MIN(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 4), GENMASK(31, 24)) -#define GET_FW_HDR_YEAR(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 5), GENMASK(31, 0)) -#define GET_FW_HDR_SEC_NUM(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 6), GENMASK(15, 8)) -#define GET_FW_HDR_DYN_HDR(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 7), BIT(16)) -#define GET_FW_HDR_CMD_VERSERION(fwhdr) \ - le32_get_bits(*((const __le32 *)(fwhdr) + 7), GENMASK(31, 24)) - -#define GET_FW_DYNHDR_LEN(fwdynhdr) \ - le32_get_bits(*((const __le32 *)(fwdynhdr)), GENMASK(31, 0)) -#define GET_FW_DYNHDR_COUNT(fwdynhdr) \ - le32_get_bits(*((const __le32 *)(fwdynhdr) + 1), GENMASK(31, 0)) +struct rtw89_fw_dynhdr_sec { + __le32 w0; + u8 content[]; +} __packed; + +struct rtw89_fw_dynhdr_hdr { + __le32 hdr_len; + __le32 setcion_count; + /* struct rtw89_fw_dynhdr_sec (nested flexible structures) */ +} __packed; + +struct rtw89_fw_hdr_section { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; +} __packed; + +#define FWSECTION_HDR_W0_DL_ADDR GENMASK(31, 0) +#define FWSECTION_HDR_W1_METADATA GENMASK(31, 24) +#define FWSECTION_HDR_W1_SECTIONTYPE GENMASK(27, 24) +#define FWSECTION_HDR_W1_SEC_SIZE GENMASK(23, 0) +#define FWSECTION_HDR_W1_CHECKSUM BIT(28) +#define FWSECTION_HDR_W1_REDL BIT(29) +#define FWSECTION_HDR_W2_MSSC GENMASK(31, 0) + +struct rtw89_fw_hdr { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + struct rtw89_fw_hdr_section sections[]; + /* struct rtw89_fw_dynhdr_hdr (optional) */ +} __packed; + +#define FW_HDR_W1_MAJOR_VERSION GENMASK(7, 0) +#define FW_HDR_W1_MINOR_VERSION GENMASK(15, 8) +#define FW_HDR_W1_SUBVERSION GENMASK(23, 16) +#define FW_HDR_W1_SUBINDEX GENMASK(31, 24) +#define FW_HDR_W3_LEN GENMASK(23, 16) +#define FW_HDR_W4_MONTH GENMASK(7, 0) +#define FW_HDR_W4_DATE GENMASK(15, 8) +#define FW_HDR_W4_HOUR GENMASK(23, 16) +#define FW_HDR_W4_MIN GENMASK(31, 24) +#define FW_HDR_W5_YEAR GENMASK(31, 0) +#define FW_HDR_W6_SEC_NUM GENMASK(15, 8) +#define FW_HDR_W7_DYN_HDR BIT(16) +#define FW_HDR_W7_CMD_VERSERION GENMASK(31, 24) static inline void SET_FW_HDR_PART_SIZE(void *fwhdr, u32 val) { @@ -3392,9 +3400,6 @@ struct rtw89_h2c_ofld { #define RTW89_H2C_OFLD_W0_TX_TP GENMASK(17, 8) #define RTW89_H2C_OFLD_W0_RX_TP GENMASK(27, 18) -#define RTW89_FW_HDR_SIZE 32 -#define RTW89_FW_SECTION_HDR_SIZE 16 - #define RTW89_MFW_SIG 0xFF struct rtw89_mfw_info { @@ -3428,7 +3433,7 @@ struct fwcmd_hdr { union rtw89_compat_fw_hdr { struct rtw89_mfw_hdr mfw_hdr; - u8 fw_hdr[RTW89_FW_HDR_SIZE]; + struct rtw89_fw_hdr fw_hdr; }; static inline u32 rtw89_compat_fw_hdr_ver_code(const void *fw_buf) -- cgit v1.2.3 From 5fdaeca73eb2bc944bb509b3cdd1520188ed2285 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 14 Jun 2023 17:47:02 +0300 Subject: MAINTAINERS: mt76: add git tree Felix has a git tree for mt76 patches, document that. Signed-off-by: Kalle Valo Acked-by: Lorenzo Bianconi Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230614144704.505553-1-kvalo@kernel.org --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0971854323a7..f7d7fdf47dd8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13212,6 +13212,7 @@ R: Shayne Chen R: Sean Wang L: linux-wireless@vger.kernel.org S: Maintained +T: git https://github.com/nbd168/wireless F: Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml F: drivers/net/wireless/mediatek/mt76/ -- cgit v1.2.3 From 30e67ed6e1d7686b215ec521cfdb9274101c8ece Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 14 Jun 2023 17:47:03 +0300 Subject: MAINTAINERS: ath9k: add git tree ath9k patches go to my ath.git tree, document that. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230614144704.505553-2-kvalo@kernel.org --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f7d7fdf47dd8..ddeae82230c6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17371,6 +17371,7 @@ M: Toke Høiland-Jørgensen L: linux-wireless@vger.kernel.org S: Maintained W: https://wireless.wiki.kernel.org/en/users/Drivers/ath9k +T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git F: Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml F: drivers/net/wireless/ath/ath9k/ -- cgit v1.2.3 From d5b9a2102075923f5f74e890661421f94a9e6177 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Wed, 14 Jun 2023 17:47:04 +0300 Subject: MAINTAINERS: ath11k: add wiki and bugreport page ath11k has a wiki and a separate page about reporting bugs, add those so hopefully people find them easier. Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230614144704.505553-3-kvalo@kernel.org --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ddeae82230c6..ac365fc4ea6c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17362,6 +17362,8 @@ QUALCOMM ATHEROS ATH11K WIRELESS DRIVER M: Kalle Valo L: ath11k@lists.infradead.org S: Supported +W: https://wireless.wiki.kernel.org/en/users/Drivers/ath11k +B: https://wireless.wiki.kernel.org/en/users/Drivers/ath11k/bugreport T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git F: Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml F: drivers/net/wireless/ath/ath11k/ -- cgit v1.2.3 From 8d0c7e1901d6083756b7530d348cb0af6b25ded8 Mon Sep 17 00:00:00 2001 From: Juerg Haefliger Date: Fri, 16 Jun 2023 14:19:17 +0200 Subject: wifi: p54: Add missing MODULE_FIRMWARE macro Add the missing MODULE_FIRMWARE macro for "3826.eeprom". Signed-off-by: Juerg Haefliger Acked-by: Christian Lamparter Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616121917.1034761-1-juerg.haefliger@canonical.com --- drivers/net/wireless/intersil/p54/p54spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index 19152fd449ba..ce0179b8ab36 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -28,6 +28,7 @@ #endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */ MODULE_FIRMWARE("3826.arm"); +MODULE_FIRMWARE("3826.eeprom"); /* gpios should be handled in board files and provided via platform data, * but because it's currently impossible for p54spi to have a header file -- cgit v1.2.3 From 7339e0f2e1bcb732b922a1c40a01b6002bec1ee5 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Mon, 19 Jun 2023 18:37:38 +0300 Subject: wifi: mac80211: drop unprotected robust mgmt before 4-way-HS When MFP is used, drop unprotected robust management frames also before the 4-way handshake has been completed, i.e. no key has been installed yet. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619183718.cfbefddccd0c.Ife369dbb61c87e311ce15739d5b2b4763bfdfbae@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6ebec32b4ebc..1d2e7a6dd2a1 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2418,13 +2418,20 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) { if (unlikely(!ieee80211_has_protected(fc) && - ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && - rx->key)) { + ieee80211_is_unicast_robust_mgmt_frame(rx->skb))) { if (ieee80211_is_deauth(fc) || - ieee80211_is_disassoc(fc)) + ieee80211_is_disassoc(fc)) { + /* + * Permit unprotected deauth/disassoc frames + * during 4-way-HS (key is installed after HS). + */ + if (!rx->key) + return 0; + cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev, rx->skb->data, rx->skb->len); + } return -EACCES; } /* BIP does not use Protected field, so need to check MMIE */ -- cgit v1.2.3 From 2cc7add345ea0e3d28a2fae29b93884909753c63 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2023 16:26:46 +0300 Subject: wifi: mac80211: move action length check up We'd like to add more checks to the function here for action frames, so move up the length check from the action processing. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619161906.e799254e923f.I0a1de5f6bbdc1b2ef5efaa0ac80c7c3f39415538@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1d2e7a6dd2a1..e35d6ba8521b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3363,6 +3363,11 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) if (!ieee80211_is_mgmt(mgmt->frame_control)) return RX_DROP_MONITOR; + /* drop too small action frames */ + if (ieee80211_is_action(mgmt->frame_control) && + rx->skb->len < IEEE80211_MIN_ACTION_SIZE) + return RX_DROP_UNUSABLE; + if (rx->sdata->vif.type == NL80211_IFTYPE_AP && ieee80211_is_beacon(mgmt->frame_control) && !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { @@ -3452,10 +3457,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (!ieee80211_is_action(mgmt->frame_control)) return RX_CONTINUE; - /* drop too small frames */ - if (len < IEEE80211_MIN_ACTION_SIZE) - return RX_DROP_UNUSABLE; - if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED && mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) -- cgit v1.2.3 From 76a3059cf1246a71f242822c6d605e5baa8924a3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2023 16:26:47 +0300 Subject: wifi: mac80211: drop some unprotected action frames We should not receive/handle unicast protected dual or public action frames that aren't protected, so drop them - in the latter case of course only if MFP is used. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619161906.eb4461108129.I3c2223cf29d8a3586dfc74b2dda3f6fa2a4eea7c@changeid Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e35d6ba8521b..e579581441de 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2405,9 +2405,9 @@ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc) static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - __le16 fc = hdr->frame_control; + struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; + __le16 fc = mgmt->frame_control; /* * Pass through unencrypted frames if the hardware has @@ -2416,6 +2416,11 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) if (status->flag & RX_FLAG_DECRYPTED) return 0; + /* drop unicast protected dual (that wasn't protected) */ + if (ieee80211_is_action(fc) && + mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION) + return -EACCES; + if (rx->sta && test_sta_flag(rx->sta, WLAN_STA_MFP)) { if (unlikely(!ieee80211_has_protected(fc) && ieee80211_is_unicast_robust_mgmt_frame(rx->skb))) { @@ -2458,6 +2463,12 @@ static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx) if (unlikely(ieee80211_is_action(fc) && !rx->key && ieee80211_is_robust_mgmt_frame(rx->skb))) return -EACCES; + + /* drop unicast public action frames when using MPF */ + if (is_unicast_ether_addr(mgmt->da) && + ieee80211_is_public_action((void *)rx->skb->data, + rx->skb->len)) + return -EACCES; } return 0; -- cgit v1.2.3 From 5c1f97537bfb9f358e0ecc88c3c8a913c51944cb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2023 16:26:48 +0300 Subject: wifi: mac80211: store BSS param change count from assoc response When receiving a multi-link association response, make sure to track the BSS parameter change count for each link, including the assoc link. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619161906.1799c164e7e9.I8e2c1f5eec6eec3fab525ae2dead9f6f099a2427@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/mlme.c | 16 +++++++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index fa679613c562..15c4e12b6fc7 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4689,6 +4689,34 @@ static inline u8 ieee80211_mle_common_size(const u8 *data) return sizeof(*mle) + common + mle->variable[0]; } +/** + * ieee80211_mle_get_bss_param_ch_cnt - returns the BSS parameter change count + * @mle: the basic multi link element + * + * The element is assumed to be of the correct type (BASIC) and big enough, + * this must be checked using ieee80211_mle_type_ok(). + * + * If the BSS parameter change count value can't be found (the presence bit + * for it is clear), 0 will be returned. + */ +static inline u8 +ieee80211_mle_get_bss_param_ch_cnt(const struct ieee80211_multi_link_elem *mle) +{ + u16 control = le16_to_cpu(mle->control); + const u8 *common = mle->variable; + + /* common points now at the beginning of ieee80211_mle_basic_common_info */ + common += sizeof(struct ieee80211_mle_basic_common_info); + + if (!(control & IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT)) + return 0; + + if (control & IEEE80211_MLC_BASIC_PRES_LINK_ID) + common += 1; + + return *common; +} + /** * ieee80211_mle_get_eml_sync_delay - returns the medium sync delay * @data: pointer to the multi link EHT IE @@ -4902,6 +4930,42 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, fixed + prof->sta_info_len <= len; } +/** + * ieee80211_mle_basic_sta_prof_bss_param_ch_cnt - get per-STA profile BSS + * parameter change count + * @prof: the per-STA profile, having been checked with + * ieee80211_mle_basic_sta_prof_size_ok() for the correct length + * + * Return: The BSS parameter change count value if present, 0 otherwise. + */ +static inline u8 +ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(const struct ieee80211_mle_per_sta_profile *prof) +{ + u16 control = le16_to_cpu(prof->control); + const u8 *pos = prof->variable; + + if (!(control & IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT)) + return 0; + + if (control & IEEE80211_MLE_STA_CONTROL_STA_MAC_ADDR_PRESENT) + pos += 6; + if (control & IEEE80211_MLE_STA_CONTROL_BEACON_INT_PRESENT) + pos += 2; + if (control & IEEE80211_MLE_STA_CONTROL_TSF_OFFS_PRESENT) + pos += 8; + if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT) + pos += 2; + if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE && + control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) { + if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) + pos += 2; + else + pos += 1; + } + + return *pos; +} + #define IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID 0x000f #define IEEE80211_MLE_STA_RECONF_CONTROL_COMPLETE_PROFILE 0x0010 #define IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT 0x0020 diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2f7665998da0..91633a0b723e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -951,6 +951,8 @@ struct ieee80211_link_data_managed { int wmm_last_param_set; int mu_edca_last_param_set; + u8 bss_param_ch_cnt; + struct cfg80211_bss *bss; }; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index cf15089e95f1..f93eb38ae0b8 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4018,6 +4018,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, const struct cfg80211_bss_ies *bss_ies = NULL; struct ieee80211_supported_band *sband; struct ieee802_11_elems *elems; + const __le16 prof_bss_param_ch_present = + cpu_to_le16(IEEE80211_MLE_STA_CONTROL_BSS_PARAM_CHANGE_CNT_PRESENT); u16 capab_info; bool ret; @@ -4033,7 +4035,17 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, * successful, so set the status directly to success */ assoc_data->link[link_id].status = WLAN_STATUS_SUCCESS; - } else if (!elems->prof) { + if (elems->ml_basic) { + if (!(elems->ml_basic->control & + cpu_to_le16(IEEE80211_MLC_BASIC_PRES_BSS_PARAM_CH_CNT))) { + ret = false; + goto out; + } + link->u.mgd.bss_param_ch_cnt = + ieee80211_mle_get_bss_param_ch_cnt(elems->ml_basic); + } + } else if (!elems->prof || + !(elems->prof->control & prof_bss_param_ch_present)) { ret = false; goto out; } else { @@ -4046,6 +4058,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, */ capab_info = get_unaligned_le16(ptr); assoc_data->link[link_id].status = get_unaligned_le16(ptr + 2); + link->u.mgd.bss_param_ch_cnt = + ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(elems->prof); if (assoc_data->link[link_id].status != WLAN_STATUS_SUCCESS) { link_info(link, "association response status code=%u\n", -- cgit v1.2.3 From 4484de23ba22e3023e9cbe4246a927ffb00db56f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2023 16:26:49 +0300 Subject: wifi: mac80211: always hold sdata lock in chanctx assign/unassign Due to all the multi-link handling, we now expose the fact that the sdata/vif is locked to drivers, e.g. when the driver uses ieee80211_set_monitor_channel(). This was true when a chanctx is added to or removed from a link, _except_ in monitor mode with the virtual sdata/vif. Change that, so that drivers can make that assumption. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619161906.a5cf7534beda.I5b51664231abee27e02f222083df7ccf88722929@changeid Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 16 +++++++++++----- net/mac80211/iface.c | 7 +++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index eea7028a46a7..e7ac24603892 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -913,24 +913,30 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy, if (cfg80211_chandef_identical(&local->monitor_chandef, chandef)) return 0; - mutex_lock(&local->mtx); if (local->use_chanctx) { sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); if (sdata) { + sdata_lock(sdata); + mutex_lock(&local->mtx); ieee80211_link_release_channel(&sdata->deflink); ret = ieee80211_link_use_channel(&sdata->deflink, chandef, IEEE80211_CHANCTX_EXCLUSIVE); + mutex_unlock(&local->mtx); + sdata_unlock(sdata); + } + } else { + mutex_lock(&local->mtx); + if (local->open_count == local->monitors) { + local->_oper_chandef = *chandef; + ieee80211_hw_config(local, 0); } - } else if (local->open_count == local->monitors) { - local->_oper_chandef = *chandef; - ieee80211_hw_config(local, 0); + mutex_unlock(&local->mtx); } if (ret == 0) local->monitor_chandef = *chandef; - mutex_unlock(&local->mtx); return ret; } diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 9518acf9643b..be586bc0b5b7 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1133,6 +1133,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) snprintf(sdata->name, IFNAMSIZ, "%s-monitor", wiphy_name(local->hw.wiphy)); sdata->wdev.iftype = NL80211_IFTYPE_MONITOR; + mutex_init(&sdata->wdev.mtx); ieee80211_sdata_init(local, sdata); @@ -1157,16 +1158,19 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) rcu_assign_pointer(local->monitor_sdata, sdata); mutex_unlock(&local->iflist_mtx); + sdata_lock(sdata); mutex_lock(&local->mtx); ret = ieee80211_link_use_channel(&sdata->deflink, &local->monitor_chandef, IEEE80211_CHANCTX_EXCLUSIVE); mutex_unlock(&local->mtx); + sdata_unlock(sdata); if (ret) { mutex_lock(&local->iflist_mtx); RCU_INIT_POINTER(local->monitor_sdata, NULL); mutex_unlock(&local->iflist_mtx); synchronize_net(); drv_remove_interface(local, sdata); + mutex_destroy(&sdata->wdev.mtx); kfree(sdata); return ret; } @@ -1202,12 +1206,15 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) synchronize_net(); + sdata_lock(sdata); mutex_lock(&local->mtx); ieee80211_link_release_channel(&sdata->deflink); mutex_unlock(&local->mtx); + sdata_unlock(sdata); drv_remove_interface(local, sdata); + mutex_destroy(&sdata->wdev.mtx); kfree(sdata); } -- cgit v1.2.3 From b8b80770b26c4591f20f1cde3328e5f1489c4488 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 19 Jun 2023 16:26:50 +0300 Subject: wifi: mac80211: avoid lockdep checking when removing deflink struct sta_info may be removed without holding sta_mtx if it has not yet been inserted. To support this, only assert that the lock is held for links other than the deflink. This fixes lockdep issues that may be triggered in error cases. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619161906.cdd81377dea0.If5a6734b4b85608a2275a09b4f99b5564d82997f@changeid Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 731b832b257c..7751f8ba960e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -355,8 +355,9 @@ static void sta_remove_link(struct sta_info *sta, unsigned int link_id, struct sta_link_alloc *alloc = NULL; struct link_sta_info *link_sta; - link_sta = rcu_dereference_protected(sta->link[link_id], - lockdep_is_held(&sta->local->sta_mtx)); + link_sta = rcu_access_pointer(sta->link[link_id]); + if (link_sta != &sta->deflink) + lockdep_assert_held(&sta->local->sta_mtx); if (WARN_ON(!link_sta)) return; -- cgit v1.2.3 From 2829b2fc8910984daa89be8005adbd9fb6205024 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2023 16:26:51 +0300 Subject: wifi: mac80211: fix CRC calculation for extended elems For extended elements, we currently only calculate the CRC for some of them, but really we should do it also for the rest that we care about, such as EHT operation and multi- link. Also, while at it, it seems we should do it even if they aren't well-formed, so we notice if that changes. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619161906.93235d5c8651.I6615cb3c1244bc9618066baa2bdad7982e9abd1f@changeid Signed-off-by: Johannes Berg --- net/mac80211/util.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6c52c597c187..8a6917cf63cf 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -918,6 +918,7 @@ ieee80211_parse_extension_element(u32 *crc, struct ieee80211_elems_parse_params *params) { const void *data = elem->data + 1; + bool calc_crc = false; u8 len; if (!elem->datalen) @@ -927,12 +928,9 @@ ieee80211_parse_extension_element(u32 *crc, switch (elem->data[0]) { case WLAN_EID_EXT_HE_MU_EDCA: - if (len >= sizeof(*elems->mu_edca_param_set)) { + calc_crc = true; + if (len >= sizeof(*elems->mu_edca_param_set)) elems->mu_edca_param_set = data; - if (crc) - *crc = crc32_be(*crc, (void *)elem, - elem->datalen + 2); - } break; case WLAN_EID_EXT_HE_CAPABILITY: if (ieee80211_he_capa_size_ok(data, len)) { @@ -941,13 +939,10 @@ ieee80211_parse_extension_element(u32 *crc, } break; case WLAN_EID_EXT_HE_OPERATION: + calc_crc = true; if (len >= sizeof(*elems->he_operation) && - len >= ieee80211_he_oper_size(data) - 1) { - if (crc) - *crc = crc32_be(*crc, (void *)elem, - elem->datalen + 2); + len >= ieee80211_he_oper_size(data) - 1) elems->he_operation = data; - } break; case WLAN_EID_EXT_UORA: if (len >= 1) @@ -981,16 +976,15 @@ ieee80211_parse_extension_element(u32 *crc, case WLAN_EID_EXT_EHT_OPERATION: if (ieee80211_eht_oper_size_ok(data, len)) elems->eht_operation = data; + calc_crc = true; break; case WLAN_EID_EXT_EHT_MULTI_LINK: + calc_crc = true; + if (ieee80211_mle_size_ok(data, len)) { const struct ieee80211_multi_link_elem *mle = (void *)data; - if (crc) - *crc = crc32_be(*crc, (void *)elem, - elem->datalen + 2); - switch (le16_get_bits(mle->control, IEEE80211_ML_CONTROL_TYPE)) { case IEEE80211_ML_CONTROL_TYPE_BASIC: @@ -1009,6 +1003,9 @@ ieee80211_parse_extension_element(u32 *crc, } break; } + + if (crc && calc_crc) + *crc = crc32_be(*crc, (void *)elem, elem->datalen + 2); } static u32 -- cgit v1.2.3 From 4ef2f53e50cba9780057b51357ef45cb5f49859d Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 19 Jun 2023 16:26:52 +0300 Subject: wifi: cfg80211: Retrieve PSD information from RNR AP information Retrieve the Power Spectral Density (PSD) value from RNR AP information entry and store it so it could be used by the drivers. PSD value is explained in Section 9.4.2.170 of Draft P802.11Revme_D2.0. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619161906.067ded2b8fc3.I9f407ab5800cbb07045a0537a513012960ced740@changeid Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 7 +++++-- include/net/cfg80211.h | 2 ++ net/wireless/scan.c | 13 +++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 15c4e12b6fc7..6f1747a9c106 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4504,6 +4504,9 @@ static inline bool for_each_element_completed(const struct element *element, #define IEEE80211_RNR_TBTT_PARAMS_PROBE_ACTIVE 0x20 #define IEEE80211_RNR_TBTT_PARAMS_COLOC_AP 0x40 +#define IEEE80211_RNR_TBTT_PARAMS_PSD_NO_LIMIT 127 +#define IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED -128 + struct ieee80211_neighbor_ap_info { u8 tbtt_info_hdr; u8 tbtt_info_len; @@ -4539,7 +4542,7 @@ struct ieee80211_tbtt_info_7_8_9 { /* The following element is optional, structure may not grow */ u8 bss_params; - u8 psd_20; + s8 psd_20; } __packed; /* Format of the TBTT information element if it has >= 11 bytes */ @@ -4550,7 +4553,7 @@ struct ieee80211_tbtt_info_ge_11 { /* The following elements are optional, structure may grow */ u8 bss_params; - u8 psd_20; + s8 psd_20; struct ieee80211_rnr_mld_params mld_params; } __packed; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 3a736f9286b0..7c7d03aa9d06 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2466,6 +2466,7 @@ struct cfg80211_scan_info { * @short_ssid_valid: @short_ssid is valid and can be used * @psc_no_listen: when set, and the channel is a PSC channel, no need to wait * 20 TUs before starting to send probe requests. + * @psd_20: The AP's 20 MHz PSD value. */ struct cfg80211_scan_6ghz_params { u32 short_ssid; @@ -2474,6 +2475,7 @@ struct cfg80211_scan_6ghz_params { bool unsolicited_probe; bool short_ssid_valid; bool psc_no_listen; + s8 psd_20; }; /** diff --git a/net/wireless/scan.c b/net/wireless/scan.c index ede95caecb34..8bf00caf5d29 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -96,6 +96,7 @@ MODULE_PARM_DESC(bss_entries_limit, * colocated and can be discovered via legacy bands. * @short_ssid_valid: short_ssid is valid and can be used * @short_ssid: the short SSID for this SSID + * @psd_20: The 20MHz PSD EIRP of the primary 20MHz channel for the reported AP */ struct cfg80211_colocated_ap { struct list_head list; @@ -111,6 +112,7 @@ struct cfg80211_colocated_ap { transmitted_bssid:1, colocated_ess:1, short_ssid_valid:1; + s8 psd_20; }; static void bss_free(struct cfg80211_internal_bss *bss) @@ -578,6 +580,8 @@ static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, { u8 bss_params; + entry->psd_20 = IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED; + /* The length is already verified by the caller to contain bss_params */ if (length > sizeof(struct ieee80211_tbtt_info_7_8_9)) { struct ieee80211_tbtt_info_ge_11 *tbtt_info = (void *)pos; @@ -594,12 +598,20 @@ static int cfg80211_parse_ap_info(struct cfg80211_colocated_ap *entry, IEEE80211_RNR_MLD_PARAMS_DISABLED_LINK)) return -EINVAL; } + + if (length >= offsetofend(struct ieee80211_tbtt_info_ge_11, + psd_20)) + entry->psd_20 = tbtt_info->psd_20; } else { struct ieee80211_tbtt_info_7_8_9 *tbtt_info = (void *)pos; memcpy(entry->bssid, tbtt_info->bssid, ETH_ALEN); bss_params = tbtt_info->bss_params; + + if (length == offsetofend(struct ieee80211_tbtt_info_7_8_9, + psd_20)) + entry->psd_20 = tbtt_info->psd_20; } /* ignore entries with invalid BSSID */ @@ -904,6 +916,7 @@ static int cfg80211_scan_6ghz(struct cfg80211_registered_device *rdev) scan_6ghz_params->short_ssid = ap->short_ssid; scan_6ghz_params->short_ssid_valid = ap->short_ssid_valid; scan_6ghz_params->unsolicited_probe = ap->unsolicited_probe; + scan_6ghz_params->psd_20 = ap->psd_20; /* * If a PSC channel is added to the scan and 'need_scan_psc' is -- cgit v1.2.3 From 6c5b9a3296e146cc74b1d006c6a546ea92534ade Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 19 Jun 2023 16:26:53 +0300 Subject: wifi: nl80211/reg: add no-EHT regulatory flag This just propagates to the channel flags, like no-HE and similar other flags before it. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230619161906.74ce2983aed8.Ifa343ba89c11760491daad5aee5a81209d5735a7@changeid Signed-off-by: Johannes Berg --- include/uapi/linux/nl80211.h | 2 ++ net/wireless/reg.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 3190d34269ef..88eb85c63029 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -4450,6 +4450,7 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed * @NL80211_RRF_NO_HE: HE operation not allowed * @NL80211_RRF_NO_320MHZ: 320MHz operation not allowed + * @NL80211_RRF_NO_EHT: EHT operation not allowed */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -4469,6 +4470,7 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_160MHZ = 1<<16, NL80211_RRF_NO_HE = 1<<17, NL80211_RRF_NO_320MHZ = 1<<18, + NL80211_RRF_NO_EHT = 1<<19, }; #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f9e03850d71b..0317cf9da307 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -5,7 +5,7 @@ * Copyright 2008-2011 Luis R. Rodriguez * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2017 Intel Deutschland GmbH - * Copyright (C) 2018 - 2022 Intel Corporation + * Copyright (C) 2018 - 2023 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1587,6 +1587,8 @@ static u32 map_regdom_flags(u32 rd_flags) channel_flags |= IEEE80211_CHAN_NO_HE; if (rd_flags & NL80211_RRF_NO_320MHZ) channel_flags |= IEEE80211_CHAN_NO_320MHZ; + if (rd_flags & NL80211_RRF_NO_EHT) + channel_flags |= IEEE80211_CHAN_NO_EHT; return channel_flags; } -- cgit v1.2.3 From 4742c732624bd2609aeb0acee38c0a126e61ed47 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:03:47 +0300 Subject: wifi: iwlwifi: pcie: refactor RB status size calculation We have three places doing this check, and even in slightly different ways (with/without an intermediate). Refactor that to a new small inline function. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.f3e87ddd5bce.Ifefba753043b68c394590a35bc6914a0f6497fd3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index da1a27b1d8b6..f87b28edc267 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -699,17 +699,25 @@ static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans, rxq->used_bd = NULL; } +static size_t iwl_pcie_rb_stts_size(struct iwl_trans *trans) +{ + bool use_rx_td = (trans->trans_cfg->device_family >= + IWL_DEVICE_FAMILY_AX210); + + if (use_rx_td) + return sizeof(__le16); + + return sizeof(struct iwl_rb_status); +} + static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, struct iwl_rxq *rxq) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + size_t rb_stts_size = iwl_pcie_rb_stts_size(trans); struct device *dev = trans->dev; int i; int free_size; - bool use_rx_td = (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_AX210); - size_t rb_stts_size = use_rx_td ? sizeof(__le16) : - sizeof(struct iwl_rb_status); spin_lock_init(&rxq->lock); if (trans->trans_cfg->mq_rx_supported) @@ -757,11 +765,9 @@ err: static int iwl_pcie_rx_alloc(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + size_t rb_stts_size = iwl_pcie_rb_stts_size(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; int i, ret; - size_t rb_stts_size = trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_AX210 ? - sizeof(__le16) : sizeof(struct iwl_rb_status); if (WARN_ON(trans_pcie->rxq)) return -EINVAL; @@ -1193,11 +1199,9 @@ int iwl_pcie_gen2_rx_init(struct iwl_trans *trans) void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + size_t rb_stts_size = iwl_pcie_rb_stts_size(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; int i; - size_t rb_stts_size = trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_AX210 ? - sizeof(__le16) : sizeof(struct iwl_rb_status); /* * if rxq is NULL, it means that nothing has been allocated, -- cgit v1.2.3 From 1caa3a5e921c146cc82a674e7ef01633a142c475 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:03:48 +0300 Subject: wifi: iwlwifi: pcie: add size assertions Ensure that the TX command scratch fits into the buffer provided by the first TB. It does, of course, but add some build-time validations in case we touch this code. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.8f54f2990b92.If19a038dfd633d4601e3d44dd0ff678bc0a851e9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 5 ++++- drivers/net/wireless/intel/iwlwifi/queue/tx.c | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 3546c5269c3b..1337fa95f657 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2003-2014, 2018-2021 Intel Corporation + * Copyright (C) 2003-2014, 2018-2021, 2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1547,6 +1547,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* there must be data left over for TB1 or this code must be changed */ BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_FIRST_TB_SIZE); + BUILD_BUG_ON(sizeof(struct iwl_cmd_header) + + offsetofend(struct iwl_tx_cmd, scratch) > + IWL_FIRST_TB_SIZE); /* map the data for TB1 */ tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE; diff --git a/drivers/net/wireless/intel/iwlwifi/queue/tx.c b/drivers/net/wireless/intel/iwlwifi/queue/tx.c index 245bff01b4f8..fbacbe9ada15 100644 --- a/drivers/net/wireless/intel/iwlwifi/queue/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/queue/tx.c @@ -648,6 +648,13 @@ struct iwl_tfh_tfd *iwl_txq_gen2_build_tfd(struct iwl_trans *trans, /* There must be data left over for TB1 or this code must be changed */ BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_gen2) < IWL_FIRST_TB_SIZE); + BUILD_BUG_ON(sizeof(struct iwl_cmd_header) + + offsetofend(struct iwl_tx_cmd_gen2, dram_info) > + IWL_FIRST_TB_SIZE); + BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_gen3) < IWL_FIRST_TB_SIZE); + BUILD_BUG_ON(sizeof(struct iwl_cmd_header) + + offsetofend(struct iwl_tx_cmd_gen3, dram_info) > + IWL_FIRST_TB_SIZE); memset(tfd, 0, sizeof(*tfd)); -- cgit v1.2.3 From 26aa35e2c5a1cbb05e939c92464437e205dd0087 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 20 Jun 2023 13:03:49 +0300 Subject: wifi: iwlwifi: mvm: check the right csa_active When the firmware says that the channel switch is happening, we check that we know about that switch by checking the csa_active bit. Until now, we checked the bss_conf from the vif instead of taking the bss_conf of the link. Fix that. Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.63f835a4f578.I0bb2a231e4da506b7c751dc23a428558f9ecfa75@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index b8143ae8b403..7369a45f7f2b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1763,6 +1763,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, u32 id; u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, CHANNEL_SWITCH_START_NOTIF, 0); + bool csa_active; rcu_read_lock(); @@ -1778,6 +1779,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, goto out_unlock; id = mac_id; + csa_active = vif->bss_conf.csa_active; } else { struct iwl_channel_switch_start_notif *notif = (void *)pkt->data; u32 link_id = le32_to_cpu(notif->link_id); @@ -1789,6 +1791,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, id = link_id; vif = bss_conf->vif; + csa_active = bss_conf->csa_active; } mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -1828,7 +1831,7 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, */ if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, CHANNEL_SWITCH_ERROR_NOTIF, - 0) && !vif->bss_conf.csa_active) { + 0) && !csa_active) { IWL_DEBUG_INFO(mvm, "Channel Switch was canceled\n"); iwl_mvm_cancel_channel_switch(mvm, vif, id); break; -- cgit v1.2.3 From eeef0168e3255732650ee81771e0d7e26e06a534 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Tue, 20 Jun 2023 13:03:50 +0300 Subject: wifi: iwlwifi: fw: send marker cmd before suspend cmd This is needed to sync the times in the FW and driver logs Signed-off-by: Miri Korenblit Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.9c84322c41b5.Id13816b3ece103f88514a7523b22bb2b9dcc8ab7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 56 +++++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 2 + drivers/net/wireless/intel/iwlwifi/fw/debugfs.c | 22 ---------- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 6 ++- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 3253d89e522a..3ab6a68f1e9f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2021 Intel Corporation + * Copyright (C) 2005-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -3154,6 +3154,51 @@ static int iwl_fw_dbg_restart_recording(struct iwl_trans *trans, return 0; } +int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt) +{ + struct iwl_mvm_marker marker = { + .dw_len = sizeof(struct iwl_mvm_marker) / 4, + .marker_id = MARKER_ID_SYNC_CLOCK, + }; + struct iwl_host_cmd hcmd = { + .flags = CMD_ASYNC, + .id = WIDE_ID(LONG_GROUP, MARKER_CMD), + .dataflags = {}, + }; + struct iwl_mvm_marker_rsp *resp; + int cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, + WIDE_ID(LONG_GROUP, MARKER_CMD), + IWL_FW_CMD_VER_UNKNOWN); + int ret; + + if (cmd_ver == 1) { + /* the real timestamp is taken from the ftrace clock + * this is for finding the match between fw and kernel logs + */ + marker.timestamp = cpu_to_le64(fwrt->timestamp.seq++); + } else if (cmd_ver == 2) { + marker.timestamp = cpu_to_le64(ktime_get_boottime_ns()); + } else { + IWL_DEBUG_INFO(fwrt, + "Invalid version of Marker CMD. Ver = %d\n", + cmd_ver); + return -EINVAL; + } + + hcmd.data[0] = ▮ + hcmd.len[0] = sizeof(marker); + + ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); + + if (cmd_ver > 1 && hcmd.resp_pkt) { + resp = (void *)hcmd.resp_pkt->data; + IWL_DEBUG_INFO(fwrt, "FW GP2 time: %u\n", + le32_to_cpu(resp->gp2)); + } + + return ret; +} + void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_params *params, bool stop) @@ -3164,12 +3209,15 @@ void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt, return; if (fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_DBG_SUSPEND_RESUME_CMD_SUPP)) + IWL_UCODE_TLV_CAPA_DBG_SUSPEND_RESUME_CMD_SUPP)) { + if (stop) + iwl_fw_send_timestamp_marker_cmd(fwrt); ret = iwl_fw_dbg_suspend_resume_hcmd(fwrt->trans, stop); - else if (stop) + } else if (stop) { iwl_fw_dbg_stop_recording(fwrt->trans, params); - else + } else { ret = iwl_fw_dbg_restart_recording(fwrt->trans, params); + } #ifdef CONFIG_IWLWIFI_DEBUGFS if (!ret) { if (stop) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index dcba0eefe70d..4227fbd2b977 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -227,6 +227,8 @@ static inline void iwl_fw_flush_dumps(struct iwl_fw_runtime *fwrt) flush_delayed_work(&fwrt->dump.wks[i].wk); } +int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt); + #ifdef CONFIG_IWLWIFI_DEBUGFS static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index ebacf0e9fb0f..3cdbc6ac7ae5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -123,28 +123,6 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \ #define FWRT_DEBUGFS_ADD_FILE(name, parent, mode) \ FWRT_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode) -static int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt) -{ - struct iwl_mvm_marker marker = { - .dw_len = sizeof(struct iwl_mvm_marker) / 4, - .marker_id = MARKER_ID_SYNC_CLOCK, - - /* the real timestamp is taken from the ftrace clock - * this is for finding the match between fw and kernel logs - */ - .timestamp = cpu_to_le64(fwrt->timestamp.seq++), - }; - - struct iwl_host_cmd hcmd = { - .id = MARKER_CMD, - .flags = CMD_ASYNC, - .data[0] = &marker, - .len[0] = sizeof(marker), - }; - - return iwl_trans_send_cmd(fwrt->trans, &hcmd); -} - static int iwl_dbgfs_enabled_severities_write(struct iwl_fw_runtime *fwrt, char *buf, size_t count) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index df689a9b7e2c..702586945533 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #ifndef __iwl_fw_runtime_h__ #define __iwl_fw_runtime_h__ @@ -146,12 +146,14 @@ struct iwl_fw_runtime { u32 umac_minor; } fw_ver; } dump; -#ifdef CONFIG_IWLWIFI_DEBUGFS struct { +#ifdef CONFIG_IWLWIFI_DEBUGFS struct delayed_work wk; u32 delay; +#endif u64 seq; } timestamp; +#ifdef CONFIG_IWLWIFI_DEBUGFS bool tpc_enabled; #endif /* CONFIG_IWLWIFI_DEBUGFS */ #ifdef CONFIG_ACPI -- cgit v1.2.3 From e119e740b1899169a19cf3cd43993a7d88c63bc6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 20 Jun 2023 13:03:51 +0300 Subject: wifi: iwlwifi: mvm: make iwl_mvm_set_fw_mu_edca_params mld aware We need to work on the right link there. Signed-off-by: Emmanuel Grumbach Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.8762a90e8857.Ic5b8e96140a449fd1ed7008907d67fc36fe98506@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 10 +++++----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 5fdebb911f7b..ace82e2c5bd9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -188,7 +188,7 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* TODO how to set ndp_fdbk_buff_th_exp? */ - if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif, + if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif->link[link_id], &cmd.trig_based_txf[0])) { flags |= LINK_FLG_MU_EDCA_CW; flags_mask |= LINK_FLG_MU_EDCA_CW; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 4c0a9cc9ff7c..ebe4163837a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2240,7 +2240,7 @@ int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm, * is enabled or not */ bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, + const struct iwl_mvm_vif_link_info *link_info, struct iwl_he_backoff_conf *trig_based_txf) { int i; @@ -2248,11 +2248,11 @@ bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, bool mu_edca_enabled = true; for (i = 0; i < IEEE80211_NUM_ACS; i++) { - struct ieee80211_he_mu_edca_param_ac_rec *mu_edca = - &mvmvif->deflink.queue_params[i].mu_edca_param_rec; + const struct ieee80211_he_mu_edca_param_ac_rec *mu_edca = + &link_info->queue_params[i].mu_edca_param_rec; u8 ac = iwl_mvm_mac80211_ac_to_ucode_ac(i); - if (!mvmvif->deflink.queue_params[i].mu_edca) { + if (!link_info->queue_params[i].mu_edca) { mu_edca_enabled = false; break; } @@ -2398,7 +2398,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, rcu_read_unlock(); - if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif, + if (iwl_mvm_set_fw_mu_edca_params(mvm, &mvmvif->deflink, &sta_ctxt_cmd.trig_based_txf[0])) flags |= STA_CTXT_HE_MU_EDCA_CW; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 11de81b58515..b575ce2f7146 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1804,7 +1804,7 @@ void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct iwl_ac_qos *ac, __le32 *qos_flags); bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, + const struct iwl_mvm_vif_link_info *link_info, struct iwl_he_backoff_conf *trig_based_txf); void iwl_mvm_set_fw_dtim_tbtt(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, -- cgit v1.2.3 From 592fef3eb6a576eb453c94b5ee1801cfb13c8dc8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:03:52 +0300 Subject: wifi: iwlwifi: nvm: handle EHT/320 MHz regulatory flag Handle the regulatory EHT/320 MHz flags from firmware just like any other flags before it. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.2c5e886c08f3.Ibc5c27d973d0590e2dea1f50435f9cf3ba8c2c09@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index d79d5453c2dc..39f13518ca5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -1567,10 +1567,17 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, if (!reg_capa.allow_160mhz) flags |= NL80211_RRF_NO_160MHZ; + + if (!reg_capa.allow_320mhz) + flags |= NL80211_RRF_NO_320MHZ; } + if (reg_capa.disable_11ax) flags |= NL80211_RRF_NO_HE; + if (reg_capa.disable_11be) + flags |= NL80211_RRF_NO_EHT; + return flags; } -- cgit v1.2.3 From c7fa5e682842dc55a0885c67edd289018a64fffd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:03:53 +0300 Subject: wifi: iwlwifi: mvm: use EHT maximum MPDU length on 2.4 GHz On 2.4 GHz there's no VHT, so EHT defines its own bits for the maximum MPDU length. Use them when telling firmware about the maximum. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.fd5322bb48a4.Ic471045f83229ceaacce25edcf992d3ce2c75de5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 2382725f25bd..6cba8a353b53 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -523,6 +523,7 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta, { const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap; const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap; + const struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; if (WARN_ON_ONCE(!link_conf->chandef.chan)) return IEEE80211_MAX_MPDU_LEN_VHT_3895; @@ -537,8 +538,18 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta, default: return IEEE80211_MAX_MPDU_LEN_VHT_3895; } - } else - if (vht_cap->vht_supported) { + } else if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ && + eht_cap->has_eht) { + switch (u8_get_bits(eht_cap->eht_cap_elem.mac_cap_info[0], + IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK)) { + case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454: + return IEEE80211_MAX_MPDU_LEN_VHT_11454; + case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991: + return IEEE80211_MAX_MPDU_LEN_VHT_7991; + default: + return IEEE80211_MAX_MPDU_LEN_VHT_3895; + } + } else if (vht_cap->vht_supported) { switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: return IEEE80211_MAX_MPDU_LEN_VHT_11454; -- cgit v1.2.3 From d51173c13b24925553489dff77c8cee136c7bfb1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:03:54 +0300 Subject: wifi: iwlwifi: mvm: use min_t() for agg_size We can use min_t() for the agg_size and avoid spelling out the (firmware) limit twice. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.211768036c1f.I78b7eea32eaae20cc9f32869aa3f42814634ce9a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index ff1ce990a9d8..3c24b25fe661 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -92,9 +92,8 @@ u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta, IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK); /* Limit to max A-MPDU supported by FW */ - if (agg_size > (STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT)) - agg_size = (STA_FLG_MAX_AGG_SIZE_4M >> - STA_FLG_MAX_AGG_SIZE_SHIFT); + agg_size = min_t(u32, agg_size, + STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT); *_agg_size = agg_size; return mpdu_dens; -- cgit v1.2.3 From 00e482010dfb5879fc9e8601d5819641fe4ae925 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:03:55 +0300 Subject: wifi: iwlwifi: mvm: add EHT A-MPDU size exponent support Add support for reading the EHT MAC capabilities A-MPDU size exponent field, as indicated by the draft spec. Also clarify the existing code a bit and add comments so it's clearer to understand what's going on here. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.c5e00045d90f.I7520787fca8f8430a564adedf975d069ad8c5417@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 3c24b25fe661..37a52ffa8897 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -60,22 +60,27 @@ u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta, if (WARN_ON(!link_sta)) return 0; - if (link_sta->ht_cap.ht_supported) + /* Note that we always use only legacy & highest supported PPDUs, so + * of Draft P802.11be D.30 Table 10-12a--Fields used for calculating + * the maximum A-MPDU size of various PPDU types in different bands, + * we only need to worry about the highest supported PPDU type here. + */ + + if (link_sta->ht_cap.ht_supported) { + agg_size = link_sta->ht_cap.ampdu_factor; mpdu_dens = link_sta->ht_cap.ampdu_density; + } - if (link_conf->chandef.chan->band == - NL80211_BAND_6GHZ) { + if (link_conf->chandef.chan->band == NL80211_BAND_6GHZ) { + /* overwrite HT values on 6 GHz */ mpdu_dens = le16_get_bits(link_sta->he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START); agg_size = le16_get_bits(link_sta->he_6ghz_capa.capa, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); } else if (link_sta->vht_cap.vht_supported) { - agg_size = link_sta->vht_cap.cap & - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; - agg_size >>= - IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; - } else if (link_sta->ht_cap.ht_supported) { - agg_size = link_sta->ht_cap.ampdu_factor; + /* if VHT supported overwrite HT value */ + agg_size = u32_get_bits(link_sta->vht_cap.cap, + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); } /* D6.0 10.12.2 A-MPDU length limit rules @@ -91,6 +96,10 @@ u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta, u8_get_bits(link_sta->he_cap.he_cap_elem.mac_cap_info[3], IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK); + if (link_sta->eht_cap.has_eht) + agg_size += u8_get_bits(link_sta->eht_cap.eht_cap_elem.mac_cap_info[1], + IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK); + /* Limit to max A-MPDU supported by FW */ agg_size = min_t(u32, agg_size, STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT); -- cgit v1.2.3 From 3a9690d030d8572736e07b912deea5547dd94db3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:03:56 +0300 Subject: wifi: iwlwifi: limit EHT capabilities based on PCIe link speed If a discrete NIC is connected to a PCIe link hat isn't at least Gen3 (8.0 GT/s), then we cannot sustain 320 MHz traffic, so remove that from EHT capabilities in that case. While at it, also move setting 320 MHz beamformee to the right place in the code so it's not set while not supporting 320 MHz. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.b77a1574a0a7.Id4120c161fb7df6dedc70d5f3e3829e9117b8cb1@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 15 +++++++++++---- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 4 ++++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 9 +++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 39f13518ca5b..8c23f57f5c89 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -680,8 +680,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, .phy_cap_info[1] = IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | - IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK | - IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, .phy_cap_info[3] = IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | @@ -890,6 +889,10 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, const struct iwl_fw *fw) { bool is_ap = iftype_data->types_mask & BIT(NL80211_IFTYPE_AP); + bool no_320; + + no_320 = !trans->trans_cfg->integrated && + trans->pcie_link_speed < PCI_EXP_LNKSTA_CLS_8_0GB; if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be) iftype_data->eht_cap.has_eht = false; @@ -916,8 +919,12 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); break; case NL80211_BAND_6GHZ: - iftype_data->eht_cap.eht_cap_elem.phy_cap_info[0] |= - IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + if (!no_320) { + iftype_data->eht_cap.eht_cap_elem.phy_cap_info[0] |= + IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + iftype_data->eht_cap.eht_cap_elem.phy_cap_info[1] |= + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK; + } fallthrough; case NL80211_BAND_5GHZ: iftype_data->he_cap.he_cap_elem.phy_cap_info[0] |= diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 1fa035decc03..d02943d0ea62 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1067,6 +1067,8 @@ struct iwl_trans_txqs { * @iwl_trans_txqs: transport tx queues data. * @mbx_addr_0_step: step address data 0 * @mbx_addr_1_step: step address data 1 + * @pcie_link_speed: current PCIe link speed (%PCI_EXP_LNKSTA_CLS_*), + * only valid for discrete (not integrated) NICs */ struct iwl_trans { bool csme_own; @@ -1129,6 +1131,8 @@ struct iwl_trans { u32 mbx_addr_0_step; u32 mbx_addr_1_step; + u8 pcie_link_speed; + /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ char trans_specific[] __aligned(sizeof(void *)); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index fcc0f3319bcd..18550c03f870 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1760,6 +1760,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) trans_pcie->num_rx_bufs = RX_QUEUE_SIZE; } + if (!iwl_trans->trans_cfg->integrated) { + u16 link_status; + + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &link_status); + + iwl_trans->pcie_link_speed = + u16_get_bits(link_status, PCI_EXP_LNKSTA_CLS); + } + ret = iwl_trans_init(iwl_trans); if (ret) goto out_free_trans; -- cgit v1.2.3 From c6b9d5664bc41f187b3c5327613569743e006154 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:03:57 +0300 Subject: wifi: iwlwifi: remove disable_dummy_notification This struct member is read-only, so can never change away from the default value of zero. Remove the code that's in an if on the value, since it's effectively dead code. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.e7c96d0aa805.I5b158ce15e48393d2896c0bff9f644d983f0e92d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 - drivers/net/wireless/intel/iwlwifi/mvm/sf.c | 5 +---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 17c357634455..115ea8d9198a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -388,7 +388,6 @@ struct iwl_cfg { high_temp:1, mac_addr_from_csr:10, lp_xtal_workaround:1, - disable_dummy_notification:1, apmg_not_supported:1, vht_mu_mimo_supported:1, cdb:1, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c index 98f330fcf678..30d4233595e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2019, 2022 Intel Corporation + * Copyright (C) 2013-2014, 2018-2019, 2022-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH */ #include "mvm.h" @@ -180,9 +180,6 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, struct ieee80211_sta *sta, }; int ret = 0; - if (mvm->cfg->disable_dummy_notification) - sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); - /* * If an associated AP sta changed its antenna configuration, the state * will remain FULL_ON but SF parameters need to be reconsidered. -- cgit v1.2.3 From c0a2f8194456af2759050a10f6d3111ad2b321da Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 20 Jun 2023 13:03:58 +0300 Subject: wifi: iwlwifi: mvm: send LARI configuration earlier Sending the LARI configuration may trigger calibration, which can have undesired side effects. Move the command to be send earlier (before the phy contexts are registered) to avoid unintended side effects. Signed-off-by: Benjamin Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.80742497eb3f.I3e599a796290082e6d331ea495a5591d55de4726@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 77cdfb4a5ba3..1f5db65a088d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1566,6 +1566,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + iwl_mvm_lari_cfg(mvm); + /* Init RSS configuration */ ret = iwl_configure_rxq(&mvm->fwrt); if (ret) @@ -1676,7 +1678,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; - iwl_mvm_lari_cfg(mvm); /* * RTNL is not taken during Ct-kill, but we don't need to scan/Tx * anyway, so don't init MCC. -- cgit v1.2.3 From 35bd6f1d043d089fcb60450e1287cc65f0095787 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Tue, 20 Jun 2023 13:03:59 +0300 Subject: wifi: iwlwifi: Add support for new PCI Id Add support for the PCI Id 51F1 without IMR support. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.9800e652e789.Ic06a085832ac3f988c8ef07d856c8e281563295d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 18550c03f870..4ba4dd881c2e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -495,6 +495,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x7AF0, PCI_ANY_ID, iwl_so_trans_cfg)}, {IWL_PCI_DEVICE(0x51F0, PCI_ANY_ID, iwl_so_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x51F1, PCI_ANY_ID, iwl_so_long_latency_imr_trans_cfg)}, + {IWL_PCI_DEVICE(0x51F1, PCI_ANY_ID, iwl_so_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x54F0, PCI_ANY_ID, iwl_so_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0x7F70, PCI_ANY_ID, iwl_so_trans_cfg)}, @@ -544,6 +545,7 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x51F0, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_160_name), IWL_DEV_INFO(0x51F0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x51F0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), + IWL_DEV_INFO(0x51F1, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x54F0, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), IWL_DEV_INFO(0x54F0, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x7A70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), -- cgit v1.2.3 From a6cc6ccb1c8ae9cbabd3dc4cf98c2b835bed2f6d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:04:00 +0300 Subject: wifi: iwlwifi: mvm: support new flush_sta method For iwlwifi this is simple to implement, and on newer hardware it's an improvement since we have per-station queues. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.a1f8ec20b727.I48594b708b41aa55dc2b8c3d346b4412ad3a5ba3@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 25 ++++++++++++++++++++++ .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ 3 files changed, 28 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index ebe4163837a0..f083ebda1e83 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -5652,6 +5652,30 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, iwl_trans_wait_tx_queues_empty(mvm->trans, msk); } +void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int i; + + mutex_lock(&mvm->mutex); + for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) { + struct iwl_mvm_sta *mvmsta; + struct ieee80211_sta *tmp; + + tmp = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], + lockdep_is_held(&mvm->mutex)); + if (tmp != sta) + continue; + + mvmsta = iwl_mvm_sta_from_mac80211(sta); + + if (iwl_mvm_flush_sta(mvm, mvmsta, false)) + IWL_ERR(mvm, "flush request fail\n"); + } + mutex_unlock(&mvm->mutex); +} + int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { @@ -6204,6 +6228,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, .flush = iwl_mvm_mac_flush, + .flush_sta = iwl_mvm_mac_flush_sta, .sched_scan_start = iwl_mvm_mac_sched_scan_start, .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, .set_key = iwl_mvm_mac_set_key, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 636ad2b76428..8b6c641772ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -1149,6 +1149,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, .flush = iwl_mvm_mac_flush, + .flush_sta = iwl_mvm_mac_flush_sta, .sched_scan_start = iwl_mvm_mac_sched_scan_start, .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, .set_key = iwl_mvm_mac_set_key, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index b575ce2f7146..b83df0631279 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2659,6 +2659,8 @@ void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_prep_tx_info *info); void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); +void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, -- cgit v1.2.3 From 2db72b8a700943aa54dce0aabe6ff1b72b615162 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:04:01 +0300 Subject: wifi: iwlwifi: mvm: indicate HW decrypt for beacon protection We've already done the 'decryption' here, so tell mac80211 it need not do it again. Fixes: b1fdc2505abc ("iwlwifi: mvm: advertise BIGTK client support if available") Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.a50cf68fbf2e.Ieceacbe3789d81ea02ae085ad8d1f8813a33c31b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 9dbe71d299ae..8d1e44fd9de7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -279,7 +279,8 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, struct ieee80211_hdr *hdr, struct iwl_rx_mpdu_desc *desc, - u32 status) + u32 status, + struct ieee80211_rx_status *stats) { struct iwl_mvm_sta *mvmsta; struct iwl_mvm_vif *mvmvif; @@ -308,8 +309,10 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, /* good cases */ if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK && - !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) + !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) { + stats->flag |= RX_FLAG_DECRYPTED; return 0; + } if (!sta) return -1; @@ -378,7 +381,7 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (unlikely(ieee80211_is_mgmt(hdr->frame_control) && !ieee80211_has_protected(hdr->frame_control))) - return iwl_mvm_rx_mgmt_prot(sta, hdr, desc, status); + return iwl_mvm_rx_mgmt_prot(sta, hdr, desc, status, stats); if (!ieee80211_has_protected(hdr->frame_control) || (status & IWL_RX_MPDU_STATUS_SEC_MASK) == -- cgit v1.2.3 From 1a528ab1da324d078ec60283c34c17848580df24 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:04:02 +0300 Subject: wifi: iwlwifi: mvm: avoid baid size integer overflow Roee reported various hard-to-debug crashes with pings in EHT aggregation scenarios. Enabling KASAN showed that we access the BAID allocation out of bounds, and looking at the code a bit shows that since the reorder buffer entry (struct iwl_mvm_reorder_buf_entry) is 128 bytes if debug such as lockdep is enabled, then staring from an agg size 512 we overflow the size calculation, and allocate a much smaller structure than we should, causing slab corruption once we initialize this. Fix this by simply using u32 instead of u16. Reported-by: Roee Goldfiner Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.f428c856030d.I2c2bb808e945adb71bc15f5b2bac2d8957ea90eb@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 37a52ffa8897..3b9a343d4f67 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2885,7 +2885,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, } if (iwl_mvm_has_new_rx_api(mvm) && start) { - u16 reorder_buf_size = buf_size * sizeof(baid_data->entries[0]); + u32 reorder_buf_size = buf_size * sizeof(baid_data->entries[0]); /* sparse doesn't like the __align() so don't check */ #ifndef __CHECKER__ -- cgit v1.2.3 From de1076008148460fe273e6d39158faffcc954991 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:04:03 +0300 Subject: wifi: iwlwifi: mvm: check only affected links When hostapd starts up, it may start up with only one link while the other is still scanning for overlapping BSSes. A station might start to connect at this point, but we run into this warning instead. Since there's no need to check for _all_ links, restrict the check to just the affected links that the STA will be using. Fixes: 57974a55d995 ("wifi: iwlwifi: mvm: refactor iwl_mvm_mac_sta_state_common()") Reported-by: Miri Korenblit Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.c3d5a006ec21.Ib4715381f598f4c18d67cd9598ebd5cdbe7d2b09@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index f083ebda1e83..ce7905faa08f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3836,6 +3836,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); + struct ieee80211_link_sta *link_sta; unsigned int link_id; int ret; @@ -3877,7 +3878,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); /* this would be a mac80211 bug ... but don't crash */ - for_each_mvm_vif_valid_link(mvmvif, link_id) { + for_each_sta_active_link(vif, sta, link_sta, link_id) { if (WARN_ON_ONCE(!mvmvif->link[link_id]->phy_ctxt)) { mutex_unlock(&mvm->mutex); return test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, -- cgit v1.2.3 From 4eca0fd5da06c084a60f9a6626df6343293bfecb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Jun 2023 13:04:04 +0300 Subject: wifi: iwlwifi: mvm: adjust skip-over-dtim in D3 The current formula can skip both too much and not enough time, given the +1 (where the comment about firmware is wrong). Adjust the formula accordingly. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.32406b6828ae.I88c315b85f7c56ac6109f84580b95a3dd104ff6c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 34d4b7a94d82..9131b5f1bc76 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -327,12 +327,11 @@ static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm, if (WARN_ON(!dtimper_tu)) return; - /* configure skip over dtim up to 306TU - 314 msec */ - skip = max_t(u8, 1, 306 / dtimper_tu); + /* configure skip over dtim up to 900 TU DTIM interval */ + skip = max_t(u8, 1, 900 / dtimper_tu); } - /* the firmware really expects "look at every X DTIMs", so add 1 */ - cmd->skip_dtim_periods = 1 + skip; + cmd->skip_dtim_periods = skip; cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); } -- cgit v1.2.3 From 69f778271f3ea4bd3d8b523c985aeea10d6b6f1a Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Tue, 20 Jun 2023 13:04:05 +0300 Subject: wifi: iwlwifi: mvm: Add support for scan version 17 Add support for scan request command version 17, which supports specifying the maximal EIRP PSD value that can be used for probe request transmission on a given channel. Signed-off-by: Ilan Peer Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230620125813.0a41c847d450.I0c9b45cc3eb39d44c75d3bdca84f0a91fdad1fa1@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 28 ++++-- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 113 ++++++++++++++++------- 2 files changed, 99 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 9cbeef16cfe5..93078f8cc08c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -727,8 +727,10 @@ enum iwl_umac_scan_general_params_flags2 { * @iter_interval: interval between two scan iterations on one channel. */ struct iwl_scan_channel_cfg_umac { +#define IWL_CHAN_CFG_FLAGS_BAND_POS 30 __le32 flags; - /* Both versions are of the same size, so use a union without adjusting + + /* All versions are of the same size, so use a union without adjusting * the command size later */ union { @@ -746,6 +748,12 @@ struct iwl_scan_channel_cfg_umac { * SCAN_CHANNEL_CONFIG_API_S_VER_3 * SCAN_CHANNEL_CONFIG_API_S_VER_4 */ + struct { + u8 channel_num; + u8 psd_20; + u8 iter_count; + u8 iter_interval; + } v5; /* SCAN_CHANNEL_CONFIG_API_S_VER_5 */ }; } __packed; @@ -982,7 +990,7 @@ struct iwl_scan_channel_params_v4 { SCAN_CHANNEL_PARAMS_API_S_VER_5 */ /** - * struct iwl_scan_channel_params_v6 + * struct iwl_scan_channel_params_v7 * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @n_aps_override: override the number of APs the FW uses to calculate dwell @@ -992,7 +1000,7 @@ struct iwl_scan_channel_params_v4 { * @channel_config: array of explicit channel configurations * for 2.4Ghz and 5.2Ghz bands */ -struct iwl_scan_channel_params_v6 { +struct iwl_scan_channel_params_v7 { u8 flags; u8 count; u8 n_aps_override[2]; @@ -1070,16 +1078,16 @@ struct iwl_scan_req_params_v12 { /** * struct iwl_scan_req_params_v16 * @general_params: &struct iwl_scan_general_params_v11 - * @channel_params: &struct iwl_scan_channel_params_v6 + * @channel_params: &struct iwl_scan_channel_params_v7 * @periodic_params: &struct iwl_scan_periodic_parms_v1 * @probe_params: &struct iwl_scan_probe_params_v4 */ -struct iwl_scan_req_params_v16 { +struct iwl_scan_req_params_v17 { struct iwl_scan_general_params_v11 general_params; - struct iwl_scan_channel_params_v6 channel_params; + struct iwl_scan_channel_params_v7 channel_params; struct iwl_scan_periodic_parms_v1 periodic_params; struct iwl_scan_probe_params_v4 probe_params; -} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_16, *_VER_15 and *_VER_14 */ +} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_17 - 14 */ /** * struct iwl_scan_req_umac_v12 @@ -1099,11 +1107,11 @@ struct iwl_scan_req_umac_v12 { * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @scan_params: scan parameters */ -struct iwl_scan_req_umac_v16 { +struct iwl_scan_req_umac_v17 { __le32 uid; __le32 ooc_priority; - struct iwl_scan_req_params_v16 scan_params; -} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_16, *_VER_15 and *_VER_14 */ + struct iwl_scan_req_params_v17 scan_params; +} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_17 - 14 */ /** * struct iwl_umac_scan_abort diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index b2154e9fcf01..c1d9ce753468 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1627,11 +1627,11 @@ iwl_mvm_umac_scan_cfg_channels_v4(struct iwl_mvm *mvm, } static void -iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, +iwl_mvm_umac_scan_cfg_channels_v7(struct iwl_mvm *mvm, struct ieee80211_channel **channels, - struct iwl_scan_channel_params_v6 *cp, + struct iwl_scan_channel_params_v7 *cp, int n_channels, u32 flags, - enum nl80211_iftype vif_type) + enum nl80211_iftype vif_type, u32 version) { int i; @@ -1641,14 +1641,19 @@ iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm, u32 n_aps_flag = iwl_mvm_scan_ch_n_aps_flag(vif_type, channels[i]->hw_value); + u8 iwl_band = iwl_mvm_phy_band_from_nl80211(band); cfg->flags = cpu_to_le32(flags | n_aps_flag); cfg->v2.channel_num = channels[i]->hw_value; - cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band); if (cfg80211_channel_is_psc(channels[i])) cfg->flags = 0; cfg->v2.iter_count = 1; cfg->v2.iter_interval = 0; + if (version < 17) + cfg->v2.band = iwl_band; + else + cfg->flags |= cpu_to_le32((iwl_band << + IWL_CHAN_CFG_FLAGS_BAND_POS)); } } @@ -1723,14 +1728,15 @@ iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm *mvm, pp->bssid_num = idex_b; } -/* TODO: this function can be merged with iwl_mvm_scan_umac_fill_ch_p_v6 */ +/* TODO: this function can be merged with iwl_mvm_scan_umac_fill_ch_p_v7 */ static u32 -iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, +iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, u32 n_channels, struct iwl_scan_probe_params_v4 *pp, - struct iwl_scan_channel_params_v6 *cp, - enum nl80211_iftype vif_type) + struct iwl_scan_channel_params_v7 *cp, + enum nl80211_iftype vif_type, + u32 version) { int i; struct cfg80211_scan_6ghz_params *scan_6ghz_params = @@ -1745,6 +1751,7 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, u8 j, k, s_max = 0, b_max = 0, n_used_bssid_entries; bool force_passive, found = false, allow_passive = true, unsolicited_probe_on_chan = false, psc_no_listen = false; + s8 psd_20 = IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED; /* * Avoid performing passive scan on non PSC channels unless the @@ -1756,9 +1763,14 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, continue; cfg->v1.channel_num = params->channels[i]->hw_value; - cfg->v2.band = 2; - cfg->v2.iter_count = 1; - cfg->v2.iter_interval = 0; + if (version < 17) + cfg->v2.band = PHY_BAND_6; + else + cfg->flags |= cpu_to_le32(PHY_BAND_6 << + IWL_CHAN_CFG_FLAGS_BAND_POS); + + cfg->v5.iter_count = 1; + cfg->v5.iter_interval = 0; /* * The optimize the scan time, i.e., reduce the scan dwell time @@ -1769,9 +1781,22 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, */ n_used_bssid_entries = 3; for (j = 0; j < params->n_6ghz_params; j++) { + s8 tmp_psd_20; + if (!(scan_6ghz_params[j].channel_idx == i)) continue; + /* Use the highest PSD value allowed as advertised by + * APs for this channel + */ + tmp_psd_20 = scan_6ghz_params[j].psd_20; + if (tmp_psd_20 != + IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED && + (psd_20 == + IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED || + psd_20 < tmp_psd_20)) + psd_20 = tmp_psd_20; + found = false; unsolicited_probe_on_chan |= scan_6ghz_params[j].unsolicited_probe; @@ -1875,6 +1900,9 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm, flags |= bssid_bitmap | (s_ssid_bitmap << 16); cfg->flags |= cpu_to_le32(flags); + if (version >= 17) + cfg->v5.psd_20 = psd_20; + ch_cnt++; } @@ -2369,21 +2397,22 @@ iwl_mvm_scan_umac_fill_ch_p_v4(struct iwl_mvm *mvm, } static void -iwl_mvm_scan_umac_fill_ch_p_v6(struct iwl_mvm *mvm, +iwl_mvm_scan_umac_fill_ch_p_v7(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif, - struct iwl_scan_channel_params_v6 *cp, - u32 channel_cfg_flags) + struct iwl_scan_channel_params_v7 *cp, + u32 channel_cfg_flags, + u32 version) { cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); cp->count = params->n_channels; cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS; - iwl_mvm_umac_scan_cfg_channels_v6(mvm, params->channels, cp, + iwl_mvm_umac_scan_cfg_channels_v7(mvm, params->channels, cp, params->n_channels, channel_cfg_flags, - vif->type); + vif->type, version); if (params->enable_6ghz_passive) { struct ieee80211_supported_band *sband = @@ -2400,11 +2429,19 @@ iwl_mvm_scan_umac_fill_ch_p_v6(struct iwl_mvm *mvm, if (!cfg80211_channel_is_psc(channel)) continue; - cfg->flags = 0; - cfg->v2.channel_num = channel->hw_value; - cfg->v2.band = PHY_BAND_6; - cfg->v2.iter_count = 1; - cfg->v2.iter_interval = 0; + cfg->v5.channel_num = channel->hw_value; + cfg->v5.iter_count = 1; + cfg->v5.iter_interval = 0; + + if (version < 17) { + cfg->flags = 0; + cfg->v2.band = PHY_BAND_6; + } else { + cfg->flags = cpu_to_le32(PHY_BAND_6 << + IWL_CHAN_CFG_FLAGS_BAND_POS); + cfg->v5.psd_20 = + IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED; + } cp->count++; } } @@ -2447,9 +2484,9 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, int type, int uid, u32 version) { - struct iwl_scan_req_umac_v16 *cmd = mvm->scan_cmd; - struct iwl_scan_req_params_v16 *scan_p = &cmd->scan_params; - struct iwl_scan_channel_params_v6 *cp = &scan_p->channel_params; + struct iwl_scan_req_umac_v17 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v17 *scan_p = &cmd->scan_params; + struct iwl_scan_channel_params_v7 *cp = &scan_p->channel_params; struct iwl_scan_probe_params_v4 *pb = &scan_p->probe_params; int ret; u16 gen_flags; @@ -2479,11 +2516,13 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, return ret; if (!params->scan_6ghz) { - iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, - &bitmap_ssid); - iwl_mvm_scan_umac_fill_ch_p_v6(mvm, params, vif, - &scan_p->channel_params, bitmap_ssid); - + iwl_mvm_scan_umac_fill_probe_p_v4(params, + &scan_p->probe_params, + &bitmap_ssid); + iwl_mvm_scan_umac_fill_ch_p_v7(mvm, params, vif, + &scan_p->channel_params, + bitmap_ssid, + version); return 0; } else { pb->preq = params->preq; @@ -2495,9 +2534,10 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, iwl_mvm_umac_scan_fill_6g_chan_list(mvm, params, pb); - cp->count = iwl_mvm_umac_scan_cfg_channels_v6_6g(mvm, params, + cp->count = iwl_mvm_umac_scan_cfg_channels_v7_6g(mvm, params, params->n_channels, - pb, cp, vif->type); + pb, cp, vif->type, + version); if (!cp->count) { mvm->scan_uid_status[uid] = 0; return -EINVAL; @@ -2531,6 +2571,13 @@ static int iwl_mvm_scan_umac_v16(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 16); } +static int iwl_mvm_scan_umac_v17(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 17); +} + static int iwl_mvm_num_scans(struct iwl_mvm *mvm) { return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); @@ -2646,6 +2693,7 @@ struct iwl_scan_umac_handler { static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { /* set the newest version first to shorten the list traverse time */ + IWL_SCAN_UMAC_HANDLER(17), IWL_SCAN_UMAC_HANDLER(16), IWL_SCAN_UMAC_HANDLER(15), IWL_SCAN_UMAC_HANDLER(14), @@ -3236,7 +3284,8 @@ static size_t iwl_scan_req_umac_get_size(u8 scan_ver) case 14: case 15: case 16: - return sizeof(struct iwl_scan_req_umac_v16); + case 17: + return sizeof(struct iwl_scan_req_umac_v17); } return 0; -- cgit v1.2.3 From 8a18d46b7507553bdf40f48d3cd7d2be5f6aa7b8 Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Wed, 21 Jun 2023 13:12:05 +0300 Subject: wifi: iwlwifi: Add support for new Bz version Add support for the new version of the Bz CNVI device. Signed-off-by: Mukesh Sisodiya Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.82d436d5f346.I0154c202c5d895cb002a2b7c827b9536e81a84b5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 44 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 4 +++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 33 +++++++++++++++---- 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 5ac9416331de..fbd73fa24230 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -67,6 +67,10 @@ #define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0-" #define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0-" #define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0-" +#define IWL_BZ_B_GF_A_FW_PRE "iwlwifi-bz-b0-gf-a0-" +#define IWL_BZ_B_GF4_A_FW_PRE "iwlwifi-bz-b0-gf4-a0-" +#define IWL_BZ_B_FM_B_FW_PRE "iwlwifi-bz-b0-fm-b0-" +#define IWL_BZ_B_FM4_B_FW_PRE "iwlwifi-bz-b0-fm4-b0-" #define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-" #define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0-" #define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0-" @@ -160,6 +164,14 @@ IWL_BZ_A_FM_C_FW_PRE __stringify(api) ".ucode" #define IWL_BZ_A_FM4_B_MODULE_FIRMWARE(api) \ IWL_BZ_A_FM4_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_B_GF_A_MODULE_FIRMWARE(api) \ + IWL_BZ_B_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_B_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BZ_B_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_B_FM_B_MODULE_FIRMWARE(api) \ + IWL_BZ_B_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_B_FM4_B_MODULE_FIRMWARE(api) \ + IWL_BZ_B_FM4_B_FW_PRE __stringify(api) ".ucode" #define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode" #define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \ @@ -1029,6 +1041,22 @@ const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_bz_b0_gf_a0 = { + .fw_name_pre = IWL_BZ_B_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_b0_gf4_a0 = { + .fw_name_pre = IWL_BZ_B_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + const struct iwl_cfg iwl_cfg_bz_a0_mr_a0 = { .fw_name_pre = IWL_BZ_A_MR_A_FW_PRE, .uhb_supported = true, @@ -1077,6 +1105,22 @@ const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_bz_b0_fm_b0 = { + .fw_name_pre = IWL_BZ_B_FM_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_b0_fm4_b0 = { + .fw_name_pre = IWL_BZ_B_FM4_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = { .fw_name_pre = IWL_GL_A_FM_A_FW_PRE, .uhb_supported = true, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 115ea8d9198a..6d7f15f277bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -653,12 +653,16 @@ extern const struct iwl_cfg iwl_cfg_bz_a0_hr_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_hr_b0; extern const struct iwl_cfg iwl_cfg_bz_a0_gf_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0; +extern const struct iwl_cfg iwl_cfg_bz_b0_gf_a0; +extern const struct iwl_cfg iwl_cfg_bz_b0_gf4_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_mr_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm_b0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm_c0; extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0; +extern const struct iwl_cfg iwl_cfg_bz_b0_fm_b0; +extern const struct iwl_cfg iwl_cfg_bz_b0_fm4_b0; extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_gl_b0_fm_b0; extern const struct iwl_cfg iwl_cfg_gl_c0_fm_c0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 4ba4dd881c2e..6c691121ad4c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1173,15 +1173,25 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl_cfg_bz_a0_hr_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl_cfg_bz_a0_gf_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, iwl_cfg_bz_a0_gf4_a0, iwl_bz_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + iwl_cfg_bz_b0_gf_a0, iwl_bz_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + iwl_cfg_bz_b0_gf4_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, @@ -1193,25 +1203,36 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl_cfg_bz_a0_fm_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET, iwl_cfg_bz_a0_fm4_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, iwl_cfg_bz_a0_fm_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, iwl_cfg_bz_a0_fm_c0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET, iwl_cfg_bz_a0_fm4_b0, iwl_bz_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + iwl_cfg_bz_b0_fm_b0, iwl_bz_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET, + iwl_cfg_bz_b0_fm4_b0, iwl_bz_name), +/* Ga (Gl) */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, -- cgit v1.2.3 From e1374ed25324e87d675bda735841d8424d83c81d Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Wed, 21 Jun 2023 13:12:06 +0300 Subject: wifi: iwlwifi: Add support for new CNVi (SC) Add support for the new Integrated Connectivity (CNVi) and Companion RF (CRF) versions and their combinations to handle new devices. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.716fd707e847.I34f6ffd61e3210c926868a3e961b16d1742bba29@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 89 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 11 +++ drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 38 ++++++++++- 3 files changed, 137 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index fbd73fa24230..a6fa57517188 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -89,6 +89,13 @@ #define IWL_BNJ_B_HR_B_FW_PRE "iwlwifi-BzBnj-b0-hr-b0-" #define IWL_BNJ_B_FM_B_FW_PRE "iwlwifi-BzBnj-b0-fm-b0-" +#define IWL_SC_A_FM_B_FW_PRE "iwlwifi-sc-a0-fm-b0-" +#define IWL_SC_A_FM_C_FW_PRE "iwlwifi-sc-a0-fm-c0-" +#define IWL_SC_A_HR_A_FW_PRE "iwlwifi-sc-a0-hr-b0-" +#define IWL_SC_A_HR_B_FW_PRE "iwlwifi-sc-a0-hr-b0-" +#define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0-" +#define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0-" +#define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0-" #define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ IWL_QU_B_HR_B_FW_PRE __stringify(api) ".ucode" @@ -203,6 +210,20 @@ IWL_BNJ_B_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_BNJ_B_FM_B_MODULE_FIRMWARE(api) \ IWL_BNJ_B_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_FM_C_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_FM_C_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_HR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_WH_A_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl_22000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -390,6 +411,10 @@ static const struct iwl_ht_params iwl_gl_a_ht_params = { IWL_DEVICE_BZ_COMMON, \ .ht_params = &iwl_gl_a_ht_params +#define IWL_DEVICE_SC \ + IWL_DEVICE_BZ_COMMON, \ + .ht_params = &iwl_22000_ht_params + const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = { .mq_rx_supported = true, .use_tfh = true, @@ -586,6 +611,7 @@ const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; const char iwl_bz_name[] = "Intel(R) TBD Bz device"; +const char iwl_sc_name[] = "Intel(R) TBD Sc device"; const char iwl_ax200_killer_1650w_name[] = "Killer(R) Wi-Fi 6 AX1650w 160MHz Wireless Network Adapter (200D2W)"; @@ -1249,6 +1275,62 @@ const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_sc_a0_fm_b0 = { + .fw_name_pre = IWL_SC_A_FM_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_fm_c0 = { + .fw_name_pre = IWL_SC_A_FM_C_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_hr_a0 = { + .fw_name_pre = IWL_SC_A_HR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_hr_b0 = { + .fw_name_pre = IWL_SC_A_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_gf_a0 = { + .fw_name_pre = IWL_SC_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_gf4_a0 = { + .fw_name_pre = IWL_SC_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_wh_a0 = { + .fw_name_pre = IWL_SC_A_WH_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); @@ -1300,3 +1382,10 @@ MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BNJ_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_FM_C_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 6d7f15f277bb..37ae57adf950 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -2,6 +2,7 @@ /* * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2018-2023 Intel Corporation */ #ifndef __IWL_CONFIG_H__ #define __IWL_CONFIG_H__ @@ -426,6 +427,7 @@ struct iwl_cfg { #define IWL_CFG_MAC_TYPE_MA 0x44 #define IWL_CFG_MAC_TYPE_BZ 0x46 #define IWL_CFG_MAC_TYPE_GL 0x47 +#define IWL_CFG_MAC_TYPE_SC 0x48 #define IWL_CFG_RF_TYPE_TH 0x105 #define IWL_CFG_RF_TYPE_TH1 0x108 @@ -437,6 +439,7 @@ struct iwl_cfg { #define IWL_CFG_RF_TYPE_MR 0x110 #define IWL_CFG_RF_TYPE_MS 0x111 #define IWL_CFG_RF_TYPE_FM 0x112 +#define IWL_CFG_RF_TYPE_WH 0x113 #define IWL_CFG_RF_ID_TH 0x1 #define IWL_CFG_RF_ID_TH1 0x1 @@ -534,6 +537,7 @@ extern const char iwl_ax221_name[]; extern const char iwl_ax231_name[]; extern const char iwl_ax411_name[]; extern const char iwl_bz_name[]; +extern const char iwl_sc_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; extern const struct iwl_cfg iwl5100_agn_cfg; @@ -679,6 +683,13 @@ extern const struct iwl_cfg iwl_cfg_bnj_b0_hr_a0; extern const struct iwl_cfg iwl_cfg_bnj_b0_hr_b0; extern const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0; extern const struct iwl_cfg iwl_cfg_bnj_b0_fm4_b0; +extern const struct iwl_cfg iwl_cfg_sc_a0_fm_b0; +extern const struct iwl_cfg iwl_cfg_sc_a0_fm_c0; +extern const struct iwl_cfg iwl_cfg_sc_a0_hr_a0; +extern const struct iwl_cfg iwl_cfg_sc_a0_hr_b0; +extern const struct iwl_cfg iwl_cfg_sc_a0_gf_a0; +extern const struct iwl_cfg iwl_cfg_sc_a0_gf4_a0; +extern const struct iwl_cfg iwl_cfg_sc_a0_wh_a0; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 6c691121ad4c..3f303ca13412 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1419,8 +1419,44 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MS, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_ms_a0, iwl_ax204_name) + iwl_cfg_snj_a0_ms_a0, iwl_ax204_name), +/* Sc */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + iwl_cfg_sc_a0_fm_b0, iwl_sc_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + iwl_cfg_sc_a0_fm_c0, iwl_sc_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, + IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + iwl_cfg_sc_a0_hr_a0, iwl_sc_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, + IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + iwl_cfg_sc_a0_hr_b0, iwl_sc_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + iwl_cfg_sc_a0_gf_a0, iwl_sc_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, + IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + iwl_cfg_sc_a0_gf4_a0, iwl_sc_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, + IWL_CFG_RF_TYPE_WH, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + iwl_cfg_sc_a0_wh_a0, iwl_sc_name), #endif /* CONFIG_IWLMVM */ }; -- cgit v1.2.3 From 19898ce9cf8a33e0ac35cb4c7f68de297cc93cb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:07 +0300 Subject: wifi: iwlwifi: split 22000.c into multiple files Split the configuration list in 22000.c into four new files, per new device family, so we don't have this huge unusable file. Yes, this duplicates a few small things, but that's still much better than what we have now. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.7543603b2ee7.Ia8dd54216d341ef1ddc0531f2c9aa30d30536a5d@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/Makefile | 1 + drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 939 +----------------------- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 452 ++++++++++++ drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 523 +++++++++++++ drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 214 ++++++ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 + drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 3 + 7 files changed, 1206 insertions(+), 928 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/ax210.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/bz.c create mode 100644 drivers/net/wireless/intel/iwlwifi/cfg/sc.c diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 75a703eb1bdf..b983982aee45 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -11,6 +11,7 @@ iwlwifi-objs += pcie/ctxt-info.o pcie/ctxt-info-gen3.o iwlwifi-objs += pcie/trans-gen2.o pcie/tx-gen2.o iwlwifi-$(CONFIG_IWLDVM) += cfg/1000.o cfg/2000.o cfg/5000.o cfg/6000.o iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/22000.o +iwlwifi-$(CONFIG_IWLMVM) += cfg/ax210.o cfg/bz.o cfg/sc.o iwlwifi-objs += iwl-dbg-tlv.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += queue/tx.o diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index a6fa57517188..12e809b715f4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -10,8 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 81 -#define IWL_22500_UCODE_API_MAX 77 +#define IWL_22000_UCODE_API_MAX 77 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 @@ -36,66 +35,6 @@ #define IWL_QUZ_A_JF_B_FW_PRE "iwlwifi-QuZ-a0-jf-b0-" #define IWL_QNJ_B_JF_B_FW_PRE "iwlwifi-QuQnj-b0-jf-b0-" #define IWL_CC_A_FW_PRE "iwlwifi-cc-a0-" -#define IWL_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0-" -#define IWL_SO_A_HR_B_FW_PRE "iwlwifi-so-a0-hr-b0-" -#define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0-" -#define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0-" -#define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0-" -#define IWL_SO_A_MR_A_FW_PRE "iwlwifi-so-a0-mr-a0-" -#define IWL_SNJ_A_GF4_A_FW_PRE "iwlwifi-SoSnj-a0-gf4-a0-" -#define IWL_SNJ_A_GF_A_FW_PRE "iwlwifi-SoSnj-a0-gf-a0-" -#define IWL_SNJ_A_HR_B_FW_PRE "iwlwifi-SoSnj-a0-hr-b0-" -#define IWL_SNJ_A_JF_B_FW_PRE "iwlwifi-SoSnj-a0-jf-b0-" -#define IWL_MA_A_HR_B_FW_PRE "iwlwifi-ma-a0-hr-b0-" -#define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0-" -#define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0-" -#define IWL_MA_A_MR_A_FW_PRE "iwlwifi-ma-a0-mr-a0-" -#define IWL_MA_A_FM_A_FW_PRE "iwlwifi-ma-a0-fm-a0-" -#define IWL_MA_B_HR_B_FW_PRE "iwlwifi-ma-b0-hr-b0-" -#define IWL_MA_B_GF_A_FW_PRE "iwlwifi-ma-b0-gf-a0-" -#define IWL_MA_B_GF4_A_FW_PRE "iwlwifi-ma-b0-gf4-a0-" -#define IWL_MA_B_MR_A_FW_PRE "iwlwifi-ma-b0-mr-a0-" -#define IWL_MA_B_FM_A_FW_PRE "iwlwifi-ma-b0-fm-a0-" -#define IWL_SNJ_A_MR_A_FW_PRE "iwlwifi-SoSnj-a0-mr-a0-" -#define IWL_BZ_A_HR_A_FW_PRE "iwlwifi-bz-a0-hr-b0-" -#define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0-" -#define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0-" -#define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0-" -#define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-" -#define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-" -#define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0-" -#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0-" -#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0-" -#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0-" -#define IWL_BZ_B_GF_A_FW_PRE "iwlwifi-bz-b0-gf-a0-" -#define IWL_BZ_B_GF4_A_FW_PRE "iwlwifi-bz-b0-gf4-a0-" -#define IWL_BZ_B_FM_B_FW_PRE "iwlwifi-bz-b0-fm-b0-" -#define IWL_BZ_B_FM4_B_FW_PRE "iwlwifi-bz-b0-fm4-b0-" -#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-" -#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0-" -#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0-" - -#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" -#define IWL_BNJ_A_FM_A_FW_PRE "iwlwifi-BzBnj-a0-fm-a0-" -#define IWL_BNJ_A_FM4_A_FW_PRE "iwlwifi-BzBnj-a0-fm4-a0-" -#define IWL_BNJ_B_FM4_B_FW_PRE "iwlwifi-BzBnj-b0-fm4-b0-" -#define IWL_BNJ_A_GF_A_FW_PRE "iwlwifi-BzBnj-a0-gf-a0-" -#define IWL_BNJ_B_GF_A_FW_PRE "iwlwifi-BzBnj-b0-gf-a0-" -#define IWL_BNJ_A_GF4_A_FW_PRE "iwlwifi-BzBnj-a0-gf4-a0-" -#define IWL_BNJ_B_GF4_A_FW_PRE "iwlwifi-BzBnj-b0-gf4-a0-" -#define IWL_BNJ_A_HR_A_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-" -#define IWL_BNJ_A_HR_B_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-" -#define IWL_BNJ_B_HR_A_FW_PRE "iwlwifi-BzBnj-b0-hr-b0-" -#define IWL_BNJ_B_HR_B_FW_PRE "iwlwifi-BzBnj-b0-hr-b0-" -#define IWL_BNJ_B_FM_B_FW_PRE "iwlwifi-BzBnj-b0-fm-b0-" - -#define IWL_SC_A_FM_B_FW_PRE "iwlwifi-sc-a0-fm-b0-" -#define IWL_SC_A_FM_C_FW_PRE "iwlwifi-sc-a0-fm-c0-" -#define IWL_SC_A_HR_A_FW_PRE "iwlwifi-sc-a0-hr-b0-" -#define IWL_SC_A_HR_B_FW_PRE "iwlwifi-sc-a0-hr-b0-" -#define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0-" -#define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0-" -#define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0-" #define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ IWL_QU_B_HR_B_FW_PRE __stringify(api) ".ucode" @@ -113,117 +52,6 @@ IWL_QNJ_B_JF_B_FW_PRE __stringify(api) ".ucode" #define IWL_CC_A_MODULE_FIRMWARE(api) \ IWL_CC_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SO_A_JF_B_MODULE_FIRMWARE(api) \ - IWL_SO_A_JF_B_FW_PRE __stringify(api) ".ucode" -#define IWL_SO_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_SO_A_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_SO_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_SO_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_TY_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_TY_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_GF4_A_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_JF_B_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_JF_B_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_MR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_FM_A_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_MR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_FM_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_MR_A_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_MR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_HR_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_HR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_BZ_A_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_MR_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_MR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_FM_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_FM4_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_FM_B_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_FM_C_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM_C_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_A_FM4_B_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM4_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_B_GF_A_MODULE_FIRMWARE(api) \ - IWL_BZ_B_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_B_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BZ_B_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_B_FM_B_MODULE_FIRMWARE(api) \ - IWL_BZ_B_FM_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BZ_B_FM4_B_MODULE_FIRMWARE(api) \ - IWL_BZ_B_FM4_B_FW_PRE __stringify(api) ".ucode" -#define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ - IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode" -#define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \ - IWL_GL_B_FM_B_FW_PRE __stringify(api) ".ucode" -#define IWL_GL_C_FM_C_MODULE_FIRMWARE(api) \ - IWL_GL_C_FM_C_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_FM_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_FM_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_FM4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_FM4_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_GF_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_GF4_A_FW_PRE __stringify(api) ".ucode" - -#define IWL_BNJ_A_HR_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_HR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_HR_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_HR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_HR_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_FM_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_FM_B_FW_PRE __stringify(api) ".ucode" -#define IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_FM_B_FW_PRE __stringify(api) ".ucode" -#define IWL_SC_A_FM_C_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_FM_C_FW_PRE __stringify(api) ".ucode" -#define IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_HR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_WH_A_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl_22000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -237,32 +65,13 @@ static const struct iwl_base_params iwl_22000_base_params = { .pcie_l1_allowed = true, }; -static const struct iwl_base_params iwl_ax210_base_params = { - .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, - .num_of_queues = 512, - .max_tfd_queue_size = 65536, - .shadow_ram_support = true, - .led_compensation = 57, - .wd_timeout = IWL_LONG_WD_TIMEOUT, - .max_event_log_size = 512, - .shadow_reg_enable = true, - .pcie_l1_allowed = true, -}; - -static const struct iwl_ht_params iwl_22000_ht_params = { +const struct iwl_ht_params iwl_22000_ht_params = { .stbc = true, .ldpc = true, .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | BIT(NL80211_BAND_6GHZ), }; -static const struct iwl_ht_params iwl_gl_a_ht_params = { - .stbc = false, /* we explicitly disable STBC for GL step A */ - .ldpc = true, - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | - BIT(NL80211_BAND_6GHZ), -}; - #define IWL_DEVICE_22000_COMMON \ .ucode_api_min = IWL_22000_UCODE_API_MIN, \ .led_mode = IWL_LED_RF_STATE, \ @@ -302,7 +111,7 @@ static const struct iwl_ht_params iwl_gl_a_ht_params = { #define IWL_DEVICE_22500 \ IWL_DEVICE_22000_COMMON, \ - .ucode_api_max = IWL_22500_UCODE_API_MAX, \ + .ucode_api_max = IWL_22000_UCODE_API_MAX, \ .trans.device_family = IWL_DEVICE_FAMILY_22000, \ .trans.base_params = &iwl_22000_base_params, \ .gp2_reg_addr = 0xa02c68, \ @@ -317,104 +126,6 @@ static const struct iwl_ht_params iwl_gl_a_ht_params = { }, \ } -#define IWL_DEVICE_AX210 \ - IWL_DEVICE_22000_COMMON, \ - .ucode_api_max = IWL_22000_UCODE_API_MAX, \ - .trans.umac_prph_offset = 0x300000, \ - .trans.device_family = IWL_DEVICE_FAMILY_AX210, \ - .trans.base_params = &iwl_ax210_base_params, \ - .min_txq_size = 128, \ - .gp2_reg_addr = 0xd02c68, \ - .min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_HE, \ - .mon_dram_regs = { \ - .write_ptr = { \ - .addr = DBGC_CUR_DBGBUF_STATUS, \ - .mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK, \ - }, \ - .cycle_cnt = { \ - .addr = DBGC_DBGBUF_WRAP_AROUND, \ - .mask = 0xffffffff, \ - }, \ - .cur_frag = { \ - .addr = DBGC_CUR_DBGBUF_STATUS, \ - .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ - }, \ - } - -#define IWL_DEVICE_BZ_COMMON \ - .ucode_api_max = IWL_22000_UCODE_API_MAX, \ - .ucode_api_min = IWL_22000_UCODE_API_MIN, \ - .led_mode = IWL_LED_RF_STATE, \ - .nvm_hw_section_num = 10, \ - .non_shared_ant = ANT_B, \ - .dccm_offset = IWL_22000_DCCM_OFFSET, \ - .dccm_len = IWL_22000_DCCM_LEN, \ - .dccm2_offset = IWL_22000_DCCM2_OFFSET, \ - .dccm2_len = IWL_22000_DCCM2_LEN, \ - .smem_offset = IWL_22000_SMEM_OFFSET, \ - .smem_len = IWL_22000_SMEM_LEN, \ - .apmg_not_supported = true, \ - .trans.mq_rx_supported = true, \ - .vht_mu_mimo_supported = true, \ - .mac_addr_from_csr = 0x30, \ - .nvm_ver = IWL_22000_NVM_VERSION, \ - .trans.use_tfh = true, \ - .trans.rf_id = true, \ - .trans.gen2 = true, \ - .nvm_type = IWL_NVM_EXT, \ - .dbgc_supported = true, \ - .min_umac_error_event_table = 0xD0000, \ - .d3_debug_data_base_addr = 0x401000, \ - .d3_debug_data_length = 60 * 1024, \ - .mon_smem_regs = { \ - .write_ptr = { \ - .addr = LDBG_M2S_BUF_WPTR, \ - .mask = LDBG_M2S_BUF_WPTR_VAL_MSK, \ - }, \ - .cycle_cnt = { \ - .addr = LDBG_M2S_BUF_WRAP_CNT, \ - .mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \ - }, \ - }, \ - .trans.umac_prph_offset = 0x300000, \ - .trans.device_family = IWL_DEVICE_FAMILY_BZ, \ - .trans.base_params = &iwl_ax210_base_params, \ - .min_txq_size = 128, \ - .gp2_reg_addr = 0xd02c68, \ - .min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_EHT, \ - .mon_dram_regs = { \ - .write_ptr = { \ - .addr = DBGC_CUR_DBGBUF_STATUS, \ - .mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK, \ - }, \ - .cycle_cnt = { \ - .addr = DBGC_DBGBUF_WRAP_AROUND, \ - .mask = 0xffffffff, \ - }, \ - .cur_frag = { \ - .addr = DBGC_CUR_DBGBUF_STATUS, \ - .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ - }, \ - }, \ - .mon_dbgi_regs = { \ - .write_ptr = { \ - .addr = DBGI_SRAM_FIFO_POINTERS, \ - .mask = DBGI_SRAM_FIFO_POINTERS_WR_PTR_MSK, \ - }, \ - } - -#define IWL_DEVICE_BZ \ - IWL_DEVICE_BZ_COMMON, \ - .ht_params = &iwl_22000_ht_params - -#define IWL_DEVICE_GL_A \ - IWL_DEVICE_BZ_COMMON, \ - .ht_params = &iwl_gl_a_ht_params - -#define IWL_DEVICE_SC \ - IWL_DEVICE_BZ_COMMON, \ - .ht_params = &iwl_22000_ht_params - const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = { .mq_rx_supported = true, .use_tfh = true, @@ -461,59 +172,6 @@ const struct iwl_cfg_trans_params iwl_qu_long_latency_trans_cfg = { .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, }; -const struct iwl_cfg_trans_params iwl_snj_trans_cfg = { - .mq_rx_supported = true, - .use_tfh = true, - .rf_id = true, - .gen2 = true, - .device_family = IWL_DEVICE_FAMILY_AX210, - .base_params = &iwl_ax210_base_params, - .umac_prph_offset = 0x300000, -}; - -const struct iwl_cfg_trans_params iwl_so_trans_cfg = { - .mq_rx_supported = true, - .use_tfh = true, - .rf_id = true, - .gen2 = true, - .device_family = IWL_DEVICE_FAMILY_AX210, - .base_params = &iwl_ax210_base_params, - .umac_prph_offset = 0x300000, - .integrated = true, - /* TODO: the following values need to be checked */ - .xtal_latency = 500, - .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_200US, -}; - -const struct iwl_cfg_trans_params iwl_so_long_latency_trans_cfg = { - .mq_rx_supported = true, - .use_tfh = true, - .rf_id = true, - .gen2 = true, - .device_family = IWL_DEVICE_FAMILY_AX210, - .base_params = &iwl_ax210_base_params, - .umac_prph_offset = 0x300000, - .integrated = true, - .low_latency_xtal = true, - .xtal_latency = 12000, - .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, -}; - -const struct iwl_cfg_trans_params iwl_so_long_latency_imr_trans_cfg = { - .mq_rx_supported = true, - .use_tfh = true, - .rf_id = true, - .gen2 = true, - .device_family = IWL_DEVICE_FAMILY_AX210, - .base_params = &iwl_ax210_base_params, - .umac_prph_offset = 0x300000, - .integrated = true, - .low_latency_xtal = true, - .xtal_latency = 12000, - .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, - .imr_enabled = true, -}; - /* * If the device doesn't support HE, no need to have that many buffers. * 22000 devices can split multiple frames into a single RB, so fewer are @@ -523,7 +181,6 @@ const struct iwl_cfg_trans_params iwl_so_long_latency_imr_trans_cfg = { */ #define IWL_NUM_RBDS_NON_HE 512 #define IWL_NUM_RBDS_22000_HE 2048 -#define IWL_NUM_RBDS_AX210_HE 4096 /* * All JF radio modules are part of the 9000 series, but the MAC part @@ -576,42 +233,11 @@ const struct iwl_cfg_trans_params iwl_ax200_trans_cfg = { .bisr_workaround = 1, }; -const struct iwl_cfg_trans_params iwl_ma_trans_cfg = { - .device_family = IWL_DEVICE_FAMILY_AX210, - .base_params = &iwl_ax210_base_params, - .mq_rx_supported = true, - .use_tfh = true, - .rf_id = true, - .gen2 = true, - .integrated = true, - .umac_prph_offset = 0x300000 -}; - -const struct iwl_cfg_trans_params iwl_bz_trans_cfg = { - .device_family = IWL_DEVICE_FAMILY_BZ, - .base_params = &iwl_ax210_base_params, - .mq_rx_supported = true, - .use_tfh = true, - .rf_id = true, - .gen2 = true, - .integrated = true, - .umac_prph_offset = 0x300000, - .xtal_latency = 12000, - .low_latency_xtal = true, - .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, -}; - const char iwl_ax101_name[] = "Intel(R) Wi-Fi 6 AX101"; const char iwl_ax200_name[] = "Intel(R) Wi-Fi 6 AX200 160MHz"; const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz"; const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203"; const char iwl_ax204_name[] = "Intel(R) Wi-Fi 6 AX204 160MHz"; -const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; -const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; -const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; -const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; -const char iwl_bz_name[] = "Intel(R) TBD Bz device"; -const char iwl_sc_name[] = "Intel(R) TBD Sc device"; const char iwl_ax200_killer_1650w_name[] = "Killer(R) Wi-Fi 6 AX1650w 160MHz Wireless Network Adapter (200D2W)"; @@ -621,18 +247,6 @@ const char iwl_ax201_killer_1650s_name[] = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)"; const char iwl_ax201_killer_1650i_name[] = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)"; -const char iwl_ax210_killer_1675w_name[] = - "Killer(R) Wi-Fi 6E AX1675w 160MHz Wireless Network Adapter (210D2W)"; -const char iwl_ax210_killer_1675x_name[] = - "Killer(R) Wi-Fi 6E AX1675x 160MHz Wireless Network Adapter (210NGW)"; -const char iwl_ax211_killer_1675s_name[] = - "Killer(R) Wi-Fi 6E AX1675s 160MHz Wireless Network Adapter (211NGW)"; -const char iwl_ax211_killer_1675i_name[] = - "Killer(R) Wi-Fi 6E AX1675i 160MHz Wireless Network Adapter (211NGW)"; -const char iwl_ax411_killer_1690s_name[] = - "Killer(R) Wi-Fi 6E AX1690s 160MHz Wireless Network Adapter (411D2W)"; -const char iwl_ax411_killer_1690i_name[] = - "Killer(R) Wi-Fi 6E AX1690i 160MHz Wireless Network Adapter (411NGW)"; const struct iwl_cfg iwl_qu_b0_hr1_b0 = { .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, @@ -838,191 +452,6 @@ const struct iwl_cfg iwl_qnj_b0_hr_b0_cfg = { .num_rbds = IWL_NUM_RBDS_22000_HE, }; -const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0 = { - .name = "Intel(R) Wireless-AC 9560 160MHz", - .fw_name_pre = IWL_SO_A_JF_B_FW_PRE, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_NON_HE, -}; - -const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = { - .name = iwl_ax211_name, - .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long = { - .name = iwl_ax211_name, - .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, - .trans.xtal_latency = 12000, - .trans.low_latency_xtal = true, -}; - -const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0 = { - .name = "Intel(R) Wi-Fi 6 AX210 160MHz", - .fw_name_pre = IWL_TY_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0 = { - .name = iwl_ax411_name, - .fw_name_pre = IWL_SO_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long = { - .name = iwl_ax411_name, - .fw_name_pre = IWL_SO_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, - .trans.xtal_latency = 12000, - .trans.low_latency_xtal = true, -}; - -const struct iwl_cfg iwlax411_2ax_cfg_sosnj_gf4_a0 = { - .name = iwl_ax411_name, - .fw_name_pre = IWL_SNJ_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwlax211_cfg_snj_gf_a0 = { - .name = iwl_ax211_name, - .fw_name_pre = IWL_SNJ_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_snj_hr_b0 = { - .fw_name_pre = IWL_SNJ_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_snj_a0_jf_b0 = { - .fw_name_pre = IWL_SNJ_A_JF_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_hr_b0 = { - .fw_name_pre = IWL_MA_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_gf_a0 = { - .fw_name_pre = IWL_MA_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0 = { - .fw_name_pre = IWL_MA_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_mr_a0 = { - .fw_name_pre = IWL_MA_A_MR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_ms_a0 = { - .fw_name_pre = IWL_MA_A_MR_A_FW_PRE, - .uhb_supported = false, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_fm_a0 = { - .fw_name_pre = IWL_MA_B_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_hr_b0 = { - .fw_name_pre = IWL_MA_B_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_gf_a0 = { - .fw_name_pre = IWL_MA_B_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_gf4_a0 = { - .fw_name_pre = IWL_MA_B_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_mr_a0 = { - .fw_name_pre = IWL_MA_B_MR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_so_a0_ms_a0 = { - .fw_name_pre = IWL_SO_A_MR_A_FW_PRE, - .uhb_supported = false, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = { - .fw_name_pre = IWL_MA_A_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_snj_a0_mr_a0 = { - .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_snj_a0_ms_a0 = { - .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, - .uhb_supported = false, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_so_a0_hr_a0 = { - .fw_name_pre = IWL_SO_A_HR_B_FW_PRE, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - const struct iwl_cfg iwl_cfg_quz_a0_hr_b0 = { .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE, IWL_DEVICE_22500, @@ -1035,357 +464,11 @@ const struct iwl_cfg iwl_cfg_quz_a0_hr_b0 = { .num_rbds = IWL_NUM_RBDS_22000_HE, }; -const struct iwl_cfg iwl_cfg_bz_a0_hr_a0 = { - .fw_name_pre = IWL_BZ_A_HR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_hr_b0 = { - .fw_name_pre = IWL_BZ_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_gf_a0 = { - .fw_name_pre = IWL_BZ_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0 = { - .fw_name_pre = IWL_BZ_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_b0_gf_a0 = { - .fw_name_pre = IWL_BZ_B_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_b0_gf4_a0 = { - .fw_name_pre = IWL_BZ_B_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_mr_a0 = { - .fw_name_pre = IWL_BZ_A_MR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm_a0 = { - .fw_name_pre = IWL_BZ_A_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0 = { - .fw_name_pre = IWL_BZ_A_FM4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm_b0 = { - .fw_name_pre = IWL_BZ_A_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm_c0 = { - .fw_name_pre = IWL_BZ_A_FM_C_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0 = { - .fw_name_pre = IWL_BZ_A_FM4_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_b0_fm_b0 = { - .fw_name_pre = IWL_BZ_B_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_b0_fm4_b0 = { - .fw_name_pre = IWL_BZ_B_FM4_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = { - .fw_name_pre = IWL_GL_A_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_GL_A, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_gl_b0_fm_b0 = { - .fw_name_pre = IWL_GL_B_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_gl_c0_fm_c0 = { - .fw_name_pre = IWL_GL_C_FM_C_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = { - .fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0 = { - .fw_name_pre = IWL_BNJ_A_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0 = { - .fw_name_pre = IWL_BNJ_A_FM4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_fm4_b0 = { - .fw_name_pre = IWL_BNJ_B_FM4_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0 = { - .fw_name_pre = IWL_BNJ_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_gf_a0 = { - .fw_name_pre = IWL_BNJ_B_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0 = { - .fw_name_pre = IWL_BNJ_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_gf4_a0 = { - .fw_name_pre = IWL_BNJ_B_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_hr_a0 = { - .fw_name_pre = IWL_BNJ_A_HR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = { - .fw_name_pre = IWL_BNJ_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_hr_a0 = { - .fw_name_pre = IWL_BNJ_B_HR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_hr_b0 = { - .fw_name_pre = IWL_BNJ_B_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = { - .fw_name_pre = IWL_BNJ_B_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_fm_b0 = { - .fw_name_pre = IWL_SC_A_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_fm_c0 = { - .fw_name_pre = IWL_SC_A_FM_C_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_hr_a0 = { - .fw_name_pre = IWL_SC_A_HR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_hr_b0 = { - .fw_name_pre = IWL_SC_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_gf_a0 = { - .fw_name_pre = IWL_SC_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_gf4_a0 = { - .fw_name_pre = IWL_SC_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_wh_a0 = { - .fw_name_pre = IWL_SC_A_WH_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QNJ_B_JF_B_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22500_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SO_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SO_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_TY_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_MR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_HR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_MR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_HR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_FM_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SC_A_FM_C_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QNJ_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c new file mode 100644 index 000000000000..cc6761e46bee --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018-2023 Intel Corporation + */ +#include +#include +#include "iwl-config.h" +#include "iwl-prph.h" +#include "fw/api/txq.h" + +/* Highest firmware API version supported */ +#define IWL_AX210_UCODE_API_MAX 82 + +/* Lowest firmware API version supported */ +#define IWL_AX210_UCODE_API_MIN 39 + +/* NVM versions */ +#define IWL_AX210_NVM_VERSION 0x0a1d + +/* Memory offsets and lengths */ +#define IWL_AX210_DCCM_OFFSET 0x800000 /* LMAC1 */ +#define IWL_AX210_DCCM_LEN 0x10000 /* LMAC1 */ +#define IWL_AX210_DCCM2_OFFSET 0x880000 +#define IWL_AX210_DCCM2_LEN 0x8000 +#define IWL_AX210_SMEM_OFFSET 0x400000 +#define IWL_AX210_SMEM_LEN 0xD0000 + +#define IWL_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0-" +#define IWL_SO_A_HR_B_FW_PRE "iwlwifi-so-a0-hr-b0-" +#define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0-" +#define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0-" +#define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0-" +#define IWL_SO_A_MR_A_FW_PRE "iwlwifi-so-a0-mr-a0-" +#define IWL_SNJ_A_GF4_A_FW_PRE "iwlwifi-SoSnj-a0-gf4-a0-" +#define IWL_SNJ_A_GF_A_FW_PRE "iwlwifi-SoSnj-a0-gf-a0-" +#define IWL_SNJ_A_HR_B_FW_PRE "iwlwifi-SoSnj-a0-hr-b0-" +#define IWL_SNJ_A_JF_B_FW_PRE "iwlwifi-SoSnj-a0-jf-b0-" +#define IWL_MA_A_HR_B_FW_PRE "iwlwifi-ma-a0-hr-b0-" +#define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0-" +#define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0-" +#define IWL_MA_A_MR_A_FW_PRE "iwlwifi-ma-a0-mr-a0-" +#define IWL_MA_A_FM_A_FW_PRE "iwlwifi-ma-a0-fm-a0-" +#define IWL_MA_B_HR_B_FW_PRE "iwlwifi-ma-b0-hr-b0-" +#define IWL_MA_B_GF_A_FW_PRE "iwlwifi-ma-b0-gf-a0-" +#define IWL_MA_B_GF4_A_FW_PRE "iwlwifi-ma-b0-gf4-a0-" +#define IWL_MA_B_MR_A_FW_PRE "iwlwifi-ma-b0-mr-a0-" +#define IWL_MA_B_FM_A_FW_PRE "iwlwifi-ma-b0-fm-a0-" +#define IWL_SNJ_A_MR_A_FW_PRE "iwlwifi-SoSnj-a0-mr-a0-" + +#define IWL_SO_A_JF_B_MODULE_FIRMWARE(api) \ + IWL_SO_A_JF_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SO_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_SO_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SO_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_SO_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_TY_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_TY_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SNJ_A_GF4_A_MODULE_FIRMWARE(api) \ + IWL_SNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SNJ_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_SNJ_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SNJ_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_SNJ_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SNJ_A_JF_B_MODULE_FIRMWARE(api) \ + IWL_SNJ_A_JF_B_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(api) \ + IWL_MA_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_A_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_A_MR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_A_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(api) \ + IWL_MA_B_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_B_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_B_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_B_MR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(api) \ + IWL_MA_B_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SNJ_A_MR_A_MODULE_FIRMWARE(api) \ + IWL_SNJ_A_MR_A_FW_PRE __stringify(api) ".ucode" + +static const struct iwl_base_params iwl_ax210_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, + .num_of_queues = 512, + .max_tfd_queue_size = 65536, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, +}; + +#define IWL_DEVICE_AX210_COMMON \ + .ucode_api_min = IWL_AX210_UCODE_API_MIN, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = 10, \ + .non_shared_ant = ANT_B, \ + .dccm_offset = IWL_AX210_DCCM_OFFSET, \ + .dccm_len = IWL_AX210_DCCM_LEN, \ + .dccm2_offset = IWL_AX210_DCCM2_OFFSET, \ + .dccm2_len = IWL_AX210_DCCM2_LEN, \ + .smem_offset = IWL_AX210_SMEM_OFFSET, \ + .smem_len = IWL_AX210_SMEM_LEN, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .apmg_not_supported = true, \ + .trans.mq_rx_supported = true, \ + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = 0x380, \ + .ht_params = &iwl_22000_ht_params, \ + .nvm_ver = IWL_AX210_NVM_VERSION, \ + .trans.rf_id = true, \ + .trans.gen2 = true, \ + .nvm_type = IWL_NVM_EXT, \ + .dbgc_supported = true, \ + .min_umac_error_event_table = 0x400000, \ + .d3_debug_data_base_addr = 0x401000, \ + .d3_debug_data_length = 60 * 1024, \ + .mon_smem_regs = { \ + .write_ptr = { \ + .addr = LDBG_M2S_BUF_WPTR, \ + .mask = LDBG_M2S_BUF_WPTR_VAL_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = LDBG_M2S_BUF_WRAP_CNT, \ + .mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \ + }, \ + } + +#define IWL_DEVICE_AX210 \ + IWL_DEVICE_AX210_COMMON, \ + .ucode_api_max = IWL_AX210_UCODE_API_MAX, \ + .trans.umac_prph_offset = 0x300000, \ + .trans.device_family = IWL_DEVICE_FAMILY_AX210, \ + .trans.base_params = &iwl_ax210_base_params, \ + .min_txq_size = 128, \ + .gp2_reg_addr = 0xd02c68, \ + .min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_HE, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = DBGC_DBGBUF_WRAP_AROUND, \ + .mask = 0xffffffff, \ + }, \ + .cur_frag = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ + }, \ + } + +const struct iwl_cfg_trans_params iwl_snj_trans_cfg = { + .mq_rx_supported = true, + .rf_id = true, + .gen2 = true, + .device_family = IWL_DEVICE_FAMILY_AX210, + .base_params = &iwl_ax210_base_params, + .umac_prph_offset = 0x300000, +}; + +const struct iwl_cfg_trans_params iwl_so_trans_cfg = { + .mq_rx_supported = true, + .rf_id = true, + .gen2 = true, + .device_family = IWL_DEVICE_FAMILY_AX210, + .base_params = &iwl_ax210_base_params, + .umac_prph_offset = 0x300000, + .integrated = true, + /* TODO: the following values need to be checked */ + .xtal_latency = 500, + .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_200US, +}; + +const struct iwl_cfg_trans_params iwl_so_long_latency_trans_cfg = { + .mq_rx_supported = true, + .rf_id = true, + .gen2 = true, + .device_family = IWL_DEVICE_FAMILY_AX210, + .base_params = &iwl_ax210_base_params, + .umac_prph_offset = 0x300000, + .integrated = true, + .low_latency_xtal = true, + .xtal_latency = 12000, + .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, +}; + +const struct iwl_cfg_trans_params iwl_so_long_latency_imr_trans_cfg = { + .mq_rx_supported = true, + .rf_id = true, + .gen2 = true, + .device_family = IWL_DEVICE_FAMILY_AX210, + .base_params = &iwl_ax210_base_params, + .umac_prph_offset = 0x300000, + .integrated = true, + .low_latency_xtal = true, + .xtal_latency = 12000, + .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, + .imr_enabled = true, +}; + +/* + * If the device doesn't support HE, no need to have that many buffers. + * AX210 devices can split multiple frames into a single RB, so fewer are + * needed; AX210 cannot (but use smaller RBs by default) - these sizes + * were picked according to 8 MSDUs inside 256 A-MSDUs in an A-MPDU, with + * additional overhead to account for processing time. + */ +#define IWL_NUM_RBDS_NON_HE 512 +#define IWL_NUM_RBDS_AX210_HE 4096 + +const struct iwl_cfg_trans_params iwl_ma_trans_cfg = { + .device_family = IWL_DEVICE_FAMILY_AX210, + .base_params = &iwl_ax210_base_params, + .mq_rx_supported = true, + .rf_id = true, + .gen2 = true, + .integrated = true, + .umac_prph_offset = 0x300000 +}; + +const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; +const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; +const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; +const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; + +const char iwl_ax210_killer_1675w_name[] = + "Killer(R) Wi-Fi 6E AX1675w 160MHz Wireless Network Adapter (210D2W)"; +const char iwl_ax210_killer_1675x_name[] = + "Killer(R) Wi-Fi 6E AX1675x 160MHz Wireless Network Adapter (210NGW)"; +const char iwl_ax211_killer_1675s_name[] = + "Killer(R) Wi-Fi 6E AX1675s 160MHz Wireless Network Adapter (211NGW)"; +const char iwl_ax211_killer_1675i_name[] = + "Killer(R) Wi-Fi 6E AX1675i 160MHz Wireless Network Adapter (211NGW)"; +const char iwl_ax411_killer_1690s_name[] = + "Killer(R) Wi-Fi 6E AX1690s 160MHz Wireless Network Adapter (411D2W)"; +const char iwl_ax411_killer_1690i_name[] = + "Killer(R) Wi-Fi 6E AX1690i 160MHz Wireless Network Adapter (411NGW)"; + +const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0 = { + .name = "Intel(R) Wireless-AC 9560 160MHz", + .fw_name_pre = IWL_SO_A_JF_B_FW_PRE, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_NON_HE, +}; + +const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = { + .name = iwl_ax211_name, + .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long = { + .name = iwl_ax211_name, + .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, + .trans.xtal_latency = 12000, + .trans.low_latency_xtal = true, +}; + +const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0 = { + .name = "Intel(R) Wi-Fi 6 AX210 160MHz", + .fw_name_pre = IWL_TY_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0 = { + .name = iwl_ax411_name, + .fw_name_pre = IWL_SO_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long = { + .name = iwl_ax411_name, + .fw_name_pre = IWL_SO_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, + .trans.xtal_latency = 12000, + .trans.low_latency_xtal = true, +}; + +const struct iwl_cfg iwlax411_2ax_cfg_sosnj_gf4_a0 = { + .name = iwl_ax411_name, + .fw_name_pre = IWL_SNJ_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwlax211_cfg_snj_gf_a0 = { + .name = iwl_ax211_name, + .fw_name_pre = IWL_SNJ_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_snj_hr_b0 = { + .fw_name_pre = IWL_SNJ_A_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_snj_a0_jf_b0 = { + .fw_name_pre = IWL_SNJ_A_JF_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_a0_hr_b0 = { + .fw_name_pre = IWL_MA_A_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_a0_gf_a0 = { + .fw_name_pre = IWL_MA_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0 = { + .fw_name_pre = IWL_MA_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_a0_mr_a0 = { + .fw_name_pre = IWL_MA_A_MR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_a0_ms_a0 = { + .fw_name_pre = IWL_MA_A_MR_A_FW_PRE, + .uhb_supported = false, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_b0_fm_a0 = { + .fw_name_pre = IWL_MA_B_FM_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_b0_hr_b0 = { + .fw_name_pre = IWL_MA_B_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_b0_gf_a0 = { + .fw_name_pre = IWL_MA_B_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_b0_gf4_a0 = { + .fw_name_pre = IWL_MA_B_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_b0_mr_a0 = { + .fw_name_pre = IWL_MA_B_MR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_so_a0_ms_a0 = { + .fw_name_pre = IWL_SO_A_MR_A_FW_PRE, + .uhb_supported = false, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = { + .fw_name_pre = IWL_MA_A_FM_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_snj_a0_mr_a0 = { + .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_snj_a0_ms_a0 = { + .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, + .uhb_supported = false, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_so_a0_hr_a0 = { + .fw_name_pre = IWL_SO_A_HR_B_FW_PRE, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +MODULE_FIRMWARE(IWL_SO_A_JF_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SO_A_GF_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_TY_A_GF_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SNJ_A_GF4_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SNJ_A_GF_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SNJ_A_HR_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SNJ_A_JF_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SNJ_A_MR_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c new file mode 100644 index 000000000000..dd0270181018 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018-2023 Intel Corporation + */ +#include +#include +#include "iwl-config.h" +#include "iwl-prph.h" +#include "fw/api/txq.h" + +/* Highest firmware API version supported */ +#define IWL_BZ_UCODE_API_MAX 82 + +/* Lowest firmware API version supported */ +#define IWL_BZ_UCODE_API_MIN 39 + +/* NVM versions */ +#define IWL_BZ_NVM_VERSION 0x0a1d + +/* Memory offsets and lengths */ +#define IWL_BZ_DCCM_OFFSET 0x800000 /* LMAC1 */ +#define IWL_BZ_DCCM_LEN 0x10000 /* LMAC1 */ +#define IWL_BZ_DCCM2_OFFSET 0x880000 +#define IWL_BZ_DCCM2_LEN 0x8000 +#define IWL_BZ_SMEM_OFFSET 0x400000 +#define IWL_BZ_SMEM_LEN 0xD0000 + +#define IWL_BZ_A_HR_A_FW_PRE "iwlwifi-bz-a0-hr-b0-" +#define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0-" +#define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0-" +#define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0-" +#define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-" +#define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-" +#define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0-" +#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0-" +#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0-" +#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0-" +#define IWL_BZ_B_GF_A_FW_PRE "iwlwifi-bz-b0-gf-a0-" +#define IWL_BZ_B_GF4_A_FW_PRE "iwlwifi-bz-b0-gf4-a0-" +#define IWL_BZ_B_FM_B_FW_PRE "iwlwifi-bz-b0-fm-b0-" +#define IWL_BZ_B_FM4_B_FW_PRE "iwlwifi-bz-b0-fm4-b0-" +#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-" +#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0-" +#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0-" +#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" +#define IWL_BNJ_A_FM_A_FW_PRE "iwlwifi-BzBnj-a0-fm-a0-" +#define IWL_BNJ_A_FM4_A_FW_PRE "iwlwifi-BzBnj-a0-fm4-a0-" +#define IWL_BNJ_B_FM4_B_FW_PRE "iwlwifi-BzBnj-b0-fm4-b0-" +#define IWL_BNJ_A_GF_A_FW_PRE "iwlwifi-BzBnj-a0-gf-a0-" +#define IWL_BNJ_B_GF_A_FW_PRE "iwlwifi-BzBnj-b0-gf-a0-" +#define IWL_BNJ_C_GF_A_FW_PRE "iwlwifi-BzBnj-c0-gf-a0-" +#define IWL_BNJ_A_GF4_A_FW_PRE "iwlwifi-BzBnj-a0-gf4-a0-" +#define IWL_BNJ_B_GF4_A_FW_PRE "iwlwifi-BzBnj-b0-gf4-a0-" +#define IWL_BNJ_C_GF4_A_FW_PRE "iwlwifi-BzBnj-c0-gf4-a0-" +#define IWL_BNJ_A_HR_A_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-" +#define IWL_BNJ_A_HR_B_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-" +#define IWL_BNJ_B_HR_A_FW_PRE "iwlwifi-BzBnj-b0-hr-b0-" +#define IWL_BNJ_B_HR_B_FW_PRE "iwlwifi-BzBnj-b0-hr-b0-" +#define IWL_BNJ_C_HR_B_FW_PRE "iwlwifi-BzBnj-c0-hr-b0-" +#define IWL_BNJ_B_FM_B_FW_PRE "iwlwifi-BzBnj-b0-fm-b0-" +#define IWL_BNJ_C_FM_C_FW_PRE "iwlwifi-BzBnj-c0-fm-c0-" +#define IWL_BNJ_A_WH_A_FW_PRE "iwlwifi-BzBnj-a0-wh-a0-" +#define IWL_BNJ_B_WH_A_FW_PRE "iwlwifi-BzBnj-b0-wh-a0-" +#define IWL_BNJ_C_WH_A_FW_PRE "iwlwifi-BzBnj-c0-wh-a0-" + +#define IWL_BZ_A_HR_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_HR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_BZ_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_MR_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_MR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_FM_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_FM4_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_FM4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_FM_B_MODULE_FIRMWARE(api) \ + IWL_BZ_A_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_FM_C_MODULE_FIRMWARE(api) \ + IWL_BZ_A_FM_C_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_A_FM4_B_MODULE_FIRMWARE(api) \ + IWL_BZ_A_FM4_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_B_GF_A_MODULE_FIRMWARE(api) \ + IWL_BZ_B_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_B_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BZ_B_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_B_FM_B_MODULE_FIRMWARE(api) \ + IWL_BZ_B_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BZ_B_FM4_B_MODULE_FIRMWARE(api) \ + IWL_BZ_B_FM4_B_FW_PRE __stringify(api) ".ucode" +#define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ + IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \ + IWL_GL_B_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_GL_C_FM_C_MODULE_FIRMWARE(api) \ + IWL_GL_C_FM_C_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_FM_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_FM4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(api) \ + IWL_BNJ_B_FM4_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_B_GF_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_B_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_C_GF_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_C_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_B_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_C_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_C_GF4_A_FW_PRE __stringify(api) ".ucode" + +#define IWL_BNJ_A_HR_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_HR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_B_HR_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_B_HR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_B_HR_B_MODULE_FIRMWARE(api) \ + IWL_BNJ_B_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_C_HR_B_MODULE_FIRMWARE(api) \ + IWL_BNJ_B_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_B_FM_B_MODULE_FIRMWARE(api) \ + IWL_BNJ_B_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_C_FM_C_MODULE_FIRMWARE(api) \ + IWL_BNJ_C_FM_C_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_WH_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_WH_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_B_WH_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_B_WH_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_C_WH_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_C_WH_A_FW_PRE __stringify(api) ".ucode" + +static const struct iwl_base_params iwl_bz_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, + .num_of_queues = 512, + .max_tfd_queue_size = 65536, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, +}; + +static const struct iwl_ht_params iwl_gl_a_ht_params = { + .stbc = false, /* we explicitly disable STBC for GL step A */ + .ldpc = true, + .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | + BIT(NL80211_BAND_6GHZ), +}; + +#define IWL_DEVICE_BZ_COMMON \ + .ucode_api_max = IWL_BZ_UCODE_API_MAX, \ + .ucode_api_min = IWL_BZ_UCODE_API_MIN, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = 10, \ + .non_shared_ant = ANT_B, \ + .dccm_offset = IWL_BZ_DCCM_OFFSET, \ + .dccm_len = IWL_BZ_DCCM_LEN, \ + .dccm2_offset = IWL_BZ_DCCM2_OFFSET, \ + .dccm2_len = IWL_BZ_DCCM2_LEN, \ + .smem_offset = IWL_BZ_SMEM_OFFSET, \ + .smem_len = IWL_BZ_SMEM_LEN, \ + .apmg_not_supported = true, \ + .trans.mq_rx_supported = true, \ + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = 0x30, \ + .nvm_ver = IWL_BZ_NVM_VERSION, \ + .trans.rf_id = true, \ + .trans.gen2 = true, \ + .nvm_type = IWL_NVM_EXT, \ + .dbgc_supported = true, \ + .min_umac_error_event_table = 0xD0000, \ + .d3_debug_data_base_addr = 0x401000, \ + .d3_debug_data_length = 60 * 1024, \ + .mon_smem_regs = { \ + .write_ptr = { \ + .addr = LDBG_M2S_BUF_WPTR, \ + .mask = LDBG_M2S_BUF_WPTR_VAL_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = LDBG_M2S_BUF_WRAP_CNT, \ + .mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \ + }, \ + }, \ + .trans.umac_prph_offset = 0x300000, \ + .trans.device_family = IWL_DEVICE_FAMILY_BZ, \ + .trans.base_params = &iwl_bz_base_params, \ + .min_txq_size = 128, \ + .gp2_reg_addr = 0xd02c68, \ + .min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_EHT, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = DBGC_DBGBUF_WRAP_AROUND, \ + .mask = 0xffffffff, \ + }, \ + .cur_frag = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ + }, \ + }, \ + .mon_dbgi_regs = { \ + .write_ptr = { \ + .addr = DBGI_SRAM_FIFO_POINTERS, \ + .mask = DBGI_SRAM_FIFO_POINTERS_WR_PTR_MSK, \ + }, \ + } + +#define IWL_DEVICE_BZ \ + IWL_DEVICE_BZ_COMMON, \ + .ht_params = &iwl_22000_ht_params + +#define IWL_DEVICE_GL_A \ + IWL_DEVICE_BZ_COMMON, \ + .ht_params = &iwl_gl_a_ht_params + +/* + * If the device doesn't support HE, no need to have that many buffers. + * These sizes were picked according to 8 MSDUs inside 256 A-MSDUs in an + * A-MPDU, with additional overhead to account for processing time. + */ +#define IWL_NUM_RBDS_NON_HE 512 +#define IWL_NUM_RBDS_BZ_HE 4096 + +const struct iwl_cfg_trans_params iwl_bz_trans_cfg = { + .device_family = IWL_DEVICE_FAMILY_BZ, + .base_params = &iwl_bz_base_params, + .mq_rx_supported = true, + .rf_id = true, + .gen2 = true, + .integrated = true, + .umac_prph_offset = 0x300000, + .xtal_latency = 12000, + .low_latency_xtal = true, + .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, +}; + +const char iwl_bz_name[] = "Intel(R) TBD Bz device"; + +const struct iwl_cfg iwl_cfg_bz_a0_hr_a0 = { + .fw_name_pre = IWL_BZ_A_HR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_hr_b0 = { + .fw_name_pre = IWL_BZ_A_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_gf_a0 = { + .fw_name_pre = IWL_BZ_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0 = { + .fw_name_pre = IWL_BZ_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_b0_gf_a0 = { + .fw_name_pre = IWL_BZ_B_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_b0_gf4_a0 = { + .fw_name_pre = IWL_BZ_B_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_mr_a0 = { + .fw_name_pre = IWL_BZ_A_MR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_fm_a0 = { + .fw_name_pre = IWL_BZ_A_FM_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0 = { + .fw_name_pre = IWL_BZ_A_FM4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_fm_b0 = { + .fw_name_pre = IWL_BZ_A_FM_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_fm_c0 = { + .fw_name_pre = IWL_BZ_A_FM_C_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0 = { + .fw_name_pre = IWL_BZ_A_FM4_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_b0_fm_b0 = { + .fw_name_pre = IWL_BZ_B_FM_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_b0_fm4_b0 = { + .fw_name_pre = IWL_BZ_B_FM4_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = { + .fw_name_pre = IWL_GL_A_FM_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_GL_A, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_gl_b0_fm_b0 = { + .fw_name_pre = IWL_GL_B_FM_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_gl_c0_fm_c0 = { + .fw_name_pre = IWL_GL_C_FM_C_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = { + .fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0 = { + .fw_name_pre = IWL_BNJ_A_FM_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0 = { + .fw_name_pre = IWL_BNJ_A_FM4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_b0_fm4_b0 = { + .fw_name_pre = IWL_BNJ_B_FM4_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0 = { + .fw_name_pre = IWL_BNJ_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_b0_gf_a0 = { + .fw_name_pre = IWL_BNJ_B_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0 = { + .fw_name_pre = IWL_BNJ_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_b0_gf4_a0 = { + .fw_name_pre = IWL_BNJ_B_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_hr_a0 = { + .fw_name_pre = IWL_BNJ_A_HR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = { + .fw_name_pre = IWL_BNJ_A_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_b0_hr_a0 = { + .fw_name_pre = IWL_BNJ_B_HR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_b0_hr_b0 = { + .fw_name_pre = IWL_BNJ_B_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = { + .fw_name_pre = IWL_BNJ_B_FM_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_HE, +}; + + +MODULE_FIRMWARE(IWL_BZ_A_HR_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_MR_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_B_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_C_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_C_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_B_HR_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_B_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_C_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_FM4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_WH_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_B_WH_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_C_WH_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c new file mode 100644 index 000000000000..a294c88e6a65 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018-2023 Intel Corporation + */ +#include +#include +#include "iwl-config.h" +#include "iwl-prph.h" +#include "fw/api/txq.h" + +/* Highest firmware API version supported */ +#define IWL_SC_UCODE_API_MAX 82 + +/* Lowest firmware API version supported */ +#define IWL_SC_UCODE_API_MIN 39 + +/* NVM versions */ +#define IWL_SC_NVM_VERSION 0x0a1d + +/* Memory offsets and lengths */ +#define IWL_SC_DCCM_OFFSET 0x800000 /* LMAC1 */ +#define IWL_SC_DCCM_LEN 0x10000 /* LMAC1 */ +#define IWL_SC_DCCM2_OFFSET 0x880000 +#define IWL_SC_DCCM2_LEN 0x8000 +#define IWL_SC_SMEM_OFFSET 0x400000 +#define IWL_SC_SMEM_LEN 0xD0000 + +#define IWL_SC_A_FM_B_FW_PRE "iwlwifi-sc-a0-fm-b0-" +#define IWL_SC_A_FM_C_FW_PRE "iwlwifi-sc-a0-fm-c0-" +#define IWL_SC_A_HR_A_FW_PRE "iwlwifi-sc-a0-hr-b0-" +#define IWL_SC_A_HR_B_FW_PRE "iwlwifi-sc-a0-hr-b0-" +#define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0-" +#define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0-" +#define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0-" + +#define IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_FM_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_FM_C_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_FM_C_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_HR_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_HR_B_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_WH_A_FW_PRE __stringify(api) ".ucode" + +static const struct iwl_base_params iwl_sc_base_params = { + .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, + .num_of_queues = 512, + .max_tfd_queue_size = 65536, + .shadow_ram_support = true, + .led_compensation = 57, + .wd_timeout = IWL_LONG_WD_TIMEOUT, + .max_event_log_size = 512, + .shadow_reg_enable = true, + .pcie_l1_allowed = true, +}; + +#define IWL_DEVICE_BZ_COMMON \ + .ucode_api_max = IWL_SC_UCODE_API_MAX, \ + .ucode_api_min = IWL_SC_UCODE_API_MIN, \ + .led_mode = IWL_LED_RF_STATE, \ + .nvm_hw_section_num = 10, \ + .non_shared_ant = ANT_B, \ + .dccm_offset = IWL_SC_DCCM_OFFSET, \ + .dccm_len = IWL_SC_DCCM_LEN, \ + .dccm2_offset = IWL_SC_DCCM2_OFFSET, \ + .dccm2_len = IWL_SC_DCCM2_LEN, \ + .smem_offset = IWL_SC_SMEM_OFFSET, \ + .smem_len = IWL_SC_SMEM_LEN, \ + .apmg_not_supported = true, \ + .trans.mq_rx_supported = true, \ + .vht_mu_mimo_supported = true, \ + .mac_addr_from_csr = 0x30, \ + .nvm_ver = IWL_SC_NVM_VERSION, \ + .trans.rf_id = true, \ + .trans.gen2 = true, \ + .nvm_type = IWL_NVM_EXT, \ + .dbgc_supported = true, \ + .min_umac_error_event_table = 0xD0000, \ + .d3_debug_data_base_addr = 0x401000, \ + .d3_debug_data_length = 60 * 1024, \ + .mon_smem_regs = { \ + .write_ptr = { \ + .addr = LDBG_M2S_BUF_WPTR, \ + .mask = LDBG_M2S_BUF_WPTR_VAL_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = LDBG_M2S_BUF_WRAP_CNT, \ + .mask = LDBG_M2S_BUF_WRAP_CNT_VAL_MSK, \ + }, \ + }, \ + .trans.umac_prph_offset = 0x300000, \ + .trans.device_family = IWL_DEVICE_FAMILY_BZ, \ + .trans.base_params = &iwl_sc_base_params, \ + .min_txq_size = 128, \ + .gp2_reg_addr = 0xd02c68, \ + .min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_EHT, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK, \ + }, \ + .cycle_cnt = { \ + .addr = DBGC_DBGBUF_WRAP_AROUND, \ + .mask = 0xffffffff, \ + }, \ + .cur_frag = { \ + .addr = DBGC_CUR_DBGBUF_STATUS, \ + .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ + }, \ + }, \ + .mon_dbgi_regs = { \ + .write_ptr = { \ + .addr = DBGI_SRAM_FIFO_POINTERS, \ + .mask = DBGI_SRAM_FIFO_POINTERS_WR_PTR_MSK, \ + }, \ + } + +#define IWL_DEVICE_SC \ + IWL_DEVICE_BZ_COMMON, \ + .ht_params = &iwl_22000_ht_params + +/* + * If the device doesn't support HE, no need to have that many buffers. + * These sizes were picked according to 8 MSDUs inside 256 A-MSDUs in an + * A-MPDU, with additional overhead to account for processing time. + */ +#define IWL_NUM_RBDS_NON_HE 512 +#define IWL_NUM_RBDS_SC_HE 4096 + +const struct iwl_cfg_trans_params iwl_sc_trans_cfg = { + .device_family = IWL_DEVICE_FAMILY_BZ, + .base_params = &iwl_sc_base_params, + .mq_rx_supported = true, + .rf_id = true, + .gen2 = true, + .integrated = true, + .umac_prph_offset = 0x300000, + .xtal_latency = 12000, + .low_latency_xtal = true, + .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, +}; + +const char iwl_sc_name[] = "Intel(R) TBD Sc device"; + +const struct iwl_cfg iwl_cfg_sc_a0_fm_b0 = { + .fw_name_pre = IWL_SC_A_FM_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_SC_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_fm_c0 = { + .fw_name_pre = IWL_SC_A_FM_C_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_SC_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_hr_a0 = { + .fw_name_pre = IWL_SC_A_HR_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_SC_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_hr_b0 = { + .fw_name_pre = IWL_SC_A_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_SC_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_gf_a0 = { + .fw_name_pre = IWL_SC_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_SC_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_gf4_a0 = { + .fw_name_pre = IWL_SC_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_SC_HE, +}; + +const struct iwl_cfg iwl_cfg_sc_a0_wh_a0 = { + .fw_name_pre = IWL_SC_A_WH_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_SC, + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_SC_HE, +}; + +MODULE_FIRMWARE(IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_FM_C_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 37ae57adf950..5c6ab5b9930b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -499,6 +499,7 @@ extern const struct iwl_cfg_trans_params iwl_so_long_latency_trans_cfg; extern const struct iwl_cfg_trans_params iwl_so_long_latency_imr_trans_cfg; extern const struct iwl_cfg_trans_params iwl_ma_trans_cfg; extern const struct iwl_cfg_trans_params iwl_bz_trans_cfg; +extern const struct iwl_cfg_trans_params iwl_sc_trans_cfg; extern const char iwl9162_name[]; extern const char iwl9260_name[]; extern const char iwl9260_1_name[]; @@ -583,6 +584,7 @@ extern const struct iwl_cfg iwl105_bgn_d_cfg; extern const struct iwl_cfg iwl135_bgn_cfg; #endif /* CONFIG_IWLDVM */ #if IS_ENABLED(CONFIG_IWLMVM) +extern const struct iwl_ht_params iwl_22000_ht_params; extern const struct iwl_cfg iwl7260_2ac_cfg; extern const struct iwl_cfg iwl7260_2ac_cfg_high_temp; extern const struct iwl_cfg iwl7260_2n_cfg; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 3f303ca13412..2b342e832f22 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -508,6 +508,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x272b, PCI_ANY_ID, iwl_bz_trans_cfg)}, {IWL_PCI_DEVICE(0xA840, PCI_ANY_ID, iwl_bz_trans_cfg)}, {IWL_PCI_DEVICE(0x7740, PCI_ANY_ID, iwl_bz_trans_cfg)}, + +/* Sc devices */ + {IWL_PCI_DEVICE(0xE440, PCI_ANY_ID, iwl_sc_trans_cfg)}, #endif /* CONFIG_IWLMVM */ {0} -- cgit v1.2.3 From 5afe98b2e2995aa17ef77a29e57b1d98ccd6cd25 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:08 +0300 Subject: wifi: iwlwifi: give Sc devices their own family They're not the same as Bz or any prior ones, and there's already one place in the driver that would erroneously assign a workaround to A-step Sc devices if they're just treated as a version of Bz. Fix that. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.e98272ddb808.If18577b2393f631d1bfaa931287cae106fa32438@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index a294c88e6a65..296ac689d075 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -96,7 +96,7 @@ static const struct iwl_base_params iwl_sc_base_params = { }, \ }, \ .trans.umac_prph_offset = 0x300000, \ - .trans.device_family = IWL_DEVICE_FAMILY_BZ, \ + .trans.device_family = IWL_DEVICE_FAMILY_SC, \ .trans.base_params = &iwl_sc_base_params, \ .min_txq_size = 128, \ .gp2_reg_addr = 0xd02c68, \ @@ -135,7 +135,7 @@ static const struct iwl_base_params iwl_sc_base_params = { #define IWL_NUM_RBDS_SC_HE 4096 const struct iwl_cfg_trans_params iwl_sc_trans_cfg = { - .device_family = IWL_DEVICE_FAMILY_BZ, + .device_family = IWL_DEVICE_FAMILY_SC, .base_params = &iwl_sc_base_params, .mq_rx_supported = true, .rf_id = true, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 5c6ab5b9930b..ef5154cf114b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -35,6 +35,7 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_22000, IWL_DEVICE_FAMILY_AX210, IWL_DEVICE_FAMILY_BZ, + IWL_DEVICE_FAMILY_SC, }; /* -- cgit v1.2.3 From 508b4a1baeb3da3f0bcf3ab4c94dd2c21cc5d395 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:09 +0300 Subject: wifi: iwlwifi: don't load old firmware for Sc This is a future product, don't try to load ancient firmware images for it, they don't exist anyway. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.a15e7bf936cb.I68c3c71fda62c837e4da885a42471bf772ac1202@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 296ac689d075..53b2a5969db6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -13,7 +13,7 @@ #define IWL_SC_UCODE_API_MAX 82 /* Lowest firmware API version supported */ -#define IWL_SC_UCODE_API_MIN 39 +#define IWL_SC_UCODE_API_MIN 82 /* NVM versions */ #define IWL_SC_NVM_VERSION 0x0a1d -- cgit v1.2.3 From a13707f7c8456022d9b4b764d1ad3f2252db2154 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:10 +0300 Subject: wifi: iwlwifi: don't load old firmware for Bz This is a future product, don't try to load ancient firmware images for it, they don't exist anyway. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.a6961592f258.Ib7afecd46b1963164481c2acf35d2582691ef0bc@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index dd0270181018..b6795e08bd40 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -13,7 +13,7 @@ #define IWL_BZ_UCODE_API_MAX 82 /* Lowest firmware API version supported */ -#define IWL_BZ_UCODE_API_MIN 39 +#define IWL_BZ_UCODE_API_MIN 80 /* NVM versions */ #define IWL_BZ_NVM_VERSION 0x0a1d -- cgit v1.2.3 From a7de384c93996f8cdf8e7b5304bf7963161241a6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:11 +0300 Subject: wifi: iwlwifi: don't load old firmware for ax210 The earliest firmware released for these products is with API version 59 (for 'ty' only), so no point trying to go back in time even further than that. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.ebe02b5dbddb.I51484ebb6c89256b0e6e7f9bb24f597c4ebead67@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index cc6761e46bee..1159c0e551b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -13,7 +13,7 @@ #define IWL_AX210_UCODE_API_MAX 82 /* Lowest firmware API version supported */ -#define IWL_AX210_UCODE_API_MIN 39 +#define IWL_AX210_UCODE_API_MIN 59 /* NVM versions */ #define IWL_AX210_NVM_VERSION 0x0a1d -- cgit v1.2.3 From c648e926d021f9c6bdeef782df06f5111904fe7e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:12 +0300 Subject: wifi: iwlwifi: don't load old firmware for 22000 The earliest firmware released for these products is with API version 50, so there's no point in trying to load any versions before that. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.768186c0475d.I7de717072221712176a3085d71c8018ae0348db8@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 12e809b715f4..c496d0d19de4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -13,7 +13,7 @@ #define IWL_22000_UCODE_API_MAX 77 /* Lowest firmware API version supported */ -#define IWL_22000_UCODE_API_MIN 39 +#define IWL_22000_UCODE_API_MIN 50 /* NVM versions */ #define IWL_22000_NVM_VERSION 0x0a1d -- cgit v1.2.3 From 0f21d7d56083f7069ff1180b40235228f3ce5b1e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:13 +0300 Subject: wifi: iwlwifi: remove support for *nJ devices These are test chips that will never reach anyone outside of Intel, so remove support for them. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.d9f4e0356ae4.If9eccc22eb500dfff8973a70a649d94af7a60841@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 41 ----- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 73 -------- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 172 ------------------- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 25 --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 218 ------------------------ 5 files changed, 529 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index c496d0d19de4..8acbbed6eb1f 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -27,19 +27,15 @@ #define IWL_22000_SMEM_LEN 0xD0000 #define IWL_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-" -#define IWL_QNJ_B_HR_B_FW_PRE "iwlwifi-QuQnj-b0-hr-b0-" #define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0-" #define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0-" #define IWL_QU_C_JF_B_FW_PRE "iwlwifi-Qu-c0-jf-b0-" #define IWL_QUZ_A_HR_B_FW_PRE "iwlwifi-QuZ-a0-hr-b0-" #define IWL_QUZ_A_JF_B_FW_PRE "iwlwifi-QuZ-a0-jf-b0-" -#define IWL_QNJ_B_JF_B_FW_PRE "iwlwifi-QuQnj-b0-jf-b0-" #define IWL_CC_A_FW_PRE "iwlwifi-cc-a0-" #define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ IWL_QU_B_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_QNJ_B_HR_B_MODULE_FIRMWARE(api) \ - IWL_QNJ_B_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api) \ IWL_QUZ_A_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_QUZ_A_JF_B_MODULE_FIRMWARE(api) \ @@ -48,8 +44,6 @@ IWL_QU_C_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \ IWL_QU_B_JF_B_FW_PRE __stringify(api) ".ucode" -#define IWL_QNJ_B_JF_B_MODULE_FIRMWARE(api) \ - IWL_QNJ_B_JF_B_FW_PRE __stringify(api) ".ucode" #define IWL_CC_A_MODULE_FIRMWARE(api) \ IWL_CC_A_FW_PRE __stringify(api) ".ucode" @@ -126,15 +120,6 @@ const struct iwl_ht_params iwl_22000_ht_params = { }, \ } -const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = { - .mq_rx_supported = true, - .use_tfh = true, - .rf_id = true, - .gen2 = true, - .device_family = IWL_DEVICE_FAMILY_22000, - .base_params = &iwl_22000_base_params, -}; - const struct iwl_cfg_trans_params iwl_qu_trans_cfg = { .mq_rx_supported = true, .use_tfh = true, @@ -211,18 +196,6 @@ const struct iwl_cfg iwl9560_quz_a0_jf_b0_cfg = { .num_rbds = IWL_NUM_RBDS_NON_HE, }; -const struct iwl_cfg iwl9560_qnj_b0_jf_b0_cfg = { - .fw_name_pre = IWL_QNJ_B_JF_B_FW_PRE, - IWL_DEVICE_22500, - /* - * This device doesn't support receiving BlockAck with a large bitmap - * so we need to restrict the size of transmitted aggregation to the - * HT size; mac80211 would otherwise pick the HE max (256) by default. - */ - .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, - .num_rbds = IWL_NUM_RBDS_NON_HE, -}; - const struct iwl_cfg_trans_params iwl_ax200_trans_cfg = { .device_family = IWL_DEVICE_FAMILY_22000, .base_params = &iwl_22000_base_params, @@ -440,18 +413,6 @@ const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0 = { .num_rbds = IWL_NUM_RBDS_22000_HE, }; -const struct iwl_cfg iwl_qnj_b0_hr_b0_cfg = { - .fw_name_pre = IWL_QNJ_B_HR_B_FW_PRE, - IWL_DEVICE_22500, - /* - * This device doesn't support receiving BlockAck with a large bitmap - * so we need to restrict the size of transmitted aggregation to the - * HT size; mac80211 would otherwise pick the HE max (256) by default. - */ - .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, - .num_rbds = IWL_NUM_RBDS_22000_HE, -}; - const struct iwl_cfg iwl_cfg_quz_a0_hr_b0 = { .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE, IWL_DEVICE_22500, @@ -465,10 +426,8 @@ const struct iwl_cfg iwl_cfg_quz_a0_hr_b0 = { }; MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QNJ_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 1159c0e551b0..e1c3afb97941 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -32,10 +32,6 @@ #define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0-" #define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0-" #define IWL_SO_A_MR_A_FW_PRE "iwlwifi-so-a0-mr-a0-" -#define IWL_SNJ_A_GF4_A_FW_PRE "iwlwifi-SoSnj-a0-gf4-a0-" -#define IWL_SNJ_A_GF_A_FW_PRE "iwlwifi-SoSnj-a0-gf-a0-" -#define IWL_SNJ_A_HR_B_FW_PRE "iwlwifi-SoSnj-a0-hr-b0-" -#define IWL_SNJ_A_JF_B_FW_PRE "iwlwifi-SoSnj-a0-jf-b0-" #define IWL_MA_A_HR_B_FW_PRE "iwlwifi-ma-a0-hr-b0-" #define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0-" #define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0-" @@ -46,7 +42,6 @@ #define IWL_MA_B_GF4_A_FW_PRE "iwlwifi-ma-b0-gf4-a0-" #define IWL_MA_B_MR_A_FW_PRE "iwlwifi-ma-b0-mr-a0-" #define IWL_MA_B_FM_A_FW_PRE "iwlwifi-ma-b0-fm-a0-" -#define IWL_SNJ_A_MR_A_FW_PRE "iwlwifi-SoSnj-a0-mr-a0-" #define IWL_SO_A_JF_B_MODULE_FIRMWARE(api) \ IWL_SO_A_JF_B_FW_PRE __stringify(api) ".ucode" @@ -56,14 +51,6 @@ IWL_SO_A_GF_A_FW_PRE __stringify(api) ".ucode" #define IWL_TY_A_GF_A_MODULE_FIRMWARE(api) \ IWL_TY_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_GF4_A_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_JF_B_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_JF_B_FW_PRE __stringify(api) ".ucode" #define IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(api) \ IWL_MA_A_HR_B_FW_PRE __stringify(api) ".ucode" #define IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(api) \ @@ -84,8 +71,6 @@ IWL_MA_B_MR_A_FW_PRE __stringify(api) ".ucode" #define IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(api) \ IWL_MA_B_FM_A_FW_PRE __stringify(api) ".ucode" -#define IWL_SNJ_A_MR_A_MODULE_FIRMWARE(api) \ - IWL_SNJ_A_MR_A_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl_ax210_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -159,15 +144,6 @@ static const struct iwl_base_params iwl_ax210_base_params = { }, \ } -const struct iwl_cfg_trans_params iwl_snj_trans_cfg = { - .mq_rx_supported = true, - .rf_id = true, - .gen2 = true, - .device_family = IWL_DEVICE_FAMILY_AX210, - .base_params = &iwl_ax210_base_params, - .umac_prph_offset = 0x300000, -}; - const struct iwl_cfg_trans_params iwl_so_trans_cfg = { .mq_rx_supported = true, .rf_id = true, @@ -297,36 +273,6 @@ const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long = { .trans.low_latency_xtal = true, }; -const struct iwl_cfg iwlax411_2ax_cfg_sosnj_gf4_a0 = { - .name = iwl_ax411_name, - .fw_name_pre = IWL_SNJ_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwlax211_cfg_snj_gf_a0 = { - .name = iwl_ax211_name, - .fw_name_pre = IWL_SNJ_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_snj_hr_b0 = { - .fw_name_pre = IWL_SNJ_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_snj_a0_jf_b0 = { - .fw_name_pre = IWL_SNJ_A_JF_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - const struct iwl_cfg iwl_cfg_ma_a0_hr_b0 = { .fw_name_pre = IWL_MA_A_HR_B_FW_PRE, .uhb_supported = true, @@ -411,20 +357,6 @@ const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; -const struct iwl_cfg iwl_cfg_snj_a0_mr_a0 = { - .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_snj_a0_ms_a0 = { - .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, - .uhb_supported = false, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - const struct iwl_cfg iwl_cfg_so_a0_hr_a0 = { .fw_name_pre = IWL_SO_A_HR_B_FW_PRE, IWL_DEVICE_AX210, @@ -435,10 +367,6 @@ MODULE_FIRMWARE(IWL_SO_A_JF_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SO_A_GF_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_TY_A_GF_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_GF4_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_GF_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_HR_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_JF_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); @@ -449,4 +377,3 @@ MODULE_FIRMWARE(IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SNJ_A_MR_A_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index b6795e08bd40..eb737e906df2 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -44,25 +44,6 @@ #define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0-" #define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0-" #define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" -#define IWL_BNJ_A_FM_A_FW_PRE "iwlwifi-BzBnj-a0-fm-a0-" -#define IWL_BNJ_A_FM4_A_FW_PRE "iwlwifi-BzBnj-a0-fm4-a0-" -#define IWL_BNJ_B_FM4_B_FW_PRE "iwlwifi-BzBnj-b0-fm4-b0-" -#define IWL_BNJ_A_GF_A_FW_PRE "iwlwifi-BzBnj-a0-gf-a0-" -#define IWL_BNJ_B_GF_A_FW_PRE "iwlwifi-BzBnj-b0-gf-a0-" -#define IWL_BNJ_C_GF_A_FW_PRE "iwlwifi-BzBnj-c0-gf-a0-" -#define IWL_BNJ_A_GF4_A_FW_PRE "iwlwifi-BzBnj-a0-gf4-a0-" -#define IWL_BNJ_B_GF4_A_FW_PRE "iwlwifi-BzBnj-b0-gf4-a0-" -#define IWL_BNJ_C_GF4_A_FW_PRE "iwlwifi-BzBnj-c0-gf4-a0-" -#define IWL_BNJ_A_HR_A_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-" -#define IWL_BNJ_A_HR_B_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-" -#define IWL_BNJ_B_HR_A_FW_PRE "iwlwifi-BzBnj-b0-hr-b0-" -#define IWL_BNJ_B_HR_B_FW_PRE "iwlwifi-BzBnj-b0-hr-b0-" -#define IWL_BNJ_C_HR_B_FW_PRE "iwlwifi-BzBnj-c0-hr-b0-" -#define IWL_BNJ_B_FM_B_FW_PRE "iwlwifi-BzBnj-b0-fm-b0-" -#define IWL_BNJ_C_FM_C_FW_PRE "iwlwifi-BzBnj-c0-fm-c0-" -#define IWL_BNJ_A_WH_A_FW_PRE "iwlwifi-BzBnj-a0-wh-a0-" -#define IWL_BNJ_B_WH_A_FW_PRE "iwlwifi-BzBnj-b0-wh-a0-" -#define IWL_BNJ_C_WH_A_FW_PRE "iwlwifi-BzBnj-c0-wh-a0-" #define IWL_BZ_A_HR_A_MODULE_FIRMWARE(api) \ IWL_BZ_A_HR_A_FW_PRE __stringify(api) ".ucode" @@ -98,45 +79,6 @@ IWL_GL_B_FM_B_FW_PRE __stringify(api) ".ucode" #define IWL_GL_C_FM_C_MODULE_FIRMWARE(api) \ IWL_GL_C_FM_C_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_FM_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_FM_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_FM4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_FM4_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_GF_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_C_GF_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_C_GF_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_GF4_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_C_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_C_GF4_A_FW_PRE __stringify(api) ".ucode" - -#define IWL_BNJ_A_HR_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_HR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_HR_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_HR_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_HR_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_C_HR_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_HR_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_FM_B_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_FM_B_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_C_FM_C_MODULE_FIRMWARE(api) \ - IWL_BNJ_C_FM_C_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_A_WH_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_A_WH_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_B_WH_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_B_WH_A_FW_PRE __stringify(api) ".ucode" -#define IWL_BNJ_C_WH_A_MODULE_FIRMWARE(api) \ - IWL_BNJ_C_WH_A_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl_bz_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -393,102 +335,6 @@ const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = { .num_rbds = IWL_NUM_RBDS_BZ_HE, }; -const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0 = { - .fw_name_pre = IWL_BNJ_A_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0 = { - .fw_name_pre = IWL_BNJ_A_FM4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_fm4_b0 = { - .fw_name_pre = IWL_BNJ_B_FM4_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0 = { - .fw_name_pre = IWL_BNJ_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_gf_a0 = { - .fw_name_pre = IWL_BNJ_B_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0 = { - .fw_name_pre = IWL_BNJ_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_gf4_a0 = { - .fw_name_pre = IWL_BNJ_B_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_hr_a0 = { - .fw_name_pre = IWL_BNJ_A_HR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = { - .fw_name_pre = IWL_BNJ_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_hr_a0 = { - .fw_name_pre = IWL_BNJ_B_HR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_hr_b0 = { - .fw_name_pre = IWL_BNJ_B_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0 = { - .fw_name_pre = IWL_BNJ_B_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - MODULE_FIRMWARE(IWL_BZ_A_HR_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); @@ -499,25 +345,7 @@ MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_C_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_C_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_HR_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_C_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_A_WH_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_B_WH_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BNJ_C_WH_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index ef5154cf114b..a18cbe75646f 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -417,13 +417,10 @@ struct iwl_cfg { #define IWL_CFG_ANY (~0) #define IWL_CFG_MAC_TYPE_PU 0x31 -#define IWL_CFG_MAC_TYPE_PNJ 0x32 #define IWL_CFG_MAC_TYPE_TH 0x32 #define IWL_CFG_MAC_TYPE_QU 0x33 #define IWL_CFG_MAC_TYPE_QUZ 0x35 -#define IWL_CFG_MAC_TYPE_QNJ 0x36 #define IWL_CFG_MAC_TYPE_SO 0x37 -#define IWL_CFG_MAC_TYPE_SNJ 0x42 #define IWL_CFG_MAC_TYPE_SOF 0x43 #define IWL_CFG_MAC_TYPE_MA 0x44 #define IWL_CFG_MAC_TYPE_BZ 0x46 @@ -489,12 +486,10 @@ extern const struct iwl_cfg_trans_params iwl9000_trans_cfg; extern const struct iwl_cfg_trans_params iwl9560_trans_cfg; extern const struct iwl_cfg_trans_params iwl9560_long_latency_trans_cfg; extern const struct iwl_cfg_trans_params iwl9560_shared_clk_trans_cfg; -extern const struct iwl_cfg_trans_params iwl_qnj_trans_cfg; extern const struct iwl_cfg_trans_params iwl_qu_trans_cfg; extern const struct iwl_cfg_trans_params iwl_qu_medium_latency_trans_cfg; extern const struct iwl_cfg_trans_params iwl_qu_long_latency_trans_cfg; extern const struct iwl_cfg_trans_params iwl_ax200_trans_cfg; -extern const struct iwl_cfg_trans_params iwl_snj_trans_cfg; extern const struct iwl_cfg_trans_params iwl_so_trans_cfg; extern const struct iwl_cfg_trans_params iwl_so_long_latency_trans_cfg; extern const struct iwl_cfg_trans_params iwl_so_long_latency_imr_trans_cfg; @@ -610,7 +605,6 @@ extern const struct iwl_cfg iwl9260_2ac_cfg; extern const struct iwl_cfg iwl9560_qu_b0_jf_b0_cfg; extern const struct iwl_cfg iwl9560_qu_c0_jf_b0_cfg; extern const struct iwl_cfg iwl9560_quz_a0_jf_b0_cfg; -extern const struct iwl_cfg iwl9560_qnj_b0_jf_b0_cfg; extern const struct iwl_cfg iwl9560_2ac_cfg_soc; extern const struct iwl_cfg iwl_qu_b0_hr1_b0; extern const struct iwl_cfg iwl_qu_c0_hr1_b0; @@ -629,17 +623,12 @@ extern const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0; extern const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0; extern const struct iwl_cfg killer1650x_2ax_cfg; extern const struct iwl_cfg killer1650w_2ax_cfg; -extern const struct iwl_cfg iwl_qnj_b0_hr_b0_cfg; extern const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0; extern const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0; extern const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long; extern const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0; extern const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0; extern const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long; -extern const struct iwl_cfg iwlax411_2ax_cfg_sosnj_gf4_a0; -extern const struct iwl_cfg iwlax211_cfg_snj_gf_a0; -extern const struct iwl_cfg iwl_cfg_snj_hr_b0; -extern const struct iwl_cfg iwl_cfg_snj_a0_jf_b0; extern const struct iwl_cfg iwl_cfg_ma_a0_hr_b0; extern const struct iwl_cfg iwl_cfg_ma_a0_gf_a0; extern const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0; @@ -651,8 +640,6 @@ extern const struct iwl_cfg iwl_cfg_ma_b0_gf_a0; extern const struct iwl_cfg iwl_cfg_ma_b0_gf4_a0; extern const struct iwl_cfg iwl_cfg_ma_b0_mr_a0; extern const struct iwl_cfg iwl_cfg_ma_b0_fm_a0; -extern const struct iwl_cfg iwl_cfg_snj_a0_mr_a0; -extern const struct iwl_cfg iwl_cfg_snj_a0_ms_a0; extern const struct iwl_cfg iwl_cfg_so_a0_hr_a0; extern const struct iwl_cfg iwl_cfg_so_a0_ms_a0; extern const struct iwl_cfg iwl_cfg_quz_a0_hr_b0; @@ -674,18 +661,6 @@ extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_gl_b0_fm_b0; extern const struct iwl_cfg iwl_cfg_gl_c0_fm_c0; extern const struct iwl_cfg iwl_cfg_bz_z0_gf_a0; -extern const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0; -extern const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0; -extern const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0; -extern const struct iwl_cfg iwl_cfg_bnj_b0_gf_a0; -extern const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0; -extern const struct iwl_cfg iwl_cfg_bnj_b0_gf4_a0; -extern const struct iwl_cfg iwl_cfg_bnj_a0_hr_a0; -extern const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0; -extern const struct iwl_cfg iwl_cfg_bnj_b0_hr_a0; -extern const struct iwl_cfg iwl_cfg_bnj_b0_hr_b0; -extern const struct iwl_cfg iwl_cfg_bnj_b0_fm_b0; -extern const struct iwl_cfg iwl_cfg_bnj_b0_fm4_b0; extern const struct iwl_cfg iwl_cfg_sc_a0_fm_b0; extern const struct iwl_cfg iwl_cfg_sc_a0_fm_c0; extern const struct iwl_cfg iwl_cfg_sc_a0_hr_a0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 2b342e832f22..49b396bf4f49 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -484,13 +484,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x43F0, PCI_ANY_ID, iwl_qu_long_latency_trans_cfg)}, {IWL_PCI_DEVICE(0xA0F0, PCI_ANY_ID, iwl_qu_long_latency_trans_cfg)}, - {IWL_PCI_DEVICE(0x2720, PCI_ANY_ID, iwl_qnj_trans_cfg)}, - {IWL_PCI_DEVICE(0x2723, PCI_ANY_ID, iwl_ax200_trans_cfg)}, /* So devices */ {IWL_PCI_DEVICE(0x2725, PCI_ANY_ID, iwl_so_trans_cfg)}, - {IWL_PCI_DEVICE(0x2726, PCI_ANY_ID, iwl_snj_trans_cfg)}, {IWL_PCI_DEVICE(0x7A70, PCI_ANY_ID, iwl_so_long_latency_imr_trans_cfg)}, {IWL_PCI_DEVICE(0x7AF0, PCI_ANY_ID, iwl_so_trans_cfg)}, {IWL_PCI_DEVICE(0x51F0, PCI_ANY_ID, iwl_so_long_latency_trans_cfg)}, @@ -666,20 +663,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x7AF0, 0x1551, iwl9560_2ac_cfg_soc, iwl9560_killer_1550s_160_name), IWL_DEV_INFO(0x7AF0, 0x1552, iwl9560_2ac_cfg_soc, iwl9560_killer_1550i_160_name), - /* SnJ with HR */ - IWL_DEV_INFO(0x2725, 0x00B0, iwlax411_2ax_cfg_sosnj_gf4_a0, NULL), - IWL_DEV_INFO(0x2726, 0x0090, iwlax211_cfg_snj_gf_a0, NULL), - IWL_DEV_INFO(0x2726, 0x0098, iwlax211_cfg_snj_gf_a0, NULL), - IWL_DEV_INFO(0x2726, 0x00B0, iwlax411_2ax_cfg_sosnj_gf4_a0, NULL), - IWL_DEV_INFO(0x2726, 0x00B4, iwlax411_2ax_cfg_sosnj_gf4_a0, NULL), - IWL_DEV_INFO(0x2726, 0x0510, iwlax211_cfg_snj_gf_a0, NULL), - IWL_DEV_INFO(0x2726, 0x1651, iwl_cfg_snj_hr_b0, iwl_ax201_killer_1650s_name), - IWL_DEV_INFO(0x2726, 0x1652, iwl_cfg_snj_hr_b0, iwl_ax201_killer_1650i_name), - IWL_DEV_INFO(0x2726, 0x1691, iwlax411_2ax_cfg_sosnj_gf4_a0, iwl_ax411_killer_1690s_name), - IWL_DEV_INFO(0x2726, 0x1692, iwlax411_2ax_cfg_sosnj_gf4_a0, iwl_ax411_killer_1690i_name), - IWL_DEV_INFO(0x7F70, 0x1691, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690s_name), - IWL_DEV_INFO(0x7F70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), - /* SO with GF2 */ IWL_DEV_INFO(0x2726, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x2726, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), @@ -730,27 +713,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl9560_2ac_cfg_soc, iwl9560_name), - _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_PNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9260_2ac_cfg, iwl9461_160_name), - _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_PNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9260_2ac_cfg, iwl9461_name), - _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_PNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9260_2ac_cfg, iwl9462_160_name), - _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_PNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9260_2ac_cfg, iwl9462_name), - _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_TH, IWL_CFG_ANY, IWL_CFG_RF_TYPE_TH, IWL_CFG_ANY, IWL_CFG_ANY, @@ -917,50 +879,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl9560_quz_a0_jf_b0_cfg, iwl9560_killer_1550i_name), - /* QnJ */ - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9560_qnj_b0_jf_b0_cfg, iwl9461_160_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9560_qnj_b0_jf_b0_cfg, iwl9461_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9560_qnj_b0_jf_b0_cfg, iwl9462_160_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9560_qnj_b0_jf_b0_cfg, iwl9462_name), - - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9560_qnj_b0_jf_b0_cfg, iwl9560_160_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9560_qnj_b0_jf_b0_cfg, iwl9560_name), - - _IWL_DEV_INFO(IWL_CFG_ANY, 0x1551, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9560_qnj_b0_jf_b0_cfg, iwl9560_killer_1550s_name), - _IWL_DEV_INFO(IWL_CFG_ANY, 0x1552, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl9560_qnj_b0_jf_b0_cfg, iwl9560_killer_1550i_name), - /* Qu with Hr */ /* Qu B step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, @@ -1008,59 +926,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl_cfg_quz_a0_hr_b0, iwl_ax201_name), -/* QnJ with Hr */ - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_QNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_qnj_b0_hr_b0_cfg, iwl_ax201_name), - -/* SnJ with Jf */ - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_jf_b0, iwl9461_160_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_jf_b0, iwl9461_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_jf_b0, iwl9462_160_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_jf_b0, iwl9462_name), - - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_jf_b0, iwl9560_160_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_jf_b0, iwl9560_name), - -/* SnJ with Hr */ - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_hr_b0, iwl_ax101_name), - - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_hr_b0, iwl_ax201_name), - /* Ma */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, @@ -1087,11 +952,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl_cfg_ma_a0_fm_a0, iwl_ax231_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_mr_a0, iwl_ax221_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, @@ -1259,68 +1119,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl_cfg_bz_z0_gf_a0, iwl_bz_name), -/* BNJ */ - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET, - iwl_cfg_bnj_a0_fm_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET, - iwl_cfg_bnj_b0_fm_b0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET, - iwl_cfg_bnj_a0_fm4_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET, - iwl_cfg_bnj_b0_fm4_b0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET, - iwl_cfg_bnj_a0_gf_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_IS_JACKET, - iwl_cfg_bnj_b0_gf_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET, - iwl_cfg_bnj_a0_gf4_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_IS_JACKET, - iwl_cfg_bnj_b0_gf4_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, - IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_bnj_a0_hr_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, - IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_bnj_a0_hr_b0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP, - IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_bnj_b0_hr_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP, - IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_bnj_b0_hr_b0, iwl_bz_name), - /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, @@ -1418,11 +1216,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_MS, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, iwl_cfg_ma_a0_ms_a0, iwl_ax204_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SNJ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_MS, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, - iwl_cfg_snj_a0_ms_a0, iwl_ax204_name), /* Sc */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, @@ -1739,17 +1532,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } #if IS_ENABLED(CONFIG_IWLMVM) - - /* - * Workaround for problematic SnJ device: sometimes when - * certain RF modules are connected to SnJ, the device ID - * changes to QnJ's ID. So we are using QnJ's trans_cfg until - * here. But if we detect that the MAC type is actually SnJ, - * we should switch to it here to avoid problems later. - */ - if (CSR_HW_REV_TYPE(iwl_trans->hw_rev) == IWL_CFG_MAC_TYPE_SNJ) - iwl_trans->trans_cfg = &iwl_so_trans_cfg; - /* * special-case 7265D, it has the same PCI IDs. * -- cgit v1.2.3 From e3597e28a2fab5e260dcbfde20c12025ee250b72 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:14 +0300 Subject: wifi: iwlwifi: pcie: also drop jacket from info macro We don't need this here anymore, ANY is just fine. Still keep the rest of the infrastructure so we can more easily add back support for testing. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.168c714cbb83.I0721ce86a042c4d8004914129bab46d7ccc8cb00@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 219 +++++++++++++------------- 1 file changed, 109 insertions(+), 110 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 49b396bf4f49..7f914bc1000c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -515,17 +515,16 @@ static const struct pci_device_id iwl_hw_card_ids[] = { MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); #define _IWL_DEV_INFO(_device, _subdevice, _mac_type, _mac_step, _rf_type, \ - _rf_id, _rf_step, _no_160, _cores, _cdb, _jacket, _cfg, \ - _name) \ + _rf_id, _rf_step, _no_160, _cores, _cdb, _cfg, _name) \ { .device = (_device), .subdevice = (_subdevice), .cfg = &(_cfg), \ .name = _name, .mac_type = _mac_type, .rf_type = _rf_type, .rf_step = _rf_step, \ .no_160 = _no_160, .cores = _cores, .rf_id = _rf_id, \ - .mac_step = _mac_step, .cdb = _cdb, .jacket = _jacket } + .mac_step = _mac_step, .cdb = _cdb, .jacket = IWL_CFG_ANY } #define IWL_DEV_INFO(_device, _subdevice, _cfg, _name) \ - _IWL_DEV_INFO(_device, _subdevice, IWL_CFG_ANY, IWL_CFG_ANY, \ - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, \ - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, _cfg, _name) + _IWL_DEV_INFO(_device, _subdevice, IWL_CFG_ANY, IWL_CFG_ANY, \ + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, \ + IWL_CFG_ANY, _cfg, _name) static const struct iwl_dev_info iwl_dev_info_table[] = { #if IS_ENABLED(CONFIG_IWLMVM) @@ -684,66 +683,66 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_2ac_cfg_soc, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_2ac_cfg_soc, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_2ac_cfg_soc, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_2ac_cfg_soc, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_2ac_cfg_soc, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_2ac_cfg_soc, iwl9560_name), _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_TH, IWL_CFG_ANY, IWL_CFG_RF_TYPE_TH, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT_GNSS, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT_GNSS, IWL_CFG_NO_CDB, iwl9260_2ac_cfg, iwl9270_160_name), _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_TH, IWL_CFG_ANY, IWL_CFG_RF_TYPE_TH, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT_GNSS, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT_GNSS, IWL_CFG_NO_CDB, iwl9260_2ac_cfg, iwl9270_name), _IWL_DEV_INFO(0x271B, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_TH, IWL_CFG_ANY, IWL_CFG_RF_TYPE_TH1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9260_2ac_cfg, iwl9162_160_name), _IWL_DEV_INFO(0x271B, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_TH, IWL_CFG_ANY, IWL_CFG_RF_TYPE_TH1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9260_2ac_cfg, iwl9162_name), _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_TH, IWL_CFG_ANY, IWL_CFG_RF_TYPE_TH, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9260_2ac_cfg, iwl9260_160_name), _IWL_DEV_INFO(0x2526, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_TH, IWL_CFG_ANY, IWL_CFG_RF_TYPE_TH, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9260_2ac_cfg, iwl9260_name), /* Qu with Jf */ @@ -751,132 +750,132 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9560_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1551, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9560_killer_1550s_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1552, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_b0_jf_b0_cfg, iwl9560_killer_1550i_name), /* Qu C step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9560_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1551, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9560_killer_1550s_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1552, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_qu_c0_jf_b0_cfg, iwl9560_killer_1550i_name), /* QuZ */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9462_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9560_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1551, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9560_killer_1550s_name), _IWL_DEV_INFO(IWL_CFG_ANY, 0x1552, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwl9560_quz_a0_jf_b0_cfg, iwl9560_killer_1550i_name), /* Qu with Hr */ @@ -884,319 +883,319 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_b0_hr1_b0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_B_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_b0_hr_b0, iwl_ax203_name), /* Qu C step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_c0_hr1_b0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_c0_hr_b0, iwl_ax203_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QU, SILICON_C_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_qu_c0_hr_b0, iwl_ax201_name), /* QuZ */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_quz_a0_hr1_b0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, SILICON_B_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_quz_a0_hr_b0, iwl_ax203_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_QUZ, SILICON_B_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_quz_a0_hr_b0, iwl_ax201_name), /* Ma */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_hr_b0, iwl_ax201_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_gf_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_ma_a0_gf4_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_mr_a0, iwl_ax221_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_fm_a0, iwl_ax231_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_b0_hr_b0, iwl_ax201_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_b0_gf_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_ma_b0_gf4_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_b0_mr_a0, iwl_ax221_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_b0_fm_a0, iwl_ax231_name), /* So with Hr */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax203_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax201_name), /* So-F with Hr */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax203_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax101_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_hr_a0, iwl_ax201_name), /* So-F with Gf */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_name), /* Bz */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_a0_hr_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_a0_hr_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_a0_gf_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_bz_a0_gf4_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_b0_gf_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_bz_b0_gf4_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_a0_mr_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_a0_fm_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_bz_a0_fm4_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_a0_fm_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_a0_fm_c0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_bz_a0_fm4_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_b0_fm_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_bz_b0_fm4_b0, iwl_bz_name), /* Ga (Gl) */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_gl_a0_fm_a0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_gl_b0_fm_b0, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_GL, SILICON_C_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_NO_JACKET, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_gl_c0_fm_c0, iwl_bz_name), /* BZ Z step */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, SILICON_Z_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_z0_gf_a0, iwl_bz_name), /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9560_name), /* SoF with JF */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9462_name), /* So with GF */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_CDB, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_name), /* So with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9560_name), /* So with JF */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9461_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, IWL_CFG_ANY, - IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, iwlax210_2ax_cfg_so_jf_b0, iwl9462_name), /* MsP */ @@ -1204,54 +1203,54 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MS, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_ms_a0, iwl_ax204_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MS, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_so_a0_ms_a0, iwl_ax204_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MS, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_ma_a0_ms_a0, iwl_ax204_name), /* Sc */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_sc_a0_fm_b0, iwl_sc_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_sc_a0_fm_c0, iwl_sc_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_sc_a0_hr_a0, iwl_sc_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_sc_a0_hr_b0, iwl_sc_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_sc_a0_gf_a0, iwl_sc_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, iwl_cfg_sc_a0_gf4_a0, iwl_sc_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, IWL_CFG_RF_TYPE_WH, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_sc_a0_wh_a0, iwl_sc_name), #endif /* CONFIG_IWLMVM */ }; -- cgit v1.2.3 From 3fd31289d5de8392c914db4f8cb36e0999afdac2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:15 +0300 Subject: wifi: iwlwifi: unify Bz/Gl device configurations All the configurations for the various Bz/Gl devices are basically identical, except for Gl A-step and the firmware filename prefixes. Add some infrastructure to auto-generate the firmware filename prefix based on the detected MAC step and RF name/step, and remove all the unneeded configs. This reduces the size of the iwlwifi module by ~9k: 517582 27111 560 545253 851e5 drivers/net/wireless/intel/iwlwifi/iwlwifi.ko 526885 27083 560 554528 87620 drivers/net/wireless/intel/iwlwifi/iwlwifi.ko Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.1dc121ba338f.I07d651516eb82cbaded4724ef30558a50f2fa866@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 128 +---------------------- drivers/net/wireless/intel/iwlwifi/fw/pnvm.h | 18 ++-- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 24 ++--- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 69 +++++++++++- drivers/net/wireless/intel/iwlwifi/iwl-drv.h | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 4 +- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 92 ++-------------- 7 files changed, 102 insertions(+), 239 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index eb737e906df2..fe6166d364cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -191,112 +191,8 @@ const struct iwl_cfg_trans_params iwl_bz_trans_cfg = { const char iwl_bz_name[] = "Intel(R) TBD Bz device"; -const struct iwl_cfg iwl_cfg_bz_a0_hr_a0 = { - .fw_name_pre = IWL_BZ_A_HR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_hr_b0 = { - .fw_name_pre = IWL_BZ_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_gf_a0 = { - .fw_name_pre = IWL_BZ_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0 = { - .fw_name_pre = IWL_BZ_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_b0_gf_a0 = { - .fw_name_pre = IWL_BZ_B_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_b0_gf4_a0 = { - .fw_name_pre = IWL_BZ_B_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_mr_a0 = { - .fw_name_pre = IWL_BZ_A_MR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm_a0 = { - .fw_name_pre = IWL_BZ_A_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0 = { - .fw_name_pre = IWL_BZ_A_FM4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm_b0 = { - .fw_name_pre = IWL_BZ_A_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm_c0 = { - .fw_name_pre = IWL_BZ_A_FM_C_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0 = { - .fw_name_pre = IWL_BZ_A_FM4_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_b0_fm_b0 = { - .fw_name_pre = IWL_BZ_B_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_b0_fm4_b0 = { - .fw_name_pre = IWL_BZ_B_FM4_B_FW_PRE, +const struct iwl_cfg iwl_cfg_bz = { + .fw_name_mac = "bz", .uhb_supported = true, IWL_DEVICE_BZ, .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, @@ -311,24 +207,8 @@ const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = { .num_rbds = IWL_NUM_RBDS_BZ_HE, }; -const struct iwl_cfg iwl_cfg_gl_b0_fm_b0 = { - .fw_name_pre = IWL_GL_B_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_gl_c0_fm_c0 = { - .fw_name_pre = IWL_GL_C_FM_C_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - -const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = { - .fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE, +const struct iwl_cfg iwl_cfg_gl = { + .fw_name_mac = "gl", .uhb_supported = true, IWL_DEVICE_BZ, .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index 4e10baa01738..32fba08b7db1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -1,13 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/****************************************************************************** - * - * Copyright(c) 2020-2022 Intel Corporation - * - *****************************************************************************/ - +/* + * Copyright(c) 2020-2023 Intel Corporation + */ #ifndef __IWL_PNVM_H__ #define __IWL_PNVM_H__ +#include "iwl-drv.h" #include "fw/notif-wait.h" #define MVM_UCODE_PNVM_TIMEOUT (HZ / 4) @@ -22,16 +20,20 @@ static inline void iwl_pnvm_get_fs_name(struct iwl_trans *trans, u8 *pnvm_name, size_t max_len) { + char _fw_name_pre[FW_NAME_PRE_BUFSIZE]; + const char *fw_name_pre; int pre_len; + fw_name_pre = iwl_drv_get_fwname_pre(trans, _fw_name_pre); + /* * The prefix unfortunately includes a hyphen at the end, so * don't add the dot here... */ - snprintf(pnvm_name, max_len, "%spnvm", trans->cfg->fw_name_pre); + snprintf(pnvm_name, max_len, "%spnvm", fw_name_pre); /* ...but replace the hyphen with the dot here. */ - pre_len = strlen(trans->cfg->fw_name_pre); + pre_len = strlen(fw_name_pre); if (pre_len < max_len && pre_len > 0) pnvm_name[pre_len - 1] = '.'; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index a18cbe75646f..47e164beda29 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -310,6 +310,8 @@ struct iwl_fw_mon_regs { * @fw_name_pre: Firmware filename prefix. The api version and extension * (.ucode) will be added to filename before loading from disk. The * filename is constructed as fw_name_pre.ucode. + * @fw_name_mac: MAC name for this config, the remaining pieces of the + * name will be generated dynamically * @ucode_api_max: Highest version of uCode API supported by driver. * @ucode_api_min: Lowest version of uCode API supported by driver. * @max_inst_size: The maximal length of the fw inst section (only DVM) @@ -363,6 +365,7 @@ struct iwl_cfg { /* params specific to an individual device within a device family */ const char *name; const char *fw_name_pre; + const char *fw_name_mac; /* params likely to change within a device family */ const struct iwl_ht_params *ht_params; const struct iwl_eeprom_params *eeprom_params; @@ -643,24 +646,11 @@ extern const struct iwl_cfg iwl_cfg_ma_b0_fm_a0; extern const struct iwl_cfg iwl_cfg_so_a0_hr_a0; extern const struct iwl_cfg iwl_cfg_so_a0_ms_a0; extern const struct iwl_cfg iwl_cfg_quz_a0_hr_b0; -extern const struct iwl_cfg iwl_cfg_bz_a0_hr_a0; -extern const struct iwl_cfg iwl_cfg_bz_a0_hr_b0; -extern const struct iwl_cfg iwl_cfg_bz_a0_gf_a0; -extern const struct iwl_cfg iwl_cfg_bz_a0_gf4_a0; -extern const struct iwl_cfg iwl_cfg_bz_b0_gf_a0; -extern const struct iwl_cfg iwl_cfg_bz_b0_gf4_a0; -extern const struct iwl_cfg iwl_cfg_bz_a0_mr_a0; -extern const struct iwl_cfg iwl_cfg_bz_a0_fm_a0; -extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_a0; -extern const struct iwl_cfg iwl_cfg_bz_a0_fm_b0; -extern const struct iwl_cfg iwl_cfg_bz_a0_fm_c0; -extern const struct iwl_cfg iwl_cfg_bz_a0_fm4_b0; -extern const struct iwl_cfg iwl_cfg_bz_b0_fm_b0; -extern const struct iwl_cfg iwl_cfg_bz_b0_fm4_b0; + +extern const struct iwl_cfg iwl_cfg_bz; extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0; -extern const struct iwl_cfg iwl_cfg_gl_b0_fm_b0; -extern const struct iwl_cfg iwl_cfg_gl_c0_fm_c0; -extern const struct iwl_cfg iwl_cfg_bz_z0_gf_a0; +extern const struct iwl_cfg iwl_cfg_gl; + extern const struct iwl_cfg iwl_cfg_sc_a0_fm_b0; extern const struct iwl_cfg iwl_cfg_sc_a0_fm_c0; extern const struct iwl_cfg iwl_cfg_sc_a0_hr_a0; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 34feb4d29adc..a7cf73d67371 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -158,12 +158,71 @@ static int iwl_alloc_fw_desc(struct iwl_drv *drv, struct fw_desc *desc, return 0; } +static inline char iwl_drv_get_step(int step) +{ + if (step == SILICON_Z_STEP) + return 'z'; + return 'a' + step; +} + +const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) +{ + char mac_step, rf_step; + const char *rf, *cdb; + + if (trans->cfg->fw_name_pre) + return trans->cfg->fw_name_pre; + + if (WARN_ON(!trans->cfg->fw_name_mac)) + return "unconfigured-"; + + mac_step = iwl_drv_get_step(trans->hw_rev_step); + + switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { + case IWL_CFG_RF_TYPE_HR1: + case IWL_CFG_RF_TYPE_HR2: + rf = "hr"; + break; + case IWL_CFG_RF_TYPE_GF: + rf = "gf"; + break; + case IWL_CFG_RF_TYPE_MR: + rf = "mr"; + break; + case IWL_CFG_RF_TYPE_MS: + rf = "ms"; + break; + case IWL_CFG_RF_TYPE_FM: + rf = "fm"; + break; + case IWL_CFG_RF_TYPE_WH: + rf = "wh"; + break; + default: + return "unknown-rf-"; + } + + cdb = CSR_HW_RFID_IS_CDB(trans->hw_rf_id) ? "4" : ""; + + rf_step = iwl_drv_get_step(CSR_HW_RFID_STEP(trans->hw_rf_id)); + + scnprintf(buf, FW_NAME_PRE_BUFSIZE, + "iwlwifi-%s-%c0-%s%s-%c0", + trans->cfg->fw_name_mac, mac_step, + rf, cdb, rf_step); + + return buf; +} +IWL_EXPORT_SYMBOL(iwl_drv_get_fwname_pre); + static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context); static int iwl_request_firmware(struct iwl_drv *drv, bool first) { const struct iwl_cfg *cfg = drv->trans->cfg; + char _fw_name_pre[FW_NAME_PRE_BUFSIZE]; + const char *fw_name_pre; if (drv->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000 && (drv->trans->hw_rev_step != SILICON_B_STEP && @@ -174,6 +233,8 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) return -EINVAL; } + fw_name_pre = iwl_drv_get_fwname_pre(drv->trans, _fw_name_pre); + if (first) drv->fw_index = cfg->ucode_api_max; else @@ -183,13 +244,13 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) IWL_ERR(drv, "no suitable firmware found!\n"); if (cfg->ucode_api_min == cfg->ucode_api_max) { - IWL_ERR(drv, "%s%d is required\n", cfg->fw_name_pre, + IWL_ERR(drv, "%s%d is required\n", fw_name_pre, cfg->ucode_api_max); } else { IWL_ERR(drv, "minimum version required: %s%d\n", - cfg->fw_name_pre, cfg->ucode_api_min); + fw_name_pre, cfg->ucode_api_min); IWL_ERR(drv, "maximum version supported: %s%d\n", - cfg->fw_name_pre, cfg->ucode_api_max); + fw_name_pre, cfg->ucode_api_max); } IWL_ERR(drv, @@ -198,7 +259,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) } snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%d.ucode", - cfg->fw_name_pre, drv->fw_index); + fw_name_pre, drv->fw_index); IWL_DEBUG_FW_INFO(drv, "attempting to load firmware '%s'\n", drv->firmware_name); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h index 80073f973334..6c19989e4ab7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2020-2021 Intel Corporation + * Copyright (C) 2005-2014, 2020-2021, 2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH */ #ifndef __iwl_drv_h__ @@ -92,4 +92,8 @@ void iwl_drv_stop(struct iwl_drv *drv); /* max retry for init flow */ #define IWL_MAX_INIT_RETRY 2 +#define FW_NAME_PRE_BUFSIZE 64 +struct iwl_trans; +const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf); + #endif /* __iwl_drv_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index c037b2ad5fa1..cf27f106d4d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -15,6 +15,7 @@ #include "iwl-io.h" #include "debugfs.h" #include "iwl-modparams.h" +#include "iwl-drv.h" #include "fw/error-dump.h" #include "fw/api/phy-ctxt.h" @@ -715,6 +716,7 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf, struct iwl_mvm *mvm = file->private_data; char *buff, *pos, *endpos; static const size_t bufsz = 1024; + char _fw_name_pre[FW_NAME_PRE_BUFSIZE]; int ret; buff = kmalloc(bufsz, GFP_KERNEL); @@ -725,7 +727,7 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf, endpos = pos + bufsz; pos += scnprintf(pos, endpos - pos, "FW prefix: %s\n", - mvm->trans->cfg->fw_name_pre); + iwl_drv_get_fwname_pre(mvm->trans, _fw_name_pre)); pos += scnprintf(pos, endpos - pos, "FW: %s\n", mvm->fwrt.fw->human_readable); pos += scnprintf(pos, endpos - pos, "Device: %s\n", diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 7f914bc1000c..33827441803b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1026,97 +1026,21 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { /* Bz */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_hr_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_hr_b0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_gf_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_bz_a0_gf4_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_b0_gf_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_bz_b0_gf4_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, IWL_CFG_ANY, - IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_mr_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_fm_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_bz_a0_fm4_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_fm_b0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_a0_fm_c0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_bz_a0_fm4_b0, iwl_bz_name), + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + iwl_cfg_bz, iwl_bz_name), + +/* Ga (Gl) */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, + IWL_CFG_MAC_TYPE_GL, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_b0_fm_b0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_B_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_bz_b0_fm4_b0, iwl_bz_name), -/* Ga (Gl) */ + iwl_cfg_gl, iwl_bz_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_gl_a0_fm_a0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_B_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_gl_b0_fm_b0, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_C_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_gl_c0_fm_c0, iwl_bz_name), - -/* BZ Z step */ - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_BZ, SILICON_Z_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_bz_z0_gf_a0, iwl_bz_name), /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, -- cgit v1.2.3 From bfed356b4fc4e24d0cc73a81d51d193353629e73 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:16 +0300 Subject: wifi: iwlwifi: also unify Sc device configurations Again, they're all the same except for the radio and steps, so use the new logic to unify them. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.3bc1191f883f.If1e6f73a164b0794ac65372b72673ce8ddf9e571@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 52 +------------------------ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 8 +--- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 38 ++---------------- 3 files changed, 7 insertions(+), 91 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 53b2a5969db6..679cb53ae18a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -149,56 +149,8 @@ const struct iwl_cfg_trans_params iwl_sc_trans_cfg = { const char iwl_sc_name[] = "Intel(R) TBD Sc device"; -const struct iwl_cfg iwl_cfg_sc_a0_fm_b0 = { - .fw_name_pre = IWL_SC_A_FM_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_fm_c0 = { - .fw_name_pre = IWL_SC_A_FM_C_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_hr_a0 = { - .fw_name_pre = IWL_SC_A_HR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_hr_b0 = { - .fw_name_pre = IWL_SC_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_gf_a0 = { - .fw_name_pre = IWL_SC_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_gf4_a0 = { - .fw_name_pre = IWL_SC_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_HE, -}; - -const struct iwl_cfg iwl_cfg_sc_a0_wh_a0 = { - .fw_name_pre = IWL_SC_A_WH_A_FW_PRE, +const struct iwl_cfg iwl_cfg_sc = { + .fw_name_mac = "sc", .uhb_supported = true, IWL_DEVICE_SC, .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 47e164beda29..49a66951c5bc 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -651,13 +651,7 @@ extern const struct iwl_cfg iwl_cfg_bz; extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_gl; -extern const struct iwl_cfg iwl_cfg_sc_a0_fm_b0; -extern const struct iwl_cfg iwl_cfg_sc_a0_fm_c0; -extern const struct iwl_cfg iwl_cfg_sc_a0_hr_a0; -extern const struct iwl_cfg iwl_cfg_sc_a0_hr_b0; -extern const struct iwl_cfg iwl_cfg_sc_a0_gf_a0; -extern const struct iwl_cfg iwl_cfg_sc_a0_gf4_a0; -extern const struct iwl_cfg iwl_cfg_sc_a0_wh_a0; +extern const struct iwl_cfg iwl_cfg_sc; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 33827441803b..1944e621dbef 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1142,40 +1142,10 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { /* Sc */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_B_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_sc_a0_fm_b0, iwl_sc_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_C_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_sc_a0_fm_c0, iwl_sc_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, - IWL_CFG_RF_TYPE_HR1, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_sc_a0_hr_a0, iwl_sc_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, - IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_sc_a0_hr_b0, iwl_sc_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_sc_a0_gf_a0, iwl_sc_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_sc_a0_gf4_a0, iwl_sc_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_SC, SILICON_A_STEP, - IWL_CFG_RF_TYPE_WH, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_sc_a0_wh_a0, iwl_sc_name), + IWL_CFG_MAC_TYPE_SC, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + iwl_cfg_sc, iwl_sc_name), #endif /* CONFIG_IWLMVM */ }; -- cgit v1.2.3 From ecf11f4e4950defa89ca9d813ba9684c19d85f6e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:17 +0300 Subject: wifi: iwlwifi: also unify Ma device configurations Again, they're all the same except for the radio and steps, so use the new logic to unify them. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.676887cc8180.I29994dec43bfb29aad5e4ab0126c06a9ea4670cb@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 74 +------------------------ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 14 +---- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 58 +++++-------------- 3 files changed, 19 insertions(+), 127 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index e1c3afb97941..a484cae3f784 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -273,76 +273,6 @@ const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long = { .trans.low_latency_xtal = true, }; -const struct iwl_cfg iwl_cfg_ma_a0_hr_b0 = { - .fw_name_pre = IWL_MA_A_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_gf_a0 = { - .fw_name_pre = IWL_MA_A_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0 = { - .fw_name_pre = IWL_MA_A_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_mr_a0 = { - .fw_name_pre = IWL_MA_A_MR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_a0_ms_a0 = { - .fw_name_pre = IWL_MA_A_MR_A_FW_PRE, - .uhb_supported = false, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_fm_a0 = { - .fw_name_pre = IWL_MA_B_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_hr_b0 = { - .fw_name_pre = IWL_MA_B_HR_B_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_gf_a0 = { - .fw_name_pre = IWL_MA_B_GF_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_gf4_a0 = { - .fw_name_pre = IWL_MA_B_GF4_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - -const struct iwl_cfg iwl_cfg_ma_b0_mr_a0 = { - .fw_name_pre = IWL_MA_B_MR_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - const struct iwl_cfg iwl_cfg_so_a0_ms_a0 = { .fw_name_pre = IWL_SO_A_MR_A_FW_PRE, .uhb_supported = false, @@ -350,8 +280,8 @@ const struct iwl_cfg iwl_cfg_so_a0_ms_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; -const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = { - .fw_name_pre = IWL_MA_A_FM_A_FW_PRE, +const struct iwl_cfg iwl_cfg_ma = { + .fw_name_mac = "ma", .uhb_supported = true, IWL_DEVICE_AX210, .num_rbds = IWL_NUM_RBDS_AX210_HE, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 49a66951c5bc..4cc0285f287e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -632,17 +632,9 @@ extern const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0_long; extern const struct iwl_cfg iwlax210_2ax_cfg_ty_gf_a0; extern const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0; extern const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long; -extern const struct iwl_cfg iwl_cfg_ma_a0_hr_b0; -extern const struct iwl_cfg iwl_cfg_ma_a0_gf_a0; -extern const struct iwl_cfg iwl_cfg_ma_a0_gf4_a0; -extern const struct iwl_cfg iwl_cfg_ma_a0_mr_a0; -extern const struct iwl_cfg iwl_cfg_ma_a0_ms_a0; -extern const struct iwl_cfg iwl_cfg_ma_a0_fm_a0; -extern const struct iwl_cfg iwl_cfg_ma_b0_hr_b0; -extern const struct iwl_cfg iwl_cfg_ma_b0_gf_a0; -extern const struct iwl_cfg iwl_cfg_ma_b0_gf4_a0; -extern const struct iwl_cfg iwl_cfg_ma_b0_mr_a0; -extern const struct iwl_cfg iwl_cfg_ma_b0_fm_a0; + +extern const struct iwl_cfg iwl_cfg_ma; + extern const struct iwl_cfg iwl_cfg_so_a0_hr_a0; extern const struct iwl_cfg iwl_cfg_so_a0_ms_a0; extern const struct iwl_cfg iwl_cfg_quz_a0_hr_b0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 1944e621dbef..41dbb9da8203 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -551,8 +551,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x7A70, 0x1692, iwlax411_2ax_cfg_so_gf4_a0, iwl_ax411_killer_1690i_name), IWL_DEV_INFO(0x271C, 0x0214, iwl9260_2ac_cfg, iwl9260_1_name), - IWL_DEV_INFO(0x7E40, 0x1691, iwl_cfg_ma_a0_gf4_a0, iwl_ax411_killer_1690s_name), - IWL_DEV_INFO(0x7E40, 0x1692, iwl_cfg_ma_a0_gf4_a0, iwl_ax411_killer_1690i_name), + IWL_DEV_INFO(0x7E40, 0x1691, iwl_cfg_ma, iwl_ax411_killer_1690s_name), + IWL_DEV_INFO(0x7E40, 0x1692, iwl_cfg_ma, iwl_ax411_killer_1690i_name), /* AX200 */ IWL_DEV_INFO(0x2723, IWL_CFG_ANY, iwl_ax200_cfg_cc, iwl_ax200_name), @@ -677,8 +677,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x7F70, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), /* MA with GF2 */ - IWL_DEV_INFO(0x7E40, 0x1671, iwl_cfg_ma_a0_gf_a0, iwl_ax211_killer_1675s_name), - IWL_DEV_INFO(0x7E40, 0x1672, iwl_cfg_ma_a0_gf_a0, iwl_ax211_killer_1675i_name), + IWL_DEV_INFO(0x7E40, 0x1671, iwl_cfg_ma, iwl_ax211_killer_1675s_name), + IWL_DEV_INFO(0x7E40, 0x1672, iwl_cfg_ma, iwl_ax211_killer_1675i_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_PU, IWL_CFG_ANY, @@ -927,55 +927,25 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { /* Ma */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, - IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_a0_hr_b0, iwl_ax201_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_a0_gf_a0, iwl_ax211_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_ma_a0_gf4_a0, iwl_ax211_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, - IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_a0_mr_a0, iwl_ax221_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_a0_fm_a0, iwl_ax231_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, + IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_HR2, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_b0_hr_b0, iwl_ax201_name), + iwl_cfg_ma, iwl_ax201_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, - IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_b0_gf_a0, iwl_ax211_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, + IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_CDB, - iwl_cfg_ma_b0_gf4_a0, iwl_ax211_name), + IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, + iwl_cfg_ma, iwl_ax211_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, + IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MR, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_b0_mr_a0, iwl_ax221_name), + iwl_cfg_ma, iwl_ax221_name), _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_MA, SILICON_B_STEP, + IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_b0_fm_a0, iwl_ax231_name), + iwl_cfg_ma, iwl_ax231_name), /* So with Hr */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, @@ -1138,7 +1108,7 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_MAC_TYPE_MA, IWL_CFG_ANY, IWL_CFG_RF_TYPE_MS, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_ma_a0_ms_a0, iwl_ax204_name), + iwl_cfg_ma, iwl_ax204_name), /* Sc */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, -- cgit v1.2.3 From 31aeae2446d50665b6ec51d564f5e7fe751d53d4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:18 +0300 Subject: wifi: iwlwifi: cfg: remove trailing dash from FW_PRE constants We have the trailing dash here, but that complicates all the code. Simplify this by removing the dashes, adding them to the *_MODULE_FIRMWARE macros, and adjusting the code using this accordingly. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130443.72240ca13b83.I1f4ed547f0964719ed98a3ef928080462d594491@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/1000.c | 10 ++-- drivers/net/wireless/intel/iwlwifi/cfg/2000.c | 18 +++---- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 26 ++++----- drivers/net/wireless/intel/iwlwifi/cfg/5000.c | 10 ++-- drivers/net/wireless/intel/iwlwifi/cfg/6000.c | 18 +++---- drivers/net/wireless/intel/iwlwifi/cfg/7000.c | 22 ++++---- drivers/net/wireless/intel/iwlwifi/cfg/8000.c | 10 ++-- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 10 ++-- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 60 ++++++++++----------- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 70 ++++++++++++------------- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 28 +++++----- drivers/net/wireless/intel/iwlwifi/fw/pnvm.h | 16 +----- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 12 ++--- 14 files changed, 150 insertions(+), 162 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c index 116defb15afb..f172ffd2a841 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/1000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/1000.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2018 - 2020 Intel Corporation + * Copyright(c) 2018 - 2020, 2023 Intel Corporation *****************************************************************************/ #include @@ -22,11 +22,11 @@ #define EEPROM_1000_TX_POWER_VERSION (4) #define EEPROM_1000_EEPROM_VERSION (0x15C) -#define IWL1000_FW_PRE "iwlwifi-1000-" -#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE __stringify(api) ".ucode" +#define IWL1000_FW_PRE "iwlwifi-1000" +#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE "-" __stringify(api) ".ucode" -#define IWL100_FW_PRE "iwlwifi-100-" -#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE __stringify(api) ".ucode" +#define IWL100_FW_PRE "iwlwifi-100" +#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl1000_base_params = { diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c index ab2038a3fbe2..6f3f26da0ad5 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/2000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/2000.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2018 - 2020 Intel Corporation + * Copyright(c) 2018 - 2020, 2023 Intel Corporation *****************************************************************************/ #include @@ -28,17 +28,17 @@ #define EEPROM_2000_EEPROM_VERSION (0x805) -#define IWL2030_FW_PRE "iwlwifi-2030-" -#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE __stringify(api) ".ucode" +#define IWL2030_FW_PRE "iwlwifi-2030" +#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE "-" __stringify(api) ".ucode" -#define IWL2000_FW_PRE "iwlwifi-2000-" -#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE __stringify(api) ".ucode" +#define IWL2000_FW_PRE "iwlwifi-2000" +#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE "-" __stringify(api) ".ucode" -#define IWL105_FW_PRE "iwlwifi-105-" -#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode" +#define IWL105_FW_PRE "iwlwifi-105" +#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE "-" __stringify(api) ".ucode" -#define IWL135_FW_PRE "iwlwifi-135-" -#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode" +#define IWL135_FW_PRE "iwlwifi-135" +#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl2000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_2K, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 8acbbed6eb1f..aa4320ca4c30 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -26,26 +26,26 @@ #define IWL_22000_SMEM_OFFSET 0x400000 #define IWL_22000_SMEM_LEN 0xD0000 -#define IWL_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0-" -#define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0-" -#define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0-" -#define IWL_QU_C_JF_B_FW_PRE "iwlwifi-Qu-c0-jf-b0-" -#define IWL_QUZ_A_HR_B_FW_PRE "iwlwifi-QuZ-a0-hr-b0-" -#define IWL_QUZ_A_JF_B_FW_PRE "iwlwifi-QuZ-a0-jf-b0-" -#define IWL_CC_A_FW_PRE "iwlwifi-cc-a0-" +#define IWL_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0" +#define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0" +#define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0" +#define IWL_QU_C_JF_B_FW_PRE "iwlwifi-Qu-c0-jf-b0" +#define IWL_QUZ_A_HR_B_FW_PRE "iwlwifi-QuZ-a0-hr-b0" +#define IWL_QUZ_A_JF_B_FW_PRE "iwlwifi-QuZ-a0-jf-b0" +#define IWL_CC_A_FW_PRE "iwlwifi-cc-a0" #define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ - IWL_QU_B_HR_B_FW_PRE __stringify(api) ".ucode" + IWL_QU_B_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_QUZ_A_HR_B_FW_PRE __stringify(api) ".ucode" + IWL_QUZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_QUZ_A_JF_B_MODULE_FIRMWARE(api) \ - IWL_QUZ_A_JF_B_FW_PRE __stringify(api) ".ucode" + IWL_QUZ_A_JF_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_QU_C_HR_B_MODULE_FIRMWARE(api) \ - IWL_QU_C_HR_B_FW_PRE __stringify(api) ".ucode" + IWL_QU_C_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \ - IWL_QU_B_JF_B_FW_PRE __stringify(api) ".ucode" + IWL_QU_B_JF_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_CC_A_MODULE_FIRMWARE(api) \ - IWL_CC_A_FW_PRE __stringify(api) ".ucode" + IWL_CC_A_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl_22000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c index e2e23d2bc1fe..de7ede59a994 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/5000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/5000.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2018 - 2020 Intel Corporation + * Copyright(c) 2018 - 2020, 2023 Intel Corporation *****************************************************************************/ #include @@ -24,11 +24,11 @@ #define EEPROM_5050_TX_POWER_VERSION (4) #define EEPROM_5050_EEPROM_VERSION (0x21E) -#define IWL5000_FW_PRE "iwlwifi-5000-" -#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE __stringify(api) ".ucode" +#define IWL5000_FW_PRE "iwlwifi-5000" +#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE "-" __stringify(api) ".ucode" -#define IWL5150_FW_PRE "iwlwifi-5150-" -#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE __stringify(api) ".ucode" +#define IWL5150_FW_PRE "iwlwifi-5150" +#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl5000_base_params = { .eeprom_size = IWLAGN_EEPROM_IMG_SIZE, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c index 20929e59c2f4..f013cf420569 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/6000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/6000.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2018 - 2020 Intel Corporation + * Copyright(c) 2018 - 2020, 2023 Intel Corporation *****************************************************************************/ #include @@ -37,17 +37,17 @@ #define EEPROM_6035_TX_POWER_VERSION (6) #define EEPROM_6035_EEPROM_VERSION (0x753) -#define IWL6000_FW_PRE "iwlwifi-6000-" -#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE __stringify(api) ".ucode" +#define IWL6000_FW_PRE "iwlwifi-6000" +#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE "-" __stringify(api) ".ucode" -#define IWL6050_FW_PRE "iwlwifi-6050-" -#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE __stringify(api) ".ucode" +#define IWL6050_FW_PRE "iwlwifi-6050" +#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE "-" __stringify(api) ".ucode" -#define IWL6005_FW_PRE "iwlwifi-6000g2a-" -#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE __stringify(api) ".ucode" +#define IWL6005_FW_PRE "iwlwifi-6000g2a" +#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE "-" __stringify(api) ".ucode" -#define IWL6030_FW_PRE "iwlwifi-6000g2b-" -#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE __stringify(api) ".ucode" +#define IWL6030_FW_PRE "iwlwifi-6000g2b" +#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl6000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_2K, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c index b24dc5523a52..4e2afdedf4c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2020, 2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 Intel Deutschland GmbH */ @@ -34,20 +34,20 @@ #define IWL3160_DCCM_LEN 0x10000 #define IWL7265_DCCM_LEN 0x17A00 -#define IWL7260_FW_PRE "iwlwifi-7260-" -#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode" +#define IWL7260_FW_PRE "iwlwifi-7260" +#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE "-" __stringify(api) ".ucode" -#define IWL3160_FW_PRE "iwlwifi-3160-" -#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE __stringify(api) ".ucode" +#define IWL3160_FW_PRE "iwlwifi-3160" +#define IWL3160_MODULE_FIRMWARE(api) IWL3160_FW_PRE "-" __stringify(api) ".ucode" -#define IWL3168_FW_PRE "iwlwifi-3168-" -#define IWL3168_MODULE_FIRMWARE(api) IWL3168_FW_PRE __stringify(api) ".ucode" +#define IWL3168_FW_PRE "iwlwifi-3168" +#define IWL3168_MODULE_FIRMWARE(api) IWL3168_FW_PRE "-" __stringify(api) ".ucode" -#define IWL7265_FW_PRE "iwlwifi-7265-" -#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode" +#define IWL7265_FW_PRE "iwlwifi-7265" +#define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE "-" __stringify(api) ".ucode" -#define IWL7265D_FW_PRE "iwlwifi-7265D-" -#define IWL7265D_MODULE_FIRMWARE(api) IWL7265D_FW_PRE __stringify(api) ".ucode" +#define IWL7265D_FW_PRE "iwlwifi-7265D" +#define IWL7265D_MODULE_FIRMWARE(api) IWL7265D_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl7000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_16K, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index a6454287d506..d09cf8d7dc01 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2014, 2018-2020 Intel Corporation + * Copyright (C) 2014, 2018-2020, 2023 Intel Corporation * Copyright (C) 2014-2015 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -27,13 +27,13 @@ #define IWL8260_SMEM_OFFSET 0x400000 #define IWL8260_SMEM_LEN 0x68000 -#define IWL8000_FW_PRE "iwlwifi-8000C-" +#define IWL8000_FW_PRE "iwlwifi-8000C" #define IWL8000_MODULE_FIRMWARE(api) \ - IWL8000_FW_PRE __stringify(api) ".ucode" + IWL8000_FW_PRE "-" __stringify(api) ".ucode" -#define IWL8265_FW_PRE "iwlwifi-8265-" +#define IWL8265_FW_PRE "iwlwifi-8265" #define IWL8265_MODULE_FIRMWARE(api) \ - IWL8265_FW_PRE __stringify(api) ".ucode" + IWL8265_FW_PRE "-" __stringify(api) ".ucode" #define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 7a7ca06d46c1..0130d9a9b78b 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2021, 2023 Intel Corporation */ #include #include @@ -26,12 +26,12 @@ #define IWL9000_SMEM_OFFSET 0x400000 #define IWL9000_SMEM_LEN 0x68000 -#define IWL9000_FW_PRE "iwlwifi-9000-pu-b0-jf-b0-" -#define IWL9260_FW_PRE "iwlwifi-9260-th-b0-jf-b0-" +#define IWL9000_FW_PRE "iwlwifi-9000-pu-b0-jf-b0" +#define IWL9260_FW_PRE "iwlwifi-9260-th-b0-jf-b0" #define IWL9000_MODULE_FIRMWARE(api) \ - IWL9000_FW_PRE __stringify(api) ".ucode" + IWL9000_FW_PRE "-" __stringify(api) ".ucode" #define IWL9260_MODULE_FIRMWARE(api) \ - IWL9260_FW_PRE __stringify(api) ".ucode" + IWL9260_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl9000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index a484cae3f784..1821e569e9b3 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -26,51 +26,51 @@ #define IWL_AX210_SMEM_OFFSET 0x400000 #define IWL_AX210_SMEM_LEN 0xD0000 -#define IWL_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0-" -#define IWL_SO_A_HR_B_FW_PRE "iwlwifi-so-a0-hr-b0-" -#define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0-" -#define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0-" -#define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0-" -#define IWL_SO_A_MR_A_FW_PRE "iwlwifi-so-a0-mr-a0-" -#define IWL_MA_A_HR_B_FW_PRE "iwlwifi-ma-a0-hr-b0-" -#define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0-" -#define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0-" -#define IWL_MA_A_MR_A_FW_PRE "iwlwifi-ma-a0-mr-a0-" -#define IWL_MA_A_FM_A_FW_PRE "iwlwifi-ma-a0-fm-a0-" -#define IWL_MA_B_HR_B_FW_PRE "iwlwifi-ma-b0-hr-b0-" -#define IWL_MA_B_GF_A_FW_PRE "iwlwifi-ma-b0-gf-a0-" -#define IWL_MA_B_GF4_A_FW_PRE "iwlwifi-ma-b0-gf4-a0-" -#define IWL_MA_B_MR_A_FW_PRE "iwlwifi-ma-b0-mr-a0-" -#define IWL_MA_B_FM_A_FW_PRE "iwlwifi-ma-b0-fm-a0-" +#define IWL_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0" +#define IWL_SO_A_HR_B_FW_PRE "iwlwifi-so-a0-hr-b0" +#define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0" +#define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0" +#define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0" +#define IWL_SO_A_MR_A_FW_PRE "iwlwifi-so-a0-mr-a0" +#define IWL_MA_A_HR_B_FW_PRE "iwlwifi-ma-a0-hr-b0" +#define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0" +#define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0" +#define IWL_MA_A_MR_A_FW_PRE "iwlwifi-ma-a0-mr-a0" +#define IWL_MA_A_FM_A_FW_PRE "iwlwifi-ma-a0-fm-a0" +#define IWL_MA_B_HR_B_FW_PRE "iwlwifi-ma-b0-hr-b0" +#define IWL_MA_B_GF_A_FW_PRE "iwlwifi-ma-b0-gf-a0" +#define IWL_MA_B_GF4_A_FW_PRE "iwlwifi-ma-b0-gf4-a0" +#define IWL_MA_B_MR_A_FW_PRE "iwlwifi-ma-b0-mr-a0" +#define IWL_MA_B_FM_A_FW_PRE "iwlwifi-ma-b0-fm-a0" #define IWL_SO_A_JF_B_MODULE_FIRMWARE(api) \ - IWL_SO_A_JF_B_FW_PRE __stringify(api) ".ucode" + IWL_SO_A_JF_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SO_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_SO_A_HR_B_FW_PRE __stringify(api) ".ucode" + IWL_SO_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SO_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_SO_A_GF_A_FW_PRE __stringify(api) ".ucode" + IWL_SO_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_TY_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_TY_A_GF_A_FW_PRE __stringify(api) ".ucode" + IWL_TY_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_HR_B_FW_PRE __stringify(api) ".ucode" + IWL_MA_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_GF_A_FW_PRE __stringify(api) ".ucode" + IWL_MA_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_GF4_A_FW_PRE __stringify(api) ".ucode" + IWL_MA_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_MR_A_FW_PRE __stringify(api) ".ucode" + IWL_MA_A_MR_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_FM_A_FW_PRE __stringify(api) ".ucode" + IWL_MA_A_FM_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_HR_B_FW_PRE __stringify(api) ".ucode" + IWL_MA_B_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_GF_A_FW_PRE __stringify(api) ".ucode" + IWL_MA_B_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_GF4_A_FW_PRE __stringify(api) ".ucode" + IWL_MA_B_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_MR_A_FW_PRE __stringify(api) ".ucode" + IWL_MA_B_MR_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_FM_A_FW_PRE __stringify(api) ".ucode" + IWL_MA_B_FM_A_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl_ax210_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index fe6166d364cf..4f0bc6924111 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -26,59 +26,59 @@ #define IWL_BZ_SMEM_OFFSET 0x400000 #define IWL_BZ_SMEM_LEN 0xD0000 -#define IWL_BZ_A_HR_A_FW_PRE "iwlwifi-bz-a0-hr-b0-" -#define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0-" -#define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0-" -#define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0-" -#define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-" -#define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-" -#define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0-" -#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0-" -#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0-" -#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0-" -#define IWL_BZ_B_GF_A_FW_PRE "iwlwifi-bz-b0-gf-a0-" -#define IWL_BZ_B_GF4_A_FW_PRE "iwlwifi-bz-b0-gf4-a0-" -#define IWL_BZ_B_FM_B_FW_PRE "iwlwifi-bz-b0-fm-b0-" -#define IWL_BZ_B_FM4_B_FW_PRE "iwlwifi-bz-b0-fm4-b0-" -#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-" -#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0-" -#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0-" -#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" +#define IWL_BZ_A_HR_A_FW_PRE "iwlwifi-bz-a0-hr-b0" +#define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0" +#define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0" +#define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0" +#define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0" +#define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0" +#define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0" +#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" +#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" +#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" +#define IWL_BZ_B_GF_A_FW_PRE "iwlwifi-bz-b0-gf-a0" +#define IWL_BZ_B_GF4_A_FW_PRE "iwlwifi-bz-b0-gf4-a0" +#define IWL_BZ_B_FM_B_FW_PRE "iwlwifi-bz-b0-fm-b0" +#define IWL_BZ_B_FM4_B_FW_PRE "iwlwifi-bz-b0-fm4-b0" +#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0" +#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" +#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" +#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0" #define IWL_BZ_A_HR_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_HR_A_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_HR_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_BZ_A_HR_B_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_GF_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_GF_A_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_GF4_A_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_MR_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_MR_A_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_MR_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM_A_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_FM_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM4_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM4_A_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_FM4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM_B_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM_B_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_FM_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM_C_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM_C_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM4_B_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM4_B_FW_PRE __stringify(api) ".ucode" + IWL_BZ_A_FM4_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_B_GF_A_MODULE_FIRMWARE(api) \ - IWL_BZ_B_GF_A_FW_PRE __stringify(api) ".ucode" + IWL_BZ_B_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_B_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BZ_B_GF4_A_FW_PRE __stringify(api) ".ucode" + IWL_BZ_B_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_B_FM_B_MODULE_FIRMWARE(api) \ - IWL_BZ_B_FM_B_FW_PRE __stringify(api) ".ucode" + IWL_BZ_B_FM_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_B_FM4_B_MODULE_FIRMWARE(api) \ - IWL_BZ_B_FM4_B_FW_PRE __stringify(api) ".ucode" + IWL_BZ_B_FM4_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ - IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode" + IWL_GL_A_FM_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \ - IWL_GL_B_FM_B_FW_PRE __stringify(api) ".ucode" + IWL_GL_B_FM_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_GL_C_FM_C_MODULE_FIRMWARE(api) \ - IWL_GL_C_FM_C_FW_PRE __stringify(api) ".ucode" + IWL_GL_C_FM_C_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl_bz_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 679cb53ae18a..6e487a83ee24 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -26,28 +26,28 @@ #define IWL_SC_SMEM_OFFSET 0x400000 #define IWL_SC_SMEM_LEN 0xD0000 -#define IWL_SC_A_FM_B_FW_PRE "iwlwifi-sc-a0-fm-b0-" -#define IWL_SC_A_FM_C_FW_PRE "iwlwifi-sc-a0-fm-c0-" -#define IWL_SC_A_HR_A_FW_PRE "iwlwifi-sc-a0-hr-b0-" -#define IWL_SC_A_HR_B_FW_PRE "iwlwifi-sc-a0-hr-b0-" -#define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0-" -#define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0-" -#define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0-" +#define IWL_SC_A_FM_B_FW_PRE "iwlwifi-sc-a0-fm-b0" +#define IWL_SC_A_FM_C_FW_PRE "iwlwifi-sc-a0-fm-c0" +#define IWL_SC_A_HR_A_FW_PRE "iwlwifi-sc-a0-hr-b0" +#define IWL_SC_A_HR_B_FW_PRE "iwlwifi-sc-a0-hr-b0" +#define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0" +#define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0" +#define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0" #define IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_FM_B_FW_PRE __stringify(api) ".ucode" + IWL_SC_A_FM_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_FM_C_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_FM_C_FW_PRE __stringify(api) ".ucode" + IWL_SC_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_HR_A_FW_PRE __stringify(api) ".ucode" + IWL_SC_A_HR_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_HR_B_FW_PRE __stringify(api) ".ucode" + IWL_SC_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_GF_A_FW_PRE __stringify(api) ".ucode" + IWL_SC_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_GF4_A_FW_PRE __stringify(api) ".ucode" + IWL_SC_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_WH_A_FW_PRE __stringify(api) ".ucode" + IWL_SC_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl_sc_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index 32fba08b7db1..1bac3466154c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -21,21 +21,9 @@ void iwl_pnvm_get_fs_name(struct iwl_trans *trans, u8 *pnvm_name, size_t max_len) { char _fw_name_pre[FW_NAME_PRE_BUFSIZE]; - const char *fw_name_pre; - int pre_len; - fw_name_pre = iwl_drv_get_fwname_pre(trans, _fw_name_pre); - - /* - * The prefix unfortunately includes a hyphen at the end, so - * don't add the dot here... - */ - snprintf(pnvm_name, max_len, "%spnvm", fw_name_pre); - - /* ...but replace the hyphen with the dot here. */ - pre_len = strlen(fw_name_pre); - if (pre_len < max_len && pre_len > 0) - pnvm_name[pre_len - 1] = '.'; + snprintf(pnvm_name, max_len, "%s.pnvm", + iwl_drv_get_fwname_pre(trans, _fw_name_pre)); } #endif /* __IWL_PNVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 4cc0285f287e..1c0cfbb6c427 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -309,7 +309,7 @@ struct iwl_fw_mon_regs { * @name: Official name of the device * @fw_name_pre: Firmware filename prefix. The api version and extension * (.ucode) will be added to filename before loading from disk. The - * filename is constructed as fw_name_pre.ucode. + * filename is constructed as -.ucode. * @fw_name_mac: MAC name for this config, the remaining pieces of the * name will be generated dynamically * @ucode_api_max: Highest version of uCode API supported by driver. diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index a7cf73d67371..3d87d26845e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -174,7 +174,7 @@ const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) return trans->cfg->fw_name_pre; if (WARN_ON(!trans->cfg->fw_name_mac)) - return "unconfigured-"; + return "unconfigured"; mac_step = iwl_drv_get_step(trans->hw_rev_step); @@ -199,7 +199,7 @@ const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) rf = "wh"; break; default: - return "unknown-rf-"; + return "unknown-rf"; } cdb = CSR_HW_RFID_IS_CDB(trans->hw_rf_id) ? "4" : ""; @@ -244,12 +244,12 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) IWL_ERR(drv, "no suitable firmware found!\n"); if (cfg->ucode_api_min == cfg->ucode_api_max) { - IWL_ERR(drv, "%s%d is required\n", fw_name_pre, + IWL_ERR(drv, "%s-%d is required\n", fw_name_pre, cfg->ucode_api_max); } else { - IWL_ERR(drv, "minimum version required: %s%d\n", + IWL_ERR(drv, "minimum version required: %s-%d\n", fw_name_pre, cfg->ucode_api_min); - IWL_ERR(drv, "maximum version supported: %s%d\n", + IWL_ERR(drv, "maximum version supported: %s-%d\n", fw_name_pre, cfg->ucode_api_max); } @@ -258,7 +258,7 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) return -ENOENT; } - snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s%d.ucode", + snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s-%d.ucode", fw_name_pre, drv->fw_index); IWL_DEBUG_FW_INFO(drv, "attempting to load firmware '%s'\n", -- cgit v1.2.3 From 399762de769c4ec7d82220feb83de9bca30e5ef0 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 21 Jun 2023 13:12:19 +0300 Subject: wifi: iwlwifi: bump FW API to 83 for AX/BZ/SC devices Start supporting API version 83 for new devices. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130444.267a136ea57f.Iaef9f04b9655c5c1b8bdee3b89cc3361ab621bcf@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 1821e569e9b3..73736f7372d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_AX210_UCODE_API_MAX 82 +#define IWL_AX210_UCODE_API_MAX 83 /* Lowest firmware API version supported */ #define IWL_AX210_UCODE_API_MIN 59 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 4f0bc6924111..2feb47af8dda 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 82 +#define IWL_BZ_UCODE_API_MAX 83 /* Lowest firmware API version supported */ #define IWL_BZ_UCODE_API_MIN 80 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 6e487a83ee24..ad283fd22e2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 82 +#define IWL_SC_UCODE_API_MAX 83 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 82 -- cgit v1.2.3 From f4daceae4087bbb3e9a56044b44601d520d009d2 Mon Sep 17 00:00:00 2001 From: Yi Kuo Date: Wed, 21 Jun 2023 13:12:20 +0300 Subject: wifi: iwlwifi: pcie: add device id 51F1 for killer 1675 Intel Killer AX1675i/s with device id 51f1 would show "No config found for PCI dev 51f1/1672" in dmesg and refuse to work. Add the new device id 51F1 for 1675i/s to fix the issue. Signed-off-by: Yi Kuo Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130444.ee224675380b.I921c905e21e8d041ad808def8f454f27b5ebcd8b@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 41dbb9da8203..d3e0ea6aeb41 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -667,6 +667,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(0x2726, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), IWL_DEV_INFO(0x51F0, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x51F0, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), + IWL_DEV_INFO(0x51F1, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), + IWL_DEV_INFO(0x51F1, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), IWL_DEV_INFO(0x54F0, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), IWL_DEV_INFO(0x54F0, 0x1672, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675i_name), IWL_DEV_INFO(0x7A70, 0x1671, iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_killer_1675s_name), -- cgit v1.2.3 From a701177bd4bc37b9775da8daf255864da3fecaf9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 21 Jun 2023 13:12:21 +0300 Subject: wifi: iwlwifi: cfg: clean up Bz module firmware lines Remove module firmware lines for images that don't exist as well as some unused macros, and add gl-a-fm-a that (still) exists. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130444.b399b0072d72.Ie7ca1b3dcdebc929ce96a739e0d557fac2c8aeeb@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 2feb47af8dda..c15dcd9bc323 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -26,35 +26,24 @@ #define IWL_BZ_SMEM_OFFSET 0x400000 #define IWL_BZ_SMEM_LEN 0xD0000 -#define IWL_BZ_A_HR_A_FW_PRE "iwlwifi-bz-a0-hr-b0" #define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0" #define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0" #define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0" -#define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0" #define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0" #define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0" #define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" #define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" #define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" -#define IWL_BZ_B_GF_A_FW_PRE "iwlwifi-bz-b0-gf-a0" -#define IWL_BZ_B_GF4_A_FW_PRE "iwlwifi-bz-b0-gf4-a0" -#define IWL_BZ_B_FM_B_FW_PRE "iwlwifi-bz-b0-fm-b0" -#define IWL_BZ_B_FM4_B_FW_PRE "iwlwifi-bz-b0-fm4-b0" #define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0" #define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" #define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" -#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0" -#define IWL_BZ_A_HR_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_HR_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \ IWL_BZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_GF_A_MODULE_FIRMWARE(api) \ IWL_BZ_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_GF4_A_MODULE_FIRMWARE(api) \ IWL_BZ_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_BZ_A_MR_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_MR_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM_A_MODULE_FIRMWARE(api) \ IWL_BZ_A_FM_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM4_A_MODULE_FIRMWARE(api) \ @@ -65,14 +54,6 @@ IWL_BZ_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM4_B_MODULE_FIRMWARE(api) \ IWL_BZ_A_FM4_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_BZ_B_GF_A_MODULE_FIRMWARE(api) \ - IWL_BZ_B_GF_A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_BZ_B_GF4_A_MODULE_FIRMWARE(api) \ - IWL_BZ_B_GF4_A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_BZ_B_FM_B_MODULE_FIRMWARE(api) \ - IWL_BZ_B_FM_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_BZ_B_FM4_B_MODULE_FIRMWARE(api) \ - IWL_BZ_B_FM4_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ IWL_GL_A_FM_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \ @@ -216,16 +197,15 @@ const struct iwl_cfg iwl_cfg_gl = { }; -MODULE_FIRMWARE(IWL_BZ_A_HR_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_MR_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); + +MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -- cgit v1.2.3 From fd006d60e83389f806d8a215c78ae608b9070bbb Mon Sep 17 00:00:00 2001 From: Mukesh Sisodiya Date: Wed, 21 Jun 2023 13:12:22 +0300 Subject: wifi: iwlwifi: remove support of A0 version of FM RF Remove the support for A0 step of latest wifi-7 FM RF as it is no longer supported. Signed-off-by: Mukesh Sisodiya Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621130444.269d55ffbc8e.I4740f32c3d95d4474a82cc153891c92b9bc465db@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 8 ------- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 30 +------------------------ drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 - drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 5 ----- 4 files changed, 1 insertion(+), 43 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 73736f7372d2..8d5f9dce71d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -36,12 +36,10 @@ #define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0" #define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0" #define IWL_MA_A_MR_A_FW_PRE "iwlwifi-ma-a0-mr-a0" -#define IWL_MA_A_FM_A_FW_PRE "iwlwifi-ma-a0-fm-a0" #define IWL_MA_B_HR_B_FW_PRE "iwlwifi-ma-b0-hr-b0" #define IWL_MA_B_GF_A_FW_PRE "iwlwifi-ma-b0-gf-a0" #define IWL_MA_B_GF4_A_FW_PRE "iwlwifi-ma-b0-gf4-a0" #define IWL_MA_B_MR_A_FW_PRE "iwlwifi-ma-b0-mr-a0" -#define IWL_MA_B_FM_A_FW_PRE "iwlwifi-ma-b0-fm-a0" #define IWL_SO_A_JF_B_MODULE_FIRMWARE(api) \ IWL_SO_A_JF_B_FW_PRE "-" __stringify(api) ".ucode" @@ -59,8 +57,6 @@ IWL_MA_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(api) \ IWL_MA_A_MR_A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_FM_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(api) \ IWL_MA_B_HR_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(api) \ @@ -69,8 +65,6 @@ IWL_MA_B_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(api) \ IWL_MA_B_MR_A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_FM_A_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl_ax210_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -301,9 +295,7 @@ MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_A_MR_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_A_FM_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_MA_B_FM_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index c15dcd9bc323..b9893b22e41d 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -29,12 +29,9 @@ #define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0" #define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0" #define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0" -#define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0" -#define IWL_BZ_A_FM4_A_FW_PRE "iwlwifi-bz-a0-fm4-a0" #define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" #define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" #define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" -#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0" #define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" #define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" @@ -44,18 +41,12 @@ IWL_BZ_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_GF4_A_MODULE_FIRMWARE(api) \ IWL_BZ_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_BZ_A_FM_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM_A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_BZ_A_FM4_A_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM_B_MODULE_FIRMWARE(api) \ IWL_BZ_A_FM_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM_C_MODULE_FIRMWARE(api) \ - IWL_BZ_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" + IWL_BZ_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" #define IWL_BZ_A_FM4_B_MODULE_FIRMWARE(api) \ IWL_BZ_A_FM4_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ - IWL_GL_A_FM_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_GL_B_FM_B_MODULE_FIRMWARE(api) \ IWL_GL_B_FM_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_GL_C_FM_C_MODULE_FIRMWARE(api) \ @@ -73,13 +64,6 @@ static const struct iwl_base_params iwl_bz_base_params = { .pcie_l1_allowed = true, }; -static const struct iwl_ht_params iwl_gl_a_ht_params = { - .stbc = false, /* we explicitly disable STBC for GL step A */ - .ldpc = true, - .ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | - BIT(NL80211_BAND_6GHZ), -}; - #define IWL_DEVICE_BZ_COMMON \ .ucode_api_max = IWL_BZ_UCODE_API_MAX, \ .ucode_api_min = IWL_BZ_UCODE_API_MIN, \ @@ -180,14 +164,6 @@ const struct iwl_cfg iwl_cfg_bz = { .num_rbds = IWL_NUM_RBDS_BZ_HE, }; -const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = { - .fw_name_pre = IWL_GL_A_FM_A_FW_PRE, - .uhb_supported = true, - IWL_DEVICE_GL_A, - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, -}; - const struct iwl_cfg iwl_cfg_gl = { .fw_name_mac = "gl", .uhb_supported = true, @@ -200,12 +176,8 @@ const struct iwl_cfg iwl_cfg_gl = { MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_BZ_A_FM4_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); - -MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 1c0cfbb6c427..742096c5a36a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -640,7 +640,6 @@ extern const struct iwl_cfg iwl_cfg_so_a0_ms_a0; extern const struct iwl_cfg iwl_cfg_quz_a0_hr_b0; extern const struct iwl_cfg iwl_cfg_bz; -extern const struct iwl_cfg iwl_cfg_gl_a0_fm_a0; extern const struct iwl_cfg iwl_cfg_gl; extern const struct iwl_cfg iwl_cfg_sc; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index d3e0ea6aeb41..f46cafb538db 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1008,11 +1008,6 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_gl, iwl_bz_name), - _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, - IWL_CFG_MAC_TYPE_GL, SILICON_A_STEP, - IWL_CFG_RF_TYPE_FM, IWL_CFG_ANY, SILICON_A_STEP, - IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwl_cfg_gl_a0_fm_a0, iwl_bz_name), /* SoF with JF2 */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, -- cgit v1.2.3 From f52a0b408ed144afa42b45f078a28542e711551b Mon Sep 17 00:00:00 2001 From: Yedidya Benshimol Date: Wed, 21 Jun 2023 14:44:36 +0300 Subject: wifi: mac80211: mark keys as uploaded when added by the driver When the driver has some form of GTK rekeying offload, e.g. during WoWLAN, mac80211 can assume that keys that the driver adds for that are already present in the hardware acceleration. Mark them accordingly. Signed-off-by: Yedidya Benshimol Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621144414.bc78c7ff2a3d.I5e313d69e2b6a7a4766ef82d0faa122dd4c1c46d@changeid Signed-off-by: Johannes Berg --- net/mac80211/key.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index e8f6c1e5eabf..21cf5a208910 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -6,7 +6,7 @@ * Copyright 2007-2008 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright 2018-2020, 2022 Intel Corporation + * Copyright 2018-2020, 2022-2023 Intel Corporation */ #include @@ -510,8 +510,12 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ret = ieee80211_key_enable_hw_accel(new); } } else { - if (!new->local->wowlan) + if (!new->local->wowlan) { ret = ieee80211_key_enable_hw_accel(new); + } else { + assert_key_lock(new->local); + new->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + } } if (ret) -- cgit v1.2.3 From 60555ea4085a956adaa58bcd24f418a631b575a2 Mon Sep 17 00:00:00 2001 From: Yedidya Benshimol Date: Wed, 21 Jun 2023 14:49:50 +0300 Subject: wifi: iwlwifi: mvm: Refactor security key update after D3 In the D3 resume flow, use two different iterating functions to go over the old keys and update the new ones Signed-off-by: Yedidya Benshimol Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621144844.a2442844c224.I598ed742c7aaa5414702f03f694f2dc0874bc077@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 82 +++++++++++++++-------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 6d1007f24b4a..d3eb13f3372b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -1779,18 +1779,17 @@ struct iwl_mvm_d3_gtk_iter_data { struct iwl_wowlan_status_data *status; void *last_gtk; u32 cipher; - bool find_phase, unhandled_cipher; + bool unhandled_cipher; int num_keys; }; -static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - void *_data) +static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) { struct iwl_mvm_d3_gtk_iter_data *data = _data; - struct iwl_wowlan_status_data *status = data->status; if (data->unhandled_cipher) return; @@ -1805,51 +1804,56 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_TKIP: /* we support these */ + data->last_gtk = key; + data->cipher = key->cipher; break; default: - /* everything else (even CMAC for MFP) - disconnect from AP */ + /* everything else - disconnect from AP */ data->unhandled_cipher = true; return; } data->num_keys++; +} - /* - * pairwise key - update sequence counters only; - * note that this assumes no TDLS sessions are active - */ - if (sta) { - if (data->find_phase) - return; +static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *_data) +{ + struct iwl_mvm_d3_gtk_iter_data *data = _data; + struct iwl_wowlan_status_data *status = data->status; - switch (key->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: + if (data->unhandled_cipher) + return; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + /* ignore WEP completely, nothing to do */ + return; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + if (sta) { atomic64_set(&key->tx_pn, status->ptk.aes.tx_pn); iwl_mvm_set_aes_ptk_rx_seq(data->mvm, status, sta, key); - break; - case WLAN_CIPHER_SUITE_TKIP: + return; + } + fallthrough; + case WLAN_CIPHER_SUITE_TKIP: + if (sta) { atomic64_set(&key->tx_pn, status->ptk.tkip.tx_pn); iwl_mvm_set_key_rx_seq_tids(key, status->ptk.tkip.seq); - break; + return; } + if (data->status->num_of_gtk_rekeys) + ieee80211_remove_key(key); - /* that's it for this key */ - return; + if (data->last_gtk == key) + iwl_mvm_set_key_rx_seq(key, data->status, false); } - - if (data->find_phase) { - data->last_gtk = key; - data->cipher = key->cipher; - return; - } - - if (data->status->num_of_gtk_rekeys) - ieee80211_remove_key(key); - - if (data->last_gtk == key) - iwl_mvm_set_key_rx_seq(key, data->status, false); } static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, @@ -1872,9 +1876,8 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, return false; /* find last GTK that we used initially, if any */ - gtkdata.find_phase = true; ieee80211_iter_keys(mvm->hw, vif, - iwl_mvm_d3_update_keys, >kdata); + iwl_mvm_d3_find_last_keys, >kdata); /* not trying to keep connections with MFP/unhandled ciphers */ if (gtkdata.unhandled_cipher) return false; @@ -1887,7 +1890,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, * invalidate all other GTKs that might still exist and update * the one that we used */ - gtkdata.find_phase = false; ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_d3_update_keys, >kdata); -- cgit v1.2.3 From fa4e48fb3ee5757d8e0ed1c5079e472687e2c667 Mon Sep 17 00:00:00 2001 From: Yedidya Benshimol Date: Wed, 21 Jun 2023 14:49:51 +0300 Subject: wifi: iwlwifi: mvm: update two most recent GTKs on D3 resume flow When resuming from D3 the two most recent GTKs are passed from the FW with wowlan_info_notif. Both keys should be updated as they both might be needed upon FW restart and they both should be removed upon station removal. Signed-off-by: Yedidya Benshimol Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621144844.3ea3a9f52ec2.I7cedfa2bb0eafb83e7c77363673560acf05bff74@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 196 ++++++++++++++++------------ 1 file changed, 115 insertions(+), 81 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d3eb13f3372b..1d900342224f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1398,7 +1398,8 @@ struct iwl_wowlan_status_data { u8 key[WOWLAN_KEY_MAX_SIZE]; u8 len; u8 flags; - } gtk; + u8 id; + } gtk[WOWLAN_GTK_KEYS_NUM]; struct { /* @@ -1758,7 +1759,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, s8 new_key_id = -1; if (status->num_of_gtk_rekeys) - new_key_id = status->gtk.flags & + new_key_id = status->gtk[0].flags & IWL_WOWLAN_GTK_IDX_MASK; /* Don't install a new key's value to an old key */ @@ -1777,8 +1778,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm *mvm; struct iwl_wowlan_status_data *status; - void *last_gtk; - u32 cipher; + u32 gtk_cipher; bool unhandled_cipher; int num_keys; }; @@ -1804,8 +1804,7 @@ static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, case WLAN_CIPHER_SUITE_GCMP_256: case WLAN_CIPHER_SUITE_TKIP: /* we support these */ - data->last_gtk = key; - data->cipher = key->cipher; + data->gtk_cipher = key->cipher; break; default: /* everything else - disconnect from AP */ @@ -1824,6 +1823,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, { struct iwl_mvm_d3_gtk_iter_data *data = _data; struct iwl_wowlan_status_data *status = data->status; + s8 keyidx; if (data->unhandled_cipher) return; @@ -1848,14 +1848,76 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, iwl_mvm_set_key_rx_seq_tids(key, status->ptk.tkip.seq); return; } - if (data->status->num_of_gtk_rekeys) + keyidx = key->keyidx; + /* The current key is always sent by the FW, even if it wasn't + * rekeyed during D3. + * We remove an existing key if it has the same index as + * a new key + */ + if (status->num_of_gtk_rekeys && + ((status->gtk[0].len && keyidx == status->gtk[0].id) || + (status->gtk[1].len && keyidx == status->gtk[1].id))) { ieee80211_remove_key(key); - - if (data->last_gtk == key) + } else { iwl_mvm_set_key_rx_seq(key, data->status, false); + } } } +static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, + struct ieee80211_vif *vif, + struct iwl_mvm *mvm, u32 gtk_cipher) +{ + int i; + struct ieee80211_key_conf *key; + struct { + struct ieee80211_key_conf conf; + u8 key[32]; + } conf = { + .conf.cipher = gtk_cipher, + }; + + BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); + BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); + BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256); + BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP); + BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk[0].key)); + + switch (gtk_cipher) { + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + conf.conf.keylen = WLAN_KEY_LEN_CCMP; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; + break; + case WLAN_CIPHER_SUITE_TKIP: + conf.conf.keylen = WLAN_KEY_LEN_TKIP; + break; + default: + WARN_ON(1); + } + + for (i = 0; i < ARRAY_SIZE(status->gtk); i++) { + if (!status->gtk[i].len) + continue; + + conf.conf.keyidx = status->gtk[i].id; + IWL_DEBUG_WOWLAN(mvm, + "Received from FW GTK cipher %d, key index %d\n", + conf.conf.cipher, conf.conf.keyidx); + memcpy(conf.conf.key, status->gtk[i].key, + sizeof(status->gtk[i].key)); + + key = ieee80211_gtk_rekey_add(vif, &conf.conf); + if (IS_ERR(key)) + return false; + iwl_mvm_set_key_rx_seq_idx(key, status, i); + } + + return true; +} + static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_wowlan_status_data *status) @@ -1883,8 +1945,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, return false; if (!gtkdata.num_keys) goto out; - if (!gtkdata.last_gtk) - return false; /* * invalidate all other GTKs that might still exist and update @@ -1893,52 +1953,14 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_d3_update_keys, >kdata); - IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n", - status->num_of_gtk_rekeys); if (status->num_of_gtk_rekeys) { - struct ieee80211_key_conf *key; - struct { - struct ieee80211_key_conf conf; - u8 key[32]; - } conf = { - .conf.cipher = gtkdata.cipher, - .conf.keyidx = - status->gtk.flags & IWL_WOWLAN_GTK_IDX_MASK, - }; - __be64 replay_ctr; - - IWL_DEBUG_WOWLAN(mvm, - "Received from FW GTK cipher %d, key index %d\n", - conf.conf.cipher, conf.conf.keyidx); + __be64 replay_ctr = cpu_to_be64(status->replay_ctr); - BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP); - BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk.key)); + IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n", + status->num_of_gtk_rekeys); - memcpy(conf.conf.key, status->gtk.key, sizeof(status->gtk.key)); - - switch (gtkdata.cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - conf.conf.keylen = WLAN_KEY_LEN_CCMP; - break; - case WLAN_CIPHER_SUITE_GCMP_256: - conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; - break; - case WLAN_CIPHER_SUITE_TKIP: - conf.conf.keylen = WLAN_KEY_LEN_TKIP; - break; - } - - key = ieee80211_gtk_rekey_add(vif, &conf.conf); - if (IS_ERR(key)) + if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher)) return false; - iwl_mvm_set_key_rx_seq(key, status, true); - - replay_ctr = cpu_to_be64(status->replay_ctr); - ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, (void *)&replay_ctr, GFP_KERNEL); } @@ -1957,40 +1979,52 @@ out: static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status, struct iwl_wowlan_gtk_status_v2 *data) { - BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key)); + BUILD_BUG_ON(sizeof(status->gtk[0].key) < sizeof(data->key)); BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY + sizeof(data->tkip_mic_key) > - sizeof(status->gtk.key)); + sizeof(status->gtk[0].key)); - status->gtk.len = data->key_len; - status->gtk.flags = data->key_flags; + status->gtk[0].len = data->key_len; + status->gtk[0].flags = data->key_flags; - memcpy(status->gtk.key, data->key, sizeof(data->key)); + memcpy(status->gtk[0].key, data->key, sizeof(data->key)); /* if it's as long as the TKIP encryption key, copy MIC key */ - if (status->gtk.len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) - memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + if (status->gtk[0].len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, data->tkip_mic_key, sizeof(data->tkip_mic_key)); } static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, struct iwl_wowlan_gtk_status_v3 *data) { - /* The parts we need are identical in v2 and v3 */ -#define CHECK(_f) do { \ - BUILD_BUG_ON(offsetof(struct iwl_wowlan_gtk_status_v2, _f) != \ - offsetof(struct iwl_wowlan_gtk_status_v3, _f)); \ - BUILD_BUG_ON(offsetofend(struct iwl_wowlan_gtk_status_v2, _f) !=\ - offsetofend(struct iwl_wowlan_gtk_status_v3, _f)); \ -} while (0) + int data_idx, status_idx = 0; - CHECK(key); - CHECK(key_len); - CHECK(key_flags); - CHECK(tkip_mic_key); -#undef CHECK + BUILD_BUG_ON(sizeof(status->gtk[0].key) < sizeof(data[0].key)); + BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY + + sizeof(data[0].tkip_mic_key) > + sizeof(status->gtk[0].key)); + BUILD_BUG_ON(ARRAY_SIZE(status->gtk) < WOWLAN_GTK_KEYS_NUM); + for (data_idx = 0; data_idx < ARRAY_SIZE(status->gtk); data_idx++) { + if (!(data[data_idx].key_len)) + continue; + status->gtk[status_idx].len = data[data_idx].key_len; + status->gtk[status_idx].flags = data[data_idx].key_flags; + status->gtk[status_idx].id = status->gtk[status_idx].flags & + IWL_WOWLAN_GTK_IDX_MASK; + + memcpy(status->gtk[status_idx].key, data[data_idx].key, + sizeof(data[data_idx].key)); - iwl_mvm_convert_gtk_v2(status, (void *)data); + /* if it's as long as the TKIP encryption key, copy MIC key */ + if (status->gtk[status_idx].len == + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(status->gtk[status_idx].key + + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + data[data_idx].tkip_mic_key, + sizeof(data[data_idx].tkip_mic_key)); + status_idx++; + } } static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, @@ -2033,7 +2067,7 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, } iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc); - iwl_mvm_convert_gtk_v3(status, &data->gtk[0]); + iwl_mvm_convert_gtk_v3(status, data->gtk); iwl_mvm_convert_igtk(status, &data->igtk[0]); status->replay_ctr = le64_to_cpu(data->replay_ctr); @@ -2156,29 +2190,29 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) goto out_free_resp; BUILD_BUG_ON(sizeof(v6->gtk.decrypt_key) > - sizeof(status->gtk.key)); + sizeof(status->gtk[0].key)); BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY + sizeof(v6->gtk.tkip_mic_key) > - sizeof(status->gtk.key)); + sizeof(status->gtk[0].key)); /* copy GTK info to the right place */ - memcpy(status->gtk.key, v6->gtk.decrypt_key, + memcpy(status->gtk[0].key, v6->gtk.decrypt_key, sizeof(v6->gtk.decrypt_key)); - memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, v6->gtk.tkip_mic_key, sizeof(v6->gtk.tkip_mic_key)); iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc); /* hardcode the key length to 16 since v6 only supports 16 */ - status->gtk.len = 16; + status->gtk[0].len = 16; /* * The key index only uses 2 bits (values 0 to 3) and * we always set bit 7 which means this is the * currently used key. */ - status->gtk.flags = v6->gtk.key_index | BIT(7); + status->gtk[0].flags = v6->gtk.key_index | BIT(7); } else if (notif_ver == 7) { struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data; @@ -2212,7 +2246,7 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) goto out_free_resp; iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc); - iwl_mvm_convert_gtk_v3(status, &v12->gtk[0]); + iwl_mvm_convert_gtk_v3(status, v12->gtk); iwl_mvm_convert_igtk(status, &v12->igtk[0]); status->tid_tear_down = v12->tid_tear_down; -- cgit v1.2.3 From 04f78e242fffe6994f7662fb00aaa398dda41d3a Mon Sep 17 00:00:00 2001 From: Yedidya Benshimol Date: Wed, 21 Jun 2023 14:49:52 +0300 Subject: wifi: iwlwifi: mvm: Add support for IGTK in D3 resume flow As part of the new security API in the FW, all security keys are to be removed before station removal. Until now IGTK rekey wasn't supported in the D3 resume flow, and thus the driver might not know the right key to remove. If an IGTK was rekeyed during D3 the old IGTK is removed and the new key is updated. If not, the old key's IPN is updated. As opposed to GTK, which both the FW and the driver hold it's two most recent keys, only one IGTK is held. Signed-off-by: Yedidya Benshimol Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230621144844.b53c301c07e6.I375277a10a1f756b93d4a343f6664351a80189c5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/api/d3.h | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 168 +++++++++++++++++++++---- 2 files changed, 147 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 380eeb2363c7..72d461c47323 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -396,6 +396,7 @@ struct iwl_wowlan_config_cmd { #define WOWLAN_KEY_MAX_SIZE 32 #define WOWLAN_GTK_KEYS_NUM 2 #define WOWLAN_IGTK_KEYS_NUM 2 +#define WOWLAN_IGTK_MIN_INDEX 4 /* * WOWLAN_TSC_RSC_PARAMS @@ -612,6 +613,7 @@ struct iwl_wowlan_gtk_status_v3 { } __packed; /* WOWLAN_GTK_MATERIAL_VER_3 */ #define IWL_WOWLAN_GTK_IDX_MASK (BIT(0) | BIT(1)) +#define IWL_WOWLAN_IGTK_BIGTK_IDX_MASK (BIT(0)) /** * struct iwl_wowlan_igtk_status - IGTK status diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 1d900342224f..f6488b4bbe68 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1380,6 +1380,14 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) return __iwl_mvm_suspend(hw, wowlan, false); } +struct iwl_multicast_key_data { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 len; + u8 flags; + u8 id; + u8 ipn[6]; +}; + /* converted data from the different status responses */ struct iwl_wowlan_status_data { u64 replay_ctr; @@ -1429,12 +1437,7 @@ struct iwl_wowlan_status_data { } tkip, aes; } ptk; - struct { - u64 ipn; - u8 key[WOWLAN_KEY_MAX_SIZE]; - u8 len; - u8 flags; - } igtk; + struct iwl_multicast_key_data igtk; u8 *wake_packet; }; @@ -1778,8 +1781,8 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm *mvm; struct iwl_wowlan_status_data *status; - u32 gtk_cipher; - bool unhandled_cipher; + u32 gtk_cipher, igtk_cipher; + bool unhandled_cipher, igtk_support; int num_keys; }; @@ -1806,6 +1809,19 @@ static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, /* we support these */ data->gtk_cipher = key->cipher; break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_AES_CMAC: + /* we support these */ + if (data->igtk_support && + (key->keyidx == 4 || key->keyidx == 5)) { + data->igtk_cipher = key->cipher; + } else { + data->unhandled_cipher = true; + return; + } + break; default: /* everything else - disconnect from AP */ data->unhandled_cipher = true; @@ -1815,6 +1831,23 @@ static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, data->num_keys++; } +static void +iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key, + struct ieee80211_key_seq *seq, u32 cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + BUILD_BUG_ON(sizeof(seq->aes_gmac.pn) != sizeof(key->ipn)); + memcpy(seq->aes_gmac.pn, key->ipn, sizeof(seq->aes_gmac.pn)); + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + BUILD_BUG_ON(sizeof(seq->aes_cmac.pn) != sizeof(key->ipn)); + memcpy(seq->aes_cmac.pn, key->ipn, sizeof(seq->aes_cmac.pn)); + break; + } +} + static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -1861,6 +1894,24 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, } else { iwl_mvm_set_key_rx_seq(key, data->status, false); } + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_AES_CMAC: + if (key->keyidx == 4 || key->keyidx == 5) { + /* remove rekeyed key */ + if (status->num_of_gtk_rekeys) { + ieee80211_remove_key(key); + } else { + struct ieee80211_key_seq seq; + + iwl_mvm_d3_set_igtk_bigtk_ipn(&status->igtk, + &seq, + key->cipher); + ieee80211_set_key_rx_seq(key, 0, &seq); + } + } } } @@ -1918,6 +1969,70 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, return true; } +static bool +iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, + struct ieee80211_vif *vif, u32 cipher, + struct iwl_multicast_key_data *key_data) +{ + struct ieee80211_key_conf *key_config; + struct { + struct ieee80211_key_conf conf; + u8 key[WOWLAN_KEY_MAX_SIZE]; + } conf = { + .conf.cipher = cipher, + .conf.keyidx = key_data->id, + }; + struct ieee80211_key_seq seq; + + if (!key_data->len) + return true; + + iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher); + + switch (cipher) { + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256; + break; + default: + WARN_ON(1); + } + BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); + memcpy(conf.conf.key, key_data->key, conf.conf.keylen); + + key_config = ieee80211_gtk_rekey_add(vif, &conf.conf); + if (IS_ERR(key_config)) + return false; + ieee80211_set_key_rx_seq(key_config, 0, &seq); + return true; +} + +static int iwl_mvm_lookup_wowlan_status_ver(struct iwl_mvm *mvm) +{ + u8 notif_ver; + + if (!fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) + return 6; + + /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */ + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, 0); + if (!notif_ver) + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + WOWLAN_GET_STATUSES, 7); + + return notif_ver; +} + static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_wowlan_status_data *status) @@ -1937,6 +2052,12 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, if (status->wakeup_reasons & disconnection_reasons) return false; + if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 || + iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, + WOWLAN_INFO_NOTIFICATION, + 0)) + gtkdata.igtk_support = true; + /* find last GTK that we used initially, if any */ ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_d3_find_last_keys, >kdata); @@ -1961,6 +2082,12 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher)) return false; + + if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif, + gtkdata.igtk_cipher, + &status->igtk)) + return false; + ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, (void *)&replay_ctr, GFP_KERNEL); } @@ -2030,21 +2157,19 @@ static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, struct iwl_wowlan_igtk_status *data) { - const u8 *ipn = data->ipn; - BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key)); + if (!data->key_len) + return; + status->igtk.len = data->key_len; status->igtk.flags = data->key_flags; + status->igtk.id = u32_get_bits(data->key_flags, + IWL_WOWLAN_IGTK_BIGTK_IDX_MASK) + + WOWLAN_IGTK_MIN_INDEX; memcpy(status->igtk.key, data->key, sizeof(data->key)); - - status->igtk.ipn = ((u64)ipn[5] << 0) | - ((u64)ipn[4] << 8) | - ((u64)ipn[3] << 16) | - ((u64)ipn[2] << 24) | - ((u64)ipn[1] << 32) | - ((u64)ipn[0] << 40); + memcpy(status->igtk.ipn, data->ipn, sizeof(data->ipn)); } static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, @@ -2175,14 +2300,9 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) len = iwl_rx_packet_payload_len(cmd.resp_pkt); /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */ - notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, - WOWLAN_GET_STATUSES, 0); - if (!notif_ver) - notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - WOWLAN_GET_STATUSES, 7); + notif_ver = iwl_mvm_lookup_wowlan_status_ver(mvm); - if (!fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) { + if (notif_ver < 7) { struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data; status = iwl_mvm_parse_wowlan_status_common_v6(mvm, v6, len); -- cgit v1.2.3 From cc75549548482ed653c23f212544e58cb38ea980 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Thu, 15 Jun 2023 11:47:40 +0200 Subject: net: micrel: Change to receive timestamp in the frame for lan8841 Currently for each timestamp frame, the SW needs to go and read the received timestamp over the MDIO bus. But the HW has the capability to store the received nanoseconds part and the least significant two bits of the seconds in the reserved field of the PTP header. In this way we could save few MDIO transactions (actually a little more transactions because the access to the PTP registers are indirect) for each received frame. Instead of reading the rest of seconds part of the timestamp of the frame using MDIO transactions schedule PTP worker thread to read the seconds part every 500ms and then for each of the received frames use this information. Because if for example running with 512 frames per second, there is no point to read 512 times the second part. Doing all these changes will give a great CPU usage performance. Running ptp4l with logSyncInterval of -9 will give a ~60% CPU improvement. Signed-off-by: Horatiu Vultur Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 250 +++++++++++++++++++++++++++++------------------ 1 file changed, 154 insertions(+), 96 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 6d18ea19e442..b6d7981b2d1e 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -252,6 +252,9 @@ #define PS_TO_REG 200 #define FIFO_SIZE 8 +/* Delay used to get the second part from the LTC */ +#define LAN8841_GET_SEC_LTC_DELAY (500 * NSEC_PER_MSEC) + struct kszphy_hw_stat { const char *string; u8 reg; @@ -319,6 +322,10 @@ struct kszphy_ptp_priv { /* Lock for ptp_clock */ struct mutex ptp_lock; struct ptp_pin_desc *pin_config; + + s64 seconds; + /* Lock for accessing seconds */ + spinlock_t seconds_lock; }; struct kszphy_priv { @@ -3311,6 +3318,9 @@ static int lan8814_probe(struct phy_device *phydev) #define LAN8841_PTP_CMD_CTL_PTP_RESET BIT(0) #define LAN8841_PTP_RX_PARSE_CONFIG 368 #define LAN8841_PTP_TX_PARSE_CONFIG 432 +#define LAN8841_PTP_RX_MODE 381 +#define LAN8841_PTP_INSERT_TS_EN BIT(0) +#define LAN8841_PTP_INSERT_TS_32BIT BIT(1) static int lan8841_config_init(struct phy_device *phydev) { @@ -3459,68 +3469,18 @@ static void lan8841_ptp_process_tx_ts(struct kszphy_ptp_priv *ptp_priv) lan8814_match_tx_skb(ptp_priv, sec, nsec, seq); } -#define LAN8841_PTP_RX_INGRESS_SEC_LO 389 -#define LAN8841_PTP_RX_INGRESS_SEC_HI 388 -#define LAN8841_PTP_RX_INGRESS_NS_LO 387 -#define LAN8841_PTP_RX_INGRESS_NS_HI 386 -#define LAN8841_PTP_RX_INGRESS_NSEC_HI_VALID BIT(15) -#define LAN8841_PTP_RX_MSG_HEADER2 391 - -static struct lan8814_ptp_rx_ts *lan8841_ptp_get_rx_ts(struct kszphy_ptp_priv *ptp_priv) -{ - struct phy_device *phydev = ptp_priv->phydev; - struct lan8814_ptp_rx_ts *rx_ts; - u32 sec, nsec; - u16 seq; - - nsec = phy_read_mmd(phydev, 2, LAN8841_PTP_RX_INGRESS_NS_HI); - if (!(nsec & LAN8841_PTP_RX_INGRESS_NSEC_HI_VALID)) - return NULL; - - nsec = ((nsec & 0x3fff) << 16); - nsec = nsec | phy_read_mmd(phydev, 2, LAN8841_PTP_RX_INGRESS_NS_LO); - - sec = phy_read_mmd(phydev, 2, LAN8841_PTP_RX_INGRESS_SEC_HI); - sec = sec << 16; - sec = sec | phy_read_mmd(phydev, 2, LAN8841_PTP_RX_INGRESS_SEC_LO); - - seq = phy_read_mmd(phydev, 2, LAN8841_PTP_RX_MSG_HEADER2); - - rx_ts = kzalloc(sizeof(*rx_ts), GFP_KERNEL); - if (!rx_ts) - return NULL; - - rx_ts->seconds = sec; - rx_ts->nsec = nsec; - rx_ts->seq_id = seq; - - return rx_ts; -} - -static void lan8841_ptp_process_rx_ts(struct kszphy_ptp_priv *ptp_priv) -{ - struct lan8814_ptp_rx_ts *rx_ts; - - while ((rx_ts = lan8841_ptp_get_rx_ts(ptp_priv)) != NULL) - lan8814_match_rx_ts(ptp_priv, rx_ts); -} - #define LAN8841_PTP_INT_STS 259 #define LAN8841_PTP_INT_STS_PTP_TX_TS_OVRFL_INT BIT(13) #define LAN8841_PTP_INT_STS_PTP_TX_TS_INT BIT(12) -#define LAN8841_PTP_INT_STS_PTP_RX_TS_OVRFL_INT BIT(9) -#define LAN8841_PTP_INT_STS_PTP_RX_TS_INT BIT(8) #define LAN8841_PTP_INT_STS_PTP_GPIO_CAP_INT BIT(2) -static void lan8841_ptp_flush_fifo(struct kszphy_ptp_priv *ptp_priv, bool egress) +static void lan8841_ptp_flush_fifo(struct kszphy_ptp_priv *ptp_priv) { struct phy_device *phydev = ptp_priv->phydev; int i; for (i = 0; i < FIFO_SIZE; ++i) - phy_read_mmd(phydev, 2, - egress ? LAN8841_PTP_TX_MSG_HEADER2 : - LAN8841_PTP_RX_MSG_HEADER2); + phy_read_mmd(phydev, 2, LAN8841_PTP_TX_MSG_HEADER2); phy_read_mmd(phydev, 2, LAN8841_PTP_INT_STS); } @@ -3598,23 +3558,17 @@ static void lan8841_handle_ptp_interrupt(struct phy_device *phydev) if (status & LAN8841_PTP_INT_STS_PTP_TX_TS_INT) lan8841_ptp_process_tx_ts(ptp_priv); - if (status & LAN8841_PTP_INT_STS_PTP_RX_TS_INT) - lan8841_ptp_process_rx_ts(ptp_priv); - if (status & LAN8841_PTP_INT_STS_PTP_GPIO_CAP_INT) lan8841_gpio_process_cap(ptp_priv); if (status & LAN8841_PTP_INT_STS_PTP_TX_TS_OVRFL_INT) { - lan8841_ptp_flush_fifo(ptp_priv, true); + lan8841_ptp_flush_fifo(ptp_priv); skb_queue_purge(&ptp_priv->tx_queue); } - if (status & LAN8841_PTP_INT_STS_PTP_RX_TS_OVRFL_INT) { - lan8841_ptp_flush_fifo(ptp_priv, false); - skb_queue_purge(&ptp_priv->rx_queue); - } - - } while (status); + } while (status & (LAN8841_PTP_INT_STS_PTP_TX_TS_INT | + LAN8841_PTP_INT_STS_PTP_GPIO_CAP_INT | + LAN8841_PTP_INT_STS_PTP_TX_TS_OVRFL_INT)); } #define LAN8841_INTS_PTP BIT(9) @@ -3678,32 +3632,46 @@ static int lan8841_ts_info(struct mii_timestamper *mii_ts, #define LAN8841_PTP_INT_EN 260 #define LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN BIT(13) #define LAN8841_PTP_INT_EN_PTP_TX_TS_EN BIT(12) -#define LAN8841_PTP_INT_EN_PTP_RX_TS_OVRFL_EN BIT(9) -#define LAN8841_PTP_INT_EN_PTP_RX_TS_EN BIT(8) -static void lan8841_ptp_enable_int(struct kszphy_ptp_priv *ptp_priv, - bool enable) +static void lan8841_ptp_enable_processing(struct kszphy_ptp_priv *ptp_priv, + bool enable) { struct phy_device *phydev = ptp_priv->phydev; - if (enable) - /* Enable interrupts */ + if (enable) { + /* Enable interrupts on the TX side */ phy_modify_mmd(phydev, 2, LAN8841_PTP_INT_EN, LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN | - LAN8841_PTP_INT_EN_PTP_RX_TS_OVRFL_EN | - LAN8841_PTP_INT_EN_PTP_TX_TS_EN | - LAN8841_PTP_INT_EN_PTP_RX_TS_EN, + LAN8841_PTP_INT_EN_PTP_TX_TS_EN, LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN | - LAN8841_PTP_INT_EN_PTP_RX_TS_OVRFL_EN | - LAN8841_PTP_INT_EN_PTP_TX_TS_EN | - LAN8841_PTP_INT_EN_PTP_RX_TS_EN); - else - /* Disable interrupts */ + LAN8841_PTP_INT_EN_PTP_TX_TS_EN); + + /* Enable the modification of the frame on RX side, + * this will add the ns and 2 bits of sec in the reserved field + * of the PTP header + */ + phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, + LAN8841_PTP_RX_MODE, + LAN8841_PTP_INSERT_TS_EN | + LAN8841_PTP_INSERT_TS_32BIT, + LAN8841_PTP_INSERT_TS_EN | + LAN8841_PTP_INSERT_TS_32BIT); + + ptp_schedule_worker(ptp_priv->ptp_clock, 0); + } else { + /* Disable interrupts on the TX side */ phy_modify_mmd(phydev, 2, LAN8841_PTP_INT_EN, LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN | - LAN8841_PTP_INT_EN_PTP_RX_TS_OVRFL_EN | - LAN8841_PTP_INT_EN_PTP_TX_TS_EN | - LAN8841_PTP_INT_EN_PTP_RX_TS_EN, 0); + LAN8841_PTP_INT_EN_PTP_TX_TS_EN, 0); + + /* Disable modification of the RX frames */ + phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, + LAN8841_PTP_RX_MODE, + LAN8841_PTP_INSERT_TS_EN | + LAN8841_PTP_INSERT_TS_32BIT, 0); + + ptp_cancel_worker_sync(ptp_priv->ptp_clock); + } } #define LAN8841_PTP_RX_TIMESTAMP_EN 379 @@ -3714,7 +3682,6 @@ static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) { struct kszphy_ptp_priv *ptp_priv = container_of(mii_ts, struct kszphy_ptp_priv, mii_ts); struct phy_device *phydev = ptp_priv->phydev; - struct lan8814_ptp_rx_ts *rx_ts, *tmp; struct hwtstamp_config config; int txcfg = 0, rxcfg = 0; int pkt_ts_enable; @@ -3778,24 +3745,61 @@ static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_ : 0); /* Now enable/disable the timestamping */ - lan8841_ptp_enable_int(ptp_priv, - config.rx_filter != HWTSTAMP_FILTER_NONE); - - /* In case of multiple starts and stops, these needs to be cleared */ - list_for_each_entry_safe(rx_ts, tmp, &ptp_priv->rx_ts_list, list) { - list_del(&rx_ts->list); - kfree(rx_ts); - } + lan8841_ptp_enable_processing(ptp_priv, + config.rx_filter != HWTSTAMP_FILTER_NONE); - skb_queue_purge(&ptp_priv->rx_queue); skb_queue_purge(&ptp_priv->tx_queue); - lan8841_ptp_flush_fifo(ptp_priv, false); - lan8841_ptp_flush_fifo(ptp_priv, true); + lan8841_ptp_flush_fifo(ptp_priv); return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; } +static bool lan8841_rxtstamp(struct mii_timestamper *mii_ts, + struct sk_buff *skb, int type) +{ + struct kszphy_ptp_priv *ptp_priv = + container_of(mii_ts, struct kszphy_ptp_priv, mii_ts); + struct ptp_header *header = ptp_parse_header(skb, type); + struct skb_shared_hwtstamps *shhwtstamps; + struct timespec64 ts; + unsigned long flags; + u32 ts_header; + + if (!header) + return false; + + if (ptp_priv->rx_filter == HWTSTAMP_FILTER_NONE || + type == PTP_CLASS_NONE) + return false; + + if ((type & ptp_priv->version) == 0 || (type & ptp_priv->layer) == 0) + return false; + + spin_lock_irqsave(&ptp_priv->seconds_lock, flags); + ts.tv_sec = ptp_priv->seconds; + spin_unlock_irqrestore(&ptp_priv->seconds_lock, flags); + ts_header = __be32_to_cpu(header->reserved2); + + shhwtstamps = skb_hwtstamps(skb); + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + + /* Check for any wrap arounds for the second part */ + if ((ts.tv_sec & GENMASK(1, 0)) == 0 && (ts_header >> 30) == 3) + ts.tv_sec -= GENMASK(1, 0) + 1; + else if ((ts.tv_sec & GENMASK(1, 0)) == 3 && (ts_header >> 30) == 0) + ts.tv_sec += 1; + + shhwtstamps->hwtstamp = + ktime_set((ts.tv_sec & ~(GENMASK(1, 0))) | ts_header >> 30, + ts_header & GENMASK(29, 0)); + header->reserved2 = 0; + + netif_rx(skb); + + return true; +} + #define LAN8841_EVENT_A 0 #define LAN8841_EVENT_B 1 #define LAN8841_PTP_LTC_TARGET_SEC_HI(event) ((event) == LAN8841_EVENT_A ? 278 : 288) @@ -3880,6 +3884,7 @@ static int lan8841_ptp_settime64(struct ptp_clock_info *ptp, struct kszphy_ptp_priv *ptp_priv = container_of(ptp, struct kszphy_ptp_priv, ptp_clock_info); struct phy_device *phydev = ptp_priv->phydev; + unsigned long flags; int ret; /* Set the value to be stored */ @@ -3896,6 +3901,10 @@ static int lan8841_ptp_settime64(struct ptp_clock_info *ptp, ret = lan8841_ptp_update_target(ptp_priv, ts); mutex_unlock(&ptp_priv->ptp_lock); + spin_lock_irqsave(&ptp_priv->seconds_lock, flags); + ptp_priv->seconds = ts->tv_sec; + spin_unlock_irqrestore(&ptp_priv->seconds_lock, flags); + return ret; } @@ -3936,6 +3945,30 @@ static int lan8841_ptp_gettime64(struct ptp_clock_info *ptp, return 0; } +static void lan8841_ptp_getseconds(struct ptp_clock_info *ptp, + struct timespec64 *ts) +{ + struct kszphy_ptp_priv *ptp_priv = container_of(ptp, struct kszphy_ptp_priv, + ptp_clock_info); + struct phy_device *phydev = ptp_priv->phydev; + time64_t s; + + mutex_lock(&ptp_priv->ptp_lock); + /* Issue the command to read the LTC */ + phy_write_mmd(phydev, 2, LAN8841_PTP_CMD_CTL, + LAN8841_PTP_CMD_CTL_PTP_LTC_READ); + + /* Read the LTC */ + s = phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_HI); + s <<= 16; + s |= phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_MID); + s <<= 16; + s |= phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_LO); + mutex_unlock(&ptp_priv->ptp_lock); + + set_normalized_timespec64(ts, s, 0); +} + #define LAN8841_PTP_LTC_STEP_ADJ_LO 276 #define LAN8841_PTP_LTC_STEP_ADJ_HI 275 #define LAN8841_PTP_LTC_STEP_ADJ_DIR BIT(15) @@ -4438,6 +4471,22 @@ static int lan8841_ptp_enable(struct ptp_clock_info *ptp, return 0; } +static long lan8841_ptp_do_aux_work(struct ptp_clock_info *ptp) +{ + struct kszphy_ptp_priv *ptp_priv = container_of(ptp, struct kszphy_ptp_priv, + ptp_clock_info); + struct timespec64 ts; + unsigned long flags; + + lan8841_ptp_getseconds(&ptp_priv->ptp_clock_info, &ts); + + spin_lock_irqsave(&ptp_priv->seconds_lock, flags); + ptp_priv->seconds = ts.tv_sec; + spin_unlock_irqrestore(&ptp_priv->seconds_lock, flags); + + return nsecs_to_jiffies(LAN8841_GET_SEC_LTC_DELAY); +} + static struct ptp_clock_info lan8841_ptp_clock_info = { .owner = THIS_MODULE, .name = "lan8841 ptp", @@ -4448,6 +4497,7 @@ static struct ptp_clock_info lan8841_ptp_clock_info = { .adjfine = lan8841_ptp_adjfine, .verify = lan8841_ptp_verify, .enable = lan8841_ptp_enable, + .do_aux_work = lan8841_ptp_do_aux_work, .n_per_out = LAN8841_PTP_GPIO_NUM, .n_ext_ts = LAN8841_PTP_GPIO_NUM, .n_pins = LAN8841_PTP_GPIO_NUM, @@ -4508,13 +4558,11 @@ static int lan8841_probe(struct phy_device *phydev) /* Initialize the SW */ skb_queue_head_init(&ptp_priv->tx_queue); - skb_queue_head_init(&ptp_priv->rx_queue); - INIT_LIST_HEAD(&ptp_priv->rx_ts_list); - spin_lock_init(&ptp_priv->rx_ts_lock); ptp_priv->phydev = phydev; mutex_init(&ptp_priv->ptp_lock); + spin_lock_init(&ptp_priv->seconds_lock); - ptp_priv->mii_ts.rxtstamp = lan8814_rxtstamp; + ptp_priv->mii_ts.rxtstamp = lan8841_rxtstamp; ptp_priv->mii_ts.txtstamp = lan8814_txtstamp; ptp_priv->mii_ts.hwtstamp = lan8841_hwtstamp; ptp_priv->mii_ts.ts_info = lan8841_ts_info; @@ -4524,6 +4572,16 @@ static int lan8841_probe(struct phy_device *phydev) return 0; } +static int lan8841_suspend(struct phy_device *phydev) +{ + struct kszphy_priv *priv = phydev->priv; + struct kszphy_ptp_priv *ptp_priv = &priv->ptp_priv; + + ptp_cancel_worker_sync(ptp_priv->ptp_clock); + + return genphy_suspend(phydev); +} + static struct phy_driver ksphy_driver[] = { { .phy_id = PHY_ID_KS8737, @@ -4747,7 +4805,7 @@ static struct phy_driver ksphy_driver[] = { .get_sset_count = kszphy_get_sset_count, .get_strings = kszphy_get_strings, .get_stats = kszphy_get_stats, - .suspend = genphy_suspend, + .suspend = lan8841_suspend, .resume = genphy_resume, .cable_test_start = lan8814_cable_test_start, .cable_test_get_status = ksz886x_cable_test_get_status, -- cgit v1.2.3 From 2aa083acea9f61be3280184384551178f510ff51 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Tue, 13 Jun 2023 16:46:55 +0300 Subject: wifi: ath9k: convert msecs to jiffies where needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 'ieee80211_queue_delayed_work()' expects timeout in jiffies and not milliseconds, 'msecs_to_jiffies()' should be used in 'ath_restart_work()' and '__ath9k_flush()'. Fixes: d63ffc45c5d3 ("ath9k: rename tx_complete_work to hw_check_work") Signed-off-by: Dmitry Antipov Acked-by: Toke Høiland-Jørgensen Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230613134655.248728-1-dmantipov@yandex.ru --- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7f9f06ea8a05..6360d3356e25 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -203,7 +203,7 @@ void ath_cancel_work(struct ath_softc *sc) void ath_restart_work(struct ath_softc *sc) { ieee80211_queue_delayed_work(sc->hw, &sc->hw_check_work, - ATH_HW_CHECK_POLL_INT); + msecs_to_jiffies(ATH_HW_CHECK_POLL_INT)); if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9330(sc->sc_ah)) ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, @@ -2240,7 +2240,7 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop, } ieee80211_queue_delayed_work(hw, &sc->hw_check_work, - ATH_HW_CHECK_POLL_INT); + msecs_to_jiffies(ATH_HW_CHECK_POLL_INT)); } static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) -- cgit v1.2.3 From 12ec37be3faf9df7831ce210947f111b3417baf3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Jun 2023 11:04:21 +0200 Subject: wifi: ath10k: improve structure padding Including an aligned structure inside of a packed one is ambiguous and can lead to misaligned data, as pointed out by this clang warning: drivers/net/wireless/ath/ath10k/htt.h:715:34: error: field prefix within 'struct htt_rx_indication' is less aligned than 'struct htt_rx_indication_prefix' and is usually due to 'struct htt_rx_indication' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] struct htt_rx_indication_prefix prefix; ^ drivers/net/wireless/ath/ath10k/htt.h:736:34: error: field prefix within 'struct htt_rx_indication_hl' is less aligned than 'struct htt_rx_indication_prefix' and is usually due to 'struct htt_rx_indication_hl' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] struct htt_rx_indication_prefix prefix; ^ drivers/net/wireless/ath/ath10k/htt.h:1564:2: error: field within 'struct htt_tx_fetch_ind' is less aligned than 'union htt_tx_fetch_ind::(anonymous at drivers/net/wireless/ath/ath10k/htt.h:1564:2)' and is usually due to 'struct htt_tx_fetch_ind' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] union { ^ drivers/net/wireless/ath/ath10k/htt.h:1702:2: error: field within 'struct htt_resp' is less aligned than 'union htt_resp::(anonymous at drivers/net/wireless/ath/ath10k/htt.h:1702:2)' and is usually due to 'struct htt_resp' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] These structures appear to actually need the packing since they are embedded at misaligned offsets. Add even more such annotations here to enforce bytewise access throughout the driver. Signed-off-by: Arnd Bergmann Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230616090439.2484857-1-arnd@kernel.org --- drivers/net/wireless/ath/ath10k/htt.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index c051a22fce14..e0c9f45e7476 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -707,7 +707,7 @@ struct htt_rx_indication_prefix { __le16 fw_rx_desc_bytes; u8 pad0; u8 pad1; -}; +} __packed; struct htt_rx_indication { struct htt_rx_indication_hdr hdr; @@ -1565,7 +1565,7 @@ struct htt_tx_fetch_ind { /* ath10k_htt_get_tx_fetch_ind_resp_ids() */ DECLARE_FLEX_ARRAY(__le32, resp_ids); DECLARE_FLEX_ARRAY(struct htt_tx_fetch_record, records); - }; + } __packed; } __packed; static inline void * @@ -1723,7 +1723,7 @@ struct htt_resp { struct htt_tx_mode_switch_ind tx_mode_switch_ind; struct htt_channel_change chan_change; struct htt_peer_tx_stats peer_tx_stats; - }; + } __packed; } __packed; /*** host side structures follow ***/ -- cgit v1.2.3 From 084f1f552f8dd8e8b993d14a30720b7484d77020 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 14 Jun 2023 09:18:31 +0300 Subject: wifi: rtlwifi: simplify LED management Introduce 'rtl_init_sw_leds()' to replace per-chip LED initialization code (and so drop 'struct rtl_led' as no longer used), drop 'init_sw_leds' and 'deinit_sw_leds' fields from 'struct rtl_hal_ops', adjust related code. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230614061832.40882-1-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/core.c | 10 ++++ drivers/net/wireless/realtek/rtlwifi/core.h | 2 + drivers/net/wireless/realtek/rtlwifi/pci.c | 2 +- .../net/wireless/realtek/rtlwifi/rtl8188ee/hw.c | 8 +-- .../net/wireless/realtek/rtlwifi/rtl8188ee/led.c | 40 ++++----------- .../net/wireless/realtek/rtlwifi/rtl8188ee/led.h | 5 +- .../net/wireless/realtek/rtlwifi/rtl8188ee/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8192ce/hw.c | 8 +-- .../net/wireless/realtek/rtlwifi/rtl8192ce/led.c | 41 ++++----------- .../net/wireless/realtek/rtlwifi/rtl8192ce/led.h | 5 +- .../net/wireless/realtek/rtlwifi/rtl8192ce/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8192cu/led.c | 56 ++++---------------- .../net/wireless/realtek/rtlwifi/rtl8192cu/led.h | 6 +-- .../net/wireless/realtek/rtlwifi/rtl8192cu/sw.c | 2 - .../net/wireless/realtek/rtlwifi/rtl8192de/hw.c | 8 +-- .../net/wireless/realtek/rtlwifi/rtl8192de/led.c | 42 ++++----------- .../net/wireless/realtek/rtlwifi/rtl8192de/led.h | 5 +- .../net/wireless/realtek/rtlwifi/rtl8192de/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8192ee/hw.c | 8 +-- .../net/wireless/realtek/rtlwifi/rtl8192ee/led.c | 40 ++++----------- .../net/wireless/realtek/rtlwifi/rtl8192ee/led.h | 5 +- .../net/wireless/realtek/rtlwifi/rtl8192ee/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8192se/hw.c | 10 ++-- .../net/wireless/realtek/rtlwifi/rtl8192se/led.c | 42 ++++----------- .../net/wireless/realtek/rtlwifi/rtl8192se/led.h | 5 +- .../net/wireless/realtek/rtlwifi/rtl8192se/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8723ae/hw.c | 8 +-- .../net/wireless/realtek/rtlwifi/rtl8723ae/led.c | 42 ++++----------- .../net/wireless/realtek/rtlwifi/rtl8723ae/led.h | 5 +- .../net/wireless/realtek/rtlwifi/rtl8723ae/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8723be/hw.c | 8 +-- .../net/wireless/realtek/rtlwifi/rtl8723be/led.c | 42 ++++----------- .../net/wireless/realtek/rtlwifi/rtl8723be/led.h | 5 +- .../net/wireless/realtek/rtlwifi/rtl8723be/sw.c | 1 - .../net/wireless/realtek/rtlwifi/rtl8821ae/hw.c | 14 ++--- .../net/wireless/realtek/rtlwifi/rtl8821ae/led.c | 60 +++++++--------------- .../net/wireless/realtek/rtlwifi/rtl8821ae/led.h | 9 ++-- .../net/wireless/realtek/rtlwifi/rtl8821ae/sw.c | 1 - drivers/net/wireless/realtek/rtlwifi/usb.c | 3 +- drivers/net/wireless/realtek/rtlwifi/wifi.h | 14 +---- 40 files changed, 177 insertions(+), 391 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 6f10727cdb94..4fb16f5f6f83 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1908,6 +1908,16 @@ bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) return true; } EXPORT_SYMBOL(rtl_cmd_send_packet); + +void rtl_init_sw_leds(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->ledctl.sw_led0 = LED_PIN_LED0; + rtlpriv->ledctl.sw_led1 = LED_PIN_LED1; +} +EXPORT_SYMBOL(rtl_init_sw_leds); + const struct ieee80211_ops rtl_ops = { .start = rtl_op_start, .stop = rtl_op_stop, diff --git a/drivers/net/wireless/realtek/rtlwifi/core.h b/drivers/net/wireless/realtek/rtlwifi/core.h index 345161b47442..42c2d9e13bb8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.h +++ b/drivers/net/wireless/realtek/rtlwifi/core.h @@ -51,6 +51,8 @@ enum dm_dig_connect_e { }; extern const struct ieee80211_ops rtl_ops; + +void rtl_init_sw_leds(struct ieee80211_hw *hw); void rtl_fw_cb(const struct firmware *firmware, void *context); void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context); void rtl_addr_delay(u32 addr); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 028a7c97bacf..9886e719739b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -2260,7 +2260,7 @@ int rtl_pci_probe(struct pci_dev *pdev, err = -ENODEV; goto fail3; } - rtlpriv->cfg->ops->init_sw_leds(hw); + rtl_init_sw_leds(hw); /*aspm */ rtl_pci_init_aspm(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c index de61c9c0ddec..58b1a46066b5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c @@ -803,17 +803,17 @@ static void _rtl88ee_gen_refresh_led_state(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; if (rtlpriv->rtlhal.up_first_time) return; if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) - rtl88ee_sw_led_on(hw, pled0); + rtl88ee_sw_led_on(hw, pin0); else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) - rtl88ee_sw_led_on(hw, pled0); + rtl88ee_sw_led_on(hw, pin0); else - rtl88ee_sw_led_off(hw, pled0); + rtl88ee_sw_led_off(hw, pin0); } static bool _rtl88ee_init_mac(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/led.c index 006b979da1c6..b57ba45902f9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/led.c @@ -6,23 +6,15 @@ #include "reg.h" #include "led.h" -static void _rtl88ee_init_led(struct ieee80211_hw *hw, - struct rtl_led *pled, enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -void rtl88ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl88ee_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u8 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -36,21 +28,20 @@ void rtl88ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) break; default: rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD, - "switch case %#x not processed\n", pled->ledpin); + "switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl88ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl88ee_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 ledcfg; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -73,34 +64,25 @@ void rtl88ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) break; default: rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD, - "switch case %#x not processed\n", pled->ledpin); + "switch case %#x not processed\n", pin); break; } - pled->ledon = false; -} - -void rtl88ee_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl88ee_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl88ee_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); } static void _rtl88ee_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; switch (ledaction) { case LED_CTL_POWER_ON: case LED_CTL_LINK: case LED_CTL_NO_LINK: - rtl88ee_sw_led_on(hw, pled0); + rtl88ee_sw_led_on(hw, pin0); break; case LED_CTL_POWER_OFF: - rtl88ee_sw_led_off(hw, pled0); + rtl88ee_sw_led_off(hw, pin0); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/led.h index 67d3dc389ba0..e5cc35d4c298 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/led.h @@ -4,9 +4,8 @@ #ifndef __RTL92CE_LED_H__ #define __RTL92CE_LED_H__ -void rtl88ee_init_sw_leds(struct ieee80211_hw *hw); -void rtl88ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl88ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl88ee_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl88ee_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl88ee_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 02b77521b5cd..b77937fe2448 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -230,7 +230,6 @@ static struct rtl_hal_ops rtl8188ee_hal_ops = { .tx_polling = rtl88ee_tx_polling, .enable_hw_sec = rtl88ee_enable_hw_security_config, .set_key = rtl88ee_set_key, - .init_sw_leds = rtl88ee_init_sw_leds, .get_bbreg = rtl88e_phy_query_bb_reg, .set_bbreg = rtl88e_phy_set_bb_reg, .get_rfreg = rtl88e_phy_query_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c index dc480323c9cb..049c4fe9eeed 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c @@ -639,17 +639,17 @@ static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; if (rtlpci->up_first_time) return; if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) - rtl92ce_sw_led_on(hw, pled0); + rtl92ce_sw_led_on(hw, pin0); else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) - rtl92ce_sw_led_on(hw, pled0); + rtl92ce_sw_led_on(hw, pin0); else - rtl92ce_sw_led_off(hw, pled0); + rtl92ce_sw_led_off(hw, pin0); } static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/led.c index 57132278eb5c..9d3ffed13ba8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/led.c @@ -6,25 +6,17 @@ #include "reg.h" #include "led.h" -static void _rtl92ce_init_led(struct ieee80211_hw *hw, - struct rtl_led *pled, enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92ce_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u8 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", - REG_LEDCFG2, pled->ledpin); + REG_LEDCFG2, pin); ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -35,24 +27,22 @@ void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92ce_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 ledcfg; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", - REG_LEDCFG2, pled->ledpin); + REG_LEDCFG2, pin); ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -69,34 +59,25 @@ void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); break; default: - pr_info("switch case %#x not processed\n", pled->ledpin); + pr_info("switch case %#x not processed\n", pin); break; } - pled->ledon = false; -} - -void rtl92ce_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl92ce_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl92ce_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); } static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; switch (ledaction) { case LED_CTL_POWER_ON: case LED_CTL_LINK: case LED_CTL_NO_LINK: - rtl92ce_sw_led_on(hw, pled0); + rtl92ce_sw_led_on(hw, pin0); break; case LED_CTL_POWER_OFF: - rtl92ce_sw_led_off(hw, pled0); + rtl92ce_sw_led_off(hw, pin0); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/led.h index 97ab1e00af5f..66dc28d62003 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/led.h @@ -4,9 +4,8 @@ #ifndef __RTL92CE_LED_H__ #define __RTL92CE_LED_H__ -void rtl92ce_init_sw_leds(struct ieee80211_hw *hw); -void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92ce_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl92ce_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index ed68c850f9a2..e452275d8789 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -207,7 +207,6 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .tx_polling = rtl92ce_tx_polling, .enable_hw_sec = rtl92ce_enable_hw_security_config, .set_key = rtl92ce_set_key, - .init_sw_leds = rtl92ce_init_sw_leds, .get_bbreg = rtl92c_phy_query_bb_reg, .set_bbreg = rtl92c_phy_set_bb_reg, .set_rfreg = rtl92ce_phy_set_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/led.c index 1488f52a2d2f..bfc07efd0eb0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/led.c @@ -6,27 +6,15 @@ #include "reg.h" #include "led.h" -static void _rtl92cu_init_led(struct ieee80211_hw *hw, - struct rtl_led *pled, enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -static void rtl92cu_deinit_led(struct rtl_led *pled) -{ -} - -void rtl92cu_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92cu_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u8 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", - REG_LEDCFG2, pled->ledpin); + REG_LEDCFG2, pin); ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -37,22 +25,20 @@ void rtl92cu_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl92cu_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92cu_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 ledcfg; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", - REG_LEDCFG2, pled->ledpin); + REG_LEDCFG2, pin); ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -69,36 +55,13 @@ void rtl92cu_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = false; -} - -void rtl92cu_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl92cu_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl92cu_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); -} - -void rtl92cu_deinit_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - rtl92cu_deinit_led(&rtlpriv->ledctl.sw_led0); - rtl92cu_deinit_led(&rtlpriv->ledctl.sw_led1); -} - -static void _rtl92cu_sw_led_control(struct ieee80211_hw *hw, - enum led_ctl_mode ledaction) -{ } void rtl92cu_led_control(struct ieee80211_hw *hw, - enum led_ctl_mode ledaction) + enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -114,5 +77,4 @@ void rtl92cu_led_control(struct ieee80211_hw *hw, return; } rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d\n", ledaction); - _rtl92cu_sw_led_control(hw, ledaction); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/led.h index 3fc1e7c8f78b..8175f8bddd6d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/led.h @@ -4,10 +4,8 @@ #ifndef __RTL92CU_LED_H__ #define __RTL92CU_LED_H__ -void rtl92cu_init_sw_leds(struct ieee80211_hw *hw); -void rtl92cu_deinit_sw_leds(struct ieee80211_hw *hw); -void rtl92cu_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl92cu_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92cu_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl92cu_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl92cu_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index 876c14d46c2f..e6403d4c937c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -115,8 +115,6 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { .led_control = rtl92cu_led_control, .enable_hw_sec = rtl92cu_enable_hw_security_config, .set_key = rtl92c_set_key, - .init_sw_leds = rtl92cu_init_sw_leds, - .deinit_sw_leds = rtl92cu_deinit_sw_leds, .get_bbreg = rtl92c_phy_query_bb_reg, .set_bbreg = rtl92c_phy_set_bb_reg, .get_rfreg = rtl92cu_phy_query_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c index df1e36fbc348..31a18bbface9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c @@ -595,16 +595,16 @@ static void _rtl92de_gen_refresh_led_state(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; if (rtlpci->up_first_time) return; if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) - rtl92de_sw_led_on(hw, pled0); + rtl92de_sw_led_on(hw, pin0); else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) - rtl92de_sw_led_on(hw, pled0); + rtl92de_sw_led_on(hw, pin0); else - rtl92de_sw_led_off(hw, pled0); + rtl92de_sw_led_off(hw, pin0); } static bool _rtl92de_init_mac(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/led.c index 93d1c6a610c3..4bd708570992 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/led.c @@ -6,23 +6,15 @@ #include "reg.h" #include "led.h" -static void _rtl92ce_init_led(struct ieee80211_hw *hw, - struct rtl_led *pled, enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -void rtl92de_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92de_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u8 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", - REG_LEDCFG2, pled->ledpin); + REG_LEDCFG2, pin); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -44,24 +36,22 @@ void rtl92de_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5)); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl92de_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92de_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 ledcfg; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", - REG_LEDCFG2, pled->ledpin); + REG_LEDCFG2, pin); ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -78,35 +68,25 @@ void rtl92de_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3))); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = false; -} - -void rtl92de_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl92ce_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl92ce_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); } static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; switch (ledaction) { case LED_CTL_POWER_ON: case LED_CTL_LINK: case LED_CTL_NO_LINK: - rtl92de_sw_led_on(hw, pled0); + rtl92de_sw_led_on(hw, pin0); break; case LED_CTL_POWER_OFF: - rtl92de_sw_led_off(hw, pled0); + rtl92de_sw_led_off(hw, pin0); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/led.h index 7599c7e5ecc3..33e544ad6f99 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/led.h @@ -4,9 +4,8 @@ #ifndef __RTL92CE_LED_H__ #define __RTL92CE_LED_H__ -void rtl92de_init_sw_leds(struct ieee80211_hw *hw); -void rtl92de_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl92de_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92de_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl92de_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl92de_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index a74724c971b9..11f319c97124 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -220,7 +220,6 @@ static struct rtl_hal_ops rtl8192de_hal_ops = { .tx_polling = rtl92de_tx_polling, .enable_hw_sec = rtl92de_enable_hw_security_config, .set_key = rtl92de_set_key, - .init_sw_leds = rtl92de_init_sw_leds, .get_bbreg = rtl92d_phy_query_bb_reg, .set_bbreg = rtl92d_phy_set_bb_reg, .get_rfreg = rtl92d_phy_query_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index 47d8999e31c0..ebb7abd0c9ad 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -714,17 +714,17 @@ static void _rtl92ee_gen_refresh_led_state(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; if (rtlpriv->rtlhal.up_first_time) return; if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) - rtl92ee_sw_led_on(hw, pled0); + rtl92ee_sw_led_on(hw, pin0); else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) - rtl92ee_sw_led_on(hw, pled0); + rtl92ee_sw_led_on(hw, pin0); else - rtl92ee_sw_led_off(hw, pled0); + rtl92ee_sw_led_off(hw, pin0); } static bool _rtl92ee_init_mac(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/led.c index fb4ea3a8481f..a9b5e3c884ee 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/led.c @@ -6,23 +6,15 @@ #include "reg.h" #include "led.h" -static void _rtl92ee_init_led(struct ieee80211_hw *hw, - struct rtl_led *pled, enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -void rtl92ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92ee_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u32 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -39,21 +31,20 @@ void rtl92ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) break; default: rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD, - "switch case %#x not processed\n", pled->ledpin); + "switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl92ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92ee_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 ledcfg; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -69,34 +60,25 @@ void rtl92ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) break; default: rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD, - "switch case %#x not processed\n", pled->ledpin); + "switch case %#x not processed\n", pin); break; } - pled->ledon = false; -} - -void rtl92ee_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl92ee_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl92ee_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); } static void _rtl92ee_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; switch (ledaction) { case LED_CTL_POWER_ON: case LED_CTL_LINK: case LED_CTL_NO_LINK: - rtl92ee_sw_led_on(hw, pled0); + rtl92ee_sw_led_on(hw, pin0); break; case LED_CTL_POWER_OFF: - rtl92ee_sw_led_off(hw, pled0); + rtl92ee_sw_led_off(hw, pin0); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/led.h index 6d775e14846f..08b8ff328b63 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/led.h @@ -4,9 +4,8 @@ #ifndef __RTL92E_LED_H__ #define __RTL92E_LED_H__ -void rtl92ee_init_sw_leds(struct ieee80211_hw *hw); -void rtl92ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl92ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92ee_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl92ee_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl92ee_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 7a16563b3a5d..616a47d8d97a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -220,7 +220,6 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = { .tx_polling = rtl92ee_tx_polling, .enable_hw_sec = rtl92ee_enable_hw_security_config, .set_key = rtl92ee_set_key, - .init_sw_leds = rtl92ee_init_sw_leds, .get_bbreg = rtl92ee_phy_query_bb_reg, .set_bbreg = rtl92ee_phy_set_bb_reg, .get_rfreg = rtl92ee_phy_query_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c index 4ae8f69c64f9..e5775b94f04e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c @@ -731,12 +731,12 @@ static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw) /* After MACIO reset,we must refresh LED state. */ if ((ppsc->rfoff_reason == RF_CHANGE_BY_IPS) || (ppsc->rfoff_reason == 0)) { - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; enum rf_pwrstate rfpwr_state_toset; rfpwr_state_toset = _rtl92se_rf_onoff_detect(hw); if (rfpwr_state_toset == ERFON) - rtl92se_sw_led_on(hw, pled0); + rtl92se_sw_led_on(hw, pin0); } } @@ -1371,15 +1371,15 @@ static void _rtl92se_gen_refreshledstate(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; if (rtlpci->up_first_time) return; if (rtlpriv->psc.rfoff_reason == RF_CHANGE_BY_IPS) - rtl92se_sw_led_on(hw, pled0); + rtl92se_sw_led_on(hw, pin0); else - rtl92se_sw_led_off(hw, pled0); + rtl92se_sw_led_off(hw, pin0); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/led.c index ecbf425f679f..db16a325c5e6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/led.c @@ -6,33 +6,17 @@ #include "reg.h" #include "led.h" -static void _rtl92se_init_led(struct ieee80211_hw *hw, - struct rtl_led *pled, enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -void rtl92se_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl92se_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl92se_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); -} - -void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92se_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u8 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", - LEDCFG, pled->ledpin); + LEDCFG, pin); ledcfg = rtl_read_byte(rtlpriv, LEDCFG); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -42,14 +26,12 @@ void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0x0f); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl92se_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv; u8 ledcfg; @@ -58,11 +40,11 @@ void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) if (!rtlpriv || rtlpriv->max_fw_size) return; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "LedAddr:%X ledpin=%d\n", - LEDCFG, pled->ledpin); + LEDCFG, pin); ledcfg = rtl_read_byte(rtlpriv, LEDCFG); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -77,27 +59,25 @@ void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3))); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = false; } static void _rtl92se_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; switch (ledaction) { case LED_CTL_POWER_ON: case LED_CTL_LINK: case LED_CTL_NO_LINK: - rtl92se_sw_led_on(hw, pled0); + rtl92se_sw_led_on(hw, pin0); break; case LED_CTL_POWER_OFF: - rtl92se_sw_led_off(hw, pled0); + rtl92se_sw_led_off(hw, pin0); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/led.h index c9e481a8d943..43fcc3c77bc1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/led.h @@ -4,9 +4,8 @@ #ifndef __REALTEK_PCI92SE_LED_H__ #define __REALTEK_PCI92SE_LED_H__ -void rtl92se_init_sw_leds(struct ieee80211_hw *hw); -void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl92se_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl92se_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index 6d352a3161b8..30bce381c3bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -260,7 +260,6 @@ static struct rtl_hal_ops rtl8192se_hal_ops = { .tx_polling = rtl92se_tx_polling, .enable_hw_sec = rtl92se_enable_hw_security_config, .set_key = rtl92se_set_key, - .init_sw_leds = rtl92se_init_sw_leds, .get_bbreg = rtl92s_phy_query_bb_reg, .set_bbreg = rtl92s_phy_set_bb_reg, .get_rfreg = rtl92s_phy_query_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 965d98b9b09f..d26d4c4314a3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -643,17 +643,17 @@ static void _rtl8723e_gen_refresh_led_state(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; if (rtlpriv->rtlhal.up_first_time) return; if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) - rtl8723e_sw_led_on(hw, pled0); + rtl8723e_sw_led_on(hw, pin0); else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) - rtl8723e_sw_led_on(hw, pled0); + rtl8723e_sw_led_on(hw, pin0); else - rtl8723e_sw_led_off(hw, pled0); + rtl8723e_sw_led_off(hw, pin0); } static bool _rtl8712e_init_mac(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/led.c index 7fab02e01a8c..90d3f6ae82d5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/led.c @@ -6,23 +6,15 @@ #include "reg.h" #include "led.h" -static void _rtl8723e_init_led(struct ieee80211_hw *hw, - struct rtl_led *pled, enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -void rtl8723e_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl8723e_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u8 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -36,24 +28,22 @@ void rtl8723e_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl8723e_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl8723e_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 ledcfg; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -77,35 +67,25 @@ void rtl8723e_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = false; -} - -void rtl8723e_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl8723e_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl8723e_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); } static void _rtl8723e_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; switch (ledaction) { case LED_CTL_POWER_ON: case LED_CTL_LINK: case LED_CTL_NO_LINK: - rtl8723e_sw_led_on(hw, pled0); + rtl8723e_sw_led_on(hw, pin0); break; case LED_CTL_POWER_OFF: - rtl8723e_sw_led_off(hw, pled0); + rtl8723e_sw_led_off(hw, pin0); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/led.h index 9f85845d23cd..6db5290da806 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/led.h @@ -4,9 +4,8 @@ #ifndef __RTL92CE_LED_H__ #define __RTL92CE_LED_H__ -void rtl8723e_init_sw_leds(struct ieee80211_hw *hw); -void rtl8723e_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl8723e_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8723e_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl8723e_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl8723e_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 7828acb1de3f..c821436a1991 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -223,7 +223,6 @@ static struct rtl_hal_ops rtl8723e_hal_ops = { .tx_polling = rtl8723e_tx_polling, .enable_hw_sec = rtl8723e_enable_hw_security_config, .set_key = rtl8723e_set_key, - .init_sw_leds = rtl8723e_init_sw_leds, .get_bbreg = rtl8723_phy_query_bb_reg, .set_bbreg = rtl8723_phy_set_bb_reg, .get_rfreg = rtl8723e_phy_query_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index 0ba3bbed6ed3..15575644551f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -793,17 +793,17 @@ static void _rtl8723be_gen_refresh_led_state(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; if (rtlpriv->rtlhal.up_first_time) return; if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) - rtl8723be_sw_led_on(hw, pled0); + rtl8723be_sw_led_on(hw, pin0); else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) - rtl8723be_sw_led_on(hw, pled0); + rtl8723be_sw_led_on(hw, pin0); else - rtl8723be_sw_led_off(hw, pled0); + rtl8723be_sw_led_off(hw, pin0); } static bool _rtl8723be_init_mac(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/led.c index 3954624ab314..462fe1d0262b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/led.c @@ -6,23 +6,15 @@ #include "reg.h" #include "led.h" -static void _rtl8723be_init_led(struct ieee80211_hw *hw, struct rtl_led *pled, - enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl8723be_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u8 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -35,24 +27,22 @@ void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10); break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl8723be_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 ledcfg; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -76,35 +66,25 @@ void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) break; default: - pr_err("switch case %#x not processed\n", - pled->ledpin); + pr_err("switch case %#x not processed\n", pin); break; } - pled->ledon = false; -} - -void rtl8723be_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl8723be_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl8723be_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); } static void _rtl8723be_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; switch (ledaction) { case LED_CTL_POWER_ON: case LED_CTL_LINK: case LED_CTL_NO_LINK: - rtl8723be_sw_led_on(hw, pled0); + rtl8723be_sw_led_on(hw, pin0); break; case LED_CTL_POWER_OFF: - rtl8723be_sw_led_off(hw, pled0); + rtl8723be_sw_led_off(hw, pin0); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/led.h index 8ac59374b632..3ca9277152f7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/led.h @@ -4,9 +4,8 @@ #ifndef __RTL8723BE_LED_H__ #define __RTL8723BE_LED_H__ -void rtl8723be_init_sw_leds(struct ieee80211_hw *hw); -void rtl8723be_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl8723be_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8723be_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl8723be_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl8723be_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index d220e8955e37..43b611d5288d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -227,7 +227,6 @@ static struct rtl_hal_ops rtl8723be_hal_ops = { .tx_polling = rtl8723be_tx_polling, .enable_hw_sec = rtl8723be_enable_hw_security_config, .set_key = rtl8723be_set_key, - .init_sw_leds = rtl8723be_init_sw_leds, .get_bbreg = rtl8723_phy_query_bb_reg, .set_bbreg = rtl8723_phy_set_bb_reg, .get_rfreg = rtl8723be_phy_query_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index a7e3250957dc..3f8f6da33b12 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -869,7 +869,7 @@ static void _rtl8821ae_gen_refresh_led_state(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); if (rtlpriv->rtlhal.up_first_time) @@ -877,19 +877,19 @@ static void _rtl8821ae_gen_refresh_led_state(struct ieee80211_hw *hw) if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) - rtl8812ae_sw_led_on(hw, pled0); + rtl8812ae_sw_led_on(hw, pin0); else - rtl8821ae_sw_led_on(hw, pled0); + rtl8821ae_sw_led_on(hw, pin0); else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT) if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) - rtl8812ae_sw_led_on(hw, pled0); + rtl8812ae_sw_led_on(hw, pin0); else - rtl8821ae_sw_led_on(hw, pled0); + rtl8821ae_sw_led_on(hw, pin0); else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) - rtl8812ae_sw_led_off(hw, pled0); + rtl8812ae_sw_led_off(hw, pin0); else - rtl8821ae_sw_led_off(hw, pled0); + rtl8821ae_sw_led_off(hw, pin0); } static bool _rtl8821ae_init_mac(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/led.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/led.c index 7d6fb134c10f..fb003f9ce1ac 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/led.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/led.c @@ -6,24 +6,15 @@ #include "reg.h" #include "led.h" -static void _rtl8821ae_init_led(struct ieee80211_hw *hw, - struct rtl_led *pled, - enum rtl_led_pin ledpin) -{ - pled->hw = hw; - pled->ledpin = ledpin; - pled->ledon = false; -} - -void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u8 ledcfg; struct rtl_priv *rtlpriv = rtl_priv(hw); rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -38,19 +29,18 @@ void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) break; default: rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD, - "switch case %#x not processed\n", pled->ledpin); + "switch case %#x not processed\n", pin); break; } - pled->ledon = true; } -void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u16 ledreg = REG_LEDCFG1; u8 ledcfg = 0; struct rtl_priv *rtlpriv = rtl_priv(hw); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_LED0: ledreg = REG_LEDCFG1; break; @@ -66,27 +56,26 @@ void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "In SwLedOn, LedAddr:%X LEDPIN=%d\n", - ledreg, pled->ledpin); + ledreg, pin); ledcfg = rtl_read_byte(rtlpriv, ledreg); ledcfg |= BIT(5); /*Set 0x4c[21]*/ ledcfg &= ~(BIT(7) | BIT(6) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); /*Clear 0x4c[23:22] and 0x4c[19:16]*/ rtl_write_byte(rtlpriv, ledreg, ledcfg); /*SW control led0 on.*/ - pled->ledon = true; } -void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 ledcfg; rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, - "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin); + "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pin); ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_GPIO0: break; case LED_PIN_LED0: @@ -110,18 +99,17 @@ void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) break; default: rtl_dbg(rtlpriv, COMP_ERR, DBG_LOUD, - "switch case %#x not processed\n", pled->ledpin); + "switch case %#x not processed\n", pin); break; } - pled->ledon = false; } -void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) +void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin) { u16 ledreg = REG_LEDCFG1; struct rtl_priv *rtlpriv = rtl_priv(hw); - switch (pled->ledpin) { + switch (pin) { case LED_PIN_LED0: ledreg = REG_LEDCFG1; break; @@ -137,7 +125,7 @@ void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) rtl_dbg(rtlpriv, COMP_LED, DBG_LOUD, "In SwLedOff,LedAddr:%X LEDPIN=%d\n", - ledreg, pled->ledpin); + ledreg, pin); /*Open-drain arrangement for controlling the LED*/ if (rtlpriv->ledctl.led_opendrain) { u8 ledcfg = rtl_read_byte(rtlpriv, ledreg); @@ -152,23 +140,13 @@ void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) } else { rtl_write_byte(rtlpriv, ledreg, 0x28); } - - pled->ledon = false; -} - -void rtl8821ae_init_sw_leds(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - - _rtl8821ae_init_led(hw, &rtlpriv->ledctl.sw_led0, LED_PIN_LED0); - _rtl8821ae_init_led(hw, &rtlpriv->ledctl.sw_led1, LED_PIN_LED1); } static void _rtl8821ae_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_led *pled0 = &rtlpriv->ledctl.sw_led0; + enum rtl_led_pin pin0 = rtlpriv->ledctl.sw_led0; struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); switch (ledaction) { @@ -176,15 +154,15 @@ static void _rtl8821ae_sw_led_control(struct ieee80211_hw *hw, case LED_CTL_LINK: case LED_CTL_NO_LINK: if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) - rtl8812ae_sw_led_on(hw, pled0); + rtl8812ae_sw_led_on(hw, pin0); else - rtl8821ae_sw_led_on(hw, pled0); + rtl8821ae_sw_led_on(hw, pin0); break; case LED_CTL_POWER_OFF: if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) - rtl8812ae_sw_led_off(hw, pled0); + rtl8812ae_sw_led_off(hw, pin0); else - rtl8821ae_sw_led_off(hw, pled0); + rtl8821ae_sw_led_off(hw, pin0); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/led.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/led.h index 249a37a8d9db..76d5c0b0e39e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/led.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/led.h @@ -4,11 +4,10 @@ #ifndef __RTL8821AE_LED_H__ #define __RTL8821AE_LED_H__ -void rtl8821ae_init_sw_leds(struct ieee80211_hw *hw); -void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); -void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); +void rtl8821ae_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl8812ae_sw_led_on(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl8821ae_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); +void rtl8812ae_sw_led_off(struct ieee80211_hw *hw, enum rtl_led_pin pin); void rtl8821ae_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index 950542a24e31..0bca542e103f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -269,7 +269,6 @@ static struct rtl_hal_ops rtl8821ae_hal_ops = { .tx_polling = rtl8821ae_tx_polling, .enable_hw_sec = rtl8821ae_enable_hw_security_config, .set_key = rtl8821ae_set_key, - .init_sw_leds = rtl8821ae_init_sw_leds, .get_bbreg = rtl8821ae_phy_query_bb_reg, .set_bbreg = rtl8821ae_phy_set_bb_reg, .get_rfreg = rtl8821ae_phy_query_rf_reg, diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index ab675703eaf5..96207b237bf0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -1068,7 +1068,7 @@ int rtl_usb_probe(struct usb_interface *intf, pr_err("Can't init_sw_vars\n"); goto error_out; } - rtlpriv->cfg->ops->init_sw_leds(hw); + rtl_init_sw_leds(hw); err = ieee80211_register_hw(hw); if (err) { @@ -1117,7 +1117,6 @@ void rtl_usb_disconnect(struct usb_interface *intf) rtl_usb_deinit(hw); rtl_deinit_core(hw); kfree(rtlpriv->usb_data); - rtlpriv->cfg->ops->deinit_sw_leds(hw); rtlpriv->cfg->ops->deinit_sw_vars(hw); _rtl_usb_io_handler_release(hw); usb_put_dev(rtlusb->udev); diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index a16b779080cb..5b4979771dbf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1070,18 +1070,10 @@ struct rtl_probe_rsp { struct rtl_info_element info_element[]; } __packed; -/*LED related.*/ -/*ledpin Identify how to implement this SW led.*/ -struct rtl_led { - void *hw; - enum rtl_led_pin ledpin; - bool ledon; -}; - struct rtl_led_ctl { bool led_opendrain; - struct rtl_led sw_led0; - struct rtl_led sw_led1; + enum rtl_led_pin sw_led0; + enum rtl_led_pin sw_led1; }; struct rtl_qos_parameters { @@ -2287,8 +2279,6 @@ struct rtl_hal_ops { void (*set_key)(struct ieee80211_hw *hw, u32 key_index, u8 *macaddr, bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all); - void (*init_sw_leds)(struct ieee80211_hw *hw); - void (*deinit_sw_leds)(struct ieee80211_hw *hw); u32 (*get_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); void (*set_bbreg)(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data); -- cgit v1.2.3 From 5f743f576d3f9ac08ed28fe8e65bdbc8d49b8034 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Wed, 14 Jun 2023 09:18:32 +0300 Subject: wifi: rtlwifi: cleanup USB interface Drop unused '_usb_writen_sync()' and relevant pointer from 'struct rtl_io', handle possible write error in '_usb_write_async()', adjust related code. Signed-off-by: Dmitry Antipov Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Link: https://lore.kernel.org/r/20230614061832.40882-2-dmantipov@yandex.ru --- drivers/net/wireless/realtek/rtlwifi/usb.c | 31 ++++++----------------------- drivers/net/wireless/realtek/rtlwifi/wifi.h | 2 -- 2 files changed, 6 insertions(+), 27 deletions(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 96207b237bf0..30bf2775a335 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -164,13 +164,17 @@ static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val, u16 wvalue; u16 index; __le32 data; + int ret; request = REALTEK_USB_VENQT_CMD_REQ; index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ wvalue = (u16)(addr&0x0000ffff); data = cpu_to_le32(val); - _usbctrl_vendorreq_async_write(udev, request, wvalue, index, &data, - len); + + ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, + index, &data, len); + if (ret < 0) + dev_err(&udev->dev, "error %d writing at 0x%x\n", ret, addr); } static void _usb_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) @@ -194,28 +198,6 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) _usb_write_async(to_usb_device(dev), addr, val, 4); } -static void _usb_writen_sync(struct rtl_priv *rtlpriv, u32 addr, void *data, - u16 len) -{ - struct device *dev = rtlpriv->io.dev; - struct usb_device *udev = to_usb_device(dev); - u8 request = REALTEK_USB_VENQT_CMD_REQ; - u8 reqtype = REALTEK_USB_VENQT_WRITE; - u16 wvalue; - u16 index = REALTEK_USB_VENQT_CMD_IDX; - int pipe = usb_sndctrlpipe(udev, 0); /* write_out */ - u8 *buffer; - - wvalue = (u16)(addr & 0x0000ffff); - buffer = kmemdup(data, len, GFP_ATOMIC); - if (!buffer) - return; - usb_control_msg(udev, pipe, request, reqtype, wvalue, - index, buffer, len, 50); - - kfree(buffer); -} - static void _rtl_usb_io_handler_init(struct device *dev, struct ieee80211_hw *hw) { @@ -229,7 +211,6 @@ static void _rtl_usb_io_handler_init(struct device *dev, rtlpriv->io.read8_sync = _usb_read8_sync; rtlpriv->io.read16_sync = _usb_read16_sync; rtlpriv->io.read32_sync = _usb_read32_sync; - rtlpriv->io.writen_sync = _usb_writen_sync; } static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 5b4979771dbf..2e7e04f91279 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1457,8 +1457,6 @@ struct rtl_io { void (*write8_async)(struct rtl_priv *rtlpriv, u32 addr, u8 val); void (*write16_async)(struct rtl_priv *rtlpriv, u32 addr, u16 val); void (*write32_async)(struct rtl_priv *rtlpriv, u32 addr, u32 val); - void (*writen_sync)(struct rtl_priv *rtlpriv, u32 addr, void *buf, - u16 len); u8 (*read8_sync)(struct rtl_priv *rtlpriv, u32 addr); u16 (*read16_sync)(struct rtl_priv *rtlpriv, u32 addr); -- cgit v1.2.3 From 8c3736ce595bccb6322c44a1f853216e278aa635 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:47 +0200 Subject: selftests: forwarding: q_in_vni: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. This will cause this selftest to fail spuriously. The swp enslavement to the 802.1ad bridge is not allowed, because RIFs are not allowed to be created for 802.1ad bridges, but the address indicates one needs to be created. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/q_in_vni.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/forwarding/q_in_vni.sh b/tools/testing/selftests/net/forwarding/q_in_vni.sh index 4c50c0234bce..798b13525c02 100755 --- a/tools/testing/selftests/net/forwarding/q_in_vni.sh +++ b/tools/testing/selftests/net/forwarding/q_in_vni.sh @@ -137,6 +137,7 @@ switch_create() { ip link add name br1 type bridge vlan_filtering 1 vlan_protocol 802.1ad \ vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br1 addrgenmode none # Make sure the bridge uses the MAC address of the local port and not # that of the VxLAN's device. ip link set dev br1 address $(mac_get $swp1) -- cgit v1.2.3 From c801533304ca87e314ecc6fc43b9a7822f159f18 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:48 +0200 Subject: selftests: forwarding: dual_vxlan_bridge: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. This will cause this selftest to fail spuriously. The swp enslavement to the 802.1ad bridge is not allowed, because RIFs are not allowed to be created for 802.1ad bridges, but the address indicates one needs to be created. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh b/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh index 5148d97a5df8..68ee92df3e07 100755 --- a/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh +++ b/tools/testing/selftests/net/forwarding/dual_vxlan_bridge.sh @@ -132,6 +132,7 @@ switch_create() #### BR1 #### ip link add name br1 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br1 addrgenmode none # Make sure the bridge uses the MAC address of the local port and not # that of the VxLAN's device. ip link set dev br1 address $(mac_get $swp1) -- cgit v1.2.3 From d7442b7d288e8a00290808623f77bc5ed87ba8e6 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:49 +0200 Subject: selftests: forwarding: skbedit_priority: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks operation of pedit on IPv4 and IPv6 dsfield and its parts. The bridge thus does not need to participate in routing traffic and the IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Since the bridge is only used for L2 forwarding, this change should not hinder usefulness of this selftest for testing SW datapath or HW datapaths in other devices. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/pedit_dsfield.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/pedit_dsfield.sh b/tools/testing/selftests/net/forwarding/pedit_dsfield.sh index 64fbd211d907..af008fbf2725 100755 --- a/tools/testing/selftests/net/forwarding/pedit_dsfield.sh +++ b/tools/testing/selftests/net/forwarding/pedit_dsfield.sh @@ -60,7 +60,9 @@ h2_destroy() switch_create() { - ip link add name br1 up type bridge vlan_filtering 1 + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev $swp1 master br1 ip link set dev $swp1 up ip link set dev $swp2 master br1 -- cgit v1.2.3 From f61018dc3e21ba0bee9caadf3015a65a7b4ce09f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:50 +0200 Subject: selftests: forwarding: pedit_dsfield: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks whether skbedit changes packet priority as appropriate. The bridge thus does not need to participate in routing traffic and the IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Since the bridge is only used for L2 forwarding, this change should not hinder usefulness of this selftest for testing SW datapath or HW datapaths in other devices. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/skbedit_priority.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/skbedit_priority.sh b/tools/testing/selftests/net/forwarding/skbedit_priority.sh index bde11dc27873..3dd5fcbd3eaa 100755 --- a/tools/testing/selftests/net/forwarding/skbedit_priority.sh +++ b/tools/testing/selftests/net/forwarding/skbedit_priority.sh @@ -54,7 +54,9 @@ h2_destroy() switch_create() { - ip link add name br1 up type bridge vlan_filtering 1 + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev $swp1 master br1 ip link set dev $swp1 up ip link set dev $swp2 master br1 -- cgit v1.2.3 From 92c3bb5393db2f36e6a23ba7bb50b34c18c523f5 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:51 +0200 Subject: selftests: forwarding: mirror_gre_*: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. These two selftests however check mirroring traffic to a gretap netdevice. The bridge here does not participate in routing traffic and the IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in these selftests, thus exempting them from mlxsw router attention. Since the bridges are only used for L2 forwarding, this change should not hinder usefulness of this selftest for testing SW datapath or HW datapaths in other devices. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/mirror_gre_bound.sh | 1 + tools/testing/selftests/net/forwarding/mirror_topo_lib.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh index 360ca133bead..6c257ec03756 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bound.sh @@ -98,6 +98,7 @@ switch_create() # Bridge between H1 and H2. ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 diff --git a/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh b/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh index 04979e5962e7..bb1adbb7b98a 100644 --- a/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh +++ b/tools/testing/selftests/net/forwarding/mirror_topo_lib.sh @@ -60,6 +60,7 @@ mirror_topo_switch_create() ip link set dev $swp3 up ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 -- cgit v1.2.3 From 8fd32576e650efe88e396febd494f12adf18262a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:52 +0200 Subject: selftests: forwarding: mirror_gre_*: Use port MAC for bridge address In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The bridge eventually inherits MAC address from its first member, after the enslavement is acked. A number of (mainly VXLAN) selftests already work around the problem by setting the MAC address to whatever it will eventually be anyway. Do the same for several mirror_gre selftests. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh | 3 ++- tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh | 3 ++- tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh index c5095da7f6bf..8ce3d95f1add 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh @@ -65,7 +65,8 @@ setup_prepare() vrf_prepare mirror_gre_topo_create - ip link add name br2 type bridge vlan_filtering 0 + ip link add name br2 address $(mac_get $swp3) \ + type bridge vlan_filtering 0 ip link set dev br2 up ip link set dev $swp3 master br2 diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh index 1b27f2b0f196..f35313c76fac 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh @@ -35,7 +35,8 @@ setup_prepare() vrf_prepare mirror_gre_topo_create - ip link add name br2 type bridge vlan_filtering 0 + ip link add name br2 address $(mac_get $swp3) \ + type bridge vlan_filtering 0 ip link set dev br2 up vlan_create $swp3 555 diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh index 91e431cd919e..c53148b1dc63 100755 --- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh +++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh @@ -140,7 +140,8 @@ switch_create() ip link set dev $swp3 up ip link set dev $swp4 up - ip link add name br1 type bridge vlan_filtering 1 + ip link add name br1 address $(mac_get $swp3) \ + type bridge vlan_filtering 1 team_create lag loadbalance $swp3 $swp4 ip link set dev lag master br1 -- cgit v1.2.3 From 5e71bf50c2e284e4b287d55336a1b2f47027624c Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:53 +0200 Subject: selftests: forwarding: router_bridge: Use port MAC for bridge address In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The bridge eventually inherits MAC address from its first member, after the enslavement is acked. A number of (mainly VXLAN) selftests already work around the problem by setting the MAC address to whatever it will eventually be anyway. Do the same here. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/forwarding/router_bridge.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/router_bridge.sh b/tools/testing/selftests/net/forwarding/router_bridge.sh index ebc596a272f7..8ce0aed54ece 100755 --- a/tools/testing/selftests/net/forwarding/router_bridge.sh +++ b/tools/testing/selftests/net/forwarding/router_bridge.sh @@ -38,7 +38,8 @@ h2_destroy() router_create() { - ip link add name br1 type bridge vlan_filtering 1 + ip link add name br1 address $(mac_get $swp1) \ + type bridge vlan_filtering 1 ip link set dev br1 up ip link set dev $swp1 master br1 -- cgit v1.2.3 From 8cfdd300a5e95fea14050cd86259bafb35244a2f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:54 +0200 Subject: selftests: mlxsw: q_in_q_veto: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. The swp enslavement to the 802.1ad bridge is not allowed, because RIFs are not allowed to be created for 802.1ad bridges, but the address indicates one needs to be created. Thus the veto selftests fail already during the port enslavement. Then the attempt to create a VLAN on top of the same bridge is not vetoed, because the bridge is not related to mlxsw, and the selftest fails. Fix by disabling automatic IPv6 address generation for the bridges in this selftest, thus exempting them from the mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Amit Cohen Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh b/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh index 7edaed8eb86a..00d55b0e98c1 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/q_in_q_veto.sh @@ -48,6 +48,7 @@ create_vlan_upper_on_top_of_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol $bridge_proto vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link set dev $swp1 master br0 @@ -88,6 +89,7 @@ create_8021ad_vlan_upper_on_top_bridge_port() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev $swp1 master br0 ip link set dev br0 up @@ -155,6 +157,7 @@ create_vlan_upper_on_top_front_panel_enslaved_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link set dev $swp1 master br0 @@ -177,6 +180,7 @@ create_vlan_upper_on_top_lag_enslaved_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link add name bond1 type bond mode 802.3ad @@ -203,6 +207,7 @@ enslave_front_panel_with_vlan_upper_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link add name $swp1.100 link $swp1 type vlan id 100 @@ -225,6 +230,7 @@ enslave_lag_with_vlan_upper_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link add name bond1 type bond mode 802.3ad @@ -252,6 +258,7 @@ add_ip_address_to_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link set dev $swp1 master br0 @@ -273,6 +280,7 @@ switch_bridge_protocol_from_8021q_to_8021ad() ip link add dev br0 type bridge vlan_filtering 1 \ vlan_protocol 802.1ad vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link set dev $swp1 master br0 -- cgit v1.2.3 From a758dc469a9caf958c0f02426aa76162c89faa97 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:55 +0200 Subject: selftests: mlxsw: extack: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge (this holds for all bridges used here), the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks whether a different vetoed aspect of the configuration provides an extack. The IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in this selftest, thus exempting them from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- .../testing/selftests/drivers/net/mlxsw/extack.sh | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/extack.sh b/tools/testing/selftests/drivers/net/mlxsw/extack.sh index 7a0a99c1d22f..6fd422d38fe8 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/extack.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/extack.sh @@ -35,7 +35,9 @@ netdev_pre_up_test() { RET=0 - ip link add name br1 up type bridge vlan_filtering 0 mcast_snooping 0 + ip link add name br1 type bridge vlan_filtering 0 mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link add name vx1 up type vxlan id 1000 \ local 192.0.2.17 remote 192.0.2.18 \ dstport 4789 nolearning noudpcsum tos inherit ttl 100 @@ -46,7 +48,9 @@ netdev_pre_up_test() ip link set dev $swp1 master br1 check_err $? - ip link add name br2 up type bridge vlan_filtering 0 mcast_snooping 0 + ip link add name br2 type bridge vlan_filtering 0 mcast_snooping 0 + ip link set dev br2 addrgenmode none + ip link set dev br2 up ip link add name vx2 up type vxlan id 2000 \ local 192.0.2.17 remote 192.0.2.18 \ dstport 4789 nolearning noudpcsum tos inherit ttl 100 @@ -81,7 +85,9 @@ vxlan_vlan_add_test() { RET=0 - ip link add name br1 up type bridge vlan_filtering 1 mcast_snooping 0 + ip link add name br1 type bridge vlan_filtering 1 mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up # Unsupported configuration: mlxsw demands VXLAN with "noudpcsum". ip link add name vx1 up type vxlan id 1000 \ @@ -117,7 +123,9 @@ vxlan_bridge_create_test() dstport 4789 tos inherit ttl 100 # Test with VLAN-aware bridge. - ip link add name br1 up type bridge vlan_filtering 1 mcast_snooping 0 + ip link add name br1 type bridge vlan_filtering 1 mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev vx1 master br1 @@ -142,8 +150,12 @@ bridge_create_test() { RET=0 - ip link add name br1 up type bridge vlan_filtering 1 - ip link add name br2 up type bridge vlan_filtering 1 + ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none + ip link set dev br1 up + ip link add name br2 type bridge vlan_filtering 1 + ip link set dev br2 addrgenmode none + ip link set dev br2 up ip link set dev $swp1 master br1 check_err $? -- cgit v1.2.3 From 32b3a7bf8570d24b30d1961fb3eaddb9f1c3250a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:56 +0200 Subject: selftests: mlxsw: mirror_gre_scale: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks how many mirroring sessions a machine is capable of offloading. The IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh index e00435753008..e5589e2fca85 100644 --- a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh @@ -165,6 +165,7 @@ mirror_gre_setup_prepare() simple_if_init $h3 ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 -- cgit v1.2.3 From 6349f9bbbfb2bda12c0a633965d03435d18d930f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:57 +0200 Subject: selftests: mlxsw: qos_dscp_bridge: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks DCB DSCP-based prioritization, and the bridge serves for its L2 forwarding capabilities, and does not need to participate in routing traffic. The IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh index 87c41f5727c9..914c63d6318a 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh @@ -65,6 +65,7 @@ h2_destroy() switch_create() { ip link add name br1 type bridge vlan_filtering 1 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 ip link set dev $swp1 up -- cgit v1.2.3 From ec7023e6745e6fb34cd855522cb8f995194bdbf1 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:58 +0200 Subject: selftests: mlxsw: qos_ets_strict: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge (this holds for both bridges used here), the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks traffic prioritization and scheduling, and the bridges serve for their L2 forwarding capabilities, and do not need to participate in routing traffic. The IP addresses or the RIFs are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in this selftest, thus exempting them from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh index 690d8daa71b4..fee74f215cec 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_ets_strict.sh @@ -138,11 +138,15 @@ switch_create() vlan_create $swp3 111 vlan_create $swp3 222 - ip link add name br111 up type bridge vlan_filtering 0 + ip link add name br111 type bridge vlan_filtering 0 + ip link set dev br111 addrgenmode none + ip link set dev br111 up ip link set dev $swp1.111 master br111 ip link set dev $swp3.111 master br111 - ip link add name br222 up type bridge vlan_filtering 0 + ip link add name br222 type bridge vlan_filtering 0 + ip link set dev br222 addrgenmode none + ip link set dev br222 up ip link set dev $swp2.222 master br222 ip link set dev $swp3.222 master br222 -- cgit v1.2.3 From ea2d5f757e914fa0f82949e130ee9da0ee931e59 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:55:59 +0200 Subject: selftests: mlxsw: qos_mc_aware: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge (this holds for both bridges used here), the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks traffic prioritization and scheduling, and the bridges serve for their L2 forwarding capabilities, and do not need to participate in routing traffic. The IP addresses or the RIFs are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in this selftest, thus exempting them from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh index c8e55fa91660..6d892de43fa8 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/qos_mc_aware.sh @@ -135,11 +135,13 @@ switch_create() prio bands 8 priomap 7 7 7 7 7 7 7 7 ip link add name br1 type bridge vlan_filtering 0 + ip link set dev br1 addrgenmode none ip link set dev br1 up ip link set dev $swp1 master br1 ip link set dev $swp3 master br1 ip link add name br111 type bridge vlan_filtering 0 + ip link set dev br111 addrgenmode none ip link set dev br111 up ip link set dev $swp2.111 master br111 ip link set dev $swp3.111 master br111 -- cgit v1.2.3 From 08035d8e354d9fc652c9d12668e89d83edc8f974 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:56:00 +0200 Subject: selftests: mlxsw: spectrum: q_in_vni_veto: Disable IPv6 autogen on a bridge In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks vetoing of a different aspect of the configuration and the bridge does not need to participate in routing traffic. The IP address or the RIF are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridge in this selftest, thus exempting it from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh index f0443b1b05b9..60753d46a2d4 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/q_in_vni_veto.sh @@ -34,6 +34,7 @@ create_vxlan_on_top_of_8021ad_bridge() ip link add dev br0 type bridge vlan_filtering 1 vlan_protocol 802.1ad \ vlan_default_pvid 0 mcast_snooping 0 + ip link set dev br0 addrgenmode none ip link set dev br0 up ip link add name vx100 type vxlan id 1000 local 192.0.2.17 dstport \ -- cgit v1.2.3 From 5541577521cc2e22bc84ba92be24959671006283 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:56:01 +0200 Subject: selftests: mlxsw: vxlan: Disable IPv6 autogen on bridges In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge (this holds for all bridges used here), the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The selftest itself however checks various aspects of VXLAN offloading and the bridges do not need to participate in routing traffic. The IP addresses or the RIFs are irrelevant. Fix by disabling automatic IPv6 address generation for the HW-offloaded bridges in this selftest, thus exempting them from mlxsw router attention. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/vxlan.sh | 41 ++++++++++++++++------ 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh b/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh index 99a332b712f0..4687b0a7dffb 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/vxlan.sh @@ -444,8 +444,12 @@ offload_indication_setup_create() { # Create a simple setup with two bridges, each with a VxLAN device # and one local port - ip link add name br0 up type bridge mcast_snooping 0 - ip link add name br1 up type bridge mcast_snooping 0 + ip link add name br0 type bridge mcast_snooping 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up + ip link add name br1 type bridge mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev $swp1 master br0 ip link set dev $swp2 master br1 @@ -646,8 +650,12 @@ offload_indication_decap_route_test() RET=0 - ip link add name br0 up type bridge mcast_snooping 0 - ip link add name br1 up type bridge mcast_snooping 0 + ip link add name br0 type bridge mcast_snooping 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up + ip link add name br1 type bridge mcast_snooping 0 + ip link set dev br1 addrgenmode none + ip link set dev br1 up ip link set dev $swp1 master br0 ip link set dev $swp2 master br1 ip link set dev vxlan0 master br0 @@ -780,7 +788,9 @@ __offload_indication_join_vxlan_first() offload_indication_join_vxlan_first() { - ip link add dev br0 up type bridge mcast_snooping 0 + ip link add dev br0 type bridge mcast_snooping 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -815,7 +825,9 @@ __offload_indication_join_vxlan_last() offload_indication_join_vxlan_last() { - ip link add dev br0 up type bridge mcast_snooping 0 + ip link add dev br0 type bridge mcast_snooping 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -842,6 +854,7 @@ sanitization_vlan_aware_test() RET=0 ip link add dev br0 type bridge mcast_snooping 0 vlan_filtering 1 + ip link set dev br0 addrgenmode none ip link add name vxlan10 up master br0 type vxlan id 10 nolearning \ $UDPCSUM_FLAFS ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -915,8 +928,10 @@ offload_indication_vlan_aware_setup_create() { # Create a simple setup with two VxLAN devices and a single VLAN-aware # bridge - ip link add name br0 up type bridge mcast_snooping 0 vlan_filtering 1 \ + ip link add name br0 type bridge mcast_snooping 0 vlan_filtering 1 \ vlan_default_pvid 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link set dev $swp1 master br0 @@ -1060,8 +1075,10 @@ offload_indication_vlan_aware_decap_route_test() offload_indication_vlan_aware_join_vxlan_first() { - ip link add dev br0 up type bridge mcast_snooping 0 \ + ip link add dev br0 type bridge mcast_snooping 0 \ vlan_filtering 1 vlan_default_pvid 1 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -1073,8 +1090,10 @@ offload_indication_vlan_aware_join_vxlan_first() offload_indication_vlan_aware_join_vxlan_last() { - ip link add dev br0 up type bridge mcast_snooping 0 \ + ip link add dev br0 type bridge mcast_snooping 0 \ vlan_filtering 1 vlan_default_pvid 1 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 @@ -1091,8 +1110,10 @@ offload_indication_vlan_aware_l3vni_test() RET=0 sysctl_set net.ipv6.conf.default.disable_ipv6 1 - ip link add dev br0 up type bridge mcast_snooping 0 \ + ip link add dev br0 type bridge mcast_snooping 0 \ vlan_filtering 1 vlan_default_pvid 0 + ip link set dev br0 addrgenmode none + ip link set dev br0 up ip link add name vxlan0 up type vxlan id 10 nolearning $UDPCSUM_FLAFS \ ttl 20 tos inherit local $LOCAL_IP_1 dstport 4789 -- cgit v1.2.3 From 664bc72dd20073be227f9e68b3db75313c6926f8 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 20 Jun 2023 15:56:02 +0200 Subject: selftests: mlxsw: one_armed_router: Use port MAC for bridge address In a future patch, mlxsw will start adding RIFs to uppers of front panel port netdevices, if they have an IP address. At the time that the front panel port is enslaved to the bridge, the bridge MAC address does not have the same prefix as other interfaces in the system. On Nvidia Spectrum-1 machines all the RIFs have to have the same 38-bit MAC address prefix. Since the bridge does not obey this limitation, the RIF cannot be created, and the enslavement attempt is vetoed on the grounds of the configuration not being offloadable. The bridge eventually inherits MAC address from its first member, after the enslavement is acked. A number of (mainly VXLAN) selftests already work around the problem by setting the MAC address to whatever it will eventually be anyway. Do the same for this selftest. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Signed-off-by: Jakub Kicinski --- tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh b/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh index f02d83e94576..fca0e1e642c6 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/one_armed_router.sh @@ -83,7 +83,8 @@ h2_destroy() switch_create() { - ip link add name br0 type bridge mcast_snooping 0 + ip link add name br0 address $(mac_get $swp1) \ + type bridge mcast_snooping 0 ip link set dev br0 up ip link set dev $swp1 master br0 -- cgit v1.2.3 From 7ad7b7023fcb1efdd71406ff7670ef6130de65a6 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Tue, 20 Jun 2023 16:48:55 +0200 Subject: bnxt_en: Link representors to PCI device Link VF representors to parent PCI device to benefit from systemd defined naming scheme. Without this change the representor is visible as ethN. Signed-off-by: Ivan Vecera Reviewed-by: Simon Horman Reviewed-by: Michael Chan Link: https://lore.kernel.org/r/20230620144855.288443-1-ivecera@redhat.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c index 2f1a1f2d2157..1467b94a6427 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c @@ -468,6 +468,7 @@ static void bnxt_vf_rep_netdev_init(struct bnxt *bp, struct bnxt_vf_rep *vf_rep, struct net_device *pf_dev = bp->dev; u16 max_mtu; + SET_NETDEV_DEV(dev, &bp->pdev->dev); dev->netdev_ops = &bnxt_vf_rep_netdev_ops; dev->ethtool_ops = &bnxt_vf_rep_ethtool_ops; /* Just inherit all the featues of the parent PF as the VF-R -- cgit v1.2.3 From d5e01266e7f5fa12400d4c8aa4e86fe89dcc61e9 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 19 Jun 2023 22:46:58 +0200 Subject: leds: trigger: netdev: add additional specific link speed mode Add additional modes for specific link speed. Use ethtool APIs to get the current link speed and enable the LED accordingly. Under netdev event handler the rtnl lock is already held and is not needed to be set to access ethtool APIs. This is especially useful for PHY and Switch that supports LEDs hw control for specific link speed. (example scenario a PHY that have 2 LED connected one green and one orange where the green is turned on with 1000mbps speed and orange is turned on with 10mpbs speed) On mode set from sysfs we check if we have enabled split link speed mode and reject enabling generic link mode to prevent wrong and redundant configuration. Rework logic on the set baseline state to support these new modes to select if we need to turn on or off the LED. Add additional modes: - link_10: Turn on LED when link speed is 10mbps - link_100: Turn on LED when link speed is 100mbps - link_1000: Turn on LED when link speed is 1000mbps Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Acked-by: Lee Jones Signed-off-by: Jakub Kicinski --- drivers/leds/trigger/ledtrig-netdev.c | 80 ++++++++++++++++++++++++++++++----- include/linux/leds.h | 3 ++ 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 2311dae7f070..f625738392bf 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include "../leds.h" @@ -52,6 +54,8 @@ struct led_netdev_data { unsigned int last_activity; unsigned long mode; + int link_speed; + bool carrier_link_up; bool hw_control; }; @@ -77,7 +81,24 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) if (!trigger_data->carrier_link_up) { led_set_brightness(led_cdev, LED_OFF); } else { + bool blink_on = false; + if (test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode)) + blink_on = true; + + if (test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) && + trigger_data->link_speed == SPEED_10) + blink_on = true; + + if (test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) && + trigger_data->link_speed == SPEED_100) + blink_on = true; + + if (test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) && + trigger_data->link_speed == SPEED_1000) + blink_on = true; + + if (blink_on) led_set_brightness(led_cdev, led_cdev->blink_brightness); else @@ -161,6 +182,18 @@ static bool can_hw_control(struct led_netdev_data *trigger_data) return true; } +static void get_device_state(struct led_netdev_data *trigger_data) +{ + struct ethtool_link_ksettings cmd; + + trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev); + if (!trigger_data->carrier_link_up) + return; + + if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) + trigger_data->link_speed = cmd.base.speed; +} + static ssize_t device_name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -196,8 +229,12 @@ static int set_device_name(struct led_netdev_data *trigger_data, dev_get_by_name(&init_net, trigger_data->device_name); trigger_data->carrier_link_up = false; - if (trigger_data->net_dev != NULL) - trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev); + trigger_data->link_speed = SPEED_UNKNOWN; + if (trigger_data->net_dev != NULL) { + rtnl_lock(); + get_device_state(trigger_data); + rtnl_unlock(); + } trigger_data->last_activity = 0; @@ -234,6 +271,9 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf, switch (attr) { case TRIGGER_NETDEV_LINK: + case TRIGGER_NETDEV_LINK_10: + case TRIGGER_NETDEV_LINK_100: + case TRIGGER_NETDEV_LINK_1000: case TRIGGER_NETDEV_TX: case TRIGGER_NETDEV_RX: bit = attr; @@ -249,7 +289,7 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, size_t size, enum led_trigger_netdev_modes attr) { struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); - unsigned long state; + unsigned long state, mode = trigger_data->mode; int ret; int bit; @@ -259,6 +299,9 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, switch (attr) { case TRIGGER_NETDEV_LINK: + case TRIGGER_NETDEV_LINK_10: + case TRIGGER_NETDEV_LINK_100: + case TRIGGER_NETDEV_LINK_1000: case TRIGGER_NETDEV_TX: case TRIGGER_NETDEV_RX: bit = attr; @@ -267,13 +310,20 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, return -EINVAL; } - cancel_delayed_work_sync(&trigger_data->work); - if (state) - set_bit(bit, &trigger_data->mode); + set_bit(bit, &mode); else - clear_bit(bit, &trigger_data->mode); + clear_bit(bit, &mode); + + if (test_bit(TRIGGER_NETDEV_LINK, &mode) && + (test_bit(TRIGGER_NETDEV_LINK_10, &mode) || + test_bit(TRIGGER_NETDEV_LINK_100, &mode) || + test_bit(TRIGGER_NETDEV_LINK_1000, &mode))) + return -EINVAL; + + cancel_delayed_work_sync(&trigger_data->work); + trigger_data->mode = mode; trigger_data->hw_control = can_hw_control(trigger_data); set_baseline_state(trigger_data); @@ -295,6 +345,9 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, static DEVICE_ATTR_RW(trigger_name) DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK); +DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10); +DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100); +DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000); DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX); DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX); @@ -338,6 +391,9 @@ static DEVICE_ATTR_RW(interval); static struct attribute *netdev_trig_attrs[] = { &dev_attr_device_name.attr, &dev_attr_link.attr, + &dev_attr_link_10.attr, + &dev_attr_link_100.attr, + &dev_attr_link_1000.attr, &dev_attr_rx.attr, &dev_attr_tx.attr, &dev_attr_interval.attr, @@ -368,9 +424,10 @@ static int netdev_trig_notify(struct notifier_block *nb, mutex_lock(&trigger_data->lock); trigger_data->carrier_link_up = false; + trigger_data->link_speed = SPEED_UNKNOWN; switch (evt) { case NETDEV_CHANGENAME: - trigger_data->carrier_link_up = netif_carrier_ok(dev); + get_device_state(trigger_data); fallthrough; case NETDEV_REGISTER: if (trigger_data->net_dev) @@ -384,7 +441,7 @@ static int netdev_trig_notify(struct notifier_block *nb, break; case NETDEV_UP: case NETDEV_CHANGE: - trigger_data->carrier_link_up = netif_carrier_ok(dev); + get_device_state(trigger_data); break; } @@ -427,7 +484,10 @@ static void netdev_trig_work(struct work_struct *work) if (trigger_data->last_activity != new_activity) { led_stop_software_blink(trigger_data->led_cdev); - invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode); + invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode); interval = jiffies_to_msecs( atomic_read(&trigger_data->interval)); /* base state is ON (link present) */ diff --git a/include/linux/leds.h b/include/linux/leds.h index 8af62ff431f0..126b79019429 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -555,6 +555,9 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev) /* Trigger specific enum */ enum led_trigger_netdev_modes { TRIGGER_NETDEV_LINK = 0, + TRIGGER_NETDEV_LINK_10, + TRIGGER_NETDEV_LINK_100, + TRIGGER_NETDEV_LINK_1000, TRIGGER_NETDEV_TX, TRIGGER_NETDEV_RX, -- cgit v1.2.3 From f22f95b9ff1551c9bab13104131929f33d51f23f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 19 Jun 2023 22:46:59 +0200 Subject: leds: trigger: netdev: add additional specific link duplex mode Add additional modes for specific link duplex. Use ethtool APIs to get the current link duplex and enable the LED accordingly. Under netdev event handler the rtnl lock is already held and is not needed to be set to access ethtool APIs. This is especially useful for PHY and Switch that supports LEDs hw control for specific link duplex. Add additional modes: - half_duplex: Turn on LED when link is half duplex - full_duplex: Turn on LED when link is full duplex Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Acked-by: Lee Jones Signed-off-by: Jakub Kicinski --- drivers/leds/trigger/ledtrig-netdev.c | 27 +++++++++++++++++++++++++-- include/linux/leds.h | 2 ++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index f625738392bf..2c1c9e95860e 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -55,6 +55,7 @@ struct led_netdev_data { unsigned long mode; int link_speed; + u8 duplex; bool carrier_link_up; bool hw_control; @@ -98,6 +99,14 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) trigger_data->link_speed == SPEED_1000) blink_on = true; + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) && + trigger_data->duplex == DUPLEX_HALF) + blink_on = true; + + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode) && + trigger_data->duplex == DUPLEX_FULL) + blink_on = true; + if (blink_on) led_set_brightness(led_cdev, led_cdev->blink_brightness); @@ -190,8 +199,10 @@ static void get_device_state(struct led_netdev_data *trigger_data) if (!trigger_data->carrier_link_up) return; - if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) + if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) { trigger_data->link_speed = cmd.base.speed; + trigger_data->duplex = cmd.base.duplex; + } } static ssize_t device_name_show(struct device *dev, @@ -230,6 +241,7 @@ static int set_device_name(struct led_netdev_data *trigger_data, trigger_data->carrier_link_up = false; trigger_data->link_speed = SPEED_UNKNOWN; + trigger_data->duplex = DUPLEX_UNKNOWN; if (trigger_data->net_dev != NULL) { rtnl_lock(); get_device_state(trigger_data); @@ -274,6 +286,8 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf, case TRIGGER_NETDEV_LINK_10: case TRIGGER_NETDEV_LINK_100: case TRIGGER_NETDEV_LINK_1000: + case TRIGGER_NETDEV_HALF_DUPLEX: + case TRIGGER_NETDEV_FULL_DUPLEX: case TRIGGER_NETDEV_TX: case TRIGGER_NETDEV_RX: bit = attr; @@ -302,6 +316,8 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf, case TRIGGER_NETDEV_LINK_10: case TRIGGER_NETDEV_LINK_100: case TRIGGER_NETDEV_LINK_1000: + case TRIGGER_NETDEV_HALF_DUPLEX: + case TRIGGER_NETDEV_FULL_DUPLEX: case TRIGGER_NETDEV_TX: case TRIGGER_NETDEV_RX: bit = attr; @@ -348,6 +364,8 @@ DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK); DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10); DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100); DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000); +DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX); +DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX); DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX); DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX); @@ -394,6 +412,8 @@ static struct attribute *netdev_trig_attrs[] = { &dev_attr_link_10.attr, &dev_attr_link_100.attr, &dev_attr_link_1000.attr, + &dev_attr_full_duplex.attr, + &dev_attr_half_duplex.attr, &dev_attr_rx.attr, &dev_attr_tx.attr, &dev_attr_interval.attr, @@ -425,6 +445,7 @@ static int netdev_trig_notify(struct notifier_block *nb, trigger_data->carrier_link_up = false; trigger_data->link_speed = SPEED_UNKNOWN; + trigger_data->duplex = DUPLEX_UNKNOWN; switch (evt) { case NETDEV_CHANGENAME: get_device_state(trigger_data); @@ -487,7 +508,9 @@ static void netdev_trig_work(struct work_struct *work) invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode) || test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) || test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) || - test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode); + test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) || + test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode); interval = jiffies_to_msecs( atomic_read(&trigger_data->interval)); /* base state is ON (link present) */ diff --git a/include/linux/leds.h b/include/linux/leds.h index 126b79019429..3a65ff72bb04 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -558,6 +558,8 @@ enum led_trigger_netdev_modes { TRIGGER_NETDEV_LINK_10, TRIGGER_NETDEV_LINK_100, TRIGGER_NETDEV_LINK_1000, + TRIGGER_NETDEV_HALF_DUPLEX, + TRIGGER_NETDEV_FULL_DUPLEX, TRIGGER_NETDEV_TX, TRIGGER_NETDEV_RX, -- cgit v1.2.3 From b655892ffd6d89b0c7407e099c40dbde82ee3f03 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 19 Jun 2023 22:47:00 +0200 Subject: leds: trigger: netdev: expose hw_control status via sysfs Expose hw_control status via sysfs for the netdev trigger to give userspace better understanding of the current state of the trigger and the LED. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Reviewed-by: Kalesh AP Acked-by: Lee Jones Signed-off-by: Jakub Kicinski --- drivers/leds/trigger/ledtrig-netdev.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index 2c1c9e95860e..32b66703068a 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -406,6 +406,16 @@ static ssize_t interval_store(struct device *dev, static DEVICE_ATTR_RW(interval); +static ssize_t hw_control_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); + + return sprintf(buf, "%d\n", trigger_data->hw_control); +} + +static DEVICE_ATTR_RO(hw_control); + static struct attribute *netdev_trig_attrs[] = { &dev_attr_device_name.attr, &dev_attr_link.attr, @@ -417,6 +427,7 @@ static struct attribute *netdev_trig_attrs[] = { &dev_attr_rx.attr, &dev_attr_tx.attr, &dev_attr_interval.attr, + &dev_attr_hw_control.attr, NULL }; ATTRIBUTE_GROUPS(netdev_trig); -- cgit v1.2.3 From 6e98730bc0b44acaf86eccc75f823128aa9c9e79 Mon Sep 17 00:00:00 2001 From: Gilad Sever Date: Wed, 21 Jun 2023 13:42:08 +0300 Subject: bpf: Factor out socket lookup functions for the TC hookpoint. Change BPF helper socket lookup functions to use TC specific variants: bpf_tc_sk_lookup_tcp() / bpf_tc_sk_lookup_udp() / bpf_tc_skc_lookup_tcp() instead of sharing implementation with the cg / sk_skb hooking points. This allows introducing a separate logic for the TC flow. The tc functions are identical to the original code. Signed-off-by: Gilad Sever Signed-off-by: Daniel Borkmann Reviewed-by: Shmulik Ladkani Reviewed-by: Eyal Birger Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230621104211.301902-2-gilad9366@gmail.com --- net/core/filter.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 428df050d021..11e2afbfdce9 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -6740,6 +6740,63 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = { .arg5_type = ARG_ANYTHING, }; +BPF_CALL_5(bpf_tc_skc_lookup_tcp, struct sk_buff *, skb, + struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) +{ + return (unsigned long)bpf_skc_lookup(skb, tuple, len, IPPROTO_TCP, + netns_id, flags); +} + +static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = { + .func = bpf_tc_skc_lookup_tcp, + .gpl_only = false, + .pkt_access = true, + .ret_type = RET_PTR_TO_SOCK_COMMON_OR_NULL, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + .arg5_type = ARG_ANYTHING, +}; + +BPF_CALL_5(bpf_tc_sk_lookup_tcp, struct sk_buff *, skb, + struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) +{ + return (unsigned long)bpf_sk_lookup(skb, tuple, len, IPPROTO_TCP, + netns_id, flags); +} + +static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = { + .func = bpf_tc_sk_lookup_tcp, + .gpl_only = false, + .pkt_access = true, + .ret_type = RET_PTR_TO_SOCKET_OR_NULL, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + .arg5_type = ARG_ANYTHING, +}; + +BPF_CALL_5(bpf_tc_sk_lookup_udp, struct sk_buff *, skb, + struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) +{ + return (unsigned long)bpf_sk_lookup(skb, tuple, len, IPPROTO_UDP, + netns_id, flags); +} + +static const struct bpf_func_proto bpf_tc_sk_lookup_udp_proto = { + .func = bpf_tc_sk_lookup_udp, + .gpl_only = false, + .pkt_access = true, + .ret_type = RET_PTR_TO_SOCKET_OR_NULL, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_ANYTHING, + .arg5_type = ARG_ANYTHING, +}; + BPF_CALL_1(bpf_sk_release, struct sock *, sk) { if (sk && sk_is_refcounted(sk)) @@ -7995,9 +8052,9 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) #endif #ifdef CONFIG_INET case BPF_FUNC_sk_lookup_tcp: - return &bpf_sk_lookup_tcp_proto; + return &bpf_tc_sk_lookup_tcp_proto; case BPF_FUNC_sk_lookup_udp: - return &bpf_sk_lookup_udp_proto; + return &bpf_tc_sk_lookup_udp_proto; case BPF_FUNC_sk_release: return &bpf_sk_release_proto; case BPF_FUNC_tcp_sock: @@ -8005,7 +8062,7 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_get_listener_sock: return &bpf_get_listener_sock_proto; case BPF_FUNC_skc_lookup_tcp: - return &bpf_skc_lookup_tcp_proto; + return &bpf_tc_skc_lookup_tcp_proto; case BPF_FUNC_tcp_check_syncookie: return &bpf_tcp_check_syncookie_proto; case BPF_FUNC_skb_ecn_set_ce: -- cgit v1.2.3 From 97fbfeb86917bdbe9c41d5143e335a929147f405 Mon Sep 17 00:00:00 2001 From: Gilad Sever Date: Wed, 21 Jun 2023 13:42:09 +0300 Subject: bpf: Call __bpf_sk_lookup()/__bpf_skc_lookup() directly via TC hookpoint skb->dev always exists in the tc flow. There is no need to use bpf_skc_lookup(), bpf_sk_lookup() from this code path. This change facilitates fixing the tc flow to be VRF aware. Signed-off-by: Gilad Sever Signed-off-by: Daniel Borkmann Reviewed-by: Shmulik Ladkani Reviewed-by: Eyal Birger Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230621104211.301902-3-gilad9366@gmail.com --- net/core/filter.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index 11e2afbfdce9..a9fb897822b2 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -6743,8 +6743,12 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = { BPF_CALL_5(bpf_tc_skc_lookup_tcp, struct sk_buff *, skb, struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) { - return (unsigned long)bpf_skc_lookup(skb, tuple, len, IPPROTO_TCP, - netns_id, flags); + struct net *caller_net = dev_net(skb->dev); + int ifindex = skb->dev->ifindex; + + return (unsigned long)__bpf_skc_lookup(skb, tuple, len, caller_net, + ifindex, IPPROTO_TCP, netns_id, + flags); } static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = { @@ -6762,8 +6766,12 @@ static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = { BPF_CALL_5(bpf_tc_sk_lookup_tcp, struct sk_buff *, skb, struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) { - return (unsigned long)bpf_sk_lookup(skb, tuple, len, IPPROTO_TCP, - netns_id, flags); + struct net *caller_net = dev_net(skb->dev); + int ifindex = skb->dev->ifindex; + + return (unsigned long)__bpf_sk_lookup(skb, tuple, len, caller_net, + ifindex, IPPROTO_TCP, netns_id, + flags); } static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = { @@ -6781,8 +6789,12 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = { BPF_CALL_5(bpf_tc_sk_lookup_udp, struct sk_buff *, skb, struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) { - return (unsigned long)bpf_sk_lookup(skb, tuple, len, IPPROTO_UDP, - netns_id, flags); + struct net *caller_net = dev_net(skb->dev); + int ifindex = skb->dev->ifindex; + + return (unsigned long)__bpf_sk_lookup(skb, tuple, len, caller_net, + ifindex, IPPROTO_UDP, netns_id, + flags); } static const struct bpf_func_proto bpf_tc_sk_lookup_udp_proto = { -- cgit v1.2.3 From 9a5cb79762e0eda17ca15c2a6eaca4622383c21c Mon Sep 17 00:00:00 2001 From: Gilad Sever Date: Wed, 21 Jun 2023 13:42:10 +0300 Subject: bpf: Fix bpf socket lookup from tc/xdp to respect socket VRF bindings When calling bpf_sk_lookup_tcp(), bpf_sk_lookup_udp() or bpf_skc_lookup_tcp() from tc/xdp ingress, VRF socket bindings aren't respoected, i.e. unbound sockets are returned, and bound sockets aren't found. VRF binding is determined by the sdif argument to sk_lookup(), however when called from tc the IP SKB control block isn't initialized and thus inet{,6}_sdif() always returns 0. Fix by calculating sdif for the tc/xdp flows by observing the device's l3 enslaved state. The cg/sk_skb hooking points which are expected to support inet{,6}_sdif() pass sdif=-1 which makes __bpf_skc_lookup() use the existing logic. Fixes: 6acc9b432e67 ("bpf: Add helper to retrieve socket in BPF") Signed-off-by: Gilad Sever Signed-off-by: Daniel Borkmann Reviewed-by: Shmulik Ladkani Reviewed-by: Eyal Birger Acked-by: Stanislav Fomichev Cc: David Ahern Link: https://lore.kernel.org/bpf/20230621104211.301902-4-gilad9366@gmail.com --- include/linux/netdevice.h | 9 +++++++ net/core/filter.c | 69 ++++++++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 08fbd4622ccf..8c95ebbcf203 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -5090,6 +5090,15 @@ static inline bool netif_is_l3_slave(const struct net_device *dev) return dev->priv_flags & IFF_L3MDEV_SLAVE; } +static inline int dev_sdif(const struct net_device *dev) +{ +#ifdef CONFIG_NET_L3_MASTER_DEV + if (netif_is_l3_slave(dev)) + return dev->ifindex; +#endif + return 0; +} + static inline bool netif_is_bridge_master(const struct net_device *dev) { return dev->priv_flags & IFF_EBRIDGE; diff --git a/net/core/filter.c b/net/core/filter.c index a9fb897822b2..06ba0e56e369 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -6568,12 +6568,11 @@ static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, static struct sock * __bpf_skc_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, struct net *caller_net, u32 ifindex, u8 proto, u64 netns_id, - u64 flags) + u64 flags, int sdif) { struct sock *sk = NULL; struct net *net; u8 family; - int sdif; if (len == sizeof(tuple->ipv4)) family = AF_INET; @@ -6585,10 +6584,12 @@ __bpf_skc_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, if (unlikely(flags || !((s32)netns_id < 0 || netns_id <= S32_MAX))) goto out; - if (family == AF_INET) - sdif = inet_sdif(skb); - else - sdif = inet6_sdif(skb); + if (sdif < 0) { + if (family == AF_INET) + sdif = inet_sdif(skb); + else + sdif = inet6_sdif(skb); + } if ((s32)netns_id < 0) { net = caller_net; @@ -6608,10 +6609,11 @@ out: static struct sock * __bpf_sk_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, struct net *caller_net, u32 ifindex, u8 proto, u64 netns_id, - u64 flags) + u64 flags, int sdif) { struct sock *sk = __bpf_skc_lookup(skb, tuple, len, caller_net, - ifindex, proto, netns_id, flags); + ifindex, proto, netns_id, flags, + sdif); if (sk) { struct sock *sk2 = sk_to_full_sk(sk); @@ -6651,7 +6653,7 @@ bpf_skc_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, } return __bpf_skc_lookup(skb, tuple, len, caller_net, ifindex, proto, - netns_id, flags); + netns_id, flags, -1); } static struct sock * @@ -6743,12 +6745,13 @@ static const struct bpf_func_proto bpf_sk_lookup_udp_proto = { BPF_CALL_5(bpf_tc_skc_lookup_tcp, struct sk_buff *, skb, struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) { - struct net *caller_net = dev_net(skb->dev); - int ifindex = skb->dev->ifindex; + struct net_device *dev = skb->dev; + int ifindex = dev->ifindex, sdif = dev_sdif(dev); + struct net *caller_net = dev_net(dev); return (unsigned long)__bpf_skc_lookup(skb, tuple, len, caller_net, ifindex, IPPROTO_TCP, netns_id, - flags); + flags, sdif); } static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = { @@ -6766,12 +6769,13 @@ static const struct bpf_func_proto bpf_tc_skc_lookup_tcp_proto = { BPF_CALL_5(bpf_tc_sk_lookup_tcp, struct sk_buff *, skb, struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) { - struct net *caller_net = dev_net(skb->dev); - int ifindex = skb->dev->ifindex; + struct net_device *dev = skb->dev; + int ifindex = dev->ifindex, sdif = dev_sdif(dev); + struct net *caller_net = dev_net(dev); return (unsigned long)__bpf_sk_lookup(skb, tuple, len, caller_net, ifindex, IPPROTO_TCP, netns_id, - flags); + flags, sdif); } static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = { @@ -6789,12 +6793,13 @@ static const struct bpf_func_proto bpf_tc_sk_lookup_tcp_proto = { BPF_CALL_5(bpf_tc_sk_lookup_udp, struct sk_buff *, skb, struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) { - struct net *caller_net = dev_net(skb->dev); - int ifindex = skb->dev->ifindex; + struct net_device *dev = skb->dev; + int ifindex = dev->ifindex, sdif = dev_sdif(dev); + struct net *caller_net = dev_net(dev); return (unsigned long)__bpf_sk_lookup(skb, tuple, len, caller_net, ifindex, IPPROTO_UDP, netns_id, - flags); + flags, sdif); } static const struct bpf_func_proto bpf_tc_sk_lookup_udp_proto = { @@ -6826,12 +6831,13 @@ static const struct bpf_func_proto bpf_sk_release_proto = { BPF_CALL_5(bpf_xdp_sk_lookup_udp, struct xdp_buff *, ctx, struct bpf_sock_tuple *, tuple, u32, len, u32, netns_id, u64, flags) { - struct net *caller_net = dev_net(ctx->rxq->dev); - int ifindex = ctx->rxq->dev->ifindex; + struct net_device *dev = ctx->rxq->dev; + int ifindex = dev->ifindex, sdif = dev_sdif(dev); + struct net *caller_net = dev_net(dev); return (unsigned long)__bpf_sk_lookup(NULL, tuple, len, caller_net, ifindex, IPPROTO_UDP, netns_id, - flags); + flags, sdif); } static const struct bpf_func_proto bpf_xdp_sk_lookup_udp_proto = { @@ -6849,12 +6855,13 @@ static const struct bpf_func_proto bpf_xdp_sk_lookup_udp_proto = { BPF_CALL_5(bpf_xdp_skc_lookup_tcp, struct xdp_buff *, ctx, struct bpf_sock_tuple *, tuple, u32, len, u32, netns_id, u64, flags) { - struct net *caller_net = dev_net(ctx->rxq->dev); - int ifindex = ctx->rxq->dev->ifindex; + struct net_device *dev = ctx->rxq->dev; + int ifindex = dev->ifindex, sdif = dev_sdif(dev); + struct net *caller_net = dev_net(dev); return (unsigned long)__bpf_skc_lookup(NULL, tuple, len, caller_net, ifindex, IPPROTO_TCP, netns_id, - flags); + flags, sdif); } static const struct bpf_func_proto bpf_xdp_skc_lookup_tcp_proto = { @@ -6872,12 +6879,13 @@ static const struct bpf_func_proto bpf_xdp_skc_lookup_tcp_proto = { BPF_CALL_5(bpf_xdp_sk_lookup_tcp, struct xdp_buff *, ctx, struct bpf_sock_tuple *, tuple, u32, len, u32, netns_id, u64, flags) { - struct net *caller_net = dev_net(ctx->rxq->dev); - int ifindex = ctx->rxq->dev->ifindex; + struct net_device *dev = ctx->rxq->dev; + int ifindex = dev->ifindex, sdif = dev_sdif(dev); + struct net *caller_net = dev_net(dev); return (unsigned long)__bpf_sk_lookup(NULL, tuple, len, caller_net, ifindex, IPPROTO_TCP, netns_id, - flags); + flags, sdif); } static const struct bpf_func_proto bpf_xdp_sk_lookup_tcp_proto = { @@ -6897,7 +6905,8 @@ BPF_CALL_5(bpf_sock_addr_skc_lookup_tcp, struct bpf_sock_addr_kern *, ctx, { return (unsigned long)__bpf_skc_lookup(NULL, tuple, len, sock_net(ctx->sk), 0, - IPPROTO_TCP, netns_id, flags); + IPPROTO_TCP, netns_id, flags, + -1); } static const struct bpf_func_proto bpf_sock_addr_skc_lookup_tcp_proto = { @@ -6916,7 +6925,7 @@ BPF_CALL_5(bpf_sock_addr_sk_lookup_tcp, struct bpf_sock_addr_kern *, ctx, { return (unsigned long)__bpf_sk_lookup(NULL, tuple, len, sock_net(ctx->sk), 0, IPPROTO_TCP, - netns_id, flags); + netns_id, flags, -1); } static const struct bpf_func_proto bpf_sock_addr_sk_lookup_tcp_proto = { @@ -6935,7 +6944,7 @@ BPF_CALL_5(bpf_sock_addr_sk_lookup_udp, struct bpf_sock_addr_kern *, ctx, { return (unsigned long)__bpf_sk_lookup(NULL, tuple, len, sock_net(ctx->sk), 0, IPPROTO_UDP, - netns_id, flags); + netns_id, flags, -1); } static const struct bpf_func_proto bpf_sock_addr_sk_lookup_udp_proto = { -- cgit v1.2.3 From 3d5786ea472c3aff14e931d52ba05627c075d432 Mon Sep 17 00:00:00 2001 From: Gilad Sever Date: Wed, 21 Jun 2023 13:42:11 +0300 Subject: selftests/bpf: Add vrf_socket_lookup tests Verify that socket lookup via TC/XDP with all BPF APIs is VRF aware. Signed-off-by: Gilad Sever Signed-off-by: Daniel Borkmann Reviewed-by: Eyal Birger Acked-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20230621104211.301902-5-gilad9366@gmail.com --- .../selftests/bpf/prog_tests/vrf_socket_lookup.c | 312 +++++++++++++++++++++ .../selftests/bpf/progs/vrf_socket_lookup.c | 88 ++++++ 2 files changed, 400 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/vrf_socket_lookup.c create mode 100644 tools/testing/selftests/bpf/progs/vrf_socket_lookup.c diff --git a/tools/testing/selftests/bpf/prog_tests/vrf_socket_lookup.c b/tools/testing/selftests/bpf/prog_tests/vrf_socket_lookup.c new file mode 100644 index 000000000000..2a5e207edad6 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/vrf_socket_lookup.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +/* + * Topology: + * --------- + * NS0 namespace | NS1 namespace + * | + * +--------------+ | +--------------+ + * | veth01 |----------| veth10 | + * | 172.16.1.100 | | | 172.16.1.200 | + * | bpf | | +--------------+ + * +--------------+ | + * server(UDP/TCP) | + * +-------------------+ | + * | vrf1 | | + * | +--------------+ | | +--------------+ + * | | veth02 |----------| veth20 | + * | | 172.16.2.100 | | | | 172.16.2.200 | + * | | bpf | | | +--------------+ + * | +--------------+ | | + * | server(UDP/TCP) | | + * +-------------------+ | + * + * Test flow + * ----------- + * The tests verifies that socket lookup via TC is VRF aware: + * 1) Creates two veth pairs between NS0 and NS1: + * a) veth01 <-> veth10 outside the VRF + * b) veth02 <-> veth20 in the VRF + * 2) Attaches to veth01 and veth02 a program that calls: + * a) bpf_skc_lookup_tcp() with TCP and tcp_skc is true + * b) bpf_sk_lookup_tcp() with TCP and tcp_skc is false + * c) bpf_sk_lookup_udp() with UDP + * The program stores the lookup result in bss->lookup_status. + * 3) Creates a socket TCP/UDP server in/outside the VRF. + * 4) The test expects lookup_status to be: + * a) 0 from device in VRF to server outside VRF + * b) 0 from device outside VRF to server in VRF + * c) 1 from device in VRF to server in VRF + * d) 1 from device outside VRF to server outside VRF + */ + +#include + +#include "test_progs.h" +#include "network_helpers.h" +#include "vrf_socket_lookup.skel.h" + +#define NS0 "vrf_socket_lookup_0" +#define NS1 "vrf_socket_lookup_1" + +#define IP4_ADDR_VETH01 "172.16.1.100" +#define IP4_ADDR_VETH10 "172.16.1.200" +#define IP4_ADDR_VETH02 "172.16.2.100" +#define IP4_ADDR_VETH20 "172.16.2.200" + +#define NON_VRF_PORT 5000 +#define IN_VRF_PORT 5001 + +#define TIMEOUT_MS 3000 + +static int make_socket(int sotype, const char *ip, int port, + struct sockaddr_storage *addr) +{ + int err, fd; + + err = make_sockaddr(AF_INET, ip, port, addr, NULL); + if (!ASSERT_OK(err, "make_address")) + return -1; + + fd = socket(AF_INET, sotype, 0); + if (!ASSERT_GE(fd, 0, "socket")) + return -1; + + if (!ASSERT_OK(settimeo(fd, TIMEOUT_MS), "settimeo")) + goto fail; + + return fd; +fail: + close(fd); + return -1; +} + +static int make_server(int sotype, const char *ip, int port, const char *ifname) +{ + int err, fd = -1; + + fd = start_server(AF_INET, sotype, ip, port, TIMEOUT_MS); + if (!ASSERT_GE(fd, 0, "start_server")) + return -1; + + if (ifname) { + err = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, + ifname, strlen(ifname) + 1); + if (!ASSERT_OK(err, "setsockopt(SO_BINDTODEVICE)")) + goto fail; + } + + return fd; +fail: + close(fd); + return -1; +} + +static int attach_progs(char *ifname, int tc_prog_fd, int xdp_prog_fd) +{ + LIBBPF_OPTS(bpf_tc_hook, hook, .attach_point = BPF_TC_INGRESS); + LIBBPF_OPTS(bpf_tc_opts, opts, .handle = 1, .priority = 1, + .prog_fd = tc_prog_fd); + int ret, ifindex; + + ifindex = if_nametoindex(ifname); + if (!ASSERT_NEQ(ifindex, 0, "if_nametoindex")) + return -1; + hook.ifindex = ifindex; + + ret = bpf_tc_hook_create(&hook); + if (!ASSERT_OK(ret, "bpf_tc_hook_create")) + return ret; + + ret = bpf_tc_attach(&hook, &opts); + if (!ASSERT_OK(ret, "bpf_tc_attach")) { + bpf_tc_hook_destroy(&hook); + return ret; + } + ret = bpf_xdp_attach(ifindex, xdp_prog_fd, 0, NULL); + if (!ASSERT_OK(ret, "bpf_xdp_attach")) { + bpf_tc_hook_destroy(&hook); + return ret; + } + + return 0; +} + +static void cleanup(void) +{ + SYS_NOFAIL("test -f /var/run/netns/" NS0 " && ip netns delete " + NS0); + SYS_NOFAIL("test -f /var/run/netns/" NS1 " && ip netns delete " + NS1); +} + +static int setup(struct vrf_socket_lookup *skel) +{ + int tc_prog_fd, xdp_prog_fd, ret = 0; + struct nstoken *nstoken = NULL; + + SYS(fail, "ip netns add " NS0); + SYS(fail, "ip netns add " NS1); + + /* NS0 <-> NS1 [veth01 <-> veth10] */ + SYS(fail, "ip link add veth01 netns " NS0 " type veth peer name veth10" + " netns " NS1); + SYS(fail, "ip -net " NS0 " addr add " IP4_ADDR_VETH01 "/24 dev veth01"); + SYS(fail, "ip -net " NS0 " link set dev veth01 up"); + SYS(fail, "ip -net " NS1 " addr add " IP4_ADDR_VETH10 "/24 dev veth10"); + SYS(fail, "ip -net " NS1 " link set dev veth10 up"); + + /* NS0 <-> NS1 [veth02 <-> veth20] */ + SYS(fail, "ip link add veth02 netns " NS0 " type veth peer name veth20" + " netns " NS1); + SYS(fail, "ip -net " NS0 " addr add " IP4_ADDR_VETH02 "/24 dev veth02"); + SYS(fail, "ip -net " NS0 " link set dev veth02 up"); + SYS(fail, "ip -net " NS1 " addr add " IP4_ADDR_VETH20 "/24 dev veth20"); + SYS(fail, "ip -net " NS1 " link set dev veth20 up"); + + /* veth02 -> vrf1 */ + SYS(fail, "ip -net " NS0 " link add vrf1 type vrf table 11"); + SYS(fail, "ip -net " NS0 " route add vrf vrf1 unreachable default" + " metric 4278198272"); + SYS(fail, "ip -net " NS0 " link set vrf1 alias vrf"); + SYS(fail, "ip -net " NS0 " link set vrf1 up"); + SYS(fail, "ip -net " NS0 " link set veth02 master vrf1"); + + /* Attach TC and XDP progs to veth devices in NS0 */ + nstoken = open_netns(NS0); + if (!ASSERT_OK_PTR(nstoken, "setns " NS0)) + goto fail; + tc_prog_fd = bpf_program__fd(skel->progs.tc_socket_lookup); + if (!ASSERT_GE(tc_prog_fd, 0, "bpf_program__tc_fd")) + goto fail; + xdp_prog_fd = bpf_program__fd(skel->progs.xdp_socket_lookup); + if (!ASSERT_GE(xdp_prog_fd, 0, "bpf_program__xdp_fd")) + goto fail; + + if (attach_progs("veth01", tc_prog_fd, xdp_prog_fd)) + goto fail; + + if (attach_progs("veth02", tc_prog_fd, xdp_prog_fd)) + goto fail; + + goto close; +fail: + ret = -1; +close: + if (nstoken) + close_netns(nstoken); + return ret; +} + +static int test_lookup(struct vrf_socket_lookup *skel, int sotype, + const char *ip, int port, bool test_xdp, bool tcp_skc, + int lookup_status_exp) +{ + static const char msg[] = "Hello Server"; + struct sockaddr_storage addr = {}; + int fd, ret = 0; + + fd = make_socket(sotype, ip, port, &addr); + if (fd < 0) + return -1; + + skel->bss->test_xdp = test_xdp; + skel->bss->tcp_skc = tcp_skc; + skel->bss->lookup_status = -1; + + if (sotype == SOCK_STREAM) + connect(fd, (void *)&addr, sizeof(struct sockaddr_in)); + else + sendto(fd, msg, sizeof(msg), 0, (void *)&addr, + sizeof(struct sockaddr_in)); + + if (!ASSERT_EQ(skel->bss->lookup_status, lookup_status_exp, + "lookup_status")) + goto fail; + + goto close; + +fail: + ret = -1; +close: + close(fd); + return ret; +} + +static void _test_vrf_socket_lookup(struct vrf_socket_lookup *skel, int sotype, + bool test_xdp, bool tcp_skc) +{ + int in_vrf_server = -1, non_vrf_server = -1; + struct nstoken *nstoken = NULL; + + nstoken = open_netns(NS0); + if (!ASSERT_OK_PTR(nstoken, "setns " NS0)) + goto done; + + /* Open sockets in and outside VRF */ + non_vrf_server = make_server(sotype, "0.0.0.0", NON_VRF_PORT, NULL); + if (!ASSERT_GE(non_vrf_server, 0, "make_server__outside_vrf_fd")) + goto done; + + in_vrf_server = make_server(sotype, "0.0.0.0", IN_VRF_PORT, "veth02"); + if (!ASSERT_GE(in_vrf_server, 0, "make_server__in_vrf_fd")) + goto done; + + /* Perform test from NS1 */ + close_netns(nstoken); + nstoken = open_netns(NS1); + if (!ASSERT_OK_PTR(nstoken, "setns " NS1)) + goto done; + + if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH02, NON_VRF_PORT, + test_xdp, tcp_skc, 0), "in_to_out")) + goto done; + if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH02, IN_VRF_PORT, + test_xdp, tcp_skc, 1), "in_to_in")) + goto done; + if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH01, NON_VRF_PORT, + test_xdp, tcp_skc, 1), "out_to_out")) + goto done; + if (!ASSERT_OK(test_lookup(skel, sotype, IP4_ADDR_VETH01, IN_VRF_PORT, + test_xdp, tcp_skc, 0), "out_to_in")) + goto done; + +done: + if (non_vrf_server >= 0) + close(non_vrf_server); + if (in_vrf_server >= 0) + close(in_vrf_server); + if (nstoken) + close_netns(nstoken); +} + +void test_vrf_socket_lookup(void) +{ + struct vrf_socket_lookup *skel; + + cleanup(); + + skel = vrf_socket_lookup__open_and_load(); + if (!ASSERT_OK_PTR(skel, "vrf_socket_lookup__open_and_load")) + return; + + if (!ASSERT_OK(setup(skel), "setup")) + goto done; + + if (test__start_subtest("tc_socket_lookup_tcp")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false); + if (test__start_subtest("tc_socket_lookup_tcp_skc")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false); + if (test__start_subtest("tc_socket_lookup_udp")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, false, false); + if (test__start_subtest("xdp_socket_lookup_tcp")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false); + if (test__start_subtest("xdp_socket_lookup_tcp_skc")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false); + if (test__start_subtest("xdp_socket_lookup_udp")) + _test_vrf_socket_lookup(skel, SOCK_STREAM, true, false); + +done: + vrf_socket_lookup__destroy(skel); + cleanup(); +} diff --git a/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c b/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c new file mode 100644 index 000000000000..26e07a252585 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include + +int lookup_status; +bool test_xdp; +bool tcp_skc; + +#define CUR_NS BPF_F_CURRENT_NETNS + +static void socket_lookup(void *ctx, void *data_end, void *data) +{ + struct ethhdr *eth = data; + struct bpf_sock_tuple *tp; + struct bpf_sock *sk; + struct iphdr *iph; + int tplen; + + if (eth + 1 > data_end) + return; + + if (eth->h_proto != bpf_htons(ETH_P_IP)) + return; + + iph = (struct iphdr *)(eth + 1); + if (iph + 1 > data_end) + return; + + tp = (struct bpf_sock_tuple *)&iph->saddr; + tplen = sizeof(tp->ipv4); + if ((void *)tp + tplen > data_end) + return; + + switch (iph->protocol) { + case IPPROTO_TCP: + if (tcp_skc) + sk = bpf_skc_lookup_tcp(ctx, tp, tplen, CUR_NS, 0); + else + sk = bpf_sk_lookup_tcp(ctx, tp, tplen, CUR_NS, 0); + break; + case IPPROTO_UDP: + sk = bpf_sk_lookup_udp(ctx, tp, tplen, CUR_NS, 0); + break; + default: + return; + } + + lookup_status = 0; + + if (sk) { + bpf_sk_release(sk); + lookup_status = 1; + } +} + +SEC("tc") +int tc_socket_lookup(struct __sk_buff *skb) +{ + void *data_end = (void *)(long)skb->data_end; + void *data = (void *)(long)skb->data; + + if (test_xdp) + return TC_ACT_UNSPEC; + + socket_lookup(skb, data_end, data); + return TC_ACT_UNSPEC; +} + +SEC("xdp") +int xdp_socket_lookup(struct xdp_md *xdp) +{ + void *data_end = (void *)(long)xdp->data_end; + void *data = (void *)(long)xdp->data; + + if (!test_xdp) + return XDP_PASS; + + socket_lookup(xdp, data_end, data); + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From e748d0fd66abc4b1c136022e4e053004fce2b792 Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Wed, 14 Jun 2023 17:17:10 +0530 Subject: net: hsr: Disable promiscuous mode in offload mode When port-to-port forwarding for interfaces in HSR node is enabled, disable promiscuous mode since L2 frame forward happens at the offloaded hardware. Signed-off-by: Ravi Gunasekaran Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230614114710.31400-1-r-gunasekaran@ti.com Signed-off-by: Jakub Kicinski --- net/hsr/hsr_device.c | 5 +++++ net/hsr/hsr_main.h | 1 + net/hsr/hsr_slave.c | 15 +++++++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index 5a236aae2366..306f942c3b28 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -531,6 +531,11 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], if (res) goto err_add_master; + /* HSR forwarding offload supported in lower device? */ + if ((slave[0]->features & NETIF_F_HW_HSR_FWD) && + (slave[1]->features & NETIF_F_HW_HSR_FWD)) + hsr->fwd_offloaded = true; + res = register_netdevice(hsr_dev); if (res) goto err_unregister; diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h index 5584c80a5c79..6851e33df7d1 100644 --- a/net/hsr/hsr_main.h +++ b/net/hsr/hsr_main.h @@ -208,6 +208,7 @@ struct hsr_priv { u8 net_id; /* for PRP, it occupies most significant 3 bits * of lan_id */ + bool fwd_offloaded; /* Forwarding offloaded to HW */ unsigned char sup_multicast_addr[ETH_ALEN] __aligned(sizeof(u16)); /* Align to u16 boundary to avoid unaligned access * in ether_addr_equal diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index b70e6bbf6021..e5742f2a2d52 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -131,9 +131,14 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev, struct hsr_port *master; int res; - res = dev_set_promiscuity(dev, 1); - if (res) - return res; + /* Don't use promiscuous mode for offload since L2 frame forward + * happens at the offloaded hardware. + */ + if (!port->hsr->fwd_offloaded) { + res = dev_set_promiscuity(dev, 1); + if (res) + return res; + } master = hsr_port_get_hsr(hsr, HSR_PT_MASTER); hsr_dev = master->dev; @@ -152,7 +157,9 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev, fail_rx_handler: netdev_upper_dev_unlink(dev, hsr_dev); fail_upper_dev_link: - dev_set_promiscuity(dev, -1); + if (!port->hsr->fwd_offloaded) + dev_set_promiscuity(dev, -1); + return res; } -- cgit v1.2.3 From 6a0a6dd8df9b6e9c0ed8d99bbfb4e5e2f8c9834f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 17 Jun 2023 18:57:16 +0200 Subject: dt-bindings: net: bluetooth: qualcomm: document VDD_CH1 WCN3990 comes with two chains - CH0 and CH1 - where each takes VDD regulator. It seems VDD_CH1 is optional (Linux driver does not care about it), so document it to fix dtbs_check warnings like: sdm850-lenovo-yoga-c630.dtb: bluetooth: 'vddch1-supply' does not match any of the regexes: 'pinctrl-[0-9]+' Signed-off-by: Krzysztof Kozlowski Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20230617165716.279857-1-krzysztof.kozlowski@linaro.org Signed-off-by: Jakub Kicinski --- .../devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml index 68f78b90d23a..604985c8068e 100644 --- a/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml +++ b/Documentation/devicetree/bindings/net/bluetooth/qualcomm-bluetooth.yaml @@ -50,6 +50,9 @@ properties: vddch0-supply: description: VDD_CH0 supply regulator handle + vddch1-supply: + description: VDD_CH1 supply regulator handle + vddaon-supply: description: VDD_AON supply regulator handle -- cgit v1.2.3 From 1ca09f5746edd5e483d144118497f622af9dbe60 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 19 Jun 2023 19:01:34 +0200 Subject: dt-bindings: net: micrel,ks8851: allow SPI device properties The Micrel KS8851 can be attached to SPI or parallel bus and the difference is expressed in compatibles. Allow common SPI properties when this is a SPI variant and narrow the parallel memory bus properties to the second case. This fixes dtbs_check warning: qcom-msm8960-cdp.dtb: ethernet@0: Unevaluated properties are not allowed ('spi-max-frequency' was unexpected) Signed-off-by: Krzysztof Kozlowski Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230619170134.65395-1-krzysztof.kozlowski@linaro.org Signed-off-by: Jakub Kicinski --- Documentation/devicetree/bindings/net/micrel,ks8851.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/micrel,ks8851.yaml b/Documentation/devicetree/bindings/net/micrel,ks8851.yaml index b44d83554ef5..b726c6e14633 100644 --- a/Documentation/devicetree/bindings/net/micrel,ks8851.yaml +++ b/Documentation/devicetree/bindings/net/micrel,ks8851.yaml @@ -44,13 +44,13 @@ required: allOf: - $ref: ethernet-controller.yaml# - - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml# - if: properties: compatible: contains: const: micrel,ks8851 then: + $ref: /schemas/spi/spi-peripheral-props.yaml# properties: reg: maxItems: 1 @@ -60,6 +60,7 @@ allOf: contains: const: micrel,ks8851-mll then: + $ref: /schemas/memory-controllers/mc-peripheral-props.yaml# properties: reg: minItems: 2 -- cgit v1.2.3 From ca4fa87435370747cac535cecfd08672bb679487 Mon Sep 17 00:00:00 2001 From: renmingshuai Date: Tue, 20 Jun 2023 09:49:39 +0800 Subject: selftests: tc-testing: add one test for flushing explicitly created chain Add the test for additional reference to chains that are explicitly created by RTM_NEWCHAIN message. The test result: 1..1 ok 1 c2b4 - soft lockup alarm will be not generated after delete the prio 0 filter of the chain This is a follow up to commit c9a82bec02c3 ("net/sched: cls_api: Fix lockup on flushing explicitly created chain"). Signed-off-by: Mingshuai Ren Acked-by: Pedro Tammela Acked-by: Victor Nogueira Link: https://lore.kernel.org/r/20230620014939.2034054-1-renmingshuai@huawei.com Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/infra/filter.json | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/infra/filter.json diff --git a/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json new file mode 100644 index 000000000000..c4c778e83da2 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/infra/filter.json @@ -0,0 +1,25 @@ +[ + { + "id": "c2b4", + "name": "soft lockup alarm will be not generated after delete the prio 0 filter of the chain", + "category": [ + "filter", + "chain" + ], + "setup": [ + "$IP link add dev $DUMMY type dummy || /bin/true", + "$TC qdisc add dev $DUMMY root handle 1: htb default 1", + "$TC chain add dev $DUMMY", + "$TC filter del dev $DUMMY chain 0 parent 1: prio 0" + ], + "cmdUnderTest": "$TC filter add dev $DUMMY chain 0 parent 1:", + "expExitCode": "2", + "verifyCmd": "$TC chain ls dev $DUMMY", + "matchPattern": "chain parent 1: chain 0", + "matchCount": "1", + "teardown": [ + "$TC qdisc del dev $DUMMY root handle 1: htb default 1", + "$IP link del dev $DUMMY type dummy" + ] + } +] -- cgit v1.2.3 From 53bf91641ae19fe51fb24422de6d07565a3536d0 Mon Sep 17 00:00:00 2001 From: Abel Wu Date: Tue, 20 Jun 2023 17:27:11 +0800 Subject: inet: Cleanup on charging memory for newly accepted sockets If there is no net-memcg associated with the sock, don't bother calculating its memory usage for charge. Signed-off-by: Abel Wu Link: https://lore.kernel.org/r/20230620092712.16217-1-wuyun.abel@bytedance.com Signed-off-by: Jakub Kicinski --- net/ipv4/inet_connection_sock.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 15424dec4584..0cc19cfbb673 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -706,20 +706,23 @@ struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern) out: release_sock(sk); if (newsk && mem_cgroup_sockets_enabled) { - int amt; + int amt = 0; /* atomically get the memory usage, set and charge the * newsk->sk_memcg. */ lock_sock(newsk); - /* The socket has not been accepted yet, no need to look at - * newsk->sk_wmem_queued. - */ - amt = sk_mem_pages(newsk->sk_forward_alloc + - atomic_read(&newsk->sk_rmem_alloc)); mem_cgroup_sk_alloc(newsk); - if (newsk->sk_memcg && amt) + if (newsk->sk_memcg) { + /* The socket has not been accepted yet, no need + * to look at newsk->sk_wmem_queued. + */ + amt = sk_mem_pages(newsk->sk_forward_alloc + + atomic_read(&newsk->sk_rmem_alloc)); + } + + if (amt) mem_cgroup_charge_skmem(newsk->sk_memcg, amt, GFP_KERNEL | __GFP_NOFAIL); -- cgit v1.2.3 From 5dfbbaa208f5429a02ccb410ae3515222bbe64ef Mon Sep 17 00:00:00 2001 From: David Arinzon Date: Tue, 20 Jun 2023 13:35:44 +0000 Subject: net: ena: Fix rst format issues in readme This patch fixes a warning in the ena documentation file identified by the kernel automatic tools. The patch also adds a missing newline between sections. Signed-off-by: David Arinzon Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202306171804.U7E92zoE-lkp@intel.com/ Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230620133544.32584-1-darinzon@amazon.com Signed-off-by: Jakub Kicinski --- Documentation/networking/device_drivers/ethernet/amazon/ena.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst index 491492677632..5eaa3ab6c73e 100644 --- a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst +++ b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst @@ -38,6 +38,7 @@ debug logs. Some of the ENA devices support a working mode called Low-latency Queue (LLQ), which saves several more microseconds. + ENA Source Code Directory Structure =================================== @@ -206,6 +207,7 @@ More information about Adaptive Interrupt Moderation (DIM) can be found in Documentation/networking/net_dim.rst .. _`RX copybreak`: + RX copybreak ============ The rx_copybreak is initialized by default to ENA_DEFAULT_RX_COPYBREAK -- cgit v1.2.3 From c026d33b8f5081969503e322ea30d7c1a6b17dda Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:14 +0200 Subject: mptcp: move snd_una update earlier for fallback socket That will avoid an unneeded conditional in both the fast-path and in the fallback case and will simplify a bit the next patch. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- net/mptcp/options.c | 6 ++++++ net/mptcp/protocol.c | 6 ------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 8a8083207be4..4bdcd2b326bd 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1119,6 +1119,12 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) mptcp_data_lock(subflow->conn); if (sk_stream_memory_free(sk)) __mptcp_check_push(subflow->conn, sk); + + /* on fallback we just need to ignore the msk-level snd_una, as + * this is really plain TCP + */ + msk->snd_una = READ_ONCE(msk->snd_nxt); + __mptcp_data_acked(subflow->conn); mptcp_data_unlock(subflow->conn); return true; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 992b89c75631..9c756d675d4d 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -1004,12 +1004,6 @@ static void __mptcp_clean_una(struct sock *sk) struct mptcp_data_frag *dtmp, *dfrag; u64 snd_una; - /* on fallback we just need to ignore snd_una, as this is really - * plain TCP - */ - if (__mptcp_check_fallback(msk)) - msk->snd_una = READ_ONCE(msk->snd_nxt); - snd_una = msk->snd_una; list_for_each_entry_safe(dfrag, dtmp, &msk->rtx_queue, list) { if (after64(dfrag->data_seq + dfrag->data_len, snd_una)) -- cgit v1.2.3 From 38967f424b5be79c4c676712e5640d846efd07e3 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:15 +0200 Subject: mptcp: track some aggregate data counters Currently there are no data transfer counters accounting for all the subflows used by a given MPTCP socket. The user-space can compute such figures aggregating the subflow info, but that is inaccurate if any subflow is closed before the MPTCP socket itself. Add the new counters in the MPTCP socket itself and expose them via the existing diag and sockopt. While touching mptcp_diag_fill_info(), acquire the relevant locks before fetching the msk data, to ensure better data consistency Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/385 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- include/uapi/linux/mptcp.h | 5 +++++ net/mptcp/options.c | 10 ++++++++-- net/mptcp/protocol.c | 11 ++++++++++- net/mptcp/protocol.h | 4 ++++ net/mptcp/sockopt.c | 25 ++++++++++++++++++++----- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h index 32af2d278cb4..a124be6ebbba 100644 --- a/include/uapi/linux/mptcp.h +++ b/include/uapi/linux/mptcp.h @@ -123,6 +123,11 @@ struct mptcp_info { __u8 mptcpi_local_addr_used; __u8 mptcpi_local_addr_max; __u8 mptcpi_csum_enabled; + __u32 mptcpi_retransmits; + __u64 mptcpi_bytes_retrans; + __u64 mptcpi_bytes_sent; + __u64 mptcpi_bytes_received; + __u64 mptcpi_bytes_acked; }; /* diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 4bdcd2b326bd..c254accb14de 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -1026,6 +1026,12 @@ u64 __mptcp_expand_seq(u64 old_seq, u64 cur_seq) return cur_seq; } +static void __mptcp_snd_una_update(struct mptcp_sock *msk, u64 new_snd_una) +{ + msk->bytes_acked += new_snd_una - msk->snd_una; + msk->snd_una = new_snd_una; +} + static void ack_update_msk(struct mptcp_sock *msk, struct sock *ssk, struct mptcp_options_received *mp_opt) @@ -1057,7 +1063,7 @@ static void ack_update_msk(struct mptcp_sock *msk, __mptcp_check_push(sk, ssk); if (after64(new_snd_una, old_snd_una)) { - msk->snd_una = new_snd_una; + __mptcp_snd_una_update(msk, new_snd_una); __mptcp_data_acked(sk); } mptcp_data_unlock(sk); @@ -1123,7 +1129,7 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) /* on fallback we just need to ignore the msk-level snd_una, as * this is really plain TCP */ - msk->snd_una = READ_ONCE(msk->snd_nxt); + __mptcp_snd_una_update(msk, READ_ONCE(msk->snd_nxt)); __mptcp_data_acked(subflow->conn); mptcp_data_unlock(subflow->conn); diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 9c756d675d4d..d5b8e488bce1 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -377,6 +377,7 @@ static bool __mptcp_move_skb(struct mptcp_sock *msk, struct sock *ssk, if (MPTCP_SKB_CB(skb)->map_seq == msk->ack_seq) { /* in sequence */ + msk->bytes_received += copy_len; WRITE_ONCE(msk->ack_seq, msk->ack_seq + copy_len); tail = skb_peek_tail(&sk->sk_receive_queue); if (tail && mptcp_try_coalesce(sk, tail, skb)) @@ -760,6 +761,7 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk) MPTCP_SKB_CB(skb)->map_seq += delta; __skb_queue_tail(&sk->sk_receive_queue, skb); } + msk->bytes_received += end_seq - msk->ack_seq; msk->ack_seq = end_seq; moved = true; } @@ -1531,8 +1533,10 @@ static void mptcp_update_post_push(struct mptcp_sock *msk, * that has been handed to the subflow for transmission * and skip update in case it was old dfrag. */ - if (likely(after64(snd_nxt_new, msk->snd_nxt))) + if (likely(after64(snd_nxt_new, msk->snd_nxt))) { + msk->bytes_sent += snd_nxt_new - msk->snd_nxt; msk->snd_nxt = snd_nxt_new; + } } void mptcp_check_and_set_pending(struct sock *sk) @@ -2590,6 +2594,7 @@ static void __mptcp_retrans(struct sock *sk) } if (copied) { dfrag->already_sent = max(dfrag->already_sent, info.sent); + msk->bytes_retrans += copied; tcp_push(ssk, 0, info.mss_now, tcp_sk(ssk)->nonagle, info.size_goal); WRITE_ONCE(msk->allow_infinite_fallback, false); @@ -3102,6 +3107,10 @@ static int mptcp_disconnect(struct sock *sk, int flags) WRITE_ONCE(msk->csum_enabled, mptcp_is_checksum_enabled(sock_net(sk))); mptcp_pm_data_reset(msk); mptcp_ca_reset(sk); + msk->bytes_acked = 0; + msk->bytes_received = 0; + msk->bytes_sent = 0; + msk->bytes_retrans = 0; WRITE_ONCE(sk->sk_shutdown, 0); sk_error_report(sk); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 47b46602870e..27adfcc5aaa2 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -262,10 +262,13 @@ struct mptcp_sock { u64 local_key; u64 remote_key; u64 write_seq; + u64 bytes_sent; u64 snd_nxt; + u64 bytes_received; u64 ack_seq; atomic64_t rcv_wnd_sent; u64 rcv_data_fin_seq; + u64 bytes_retrans; int rmem_fwd_alloc; struct sock *last_snd; int snd_burst; @@ -274,6 +277,7 @@ struct mptcp_sock { * recovery related fields are under data_lock * protection */ + u64 bytes_acked; u64 snd_una; u64 wnd_end; unsigned long timer_ival; diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index e172a5848b0d..fa5055d5b029 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -889,7 +889,9 @@ out: void mptcp_diag_fill_info(struct mptcp_sock *msk, struct mptcp_info *info) { + struct sock *sk = (struct sock *)msk; u32 flags = 0; + bool slow; memset(info, 0, sizeof(*info)); @@ -898,6 +900,9 @@ void mptcp_diag_fill_info(struct mptcp_sock *msk, struct mptcp_info *info) info->mptcpi_add_addr_accepted = READ_ONCE(msk->pm.add_addr_accepted); info->mptcpi_local_addr_used = READ_ONCE(msk->pm.local_addr_used); + if (inet_sk_state_load(sk) == TCP_LISTEN) + return; + /* The following limits only make sense for the in-kernel PM */ if (mptcp_pm_is_kernel(msk)) { info->mptcpi_subflows_max = @@ -915,11 +920,21 @@ void mptcp_diag_fill_info(struct mptcp_sock *msk, struct mptcp_info *info) if (READ_ONCE(msk->can_ack)) flags |= MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED; info->mptcpi_flags = flags; - info->mptcpi_token = READ_ONCE(msk->token); - info->mptcpi_write_seq = READ_ONCE(msk->write_seq); - info->mptcpi_snd_una = READ_ONCE(msk->snd_una); - info->mptcpi_rcv_nxt = READ_ONCE(msk->ack_seq); - info->mptcpi_csum_enabled = READ_ONCE(msk->csum_enabled); + mptcp_data_lock(sk); + info->mptcpi_snd_una = msk->snd_una; + info->mptcpi_rcv_nxt = msk->ack_seq; + info->mptcpi_bytes_acked = msk->bytes_acked; + mptcp_data_unlock(sk); + + slow = lock_sock_fast(sk); + info->mptcpi_csum_enabled = msk->csum_enabled; + info->mptcpi_token = msk->token; + info->mptcpi_write_seq = msk->write_seq; + info->mptcpi_retransmits = inet_csk(sk)->icsk_retransmits; + info->mptcpi_bytes_sent = msk->bytes_sent; + info->mptcpi_bytes_received = msk->bytes_received; + info->mptcpi_bytes_retrans = msk->bytes_retrans; + unlock_sock_fast(sk, slow); } EXPORT_SYMBOL_GPL(mptcp_diag_fill_info); -- cgit v1.2.3 From 5dcff89e14555a4ee6cfa132b82f7d13dcb1e80a Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:16 +0200 Subject: selftests: mptcp: explicitly tests aggregate counters Update the existing sockopt test-case to do some basic checks on the newly added counters. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/385 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c index b35148edbf02..5ee710b30f10 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c @@ -51,6 +51,11 @@ struct mptcp_info { __u8 mptcpi_local_addr_used; __u8 mptcpi_local_addr_max; __u8 mptcpi_csum_enabled; + __u32 mptcpi_retransmits; + __u64 mptcpi_bytes_retrans; + __u64 mptcpi_bytes_sent; + __u64 mptcpi_bytes_received; + __u64 mptcpi_bytes_acked; }; struct mptcp_subflow_data { @@ -83,8 +88,10 @@ struct mptcp_subflow_addrs { struct so_state { struct mptcp_info mi; + struct mptcp_info last_sample; uint64_t mptcpi_rcv_delta; uint64_t tcpi_rcv_delta; + bool pkt_stats_avail; }; #ifndef MIN @@ -322,8 +329,9 @@ static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w) if (ret < 0) die_perror("getsockopt MPTCP_INFO"); - assert(olen == sizeof(i)); + s->pkt_stats_avail = olen >= sizeof(i); + s->last_sample = i; if (s->mi.mptcpi_write_seq == 0) s->mi = i; @@ -562,6 +570,23 @@ static void process_one_client(int fd, int pipefd) do_getsockopts(&s, fd, ret, ret2); if (s.mptcpi_rcv_delta != (uint64_t)ret + 1) xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64, s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - ret); + + /* be nice when running on top of older kernel */ + if (s.pkt_stats_avail) { + if (s.last_sample.mptcpi_bytes_sent != ret2) + xerror("mptcpi_bytes_sent %" PRIu64 ", expect %" PRIu64, + s.last_sample.mptcpi_bytes_sent, ret2, + s.last_sample.mptcpi_bytes_sent - ret2); + if (s.last_sample.mptcpi_bytes_received != ret) + xerror("mptcpi_bytes_received %" PRIu64 ", expect %" PRIu64, + s.last_sample.mptcpi_bytes_received, ret, + s.last_sample.mptcpi_bytes_received - ret); + if (s.last_sample.mptcpi_bytes_acked != ret) + xerror("mptcpi_bytes_acked %" PRIu64 ", expect %" PRIu64, + s.last_sample.mptcpi_bytes_acked, ret2, + s.last_sample.mptcpi_bytes_acked - ret2); + } + close(fd); } -- cgit v1.2.3 From 6f06b4d4d1cc676a3f9d947f931ec3866b6c4f6c Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:17 +0200 Subject: mptcp: add subflow unique id The user-space need to properly account the data received/sent by individual subflows. When additional subflows are created and/or closed during the MPTCP socket lifetime, the information currently exposed via MPTCP_TCPINFO are not enough: subflows are identified only by the sequential position inside the info dumps, and that will change with the above mentioned events. To solve the above problem, this patch introduces a new subflow identifier that is unique inside the given MPTCP socket scope. The initial subflow get the id 1 and the other subflows get incremental values at join time. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/388 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.c | 6 ++++++ net/mptcp/protocol.h | 5 ++++- net/mptcp/subflow.c | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index d5b8e488bce1..4ebd6e9aa949 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -96,6 +96,7 @@ static int __mptcp_socket_create(struct mptcp_sock *msk) list_add(&subflow->node, &msk->conn_list); sock_hold(ssock->sk); subflow->request_mptcp = 1; + subflow->subflow_id = msk->subflow_id++; /* This is the first subflow, always with id 0 */ subflow->local_id_valid = 1; @@ -847,6 +848,7 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk) if (sk->sk_socket && !ssk->sk_socket) mptcp_sock_graft(ssk, sk->sk_socket); + mptcp_subflow_ctx(ssk)->subflow_id = msk->subflow_id++; mptcp_sockopt_sync_locked(msk, ssk); mptcp_subflow_joined(msk, ssk); return true; @@ -2732,6 +2734,7 @@ static int __mptcp_init_sock(struct sock *sk) WRITE_ONCE(msk->csum_enabled, mptcp_is_checksum_enabled(sock_net(sk))); WRITE_ONCE(msk->allow_infinite_fallback, true); msk->recovery = false; + msk->subflow_id = 1; mptcp_pm_data_init(msk); @@ -3160,6 +3163,9 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, msk->wnd_end = msk->snd_nxt + req->rsk_rcv_wnd; msk->setsockopt_seq = mptcp_sk(sk)->setsockopt_seq; + /* passive msk is created after the first/MPC subflow */ + msk->subflow_id = 2; + sock_reset_flag(nsk, SOCK_RCU_FREE); security_inet_csk_clone(nsk, req); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 27adfcc5aaa2..bb4cacd92778 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -323,7 +323,8 @@ struct mptcp_sock { u64 rtt_us; /* last maximum rtt of subflows */ } rcvq_space; - u32 setsockopt_seq; + u32 subflow_id; + u32 setsockopt_seq; char ca_name[TCP_CA_NAME_MAX]; struct mptcp_sock *dl_next; }; @@ -504,6 +505,8 @@ struct mptcp_subflow_context { u8 reset_reason:4; u8 stale_count; + u32 subflow_id; + long delegated_status; unsigned long fail_tout; diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 4688daa6b38b..222dfcdadf2e 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -819,6 +819,7 @@ create_child: if (!ctx->conn) goto fallback; + ctx->subflow_id = 1; owner = mptcp_sk(ctx->conn); mptcp_pm_new_connection(owner, child, 1); @@ -1574,6 +1575,7 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc, subflow->remote_id = remote_id; subflow->request_join = 1; subflow->request_bkup = !!(flags & MPTCP_PM_ADDR_FLAG_BACKUP); + subflow->subflow_id = msk->subflow_id++; mptcp_info2sockaddr(remote, &addr, ssk->sk_family); sock_hold(ssk); -- cgit v1.2.3 From 492432074e4fce4f8880213bf009b47adbf94a3a Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:18 +0200 Subject: mptcp: introduce MPTCP_FULL_INFO getsockopt Some user-space applications want to monitor the subflows utilization. Dumping the per subflow tcp_info is not enough, as the PM could close and re-create the subflows under-the-hood, fooling the accounting. Even checking the src/dst addresses used by each subflow could not be enough, because new subflows could re-use the same address/port of the just closed one. This patch introduces a new socket option, allow dumping all the relevant information all-at-once (everything, everywhere...), in a consistent manner. Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/388 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- include/uapi/linux/mptcp.h | 24 +++++++++ net/mptcp/sockopt.c | 127 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h index a124be6ebbba..ee9c49f949a2 100644 --- a/include/uapi/linux/mptcp.h +++ b/include/uapi/linux/mptcp.h @@ -249,9 +249,33 @@ struct mptcp_subflow_addrs { }; }; +struct mptcp_subflow_info { + __u32 id; + struct mptcp_subflow_addrs addrs; +}; + +struct mptcp_full_info { + __u32 size_tcpinfo_kernel; /* must be 0, set by kernel */ + __u32 size_tcpinfo_user; + __u32 size_sfinfo_kernel; /* must be 0, set by kernel */ + __u32 size_sfinfo_user; + __u32 num_subflows; /* must be 0, set by kernel (real subflow count) */ + __u32 size_arrays_user; /* max subflows that userspace is interested in; + * the buffers at subflow_info/tcp_info + * are respectively at least: + * size_arrays * size_sfinfo_user + * size_arrays * size_tcpinfo_user + * bytes wide + */ + __aligned_u64 subflow_info; + __aligned_u64 tcp_info; + struct mptcp_info mptcp_info; +}; + /* MPTCP socket options */ #define MPTCP_INFO 1 #define MPTCP_TCPINFO 2 #define MPTCP_SUBFLOW_ADDRS 3 +#define MPTCP_FULL_INFO 4 #endif /* _UAPI_MPTCP_H */ diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index fa5055d5b029..63f7a09335c5 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -14,7 +14,8 @@ #include #include "protocol.h" -#define MIN_INFO_OPTLEN_SIZE 16 +#define MIN_INFO_OPTLEN_SIZE 16 +#define MIN_FULL_INFO_OPTLEN_SIZE 40 static struct sock *__mptcp_tcp_fallback(struct mptcp_sock *msk) { @@ -981,7 +982,8 @@ static int mptcp_put_subflow_data(struct mptcp_subflow_data *sfd, } static int mptcp_get_subflow_data(struct mptcp_subflow_data *sfd, - char __user *optval, int __user *optlen) + char __user *optval, + int __user *optlen) { int len, copylen; @@ -1162,6 +1164,125 @@ static int mptcp_getsockopt_subflow_addrs(struct mptcp_sock *msk, char __user *o return 0; } +static int mptcp_get_full_info(struct mptcp_full_info *mfi, + char __user *optval, + int __user *optlen) +{ + int len; + + BUILD_BUG_ON(offsetof(struct mptcp_full_info, mptcp_info) != + MIN_FULL_INFO_OPTLEN_SIZE); + + if (get_user(len, optlen)) + return -EFAULT; + + if (len < MIN_FULL_INFO_OPTLEN_SIZE) + return -EINVAL; + + memset(mfi, 0, sizeof(*mfi)); + if (copy_from_user(mfi, optval, MIN_FULL_INFO_OPTLEN_SIZE)) + return -EFAULT; + + if (mfi->size_tcpinfo_kernel || + mfi->size_sfinfo_kernel || + mfi->num_subflows) + return -EINVAL; + + if (mfi->size_sfinfo_user > INT_MAX || + mfi->size_tcpinfo_user > INT_MAX) + return -EINVAL; + + return len - MIN_FULL_INFO_OPTLEN_SIZE; +} + +static int mptcp_put_full_info(struct mptcp_full_info *mfi, + char __user *optval, + u32 copylen, + int __user *optlen) +{ + copylen += MIN_FULL_INFO_OPTLEN_SIZE; + if (put_user(copylen, optlen)) + return -EFAULT; + + if (copy_to_user(optval, mfi, copylen)) + return -EFAULT; + return 0; +} + +static int mptcp_getsockopt_full_info(struct mptcp_sock *msk, char __user *optval, + int __user *optlen) +{ + unsigned int sfcount = 0, copylen = 0; + struct mptcp_subflow_context *subflow; + struct sock *sk = (struct sock *)msk; + void __user *tcpinfoptr, *sfinfoptr; + struct mptcp_full_info mfi; + int len; + + len = mptcp_get_full_info(&mfi, optval, optlen); + if (len < 0) + return len; + + /* don't bother filling the mptcp info if there is not enough + * user-space-provided storage + */ + if (len > 0) { + mptcp_diag_fill_info(msk, &mfi.mptcp_info); + copylen += min_t(unsigned int, len, sizeof(struct mptcp_info)); + } + + mfi.size_tcpinfo_kernel = sizeof(struct tcp_info); + mfi.size_tcpinfo_user = min_t(unsigned int, mfi.size_tcpinfo_user, + sizeof(struct tcp_info)); + sfinfoptr = u64_to_user_ptr(mfi.subflow_info); + mfi.size_sfinfo_kernel = sizeof(struct mptcp_subflow_info); + mfi.size_sfinfo_user = min_t(unsigned int, mfi.size_sfinfo_user, + sizeof(struct mptcp_subflow_info)); + tcpinfoptr = u64_to_user_ptr(mfi.tcp_info); + + lock_sock(sk); + mptcp_for_each_subflow(msk, subflow) { + struct sock *ssk = mptcp_subflow_tcp_sock(subflow); + struct mptcp_subflow_info sfinfo; + struct tcp_info tcp_info; + + if (sfcount++ >= mfi.size_arrays_user) + continue; + + /* fetch addr/tcp_info only if the user space buffers + * are wide enough + */ + memset(&sfinfo, 0, sizeof(sfinfo)); + sfinfo.id = subflow->subflow_id; + if (mfi.size_sfinfo_user > + offsetof(struct mptcp_subflow_info, addrs)) + mptcp_get_sub_addrs(ssk, &sfinfo.addrs); + if (copy_to_user(sfinfoptr, &sfinfo, mfi.size_sfinfo_user)) + goto fail_release; + + if (mfi.size_tcpinfo_user) { + tcp_get_info(ssk, &tcp_info); + if (copy_to_user(tcpinfoptr, &tcp_info, + mfi.size_tcpinfo_user)) + goto fail_release; + } + + tcpinfoptr += mfi.size_tcpinfo_user; + sfinfoptr += mfi.size_sfinfo_user; + } + release_sock(sk); + + mfi.num_subflows = sfcount; + if (mptcp_put_full_info(&mfi, optval, copylen, optlen)) + return -EFAULT; + + return 0; + +fail_release: + release_sock(sk); + return -EFAULT; +} + static int mptcp_put_int_option(struct mptcp_sock *msk, char __user *optval, int __user *optlen, int val) { @@ -1235,6 +1356,8 @@ static int mptcp_getsockopt_sol_mptcp(struct mptcp_sock *msk, int optname, switch (optname) { case MPTCP_INFO: return mptcp_getsockopt_info(msk, optval, optlen); + case MPTCP_FULL_INFO: + return mptcp_getsockopt_full_info(msk, optval, optlen); case MPTCP_TCPINFO: return mptcp_getsockopt_tcpinfo(msk, optval, optlen); case MPTCP_SUBFLOW_ADDRS: -- cgit v1.2.3 From aa723d5b3541bfcf9b7493fc1c47e6af6a11b765 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:19 +0200 Subject: selftests: mptcp: add MPTCP_FULL_INFO testcase Add a testcase explicitly triggering the newly introduce MPTCP_FULL_INFO getsockopt. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/388 Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Co-developed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_sockopt.c | 93 ++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c index 5ee710b30f10..926b0be87c99 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c @@ -86,9 +86,38 @@ struct mptcp_subflow_addrs { #define MPTCP_SUBFLOW_ADDRS 3 #endif +#ifndef MPTCP_FULL_INFO +struct mptcp_subflow_info { + __u32 id; + struct mptcp_subflow_addrs addrs; +}; + +struct mptcp_full_info { + __u32 size_tcpinfo_kernel; /* must be 0, set by kernel */ + __u32 size_tcpinfo_user; + __u32 size_sfinfo_kernel; /* must be 0, set by kernel */ + __u32 size_sfinfo_user; + __u32 num_subflows; /* must be 0, set by kernel (real subflow count) */ + __u32 size_arrays_user; /* max subflows that userspace is interested in; + * the buffers at subflow_info/tcp_info + * are respectively at least: + * size_arrays * size_sfinfo_user + * size_arrays * size_tcpinfo_user + * bytes wide + */ + __aligned_u64 subflow_info; + __aligned_u64 tcp_info; + struct mptcp_info mptcp_info; +}; + +#define MPTCP_FULL_INFO 4 +#endif + struct so_state { struct mptcp_info mi; struct mptcp_info last_sample; + struct tcp_info tcp_info; + struct mptcp_subflow_addrs addrs; uint64_t mptcpi_rcv_delta; uint64_t tcpi_rcv_delta; bool pkt_stats_avail; @@ -370,6 +399,8 @@ static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t olen -= sizeof(struct mptcp_subflow_data); assert(olen == ti.d.size_user); + s->tcp_info = ti.ti[0]; + if (ti.ti[0].tcpi_bytes_sent == w && ti.ti[0].tcpi_bytes_received == r) goto done; @@ -391,7 +422,7 @@ done: do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO); } -static void do_getsockopt_subflow_addrs(int fd) +static void do_getsockopt_subflow_addrs(struct so_state *s, int fd) { struct sockaddr_storage remote, local; socklen_t olen, rlen, llen; @@ -439,6 +470,7 @@ static void do_getsockopt_subflow_addrs(int fd) assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0); assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0); + s->addrs = addrs.addr[0]; memset(&addrs, 0, sizeof(addrs)); @@ -459,13 +491,70 @@ static void do_getsockopt_subflow_addrs(int fd) do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS); } +static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd) +{ + size_t data_size = sizeof(struct mptcp_full_info); + struct mptcp_subflow_info sfinfo[2]; + struct tcp_info tcp_info[2]; + struct mptcp_full_info mfi; + socklen_t olen; + int ret; + + memset(&mfi, 0, data_size); + memset(tcp_info, 0, sizeof(tcp_info)); + memset(sfinfo, 0, sizeof(sfinfo)); + + mfi.size_tcpinfo_user = sizeof(struct tcp_info); + mfi.size_sfinfo_user = sizeof(struct mptcp_subflow_info); + mfi.size_arrays_user = 2; + mfi.subflow_info = (unsigned long)&sfinfo[0]; + mfi.tcp_info = (unsigned long)&tcp_info[0]; + olen = data_size; + + ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen); + if (ret < 0) { + if (errno == EOPNOTSUPP) { + perror("MPTCP_FULL_INFO test skipped"); + return; + } + xerror("getsockopt MPTCP_FULL_INFO"); + } + + assert(olen <= data_size); + assert(mfi.size_tcpinfo_kernel > 0); + assert(mfi.size_tcpinfo_user == + MIN(mfi.size_tcpinfo_kernel, sizeof(struct tcp_info))); + assert(mfi.size_sfinfo_kernel > 0); + assert(mfi.size_sfinfo_user == + MIN(mfi.size_sfinfo_kernel, sizeof(struct mptcp_subflow_info))); + assert(mfi.num_subflows == 1); + + /* Tolerate future extension to mptcp_info struct and running newer + * test on top of older kernel. + * Anyway any kernel supporting MPTCP_FULL_INFO must at least include + * the following in mptcp_info. + */ + assert(olen > (socklen_t)__builtin_offsetof(struct mptcp_full_info, tcp_info)); + assert(mfi.mptcp_info.mptcpi_subflows == 0); + assert(mfi.mptcp_info.mptcpi_bytes_sent == s->last_sample.mptcpi_bytes_sent); + assert(mfi.mptcp_info.mptcpi_bytes_received == s->last_sample.mptcpi_bytes_received); + + assert(sfinfo[0].id == 1); + assert(tcp_info[0].tcpi_bytes_sent == s->tcp_info.tcpi_bytes_sent); + assert(tcp_info[0].tcpi_bytes_received == s->tcp_info.tcpi_bytes_received); + assert(!memcmp(&sfinfo->addrs, &s->addrs, sizeof(struct mptcp_subflow_addrs))); +} + static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w) { do_getsockopt_mptcp_info(s, fd, w); do_getsockopt_tcp_info(s, fd, r, w); - do_getsockopt_subflow_addrs(fd); + do_getsockopt_subflow_addrs(s, fd); + + if (r) + do_getsockopt_mptcp_full_info(s, fd); } static void connect_one_server(int fd, int pipefd) -- cgit v1.2.3 From 00079f18c24f373797cc38273c1bc0b475469d2b Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Tue, 20 Jun 2023 18:30:20 +0200 Subject: selftests: mptcp: join: skip check if MIB counter not supported (part 2) Selftests are supposed to run on any kernels, including the old ones not supporting all MPTCP features. One of them is the MPTCP MIB counters introduced in commit fc518953bc9c ("mptcp: add and use MIB counter infrastructure") and more later. The MPTCP Join selftest heavily relies on these counters. If a counter is not supported by the kernel, it is not displayed when using 'nstat -z'. We can then detect that and skip the verification. A new helper (get_counter()) has been added recently in the -net tree to do the required checks and return an error if the counter is not available. This commit is similar to the one with the same title applied in the -net tree but it modifies code only present in net-next for the moment, see the Fixes commit below. While at it, we can also remove the use of ${extra_msg} variable which is never assigned in chk_rm_tx_nr() function and use 'echo' without '-n' parameter. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/368 Fixes: 0639fa230a21 ("selftests: mptcp: add explicit check for new mibs") Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 33 +++++++++++++------------ 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 1b68fe1c0885..a7973d6a40a0 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1683,12 +1683,12 @@ chk_add_tx_nr() timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout) printf "%-${nr_blank}s %s" " " "add TX" - count=$(ip netns exec $ns1 nstat -as MPTcpExtAddAddrTx | grep MPTcpExtAddAddrTx | awk '{print $2}') - [ -z "$count" ] && count=0 - + count=$(get_counter ${ns1} "MPTcpExtAddAddrTx") + if [ -z "$count" ]; then + echo -n "[skip]" # if the test configured a short timeout tolerate greater then expected # add addrs options, due to retransmissions - if [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then + elif [ "$count" != "$add_tx_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_tx_nr" ]; }; then echo "[fail] got $count ADD_ADDR[s] TX, expected $add_tx_nr" fail_test else @@ -1696,9 +1696,10 @@ chk_add_tx_nr() fi echo -n " - echo TX " - count=$(ip netns exec $ns2 nstat -as MPTcpExtEchoAddTx | grep MPTcpExtEchoAddTx | awk '{print $2}') - [ -z "$count" ] && count=0 - if [ "$count" != "$echo_tx_nr" ]; then + count=$(get_counter ${ns2} "MPTcpExtEchoAddTx") + if [ -z "$count" ]; then + echo "[skip]" + elif [ "$count" != "$echo_tx_nr" ]; then echo "[fail] got $count ADD_ADDR echo[s] TX, expected $echo_tx_nr" fail_test else @@ -1734,9 +1735,10 @@ chk_rm_nr() fi printf "%-${nr_blank}s %s" " " "rm " - count=$(ip netns exec $addr_ns nstat -as MPTcpExtRmAddr | grep MPTcpExtRmAddr | awk '{print $2}') - [ -z "$count" ] && count=0 - if [ "$count" != "$rm_addr_nr" ]; then + count=$(get_counter ${addr_ns} "MPTcpExtRmAddr") + if [ -z "$count" ]; then + echo -n "[skip]" + elif [ "$count" != "$rm_addr_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr" fail_test else @@ -1778,16 +1780,15 @@ chk_rm_tx_nr() local rm_addr_tx_nr=$1 printf "%-${nr_blank}s %s" " " "rm TX " - count=$(ip netns exec $ns2 nstat -as MPTcpExtRmAddrTx | grep MPTcpExtRmAddrTx | awk '{print $2}') - [ -z "$count" ] && count=0 - if [ "$count" != "$rm_addr_tx_nr" ]; then + count=$(get_counter ${ns2} "MPTcpExtRmAddrTx") + if [ -z "$count" ]; then + echo "[skip]" + elif [ "$count" != "$rm_addr_tx_nr" ]; then echo "[fail] got $count RM_ADDR[s] expected $rm_addr_tx_nr" fail_test else - echo -n "[ ok ]" + echo "[ ok ]" fi - - echo "$extra_msg" } chk_prio_nr() -- cgit v1.2.3 From bbd49d114d5790a2dc3f67926cec3fc48b2d5d81 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Tue, 20 Jun 2023 18:30:21 +0200 Subject: mptcp: consolidate transition to TCP_CLOSE in mptcp_do_fastclose() The MPTCP code always set the msk state to TCP_CLOSE before calling performing the fast-close. Move such state transition in mptcp_do_fastclose() to avoid some code duplication. Signed-off-by: Paolo Abeni Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- net/mptcp/protocol.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 4ebd6e9aa949..f65eec3e0d22 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -2655,6 +2655,7 @@ static void mptcp_do_fastclose(struct sock *sk) struct mptcp_subflow_context *subflow, *tmp; struct mptcp_sock *msk = mptcp_sk(sk); + inet_sk_state_store(sk, TCP_CLOSE); mptcp_for_each_subflow_safe(msk, subflow, tmp) __mptcp_close_ssk(sk, mptcp_subflow_tcp_sock(subflow), subflow, MPTCP_CF_FASTCLOSE); @@ -2692,10 +2693,9 @@ static void mptcp_worker(struct work_struct *work) * even if it is orphaned and in FIN_WAIT2 state */ if (sock_flag(sk, SOCK_DEAD)) { - if (mptcp_should_close(sk)) { - inet_sk_state_store(sk, TCP_CLOSE); + if (mptcp_should_close(sk)) mptcp_do_fastclose(sk); - } + if (sk->sk_state == TCP_CLOSE) { __mptcp_destroy_sock(sk); goto unlock; @@ -2938,7 +2938,6 @@ static void __mptcp_destroy_sock(struct sock *sk) void __mptcp_unaccepted_force_close(struct sock *sk) { sock_set_flag(sk, SOCK_DEAD); - inet_sk_state_store(sk, TCP_CLOSE); mptcp_do_fastclose(sk); __mptcp_destroy_sock(sk); } @@ -2980,7 +2979,6 @@ bool __mptcp_close(struct sock *sk, long timeout) /* If the msk has read data, or the caller explicitly ask it, * do the MPTCP equivalent of TCP reset, aka MPTCP fastclose */ - inet_sk_state_store(sk, TCP_CLOSE); mptcp_do_fastclose(sk); timeout = 0; } else if (mptcp_close_state(sk)) { -- cgit v1.2.3 From 528cb5f2a1e859522f36f091f29f5c81ec6d4a4c Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 20 Jun 2023 18:30:22 +0200 Subject: mptcp: pass addr to mptcp_pm_alloc_anno_list Pass addr parameter to mptcp_pm_alloc_anno_list() instead of entry. We can reduce the scope, e.g. in mptcp_pm_alloc_anno_list(), we only access "entry->addr", we can then restrict to the pointer to "addr" then. Signed-off-by: Geliang Tang Reviewed-by: Matthieu Baerts Signed-off-by: Matthieu Baerts Signed-off-by: Jakub Kicinski --- net/mptcp/pm_netlink.c | 8 ++++---- net/mptcp/pm_userspace.c | 2 +- net/mptcp/protocol.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index a56718ffdd02..547e51c65480 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -341,7 +341,7 @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk, } bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, - const struct mptcp_pm_addr_entry *entry) + const struct mptcp_addr_info *addr) { struct mptcp_pm_add_entry *add_entry = NULL; struct sock *sk = (struct sock *)msk; @@ -349,7 +349,7 @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, lockdep_assert_held(&msk->pm.lock); - add_entry = mptcp_lookup_anno_list_by_saddr(msk, &entry->addr); + add_entry = mptcp_lookup_anno_list_by_saddr(msk, addr); if (add_entry) { if (mptcp_pm_is_kernel(msk)) @@ -366,7 +366,7 @@ bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, list_add(&add_entry->list, &msk->pm.anno_list); - add_entry->addr = entry->addr; + add_entry->addr = *addr; add_entry->sock = msk; add_entry->retrans_times = 0; @@ -576,7 +576,7 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk) return; if (local) { - if (mptcp_pm_alloc_anno_list(msk, local)) { + if (mptcp_pm_alloc_anno_list(msk, &local->addr)) { __clear_bit(local->addr.id, msk->pm.id_avail_bitmap); msk->pm.add_addr_signaled++; mptcp_pm_announce_addr(msk, &local->addr, false); diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c index 47a883a16c11..b5a8aa4c1ebd 100644 --- a/net/mptcp/pm_userspace.c +++ b/net/mptcp/pm_userspace.c @@ -193,7 +193,7 @@ int mptcp_nl_cmd_announce(struct sk_buff *skb, struct genl_info *info) lock_sock((struct sock *)msk); spin_lock_bh(&msk->pm.lock); - if (mptcp_pm_alloc_anno_list(msk, &addr_val)) { + if (mptcp_pm_alloc_anno_list(msk, &addr_val.addr)) { msk->pm.add_addr_signaled++; mptcp_pm_announce_addr(msk, &addr_val.addr, false); mptcp_pm_nl_addr_send_ack(msk); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index bb4cacd92778..3a1a64cdeba6 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -817,7 +817,7 @@ int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk, struct mptcp_addr_info *rem, u8 bkup); bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, - const struct mptcp_pm_addr_entry *entry); + const struct mptcp_addr_info *addr); void mptcp_pm_free_anno_list(struct mptcp_sock *msk); bool mptcp_pm_sport_in_anno_list(struct mptcp_sock *msk, const struct sock *sk); struct mptcp_pm_add_entry * -- cgit v1.2.3 From 5a4dd8796d772252d7f31b547673d03d3a40df75 Mon Sep 17 00:00:00 2001 From: Frank Jungclaus Date: Fri, 19 May 2023 21:55:56 +0200 Subject: can: esd_usb: Replace initializer macros used for struct can_bittiming_const Replace the macros used to initialize the members of struct can_bittiming_const with direct values. Then also use those struct members to do the calculations in esd_usb2_set_bittiming(). Link: https://lore.kernel.org/all/CAMZ6RqLaDNy-fZ2G0+QMhUEckkXLL+ZyELVSDFmqpd++aBzZQg@mail.gmail.com/ Suggested-by: Vincent MAILHOL Signed-off-by: Frank Jungclaus Link: https://lore.kernel.org/r/20230519195600.420644-3-frank.jungclaus@esd.eu [mkl: esd_usb2_set_bittiming() use esd_usb2_bittiming_const instead of priv->can.bittiming_const] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index 93c2351d1e3c..310cae5c4648 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -60,18 +60,10 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB_NO_BAUDRATE GENMASK(30, 0) /* bit rate unconfigured */ /* bit timing CAN-USB/2 */ -#define ESD_USB2_TSEG1_MIN 1 -#define ESD_USB2_TSEG1_MAX 16 #define ESD_USB2_TSEG1_SHIFT 16 -#define ESD_USB2_TSEG2_MIN 1 -#define ESD_USB2_TSEG2_MAX 8 #define ESD_USB2_TSEG2_SHIFT 20 -#define ESD_USB2_SJW_MAX 4 #define ESD_USB2_SJW_SHIFT 14 #define ESD_USBM_SJW_SHIFT 24 -#define ESD_USB2_BRP_MIN 1 -#define ESD_USB2_BRP_MAX 1024 -#define ESD_USB2_BRP_INC 1 #define ESD_USB2_3_SAMPLES BIT(23) /* esd IDADD message */ @@ -909,18 +901,19 @@ static const struct ethtool_ops esd_usb_ethtool_ops = { static const struct can_bittiming_const esd_usb2_bittiming_const = { .name = "esd_usb2", - .tseg1_min = ESD_USB2_TSEG1_MIN, - .tseg1_max = ESD_USB2_TSEG1_MAX, - .tseg2_min = ESD_USB2_TSEG2_MIN, - .tseg2_max = ESD_USB2_TSEG2_MAX, - .sjw_max = ESD_USB2_SJW_MAX, - .brp_min = ESD_USB2_BRP_MIN, - .brp_max = ESD_USB2_BRP_MAX, - .brp_inc = ESD_USB2_BRP_INC, + .tseg1_min = 1, + .tseg1_max = 16, + .tseg2_min = 1, + .tseg2_max = 8, + .sjw_max = 4, + .brp_min = 1, + .brp_max = 1024, + .brp_inc = 1, }; static int esd_usb2_set_bittiming(struct net_device *netdev) { + const struct can_bittiming_const *btc = &esd_usb2_bittiming_const; struct esd_usb_net_priv *priv = netdev_priv(netdev); struct can_bittiming *bt = &priv->can.bittiming; union esd_usb_msg *msg; @@ -932,7 +925,7 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) canbtr |= ESD_USB_LOM; - canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1); + canbtr |= (bt->brp - 1) & (btc->brp_max - 1); if (le16_to_cpu(priv->usb->udev->descriptor.idProduct) == USB_CANUSBM_PRODUCT_ID) @@ -940,12 +933,12 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) else sjw_shift = ESD_USB2_SJW_SHIFT; - canbtr |= ((bt->sjw - 1) & (ESD_USB2_SJW_MAX - 1)) + canbtr |= ((bt->sjw - 1) & (btc->sjw_max - 1)) << sjw_shift; canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1) - & (ESD_USB2_TSEG1_MAX - 1)) + & (btc->tseg1_max - 1)) << ESD_USB2_TSEG1_SHIFT; - canbtr |= ((bt->phase_seg2 - 1) & (ESD_USB2_TSEG2_MAX - 1)) + canbtr |= ((bt->phase_seg2 - 1) & (btc->tseg2_max - 1)) << ESD_USB2_TSEG2_SHIFT; if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) canbtr |= ESD_USB2_3_SAMPLES; -- cgit v1.2.3 From 9dc3a695da58f69ce580797a2fccea8262faa9cd Mon Sep 17 00:00:00 2001 From: Frank Jungclaus Date: Fri, 19 May 2023 21:55:57 +0200 Subject: can: esd_usb: Use consistent prefixes for macros Add the consistent prefix ESD_USB_ to all macros defined within esd_usb.c. For macros specific to esd CAN-USB/2 use ESD_USB_2_ as prefix. For macros specific to esd CAN-USB/Micro use ESD_USB_M_ as prefix. Change the macro ESD_USB_3_SAMPLES to ESD_USB_TRIPLE_SAMPLES to not mix up with the prefix ESD_USB_3_ which will be introduced for the CAN-USB/3 device. Link: https://lore.kernel.org/all/CAMZ6RqLaDNy-fZ2G0+QMhUEckkXLL+ZyELVSDFmqpd++aBzZQg@mail.gmail.com/ Suggested-by: Vincent MAILHOL Signed-off-by: Frank Jungclaus Link: https://lore.kernel.org/r/20230519195600.420644-4-frank.jungclaus@esd.eu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 198 +++++++++++++++++++++--------------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index 310cae5c4648..b7d5a82d602b 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -23,33 +23,33 @@ MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Mi MODULE_LICENSE("GPL v2"); /* USB vendor and product ID */ -#define USB_ESDGMBH_VENDOR_ID 0x0ab4 -#define USB_CANUSB2_PRODUCT_ID 0x0010 -#define USB_CANUSBM_PRODUCT_ID 0x0011 +#define ESD_USB_ESDGMBH_VENDOR_ID 0x0ab4 +#define ESD_USB_CANUSB2_PRODUCT_ID 0x0010 +#define ESD_USB_CANUSBM_PRODUCT_ID 0x0011 /* CAN controller clock frequencies */ -#define ESD_USB2_CAN_CLOCK (60 * MEGA) /* Hz */ -#define ESD_USBM_CAN_CLOCK (36 * MEGA) /* Hz */ +#define ESD_USB_2_CAN_CLOCK (60 * MEGA) /* Hz */ +#define ESD_USB_M_CAN_CLOCK (36 * MEGA) /* Hz */ /* Maximum number of CAN nets */ #define ESD_USB_MAX_NETS 2 /* USB commands */ -#define CMD_VERSION 1 /* also used for VERSION_REPLY */ -#define CMD_CAN_RX 2 /* device to host only */ -#define CMD_CAN_TX 3 /* also used for TX_DONE */ -#define CMD_SETBAUD 4 /* also used for SETBAUD_REPLY */ -#define CMD_TS 5 /* also used for TS_REPLY */ -#define CMD_IDADD 6 /* also used for IDADD_REPLY */ +#define ESD_USB_CMD_VERSION 1 /* also used for VERSION_REPLY */ +#define ESD_USB_CMD_CAN_RX 2 /* device to host only */ +#define ESD_USB_CMD_CAN_TX 3 /* also used for TX_DONE */ +#define ESD_USB_CMD_SETBAUD 4 /* also used for SETBAUD_REPLY */ +#define ESD_USB_CMD_TS 5 /* also used for TS_REPLY */ +#define ESD_USB_CMD_IDADD 6 /* also used for IDADD_REPLY */ /* esd CAN message flags - dlc field */ #define ESD_RTR BIT(4) /* esd CAN message flags - id field */ -#define ESD_EXTID BIT(29) -#define ESD_EVENT BIT(30) -#define ESD_IDMASK GENMASK(28, 0) +#define ESD_USB_EXTID BIT(29) +#define ESD_USB_EVENT BIT(30) +#define ESD_USB_IDMASK GENMASK(28, 0) /* esd CAN event ids */ #define ESD_EV_CAN_ERROR_EXT 2 /* CAN controller specific diagnostic data */ @@ -59,35 +59,35 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB_UBR BIT(31) /* User Bit Rate (controller BTR) in bits 0..27 */ #define ESD_USB_NO_BAUDRATE GENMASK(30, 0) /* bit rate unconfigured */ -/* bit timing CAN-USB/2 */ -#define ESD_USB2_TSEG1_SHIFT 16 -#define ESD_USB2_TSEG2_SHIFT 20 -#define ESD_USB2_SJW_SHIFT 14 -#define ESD_USBM_SJW_SHIFT 24 -#define ESD_USB2_3_SAMPLES BIT(23) +/* bit timing esd CAN-USB */ +#define ESD_USB_2_TSEG1_SHIFT 16 +#define ESD_USB_2_TSEG2_SHIFT 20 +#define ESD_USB_2_SJW_SHIFT 14 +#define ESD_USB_M_SJW_SHIFT 24 +#define ESD_USB_TRIPLE_SAMPLES BIT(23) /* esd IDADD message */ -#define ESD_ID_ENABLE 0x80 -#define ESD_MAX_ID_SEGMENT 64 +#define ESD_USB_ID_ENABLE 0x80 +#define ESD_USB_MAX_ID_SEGMENT 64 /* SJA1000 ECC register (emulated by usb firmware) */ -#define SJA1000_ECC_SEG 0x1F -#define SJA1000_ECC_DIR 0x20 -#define SJA1000_ECC_ERR 0x06 -#define SJA1000_ECC_BIT 0x00 -#define SJA1000_ECC_FORM 0x40 -#define SJA1000_ECC_STUFF 0x80 -#define SJA1000_ECC_MASK 0xc0 +#define ESD_USB_SJA1000_ECC_SEG 0x1F +#define ESD_USB_SJA1000_ECC_DIR 0x20 +#define ESD_USB_SJA1000_ECC_ERR 0x06 +#define ESD_USB_SJA1000_ECC_BIT 0x00 +#define ESD_USB_SJA1000_ECC_FORM 0x40 +#define ESD_USB_SJA1000_ECC_STUFF 0x80 +#define ESD_USB_SJA1000_ECC_MASK 0xc0 /* esd bus state event codes */ -#define ESD_BUSSTATE_MASK 0xc0 -#define ESD_BUSSTATE_WARN 0x40 -#define ESD_BUSSTATE_ERRPASSIVE 0x80 -#define ESD_BUSSTATE_BUSOFF 0xc0 +#define ESD_USB_BUSSTATE_MASK 0xc0 +#define ESD_USB_BUSSTATE_WARN 0x40 +#define ESD_USB_BUSSTATE_ERRPASSIVE 0x80 +#define ESD_USB_BUSSTATE_BUSOFF 0xc0 -#define RX_BUFFER_SIZE 1024 -#define MAX_RX_URBS 4 -#define MAX_TX_URBS 16 /* must be power of 2 */ +#define ESD_USB_RX_BUFFER_SIZE 1024 +#define ESD_USB_MAX_RX_URBS 4 +#define ESD_USB_MAX_TX_URBS 16 /* must be power of 2 */ struct header_msg { u8 len; /* len is always the total message length in 32bit words */ @@ -156,7 +156,7 @@ struct id_filter_msg { u8 cmd; u8 net; u8 option; - __le32 mask[ESD_MAX_ID_SEGMENT + 1]; + __le32 mask[ESD_USB_MAX_ID_SEGMENT + 1]; }; struct set_baudrate_msg { @@ -180,8 +180,8 @@ union __packed esd_usb_msg { }; static struct usb_device_id esd_usb_table[] = { - {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)}, - {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)}, + {USB_DEVICE(ESD_USB_ESDGMBH_VENDOR_ID, ESD_USB_CANUSB2_PRODUCT_ID)}, + {USB_DEVICE(ESD_USB_ESDGMBH_VENDOR_ID, ESD_USB_CANUSBM_PRODUCT_ID)}, {} }; MODULE_DEVICE_TABLE(usb, esd_usb_table); @@ -202,8 +202,8 @@ struct esd_usb { int net_count; u32 version; int rxinitdone; - void *rxbuf[MAX_RX_URBS]; - dma_addr_t rxbuf_dma[MAX_RX_URBS]; + void *rxbuf[ESD_USB_MAX_RX_URBS]; + dma_addr_t rxbuf_dma[ESD_USB_MAX_RX_URBS]; }; struct esd_usb_net_priv { @@ -211,7 +211,7 @@ struct esd_usb_net_priv { atomic_t active_tx_jobs; struct usb_anchor tx_submitted; - struct esd_tx_urb_context tx_contexts[MAX_TX_URBS]; + struct esd_tx_urb_context tx_contexts[ESD_USB_MAX_TX_URBS]; struct esd_usb *usb; struct net_device *netdev; @@ -226,7 +226,7 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, struct net_device_stats *stats = &priv->netdev->stats; struct can_frame *cf; struct sk_buff *skb; - u32 id = le32_to_cpu(msg->rx.id) & ESD_IDMASK; + u32 id = le32_to_cpu(msg->rx.id) & ESD_USB_IDMASK; if (id == ESD_EV_CAN_ERROR_EXT) { u8 state = msg->rx.ev_can_err_ext.status; @@ -255,15 +255,15 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, priv->old_state = state; - switch (state & ESD_BUSSTATE_MASK) { - case ESD_BUSSTATE_BUSOFF: + switch (state & ESD_USB_BUSSTATE_MASK) { + case ESD_USB_BUSSTATE_BUSOFF: new_state = CAN_STATE_BUS_OFF; can_bus_off(priv->netdev); break; - case ESD_BUSSTATE_WARN: + case ESD_USB_BUSSTATE_WARN: new_state = CAN_STATE_ERROR_WARNING; break; - case ESD_BUSSTATE_ERRPASSIVE: + case ESD_USB_BUSSTATE_ERRPASSIVE: new_state = CAN_STATE_ERROR_PASSIVE; break; default: @@ -285,14 +285,14 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; - switch (ecc & SJA1000_ECC_MASK) { - case SJA1000_ECC_BIT: + switch (ecc & ESD_USB_SJA1000_ECC_MASK) { + case ESD_USB_SJA1000_ECC_BIT: cf->data[2] |= CAN_ERR_PROT_BIT; break; - case SJA1000_ECC_FORM: + case ESD_USB_SJA1000_ECC_FORM: cf->data[2] |= CAN_ERR_PROT_FORM; break; - case SJA1000_ECC_STUFF: + case ESD_USB_SJA1000_ECC_STUFF: cf->data[2] |= CAN_ERR_PROT_STUFF; break; default: @@ -300,11 +300,11 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, } /* Error occurred during transmission? */ - if (!(ecc & SJA1000_ECC_DIR)) + if (!(ecc & ESD_USB_SJA1000_ECC_DIR)) cf->data[2] |= CAN_ERR_PROT_TX; /* Bit stream position in CAN frame as the error was detected */ - cf->data[3] = ecc & SJA1000_ECC_SEG; + cf->data[3] = ecc & ESD_USB_SJA1000_ECC_SEG; } if (skb) { @@ -331,7 +331,7 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, id = le32_to_cpu(msg->rx.id); - if (id & ESD_EVENT) { + if (id & ESD_USB_EVENT) { esd_usb_rx_event(priv, msg); } else { skb = alloc_can_skb(priv->netdev, &cf); @@ -340,11 +340,11 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, return; } - cf->can_id = id & ESD_IDMASK; + cf->can_id = id & ESD_USB_IDMASK; can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_RTR, priv->can.ctrlmode); - if (id & ESD_EXTID) + if (id & ESD_USB_EXTID) cf->can_id |= CAN_EFF_FLAG; if (msg->rx.dlc & ESD_RTR) { @@ -371,7 +371,7 @@ static void esd_usb_tx_done_msg(struct esd_usb_net_priv *priv, if (!netif_device_present(netdev)) return; - context = &priv->tx_contexts[msg->txdone.hnd & (MAX_TX_URBS - 1)]; + context = &priv->tx_contexts[msg->txdone.hnd & (ESD_USB_MAX_TX_URBS - 1)]; if (!msg->txdone.status) { stats->tx_packets++; @@ -383,7 +383,7 @@ static void esd_usb_tx_done_msg(struct esd_usb_net_priv *priv, } /* Release context */ - context->echo_index = MAX_TX_URBS; + context->echo_index = ESD_USB_MAX_TX_URBS; atomic_dec(&priv->active_tx_jobs); netif_wake_queue(netdev); @@ -418,7 +418,7 @@ static void esd_usb_read_bulk_callback(struct urb *urb) msg = (union esd_usb_msg *)(urb->transfer_buffer + pos); switch (msg->hdr.cmd) { - case CMD_CAN_RX: + case ESD_USB_CMD_CAN_RX: if (msg->rx.net >= dev->net_count) { dev_err(dev->udev->dev.parent, "format error\n"); break; @@ -427,7 +427,7 @@ static void esd_usb_read_bulk_callback(struct urb *urb) esd_usb_rx_can_msg(dev->nets[msg->rx.net], msg); break; - case CMD_CAN_TX: + case ESD_USB_CMD_CAN_TX: if (msg->txdone.net >= dev->net_count) { dev_err(dev->udev->dev.parent, "format error\n"); break; @@ -448,7 +448,7 @@ static void esd_usb_read_bulk_callback(struct urb *urb) resubmit_urb: usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), - urb->transfer_buffer, RX_BUFFER_SIZE, + urb->transfer_buffer, ESD_USB_RX_BUFFER_SIZE, esd_usb_read_bulk_callback, dev); retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -557,7 +557,7 @@ static int esd_usb_setup_rx_urbs(struct esd_usb *dev) if (dev->rxinitdone) return 0; - for (i = 0; i < MAX_RX_URBS; i++) { + for (i = 0; i < ESD_USB_MAX_RX_URBS; i++) { struct urb *urb = NULL; u8 *buf = NULL; dma_addr_t buf_dma; @@ -569,7 +569,7 @@ static int esd_usb_setup_rx_urbs(struct esd_usb *dev) break; } - buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL, + buf = usb_alloc_coherent(dev->udev, ESD_USB_RX_BUFFER_SIZE, GFP_KERNEL, &buf_dma); if (!buf) { dev_warn(dev->udev->dev.parent, @@ -582,7 +582,7 @@ static int esd_usb_setup_rx_urbs(struct esd_usb *dev) usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), - buf, RX_BUFFER_SIZE, + buf, ESD_USB_RX_BUFFER_SIZE, esd_usb_read_bulk_callback, dev); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_anchor_urb(urb, &dev->rx_submitted); @@ -590,7 +590,7 @@ static int esd_usb_setup_rx_urbs(struct esd_usb *dev) err = usb_submit_urb(urb, GFP_KERNEL); if (err) { usb_unanchor_urb(urb); - usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf, + usb_free_coherent(dev->udev, ESD_USB_RX_BUFFER_SIZE, buf, urb->transfer_dma); goto freeurb; } @@ -612,7 +612,7 @@ freeurb: } /* Warn if we've couldn't transmit all the URBs */ - if (i < MAX_RX_URBS) { + if (i < ESD_USB_MAX_RX_URBS) { dev_warn(dev->udev->dev.parent, "rx performance may be slow\n"); } @@ -647,14 +647,14 @@ static int esd_usb_start(struct esd_usb_net_priv *priv) * the number of the starting bitmask (0..64) to the filter.option * field followed by only some bitmasks. */ - msg->hdr.cmd = CMD_IDADD; - msg->hdr.len = 2 + ESD_MAX_ID_SEGMENT; + msg->hdr.cmd = ESD_USB_CMD_IDADD; + msg->hdr.len = 2 + ESD_USB_MAX_ID_SEGMENT; msg->filter.net = priv->index; - msg->filter.option = ESD_ID_ENABLE; /* start with segment 0 */ - for (i = 0; i < ESD_MAX_ID_SEGMENT; i++) + msg->filter.option = ESD_USB_ID_ENABLE; /* start with segment 0 */ + for (i = 0; i < ESD_USB_MAX_ID_SEGMENT; i++) msg->filter.mask[i] = cpu_to_le32(0xffffffff); /* enable 29bit extended IDs */ - msg->filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); + msg->filter.mask[ESD_USB_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); err = esd_usb_send_msg(dev, msg); if (err) @@ -683,8 +683,8 @@ static void unlink_all_urbs(struct esd_usb *dev) usb_kill_anchored_urbs(&dev->rx_submitted); - for (i = 0; i < MAX_RX_URBS; ++i) - usb_free_coherent(dev->udev, RX_BUFFER_SIZE, + for (i = 0; i < ESD_USB_MAX_RX_URBS; ++i) + usb_free_coherent(dev->udev, ESD_USB_RX_BUFFER_SIZE, dev->rxbuf[i], dev->rxbuf_dma[i]); for (i = 0; i < dev->net_count; i++) { @@ -693,8 +693,8 @@ static void unlink_all_urbs(struct esd_usb *dev) usb_kill_anchored_urbs(&priv->tx_submitted); atomic_set(&priv->active_tx_jobs, 0); - for (j = 0; j < MAX_TX_URBS; j++) - priv->tx_contexts[j].echo_index = MAX_TX_URBS; + for (j = 0; j < ESD_USB_MAX_TX_URBS; j++) + priv->tx_contexts[j].echo_index = ESD_USB_MAX_TX_URBS; } } } @@ -760,7 +760,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, msg = (union esd_usb_msg *)buf; msg->hdr.len = 3; /* minimal length */ - msg->hdr.cmd = CMD_CAN_TX; + msg->hdr.cmd = ESD_USB_CMD_CAN_TX; msg->tx.net = priv->index; msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); @@ -769,15 +769,15 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, msg->tx.dlc |= ESD_RTR; if (cf->can_id & CAN_EFF_FLAG) - msg->tx.id |= cpu_to_le32(ESD_EXTID); + msg->tx.id |= cpu_to_le32(ESD_USB_EXTID); for (i = 0; i < cf->len; i++) msg->tx.data[i] = cf->data[i]; msg->hdr.len += (cf->len + 3) >> 2; - for (i = 0; i < MAX_TX_URBS; i++) { - if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { + for (i = 0; i < ESD_USB_MAX_TX_URBS; i++) { + if (priv->tx_contexts[i].echo_index == ESD_USB_MAX_TX_URBS) { context = &priv->tx_contexts[i]; break; } @@ -809,7 +809,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, atomic_inc(&priv->active_tx_jobs); /* Slow down tx path */ - if (atomic_read(&priv->active_tx_jobs) >= MAX_TX_URBS) + if (atomic_read(&priv->active_tx_jobs) >= ESD_USB_MAX_TX_URBS) netif_stop_queue(netdev); err = usb_submit_urb(urb, GFP_ATOMIC); @@ -859,18 +859,18 @@ static int esd_usb_close(struct net_device *netdev) return -ENOMEM; /* Disable all IDs (see esd_usb_start()) */ - msg->hdr.cmd = CMD_IDADD; - msg->hdr.len = 2 + ESD_MAX_ID_SEGMENT; + msg->hdr.cmd = ESD_USB_CMD_IDADD; + msg->hdr.len = 2 + ESD_USB_MAX_ID_SEGMENT; msg->filter.net = priv->index; - msg->filter.option = ESD_ID_ENABLE; /* start with segment 0 */ - for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++) + msg->filter.option = ESD_USB_ID_ENABLE; /* start with segment 0 */ + for (i = 0; i <= ESD_USB_MAX_ID_SEGMENT; i++) msg->filter.mask[i] = 0; if (esd_usb_send_msg(priv->usb, msg) < 0) netdev_err(netdev, "sending idadd message failed\n"); /* set CAN controller to reset mode */ msg->hdr.len = 2; - msg->hdr.cmd = CMD_SETBAUD; + msg->hdr.cmd = ESD_USB_CMD_SETBAUD; msg->setbaud.net = priv->index; msg->setbaud.rsvd = 0; msg->setbaud.baud = cpu_to_le32(ESD_USB_NO_BAUDRATE); @@ -928,27 +928,27 @@ static int esd_usb2_set_bittiming(struct net_device *netdev) canbtr |= (bt->brp - 1) & (btc->brp_max - 1); if (le16_to_cpu(priv->usb->udev->descriptor.idProduct) == - USB_CANUSBM_PRODUCT_ID) - sjw_shift = ESD_USBM_SJW_SHIFT; + ESD_USB_CANUSBM_PRODUCT_ID) + sjw_shift = ESD_USB_M_SJW_SHIFT; else - sjw_shift = ESD_USB2_SJW_SHIFT; + sjw_shift = ESD_USB_2_SJW_SHIFT; canbtr |= ((bt->sjw - 1) & (btc->sjw_max - 1)) << sjw_shift; canbtr |= ((bt->prop_seg + bt->phase_seg1 - 1) & (btc->tseg1_max - 1)) - << ESD_USB2_TSEG1_SHIFT; + << ESD_USB_2_TSEG1_SHIFT; canbtr |= ((bt->phase_seg2 - 1) & (btc->tseg2_max - 1)) - << ESD_USB2_TSEG2_SHIFT; + << ESD_USB_2_TSEG2_SHIFT; if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) - canbtr |= ESD_USB2_3_SAMPLES; + canbtr |= ESD_USB_TRIPLE_SAMPLES; msg = kmalloc(sizeof(*msg), GFP_KERNEL); if (!msg) return -ENOMEM; msg->hdr.len = 2; - msg->hdr.cmd = CMD_SETBAUD; + msg->hdr.cmd = ESD_USB_CMD_SETBAUD; msg->setbaud.net = priv->index; msg->setbaud.rsvd = 0; msg->setbaud.baud = cpu_to_le32(canbtr); @@ -994,7 +994,7 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) int err = 0; int i; - netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS); + netdev = alloc_candev(sizeof(*priv), ESD_USB_MAX_TX_URBS); if (!netdev) { dev_err(&intf->dev, "couldn't alloc candev\n"); err = -ENOMEM; @@ -1006,8 +1006,8 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) init_usb_anchor(&priv->tx_submitted); atomic_set(&priv->active_tx_jobs, 0); - for (i = 0; i < MAX_TX_URBS; i++) - priv->tx_contexts[i].echo_index = MAX_TX_URBS; + for (i = 0; i < ESD_USB_MAX_TX_URBS; i++) + priv->tx_contexts[i].echo_index = ESD_USB_MAX_TX_URBS; priv->usb = dev; priv->netdev = netdev; @@ -1019,10 +1019,10 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) CAN_CTRLMODE_BERR_REPORTING; if (le16_to_cpu(dev->udev->descriptor.idProduct) == - USB_CANUSBM_PRODUCT_ID) - priv->can.clock.freq = ESD_USBM_CAN_CLOCK; + ESD_USB_CANUSBM_PRODUCT_ID) + priv->can.clock.freq = ESD_USB_M_CAN_CLOCK; else { - priv->can.clock.freq = ESD_USB2_CAN_CLOCK; + priv->can.clock.freq = ESD_USB_2_CAN_CLOCK; priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; } @@ -1085,7 +1085,7 @@ static int esd_usb_probe(struct usb_interface *intf, } /* query number of CAN interfaces (nets) */ - msg->hdr.cmd = CMD_VERSION; + msg->hdr.cmd = ESD_USB_CMD_VERSION; msg->hdr.len = 2; msg->version.rsvd = 0; msg->version.flags = 0; -- cgit v1.2.3 From 8ef426e1f605cea86f9375ca75b59b3e7afab5f7 Mon Sep 17 00:00:00 2001 From: Frank Jungclaus Date: Fri, 19 May 2023 21:55:58 +0200 Subject: can: esd_usb: Prefix all structures with the device name Prefix all the structures with the device name. For commonly used structures make use of (the module name) esd_usb_. For esd CAN-USB/2 and CAN-USB/Micro specific structures use esd_usb_2_ and esd_usb_m. Link: https://lore.kernel.org/all/CAMZ6RqLaDNy-fZ2G0+QMhUEckkXLL+ZyELVSDFmqpd++aBzZQg@mail.gmail.com/ Suggested-by: Vincent MAILHOL Signed-off-by: Frank Jungclaus Link: https://lore.kernel.org/r/20230519195600.420644-5-frank.jungclaus@esd.eu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index b7d5a82d602b..842e4dd187d4 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -89,13 +89,13 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB_MAX_RX_URBS 4 #define ESD_USB_MAX_TX_URBS 16 /* must be power of 2 */ -struct header_msg { +struct esd_usb_header_msg { u8 len; /* len is always the total message length in 32bit words */ u8 cmd; u8 rsvd[2]; }; -struct version_msg { +struct esd_usb_version_msg { u8 len; u8 cmd; u8 rsvd; @@ -103,7 +103,7 @@ struct version_msg { __le32 drv_version; }; -struct version_reply_msg { +struct esd_usb_version_reply_msg { u8 len; u8 cmd; u8 nets; @@ -114,7 +114,7 @@ struct version_reply_msg { __le32 ts; }; -struct rx_msg { +struct esd_usb_rx_msg { u8 len; u8 cmd; u8 net; @@ -132,7 +132,7 @@ struct rx_msg { }; }; -struct tx_msg { +struct esd_usb_tx_msg { u8 len; u8 cmd; u8 net; @@ -142,7 +142,7 @@ struct tx_msg { u8 data[CAN_MAX_DLEN]; }; -struct tx_done_msg { +struct esd_usb_tx_done_msg { u8 len; u8 cmd; u8 net; @@ -151,7 +151,7 @@ struct tx_done_msg { __le32 ts; }; -struct id_filter_msg { +struct esd_usb_id_filter_msg { u8 len; u8 cmd; u8 net; @@ -159,7 +159,7 @@ struct id_filter_msg { __le32 mask[ESD_USB_MAX_ID_SEGMENT + 1]; }; -struct set_baudrate_msg { +struct esd_usb_set_baudrate_msg { u8 len; u8 cmd; u8 net; @@ -169,14 +169,14 @@ struct set_baudrate_msg { /* Main message type used between library and application */ union __packed esd_usb_msg { - struct header_msg hdr; - struct version_msg version; - struct version_reply_msg version_reply; - struct rx_msg rx; - struct tx_msg tx; - struct tx_done_msg txdone; - struct set_baudrate_msg setbaud; - struct id_filter_msg filter; + struct esd_usb_header_msg hdr; + struct esd_usb_version_msg version; + struct esd_usb_version_reply_msg version_reply; + struct esd_usb_rx_msg rx; + struct esd_usb_tx_msg tx; + struct esd_usb_tx_done_msg txdone; + struct esd_usb_set_baudrate_msg setbaud; + struct esd_usb_id_filter_msg filter; }; static struct usb_device_id esd_usb_table[] = { @@ -899,8 +899,8 @@ static const struct ethtool_ops esd_usb_ethtool_ops = { .get_ts_info = ethtool_op_get_ts_info, }; -static const struct can_bittiming_const esd_usb2_bittiming_const = { - .name = "esd_usb2", +static const struct can_bittiming_const esd_usb_2_bittiming_const = { + .name = "esd_usb_2", .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1, @@ -911,9 +911,9 @@ static const struct can_bittiming_const esd_usb2_bittiming_const = { .brp_inc = 1, }; -static int esd_usb2_set_bittiming(struct net_device *netdev) +static int esd_usb_2_set_bittiming(struct net_device *netdev) { - const struct can_bittiming_const *btc = &esd_usb2_bittiming_const; + const struct can_bittiming_const *btc = &esd_usb_2_bittiming_const; struct esd_usb_net_priv *priv = netdev_priv(netdev); struct can_bittiming *bt = &priv->can.bittiming; union esd_usb_msg *msg; @@ -1026,8 +1026,8 @@ static int esd_usb_probe_one_net(struct usb_interface *intf, int index) priv->can.ctrlmode_supported |= CAN_CTRLMODE_3_SAMPLES; } - priv->can.bittiming_const = &esd_usb2_bittiming_const; - priv->can.do_set_bittiming = esd_usb2_set_bittiming; + priv->can.bittiming_const = &esd_usb_2_bittiming_const; + priv->can.do_set_bittiming = esd_usb_2_set_bittiming; priv->can.do_set_mode = esd_usb_set_mode; priv->can.do_get_berr_counter = esd_usb_get_berr_counter; -- cgit v1.2.3 From 299a557651d7847c2acb5c43674e2a1c85d38d16 Mon Sep 17 00:00:00 2001 From: Frank Jungclaus Date: Fri, 19 May 2023 21:55:59 +0200 Subject: can: esd_usb: Replace hardcoded message length given to USB commands Replace all hardcoded values supplied to the len element of esd_usb_msg (and its siblings) by more readable expressions, based on sizeof(), offsetof(), etc. Also spend documentation / comments that the len element of esd_usb_msg is in multiples of 32bit words and not in bytes. Link: https://lore.kernel.org/all/CAMZ6RqLaDNy-fZ2G0+QMhUEckkXLL+ZyELVSDFmqpd++aBzZQg@mail.gmail.com/ Suggested-by: Vincent MAILHOL Signed-off-by: Frank Jungclaus Link: https://lore.kernel.org/r/20230519195600.420644-6-frank.jungclaus@esd.eu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index 842e4dd187d4..c10fa578a5b0 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -90,13 +90,13 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB_MAX_TX_URBS 16 /* must be power of 2 */ struct esd_usb_header_msg { - u8 len; /* len is always the total message length in 32bit words */ + u8 len; /* total message length in 32bit words */ u8 cmd; u8 rsvd[2]; }; struct esd_usb_version_msg { - u8 len; + u8 len; /* total message length in 32bit words */ u8 cmd; u8 rsvd; u8 flags; @@ -104,7 +104,7 @@ struct esd_usb_version_msg { }; struct esd_usb_version_reply_msg { - u8 len; + u8 len; /* total message length in 32bit words */ u8 cmd; u8 nets; u8 features; @@ -115,7 +115,7 @@ struct esd_usb_version_reply_msg { }; struct esd_usb_rx_msg { - u8 len; + u8 len; /* total message length in 32bit words */ u8 cmd; u8 net; u8 dlc; @@ -133,7 +133,7 @@ struct esd_usb_rx_msg { }; struct esd_usb_tx_msg { - u8 len; + u8 len; /* total message length in 32bit words */ u8 cmd; u8 net; u8 dlc; @@ -143,7 +143,7 @@ struct esd_usb_tx_msg { }; struct esd_usb_tx_done_msg { - u8 len; + u8 len; /* total message length in 32bit words */ u8 cmd; u8 net; u8 status; @@ -152,15 +152,15 @@ struct esd_usb_tx_done_msg { }; struct esd_usb_id_filter_msg { - u8 len; + u8 len; /* total message length in 32bit words */ u8 cmd; u8 net; u8 option; - __le32 mask[ESD_USB_MAX_ID_SEGMENT + 1]; + __le32 mask[ESD_USB_MAX_ID_SEGMENT + 1]; /* +1 for 29bit extended IDs */ }; struct esd_usb_set_baudrate_msg { - u8 len; + u8 len; /* total message length in 32bit words */ u8 cmd; u8 net; u8 rsvd; @@ -438,7 +438,7 @@ static void esd_usb_read_bulk_callback(struct urb *urb) break; } - pos += msg->hdr.len << 2; + pos += msg->hdr.len * sizeof(u32); /* convert to # of bytes */ if (pos > urb->actual_length) { dev_err(dev->udev->dev.parent, "format error\n"); @@ -532,7 +532,7 @@ static int esd_usb_send_msg(struct esd_usb *dev, union esd_usb_msg *msg) return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), msg, - msg->hdr.len << 2, + msg->hdr.len * sizeof(u32), /* convert to # of bytes */ &actual_length, 1000); } @@ -648,7 +648,7 @@ static int esd_usb_start(struct esd_usb_net_priv *priv) * field followed by only some bitmasks. */ msg->hdr.cmd = ESD_USB_CMD_IDADD; - msg->hdr.len = 2 + ESD_USB_MAX_ID_SEGMENT; + msg->hdr.len = sizeof(struct esd_usb_id_filter_msg) / sizeof(u32); /* # of 32bit words */ msg->filter.net = priv->index; msg->filter.option = ESD_USB_ID_ENABLE; /* start with segment 0 */ for (i = 0; i < ESD_USB_MAX_ID_SEGMENT; i++) @@ -759,7 +759,8 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, msg = (union esd_usb_msg *)buf; - msg->hdr.len = 3; /* minimal length */ + /* minimal length as # of 32bit words */ + msg->hdr.len = offsetof(struct esd_usb_tx_msg, data) / sizeof(u32); msg->hdr.cmd = ESD_USB_CMD_CAN_TX; msg->tx.net = priv->index; msg->tx.dlc = can_get_cc_dlc(cf, priv->can.ctrlmode); @@ -774,7 +775,8 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, for (i = 0; i < cf->len; i++) msg->tx.data[i] = cf->data[i]; - msg->hdr.len += (cf->len + 3) >> 2; + /* round up, then divide by 4 to add the payload length as # of 32bit words */ + msg->hdr.len += DIV_ROUND_UP(cf->len, sizeof(u32)); for (i = 0; i < ESD_USB_MAX_TX_URBS; i++) { if (priv->tx_contexts[i].echo_index == ESD_USB_MAX_TX_URBS) { @@ -797,7 +799,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, msg->tx.hnd = 0x80000000 | i; /* returned in TX done message */ usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf, - msg->hdr.len << 2, + msg->hdr.len * sizeof(u32), /* convert to # of bytes */ esd_usb_write_bulk_callback, context); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -860,7 +862,7 @@ static int esd_usb_close(struct net_device *netdev) /* Disable all IDs (see esd_usb_start()) */ msg->hdr.cmd = ESD_USB_CMD_IDADD; - msg->hdr.len = 2 + ESD_USB_MAX_ID_SEGMENT; + msg->hdr.len = sizeof(struct esd_usb_id_filter_msg) / sizeof(u32);/* # of 32bit words */ msg->filter.net = priv->index; msg->filter.option = ESD_USB_ID_ENABLE; /* start with segment 0 */ for (i = 0; i <= ESD_USB_MAX_ID_SEGMENT; i++) @@ -869,7 +871,7 @@ static int esd_usb_close(struct net_device *netdev) netdev_err(netdev, "sending idadd message failed\n"); /* set CAN controller to reset mode */ - msg->hdr.len = 2; + msg->hdr.len = sizeof(struct esd_usb_set_baudrate_msg) / sizeof(u32); /* # of 32bit words */ msg->hdr.cmd = ESD_USB_CMD_SETBAUD; msg->setbaud.net = priv->index; msg->setbaud.rsvd = 0; @@ -947,7 +949,7 @@ static int esd_usb_2_set_bittiming(struct net_device *netdev) if (!msg) return -ENOMEM; - msg->hdr.len = 2; + msg->hdr.len = sizeof(struct esd_usb_set_baudrate_msg) / sizeof(u32); /* # of 32bit words */ msg->hdr.cmd = ESD_USB_CMD_SETBAUD; msg->setbaud.net = priv->index; msg->setbaud.rsvd = 0; @@ -1086,7 +1088,7 @@ static int esd_usb_probe(struct usb_interface *intf, /* query number of CAN interfaces (nets) */ msg->hdr.cmd = ESD_USB_CMD_VERSION; - msg->hdr.len = 2; + msg->hdr.len = sizeof(struct esd_usb_version_msg) / sizeof(u32); /* # of 32bit words */ msg->version.rsvd = 0; msg->version.flags = 0; msg->version.drv_version = 0; -- cgit v1.2.3 From 1336ca2d46017d4249a9bd6a9a403d1e86109751 Mon Sep 17 00:00:00 2001 From: Frank Jungclaus Date: Fri, 19 May 2023 21:56:00 +0200 Subject: can: esd_usb: Don't bother the user with nonessential log message Replace a netdev_info(), emitting an informational message about the BTR value to be send to the controller, with a debug message by means of netdev_dbg(). Link: https://lore.kernel.org/all/20230509-superglue-hazy-38108aa66bfa-mkl@pengutronix.de/ Suggested-by: Marc Kleine-Budde Suggested-by: Vincent MAILHOL Signed-off-by: Frank Jungclaus Link: https://lore.kernel.org/r/20230519195600.420644-7-frank.jungclaus@esd.eu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index c10fa578a5b0..1399b832ea3f 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -955,7 +955,7 @@ static int esd_usb_2_set_bittiming(struct net_device *netdev) msg->setbaud.rsvd = 0; msg->setbaud.baud = cpu_to_le32(canbtr); - netdev_info(netdev, "setting BTR=%#x\n", canbtr); + netdev_dbg(netdev, "setting BTR=%#x\n", canbtr); err = esd_usb_send_msg(priv->usb, msg); -- cgit v1.2.3 From 33665fdbd7ff825f2c7369524f0d985707e9f029 Mon Sep 17 00:00:00 2001 From: Frank Jungclaus Date: Tue, 23 May 2023 19:31:04 +0200 Subject: can: esd_usb: Make use of kernel macros BIT() and GENMASK() Make use of kernel macros BIT() and GENMASK(). Signed-off-by: Frank Jungclaus Link: https://lore.kernel.org/r/20230523173105.3175086-2-frank.jungclaus@esd.eu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index 1399b832ea3f..d40a04db7458 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -67,23 +67,23 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB_TRIPLE_SAMPLES BIT(23) /* esd IDADD message */ -#define ESD_USB_ID_ENABLE 0x80 +#define ESD_USB_ID_ENABLE BIT(7) #define ESD_USB_MAX_ID_SEGMENT 64 /* SJA1000 ECC register (emulated by usb firmware) */ -#define ESD_USB_SJA1000_ECC_SEG 0x1F -#define ESD_USB_SJA1000_ECC_DIR 0x20 -#define ESD_USB_SJA1000_ECC_ERR 0x06 +#define ESD_USB_SJA1000_ECC_SEG GENMASK(4, 0) +#define ESD_USB_SJA1000_ECC_DIR BIT(5) +#define ESD_USB_SJA1000_ECC_ERR BIT(2, 1) #define ESD_USB_SJA1000_ECC_BIT 0x00 -#define ESD_USB_SJA1000_ECC_FORM 0x40 -#define ESD_USB_SJA1000_ECC_STUFF 0x80 -#define ESD_USB_SJA1000_ECC_MASK 0xc0 +#define ESD_USB_SJA1000_ECC_FORM BIT(6) +#define ESD_USB_SJA1000_ECC_STUFF BIT(7) +#define ESD_USB_SJA1000_ECC_MASK GENMASK(7, 6) /* esd bus state event codes */ -#define ESD_USB_BUSSTATE_MASK 0xc0 -#define ESD_USB_BUSSTATE_WARN 0x40 -#define ESD_USB_BUSSTATE_ERRPASSIVE 0x80 -#define ESD_USB_BUSSTATE_BUSOFF 0xc0 +#define ESD_USB_BUSSTATE_MASK GENMASK(7, 6) +#define ESD_USB_BUSSTATE_WARN BIT(6) +#define ESD_USB_BUSSTATE_ERRPASSIVE BIT(7) +#define ESD_USB_BUSSTATE_BUSOFF GENMASK(7, 6) #define ESD_USB_RX_BUFFER_SIZE 1024 #define ESD_USB_MAX_RX_URBS 4 @@ -652,9 +652,9 @@ static int esd_usb_start(struct esd_usb_net_priv *priv) msg->filter.net = priv->index; msg->filter.option = ESD_USB_ID_ENABLE; /* start with segment 0 */ for (i = 0; i < ESD_USB_MAX_ID_SEGMENT; i++) - msg->filter.mask[i] = cpu_to_le32(0xffffffff); + msg->filter.mask[i] = cpu_to_le32(GENMASK(31, 0)); /* enable 29bit extended IDs */ - msg->filter.mask[ESD_USB_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001); + msg->filter.mask[ESD_USB_MAX_ID_SEGMENT] = cpu_to_le32(BIT(0)); err = esd_usb_send_msg(dev, msg); if (err) @@ -796,7 +796,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, context->echo_index = i; /* hnd must not be 0 - MSB is stripped in txdone handling */ - msg->tx.hnd = 0x80000000 | i; /* returned in TX done message */ + msg->tx.hnd = BIT(31) | i; /* returned in TX done message */ usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf, msg->hdr.len * sizeof(u32), /* convert to # of bytes */ -- cgit v1.2.3 From 8a99f2ada0b808aaaa3e2f13c15e623c7fe329bd Mon Sep 17 00:00:00 2001 From: Frank Jungclaus Date: Tue, 23 May 2023 19:31:05 +0200 Subject: can: esd_usb: Use consistent prefix ESD_USB_ for macros Rename the following macros: - ESD_RTR to ESD_USB_RTR - ESD_EV_CAN_ERROR_EXT to ESD_USB_EV_CAN_ERROR_EXT Additionally remove the double newline trailing to definition of ESD_USB_RTR. Signed-off-by: Frank Jungclaus Link: https://lore.kernel.org/r/20230523173105.3175086-3-frank.jungclaus@esd.eu Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index d40a04db7458..6201637ac0ff 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -43,8 +43,7 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB_CMD_IDADD 6 /* also used for IDADD_REPLY */ /* esd CAN message flags - dlc field */ -#define ESD_RTR BIT(4) - +#define ESD_USB_RTR BIT(4) /* esd CAN message flags - id field */ #define ESD_USB_EXTID BIT(29) @@ -52,7 +51,7 @@ MODULE_LICENSE("GPL v2"); #define ESD_USB_IDMASK GENMASK(28, 0) /* esd CAN event ids */ -#define ESD_EV_CAN_ERROR_EXT 2 /* CAN controller specific diagnostic data */ +#define ESD_USB_EV_CAN_ERROR_EXT 2 /* CAN controller specific diagnostic data */ /* baudrate message flags */ #define ESD_USB_LOM BIT(30) /* Listen Only Mode */ @@ -228,7 +227,7 @@ static void esd_usb_rx_event(struct esd_usb_net_priv *priv, struct sk_buff *skb; u32 id = le32_to_cpu(msg->rx.id) & ESD_USB_IDMASK; - if (id == ESD_EV_CAN_ERROR_EXT) { + if (id == ESD_USB_EV_CAN_ERROR_EXT) { u8 state = msg->rx.ev_can_err_ext.status; u8 ecc = msg->rx.ev_can_err_ext.ecc; @@ -341,13 +340,13 @@ static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv, } cf->can_id = id & ESD_USB_IDMASK; - can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_RTR, + can_frame_set_cc_len(cf, msg->rx.dlc & ~ESD_USB_RTR, priv->can.ctrlmode); if (id & ESD_USB_EXTID) cf->can_id |= CAN_EFF_FLAG; - if (msg->rx.dlc & ESD_RTR) { + if (msg->rx.dlc & ESD_USB_RTR) { cf->can_id |= CAN_RTR_FLAG; } else { for (i = 0; i < cf->len; i++) @@ -767,7 +766,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb, msg->tx.id = cpu_to_le32(cf->can_id & CAN_ERR_MASK); if (cf->can_id & CAN_RTR_FLAG) - msg->tx.dlc |= ESD_RTR; + msg->tx.dlc |= ESD_USB_RTR; if (cf->can_id & CAN_EFF_FLAG) msg->tx.id |= cpu_to_le32(ESD_USB_EXTID); -- cgit v1.2.3 From af7647a0b4b50c3f988a76b05dea5e6bf20c858a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 16 Jun 2023 15:45:52 +0200 Subject: can: sja1000: Prepare the use of a threaded handler In order to support a flavor of the sja1000 which sometimes freezes, it will be needed upon certain interrupts to perform a soft reset. The soft reset operation takes a bit of time, so better not do it within the hard interrupt handler but rather in a threaded handler. Let's prepare the possibility for sja1000_err() to request "interrupting" the current flow and request the threaded handler to be run while keeping the interrupt line low. There is no functional change. Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/all/20230616134553.2786391-1-miquel.raynal@bootlin.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index aac5956e4a53..4719806e3a9f 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -501,7 +501,8 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) struct sja1000_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; uint8_t isrc, status; - int n = 0; + irqreturn_t ret = 0; + int n = 0, err; if (priv->pre_irq) priv->pre_irq(priv); @@ -546,19 +547,23 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) } if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { /* error interrupt */ - if (sja1000_err(dev, isrc, status)) + err = sja1000_err(dev, isrc, status); + if (err) break; } n++; } out: + if (!ret) + ret = (n) ? IRQ_HANDLED : IRQ_NONE; + if (priv->post_irq) priv->post_irq(priv); if (n >= SJA1000_MAX_IRQ) netdev_dbg(dev, "%d messages handled in ISR", n); - return (n) ? IRQ_HANDLED : IRQ_NONE; + return ret; } EXPORT_SYMBOL_GPL(sja1000_interrupt); -- cgit v1.2.3 From 717c6ec241b5524400acc0f6009b89e2c59527f9 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Fri, 16 Jun 2023 15:45:53 +0200 Subject: can: sja1000: Prevent overrun stalls with a soft reset on Renesas SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In their RZN1 SoC, Renesas put a CAN controller supposed to act very similarly to the original Philips sja1000. In practice, while flooding the bus with another device, we discovered that the controller very often after an overrun situation would just refuse any new frame, drop them all and trigger over and over again the overrun interrupt, even though the buffer would have been totally emptied. The controller acts like if its internal buffer offsets (where it writes and where the host reads) where totally screwed-up. Renesas manual mentions a single action to perform in order to resynchronize the read and write offsets within the buffer: performing a soft reset. Performing a soft reset takes a bit of time and involves small delays, so better do that in a threaded handler rather than inside the hard IRQ handler. Add platform data to recognize the platforms which need this workaround, and when the faulty situation is diagnosed, stop what is being performed and request the threaded handler to be executed in order to perform the reset. Tested-by: Jérémie Dautheribes # 5.10 Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/all/20230616134553.2786391-2-miquel.raynal@bootlin.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sja1000/sja1000.c | 29 ++++++++++++++++++++++++++--- drivers/net/can/sja1000/sja1000.h | 1 + drivers/net/can/sja1000/sja1000_platform.c | 5 ++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 4719806e3a9f..0ada0e160e93 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -387,6 +387,16 @@ static void sja1000_rx(struct net_device *dev) netif_rx(skb); } +static irqreturn_t sja1000_reset_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *)dev_id; + + netdev_dbg(dev, "performing a soft reset upon overrun\n"); + sja1000_start(dev); + + return IRQ_HANDLED; +} + static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) { struct sja1000_priv *priv = netdev_priv(dev); @@ -397,6 +407,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) enum can_state rx_state, tx_state; unsigned int rxerr, txerr; uint8_t ecc, alc; + int ret = 0; skb = alloc_can_err_skb(dev, &cf); if (skb == NULL) @@ -413,6 +424,15 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) stats->rx_over_errors++; stats->rx_errors++; sja1000_write_cmdreg(priv, CMD_CDO); /* clear bit */ + + /* Some controllers needs additional handling upon overrun + * condition: the controller may sometimes be totally confused + * and refuse any new frame while its buffer is empty. The only + * way to re-sync the read vs. write buffer offsets is to + * stop any current handling and perform a reset. + */ + if (priv->flags & SJA1000_QUIRK_RESET_ON_OVERRUN) + ret = IRQ_WAKE_THREAD; } if (isrc & IRQ_EI) { @@ -492,7 +512,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) netif_rx(skb); - return 0; + return ret; } irqreturn_t sja1000_interrupt(int irq, void *dev_id) @@ -548,6 +568,8 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) { /* error interrupt */ err = sja1000_err(dev, isrc, status); + if (err == IRQ_WAKE_THREAD) + ret = err; if (err) break; } @@ -582,8 +604,9 @@ static int sja1000_open(struct net_device *dev) /* register interrupt handler, if not done by the device driver */ if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER)) { - err = request_irq(dev->irq, sja1000_interrupt, priv->irq_flags, - dev->name, (void *)dev); + err = request_threaded_irq(dev->irq, sja1000_interrupt, + sja1000_reset_interrupt, + priv->irq_flags, dev->name, (void *)dev); if (err) { close_candev(dev); return -EAGAIN; diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index 7f736f1df547..f015e39e2224 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -147,6 +147,7 @@ */ #define SJA1000_CUSTOM_IRQ_HANDLER BIT(0) #define SJA1000_QUIRK_NO_CDR_REG BIT(1) +#define SJA1000_QUIRK_RESET_ON_OVERRUN BIT(2) /* * SJA1000 private data structure diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index b4889b5746e5..4e59952c66d4 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -106,7 +106,7 @@ static void sp_technologic_init(struct sja1000_priv *priv, struct device_node *o static void sp_rzn1_init(struct sja1000_priv *priv, struct device_node *of) { - priv->flags = SJA1000_QUIRK_NO_CDR_REG; + priv->flags = SJA1000_QUIRK_NO_CDR_REG | SJA1000_QUIRK_RESET_ON_OVERRUN; } static void sp_populate(struct sja1000_priv *priv, @@ -277,6 +277,9 @@ static int sp_probe(struct platform_device *pdev) priv->irq_flags = IRQF_SHARED; } + if (priv->flags & SJA1000_QUIRK_RESET_ON_OVERRUN) + priv->irq_flags |= IRQF_ONESHOT; + dev->irq = irq; priv->reg_base = addr; -- cgit v1.2.3 From fe6027fe097a173d12067e781143bc1cd2fb1a57 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 20 Jun 2023 15:11:29 +0200 Subject: can: rx-offload: fix coding style This patch aligns code to match open parenthesis. Link: https://lore.kernel.org/all/20230620131130.240180-2-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev/rx-offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/dev/rx-offload.c b/drivers/net/can/dev/rx-offload.c index 81ebf0562c89..161e45a7e8c1 100644 --- a/drivers/net/can/dev/rx-offload.c +++ b/drivers/net/can/dev/rx-offload.c @@ -220,7 +220,7 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload) EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo); int can_rx_offload_queue_timestamp(struct can_rx_offload *offload, - struct sk_buff *skb, u32 timestamp) + struct sk_buff *skb, u32 timestamp) { struct can_rx_offload_cb *cb; -- cgit v1.2.3 From 8a9d8a3c8a05fdb9d076905855bc0d5b5ee8c881 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 20 Jun 2023 15:11:30 +0200 Subject: can: ti_hecc: fix coding style This patch aligns code to match open parenthesis. Link: https://lore.kernel.org/all/20230620131130.240180-3-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ti_hecc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 9bab0b4cc449..54284661992e 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -625,7 +625,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, timestamp = hecc_read(priv, HECC_CANLNT); err = can_rx_offload_queue_timestamp(&priv->offload, skb, - timestamp); + timestamp); if (err) ndev->stats.rx_fifo_errors++; } -- cgit v1.2.3 From 3d68f116ccdfe8cd3a4923b47ae55401fd85d74b Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 23 May 2023 08:11:16 +0200 Subject: can: m_can: fix coding style This patch aligns code to match open parenthesis and removes a trailing whitespace. Fixes: eb38c2053b67 ("can: rx-offload: rename can_rx_offload_queue_sorted() -> can_rx_offload_queue_timestamp()") Fixes: f5071d9e729d ("can: m_can: m_can_handle_bus_errors(): add support for handling DLEC error on CAN-FD frames") Reported-by: Judith Mendez Link: https://lore.kernel.org/all/20230523062410.1984098-1-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index a5003435802b..c5af92bcc9c9 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -469,7 +469,7 @@ static void m_can_receive_skb(struct m_can_classdev *cdev, int err; err = can_rx_offload_queue_timestamp(&cdev->offload, skb, - timestamp); + timestamp); if (err) stats->rx_fifo_errors++; } else { @@ -895,7 +895,7 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus, netdev_dbg(dev, "Arbitration phase error detected\n"); work_done += m_can_handle_lec_err(dev, lec); } - + if (is_lec_err(dlec)) { netdev_dbg(dev, "Data phase error detected\n"); work_done += m_can_handle_lec_err(dev, dlec); -- cgit v1.2.3 From 10711b11102bfc351240982d46a51d4eecc28c10 Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Sun, 11 Jun 2023 11:57:27 +0900 Subject: can: length: fix description of the RRS field The CAN-FD frames only have one reserved bit. The bit corresponding to Classical CAN frame's RTR bit is called the "Remote Request Substitution (RRS)" [1]. N.B. The RRS is not to be confused with the Substitute Remote Request (SRR). Fix the description in the CANFD_FRAME_OVERHEAD_SFF/EFF macros. The total remains unchanged, so this is just a documentation fix. In addition to the above add myself as copyright owner for 2020 (as coauthor of the initial version, c.f. Fixes tag). [1] ISO 11898-1:2015 paragraph 10.4.2.3 "Arbitration field": RSS bit [only in FD Frames] The RRS bit shall be transmitted in FD Frames at the position of the RTR bit in Classical Frames. The RRS bit shall be transmitted dominant, but receivers shall accept recessive and dominant RRS bits. Fixes: 85d99c3e2a13 ("can: length: can_skb_get_frame_len(): introduce function to get data length of frame in data link layer") Signed-off-by: Vincent Mailhol Reviewed-by: Thomas Kopp Link: https://lore.kernel.org/all/20230611025728.450837-3-mailhol.vincent@wanadoo.fr Signed-off-by: Marc Kleine-Budde --- include/linux/can/length.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/can/length.h b/include/linux/can/length.h index b8c12c83bc51..521fdbce2d69 100644 --- a/include/linux/can/length.h +++ b/include/linux/can/length.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (C) 2020 Oliver Hartkopp * Copyright (C) 2020 Marc Kleine-Budde + * Copyright (C) 2020 Vincent Mailhol */ #ifndef _CAN_LENGTH_H @@ -64,7 +65,7 @@ * --------------------------------------------------------- * Start-of-frame 1 * Identifier 11 - * Reserved bit (r1) 1 + * Remote Request Substitution (RRS) 1 * Identifier extension bit (IDE) 1 * Flexible data rate format (FDF) 1 * Reserved bit (r0) 1 @@ -95,7 +96,7 @@ * Substitute remote request (SRR) 1 * Identifier extension bit (IDE) 1 * Identifier B 18 - * Reserved bit (r1) 1 + * Remote Request Substitution (RRS) 1 * Flexible data rate format (FDF) 1 * Reserved bit (r0) 1 * Bit Rate Switch (BRS) 1 -- cgit v1.2.3 From 9fde4c557f78ee2f3626e92b4089ce9d54a2573a Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Sun, 11 Jun 2023 11:57:26 +0900 Subject: can: length: fix bitstuffing count The Stuff Bit Count is always coded on 4 bits [1]. Update the Stuff Bit Count size accordingly. In addition, the CRC fields of CAN FD Frames contain stuff bits at fixed positions called fixed stuff bits [2]. The CRC field starts with a fixed stuff bit and then has another fixed stuff bit after each fourth bit [2], which allows us to derive this formula: FSB count = 1 + round_down(len(CRC field)/4) The length of the CRC field is [1]: len(CRC field) = len(Stuff Bit Count) + len(CRC) = 4 + len(CRC) with len(CRC) either 17 or 21 bits depending of the payload length. In conclusion, for CRC17: FSB count = 1 + round_down((4 + 17)/4) = 6 and for CRC 21: FSB count = 1 + round_down((4 + 21)/4) = 7 Add a Fixed Stuff bits (FSB) field with above values and update CANFD_FRAME_OVERHEAD_SFF and CANFD_FRAME_OVERHEAD_EFF accordingly. [1] ISO 11898-1:2015 section 10.4.2.6 "CRC field": The CRC field shall contain the CRC sequence followed by a recessive CRC delimiter. For FD Frames, the CRC field shall also contain the stuff count. Stuff count If FD Frames, the stuff count shall be at the beginning of the CRC field. It shall consist of the stuff bit count modulo 8 in a 3-bit gray code followed by a parity bit [...] [2] ISO 11898-1:2015 paragraph 10.5 "Frame coding": In the CRC field of FD Frames, the stuff bits shall be inserted at fixed positions; they are called fixed stuff bits. There shall be a fixed stuff bit before the first bit of the stuff count, even if the last bits of the preceding field are a sequence of five consecutive bits of identical value, there shall be only the fixed stuff bit, there shall not be two consecutive stuff bits. A further fixed stuff bit shall be inserted after each fourth bit of the CRC field [...] Fixes: 85d99c3e2a13 ("can: length: can_skb_get_frame_len(): introduce function to get data length of frame in data link layer") Suggested-by: Thomas Kopp Signed-off-by: Vincent Mailhol Reviewed-by: Thomas Kopp Link: https://lore.kernel.org/all/20230611025728.450837-2-mailhol.vincent@wanadoo.fr Signed-off-by: Marc Kleine-Budde --- include/linux/can/length.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/linux/can/length.h b/include/linux/can/length.h index 69336549d24f..b8c12c83bc51 100644 --- a/include/linux/can/length.h +++ b/include/linux/can/length.h @@ -72,17 +72,18 @@ * Error Status Indicator (ESI) 1 * Data length code (DLC) 4 * Data field 0...512 - * Stuff Bit Count (SBC) 0...16: 4 20...64:5 + * Stuff Bit Count (SBC) 4 * CRC 0...16: 17 20...64:21 * CRC delimiter (CD) 1 + * Fixed Stuff bits (FSB) 0...16: 6 20...64:7 * ACK slot (AS) 1 * ACK delimiter (AD) 1 * End-of-frame (EOF) 7 * Inter frame spacing 3 * - * assuming CRC21, rounded up and ignoring bitstuffing + * assuming CRC21, rounded up and ignoring dynamic bitstuffing */ -#define CANFD_FRAME_OVERHEAD_SFF DIV_ROUND_UP(61, 8) +#define CANFD_FRAME_OVERHEAD_SFF DIV_ROUND_UP(67, 8) /* * Size of a CAN-FD Extended Frame @@ -101,17 +102,18 @@ * Error Status Indicator (ESI) 1 * Data length code (DLC) 4 * Data field 0...512 - * Stuff Bit Count (SBC) 0...16: 4 20...64:5 + * Stuff Bit Count (SBC) 4 * CRC 0...16: 17 20...64:21 * CRC delimiter (CD) 1 + * Fixed Stuff bits (FSB) 0...16: 6 20...64:7 * ACK slot (AS) 1 * ACK delimiter (AD) 1 * End-of-frame (EOF) 7 * Inter frame spacing 3 * - * assuming CRC21, rounded up and ignoring bitstuffing + * assuming CRC21, rounded up and ignoring dynamic bitstuffing */ -#define CANFD_FRAME_OVERHEAD_EFF DIV_ROUND_UP(80, 8) +#define CANFD_FRAME_OVERHEAD_EFF DIV_ROUND_UP(86, 8) /* * Maximum size of a Classical CAN frame -- cgit v1.2.3 From 80a2fbce456e3f73b4f49ce12fefa3215a3d0773 Mon Sep 17 00:00:00 2001 From: Vincent Mailhol Date: Sun, 11 Jun 2023 11:57:28 +0900 Subject: can: length: refactor frame lengths definition to add size in bits Introduce a method to calculate the exact size in bits of a CAN(-FD) frame with or without dynamic bitstuffing. These are all the possible combinations taken into account: - Classical CAN or CAN-FD - Standard or Extended frame format - CAN-FD CRC17 or CRC21 - Include or not intermission Instead of doing several individual macro definitions, declare the can_frame_bits() function-like macro. To this extent, do a full refactoring of the length definitions. In addition add the can_frame_bytes(). This function-like macro replaces the existing macro: - CAN_FRAME_OVERHEAD_SFF: can_frame_bytes(false, false, 0) - CAN_FRAME_OVERHEAD_EFF: can_frame_bytes(false, true, 0) - CANFD_FRAME_OVERHEAD_SFF: can_frame_bytes(true, false, 0) - CANFD_FRAME_OVERHEAD_EFF: can_frame_bytes(true, true, 0) Function-like macros were chosen over inline functions because they can be used to initialize const struct fields. The different maximum frame lengths (maximum data length, including intermission) are as follow: Frame type bits bytes ------------------------------------------------------- Classic CAN SFF no bitstuffing 111 14 Classic CAN EFF no bitstuffing 131 17 Classic CAN SFF bitstuffing 135 17 Classic CAN EFF bitstuffing 160 20 CAN-FD SFF no bitstuffing 579 73 CAN-FD EFF no bitstuffing 598 75 CAN-FD SFF bitstuffing 712 89 CAN-FD EFF bitstuffing 736 92 The macro CAN_FRAME_LEN_MAX and CANFD_FRAME_LEN_MAX are kept as an alias to, respectively, can_frame_bytes(false, true, CAN_MAX_DLEN) and can_frame_bytes(true, true, CANFD_MAX_DLEN). In addition to the above: - Use ISO 11898-1:2015 definitions for the names of the CAN frame fields. - Include linux/bits.h for use of BITS_PER_BYTE. - Include linux/math.h for use of mult_frac() and DIV_ROUND_UP(). N.B: the use of DIV_ROUND_UP() is not new to this patch, but the include was previously omitted. - Add copyright 2023 for myself. Suggested-by: Thomas Kopp Signed-off-by: Vincent Mailhol Reviewed-by: Thomas Kopp Link: https://lore.kernel.org/all/20230611025728.450837-4-mailhol.vincent@wanadoo.fr Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev/length.c | 15 +-- include/linux/can/length.h | 302 ++++++++++++++++++++++++++++++------------- 2 files changed, 216 insertions(+), 101 deletions(-) diff --git a/drivers/net/can/dev/length.c b/drivers/net/can/dev/length.c index b48140b1102e..b7f4d76dd444 100644 --- a/drivers/net/can/dev/length.c +++ b/drivers/net/can/dev/length.c @@ -78,18 +78,7 @@ unsigned int can_skb_get_frame_len(const struct sk_buff *skb) else len = cf->len; - if (can_is_canfd_skb(skb)) { - if (cf->can_id & CAN_EFF_FLAG) - len += CANFD_FRAME_OVERHEAD_EFF; - else - len += CANFD_FRAME_OVERHEAD_SFF; - } else { - if (cf->can_id & CAN_EFF_FLAG) - len += CAN_FRAME_OVERHEAD_EFF; - else - len += CAN_FRAME_OVERHEAD_SFF; - } - - return len; + return can_frame_bytes(can_is_canfd_skb(skb), cf->can_id & CAN_EFF_FLAG, + false, len); } EXPORT_SYMBOL_GPL(can_skb_get_frame_len); diff --git a/include/linux/can/length.h b/include/linux/can/length.h index 521fdbce2d69..abc978b38f79 100644 --- a/include/linux/can/length.h +++ b/include/linux/can/length.h @@ -1,132 +1,258 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (C) 2020 Oliver Hartkopp * Copyright (C) 2020 Marc Kleine-Budde - * Copyright (C) 2020 Vincent Mailhol + * Copyright (C) 2020, 2023 Vincent Mailhol */ #ifndef _CAN_LENGTH_H #define _CAN_LENGTH_H +#include #include #include +#include /* - * Size of a Classical CAN Standard Frame + * Size of a Classical CAN Standard Frame header in bits * - * Name of Field Bits + * Name of Field Bits * --------------------------------------------------------- - * Start-of-frame 1 - * Identifier 11 - * Remote transmission request (RTR) 1 - * Identifier extension bit (IDE) 1 - * Reserved bit (r0) 1 - * Data length code (DLC) 4 - * Data field 0...64 - * CRC 15 - * CRC delimiter 1 - * ACK slot 1 - * ACK delimiter 1 - * End-of-frame (EOF) 7 - * Inter frame spacing 3 + * Start Of Frame (SOF) 1 + * Arbitration field: + * base ID 11 + * Remote Transmission Request (RTR) 1 + * Control field: + * IDentifier Extension bit (IDE) 1 + * FD Format indicator (FDF) 1 + * Data Length Code (DLC) 4 + * + * including all fields preceding the data field, ignoring bitstuffing + */ +#define CAN_FRAME_HEADER_SFF_BITS 19 + +/* + * Size of a Classical CAN Extended Frame header in bits * - * rounded up and ignoring bitstuffing + * Name of Field Bits + * --------------------------------------------------------- + * Start Of Frame (SOF) 1 + * Arbitration field: + * base ID 11 + * Substitute Remote Request (SRR) 1 + * IDentifier Extension bit (IDE) 1 + * ID extension 18 + * Remote Transmission Request (RTR) 1 + * Control field: + * FD Format indicator (FDF) 1 + * Reserved bit (r0) 1 + * Data length code (DLC) 4 + * + * including all fields preceding the data field, ignoring bitstuffing */ -#define CAN_FRAME_OVERHEAD_SFF DIV_ROUND_UP(47, 8) +#define CAN_FRAME_HEADER_EFF_BITS 39 /* - * Size of a Classical CAN Extended Frame + * Size of a CAN-FD Standard Frame in bits + * + * Name of Field Bits + * --------------------------------------------------------- + * Start Of Frame (SOF) 1 + * Arbitration field: + * base ID 11 + * Remote Request Substitution (RRS) 1 + * Control field: + * IDentifier Extension bit (IDE) 1 + * FD Format indicator (FDF) 1 + * Reserved bit (res) 1 + * Bit Rate Switch (BRS) 1 + * Error Status Indicator (ESI) 1 + * Data length code (DLC) 4 + * + * including all fields preceding the data field, ignoring bitstuffing + */ +#define CANFD_FRAME_HEADER_SFF_BITS 22 + +/* + * Size of a CAN-FD Extended Frame in bits + * + * Name of Field Bits + * --------------------------------------------------------- + * Start Of Frame (SOF) 1 + * Arbitration field: + * base ID 11 + * Substitute Remote Request (SRR) 1 + * IDentifier Extension bit (IDE) 1 + * ID extension 18 + * Remote Request Substitution (RRS) 1 + * Control field: + * FD Format indicator (FDF) 1 + * Reserved bit (res) 1 + * Bit Rate Switch (BRS) 1 + * Error Status Indicator (ESI) 1 + * Data length code (DLC) 4 + * + * including all fields preceding the data field, ignoring bitstuffing + */ +#define CANFD_FRAME_HEADER_EFF_BITS 41 + +/* + * Size of a CAN CRC Field in bits * * Name of Field Bits * --------------------------------------------------------- - * Start-of-frame 1 - * Identifier A 11 - * Substitute remote request (SRR) 1 - * Identifier extension bit (IDE) 1 - * Identifier B 18 - * Remote transmission request (RTR) 1 - * Reserved bits (r1, r0) 2 - * Data length code (DLC) 4 - * Data field 0...64 - * CRC 15 - * CRC delimiter 1 - * ACK slot 1 - * ACK delimiter 1 - * End-of-frame (EOF) 7 - * Inter frame spacing 3 + * CRC sequence (CRC15) 15 + * CRC Delimiter 1 + * + * ignoring bitstuffing + */ +#define CAN_FRAME_CRC_FIELD_BITS 16 + +/* + * Size of a CAN-FD CRC17 Field in bits (length: 0..16) * - * rounded up and ignoring bitstuffing + * Name of Field Bits + * --------------------------------------------------------- + * Stuff Count 4 + * CRC Sequence (CRC17) 17 + * CRC Delimiter 1 + * Fixed stuff bits 6 */ -#define CAN_FRAME_OVERHEAD_EFF DIV_ROUND_UP(67, 8) +#define CANFD_FRAME_CRC17_FIELD_BITS 28 /* - * Size of a CAN-FD Standard Frame + * Size of a CAN-FD CRC21 Field in bits (length: 20..64) * * Name of Field Bits * --------------------------------------------------------- - * Start-of-frame 1 - * Identifier 11 - * Remote Request Substitution (RRS) 1 - * Identifier extension bit (IDE) 1 - * Flexible data rate format (FDF) 1 - * Reserved bit (r0) 1 - * Bit Rate Switch (BRS) 1 - * Error Status Indicator (ESI) 1 - * Data length code (DLC) 4 - * Data field 0...512 - * Stuff Bit Count (SBC) 4 - * CRC 0...16: 17 20...64:21 - * CRC delimiter (CD) 1 - * Fixed Stuff bits (FSB) 0...16: 6 20...64:7 - * ACK slot (AS) 1 - * ACK delimiter (AD) 1 - * End-of-frame (EOF) 7 - * Inter frame spacing 3 - * - * assuming CRC21, rounded up and ignoring dynamic bitstuffing - */ -#define CANFD_FRAME_OVERHEAD_SFF DIV_ROUND_UP(67, 8) + * Stuff Count 4 + * CRC sequence (CRC21) 21 + * CRC Delimiter 1 + * Fixed stuff bits 7 + */ +#define CANFD_FRAME_CRC21_FIELD_BITS 33 /* - * Size of a CAN-FD Extended Frame + * Size of a CAN(-FD) Frame footer in bits * * Name of Field Bits * --------------------------------------------------------- - * Start-of-frame 1 - * Identifier A 11 - * Substitute remote request (SRR) 1 - * Identifier extension bit (IDE) 1 - * Identifier B 18 - * Remote Request Substitution (RRS) 1 - * Flexible data rate format (FDF) 1 - * Reserved bit (r0) 1 - * Bit Rate Switch (BRS) 1 - * Error Status Indicator (ESI) 1 - * Data length code (DLC) 4 - * Data field 0...512 - * Stuff Bit Count (SBC) 4 - * CRC 0...16: 17 20...64:21 - * CRC delimiter (CD) 1 - * Fixed Stuff bits (FSB) 0...16: 6 20...64:7 - * ACK slot (AS) 1 - * ACK delimiter (AD) 1 - * End-of-frame (EOF) 7 - * Inter frame spacing 3 - * - * assuming CRC21, rounded up and ignoring dynamic bitstuffing - */ -#define CANFD_FRAME_OVERHEAD_EFF DIV_ROUND_UP(86, 8) + * ACK slot 1 + * ACK delimiter 1 + * End Of Frame (EOF) 7 + * + * including all fields following the CRC field + */ +#define CAN_FRAME_FOOTER_BITS 9 + +/* + * First part of the Inter Frame Space + * (a.k.a. IMF - intermission field) + */ +#define CAN_INTERMISSION_BITS 3 + +/** + * can_bitstuffing_len() - Calculate the maximum length with bitstuffing + * @destuffed_len: length of a destuffed bit stream + * + * The worst bit stuffing case is a sequence in which dominant and + * recessive bits alternate every four bits: + * + * Destuffed: 1 1111 0000 1111 0000 1111 + * Stuffed: 1 1111o 0000i 1111o 0000i 1111o + * + * Nomenclature + * + * - "0": dominant bit + * - "o": dominant stuff bit + * - "1": recessive bit + * - "i": recessive stuff bit + * + * Aside from the first bit, one stuff bit is added every four bits. + * + * Return: length of the stuffed bit stream in the worst case scenario. + */ +#define can_bitstuffing_len(destuffed_len) \ + (destuffed_len + (destuffed_len - 1) / 4) + +#define __can_bitstuffing_len(bitstuffing, destuffed_len) \ + (bitstuffing ? can_bitstuffing_len(destuffed_len) : \ + destuffed_len) + +#define __can_cc_frame_bits(is_eff, bitstuffing, \ + intermission, data_len) \ +( \ + __can_bitstuffing_len(bitstuffing, \ + (is_eff ? CAN_FRAME_HEADER_EFF_BITS : \ + CAN_FRAME_HEADER_SFF_BITS) + \ + (data_len) * BITS_PER_BYTE + \ + CAN_FRAME_CRC_FIELD_BITS) + \ + CAN_FRAME_FOOTER_BITS + \ + (intermission ? CAN_INTERMISSION_BITS : 0) \ +) + +#define __can_fd_frame_bits(is_eff, bitstuffing, \ + intermission, data_len) \ +( \ + __can_bitstuffing_len(bitstuffing, \ + (is_eff ? CANFD_FRAME_HEADER_EFF_BITS : \ + CANFD_FRAME_HEADER_SFF_BITS) + \ + (data_len) * BITS_PER_BYTE) + \ + ((data_len) <= 16 ? \ + CANFD_FRAME_CRC17_FIELD_BITS : \ + CANFD_FRAME_CRC21_FIELD_BITS) + \ + CAN_FRAME_FOOTER_BITS + \ + (intermission ? CAN_INTERMISSION_BITS : 0) \ +) + +/** + * can_frame_bits() - Calculate the number of bits on the wire in a + * CAN frame + * @is_fd: true: CAN-FD frame; false: Classical CAN frame. + * @is_eff: true: Extended frame; false: Standard frame. + * @bitstuffing: true: calculate the bitstuffing worst case; false: + * calculate the bitstuffing best case (no dynamic + * bitstuffing). CAN-FD's fixed stuff bits are always included. + * @intermission: if and only if true, include the inter frame space + * assuming no bus idle (i.e. only the intermission). Strictly + * speaking, the inter frame space is not part of the + * frame. However, it is needed when calculating the delay + * between the Start Of Frame of two consecutive frames. + * @data_len: length of the data field in bytes. Correspond to + * can(fd)_frame->len. Should be zero for remote frames. No + * sanitization is done on @data_len and it shall have no side + * effects. + * + * Return: the numbers of bits on the wire of a CAN frame. + */ +#define can_frame_bits(is_fd, is_eff, bitstuffing, \ + intermission, data_len) \ +( \ + is_fd ? __can_fd_frame_bits(is_eff, bitstuffing, \ + intermission, data_len) : \ + __can_cc_frame_bits(is_eff, bitstuffing, \ + intermission, data_len) \ +) + +/* + * Number of bytes in a CAN frame + * (rounded up, including intermission) + */ +#define can_frame_bytes(is_fd, is_eff, bitstuffing, data_len) \ + DIV_ROUND_UP(can_frame_bits(is_fd, is_eff, bitstuffing, \ + true, data_len), \ + BITS_PER_BYTE) /* * Maximum size of a Classical CAN frame - * (rounded up and ignoring bitstuffing) + * (rounded up, ignoring bitstuffing but including intermission) */ -#define CAN_FRAME_LEN_MAX (CAN_FRAME_OVERHEAD_EFF + CAN_MAX_DLEN) +#define CAN_FRAME_LEN_MAX can_frame_bytes(false, true, false, CAN_MAX_DLEN) /* * Maximum size of a CAN-FD frame - * (rounded up and ignoring bitstuffing) + * (rounded up, ignoring dynamic bitstuffing but including intermission) */ -#define CANFD_FRAME_LEN_MAX (CANFD_FRAME_OVERHEAD_EFF + CANFD_MAX_DLEN) +#define CANFD_FRAME_LEN_MAX can_frame_bytes(true, true, false, CANFD_MAX_DLEN) /* * can_cc_dlc2len(value) - convert a given data length code (dlc) of a -- cgit v1.2.3 From 7c921556c04f1907e68e57610f315d8873320ad7 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:35 +0200 Subject: can: kvaser_pciefd: Remove useless write to interrupt register The PCI interrupt register, KVASER_PCIEFD_IRQ_REG, is level triggered. Writing to the register doesn't affect it. Fixes: 26ad340e582d ("can: kvaser_pciefd: Add driver for Kvaser PCIEcan devices") Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-2-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index be189edb256c..d60d17199a1b 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -1768,7 +1768,6 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev) kvaser_pciefd_transmit_irq(pcie->can[i]); } - iowrite32(board_irq, pcie->reg_base + KVASER_PCIEFD_IRQ_REG); return IRQ_HANDLED; } @@ -1842,9 +1841,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, KVASER_PCIEFD_SRB_IRQ_DUF0 | KVASER_PCIEFD_SRB_IRQ_DUF1, pcie->reg_base + KVASER_PCIEFD_SRB_IEN_REG); - /* Reset IRQ handling, expected to be off before */ - iowrite32(KVASER_PCIEFD_IRQ_ALL_MSK, - pcie->reg_base + KVASER_PCIEFD_IRQ_REG); + /* Enable PCI interrupts */ iowrite32(KVASER_PCIEFD_IRQ_ALL_MSK, pcie->reg_base + KVASER_PCIEFD_IEN_REG); @@ -1906,10 +1903,8 @@ static void kvaser_pciefd_remove(struct pci_dev *pdev) kvaser_pciefd_remove_all_ctrls(pcie); - /* Turn off IRQ generation */ + /* Disable interrupts */ iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG); - iowrite32(KVASER_PCIEFD_IRQ_ALL_MSK, - pcie->reg_base + KVASER_PCIEFD_IRQ_REG); iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG); free_irq(pcie->pci->irq, pcie); -- cgit v1.2.3 From 76c66ddf7f899b6a9cbd9098990b90f77a8bea9c Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:36 +0200 Subject: can: kvaser_pciefd: Remove handler for unused KVASER_PCIEFD_PACK_TYPE_EFRAME_ACK The Kvaser KCAN controller got a feature to send error frames on request. The packet KVASER_PCIEFD_PACK_TYPE_EFRAME_ACK signals that the requested error frame was transmitted. Since this feature is not supported by the driver, drop the handler and add KVASER_PCIEFD_PACK_TYPE_EFRAME_ACK to the list of unexpected packet types. Fixes: 26ad340e582d ("can: kvaser_pciefd: Add driver for Kvaser PCIEcan devices") Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-3-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 39 +-------------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index d60d17199a1b..1821ffa4ca79 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -1472,40 +1472,6 @@ static int kvaser_pciefd_handle_status_packet(struct kvaser_pciefd *pcie, return 0; } -static int kvaser_pciefd_handle_eack_packet(struct kvaser_pciefd *pcie, - struct kvaser_pciefd_rx_packet *p) -{ - struct kvaser_pciefd_can *can; - u8 ch_id = (p->header[1] >> KVASER_PCIEFD_PACKET_CHID_SHIFT) & 0x7; - - if (ch_id >= pcie->nr_channels) - return -EIO; - - can = pcie->can[ch_id]; - - /* If this is the last flushed packet, send end of flush */ - if (p->header[0] & KVASER_PCIEFD_APACKET_FLU) { - u8 count = ioread32(can->reg_base + - KVASER_PCIEFD_KCAN_TX_NPACKETS_REG) & 0xff; - - if (count == 0) - iowrite32(KVASER_PCIEFD_KCAN_CTRL_EFLUSH, - can->reg_base + KVASER_PCIEFD_KCAN_CTRL_REG); - } else { - int echo_idx = p->header[0] & KVASER_PCIEFD_PACKET_SEQ_MSK; - int dlc = can_get_echo_skb(can->can.dev, echo_idx, NULL); - struct net_device_stats *stats = &can->can.dev->stats; - - stats->tx_bytes += dlc; - stats->tx_packets++; - - if (netif_queue_stopped(can->can.dev)) - netif_wake_queue(can->can.dev); - } - - return 0; -} - static void kvaser_pciefd_handle_nack_packet(struct kvaser_pciefd_can *can, struct kvaser_pciefd_rx_packet *p) { @@ -1644,16 +1610,13 @@ static int kvaser_pciefd_read_packet(struct kvaser_pciefd *pcie, int *start_pos, ret = kvaser_pciefd_handle_error_packet(pcie, p); break; - case KVASER_PCIEFD_PACK_TYPE_EFRAME_ACK: - ret = kvaser_pciefd_handle_eack_packet(pcie, p); - break; - case KVASER_PCIEFD_PACK_TYPE_EFLUSH_ACK: ret = kvaser_pciefd_handle_eflush_packet(pcie, p); break; case KVASER_PCIEFD_PACK_TYPE_ACK_DATA: case KVASER_PCIEFD_PACK_TYPE_BUS_LOAD: + case KVASER_PCIEFD_PACK_TYPE_EFRAME_ACK: case KVASER_PCIEFD_PACK_TYPE_TXRQ: dev_info(&pcie->pci->dev, "Received unexpected packet type 0x%08X\n", type); -- cgit v1.2.3 From 2d55e9f9b4427e1ad59b974f2267767aac3788d3 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:37 +0200 Subject: can: kvaser_pciefd: Add function to set skb hwtstamps Add new function, kvaser_pciefd_set_skb_timestamp(), to set skb hwtstamps. Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-4-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 1821ffa4ca79..7646338d4d44 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -538,6 +538,13 @@ static int kvaser_pciefd_set_tx_irq(struct kvaser_pciefd_can *can) return 0; } +static inline void kvaser_pciefd_set_skb_timestamp(const struct kvaser_pciefd *pcie, + struct sk_buff *skb, u64 timestamp) +{ + skb_hwtstamps(skb)->hwtstamp = + ns_to_ktime(div_u64(timestamp * 1000, pcie->freq_to_ticks_div)); +} + static void kvaser_pciefd_setup_controller(struct kvaser_pciefd_can *can) { u32 mode; @@ -1171,7 +1178,6 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, struct canfd_frame *cf; struct can_priv *priv; struct net_device_stats *stats; - struct skb_shared_hwtstamps *shhwtstamps; u8 ch_id = (p->header[1] >> KVASER_PCIEFD_PACKET_CHID_SHIFT) & 0x7; if (ch_id >= pcie->nr_channels) @@ -1214,12 +1220,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, stats->rx_bytes += cf->len; } stats->rx_packets++; - - shhwtstamps = skb_hwtstamps(skb); - - shhwtstamps->hwtstamp = - ns_to_ktime(div_u64(p->timestamp * 1000, - pcie->freq_to_ticks_div)); + kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp); return netif_rx(skb); } @@ -1282,7 +1283,6 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can, struct net_device *ndev = can->can.dev; struct sk_buff *skb; struct can_frame *cf = NULL; - struct skb_shared_hwtstamps *shhwtstamps; struct net_device_stats *stats = &ndev->stats; old_state = can->can.state; @@ -1323,10 +1323,7 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can, return -ENOMEM; } - shhwtstamps = skb_hwtstamps(skb); - shhwtstamps->hwtstamp = - ns_to_ktime(div_u64(p->timestamp * 1000, - can->kv_pcie->freq_to_ticks_div)); + kvaser_pciefd_set_skb_timestamp(can->kv_pcie, skb, p->timestamp); cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_CNT; cf->data[6] = bec.txerr; @@ -1374,7 +1371,6 @@ static int kvaser_pciefd_handle_status_resp(struct kvaser_pciefd_can *can, struct net_device *ndev = can->can.dev; struct sk_buff *skb; struct can_frame *cf; - struct skb_shared_hwtstamps *shhwtstamps; skb = alloc_can_err_skb(ndev, &cf); if (!skb) { @@ -1394,10 +1390,7 @@ static int kvaser_pciefd_handle_status_resp(struct kvaser_pciefd_can *can, cf->can_id |= CAN_ERR_RESTARTED; } - shhwtstamps = skb_hwtstamps(skb); - shhwtstamps->hwtstamp = - ns_to_ktime(div_u64(p->timestamp * 1000, - can->kv_pcie->freq_to_ticks_div)); + kvaser_pciefd_set_skb_timestamp(can->kv_pcie, skb, p->timestamp); cf->data[6] = bec.txerr; cf->data[7] = bec.rxerr; -- cgit v1.2.3 From ec681b91befa982477e24a150dd6452427fe6473 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:38 +0200 Subject: can: kvaser_pciefd: Set hardware timestamp on transmitted packets Set hardware timestamp on transmitted packets. Fixes: 26ad340e582d ("can: kvaser_pciefd: Add driver for Kvaser PCIEcan devices") Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-5-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 7646338d4d44..88bad2c2b641 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -1485,6 +1485,7 @@ static void kvaser_pciefd_handle_nack_packet(struct kvaser_pciefd_can *can, if (skb) { cf->can_id |= CAN_ERR_BUSERROR; + kvaser_pciefd_set_skb_timestamp(can->kv_pcie, skb, p->timestamp); netif_rx(skb); } else { stats->rx_dropped++; @@ -1516,8 +1517,15 @@ static int kvaser_pciefd_handle_ack_packet(struct kvaser_pciefd *pcie, netdev_dbg(can->can.dev, "Packet was flushed\n"); } else { int echo_idx = p->header[0] & KVASER_PCIEFD_PACKET_SEQ_MSK; - int dlc = can_get_echo_skb(can->can.dev, echo_idx, NULL); - u8 count = ioread32(can->reg_base + + int dlc; + u8 count; + struct sk_buff *skb; + + skb = can->can.echo_skb[echo_idx]; + if (skb) + kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp); + dlc = can_get_echo_skb(can->can.dev, echo_idx, NULL); + count = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG) & 0xff; if (count < KVASER_PCIEFD_CAN_TX_MAX_COUNT && -- cgit v1.2.3 From 2c470dbbd32ff7f864e77397269cbb7dc453cfa2 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:39 +0200 Subject: can: kvaser_pciefd: Define unsigned constants with type suffix 'U' Define unsigned constants with type suffix 'U' Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-6-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 88bad2c2b641..abb556fb5cb6 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -25,12 +25,12 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_WAIT_TIMEOUT msecs_to_jiffies(1000) #define KVASER_PCIEFD_BEC_POLL_FREQ (jiffies + msecs_to_jiffies(200)) -#define KVASER_PCIEFD_MAX_ERR_REP 256 -#define KVASER_PCIEFD_CAN_TX_MAX_COUNT 17 -#define KVASER_PCIEFD_MAX_CAN_CHANNELS 4 -#define KVASER_PCIEFD_DMA_COUNT 2 +#define KVASER_PCIEFD_MAX_ERR_REP 256U +#define KVASER_PCIEFD_CAN_TX_MAX_COUNT 17U +#define KVASER_PCIEFD_MAX_CAN_CHANNELS 4U +#define KVASER_PCIEFD_DMA_COUNT 2U -#define KVASER_PCIEFD_DMA_SIZE (4 * 1024) +#define KVASER_PCIEFD_DMA_SIZE (4U * 1024U) #define KVASER_PCIEFD_64BIT_DMA_BIT BIT(0) #define KVASER_PCIEFD_VENDOR 0x1a07 -- cgit v1.2.3 From 735d86a8aaf660e2a5fd5d711ee05fa817e8d567 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 9 Jun 2023 14:10:51 +0200 Subject: can: uapi: move CAN_RAW_FILTER_MAX definition to raw.h CAN_RAW_FILTER_MAX is only relevant for CAN_RAW sockets and used in linux/can/raw.c or in userspace applications that include the raw.h file anyway. Signed-off-by: Oliver Hartkopp Link: https://lore.kernel.org/all/20230609121051.9631-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde --- include/uapi/linux/can.h | 1 - include/uapi/linux/can/raw.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/can.h b/include/uapi/linux/can.h index dd645ea72306..939db2388208 100644 --- a/include/uapi/linux/can.h +++ b/include/uapi/linux/can.h @@ -285,6 +285,5 @@ struct can_filter { }; #define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */ -#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */ #endif /* !_UAPI_CAN_H */ diff --git a/include/uapi/linux/can/raw.h b/include/uapi/linux/can/raw.h index ff12f525c37c..31622c9b7988 100644 --- a/include/uapi/linux/can/raw.h +++ b/include/uapi/linux/can/raw.h @@ -49,6 +49,8 @@ #include #define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW) +#define CAN_RAW_FILTER_MAX 512 /* maximum number of can_filter set via setsockopt() */ + enum { SCM_CAN_RAW_ERRQUEUE = 1, }; -- cgit v1.2.3 From c496adafee686246fdc803183c2506043f99b3af Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:40 +0200 Subject: can: kvaser_pciefd: Remove SPI flash parameter read functionality Remove SPI flash parameter read functionality, since it's only used for reading the interface CAN controller count. This information is already read from a register, making the information redundant. Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-7-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/Kconfig | 3 +- drivers/net/can/kvaser_pciefd.c | 220 +--------------------------------------- 2 files changed, 5 insertions(+), 218 deletions(-) diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index b190007c01be..a5c5036dfb94 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -153,8 +153,7 @@ config CAN_JANZ_ICAN3 config CAN_KVASER_PCIEFD depends on PCI tristate "Kvaser PCIe FD cards" - select CRC32 - help + help This is a driver for the Kvaser PCI Express CAN FD family. Supported devices: diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index abb556fb5cb6..e24a8e77aef1 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -3,10 +3,10 @@ * Parts of this driver are based on the following: * - Kvaser linux pciefd driver (version 5.25) * - PEAK linux canfd driver - * - Altera Avalon EPCS flash controller driver */ #include +#include #include #include #include @@ -14,7 +14,6 @@ #include #include #include -#include #include MODULE_LICENSE("Dual BSD/GPL"); @@ -78,13 +77,6 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_SRB_STAT_REG (KVASER_PCIEFD_SRB_BASE + 0x210) #define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG (KVASER_PCIEFD_SRB_BASE + 0x214) #define KVASER_PCIEFD_SRB_CTRL_REG (KVASER_PCIEFD_SRB_BASE + 0x218) -/* EPCS flash controller registers */ -#define KVASER_PCIEFD_SPI_BASE 0x1fc00 -#define KVASER_PCIEFD_SPI_RX_REG KVASER_PCIEFD_SPI_BASE -#define KVASER_PCIEFD_SPI_TX_REG (KVASER_PCIEFD_SPI_BASE + 0x4) -#define KVASER_PCIEFD_SPI_STATUS_REG (KVASER_PCIEFD_SPI_BASE + 0x8) -#define KVASER_PCIEFD_SPI_CTRL_REG (KVASER_PCIEFD_SPI_BASE + 0xc) -#define KVASER_PCIEFD_SPI_SSEL_REG (KVASER_PCIEFD_SPI_BASE + 0x14) #define KVASER_PCIEFD_IRQ_ALL_MSK 0x1f #define KVASER_PCIEFD_IRQ_SRB BIT(4) @@ -119,23 +111,6 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* DMA Enable */ #define KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE BIT(0) -/* EPCS flash controller definitions */ -#define KVASER_PCIEFD_CFG_IMG_SZ (64 * 1024) -#define KVASER_PCIEFD_CFG_IMG_OFFSET (31 * 65536L) -#define KVASER_PCIEFD_CFG_MAX_PARAMS 256 -#define KVASER_PCIEFD_CFG_MAGIC 0xcafef00d -#define KVASER_PCIEFD_CFG_PARAM_MAX_SZ 24 -#define KVASER_PCIEFD_CFG_SYS_VER 1 -#define KVASER_PCIEFD_CFG_PARAM_NR_CHAN 130 -#define KVASER_PCIEFD_SPI_TMT BIT(5) -#define KVASER_PCIEFD_SPI_TRDY BIT(6) -#define KVASER_PCIEFD_SPI_RRDY BIT(7) -#define KVASER_PCIEFD_FLASH_ID_EPCS16 0x14 -/* Commands for controlling the onboard flash */ -#define KVASER_PCIEFD_FLASH_RES_CMD 0xab -#define KVASER_PCIEFD_FLASH_READ_CMD 0x3 -#define KVASER_PCIEFD_FLASH_STATUS_CMD 0x5 - /* Kvaser KCAN definitions */ #define KVASER_PCIEFD_KCAN_CTRL_EFLUSH (4 << 29) #define KVASER_PCIEFD_KCAN_CTRL_EFRAME (5 << 29) @@ -306,20 +281,6 @@ static const struct can_bittiming_const kvaser_pciefd_bittiming_const = { .brp_inc = 1, }; -struct kvaser_pciefd_cfg_param { - __le32 magic; - __le32 nr; - __le32 len; - u8 data[KVASER_PCIEFD_CFG_PARAM_MAX_SZ]; -}; - -struct kvaser_pciefd_cfg_img { - __le32 version; - __le32 magic; - __le32 crc; - struct kvaser_pciefd_cfg_param params[KVASER_PCIEFD_CFG_MAX_PARAMS]; -}; - static struct pci_device_id kvaser_pciefd_id_table[] = { { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4HS_ID), }, { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2HS_ID), }, @@ -330,164 +291,6 @@ static struct pci_device_id kvaser_pciefd_id_table[] = { }; MODULE_DEVICE_TABLE(pci, kvaser_pciefd_id_table); -/* Onboard flash memory functions */ -static int kvaser_pciefd_spi_wait_loop(struct kvaser_pciefd *pcie, int msk) -{ - u32 res; - - return readl_poll_timeout(pcie->reg_base + KVASER_PCIEFD_SPI_STATUS_REG, - res, res & msk, 0, 10); -} - -static int kvaser_pciefd_spi_cmd(struct kvaser_pciefd *pcie, const u8 *tx, - u32 tx_len, u8 *rx, u32 rx_len) -{ - int c; - - iowrite32(BIT(0), pcie->reg_base + KVASER_PCIEFD_SPI_SSEL_REG); - iowrite32(BIT(10), pcie->reg_base + KVASER_PCIEFD_SPI_CTRL_REG); - ioread32(pcie->reg_base + KVASER_PCIEFD_SPI_RX_REG); - - c = tx_len; - while (c--) { - if (kvaser_pciefd_spi_wait_loop(pcie, KVASER_PCIEFD_SPI_TRDY)) - return -EIO; - - iowrite32(*tx++, pcie->reg_base + KVASER_PCIEFD_SPI_TX_REG); - - if (kvaser_pciefd_spi_wait_loop(pcie, KVASER_PCIEFD_SPI_RRDY)) - return -EIO; - - ioread32(pcie->reg_base + KVASER_PCIEFD_SPI_RX_REG); - } - - c = rx_len; - while (c-- > 0) { - if (kvaser_pciefd_spi_wait_loop(pcie, KVASER_PCIEFD_SPI_TRDY)) - return -EIO; - - iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SPI_TX_REG); - - if (kvaser_pciefd_spi_wait_loop(pcie, KVASER_PCIEFD_SPI_RRDY)) - return -EIO; - - *rx++ = ioread32(pcie->reg_base + KVASER_PCIEFD_SPI_RX_REG); - } - - if (kvaser_pciefd_spi_wait_loop(pcie, KVASER_PCIEFD_SPI_TMT)) - return -EIO; - - iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SPI_CTRL_REG); - - if (c != -1) { - dev_err(&pcie->pci->dev, "Flash SPI transfer failed\n"); - return -EIO; - } - - return 0; -} - -static int kvaser_pciefd_cfg_read_and_verify(struct kvaser_pciefd *pcie, - struct kvaser_pciefd_cfg_img *img) -{ - int offset = KVASER_PCIEFD_CFG_IMG_OFFSET; - int res, crc; - u8 *crc_buff; - - u8 cmd[] = { - KVASER_PCIEFD_FLASH_READ_CMD, - (u8)((offset >> 16) & 0xff), - (u8)((offset >> 8) & 0xff), - (u8)(offset & 0xff) - }; - - res = kvaser_pciefd_spi_cmd(pcie, cmd, ARRAY_SIZE(cmd), (u8 *)img, - KVASER_PCIEFD_CFG_IMG_SZ); - if (res) - return res; - - crc_buff = (u8 *)img->params; - - if (le32_to_cpu(img->version) != KVASER_PCIEFD_CFG_SYS_VER) { - dev_err(&pcie->pci->dev, - "Config flash corrupted, version number is wrong\n"); - return -ENODEV; - } - - if (le32_to_cpu(img->magic) != KVASER_PCIEFD_CFG_MAGIC) { - dev_err(&pcie->pci->dev, - "Config flash corrupted, magic number is wrong\n"); - return -ENODEV; - } - - crc = ~crc32_be(0xffffffff, crc_buff, sizeof(img->params)); - if (le32_to_cpu(img->crc) != crc) { - dev_err(&pcie->pci->dev, - "Stored CRC does not match flash image contents\n"); - return -EIO; - } - - return 0; -} - -static void kvaser_pciefd_cfg_read_params(struct kvaser_pciefd *pcie, - struct kvaser_pciefd_cfg_img *img) -{ - struct kvaser_pciefd_cfg_param *param; - - param = &img->params[KVASER_PCIEFD_CFG_PARAM_NR_CHAN]; - memcpy(&pcie->nr_channels, param->data, le32_to_cpu(param->len)); -} - -static int kvaser_pciefd_read_cfg(struct kvaser_pciefd *pcie) -{ - int res; - struct kvaser_pciefd_cfg_img *img; - - /* Read electronic signature */ - u8 cmd[] = {KVASER_PCIEFD_FLASH_RES_CMD, 0, 0, 0}; - - res = kvaser_pciefd_spi_cmd(pcie, cmd, ARRAY_SIZE(cmd), cmd, 1); - if (res) - return -EIO; - - img = kmalloc(KVASER_PCIEFD_CFG_IMG_SZ, GFP_KERNEL); - if (!img) - return -ENOMEM; - - if (cmd[0] != KVASER_PCIEFD_FLASH_ID_EPCS16) { - dev_err(&pcie->pci->dev, - "Flash id is 0x%x instead of expected EPCS16 (0x%x)\n", - cmd[0], KVASER_PCIEFD_FLASH_ID_EPCS16); - - res = -ENODEV; - goto image_free; - } - - cmd[0] = KVASER_PCIEFD_FLASH_STATUS_CMD; - res = kvaser_pciefd_spi_cmd(pcie, cmd, 1, cmd, 1); - if (res) { - goto image_free; - } else if (cmd[0] & 1) { - res = -EIO; - /* No write is ever done, the WIP should never be set */ - dev_err(&pcie->pci->dev, "Unexpected WIP bit set in flash\n"); - goto image_free; - } - - res = kvaser_pciefd_cfg_read_and_verify(pcie, img); - if (res) { - res = -EIO; - goto image_free; - } - - kvaser_pciefd_cfg_read_params(pcie, img); - -image_free: - kfree(img); - return res; -} - static void kvaser_pciefd_request_status(struct kvaser_pciefd_can *can) { u32 cmd; @@ -1125,25 +928,10 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie) { u32 sysid, srb_status, build; - u8 sysid_nr_chan; - int ret; - - ret = kvaser_pciefd_read_cfg(pcie); - if (ret) - return ret; sysid = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_VERSION_REG); - sysid_nr_chan = (sysid >> KVASER_PCIEFD_SYSID_NRCHAN_SHIFT) & 0xff; - if (pcie->nr_channels != sysid_nr_chan) { - dev_err(&pcie->pci->dev, - "Number of channels does not match: %u vs %u\n", - pcie->nr_channels, - sysid_nr_chan); - return -ENODEV; - } - - if (pcie->nr_channels > KVASER_PCIEFD_MAX_CAN_CHANNELS) - pcie->nr_channels = KVASER_PCIEFD_MAX_CAN_CHANNELS; + pcie->nr_channels = min(KVASER_PCIEFD_MAX_CAN_CHANNELS, + ((sysid >> KVASER_PCIEFD_SYSID_NRCHAN_SHIFT) & 0xff)); build = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_BUILD_REG); dev_dbg(&pcie->pci->dev, "Version %u.%u.%u\n", @@ -1167,7 +955,7 @@ static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie) /* Turn off all loopback functionality */ iowrite32(0, pcie->reg_base + KVASER_PCIEFD_LOOP_REG); - return ret; + return 0; } static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, -- cgit v1.2.3 From 1b83d0ba1c11d51342d390db19d8e53128a80b40 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:41 +0200 Subject: can: kvaser_pciefd: Sort includes in alphabetic order Sort the includes in alphabetic order. Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-8-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index e24a8e77aef1..8be27a7dc7e9 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -5,16 +5,16 @@ * - PEAK linux canfd driver */ +#include +#include +#include +#include #include #include #include -#include -#include +#include #include -#include #include -#include -#include MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Kvaser AB "); -- cgit v1.2.3 From 488c07b441f95e0d0d8df0ede4c67319f0f35787 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:42 +0200 Subject: can: kvaser_pciefd: Rename device ID defines Rename device ID defines to better match the product name of the supported device. Use 16 bit hexadecimal values for device IDs. And format kvaser_pciefd_id_table using clang-format. Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-9-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 8be27a7dc7e9..bf3fa51069a9 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -33,11 +33,11 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_64BIT_DMA_BIT BIT(0) #define KVASER_PCIEFD_VENDOR 0x1a07 -#define KVASER_PCIEFD_4HS_ID 0x0d -#define KVASER_PCIEFD_2HS_ID 0x0e -#define KVASER_PCIEFD_HS_ID 0x0f -#define KVASER_PCIEFD_MINIPCIE_HS_ID 0x10 -#define KVASER_PCIEFD_MINIPCIE_2HS_ID 0x11 +#define KVASER_PCIEFD_4HS_DEVICE_ID 0x000d +#define KVASER_PCIEFD_2HS_V2_DEVICE_ID 0x000e +#define KVASER_PCIEFD_HS_V2_DEVICE_ID 0x000f +#define KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID 0x0010 +#define KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID 0x0011 /* PCIe IRQ registers */ #define KVASER_PCIEFD_IRQ_REG 0x40 @@ -282,12 +282,24 @@ static const struct can_bittiming_const kvaser_pciefd_bittiming_const = { }; static struct pci_device_id kvaser_pciefd_id_table[] = { - { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4HS_ID), }, - { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2HS_ID), }, - { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_HS_ID), }, - { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_HS_ID), }, - { PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2HS_ID), }, - { 0,}, + { + PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4HS_DEVICE_ID), + }, + { + PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2HS_V2_DEVICE_ID), + }, + { + PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_HS_V2_DEVICE_ID), + }, + { + PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID), + }, + { + PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID), + }, + { + 0, + }, }; MODULE_DEVICE_TABLE(pci, kvaser_pciefd_id_table); -- cgit v1.2.3 From 24aecf55370103cc2d1e3cbb1b8fffcb00482b74 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:43 +0200 Subject: can: kvaser_pciefd: Change return type for kvaser_pciefd_{receive,transmit,set_tx}_irq() Change return type to void for kvaser_pciefd_transmit_irq(), kvaser_pciefd_receive_irq() and kvaser_pciefd_set_tx_irq(). These functions always return zero. Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-10-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index bf3fa51069a9..feef044c6b0a 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -338,7 +338,7 @@ static void kvaser_pciefd_disable_err_gen(struct kvaser_pciefd_can *can) spin_unlock_irqrestore(&can->lock, irq); } -static int kvaser_pciefd_set_tx_irq(struct kvaser_pciefd_can *can) +static void kvaser_pciefd_set_tx_irq(struct kvaser_pciefd_can *can) { u32 msk; @@ -349,8 +349,6 @@ static int kvaser_pciefd_set_tx_irq(struct kvaser_pciefd_can *can) KVASER_PCIEFD_KCAN_IRQ_TAR; iowrite32(msk, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); - - return 0; } static inline void kvaser_pciefd_set_skb_timestamp(const struct kvaser_pciefd *pcie, @@ -1456,7 +1454,7 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf) return res; } -static int kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) +static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) { u32 irq; @@ -1482,10 +1480,9 @@ static int kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq); iowrite32(irq, pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG); - return 0; } -static int kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can) +static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can) { u32 irq = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); @@ -1503,7 +1500,6 @@ static int kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can) netdev_err(can->can.dev, "Rx FIFO overflow\n"); iowrite32(irq, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); - return 0; } static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev) -- cgit v1.2.3 From 69335013c4511cf99d3e338d369ccb37d30d6fee Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:44 +0200 Subject: can: kvaser_pciefd: Sort register definitions Sort the registers defines, in the same order as the register bits/fields are defined. Sort register bits/fields in MSB-to-LSB order. Update and add comments. Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-11-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 210 +++++++++++++++++++++------------------- 1 file changed, 110 insertions(+), 100 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index feef044c6b0a..d2e520f9eaa7 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -30,7 +30,6 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_DMA_COUNT 2U #define KVASER_PCIEFD_DMA_SIZE (4U * 1024U) -#define KVASER_PCIEFD_64BIT_DMA_BIT BIT(0) #define KVASER_PCIEFD_VENDOR 0x1a07 #define KVASER_PCIEFD_4HS_DEVICE_ID 0x000d @@ -42,24 +41,8 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* PCIe IRQ registers */ #define KVASER_PCIEFD_IRQ_REG 0x40 #define KVASER_PCIEFD_IEN_REG 0x50 -/* DMA map */ +/* DMA address translation map register base */ #define KVASER_PCIEFD_DMA_MAP_BASE 0x1000 -/* Kvaser KCAN CAN controller registers */ -#define KVASER_PCIEFD_KCAN0_BASE 0x10000 -#define KVASER_PCIEFD_KCAN_BASE_OFFSET 0x1000 -#define KVASER_PCIEFD_KCAN_FIFO_REG 0x100 -#define KVASER_PCIEFD_KCAN_FIFO_LAST_REG 0x180 -#define KVASER_PCIEFD_KCAN_CTRL_REG 0x2c0 -#define KVASER_PCIEFD_KCAN_CMD_REG 0x400 -#define KVASER_PCIEFD_KCAN_IEN_REG 0x408 -#define KVASER_PCIEFD_KCAN_IRQ_REG 0x410 -#define KVASER_PCIEFD_KCAN_TX_NPACKETS_REG 0x414 -#define KVASER_PCIEFD_KCAN_STAT_REG 0x418 -#define KVASER_PCIEFD_KCAN_MODE_REG 0x41c -#define KVASER_PCIEFD_KCAN_BTRN_REG 0x420 -#define KVASER_PCIEFD_KCAN_BUS_LOAD_REG 0x424 -#define KVASER_PCIEFD_KCAN_BTRD_REG 0x428 -#define KVASER_PCIEFD_KCAN_PWM_REG 0x430 /* Loopback control register */ #define KVASER_PCIEFD_LOOP_REG 0x1f000 /* System identification and information registers */ @@ -77,33 +60,54 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_SRB_STAT_REG (KVASER_PCIEFD_SRB_BASE + 0x210) #define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG (KVASER_PCIEFD_SRB_BASE + 0x214) #define KVASER_PCIEFD_SRB_CTRL_REG (KVASER_PCIEFD_SRB_BASE + 0x218) +/* Kvaser KCAN CAN controller registers */ +#define KVASER_PCIEFD_KCAN0_BASE 0x10000 +#define KVASER_PCIEFD_KCAN_BASE_OFFSET 0x1000 +#define KVASER_PCIEFD_KCAN_FIFO_REG 0x100 +#define KVASER_PCIEFD_KCAN_FIFO_LAST_REG 0x180 +#define KVASER_PCIEFD_KCAN_CTRL_REG 0x2c0 +#define KVASER_PCIEFD_KCAN_CMD_REG 0x400 +#define KVASER_PCIEFD_KCAN_IEN_REG 0x408 +#define KVASER_PCIEFD_KCAN_IRQ_REG 0x410 +#define KVASER_PCIEFD_KCAN_TX_NPACKETS_REG 0x414 +#define KVASER_PCIEFD_KCAN_STAT_REG 0x418 +#define KVASER_PCIEFD_KCAN_MODE_REG 0x41c +#define KVASER_PCIEFD_KCAN_BTRN_REG 0x420 +#define KVASER_PCIEFD_KCAN_BUS_LOAD_REG 0x424 +#define KVASER_PCIEFD_KCAN_BTRD_REG 0x428 +#define KVASER_PCIEFD_KCAN_PWM_REG 0x430 -#define KVASER_PCIEFD_IRQ_ALL_MSK 0x1f +/* PCI interrupt fields */ #define KVASER_PCIEFD_IRQ_SRB BIT(4) +#define KVASER_PCIEFD_IRQ_ALL_MSK 0x1f + +/* Enable 64-bit DMA address translation */ +#define KVASER_PCIEFD_64BIT_DMA_BIT BIT(0) +/* System build information fields */ #define KVASER_PCIEFD_SYSID_NRCHAN_SHIFT 24 #define KVASER_PCIEFD_SYSID_MAJOR_VER_SHIFT 16 #define KVASER_PCIEFD_SYSID_BUILD_VER_SHIFT 1 /* Reset DMA buffer 0, 1 and FIFO offset */ -#define KVASER_PCIEFD_SRB_CMD_RDB0 BIT(4) #define KVASER_PCIEFD_SRB_CMD_RDB1 BIT(5) +#define KVASER_PCIEFD_SRB_CMD_RDB0 BIT(4) #define KVASER_PCIEFD_SRB_CMD_FOR BIT(0) -/* DMA packet done, buffer 0 and 1 */ -#define KVASER_PCIEFD_SRB_IRQ_DPD0 BIT(8) -#define KVASER_PCIEFD_SRB_IRQ_DPD1 BIT(9) -/* DMA overflow, buffer 0 and 1 */ -#define KVASER_PCIEFD_SRB_IRQ_DOF0 BIT(10) -#define KVASER_PCIEFD_SRB_IRQ_DOF1 BIT(11) /* DMA underflow, buffer 0 and 1 */ -#define KVASER_PCIEFD_SRB_IRQ_DUF0 BIT(12) #define KVASER_PCIEFD_SRB_IRQ_DUF1 BIT(13) +#define KVASER_PCIEFD_SRB_IRQ_DUF0 BIT(12) +/* DMA overflow, buffer 0 and 1 */ +#define KVASER_PCIEFD_SRB_IRQ_DOF1 BIT(11) +#define KVASER_PCIEFD_SRB_IRQ_DOF0 BIT(10) +/* DMA packet done, buffer 0 and 1 */ +#define KVASER_PCIEFD_SRB_IRQ_DPD1 BIT(9) +#define KVASER_PCIEFD_SRB_IRQ_DPD0 BIT(8) +/* Got DMA support */ +#define KVASER_PCIEFD_SRB_STAT_DMA BIT(24) /* DMA idle */ #define KVASER_PCIEFD_SRB_STAT_DI BIT(15) -/* DMA support */ -#define KVASER_PCIEFD_SRB_STAT_DMA BIT(24) /* SRB current packet level */ #define KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK 0xff @@ -111,80 +115,86 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* DMA Enable */ #define KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE BIT(0) -/* Kvaser KCAN definitions */ +/* KCAN CTRL packet types */ #define KVASER_PCIEFD_KCAN_CTRL_EFLUSH (4 << 29) #define KVASER_PCIEFD_KCAN_CTRL_EFRAME (5 << 29) +/* Command sequence number */ #define KVASER_PCIEFD_KCAN_CMD_SEQ_SHIFT 16 -/* Request status packet */ -#define KVASER_PCIEFD_KCAN_CMD_SRQ BIT(0) /* Abort, flush and reset */ #define KVASER_PCIEFD_KCAN_CMD_AT BIT(1) +/* Request status packet */ +#define KVASER_PCIEFD_KCAN_CMD_SRQ BIT(0) -/* Tx FIFO unaligned read */ -#define KVASER_PCIEFD_KCAN_IRQ_TAR BIT(0) -/* Tx FIFO unaligned end */ -#define KVASER_PCIEFD_KCAN_IRQ_TAE BIT(1) -/* Bus parameter protection error */ -#define KVASER_PCIEFD_KCAN_IRQ_BPP BIT(2) -/* FDF bit when controller is in classic mode */ -#define KVASER_PCIEFD_KCAN_IRQ_FDIC BIT(3) -/* Rx FIFO overflow */ -#define KVASER_PCIEFD_KCAN_IRQ_ROF BIT(5) -/* Abort done */ -#define KVASER_PCIEFD_KCAN_IRQ_ABD BIT(13) -/* Tx buffer flush done */ -#define KVASER_PCIEFD_KCAN_IRQ_TFD BIT(14) -/* Tx FIFO overflow */ -#define KVASER_PCIEFD_KCAN_IRQ_TOF BIT(15) -/* Tx FIFO empty */ -#define KVASER_PCIEFD_KCAN_IRQ_TE BIT(16) /* Transmitter unaligned */ #define KVASER_PCIEFD_KCAN_IRQ_TAL BIT(17) +/* Tx FIFO empty */ +#define KVASER_PCIEFD_KCAN_IRQ_TE BIT(16) +/* Tx FIFO overflow */ +#define KVASER_PCIEFD_KCAN_IRQ_TOF BIT(15) +/* Tx buffer flush done */ +#define KVASER_PCIEFD_KCAN_IRQ_TFD BIT(14) +/* Abort done */ +#define KVASER_PCIEFD_KCAN_IRQ_ABD BIT(13) +/* Rx FIFO overflow */ +#define KVASER_PCIEFD_KCAN_IRQ_ROF BIT(5) +/* FDF bit when controller is in classic CAN mode */ +#define KVASER_PCIEFD_KCAN_IRQ_FDIC BIT(3) +/* Bus parameter protection error */ +#define KVASER_PCIEFD_KCAN_IRQ_BPP BIT(2) +/* Tx FIFO unaligned end */ +#define KVASER_PCIEFD_KCAN_IRQ_TAE BIT(1) +/* Tx FIFO unaligned read */ +#define KVASER_PCIEFD_KCAN_IRQ_TAR BIT(0) +/* Tx FIFO size */ #define KVASER_PCIEFD_KCAN_TX_NPACKETS_MAX_SHIFT 16 +/* Current status packet sequence number */ #define KVASER_PCIEFD_KCAN_STAT_SEQNO_SHIFT 24 -/* Abort request */ -#define KVASER_PCIEFD_KCAN_STAT_AR BIT(7) -/* Idle state. Controller in reset mode and no abort or flush pending */ -#define KVASER_PCIEFD_KCAN_STAT_IDLE BIT(10) -/* Bus off */ -#define KVASER_PCIEFD_KCAN_STAT_BOFF BIT(11) -/* Reset mode request */ -#define KVASER_PCIEFD_KCAN_STAT_RMR BIT(14) -/* Controller in reset mode */ -#define KVASER_PCIEFD_KCAN_STAT_IRM BIT(15) -/* Controller got one-shot capability */ -#define KVASER_PCIEFD_KCAN_STAT_CAP BIT(16) /* Controller got CAN FD capability */ #define KVASER_PCIEFD_KCAN_STAT_FD BIT(19) +/* Controller got one-shot capability */ +#define KVASER_PCIEFD_KCAN_STAT_CAP BIT(16) +/* Controller in reset mode */ +#define KVASER_PCIEFD_KCAN_STAT_IRM BIT(15) +/* Reset mode request */ +#define KVASER_PCIEFD_KCAN_STAT_RMR BIT(14) +/* Bus off */ +#define KVASER_PCIEFD_KCAN_STAT_BOFF BIT(11) +/* Idle state. Controller in reset mode and no abort or flush pending */ +#define KVASER_PCIEFD_KCAN_STAT_IDLE BIT(10) +/* Abort request */ +#define KVASER_PCIEFD_KCAN_STAT_AR BIT(7) +/* Controller is bus off */ #define KVASER_PCIEFD_KCAN_STAT_BUS_OFF_MSK (KVASER_PCIEFD_KCAN_STAT_AR | \ KVASER_PCIEFD_KCAN_STAT_BOFF | KVASER_PCIEFD_KCAN_STAT_RMR | \ KVASER_PCIEFD_KCAN_STAT_IRM) -/* Reset mode */ -#define KVASER_PCIEFD_KCAN_MODE_RM BIT(8) -/* Listen only mode */ -#define KVASER_PCIEFD_KCAN_MODE_LOM BIT(9) -/* Error packet enable */ -#define KVASER_PCIEFD_KCAN_MODE_EPEN BIT(12) -/* CAN FD non-ISO */ -#define KVASER_PCIEFD_KCAN_MODE_NIFDEN BIT(15) -/* Acknowledgment packet type */ -#define KVASER_PCIEFD_KCAN_MODE_APT BIT(20) -/* Active error flag enable. Clear to force error passive */ -#define KVASER_PCIEFD_KCAN_MODE_EEN BIT(23) /* Classic CAN mode */ #define KVASER_PCIEFD_KCAN_MODE_CCM BIT(31) +/* Active error flag enable. Clear to force error passive */ +#define KVASER_PCIEFD_KCAN_MODE_EEN BIT(23) +/* Acknowledgment packet type */ +#define KVASER_PCIEFD_KCAN_MODE_APT BIT(20) +/* CAN FD non-ISO */ +#define KVASER_PCIEFD_KCAN_MODE_NIFDEN BIT(15) +/* Error packet enable */ +#define KVASER_PCIEFD_KCAN_MODE_EPEN BIT(12) +/* Listen only mode */ +#define KVASER_PCIEFD_KCAN_MODE_LOM BIT(9) +/* Reset mode */ +#define KVASER_PCIEFD_KCAN_MODE_RM BIT(8) -#define KVASER_PCIEFD_KCAN_BTRN_SJW_SHIFT 13 -#define KVASER_PCIEFD_KCAN_BTRN_TSEG1_SHIFT 17 +/* BTRN and BTRD fields */ #define KVASER_PCIEFD_KCAN_BTRN_TSEG2_SHIFT 26 +#define KVASER_PCIEFD_KCAN_BTRN_TSEG1_SHIFT 17 +#define KVASER_PCIEFD_KCAN_BTRN_SJW_SHIFT 13 +/* PWM Control fields */ #define KVASER_PCIEFD_KCAN_PWM_TOP_SHIFT 16 -/* Kvaser KCAN packet types */ +/* KCAN packet type IDs */ #define KVASER_PCIEFD_PACK_TYPE_DATA 0 #define KVASER_PCIEFD_PACK_TYPE_ACK 1 #define KVASER_PCIEFD_PACK_TYPE_TXRQ 2 @@ -195,41 +205,41 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_PACK_TYPE_STATUS 8 #define KVASER_PCIEFD_PACK_TYPE_BUS_LOAD 9 -/* Kvaser KCAN packet common definitions */ -#define KVASER_PCIEFD_PACKET_SEQ_MSK 0xff -#define KVASER_PCIEFD_PACKET_CHID_SHIFT 25 +/* Common KCAN packet definitions, second word */ #define KVASER_PCIEFD_PACKET_TYPE_SHIFT 28 +#define KVASER_PCIEFD_PACKET_CHID_SHIFT 25 +#define KVASER_PCIEFD_PACKET_SEQ_MSK 0xff -/* Kvaser KCAN TDATA and RDATA first word */ +/* KCAN Transmit/Receive data packet, first word */ #define KVASER_PCIEFD_RPACKET_IDE BIT(30) #define KVASER_PCIEFD_RPACKET_RTR BIT(29) -/* Kvaser KCAN TDATA and RDATA second word */ -#define KVASER_PCIEFD_RPACKET_ESI BIT(13) -#define KVASER_PCIEFD_RPACKET_BRS BIT(14) +/* KCAN Transmit data packet, second word */ +#define KVASER_PCIEFD_TPACKET_AREQ BIT(31) +#define KVASER_PCIEFD_TPACKET_SMS BIT(16) +/* KCAN Transmit/Receive data packet, second word */ #define KVASER_PCIEFD_RPACKET_FDF BIT(15) +#define KVASER_PCIEFD_RPACKET_BRS BIT(14) +#define KVASER_PCIEFD_RPACKET_ESI BIT(13) #define KVASER_PCIEFD_RPACKET_DLC_SHIFT 8 -/* Kvaser KCAN TDATA second word */ -#define KVASER_PCIEFD_TPACKET_SMS BIT(16) -#define KVASER_PCIEFD_TPACKET_AREQ BIT(31) -/* Kvaser KCAN APACKET */ -#define KVASER_PCIEFD_APACKET_FLU BIT(8) -#define KVASER_PCIEFD_APACKET_CT BIT(9) -#define KVASER_PCIEFD_APACKET_ABL BIT(10) +/* KCAN Transmit acknowledge packet, first word */ #define KVASER_PCIEFD_APACKET_NACK BIT(11) +#define KVASER_PCIEFD_APACKET_ABL BIT(10) +#define KVASER_PCIEFD_APACKET_CT BIT(9) +#define KVASER_PCIEFD_APACKET_FLU BIT(8) -/* Kvaser KCAN SPACK first word */ -#define KVASER_PCIEFD_SPACK_RXERR_SHIFT 8 -#define KVASER_PCIEFD_SPACK_BOFF BIT(16) -#define KVASER_PCIEFD_SPACK_IDET BIT(20) -#define KVASER_PCIEFD_SPACK_IRM BIT(21) +/* KCAN Status packet, first word */ #define KVASER_PCIEFD_SPACK_RMCD BIT(22) -/* Kvaser KCAN SPACK second word */ -#define KVASER_PCIEFD_SPACK_AUTO BIT(21) -#define KVASER_PCIEFD_SPACK_EWLR BIT(23) +#define KVASER_PCIEFD_SPACK_IRM BIT(21) +#define KVASER_PCIEFD_SPACK_IDET BIT(20) +#define KVASER_PCIEFD_SPACK_BOFF BIT(16) +#define KVASER_PCIEFD_SPACK_RXERR_SHIFT 8 +/* KCAN Status packet, second word */ #define KVASER_PCIEFD_SPACK_EPLR BIT(24) +#define KVASER_PCIEFD_SPACK_EWLR BIT(23) +#define KVASER_PCIEFD_SPACK_AUTO BIT(21) -/* Kvaser KCAN_EPACK second word */ +/* KCAN Error detected packet, second word */ #define KVASER_PCIEFD_EPACK_DIR_TX BIT(0) struct kvaser_pciefd; -- cgit v1.2.3 From 954fb21268dd59a911dd0b493249eabfa03d0567 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:45 +0200 Subject: can: kvaser_pciefd: Use FIELD_{GET,PREP} and GENMASK where appropriate Replace opencoded masking and shifting, with GENMASK, FIELD_GET and FIELD_PREP macros. Suggested-by: Vincent MAILHOL Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-12-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 168 +++++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 79 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index d2e520f9eaa7..8779091c448c 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -5,6 +5,7 @@ * - PEAK linux canfd driver */ +#include #include #include #include @@ -26,7 +27,7 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_BEC_POLL_FREQ (jiffies + msecs_to_jiffies(200)) #define KVASER_PCIEFD_MAX_ERR_REP 256U #define KVASER_PCIEFD_CAN_TX_MAX_COUNT 17U -#define KVASER_PCIEFD_MAX_CAN_CHANNELS 4U +#define KVASER_PCIEFD_MAX_CAN_CHANNELS 4UL #define KVASER_PCIEFD_DMA_COUNT 2U #define KVASER_PCIEFD_DMA_SIZE (4U * 1024U) @@ -79,15 +80,16 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* PCI interrupt fields */ #define KVASER_PCIEFD_IRQ_SRB BIT(4) -#define KVASER_PCIEFD_IRQ_ALL_MSK 0x1f +#define KVASER_PCIEFD_IRQ_ALL_MASK GENMASK(4, 0) /* Enable 64-bit DMA address translation */ #define KVASER_PCIEFD_64BIT_DMA_BIT BIT(0) /* System build information fields */ -#define KVASER_PCIEFD_SYSID_NRCHAN_SHIFT 24 -#define KVASER_PCIEFD_SYSID_MAJOR_VER_SHIFT 16 -#define KVASER_PCIEFD_SYSID_BUILD_VER_SHIFT 1 +#define KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK GENMASK(31, 24) +#define KVASER_PCIEFD_SYSID_VERSION_MAJOR_MASK GENMASK(23, 16) +#define KVASER_PCIEFD_SYSID_VERSION_MINOR_MASK GENMASK(7, 0) +#define KVASER_PCIEFD_SYSID_BUILD_SEQ_MASK GENMASK(15, 1) /* Reset DMA buffer 0, 1 and FIFO offset */ #define KVASER_PCIEFD_SRB_CMD_RDB1 BIT(5) @@ -110,17 +112,18 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_SRB_STAT_DI BIT(15) /* SRB current packet level */ -#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK 0xff +#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK GENMASK(7, 0) /* DMA Enable */ #define KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE BIT(0) /* KCAN CTRL packet types */ -#define KVASER_PCIEFD_KCAN_CTRL_EFLUSH (4 << 29) -#define KVASER_PCIEFD_KCAN_CTRL_EFRAME (5 << 29) +#define KVASER_PCIEFD_KCAN_CTRL_TYPE_MASK GENMASK(31, 29) +#define KVASER_PCIEFD_KCAN_CTRL_TYPE_EFLUSH 0x4 +#define KVASER_PCIEFD_KCAN_CTRL_TYPE_EFRAME 0x5 /* Command sequence number */ -#define KVASER_PCIEFD_KCAN_CMD_SEQ_SHIFT 16 +#define KVASER_PCIEFD_KCAN_CMD_SEQ_MASK GENMASK(23, 16) /* Abort, flush and reset */ #define KVASER_PCIEFD_KCAN_CMD_AT BIT(1) /* Request status packet */ @@ -148,10 +151,12 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_KCAN_IRQ_TAR BIT(0) /* Tx FIFO size */ -#define KVASER_PCIEFD_KCAN_TX_NPACKETS_MAX_SHIFT 16 +#define KVASER_PCIEFD_KCAN_TX_NR_PACKETS_MAX_MASK GENMASK(23, 16) +/* Tx FIFO current packet level */ +#define KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK GENMASK(7, 0) /* Current status packet sequence number */ -#define KVASER_PCIEFD_KCAN_STAT_SEQNO_SHIFT 24 +#define KVASER_PCIEFD_KCAN_STAT_SEQNO_MASK GENMASK(31, 24) /* Controller got CAN FD capability */ #define KVASER_PCIEFD_KCAN_STAT_FD BIT(19) /* Controller got one-shot capability */ @@ -187,12 +192,14 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_KCAN_MODE_RM BIT(8) /* BTRN and BTRD fields */ -#define KVASER_PCIEFD_KCAN_BTRN_TSEG2_SHIFT 26 -#define KVASER_PCIEFD_KCAN_BTRN_TSEG1_SHIFT 17 -#define KVASER_PCIEFD_KCAN_BTRN_SJW_SHIFT 13 +#define KVASER_PCIEFD_KCAN_BTRN_TSEG2_MASK GENMASK(30, 26) +#define KVASER_PCIEFD_KCAN_BTRN_TSEG1_MASK GENMASK(25, 17) +#define KVASER_PCIEFD_KCAN_BTRN_SJW_MASK GENMASK(16, 13) +#define KVASER_PCIEFD_KCAN_BTRN_BRP_MASK GENMASK(12, 0) /* PWM Control fields */ -#define KVASER_PCIEFD_KCAN_PWM_TOP_SHIFT 16 +#define KVASER_PCIEFD_KCAN_PWM_TOP_MASK GENMASK(23, 16) +#define KVASER_PCIEFD_KCAN_PWM_TRIGGER_MASK GENMASK(7, 0) /* KCAN packet type IDs */ #define KVASER_PCIEFD_PACK_TYPE_DATA 0 @@ -206,13 +213,14 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_PACK_TYPE_BUS_LOAD 9 /* Common KCAN packet definitions, second word */ -#define KVASER_PCIEFD_PACKET_TYPE_SHIFT 28 -#define KVASER_PCIEFD_PACKET_CHID_SHIFT 25 -#define KVASER_PCIEFD_PACKET_SEQ_MSK 0xff +#define KVASER_PCIEFD_PACKET_TYPE_MASK GENMASK(31, 28) +#define KVASER_PCIEFD_PACKET_CHID_MASK GENMASK(27, 25) +#define KVASER_PCIEFD_PACKET_SEQ_MASK GENMASK(7, 0) /* KCAN Transmit/Receive data packet, first word */ #define KVASER_PCIEFD_RPACKET_IDE BIT(30) #define KVASER_PCIEFD_RPACKET_RTR BIT(29) +#define KVASER_PCIEFD_RPACKET_ID_MASK GENMASK(28, 0) /* KCAN Transmit data packet, second word */ #define KVASER_PCIEFD_TPACKET_AREQ BIT(31) #define KVASER_PCIEFD_TPACKET_SMS BIT(16) @@ -220,7 +228,7 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_RPACKET_FDF BIT(15) #define KVASER_PCIEFD_RPACKET_BRS BIT(14) #define KVASER_PCIEFD_RPACKET_ESI BIT(13) -#define KVASER_PCIEFD_RPACKET_DLC_SHIFT 8 +#define KVASER_PCIEFD_RPACKET_DLC_MASK GENMASK(11, 8) /* KCAN Transmit acknowledge packet, first word */ #define KVASER_PCIEFD_APACKET_NACK BIT(11) @@ -233,7 +241,8 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_SPACK_IRM BIT(21) #define KVASER_PCIEFD_SPACK_IDET BIT(20) #define KVASER_PCIEFD_SPACK_BOFF BIT(16) -#define KVASER_PCIEFD_SPACK_RXERR_SHIFT 8 +#define KVASER_PCIEFD_SPACK_RXERR_MASK GENMASK(15, 8) +#define KVASER_PCIEFD_SPACK_TXERR_MASK GENMASK(7, 0) /* KCAN Status packet, second word */ #define KVASER_PCIEFD_SPACK_EPLR BIT(24) #define KVASER_PCIEFD_SPACK_EWLR BIT(23) @@ -318,7 +327,7 @@ static void kvaser_pciefd_request_status(struct kvaser_pciefd_can *can) u32 cmd; cmd = KVASER_PCIEFD_KCAN_CMD_SRQ; - cmd |= ++can->cmd_seq << KVASER_PCIEFD_KCAN_CMD_SEQ_SHIFT; + cmd |= FIELD_PREP(KVASER_PCIEFD_KCAN_CMD_SEQ_MASK, ++can->cmd_seq); iowrite32(cmd, can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG); } @@ -418,7 +427,7 @@ static void kvaser_pciefd_start_controller_flush(struct kvaser_pciefd_can *can) /* If controller is already idle, run abort, flush and reset */ cmd = KVASER_PCIEFD_KCAN_CMD_AT; - cmd |= ++can->cmd_seq << KVASER_PCIEFD_KCAN_CMD_SEQ_SHIFT; + cmd |= FIELD_PREP(KVASER_PCIEFD_KCAN_CMD_SEQ_MASK, ++can->cmd_seq); iowrite32(cmd, can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG); } else if (!(status & KVASER_PCIEFD_KCAN_STAT_RMR)) { u32 mode; @@ -489,10 +498,10 @@ static void kvaser_pciefd_pwm_stop(struct kvaser_pciefd_can *can) spin_lock_irqsave(&can->lock, irq); pwm_ctrl = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_PWM_REG); - top = (pwm_ctrl >> KVASER_PCIEFD_KCAN_PWM_TOP_SHIFT) & 0xff; + top = FIELD_GET(KVASER_PCIEFD_KCAN_PWM_TOP_MASK, pwm_ctrl); /* Set duty cycle to zero */ - pwm_ctrl |= top; + pwm_ctrl |= FIELD_PREP(KVASER_PCIEFD_KCAN_PWM_TRIGGER_MASK, top); iowrite32(pwm_ctrl, can->reg_base + KVASER_PCIEFD_KCAN_PWM_REG); spin_unlock_irqrestore(&can->lock, irq); } @@ -509,14 +518,14 @@ static void kvaser_pciefd_pwm_start(struct kvaser_pciefd_can *can) /* Set frequency to 500 KHz*/ top = can->kv_pcie->bus_freq / (2 * 500000) - 1; - pwm_ctrl = top & 0xff; - pwm_ctrl |= (top & 0xff) << KVASER_PCIEFD_KCAN_PWM_TOP_SHIFT; + pwm_ctrl = FIELD_PREP(KVASER_PCIEFD_KCAN_PWM_TRIGGER_MASK, top); + pwm_ctrl |= FIELD_PREP(KVASER_PCIEFD_KCAN_PWM_TOP_MASK, top); iowrite32(pwm_ctrl, can->reg_base + KVASER_PCIEFD_KCAN_PWM_REG); /* Set duty cycle to 95 */ trigger = (100 * top - 95 * (top + 1) + 50) / 100; - pwm_ctrl = trigger & 0xff; - pwm_ctrl |= (top & 0xff) << KVASER_PCIEFD_KCAN_PWM_TOP_SHIFT; + pwm_ctrl = FIELD_PREP(KVASER_PCIEFD_KCAN_PWM_TRIGGER_MASK, trigger); + pwm_ctrl |= FIELD_PREP(KVASER_PCIEFD_KCAN_PWM_TOP_MASK, top); iowrite32(pwm_ctrl, can->reg_base + KVASER_PCIEFD_KCAN_PWM_REG); spin_unlock_irqrestore(&can->lock, irq); } @@ -581,8 +590,8 @@ static int kvaser_pciefd_prepare_tx_packet(struct kvaser_pciefd_tx_packet *p, if (cf->can_id & CAN_EFF_FLAG) p->header[0] |= KVASER_PCIEFD_RPACKET_IDE; - p->header[0] |= cf->can_id & CAN_EFF_MASK; - p->header[1] |= can_fd_len2dlc(cf->len) << KVASER_PCIEFD_RPACKET_DLC_SHIFT; + p->header[0] |= FIELD_PREP(KVASER_PCIEFD_RPACKET_ID_MASK, cf->can_id); + p->header[1] |= FIELD_PREP(KVASER_PCIEFD_RPACKET_DLC_MASK, can_fd_len2dlc(cf->len)); p->header[1] |= KVASER_PCIEFD_TPACKET_AREQ; if (can_is_canfd_skb(skb)) { @@ -593,7 +602,7 @@ static int kvaser_pciefd_prepare_tx_packet(struct kvaser_pciefd_tx_packet *p, p->header[1] |= KVASER_PCIEFD_RPACKET_ESI; } - p->header[1] |= seq & KVASER_PCIEFD_PACKET_SEQ_MSK; + p->header[1] |= FIELD_PREP(KVASER_PCIEFD_PACKET_SEQ_MASK, seq); packet_size = cf->len; memcpy(p->data, cf->data, packet_size); @@ -645,7 +654,8 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb, KVASER_PCIEFD_KCAN_FIFO_LAST_REG); } - count = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG); + count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK, + ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG)); /* No room for a new message, stop the queue until at least one * successful transmit */ @@ -670,12 +680,10 @@ static int kvaser_pciefd_set_bittiming(struct kvaser_pciefd_can *can, bool data) else bt = &can->can.bittiming; - btrn = ((bt->phase_seg2 - 1) & 0x1f) << - KVASER_PCIEFD_KCAN_BTRN_TSEG2_SHIFT | - (((bt->prop_seg + bt->phase_seg1) - 1) & 0x1ff) << - KVASER_PCIEFD_KCAN_BTRN_TSEG1_SHIFT | - ((bt->sjw - 1) & 0xf) << KVASER_PCIEFD_KCAN_BTRN_SJW_SHIFT | - ((bt->brp - 1) & 0x1fff); + btrn = FIELD_PREP(KVASER_PCIEFD_KCAN_BTRN_TSEG2_MASK, bt->phase_seg2 - 1) | + FIELD_PREP(KVASER_PCIEFD_KCAN_BTRN_TSEG1_MASK, bt->prop_seg + bt->phase_seg1 - 1) | + FIELD_PREP(KVASER_PCIEFD_KCAN_BTRN_SJW_MASK, bt->sjw - 1) | + FIELD_PREP(KVASER_PCIEFD_KCAN_BTRN_BRP_MASK, bt->brp - 1); spin_lock_irqsave(&can->lock, irq_flags); mode = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); @@ -771,7 +779,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) for (i = 0; i < pcie->nr_channels; i++) { struct net_device *netdev; struct kvaser_pciefd_can *can; - u32 status, tx_npackets; + u32 status, tx_nr_packets_max; netdev = alloc_candev(sizeof(struct kvaser_pciefd_can), KVASER_PCIEFD_CAN_TX_MAX_COUNT); @@ -798,10 +806,10 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) /* Disable Bus load reporting */ iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_BUS_LOAD_REG); - tx_npackets = ioread32(can->reg_base + - KVASER_PCIEFD_KCAN_TX_NPACKETS_REG); - if (((tx_npackets >> KVASER_PCIEFD_KCAN_TX_NPACKETS_MAX_SHIFT) & - 0xff) < KVASER_PCIEFD_CAN_TX_MAX_COUNT) { + tx_nr_packets_max = + FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_MAX_MASK, + ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG)); + if (tx_nr_packets_max < KVASER_PCIEFD_CAN_TX_MAX_COUNT) { dev_err(&pcie->pci->dev, "Max Tx count is smaller than expected\n"); @@ -924,8 +932,9 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); /* Empty Rx FIFO */ - srb_packet_count = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG) & - KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK; + srb_packet_count = + FIELD_GET(KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK, + ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG)); while (srb_packet_count) { /* Drop current packet in FIFO */ ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_FIFO_LAST_REG); @@ -947,17 +956,17 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie) { - u32 sysid, srb_status, build; + u32 version, srb_status, build; - sysid = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_VERSION_REG); + version = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_VERSION_REG); pcie->nr_channels = min(KVASER_PCIEFD_MAX_CAN_CHANNELS, - ((sysid >> KVASER_PCIEFD_SYSID_NRCHAN_SHIFT) & 0xff)); + FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK, version)); build = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_BUILD_REG); - dev_dbg(&pcie->pci->dev, "Version %u.%u.%u\n", - (sysid >> KVASER_PCIEFD_SYSID_MAJOR_VER_SHIFT) & 0xff, - sysid & 0xff, - (build >> KVASER_PCIEFD_SYSID_BUILD_VER_SHIFT) & 0x7fff); + dev_dbg(&pcie->pci->dev, "Version %lu.%lu.%lu\n", + FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MAJOR_MASK, version), + FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MINOR_MASK, version), + FIELD_GET(KVASER_PCIEFD_SYSID_BUILD_SEQ_MASK, build)); srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG); if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DMA)) { @@ -986,7 +995,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, struct canfd_frame *cf; struct can_priv *priv; struct net_device_stats *stats; - u8 ch_id = (p->header[1] >> KVASER_PCIEFD_PACKET_CHID_SHIFT) & 0x7; + u8 ch_id = FIELD_GET(KVASER_PCIEFD_PACKET_CHID_MASK, p->header[1]); if (ch_id >= pcie->nr_channels) return -EIO; @@ -1014,11 +1023,11 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, } } - cf->can_id = p->header[0] & CAN_EFF_MASK; + cf->can_id = FIELD_GET(KVASER_PCIEFD_RPACKET_ID_MASK, p->header[0]); if (p->header[0] & KVASER_PCIEFD_RPACKET_IDE) cf->can_id |= CAN_EFF_FLAG; - cf->len = can_fd_dlc2len(p->header[1] >> KVASER_PCIEFD_RPACKET_DLC_SHIFT); + cf->len = can_fd_dlc2len(FIELD_GET(KVASER_PCIEFD_RPACKET_DLC_MASK, p->header[1])); if (p->header[0] & KVASER_PCIEFD_RPACKET_RTR) { cf->can_id |= CAN_RTR_FLAG; @@ -1095,8 +1104,8 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can, old_state = can->can.state; - bec.txerr = p->header[0] & 0xff; - bec.rxerr = (p->header[0] >> KVASER_PCIEFD_SPACK_RXERR_SHIFT) & 0xff; + bec.txerr = FIELD_GET(KVASER_PCIEFD_SPACK_TXERR_MASK, p->header[0]); + bec.rxerr = FIELD_GET(KVASER_PCIEFD_SPACK_RXERR_MASK, p->header[0]); kvaser_pciefd_packet_to_state(p, &bec, &new_state, &tx_state, &rx_state); @@ -1145,7 +1154,7 @@ static int kvaser_pciefd_handle_error_packet(struct kvaser_pciefd *pcie, struct kvaser_pciefd_rx_packet *p) { struct kvaser_pciefd_can *can; - u8 ch_id = (p->header[1] >> KVASER_PCIEFD_PACKET_CHID_SHIFT) & 0x7; + u8 ch_id = FIELD_GET(KVASER_PCIEFD_PACKET_CHID_MASK, p->header[1]); if (ch_id >= pcie->nr_channels) return -EIO; @@ -1169,8 +1178,8 @@ static int kvaser_pciefd_handle_status_resp(struct kvaser_pciefd_can *can, old_state = can->can.state; - bec.txerr = p->header[0] & 0xff; - bec.rxerr = (p->header[0] >> KVASER_PCIEFD_SPACK_RXERR_SHIFT) & 0xff; + bec.txerr = FIELD_GET(KVASER_PCIEFD_SPACK_TXERR_MASK, p->header[0]); + bec.rxerr = FIELD_GET(KVASER_PCIEFD_SPACK_RXERR_MASK, p->header[0]); kvaser_pciefd_packet_to_state(p, &bec, &new_state, &tx_state, &rx_state); @@ -1220,7 +1229,7 @@ static int kvaser_pciefd_handle_status_packet(struct kvaser_pciefd *pcie, struct kvaser_pciefd_can *can; u8 cmdseq; u32 status; - u8 ch_id = (p->header[1] >> KVASER_PCIEFD_PACKET_CHID_SHIFT) & 0x7; + u8 ch_id = FIELD_GET(KVASER_PCIEFD_PACKET_CHID_MASK, p->header[1]); if (ch_id >= pcie->nr_channels) return -EIO; @@ -1228,34 +1237,35 @@ static int kvaser_pciefd_handle_status_packet(struct kvaser_pciefd *pcie, can = pcie->can[ch_id]; status = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_STAT_REG); - cmdseq = (status >> KVASER_PCIEFD_KCAN_STAT_SEQNO_SHIFT) & 0xff; + cmdseq = FIELD_GET(KVASER_PCIEFD_KCAN_STAT_SEQNO_MASK, status); /* Reset done, start abort and flush */ if (p->header[0] & KVASER_PCIEFD_SPACK_IRM && p->header[0] & KVASER_PCIEFD_SPACK_RMCD && p->header[1] & KVASER_PCIEFD_SPACK_AUTO && - cmdseq == (p->header[1] & KVASER_PCIEFD_PACKET_SEQ_MSK) && + cmdseq == FIELD_GET(KVASER_PCIEFD_PACKET_SEQ_MASK, p->header[1]) && status & KVASER_PCIEFD_KCAN_STAT_IDLE) { u32 cmd; iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); cmd = KVASER_PCIEFD_KCAN_CMD_AT; - cmd |= ++can->cmd_seq << KVASER_PCIEFD_KCAN_CMD_SEQ_SHIFT; + cmd |= FIELD_PREP(KVASER_PCIEFD_KCAN_CMD_SEQ_MASK, ++can->cmd_seq); iowrite32(cmd, can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG); } else if (p->header[0] & KVASER_PCIEFD_SPACK_IDET && p->header[0] & KVASER_PCIEFD_SPACK_IRM && - cmdseq == (p->header[1] & KVASER_PCIEFD_PACKET_SEQ_MSK) && + cmdseq == FIELD_GET(KVASER_PCIEFD_PACKET_SEQ_MASK, p->header[1]) && status & KVASER_PCIEFD_KCAN_STAT_IDLE) { /* Reset detected, send end of flush if no packet are in FIFO */ - u8 count = ioread32(can->reg_base + - KVASER_PCIEFD_KCAN_TX_NPACKETS_REG) & 0xff; + u8 count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK, + ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG)); if (!count) - iowrite32(KVASER_PCIEFD_KCAN_CTRL_EFLUSH, + iowrite32(FIELD_PREP(KVASER_PCIEFD_KCAN_CTRL_TYPE_MASK, + KVASER_PCIEFD_KCAN_CTRL_TYPE_EFLUSH), can->reg_base + KVASER_PCIEFD_KCAN_CTRL_REG); } else if (!(p->header[1] & KVASER_PCIEFD_SPACK_AUTO) && - cmdseq == (p->header[1] & KVASER_PCIEFD_PACKET_SEQ_MSK)) { + cmdseq == FIELD_GET(KVASER_PCIEFD_PACKET_SEQ_MASK, p->header[1])) { /* Response to status request received */ kvaser_pciefd_handle_status_resp(can, p); if (can->can.state != CAN_STATE_BUS_OFF && @@ -1306,7 +1316,7 @@ static int kvaser_pciefd_handle_ack_packet(struct kvaser_pciefd *pcie, { struct kvaser_pciefd_can *can; bool one_shot_fail = false; - u8 ch_id = (p->header[1] >> KVASER_PCIEFD_PACKET_CHID_SHIFT) & 0x7; + u8 ch_id = FIELD_GET(KVASER_PCIEFD_PACKET_CHID_MASK, p->header[1]); if (ch_id >= pcie->nr_channels) return -EIO; @@ -1324,7 +1334,7 @@ static int kvaser_pciefd_handle_ack_packet(struct kvaser_pciefd *pcie, if (p->header[0] & KVASER_PCIEFD_APACKET_FLU) { netdev_dbg(can->can.dev, "Packet was flushed\n"); } else { - int echo_idx = p->header[0] & KVASER_PCIEFD_PACKET_SEQ_MSK; + int echo_idx = FIELD_GET(KVASER_PCIEFD_PACKET_SEQ_MASK, p->header[0]); int dlc; u8 count; struct sk_buff *skb; @@ -1333,8 +1343,8 @@ static int kvaser_pciefd_handle_ack_packet(struct kvaser_pciefd *pcie, if (skb) kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp); dlc = can_get_echo_skb(can->can.dev, echo_idx, NULL); - count = ioread32(can->reg_base + - KVASER_PCIEFD_KCAN_TX_NPACKETS_REG) & 0xff; + count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK, + ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG)); if (count < KVASER_PCIEFD_CAN_TX_MAX_COUNT && netif_queue_stopped(can->can.dev)) @@ -1355,7 +1365,7 @@ static int kvaser_pciefd_handle_eflush_packet(struct kvaser_pciefd *pcie, struct kvaser_pciefd_rx_packet *p) { struct kvaser_pciefd_can *can; - u8 ch_id = (p->header[1] >> KVASER_PCIEFD_PACKET_CHID_SHIFT) & 0x7; + u8 ch_id = FIELD_GET(KVASER_PCIEFD_PACKET_CHID_MASK, p->header[1]); if (ch_id >= pcie->nr_channels) return -EIO; @@ -1394,15 +1404,15 @@ static int kvaser_pciefd_read_packet(struct kvaser_pciefd *pcie, int *start_pos, pos += 2; p->timestamp = le64_to_cpu(timestamp); - type = (p->header[1] >> KVASER_PCIEFD_PACKET_TYPE_SHIFT) & 0xf; + type = FIELD_GET(KVASER_PCIEFD_PACKET_TYPE_MASK, p->header[1]); switch (type) { case KVASER_PCIEFD_PACK_TYPE_DATA: ret = kvaser_pciefd_handle_data_packet(pcie, p, &buffer[pos]); if (!(p->header[0] & KVASER_PCIEFD_RPACKET_RTR)) { u8 data_len; - data_len = can_fd_dlc2len(p->header[1] >> - KVASER_PCIEFD_RPACKET_DLC_SHIFT); + data_len = can_fd_dlc2len(FIELD_GET(KVASER_PCIEFD_RPACKET_DLC_MASK, + p->header[1])); pos += DIV_ROUND_UP(data_len, 4); } break; @@ -1520,7 +1530,7 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev) board_irq = ioread32(pcie->reg_base + KVASER_PCIEFD_IRQ_REG); - if (!(board_irq & KVASER_PCIEFD_IRQ_ALL_MSK)) + if (!(board_irq & KVASER_PCIEFD_IRQ_ALL_MASK)) return IRQ_NONE; if (board_irq & KVASER_PCIEFD_IRQ_SRB) @@ -1612,7 +1622,7 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, pcie->reg_base + KVASER_PCIEFD_SRB_IEN_REG); /* Enable PCI interrupts */ - iowrite32(KVASER_PCIEFD_IRQ_ALL_MSK, + iowrite32(KVASER_PCIEFD_IRQ_ALL_MASK, pcie->reg_base + KVASER_PCIEFD_IEN_REG); /* Ready the DMA buffers */ -- cgit v1.2.3 From f07008a213640ba5389d924ad0e9e08ea3beed4a Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:46 +0200 Subject: can: kvaser_pciefd: Add len8_dlc support Add support for the Classical CAN raw DLC functionality to send and receive DLC values from 9 .. 15. Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-13-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 8779091c448c..e3d730264462 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -591,15 +591,20 @@ static int kvaser_pciefd_prepare_tx_packet(struct kvaser_pciefd_tx_packet *p, p->header[0] |= KVASER_PCIEFD_RPACKET_IDE; p->header[0] |= FIELD_PREP(KVASER_PCIEFD_RPACKET_ID_MASK, cf->can_id); - p->header[1] |= FIELD_PREP(KVASER_PCIEFD_RPACKET_DLC_MASK, can_fd_len2dlc(cf->len)); p->header[1] |= KVASER_PCIEFD_TPACKET_AREQ; if (can_is_canfd_skb(skb)) { + p->header[1] |= FIELD_PREP(KVASER_PCIEFD_RPACKET_DLC_MASK, + can_fd_len2dlc(cf->len)); p->header[1] |= KVASER_PCIEFD_RPACKET_FDF; if (cf->flags & CANFD_BRS) p->header[1] |= KVASER_PCIEFD_RPACKET_BRS; if (cf->flags & CANFD_ESI) p->header[1] |= KVASER_PCIEFD_RPACKET_ESI; + } else { + p->header[1] |= + FIELD_PREP(KVASER_PCIEFD_RPACKET_DLC_MASK, + can_get_cc_dlc((struct can_frame *)cf, can->can.ctrlmode)); } p->header[1] |= FIELD_PREP(KVASER_PCIEFD_PACKET_SEQ_MASK, seq); @@ -834,7 +839,8 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) can->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_FD | - CAN_CTRLMODE_FD_NON_ISO; + CAN_CTRLMODE_FD_NON_ISO | + CAN_CTRLMODE_CC_LEN8_DLC; status = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_STAT_REG); if (!(status & KVASER_PCIEFD_KCAN_STAT_FD)) { @@ -996,12 +1002,14 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, struct can_priv *priv; struct net_device_stats *stats; u8 ch_id = FIELD_GET(KVASER_PCIEFD_PACKET_CHID_MASK, p->header[1]); + u8 dlc; if (ch_id >= pcie->nr_channels) return -EIO; priv = &pcie->can[ch_id]->can; stats = &priv->dev->stats; + dlc = FIELD_GET(KVASER_PCIEFD_RPACKET_DLC_MASK, p->header[1]); if (p->header[1] & KVASER_PCIEFD_RPACKET_FDF) { skb = alloc_canfd_skb(priv->dev, &cf); @@ -1010,6 +1018,7 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, return -ENOMEM; } + cf->len = can_fd_dlc2len(dlc); if (p->header[1] & KVASER_PCIEFD_RPACKET_BRS) cf->flags |= CANFD_BRS; @@ -1021,14 +1030,13 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, stats->rx_dropped++; return -ENOMEM; } + can_frame_set_cc_len((struct can_frame *)cf, dlc, priv->ctrlmode); } cf->can_id = FIELD_GET(KVASER_PCIEFD_RPACKET_ID_MASK, p->header[0]); if (p->header[0] & KVASER_PCIEFD_RPACKET_IDE) cf->can_id |= CAN_EFF_FLAG; - cf->len = can_fd_dlc2len(FIELD_GET(KVASER_PCIEFD_RPACKET_DLC_MASK, p->header[1])); - if (p->header[0] & KVASER_PCIEFD_RPACKET_RTR) { cf->can_id |= CAN_RTR_FLAG; } else { -- cgit v1.2.3 From f4845741e4220eecf96aa157cbb5ba34aaed995e Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:47 +0200 Subject: can: kvaser_pciefd: Refactor code Refactor code; - Format code - Rename variables and macros - Remove intermediate variables - Add/remove blank lines - Reduce scope of variables - Add helper functions Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-14-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 221 ++++++++++++++++------------------------ 1 file changed, 87 insertions(+), 134 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index e3d730264462..0321b70a3b71 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -70,7 +70,7 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_KCAN_CMD_REG 0x400 #define KVASER_PCIEFD_KCAN_IEN_REG 0x408 #define KVASER_PCIEFD_KCAN_IRQ_REG 0x410 -#define KVASER_PCIEFD_KCAN_TX_NPACKETS_REG 0x414 +#define KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG 0x414 #define KVASER_PCIEFD_KCAN_STAT_REG 0x418 #define KVASER_PCIEFD_KCAN_MODE_REG 0x41c #define KVASER_PCIEFD_KCAN_BTRN_REG 0x420 @@ -124,6 +124,8 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* Command sequence number */ #define KVASER_PCIEFD_KCAN_CMD_SEQ_MASK GENMASK(23, 16) +/* Command bits */ +#define KVASER_PCIEFD_KCAN_CMD_MASK GENMASK(5, 0) /* Abort, flush and reset */ #define KVASER_PCIEFD_KCAN_CMD_AT BIT(1) /* Request status packet */ @@ -172,9 +174,9 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); /* Abort request */ #define KVASER_PCIEFD_KCAN_STAT_AR BIT(7) /* Controller is bus off */ -#define KVASER_PCIEFD_KCAN_STAT_BUS_OFF_MSK (KVASER_PCIEFD_KCAN_STAT_AR | \ - KVASER_PCIEFD_KCAN_STAT_BOFF | KVASER_PCIEFD_KCAN_STAT_RMR | \ - KVASER_PCIEFD_KCAN_STAT_IRM) +#define KVASER_PCIEFD_KCAN_STAT_BUS_OFF_MASK \ + (KVASER_PCIEFD_KCAN_STAT_AR | KVASER_PCIEFD_KCAN_STAT_BOFF | \ + KVASER_PCIEFD_KCAN_STAT_RMR | KVASER_PCIEFD_KCAN_STAT_IRM) /* Classic CAN mode */ #define KVASER_PCIEFD_KCAN_MODE_CCM BIT(31) @@ -202,15 +204,15 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); #define KVASER_PCIEFD_KCAN_PWM_TRIGGER_MASK GENMASK(7, 0) /* KCAN packet type IDs */ -#define KVASER_PCIEFD_PACK_TYPE_DATA 0 -#define KVASER_PCIEFD_PACK_TYPE_ACK 1 -#define KVASER_PCIEFD_PACK_TYPE_TXRQ 2 -#define KVASER_PCIEFD_PACK_TYPE_ERROR 3 -#define KVASER_PCIEFD_PACK_TYPE_EFLUSH_ACK 4 -#define KVASER_PCIEFD_PACK_TYPE_EFRAME_ACK 5 -#define KVASER_PCIEFD_PACK_TYPE_ACK_DATA 6 -#define KVASER_PCIEFD_PACK_TYPE_STATUS 8 -#define KVASER_PCIEFD_PACK_TYPE_BUS_LOAD 9 +#define KVASER_PCIEFD_PACK_TYPE_DATA 0x0 +#define KVASER_PCIEFD_PACK_TYPE_ACK 0x1 +#define KVASER_PCIEFD_PACK_TYPE_TXRQ 0x2 +#define KVASER_PCIEFD_PACK_TYPE_ERROR 0x3 +#define KVASER_PCIEFD_PACK_TYPE_EFLUSH_ACK 0x4 +#define KVASER_PCIEFD_PACK_TYPE_EFRAME_ACK 0x5 +#define KVASER_PCIEFD_PACK_TYPE_ACK_DATA 0x6 +#define KVASER_PCIEFD_PACK_TYPE_STATUS 0x8 +#define KVASER_PCIEFD_PACK_TYPE_BUS_LOAD 0x9 /* Common KCAN packet definitions, second word */ #define KVASER_PCIEFD_PACKET_TYPE_MASK GENMASK(31, 28) @@ -322,13 +324,21 @@ static struct pci_device_id kvaser_pciefd_id_table[] = { }; MODULE_DEVICE_TABLE(pci, kvaser_pciefd_id_table); -static void kvaser_pciefd_request_status(struct kvaser_pciefd_can *can) +static inline void kvaser_pciefd_send_kcan_cmd(struct kvaser_pciefd_can *can, u32 cmd) { - u32 cmd; + iowrite32(FIELD_PREP(KVASER_PCIEFD_KCAN_CMD_MASK, cmd) | + FIELD_PREP(KVASER_PCIEFD_KCAN_CMD_SEQ_MASK, ++can->cmd_seq), + can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG); +} + +static inline void kvaser_pciefd_request_status(struct kvaser_pciefd_can *can) +{ + kvaser_pciefd_send_kcan_cmd(can, KVASER_PCIEFD_KCAN_CMD_SRQ); +} - cmd = KVASER_PCIEFD_KCAN_CMD_SRQ; - cmd |= FIELD_PREP(KVASER_PCIEFD_KCAN_CMD_SEQ_MASK, ++can->cmd_seq); - iowrite32(cmd, can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG); +static inline void kvaser_pciefd_abort_flush_reset(struct kvaser_pciefd_can *can) +{ + kvaser_pciefd_send_kcan_cmd(can, KVASER_PCIEFD_KCAN_CMD_AT); } static void kvaser_pciefd_enable_err_gen(struct kvaser_pciefd_can *can) @@ -383,7 +393,6 @@ static void kvaser_pciefd_setup_controller(struct kvaser_pciefd_can *can) unsigned long irq; spin_lock_irqsave(&can->lock, irq); - mode = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); if (can->can.ctrlmode & CAN_CTRLMODE_FD) { mode &= ~KVASER_PCIEFD_KCAN_MODE_CCM; @@ -400,7 +409,6 @@ static void kvaser_pciefd_setup_controller(struct kvaser_pciefd_can *can) mode |= KVASER_PCIEFD_KCAN_MODE_LOM; else mode &= ~KVASER_PCIEFD_KCAN_MODE_LOM; - mode |= KVASER_PCIEFD_KCAN_MODE_EEN; mode |= KVASER_PCIEFD_KCAN_MODE_EPEN; /* Use ACK packet type */ @@ -417,18 +425,13 @@ static void kvaser_pciefd_start_controller_flush(struct kvaser_pciefd_can *can) unsigned long irq; spin_lock_irqsave(&can->lock, irq); - iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); + iowrite32(GENMASK(31, 0), can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); - status = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_STAT_REG); if (status & KVASER_PCIEFD_KCAN_STAT_IDLE) { - u32 cmd; - /* If controller is already idle, run abort, flush and reset */ - cmd = KVASER_PCIEFD_KCAN_CMD_AT; - cmd |= FIELD_PREP(KVASER_PCIEFD_KCAN_CMD_SEQ_MASK, ++can->cmd_seq); - iowrite32(cmd, can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG); + kvaser_pciefd_abort_flush_reset(can); } else if (!(status & KVASER_PCIEFD_KCAN_STAT_RMR)) { u32 mode; @@ -437,7 +440,6 @@ static void kvaser_pciefd_start_controller_flush(struct kvaser_pciefd_can *can) mode |= KVASER_PCIEFD_KCAN_MODE_RM; iowrite32(mode, can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); } - spin_unlock_irqrestore(&can->lock, irq); } @@ -447,7 +449,6 @@ static int kvaser_pciefd_bus_on(struct kvaser_pciefd_can *can) unsigned long irq; del_timer(&can->bec_poll_timer); - if (!completion_done(&can->flush_comp)) kvaser_pciefd_start_controller_flush(can); @@ -459,11 +460,9 @@ static int kvaser_pciefd_bus_on(struct kvaser_pciefd_can *can) spin_lock_irqsave(&can->lock, irq); iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); - iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); - + iowrite32(GENMASK(31, 0), can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); - mode = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); mode &= ~KVASER_PCIEFD_KCAN_MODE_RM; iowrite32(mode, can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); @@ -476,11 +475,10 @@ static int kvaser_pciefd_bus_on(struct kvaser_pciefd_can *can) } /* Reset interrupt handling */ iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); - iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); + iowrite32(GENMASK(31, 0), can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); kvaser_pciefd_set_tx_irq(can); kvaser_pciefd_setup_controller(can); - can->can.state = CAN_STATE_ERROR_ACTIVE; netif_wake_queue(can->can.dev); can->bec.txerr = 0; @@ -499,7 +497,6 @@ static void kvaser_pciefd_pwm_stop(struct kvaser_pciefd_can *can) spin_lock_irqsave(&can->lock, irq); pwm_ctrl = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_PWM_REG); top = FIELD_GET(KVASER_PCIEFD_KCAN_PWM_TOP_MASK, pwm_ctrl); - /* Set duty cycle to zero */ pwm_ctrl |= FIELD_PREP(KVASER_PCIEFD_KCAN_PWM_TRIGGER_MASK, top); iowrite32(pwm_ctrl, can->reg_base + KVASER_PCIEFD_KCAN_PWM_REG); @@ -514,8 +511,7 @@ static void kvaser_pciefd_pwm_start(struct kvaser_pciefd_can *can) kvaser_pciefd_pwm_stop(can); spin_lock_irqsave(&can->lock, irq); - - /* Set frequency to 500 KHz*/ + /* Set frequency to 500 KHz */ top = can->kv_pcie->bus_freq / (2 * 500000) - 1; pwm_ctrl = FIELD_PREP(KVASER_PCIEFD_KCAN_PWM_TRIGGER_MASK, top); @@ -580,7 +576,6 @@ static int kvaser_pciefd_prepare_tx_packet(struct kvaser_pciefd_tx_packet *p, int seq = can->echo_idx; memset(p, 0, sizeof(*p)); - if (can->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) p->header[1] |= KVASER_PCIEFD_TPACKET_SMS; @@ -621,16 +616,15 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb, struct kvaser_pciefd_can *can = netdev_priv(netdev); unsigned long irq_flags; struct kvaser_pciefd_tx_packet packet; - int nwords; + int nr_words; u8 count; if (can_dev_dropped_skb(netdev, skb)) return NETDEV_TX_OK; - nwords = kvaser_pciefd_prepare_tx_packet(&packet, can, skb); + nr_words = kvaser_pciefd_prepare_tx_packet(&packet, can, skb); spin_lock_irqsave(&can->echo_lock, irq_flags); - /* Prepare and save echo skb in internal slot */ can_put_echo_skb(skb, netdev, can->echo_idx, 0); @@ -643,13 +637,13 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb, iowrite32(packet.header[1], can->reg_base + KVASER_PCIEFD_KCAN_FIFO_REG); - if (nwords) { - u32 data_last = ((u32 *)packet.data)[nwords - 1]; + if (nr_words) { + u32 data_last = ((u32 *)packet.data)[nr_words - 1]; /* Write data to fifo, except last word */ iowrite32_rep(can->reg_base + KVASER_PCIEFD_KCAN_FIFO_REG, packet.data, - nwords - 1); + nr_words - 1); /* Write last word to end of fifo */ __raw_writel(data_last, can->reg_base + KVASER_PCIEFD_KCAN_FIFO_LAST_REG); @@ -660,14 +654,13 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb, } count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK, - ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG)); + ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG)); /* No room for a new message, stop the queue until at least one * successful transmit */ if (count >= KVASER_PCIEFD_CAN_TX_MAX_COUNT || can->can.echo_skb[can->echo_idx]) netif_stop_queue(netdev); - spin_unlock_irqrestore(&can->echo_lock, irq_flags); return NETDEV_TX_OK; @@ -692,16 +685,13 @@ static int kvaser_pciefd_set_bittiming(struct kvaser_pciefd_can *can, bool data) spin_lock_irqsave(&can->lock, irq_flags); mode = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); - /* Put the circuit in reset mode */ iowrite32(mode | KVASER_PCIEFD_KCAN_MODE_RM, can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); /* Can only set bittiming if in reset mode */ ret = readl_poll_timeout(can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG, - test, test & KVASER_PCIEFD_KCAN_MODE_RM, - 0, 10); - + test, test & KVASER_PCIEFD_KCAN_MODE_RM, 0, 10); if (ret) { spin_unlock_irqrestore(&can->lock, irq_flags); return -EBUSY; @@ -711,11 +701,10 @@ static int kvaser_pciefd_set_bittiming(struct kvaser_pciefd_can *can, bool data) iowrite32(btrn, can->reg_base + KVASER_PCIEFD_KCAN_BTRD_REG); else iowrite32(btrn, can->reg_base + KVASER_PCIEFD_KCAN_BTRN_REG); - /* Restore previous reset mode status */ iowrite32(mode, can->reg_base + KVASER_PCIEFD_KCAN_MODE_REG); - spin_unlock_irqrestore(&can->lock, irq_flags); + return 0; } @@ -753,6 +742,7 @@ static int kvaser_pciefd_get_berr_counter(const struct net_device *ndev, bec->rxerr = can->bec.rxerr; bec->txerr = can->bec.txerr; + return 0; } @@ -796,7 +786,6 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) netdev->ethtool_ops = &kvaser_pciefd_ethtool_ops; can->reg_base = pcie->reg_base + KVASER_PCIEFD_KCAN0_BASE + i * KVASER_PCIEFD_KCAN_BASE_OFFSET; - can->kv_pcie = pcie; can->cmd_seq = 0; can->err_rep_cnt = 0; @@ -805,15 +794,14 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) init_completion(&can->start_comp); init_completion(&can->flush_comp); - timer_setup(&can->bec_poll_timer, kvaser_pciefd_bec_poll_timer, - 0); + timer_setup(&can->bec_poll_timer, kvaser_pciefd_bec_poll_timer, 0); /* Disable Bus load reporting */ iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_BUS_LOAD_REG); tx_nr_packets_max = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_MAX_MASK, - ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG)); + ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG)); if (tx_nr_packets_max < KVASER_PCIEFD_CAN_TX_MAX_COUNT) { dev_err(&pcie->pci->dev, "Max Tx count is smaller than expected\n"); @@ -827,16 +815,13 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) can->echo_idx = 0; spin_lock_init(&can->echo_lock); spin_lock_init(&can->lock); + can->can.bittiming_const = &kvaser_pciefd_bittiming_const; can->can.data_bittiming_const = &kvaser_pciefd_bittiming_const; - can->can.do_set_bittiming = kvaser_pciefd_set_nominal_bittiming; - can->can.do_set_data_bittiming = - kvaser_pciefd_set_data_bittiming; - + can->can.do_set_data_bittiming = kvaser_pciefd_set_data_bittiming; can->can.do_set_mode = kvaser_pciefd_set_mode; can->can.do_get_berr_counter = kvaser_pciefd_get_berr_counter; - can->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO | @@ -855,10 +840,9 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) can->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT; netdev->flags |= IFF_ECHO; - SET_NETDEV_DEV(netdev, &pcie->pci->dev); - iowrite32(-1, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); + iowrite32(GENMASK(31, 0), can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); @@ -917,18 +901,16 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) for (i = 0; i < KVASER_PCIEFD_DMA_COUNT; i++) { unsigned int offset = KVASER_PCIEFD_DMA_MAP_BASE + 8 * i; - pcie->dma_data[i] = - dmam_alloc_coherent(&pcie->pci->dev, - KVASER_PCIEFD_DMA_SIZE, - &dma_addr[i], - GFP_KERNEL); + pcie->dma_data[i] = dmam_alloc_coherent(&pcie->pci->dev, + KVASER_PCIEFD_DMA_SIZE, + &dma_addr[i], + GFP_KERNEL); if (!pcie->dma_data[i] || !dma_addr[i]) { dev_err(&pcie->pci->dev, "Rx dma_alloc(%u) failure\n", KVASER_PCIEFD_DMA_SIZE); return -ENOMEM; } - kvaser_pciefd_write_dma_map(pcie, dma_addr[i], offset); } @@ -936,7 +918,6 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) iowrite32(KVASER_PCIEFD_SRB_CMD_FOR | KVASER_PCIEFD_SRB_CMD_RDB0 | KVASER_PCIEFD_SRB_CMD_RDB1, pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); - /* Empty Rx FIFO */ srb_packet_count = FIELD_GET(KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK, @@ -976,8 +957,7 @@ static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie) srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG); if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DMA)) { - dev_err(&pcie->pci->dev, - "Hardware without DMA is not supported\n"); + dev_err(&pcie->pci->dev, "Hardware without DMA is not supported\n"); return -ENODEV; } @@ -987,9 +967,9 @@ static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie) pcie->freq_to_ticks_div = pcie->freq / 1000000; if (pcie->freq_to_ticks_div == 0) pcie->freq_to_ticks_div = 1; - /* Turn off all loopback functionality */ iowrite32(0, pcie->reg_base + KVASER_PCIEFD_LOOP_REG); + return 0; } @@ -1000,7 +980,6 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, struct sk_buff *skb; struct canfd_frame *cf; struct can_priv *priv; - struct net_device_stats *stats; u8 ch_id = FIELD_GET(KVASER_PCIEFD_PACKET_CHID_MASK, p->header[1]); u8 dlc; @@ -1008,26 +987,24 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, return -EIO; priv = &pcie->can[ch_id]->can; - stats = &priv->dev->stats; dlc = FIELD_GET(KVASER_PCIEFD_RPACKET_DLC_MASK, p->header[1]); if (p->header[1] & KVASER_PCIEFD_RPACKET_FDF) { skb = alloc_canfd_skb(priv->dev, &cf); if (!skb) { - stats->rx_dropped++; + priv->dev->stats.rx_dropped++; return -ENOMEM; } cf->len = can_fd_dlc2len(dlc); if (p->header[1] & KVASER_PCIEFD_RPACKET_BRS) cf->flags |= CANFD_BRS; - if (p->header[1] & KVASER_PCIEFD_RPACKET_ESI) cf->flags |= CANFD_ESI; } else { skb = alloc_can_skb(priv->dev, (struct can_frame **)&cf); if (!skb) { - stats->rx_dropped++; + priv->dev->stats.rx_dropped++; return -ENOMEM; } can_frame_set_cc_len((struct can_frame *)cf, dlc, priv->ctrlmode); @@ -1041,10 +1018,9 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie, cf->can_id |= CAN_RTR_FLAG; } else { memcpy(cf->data, data, cf->len); - - stats->rx_bytes += cf->len; + priv->dev->stats.rx_bytes += cf->len; } - stats->rx_packets++; + priv->dev->stats.rx_packets++; kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp); return netif_rx(skb); @@ -1065,7 +1041,6 @@ static void kvaser_pciefd_change_state(struct kvaser_pciefd_can *can, spin_lock_irqsave(&can->lock, irq_flags); netif_stop_queue(can->can.dev); spin_unlock_irqrestore(&can->lock, irq_flags); - /* Prevent CAN controller from auto recover from bus off */ if (!can->can.restart_ms) { kvaser_pciefd_start_controller_flush(can); @@ -1083,7 +1058,7 @@ static void kvaser_pciefd_packet_to_state(struct kvaser_pciefd_rx_packet *p, if (p->header[0] & KVASER_PCIEFD_SPACK_BOFF || p->header[0] & KVASER_PCIEFD_SPACK_IRM) *new_state = CAN_STATE_BUS_OFF; - else if (bec->txerr >= 255 || bec->rxerr >= 255) + else if (bec->txerr >= 255 || bec->rxerr >= 255) *new_state = CAN_STATE_BUS_OFF; else if (p->header[1] & KVASER_PCIEFD_SPACK_EPLR) *new_state = CAN_STATE_ERROR_PASSIVE; @@ -1108,22 +1083,16 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can, struct net_device *ndev = can->can.dev; struct sk_buff *skb; struct can_frame *cf = NULL; - struct net_device_stats *stats = &ndev->stats; old_state = can->can.state; bec.txerr = FIELD_GET(KVASER_PCIEFD_SPACK_TXERR_MASK, p->header[0]); bec.rxerr = FIELD_GET(KVASER_PCIEFD_SPACK_RXERR_MASK, p->header[0]); - kvaser_pciefd_packet_to_state(p, &bec, &new_state, &tx_state, - &rx_state); - + kvaser_pciefd_packet_to_state(p, &bec, &new_state, &tx_state, &rx_state); skb = alloc_can_err_skb(ndev, &cf); - if (new_state != old_state) { - kvaser_pciefd_change_state(can, cf, new_state, tx_state, - rx_state); - + kvaser_pciefd_change_state(can, cf, new_state, tx_state, rx_state); if (old_state == CAN_STATE_BUS_OFF && new_state == CAN_STATE_ERROR_ACTIVE && can->can.restart_ms) { @@ -1136,25 +1105,25 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can, can->err_rep_cnt++; can->can.can_stats.bus_error++; if (p->header[1] & KVASER_PCIEFD_EPACK_DIR_TX) - stats->tx_errors++; + ndev->stats.tx_errors++; else - stats->rx_errors++; + ndev->stats.rx_errors++; can->bec.txerr = bec.txerr; can->bec.rxerr = bec.rxerr; if (!skb) { - stats->rx_dropped++; + ndev->stats.rx_dropped++; return -ENOMEM; } kvaser_pciefd_set_skb_timestamp(can->kv_pcie, skb, p->timestamp); cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_CNT; - cf->data[6] = bec.txerr; cf->data[7] = bec.rxerr; netif_rx(skb); + return 0; } @@ -1168,13 +1137,13 @@ static int kvaser_pciefd_handle_error_packet(struct kvaser_pciefd *pcie, return -EIO; can = pcie->can[ch_id]; - kvaser_pciefd_rx_error_frame(can, p); if (can->err_rep_cnt >= KVASER_PCIEFD_MAX_ERR_REP) /* Do not report more errors, until bec_poll_timer expires */ kvaser_pciefd_disable_err_gen(can); /* Start polling the error counters */ mod_timer(&can->bec_poll_timer, KVASER_PCIEFD_BEC_POLL_FREQ); + return 0; } @@ -1189,9 +1158,7 @@ static int kvaser_pciefd_handle_status_resp(struct kvaser_pciefd_can *can, bec.txerr = FIELD_GET(KVASER_PCIEFD_SPACK_TXERR_MASK, p->header[0]); bec.rxerr = FIELD_GET(KVASER_PCIEFD_SPACK_RXERR_MASK, p->header[0]); - kvaser_pciefd_packet_to_state(p, &bec, &new_state, &tx_state, - &rx_state); - + kvaser_pciefd_packet_to_state(p, &bec, &new_state, &tx_state, &rx_state); if (new_state != old_state) { struct net_device *ndev = can->can.dev; struct sk_buff *skb; @@ -1199,15 +1166,11 @@ static int kvaser_pciefd_handle_status_resp(struct kvaser_pciefd_can *can, skb = alloc_can_err_skb(ndev, &cf); if (!skb) { - struct net_device_stats *stats = &ndev->stats; - - stats->rx_dropped++; + ndev->stats.rx_dropped++; return -ENOMEM; } - kvaser_pciefd_change_state(can, cf, new_state, tx_state, - rx_state); - + kvaser_pciefd_change_state(can, cf, new_state, tx_state, rx_state); if (old_state == CAN_STATE_BUS_OFF && new_state == CAN_STATE_ERROR_ACTIVE && can->can.restart_ms) { @@ -1253,21 +1216,18 @@ static int kvaser_pciefd_handle_status_packet(struct kvaser_pciefd *pcie, p->header[1] & KVASER_PCIEFD_SPACK_AUTO && cmdseq == FIELD_GET(KVASER_PCIEFD_PACKET_SEQ_MASK, p->header[1]) && status & KVASER_PCIEFD_KCAN_STAT_IDLE) { - u32 cmd; - iowrite32(KVASER_PCIEFD_KCAN_IRQ_ABD, can->reg_base + KVASER_PCIEFD_KCAN_IRQ_REG); - cmd = KVASER_PCIEFD_KCAN_CMD_AT; - cmd |= FIELD_PREP(KVASER_PCIEFD_KCAN_CMD_SEQ_MASK, ++can->cmd_seq); - iowrite32(cmd, can->reg_base + KVASER_PCIEFD_KCAN_CMD_REG); + kvaser_pciefd_abort_flush_reset(can); } else if (p->header[0] & KVASER_PCIEFD_SPACK_IDET && p->header[0] & KVASER_PCIEFD_SPACK_IRM && cmdseq == FIELD_GET(KVASER_PCIEFD_PACKET_SEQ_MASK, p->header[1]) && status & KVASER_PCIEFD_KCAN_STAT_IDLE) { /* Reset detected, send end of flush if no packet are in FIFO */ - u8 count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK, - ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG)); + u8 count; + count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK, + ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG)); if (!count) iowrite32(FIELD_PREP(KVASER_PCIEFD_KCAN_CTRL_TYPE_MASK, KVASER_PCIEFD_KCAN_CTRL_TYPE_EFLUSH), @@ -1278,11 +1238,10 @@ static int kvaser_pciefd_handle_status_packet(struct kvaser_pciefd *pcie, kvaser_pciefd_handle_status_resp(can, p); if (can->can.state != CAN_STATE_BUS_OFF && can->can.state != CAN_STATE_ERROR_ACTIVE) { - mod_timer(&can->bec_poll_timer, - KVASER_PCIEFD_BEC_POLL_FREQ); + mod_timer(&can->bec_poll_timer, KVASER_PCIEFD_BEC_POLL_FREQ); } } else if (p->header[0] & KVASER_PCIEFD_SPACK_RMCD && - !(status & KVASER_PCIEFD_KCAN_STAT_BUS_OFF_MSK)) { + !(status & KVASER_PCIEFD_KCAN_STAT_BUS_OFF_MASK)) { /* Reset to bus on detected */ if (!completion_done(&can->start_comp)) complete(&can->start_comp); @@ -1295,12 +1254,10 @@ static void kvaser_pciefd_handle_nack_packet(struct kvaser_pciefd_can *can, struct kvaser_pciefd_rx_packet *p) { struct sk_buff *skb; - struct net_device_stats *stats = &can->can.dev->stats; struct can_frame *cf; skb = alloc_can_err_skb(can->can.dev, &cf); - - stats->tx_errors++; + can->can.dev->stats.tx_errors++; if (p->header[0] & KVASER_PCIEFD_APACKET_ABL) { if (skb) cf->can_id |= CAN_ERR_LOSTARB; @@ -1314,7 +1271,7 @@ static void kvaser_pciefd_handle_nack_packet(struct kvaser_pciefd_can *can, kvaser_pciefd_set_skb_timestamp(can->kv_pcie, skb, p->timestamp); netif_rx(skb); } else { - stats->rx_dropped++; + can->can.dev->stats.rx_dropped++; netdev_warn(can->can.dev, "No memory left for err_skb\n"); } } @@ -1343,26 +1300,24 @@ static int kvaser_pciefd_handle_ack_packet(struct kvaser_pciefd *pcie, netdev_dbg(can->can.dev, "Packet was flushed\n"); } else { int echo_idx = FIELD_GET(KVASER_PCIEFD_PACKET_SEQ_MASK, p->header[0]); - int dlc; + int len; u8 count; struct sk_buff *skb; skb = can->can.echo_skb[echo_idx]; if (skb) kvaser_pciefd_set_skb_timestamp(pcie, skb, p->timestamp); - dlc = can_get_echo_skb(can->can.dev, echo_idx, NULL); + len = can_get_echo_skb(can->can.dev, echo_idx, NULL); count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK, - ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NPACKETS_REG)); + ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG)); if (count < KVASER_PCIEFD_CAN_TX_MAX_COUNT && netif_queue_stopped(can->can.dev)) netif_wake_queue(can->can.dev); if (!one_shot_fail) { - struct net_device_stats *stats = &can->can.dev->stats; - - stats->tx_bytes += dlc; - stats->tx_packets++; + can->can.dev->stats.tx_bytes += len; + can->can.dev->stats.tx_packets++; } } @@ -1562,13 +1517,12 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev) static void kvaser_pciefd_teardown_can_ctrls(struct kvaser_pciefd *pcie) { int i; - struct kvaser_pciefd_can *can; for (i = 0; i < pcie->nr_channels; i++) { - can = pcie->can[i]; + struct kvaser_pciefd_can *can = pcie->can[i]; + if (can) { - iowrite32(0, - can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); + iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); kvaser_pciefd_pwm_stop(can); free_candev(can->can.dev); } @@ -1669,14 +1623,13 @@ err_disable_pci: static void kvaser_pciefd_remove_all_ctrls(struct kvaser_pciefd *pcie) { - struct kvaser_pciefd_can *can; int i; for (i = 0; i < pcie->nr_channels; i++) { - can = pcie->can[i]; + struct kvaser_pciefd_can *can = pcie->can[i]; + if (can) { - iowrite32(0, - can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); + iowrite32(0, can->reg_base + KVASER_PCIEFD_KCAN_IEN_REG); unregister_candev(can->can.dev); del_timer(&can->bec_poll_timer); kvaser_pciefd_pwm_stop(can); -- cgit v1.2.3 From 6fdcd64ec34dc896335718299c348de99b29a605 Mon Sep 17 00:00:00 2001 From: Jimmy Assarsson Date: Mon, 29 May 2023 15:42:48 +0200 Subject: can: kvaser_pciefd: Use TX FIFO size read from CAN controller Use the TX FIFO size read from CAN controller register, instead of using hard coded value. Signed-off-by: Jimmy Assarsson Reviewed-by: Vincent Mailhol Link: https://lore.kernel.org/all/20230529134248.752036-15-extja@kvaser.com Signed-off-by: Marc Kleine-Budde --- drivers/net/can/kvaser_pciefd.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/net/can/kvaser_pciefd.c b/drivers/net/can/kvaser_pciefd.c index 0321b70a3b71..db6256f2b1b3 100644 --- a/drivers/net/can/kvaser_pciefd.c +++ b/drivers/net/can/kvaser_pciefd.c @@ -658,8 +658,7 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb, /* No room for a new message, stop the queue until at least one * successful transmit */ - if (count >= KVASER_PCIEFD_CAN_TX_MAX_COUNT || - can->can.echo_skb[can->echo_idx]) + if (count >= can->can.echo_skb_max || can->can.echo_skb[can->echo_idx]) netif_stop_queue(netdev); spin_unlock_irqrestore(&can->echo_lock, irq_flags); @@ -802,16 +801,9 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) tx_nr_packets_max = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_MAX_MASK, ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG)); - if (tx_nr_packets_max < KVASER_PCIEFD_CAN_TX_MAX_COUNT) { - dev_err(&pcie->pci->dev, - "Max Tx count is smaller than expected\n"); - - free_candev(netdev); - return -ENODEV; - } can->can.clock.freq = pcie->freq; - can->can.echo_skb_max = KVASER_PCIEFD_CAN_TX_MAX_COUNT; + can->can.echo_skb_max = min(KVASER_PCIEFD_CAN_TX_MAX_COUNT, tx_nr_packets_max - 1); can->echo_idx = 0; spin_lock_init(&can->echo_lock); spin_lock_init(&can->lock); @@ -1311,8 +1303,7 @@ static int kvaser_pciefd_handle_ack_packet(struct kvaser_pciefd *pcie, count = FIELD_GET(KVASER_PCIEFD_KCAN_TX_NR_PACKETS_CURRENT_MASK, ioread32(can->reg_base + KVASER_PCIEFD_KCAN_TX_NR_PACKETS_REG)); - if (count < KVASER_PCIEFD_CAN_TX_MAX_COUNT && - netif_queue_stopped(can->can.dev)) + if (count < can->can.echo_skb_max && netif_queue_stopped(can->can.dev)) netif_wake_queue(can->can.dev); if (!one_shot_fail) { -- cgit v1.2.3 From e38910c0072b541a91954682c8b074a93e57c09b Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 7 Jun 2023 09:27:08 +0200 Subject: can: isotp: isotp_sendmsg(): fix return error fix on TX path With commit d674a8f123b4 ("can: isotp: isotp_sendmsg(): fix return error on FC timeout on TX path") the missing correct return value in the case of a protocol error was introduced. But the way the error value has been read and sent to the user space does not follow the common scheme to clear the error after reading which is provided by the sock_error() function. This leads to an error report at the following write() attempt although everything should be working. Fixes: d674a8f123b4 ("can: isotp: isotp_sendmsg(): fix return error on FC timeout on TX path") Reported-by: Carsten Schmidt Signed-off-by: Oliver Hartkopp Link: https://lore.kernel.org/all/20230607072708.38809-1-socketcan@hartkopp.net Cc: stable@vger.kernel.org Signed-off-by: Marc Kleine-Budde --- net/can/isotp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/can/isotp.c b/net/can/isotp.c index 84f9aba02901..ca9d728d6d72 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1112,8 +1112,9 @@ wait_free_buffer: if (err) goto err_event_drop; - if (sk->sk_err) - return -sk->sk_err; + err = sock_error(sk); + if (err) + return err; } return size; -- cgit v1.2.3 From ee77f3d602b0116203151fee372817c194970213 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 21 Jun 2023 23:19:21 -0700 Subject: selftests/bpf: Fix compilation failure for prog vrf_socket_lookup When building the latest kernel/selftest with clang17 compiler: make LLVM=1 -j <== for kernel make -C tools/testing/selftests/bpf LLVM=1 -j <== for selftest I hit the following compilation error: [...] In file included from progs/vrf_socket_lookup.c:3: In file included from /usr/include/linux/ip.h:21: In file included from /usr/include/asm/byteorder.h:5: In file included from /usr/include/linux/byteorder/little_endian.h:13: /usr/include/linux/swab.h:136:8: error: unknown type name '__always_inline' 136 | static __always_inline unsigned long __swab(const unsigned long y) | ^ /usr/include/linux/swab.h:171:8: error: unknown type name '__always_inline' 171 | static __always_inline __u16 __swab16p(const __u16 *p) | ^ /usr/include/linux/swab.h:171:29: error: expected ';' after top level declarator 171 | static __always_inline __u16 __swab16p(const __u16 *p) | ^ [...] Basically, with header files in my local host which is based on 5.12 kernel, __always_inline is not defined and this caused compilation failure. Since __always_inline is defined in bpf_helpers.h, let us move bpf_helpers.h to an early position which fixed the problem. Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20230622061921.816772-1-yhs@fb.com --- tools/testing/selftests/bpf/progs/vrf_socket_lookup.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c b/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c index 26e07a252585..bcfb6feb38c0 100644 --- a/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c +++ b/tools/testing/selftests/bpf/progs/vrf_socket_lookup.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include +#include + #include #include #include #include -#include -#include #include int lookup_status; -- cgit v1.2.3 From 9c50e2b150c8ee0eee5f8154e2ad168cdd748877 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Wed, 7 Jun 2023 14:32:29 -0700 Subject: igc: Fix race condition in PTP tx code Currently, the igc driver supports timestamping only one tx packet at a time. During the transmission flow, the skb that requires hardware timestamping is saved in adapter->ptp_tx_skb. Once hardware has the timestamp, an interrupt is delivered, and adapter->ptp_tx_work is scheduled. In igc_ptp_tx_work(), we read the timestamp register, update adapter->ptp_tx_skb, and notify the network stack. While the thread executing the transmission flow (the user process running in kernel mode) and the thread executing ptp_tx_work don't access adapter->ptp_tx_skb concurrently, there are two other places where adapter->ptp_tx_skb is accessed: igc_ptp_tx_hang() and igc_ptp_suspend(). igc_ptp_tx_hang() is executed by the adapter->watchdog_task worker thread which runs periodically so it is possible we have two threads accessing ptp_tx_skb at the same time. Consider the following scenario: right after __IGC_PTP_TX_IN_PROGRESS is set in igc_xmit_frame_ring(), igc_ptp_tx_hang() is executed. Since adapter->ptp_tx_start hasn't been written yet, this is considered a timeout and adapter->ptp_tx_skb is cleaned up. This patch fixes the issue described above by adding the ptp_tx_lock to protect access to ptp_tx_skb and ptp_tx_start fields from igc_adapter. Since igc_xmit_frame_ring() called in atomic context by the networking stack, ptp_tx_lock is defined as a spinlock, and the irq safe variants of lock/unlock are used. With the introduction of the ptp_tx_lock, the __IGC_PTP_TX_IN_PROGRESS flag doesn't provide much of a use anymore so this patch gets rid of it. Fixes: 2c344ae24501 ("igc: Add support for TX timestamping") Signed-off-by: Andre Guedes Signed-off-by: Vinicius Costa Gomes Reviewed-by: Kurt Kanzenbach Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc.h | 5 ++- drivers/net/ethernet/intel/igc/igc_main.c | 9 +++-- drivers/net/ethernet/intel/igc/igc_ptp.c | 57 +++++++++++++++++-------------- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 34aebf00a512..7da0657ea48f 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -229,6 +229,10 @@ struct igc_adapter { struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_caps; struct work_struct ptp_tx_work; + /* Access to ptp_tx_skb and ptp_tx_start are protected by the + * ptp_tx_lock. + */ + spinlock_t ptp_tx_lock; struct sk_buff *ptp_tx_skb; struct hwtstamp_config tstamp_config; unsigned long ptp_tx_start; @@ -401,7 +405,6 @@ enum igc_state_t { __IGC_TESTING, __IGC_RESETTING, __IGC_DOWN, - __IGC_PTP_TX_IN_PROGRESS, }; enum igc_tx_flags { diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index fa764190f270..9fcb263bd3a7 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -1590,9 +1590,10 @@ done: * the other timer registers before skipping the * timestamping request. */ - if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON && - !test_and_set_bit_lock(__IGC_PTP_TX_IN_PROGRESS, - &adapter->state)) { + unsigned long flags; + + spin_lock_irqsave(&adapter->ptp_tx_lock, flags); + if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON && !adapter->ptp_tx_skb) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; tx_flags |= IGC_TX_FLAGS_TSTAMP; @@ -1601,6 +1602,8 @@ done: } else { adapter->tx_hwtstamp_skipped++; } + + spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags); } if (skb_vlan_tag_present(skb)) { diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 4e10ced736db..56128e55f5c0 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -603,6 +603,7 @@ static int igc_ptp_set_timestamp_mode(struct igc_adapter *adapter, return 0; } +/* Requires adapter->ptp_tx_lock held by caller. */ static void igc_ptp_tx_timeout(struct igc_adapter *adapter) { struct igc_hw *hw = &adapter->hw; @@ -610,7 +611,6 @@ static void igc_ptp_tx_timeout(struct igc_adapter *adapter) dev_kfree_skb_any(adapter->ptp_tx_skb); adapter->ptp_tx_skb = NULL; adapter->tx_hwtstamp_timeouts++; - clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); /* Clear the tx valid bit in TSYNCTXCTL register to enable interrupt. */ rd32(IGC_TXSTMPH); netdev_warn(adapter->netdev, "Tx timestamp timeout\n"); @@ -618,20 +618,20 @@ static void igc_ptp_tx_timeout(struct igc_adapter *adapter) void igc_ptp_tx_hang(struct igc_adapter *adapter) { - bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + - IGC_PTP_TX_TIMEOUT); + unsigned long flags; - if (!test_bit(__IGC_PTP_TX_IN_PROGRESS, &adapter->state)) - return; + spin_lock_irqsave(&adapter->ptp_tx_lock, flags); - /* If we haven't received a timestamp within the timeout, it is - * reasonable to assume that it will never occur, so we can unlock the - * timestamp bit when this occurs. - */ - if (timeout) { - cancel_work_sync(&adapter->ptp_tx_work); - igc_ptp_tx_timeout(adapter); - } + if (!adapter->ptp_tx_skb) + goto unlock; + + if (time_is_after_jiffies(adapter->ptp_tx_start + IGC_PTP_TX_TIMEOUT)) + goto unlock; + + igc_ptp_tx_timeout(adapter); + +unlock: + spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags); } /** @@ -641,6 +641,8 @@ void igc_ptp_tx_hang(struct igc_adapter *adapter) * If we were asked to do hardware stamping and such a time stamp is * available, then it must have been for this skb here because we only * allow only one such packet into the queue. + * + * Context: Expects adapter->ptp_tx_lock to be held by caller. */ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) { @@ -676,13 +678,7 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) shhwtstamps.hwtstamp = ktime_add_ns(shhwtstamps.hwtstamp, adjust); - /* Clear the lock early before calling skb_tstamp_tx so that - * applications are not woken up before the lock bit is clear. We use - * a copy of the skb pointer to ensure other threads can't change it - * while we're notifying the stack. - */ adapter->ptp_tx_skb = NULL; - clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); /* Notify the stack and free the skb after we've unlocked */ skb_tstamp_tx(skb, &shhwtstamps); @@ -693,24 +689,33 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) * igc_ptp_tx_work * @work: pointer to work struct * - * This work function polls the TSYNCTXCTL valid bit to determine when a - * timestamp has been taken for the current stored skb. + * This work function checks the TSYNCTXCTL valid bit to determine when + * a timestamp has been taken for the current stored skb. */ static void igc_ptp_tx_work(struct work_struct *work) { struct igc_adapter *adapter = container_of(work, struct igc_adapter, ptp_tx_work); struct igc_hw *hw = &adapter->hw; + unsigned long flags; u32 tsynctxctl; - if (!test_bit(__IGC_PTP_TX_IN_PROGRESS, &adapter->state)) - return; + spin_lock_irqsave(&adapter->ptp_tx_lock, flags); + + if (!adapter->ptp_tx_skb) + goto unlock; tsynctxctl = rd32(IGC_TSYNCTXCTL); - if (WARN_ON_ONCE(!(tsynctxctl & IGC_TSYNCTXCTL_TXTT_0))) - return; + tsynctxctl &= IGC_TSYNCTXCTL_TXTT_0; + if (!tsynctxctl) { + WARN_ONCE(1, "Received a TSTAMP interrupt but no TSTAMP is ready.\n"); + goto unlock; + } igc_ptp_tx_hwtstamp(adapter); + +unlock: + spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags); } /** @@ -959,6 +964,7 @@ void igc_ptp_init(struct igc_adapter *adapter) return; } + spin_lock_init(&adapter->ptp_tx_lock); spin_lock_init(&adapter->tmreg_lock); INIT_WORK(&adapter->ptp_tx_work, igc_ptp_tx_work); @@ -1023,7 +1029,6 @@ void igc_ptp_suspend(struct igc_adapter *adapter) cancel_work_sync(&adapter->ptp_tx_work); dev_kfree_skb_any(adapter->ptp_tx_skb); adapter->ptp_tx_skb = NULL; - clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); if (pci_device_is_present(adapter->pdev)) { igc_ptp_time_save(adapter); -- cgit v1.2.3 From ce58c7cc8b9910f2bc1d038d7ba60c3f011b2cb2 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Wed, 7 Jun 2023 14:32:30 -0700 Subject: igc: Check if hardware TX timestamping is enabled earlier Before requesting a packet transmission to be hardware timestamped, check if the user has TX timestamping enabled. Fixes an issue that if a packet was internally forwarded to the NIC, and it had the SKBTX_HW_TSTAMP flag set, the driver would mark that timestamp as skipped. In reality, that timestamp was "not for us", as TX timestamp could never be enabled in the NIC. Checking if the TX timestamping is enabled earlier has a secondary effect that when TX timestamping is disabled, there's no need to check for timestamp timeouts. We should only take care to free any pending timestamp when TX timestamping is disabled, as that skb would never be released otherwise. Fixes: 2c344ae24501 ("igc: Add support for TX timestamping") Suggested-by: Vladimir Oltean Signed-off-by: Vinicius Costa Gomes Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc.h | 1 + drivers/net/ethernet/intel/igc/igc_main.c | 5 ++-- drivers/net/ethernet/intel/igc/igc_ptp.c | 42 ++++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 7da0657ea48f..66fb67c17e4f 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -581,6 +581,7 @@ enum igc_ring_flags_t { IGC_RING_FLAG_TX_CTX_IDX, IGC_RING_FLAG_TX_DETECT_HANG, IGC_RING_FLAG_AF_XDP_ZC, + IGC_RING_FLAG_TX_HWTSTAMP, }; #define ring_uses_large_buffer(ring) \ diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 9fcb263bd3a7..eb50bfd5b867 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -1585,7 +1585,8 @@ done: } } - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { + if (unlikely(test_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags) && + skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { /* FIXME: add support for retrieving timestamps from * the other timer registers before skipping the * timestamping request. @@ -1593,7 +1594,7 @@ done: unsigned long flags; spin_lock_irqsave(&adapter->ptp_tx_lock, flags); - if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON && !adapter->ptp_tx_skb) { + if (!adapter->ptp_tx_skb) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; tx_flags |= IGC_TX_FLAGS_TSTAMP; diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 56128e55f5c0..42f622ceb64b 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -536,9 +536,36 @@ static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter) wr32(IGC_TSYNCRXCTL, val); } +static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter) +{ + unsigned long flags; + + cancel_work_sync(&adapter->ptp_tx_work); + + spin_lock_irqsave(&adapter->ptp_tx_lock, flags); + + dev_kfree_skb_any(adapter->ptp_tx_skb); + adapter->ptp_tx_skb = NULL; + + spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags); +} + static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter) { struct igc_hw *hw = &adapter->hw; + int i; + + /* Clear the flags first to avoid new packets to be enqueued + * for TX timestamping. + */ + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igc_ring *tx_ring = adapter->tx_ring[i]; + + clear_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags); + } + + /* Now we can clean the pending TX timestamp requests. */ + igc_ptp_clear_tx_tstamp(adapter); wr32(IGC_TSYNCTXCTL, 0); } @@ -546,12 +573,23 @@ static void igc_ptp_disable_tx_timestamp(struct igc_adapter *adapter) static void igc_ptp_enable_tx_timestamp(struct igc_adapter *adapter) { struct igc_hw *hw = &adapter->hw; + int i; wr32(IGC_TSYNCTXCTL, IGC_TSYNCTXCTL_ENABLED | IGC_TSYNCTXCTL_TXSYNSIG); /* Read TXSTMP registers to discard any timestamp previously stored. */ rd32(IGC_TXSTMPL); rd32(IGC_TXSTMPH); + + /* The hardware is ready to accept TX timestamp requests, + * notify the transmit path. + */ + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igc_ring *tx_ring = adapter->tx_ring[i]; + + set_bit(IGC_RING_FLAG_TX_HWTSTAMP, &tx_ring->flags); + } + } /** @@ -1026,9 +1064,7 @@ void igc_ptp_suspend(struct igc_adapter *adapter) if (!(adapter->ptp_flags & IGC_PTP_ENABLED)) return; - cancel_work_sync(&adapter->ptp_tx_work); - dev_kfree_skb_any(adapter->ptp_tx_skb); - adapter->ptp_tx_skb = NULL; + igc_ptp_clear_tx_tstamp(adapter); if (pci_device_is_present(adapter->pdev)) { igc_ptp_time_save(adapter); -- cgit v1.2.3 From afa141583d82725f682b2fa762cb36a07f58b3f3 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Wed, 7 Jun 2023 14:32:31 -0700 Subject: igc: Retrieve TX timestamp during interrupt handling When the interrupt is handled, the TXTT_0 bit in the TSYNCTXCTL register should already be set and the timestamp value already loaded in the appropriate register. This simplifies the handling, and reduces the latency for retrieving the TX timestamp, which increase the amount of TX timestamps that can be handled in a given time period. As the "work" function doesn't run in a workqueue anymore, rename it to something more sensible, a event handler. Using ntpperf[1] we can see the following performance improvements: Before: $ sudo ./ntpperf -i enp3s0 -m 10:22:22:22:22:21 -d 192.168.1.3 -s 172.18.0.0/16 -I -H -o -37 | responses | TX timestamp offset (ns) rate clients | lost invalid basic xleave | min mean max stddev 1000 100 0.00% 0.00% 0.00% 100.00% -56 +9 +52 19 1500 150 0.00% 0.00% 0.00% 100.00% -40 +30 +75 22 2250 225 0.00% 0.00% 0.00% 100.00% -11 +29 +72 15 3375 337 0.00% 0.00% 0.00% 100.00% -18 +40 +88 22 5062 506 0.00% 0.00% 0.00% 100.00% -19 +23 +77 15 7593 759 0.00% 0.00% 0.00% 100.00% +7 +47 +5168 43 11389 1138 0.00% 0.00% 0.00% 100.00% -11 +41 +5240 39 17083 1708 0.00% 0.00% 0.00% 100.00% +19 +60 +5288 50 25624 2562 0.00% 0.00% 0.00% 100.00% +1 +56 +5368 58 38436 3843 0.00% 0.00% 0.00% 100.00% -84 +12 +8847 66 57654 5765 0.00% 0.00% 100.00% 0.00% 86481 8648 0.00% 0.00% 100.00% 0.00% 129721 12972 0.00% 0.00% 100.00% 0.00% 194581 16384 0.00% 0.00% 100.00% 0.00% 291871 16384 27.35% 0.00% 72.65% 0.00% 437806 16384 50.05% 0.00% 49.95% 0.00% After: $ sudo ./ntpperf -i enp3s0 -m 10:22:22:22:22:21 -d 192.168.1.3 -s 172.18.0.0/16 -I -H -o -37 | responses | TX timestamp offset (ns) rate clients | lost invalid basic xleave | min mean max stddev 1000 100 0.00% 0.00% 0.00% 100.00% -44 +0 +61 19 1500 150 0.00% 0.00% 0.00% 100.00% -6 +39 +81 16 2250 225 0.00% 0.00% 0.00% 100.00% -22 +25 +69 15 3375 337 0.00% 0.00% 0.00% 100.00% -28 +15 +56 14 5062 506 0.00% 0.00% 0.00% 100.00% +7 +78 +143 27 7593 759 0.00% 0.00% 0.00% 100.00% -54 +24 +144 47 11389 1138 0.00% 0.00% 0.00% 100.00% -90 -33 +28 21 17083 1708 0.00% 0.00% 0.00% 100.00% -50 -2 +35 14 25624 2562 0.00% 0.00% 0.00% 100.00% -62 +7 +66 23 38436 3843 0.00% 0.00% 0.00% 100.00% -33 +30 +5395 36 57654 5765 0.00% 0.00% 100.00% 0.00% 86481 8648 0.00% 0.00% 100.00% 0.00% 129721 12972 0.00% 0.00% 100.00% 0.00% 194581 16384 19.50% 0.00% 80.50% 0.00% 291871 16384 35.81% 0.00% 64.19% 0.00% 437806 16384 55.40% 0.00% 44.60% 0.00% [1] https://github.com/mlichvar/ntpperf Signed-off-by: Vinicius Costa Gomes Reviewed-by: Kurt Kanzenbach Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc.h | 2 +- drivers/net/ethernet/intel/igc/igc_main.c | 2 +- drivers/net/ethernet/intel/igc/igc_ptp.c | 15 +++++---------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 66fb67c17e4f..a00738bf6b19 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -228,7 +228,6 @@ struct igc_adapter { struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_caps; - struct work_struct ptp_tx_work; /* Access to ptp_tx_skb and ptp_tx_start are protected by the * ptp_tx_lock. */ @@ -638,6 +637,7 @@ int igc_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr); int igc_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr); void igc_ptp_tx_hang(struct igc_adapter *adapter); void igc_ptp_read(struct igc_adapter *adapter, struct timespec64 *ts); +void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter); #define igc_rx_pg_size(_ring) (PAGE_SIZE << igc_rx_pg_order(_ring)) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index eb50bfd5b867..eb4f0e562f60 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -5223,7 +5223,7 @@ static void igc_tsync_interrupt(struct igc_adapter *adapter) if (tsicr & IGC_TSICR_TXTS) { /* retrieve hardware timestamp */ - schedule_work(&adapter->ptp_tx_work); + igc_ptp_tx_tstamp_event(adapter); ack |= IGC_TSICR_TXTS; } diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 42f622ceb64b..cf963a12a92f 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -540,8 +540,6 @@ static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter) { unsigned long flags; - cancel_work_sync(&adapter->ptp_tx_work); - spin_lock_irqsave(&adapter->ptp_tx_lock, flags); dev_kfree_skb_any(adapter->ptp_tx_skb); @@ -724,16 +722,14 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) } /** - * igc_ptp_tx_work - * @work: pointer to work struct + * igc_ptp_tx_tstamp_event + * @adapter: board private structure * - * This work function checks the TSYNCTXCTL valid bit to determine when - * a timestamp has been taken for the current stored skb. + * Called when a TX timestamp interrupt happens to retrieve the + * timestamp and send it up to the socket. */ -static void igc_ptp_tx_work(struct work_struct *work) +void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter) { - struct igc_adapter *adapter = container_of(work, struct igc_adapter, - ptp_tx_work); struct igc_hw *hw = &adapter->hw; unsigned long flags; u32 tsynctxctl; @@ -1004,7 +1000,6 @@ void igc_ptp_init(struct igc_adapter *adapter) spin_lock_init(&adapter->ptp_tx_lock); spin_lock_init(&adapter->tmreg_lock); - INIT_WORK(&adapter->ptp_tx_work, igc_ptp_tx_work); adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; -- cgit v1.2.3 From c789ad7cbebcac5d5f417296c140a1252c689524 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Wed, 7 Jun 2023 14:32:32 -0700 Subject: igc: Work around HW bug causing missing timestamps There's an hardware issue that can cause missing timestamps. The bug is that the interrupt is only cleared if the IGC_TXSTMPH_0 register is read. The bug can cause a race condition if a timestamp is captured at the wrong time, and we will miss that timestamp. To reduce the time window that the problem is able to happen, in case no timestamp was ready, we read the "previous" value of the timestamp registers, and we compare with the "current" one, if it didn't change we can be reasonably sure that no timestamp was captured. If they are different, we use the new value as the captured timestamp. The HW bug is not easy to reproduce, got to reproduce it when smashing the NIC with timestamping requests from multiple applications (e.g. multiple ntpperf instances + ptp4l), after 10s of minutes. This workaround has more impact when multiple timestamp registers are used, and the IGC_TXSTMPH_0 register always need to be read, so the interrupt is cleared. Fixes: 2c344ae24501 ("igc: Add support for TX timestamping") Signed-off-by: Vinicius Costa Gomes Tested-by: Naama Meir Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_ptp.c | 48 ++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index cf963a12a92f..32ef112f8291 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -685,14 +685,49 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) struct sk_buff *skb = adapter->ptp_tx_skb; struct skb_shared_hwtstamps shhwtstamps; struct igc_hw *hw = &adapter->hw; + u32 tsynctxctl; int adjust = 0; u64 regval; if (WARN_ON_ONCE(!skb)) return; - regval = rd32(IGC_TXSTMPL); - regval |= (u64)rd32(IGC_TXSTMPH) << 32; + tsynctxctl = rd32(IGC_TSYNCTXCTL); + tsynctxctl &= IGC_TSYNCTXCTL_TXTT_0; + if (tsynctxctl) { + regval = rd32(IGC_TXSTMPL); + regval |= (u64)rd32(IGC_TXSTMPH) << 32; + } else { + /* There's a bug in the hardware that could cause + * missing interrupts for TX timestamping. The issue + * is that for new interrupts to be triggered, the + * IGC_TXSTMPH_0 register must be read. + * + * To avoid discarding a valid timestamp that just + * happened at the "wrong" time, we need to confirm + * that there was no timestamp captured, we do that by + * assuming that no two timestamps in sequence have + * the same nanosecond value. + * + * So, we read the "low" register, read the "high" + * register (to latch a new timestamp) and read the + * "low" register again, if "old" and "new" versions + * of the "low" register are different, a valid + * timestamp was captured, we can read the "high" + * register again. + */ + u32 txstmpl_old, txstmpl_new; + + txstmpl_old = rd32(IGC_TXSTMPL); + rd32(IGC_TXSTMPH); + txstmpl_new = rd32(IGC_TXSTMPL); + + if (txstmpl_old == txstmpl_new) + return; + + regval = txstmpl_new; + regval |= (u64)rd32(IGC_TXSTMPH) << 32; + } if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval)) return; @@ -730,22 +765,13 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) */ void igc_ptp_tx_tstamp_event(struct igc_adapter *adapter) { - struct igc_hw *hw = &adapter->hw; unsigned long flags; - u32 tsynctxctl; spin_lock_irqsave(&adapter->ptp_tx_lock, flags); if (!adapter->ptp_tx_skb) goto unlock; - tsynctxctl = rd32(IGC_TSYNCTXCTL); - tsynctxctl &= IGC_TSYNCTXCTL_TXTT_0; - if (!tsynctxctl) { - WARN_ONCE(1, "Received a TSTAMP interrupt but no TSTAMP is ready.\n"); - goto unlock; - } - igc_ptp_tx_hwtstamp(adapter); unlock: -- cgit v1.2.3 From 61f723e6f3d20f3276c678cd346de5ea86b8e5d3 Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Mon, 19 Jun 2023 04:06:35 -0400 Subject: iavf: fix err handling for MAC replace Defer removal of current primary MAC until a replacement is successfully added. Previous implementation would left filter list with no primary MAC. This was found while reading the code. The patch takes advantage of the fact that there can only be a single primary MAC filter at any time ([1] by Piotr) Piotr has also applied some review suggestions during our internal patch submittal process. [1] https://lore.kernel.org/netdev/20230614145302.902301-2-piotrx.gardocki@intel.com/ Reviewed-by: Michal Swiatkowski Tested-by: Rafal Romanowski Signed-off-by: Piotr Gardocki Signed-off-by: Przemek Kitszel Reviewed-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_main.c | 42 +++++++++++++---------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 4a66873882d1..f8e6f3cd7b38 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -1007,40 +1007,36 @@ int iavf_replace_primary_mac(struct iavf_adapter *adapter, const u8 *new_mac) { struct iavf_hw *hw = &adapter->hw; - struct iavf_mac_filter *f; + struct iavf_mac_filter *new_f; + struct iavf_mac_filter *old_f; spin_lock_bh(&adapter->mac_vlan_list_lock); - list_for_each_entry(f, &adapter->mac_filter_list, list) { - f->is_primary = false; + new_f = iavf_add_filter(adapter, new_mac); + if (!new_f) { + spin_unlock_bh(&adapter->mac_vlan_list_lock); + return -ENOMEM; } - f = iavf_find_filter(adapter, hw->mac.addr); - if (f) { - f->remove = true; + old_f = iavf_find_filter(adapter, hw->mac.addr); + if (old_f) { + old_f->is_primary = false; + old_f->remove = true; adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER; } - - f = iavf_add_filter(adapter, new_mac); - - if (f) { - /* Always send the request to add if changing primary MAC - * even if filter is already present on the list - */ - f->is_primary = true; - f->add = true; - adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; - ether_addr_copy(hw->mac.addr, new_mac); - } + /* Always send the request to add if changing primary MAC, + * even if filter is already present on the list + */ + new_f->is_primary = true; + new_f->add = true; + adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; + ether_addr_copy(hw->mac.addr, new_mac); spin_unlock_bh(&adapter->mac_vlan_list_lock); /* schedule the watchdog task to immediately process the request */ - if (f) { - mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); - return 0; - } - return -ENOMEM; + mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); + return 0; } /** -- cgit v1.2.3 From b855bcdeb89777ff255bedf8f1330aac9b26b405 Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Thu, 15 Jun 2023 07:03:08 -0400 Subject: iavf: remove some unused functions and pointless wrappers Remove iavf_aq_get_rss_lut(), iavf_aq_get_rss_key(), iavf_vf_reset(). Remove some "OS specific memory free for shared code" wrappers ;) Signed-off-by: Przemek Kitszel Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf_alloc.h | 3 +- drivers/net/ethernet/intel/iavf/iavf_common.c | 45 ------------------------ drivers/net/ethernet/intel/iavf/iavf_main.c | 22 ++++-------- drivers/net/ethernet/intel/iavf/iavf_osdep.h | 9 ----- drivers/net/ethernet/intel/iavf/iavf_prototype.h | 5 --- 5 files changed, 8 insertions(+), 76 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf_alloc.h b/drivers/net/ethernet/intel/iavf/iavf_alloc.h index 2711573c14ec..162ea70685a6 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_alloc.h +++ b/drivers/net/ethernet/intel/iavf/iavf_alloc.h @@ -28,7 +28,6 @@ enum iavf_status iavf_free_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem); enum iavf_status iavf_allocate_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem, u32 size); -enum iavf_status iavf_free_virt_mem(struct iavf_hw *hw, - struct iavf_virt_mem *mem); +void iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem); #endif /* _IAVF_ALLOC_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c index dd11dbbd5551..1afd761d8052 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_common.c +++ b/drivers/net/ethernet/intel/iavf/iavf_common.c @@ -35,7 +35,6 @@ enum iavf_status iavf_set_mac_type(struct iavf_hw *hw) status = IAVF_ERR_DEVICE_NOT_SUPPORTED; } - hw_dbg(hw, "found mac: %d, returns: %d\n", hw->mac.type, status); return status; } @@ -397,23 +396,6 @@ static enum iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw, return status; } -/** - * iavf_aq_get_rss_lut - * @hw: pointer to the hardware structure - * @vsi_id: vsi fw index - * @pf_lut: for PF table set true, for VSI table set false - * @lut: pointer to the lut buffer provided by the caller - * @lut_size: size of the lut buffer - * - * get the RSS lookup table, PF or VSI type - **/ -enum iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 vsi_id, - bool pf_lut, u8 *lut, u16 lut_size) -{ - return iavf_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, - false); -} - /** * iavf_aq_set_rss_lut * @hw: pointer to the hardware structure @@ -472,19 +454,6 @@ iavf_status iavf_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id, return status; } -/** - * iavf_aq_get_rss_key - * @hw: pointer to the hw struct - * @vsi_id: vsi fw index - * @key: pointer to key info struct - * - **/ -enum iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 vsi_id, - struct iavf_aqc_get_set_rss_key_data *key) -{ - return iavf_aq_get_set_rss_key(hw, vsi_id, key, false); -} - /** * iavf_aq_set_rss_key * @hw: pointer to the hw struct @@ -828,17 +797,3 @@ void iavf_vf_parse_hw_config(struct iavf_hw *hw, vsi_res++; } } - -/** - * iavf_vf_reset - * @hw: pointer to the hardware structure - * - * Send a VF_RESET message to the PF. Does not wait for response from PF - * as none will be forthcoming. Immediately after calling this function, - * the admin queue should be shut down and (optionally) reinitialized. - **/ -enum iavf_status iavf_vf_reset(struct iavf_hw *hw) -{ - return iavf_aq_send_msg_to_pf(hw, VIRTCHNL_OP_RESET_VF, - 0, NULL, 0, NULL); -} diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index f8e6f3cd7b38..f83720a72cc0 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -192,12 +192,11 @@ enum iavf_status iavf_allocate_dma_mem_d(struct iavf_hw *hw, } /** - * iavf_free_dma_mem_d - OS specific memory free for shared code + * iavf_free_dma_mem - wrapper for DMA memory freeing * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -enum iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, - struct iavf_dma_mem *mem) +enum iavf_status iavf_free_dma_mem(struct iavf_hw *hw, struct iavf_dma_mem *mem) { struct iavf_adapter *adapter = (struct iavf_adapter *)hw->back; @@ -209,13 +208,13 @@ enum iavf_status iavf_free_dma_mem_d(struct iavf_hw *hw, } /** - * iavf_allocate_virt_mem_d - OS specific memory alloc for shared code + * iavf_allocate_virt_mem - virt memory alloc wrapper * @hw: pointer to the HW structure * @mem: ptr to mem struct to fill out * @size: size of memory requested **/ -enum iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw, - struct iavf_virt_mem *mem, u32 size) +enum iavf_status iavf_allocate_virt_mem(struct iavf_hw *hw, + struct iavf_virt_mem *mem, u32 size) { if (!mem) return IAVF_ERR_PARAM; @@ -230,20 +229,13 @@ enum iavf_status iavf_allocate_virt_mem_d(struct iavf_hw *hw, } /** - * iavf_free_virt_mem_d - OS specific memory free for shared code + * iavf_free_virt_mem - virt memory free wrapper * @hw: pointer to the HW structure * @mem: ptr to mem struct to free **/ -enum iavf_status iavf_free_virt_mem_d(struct iavf_hw *hw, - struct iavf_virt_mem *mem) +void iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem) { - if (!mem) - return IAVF_ERR_PARAM; - - /* it's ok to kfree a NULL pointer */ kfree(mem->va); - - return 0; } /** diff --git a/drivers/net/ethernet/intel/iavf/iavf_osdep.h b/drivers/net/ethernet/intel/iavf/iavf_osdep.h index a452ce90679a..77d33deaabb5 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_osdep.h +++ b/drivers/net/ethernet/intel/iavf/iavf_osdep.h @@ -13,12 +13,6 @@ /* get readq/writeq support for 32 bit kernels, use the low-first version */ #include -/* File to be the magic between shared code and - * actual OS primitives - */ - -#define hw_dbg(hw, S, A...) do {} while (0) - #define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg))) #define rd32(a, reg) readl((a)->hw_addr + (reg)) @@ -35,14 +29,11 @@ struct iavf_dma_mem { #define iavf_allocate_dma_mem(h, m, unused, s, a) \ iavf_allocate_dma_mem_d(h, m, s, a) -#define iavf_free_dma_mem(h, m) iavf_free_dma_mem_d(h, m) struct iavf_virt_mem { void *va; u32 size; }; -#define iavf_allocate_virt_mem(h, m, s) iavf_allocate_virt_mem_d(h, m, s) -#define iavf_free_virt_mem(h, m) iavf_free_virt_mem_d(h, m) #define iavf_debug(h, m, s, ...) \ do { \ diff --git a/drivers/net/ethernet/intel/iavf/iavf_prototype.h b/drivers/net/ethernet/intel/iavf/iavf_prototype.h index edebfbbcffdc..940cb4203fbe 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_prototype.h +++ b/drivers/net/ethernet/intel/iavf/iavf_prototype.h @@ -40,12 +40,8 @@ enum iavf_status iavf_aq_queue_shutdown(struct iavf_hw *hw, bool unloading); const char *iavf_aq_str(struct iavf_hw *hw, enum iavf_admin_queue_err aq_err); const char *iavf_stat_str(struct iavf_hw *hw, enum iavf_status stat_err); -enum iavf_status iavf_aq_get_rss_lut(struct iavf_hw *hw, u16 seid, - bool pf_lut, u8 *lut, u16 lut_size); enum iavf_status iavf_aq_set_rss_lut(struct iavf_hw *hw, u16 seid, bool pf_lut, u8 *lut, u16 lut_size); -enum iavf_status iavf_aq_get_rss_key(struct iavf_hw *hw, u16 seid, - struct iavf_aqc_get_set_rss_key_data *key); enum iavf_status iavf_aq_set_rss_key(struct iavf_hw *hw, u16 seid, struct iavf_aqc_get_set_rss_key_data *key); @@ -60,7 +56,6 @@ static inline struct iavf_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) void iavf_vf_parse_hw_config(struct iavf_hw *hw, struct virtchnl_vf_resource *msg); -enum iavf_status iavf_vf_reset(struct iavf_hw *hw); enum iavf_status iavf_aq_send_msg_to_pf(struct iavf_hw *hw, enum virtchnl_ops v_opcode, enum iavf_status v_retval, -- cgit v1.2.3 From a4aadf0f5905661cd25c366b96cc1c840f05b756 Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Wed, 21 Jun 2023 08:54:05 -0700 Subject: iavf: make functions static where possible Make all possible functions static. Move iavf_force_wb() up to avoid forward declaration. Suggested-by: Maciej Fijalkowski Reviewed-by: Maciej Fijalkowski Signed-off-by: Przemek Kitszel Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/iavf/iavf.h | 10 ------- drivers/net/ethernet/intel/iavf/iavf_main.c | 14 +++++----- drivers/net/ethernet/intel/iavf/iavf_txrx.c | 43 ++++++++++++++--------------- drivers/net/ethernet/intel/iavf/iavf_txrx.h | 4 --- 4 files changed, 28 insertions(+), 43 deletions(-) diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index 39d0fe76a38f..f80f2735e688 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -523,9 +523,6 @@ void iavf_schedule_request_stats(struct iavf_adapter *adapter); void iavf_reset(struct iavf_adapter *adapter); void iavf_set_ethtool_ops(struct net_device *netdev); void iavf_update_stats(struct iavf_adapter *adapter); -void iavf_reset_interrupt_capability(struct iavf_adapter *adapter); -int iavf_init_interrupt_scheme(struct iavf_adapter *adapter); -void iavf_irq_enable_queues(struct iavf_adapter *adapter); void iavf_free_all_tx_resources(struct iavf_adapter *adapter); void iavf_free_all_rx_resources(struct iavf_adapter *adapter); @@ -579,17 +576,10 @@ void iavf_enable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid); void iavf_disable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid); void iavf_enable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid); void iavf_disable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid); -int iavf_replace_primary_mac(struct iavf_adapter *adapter, - const u8 *new_mac); -void -iavf_set_vlan_offload_features(struct iavf_adapter *adapter, - netdev_features_t prev_features, - netdev_features_t features); void iavf_add_fdir_filter(struct iavf_adapter *adapter); void iavf_del_fdir_filter(struct iavf_adapter *adapter); void iavf_add_adv_rss_cfg(struct iavf_adapter *adapter); void iavf_del_adv_rss_cfg(struct iavf_adapter *adapter); struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter, const u8 *macaddr); -int iavf_lock_timeout(struct mutex *lock, unsigned int msecs); #endif /* _IAVF_H_ */ diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index f83720a72cc0..a483eb185c99 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -245,7 +245,7 @@ void iavf_free_virt_mem(struct iavf_hw *hw, struct iavf_virt_mem *mem) * * Returns 0 on success, negative on failure **/ -int iavf_lock_timeout(struct mutex *lock, unsigned int msecs) +static int iavf_lock_timeout(struct mutex *lock, unsigned int msecs) { unsigned int wait, delay = 10; @@ -354,7 +354,7 @@ static void iavf_irq_disable(struct iavf_adapter *adapter) * iavf_irq_enable_queues - Enable interrupt for all queues * @adapter: board private structure **/ -void iavf_irq_enable_queues(struct iavf_adapter *adapter) +static void iavf_irq_enable_queues(struct iavf_adapter *adapter) { struct iavf_hw *hw = &adapter->hw; int i; @@ -995,8 +995,8 @@ struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter, * * Do not call this with mac_vlan_list_lock! **/ -int iavf_replace_primary_mac(struct iavf_adapter *adapter, - const u8 *new_mac) +static int iavf_replace_primary_mac(struct iavf_adapter *adapter, + const u8 *new_mac) { struct iavf_hw *hw = &adapter->hw; struct iavf_mac_filter *new_f; @@ -1851,7 +1851,7 @@ static void iavf_free_q_vectors(struct iavf_adapter *adapter) * @adapter: board private structure * **/ -void iavf_reset_interrupt_capability(struct iavf_adapter *adapter) +static void iavf_reset_interrupt_capability(struct iavf_adapter *adapter) { if (!adapter->msix_entries) return; @@ -1866,7 +1866,7 @@ void iavf_reset_interrupt_capability(struct iavf_adapter *adapter) * @adapter: board private structure to initialize * **/ -int iavf_init_interrupt_scheme(struct iavf_adapter *adapter) +static int iavf_init_interrupt_scheme(struct iavf_adapter *adapter) { int err; @@ -2164,7 +2164,7 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter) * the watchdog if any changes are requested to expedite the request via * virtchnl. **/ -void +static void iavf_set_vlan_offload_features(struct iavf_adapter *adapter, netdev_features_t prev_features, netdev_features_t features) diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c index e989feda133c..8c5f6096b002 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c @@ -54,7 +54,7 @@ static void iavf_unmap_and_free_tx_resource(struct iavf_ring *ring, * iavf_clean_tx_ring - Free any empty Tx buffers * @tx_ring: ring to be cleaned **/ -void iavf_clean_tx_ring(struct iavf_ring *tx_ring) +static void iavf_clean_tx_ring(struct iavf_ring *tx_ring) { unsigned long bi_size; u16 i; @@ -110,7 +110,7 @@ void iavf_free_tx_resources(struct iavf_ring *tx_ring) * Since there is no access to the ring head register * in XL710, we need to use our local copies **/ -u32 iavf_get_tx_pending(struct iavf_ring *ring, bool in_sw) +static u32 iavf_get_tx_pending(struct iavf_ring *ring, bool in_sw) { u32 head, tail; @@ -127,6 +127,24 @@ u32 iavf_get_tx_pending(struct iavf_ring *ring, bool in_sw) return 0; } +/** + * iavf_force_wb - Issue SW Interrupt so HW does a wb + * @vsi: the VSI we care about + * @q_vector: the vector on which to force writeback + **/ +static void iavf_force_wb(struct iavf_vsi *vsi, struct iavf_q_vector *q_vector) +{ + u32 val = IAVF_VFINT_DYN_CTLN1_INTENA_MASK | + IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */ + IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | + IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK + /* allow 00 to be written to the index */; + + wr32(&vsi->back->hw, + IAVF_VFINT_DYN_CTLN1(q_vector->reg_idx), + val); +} + /** * iavf_detect_recover_hung - Function to detect and recover hung_queues * @vsi: pointer to vsi struct with tx queues @@ -352,25 +370,6 @@ static void iavf_enable_wb_on_itr(struct iavf_vsi *vsi, q_vector->arm_wb_state = true; } -/** - * iavf_force_wb - Issue SW Interrupt so HW does a wb - * @vsi: the VSI we care about - * @q_vector: the vector on which to force writeback - * - **/ -void iavf_force_wb(struct iavf_vsi *vsi, struct iavf_q_vector *q_vector) -{ - u32 val = IAVF_VFINT_DYN_CTLN1_INTENA_MASK | - IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */ - IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | - IAVF_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK - /* allow 00 to be written to the index */; - - wr32(&vsi->back->hw, - IAVF_VFINT_DYN_CTLN1(q_vector->reg_idx), - val); -} - static inline bool iavf_container_is_rx(struct iavf_q_vector *q_vector, struct iavf_ring_container *rc) { @@ -687,7 +686,7 @@ err: * iavf_clean_rx_ring - Free Rx buffers * @rx_ring: ring to be cleaned **/ -void iavf_clean_rx_ring(struct iavf_ring *rx_ring) +static void iavf_clean_rx_ring(struct iavf_ring *rx_ring) { unsigned long bi_size; u16 i; diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.h b/drivers/net/ethernet/intel/iavf/iavf_txrx.h index 2624bf6d009e..7e6ee32d19b6 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_txrx.h +++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.h @@ -442,15 +442,11 @@ static inline unsigned int iavf_rx_pg_order(struct iavf_ring *ring) bool iavf_alloc_rx_buffers(struct iavf_ring *rxr, u16 cleaned_count); netdev_tx_t iavf_xmit_frame(struct sk_buff *skb, struct net_device *netdev); -void iavf_clean_tx_ring(struct iavf_ring *tx_ring); -void iavf_clean_rx_ring(struct iavf_ring *rx_ring); int iavf_setup_tx_descriptors(struct iavf_ring *tx_ring); int iavf_setup_rx_descriptors(struct iavf_ring *rx_ring); void iavf_free_tx_resources(struct iavf_ring *tx_ring); void iavf_free_rx_resources(struct iavf_ring *rx_ring); int iavf_napi_poll(struct napi_struct *napi, int budget); -void iavf_force_wb(struct iavf_vsi *vsi, struct iavf_q_vector *q_vector); -u32 iavf_get_tx_pending(struct iavf_ring *ring, bool in_sw); void iavf_detect_recover_hung(struct iavf_vsi *vsi); int __iavf_maybe_stop_tx(struct iavf_ring *tx_ring, int size); bool __iavf_chk_linearize(struct sk_buff *skb); -- cgit v1.2.3 From a734c43caa4d9a08da521be1a2135cadf1510e75 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 13 Jun 2023 13:40:53 -0700 Subject: ice: reduce initial wait for control queue messages The ice_sq_send_cmd() function is used to send messages to the control queues used to communicate with firmware, virtual functions, and even some hardware. When sending a control queue message, the driver is designed to synchronously wait for a response from the queue. Currently it waits between checks for 100 to 150 microseconds. Commit f86d6f9c49f6 ("ice: sleep, don't busy-wait, for ICE_CTL_Q_SQ_CMD_TIMEOUT") did recently change the behavior from an unnecessary delay into a sleep which is a significant improvement over the old behavior of polling using udelay. Because of the nature of PCIe transactions, the hardware won't be informed about a new message until the write to the tail register posts. This is only guaranteed to occur at the next register read. In ice_sq_send_cmd(), this happens at the ice_sq_done() call. Because of this, the driver essentially forces a minimum of one full wait time regardless of how fast the response is. For the hardware-based sideband queue, this is especially slow. It is expected that the hardware will respond within 2 or 3 microseconds, an order of magnitude faster than the 100-150 microsecond sleep. Allow such fast completions to occur without delay by introducing a small 5 microsecond delay first before entering the sleeping timeout loop. Ensure the tail write has been posted by using ice_flush(hw) first. While at it, lets also remove the ICE_CTL_Q_SQ_CMD_USEC macro as it obscures the sleep time in the inner loop. It was likely introduced to avoid "magic numbers", but in practice sleep and delay values are easier to read and understand when using actual numbers instead of a named constant. This change should allow the fast hardware based control queue messages to complete quickly without delay, while slower firmware queue response times will sleep while waiting for the response. Signed-off-by: Jacob Keller Reviewed-by: Michal Schmidt Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_controlq.c | 9 +++++++-- drivers/net/ethernet/intel/ice/ice_controlq.h | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index d2faf1baad2f..385fd88831db 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -1056,14 +1056,19 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, if (cq->sq.next_to_use == cq->sq.count) cq->sq.next_to_use = 0; wr32(hw, cq->sq.tail, cq->sq.next_to_use); + ice_flush(hw); + + /* Wait a short time before initial ice_sq_done() check, to allow + * hardware time for completion. + */ + udelay(5); timeout = jiffies + ICE_CTL_Q_SQ_CMD_TIMEOUT; do { if (ice_sq_done(hw, cq)) break; - usleep_range(ICE_CTL_Q_SQ_CMD_USEC, - ICE_CTL_Q_SQ_CMD_USEC * 3 / 2); + usleep_range(100, 150); } while (time_before(jiffies, timeout)); /* if ready, copy the desc back to temp */ diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h index 950b7f4a7a05..8f2fd1613a95 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.h +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h @@ -35,7 +35,6 @@ enum ice_ctl_q { /* Control Queue timeout settings - max delay 1s */ #define ICE_CTL_Q_SQ_CMD_TIMEOUT HZ /* Wait max 1s */ -#define ICE_CTL_Q_SQ_CMD_USEC 100 /* Check every 100usec */ #define ICE_CTL_Q_ADMIN_INIT_TIMEOUT 10 /* Count 10 times */ #define ICE_CTL_Q_ADMIN_INIT_MSEC 100 /* Check every 100msec */ -- cgit v1.2.3 From 469748429ac81f0a6a344637fc9d3b1d16a9f3d8 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Thu, 15 Jun 2023 13:33:26 +0200 Subject: ice: allow hot-swapping XDP programs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently ice driver's .ndo_bpf callback brings interface down and up independently of XDP resources' presence. This is only needed when either these resources have to be configured or removed. It means that if one is switching XDP programs on-the-fly with running traffic, packets will be dropped. To avoid this, compare early on ice_xdp_setup_prog() state of incoming bpf_prog pointer vs the bpf_prog pointer that is already assigned to VSI. Do the swap in case VSI has bpf_prog and incoming one are non-NULL. Lastly, while at it, put old bpf_prog *after* the update of Rx ring's bpf_prog pointer. In theory previous code could expose us to a state where Rx ring's bpf_prog would still be referring to old_prog that got released with earlier bpf_prog_put(). Signed-off-by: Maciej Fijalkowski Acked-by: Toke Høiland-Jørgensen Reviewed-by: Alexander Lobakin Tested-by: Chandan Kumar Rout (A Contingent Worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 65bf399a0efc..5dd88611141e 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2633,11 +2633,11 @@ static void ice_vsi_assign_bpf_prog(struct ice_vsi *vsi, struct bpf_prog *prog) int i; old_prog = xchg(&vsi->xdp_prog, prog); - if (old_prog) - bpf_prog_put(old_prog); - ice_for_each_rxq(vsi, i) WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog); + + if (old_prog) + bpf_prog_put(old_prog); } /** @@ -2922,6 +2922,12 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, } } + /* hot swap progs and avoid toggling link */ + if (ice_is_xdp_ena_vsi(vsi) == !!prog) { + ice_vsi_assign_bpf_prog(vsi, prog); + return 0; + } + /* need to stop netdev while setting up the program for Rx rings */ if (if_running && !test_and_set_bit(ICE_VSI_DOWN, vsi->state)) { ret = ice_down(vsi); @@ -2954,13 +2960,6 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, xdp_ring_err = ice_realloc_zc_buf(vsi, false); if (xdp_ring_err) NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Rx resources failed"); - } else { - /* safe to call even when prog == vsi->xdp_prog as - * dev_xdp_install in net/core/dev.c incremented prog's - * refcount so corresponding bpf_prog_put won't cause - * underflow - */ - ice_vsi_assign_bpf_prog(vsi, prog); } if (if_running) -- cgit v1.2.3 From f98277479ad85ff1398e11c1e944ba97c3917393 Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Wed, 31 May 2023 14:36:42 +0200 Subject: ice: clean up freeing SR-IOV VFs The check for existing VFs was redundant since very inception of SR-IOV sysfs interface in the kernel, see commit 1789382a72a5 ("PCI: SRIOV control and status via sysfs"). Reviewed-by: Michal Swiatkowski Reviewed-by: Simon Horman Signed-off-by: Przemek Kitszel Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_sriov.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 2ea6d24977a6..1f66914c7a20 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -905,14 +905,13 @@ err_unroll_intr: */ static int ice_pci_sriov_ena(struct ice_pf *pf, int num_vfs) { - int pre_existing_vfs = pci_num_vf(pf->pdev); struct device *dev = ice_pf_to_dev(pf); int err; - if (pre_existing_vfs && pre_existing_vfs != num_vfs) + if (!num_vfs) { ice_free_vfs(pf); - else if (pre_existing_vfs && pre_existing_vfs == num_vfs) return 0; + } if (num_vfs > pf->vfs.num_supported) { dev_err(dev, "Can't enable %d VFs, max VFs supported is %d\n", -- cgit v1.2.3 From ad667d626825383b626ad6ed38d6205618abb115 Mon Sep 17 00:00:00 2001 From: Przemek Kitszel Date: Wed, 31 May 2023 14:38:40 +0200 Subject: ice: remove null checks before devm_kfree() calls We all know they are redundant. Reviewed-by: Michal Swiatkowski Reviewed-by: Michal Wilczynski Reviewed-by: Simon Horman Signed-off-by: Przemek Kitszel Tested-by: Arpana Arland (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 6 ++-- drivers/net/ethernet/intel/ice/ice_controlq.c | 3 +- drivers/net/ethernet/intel/ice/ice_flow.c | 23 ++------------- drivers/net/ethernet/intel/ice/ice_lib.c | 42 +++++++++------------------ drivers/net/ethernet/intel/ice/ice_sched.c | 11 ++----- drivers/net/ethernet/intel/ice/ice_switch.c | 19 ++++-------- 6 files changed, 29 insertions(+), 75 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index eb2dc0983776..6acb40f3c202 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -814,8 +814,7 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw) devm_kfree(ice_hw_to_dev(hw), lst_itr); } } - if (recps[i].root_buf) - devm_kfree(ice_hw_to_dev(hw), recps[i].root_buf); + devm_kfree(ice_hw_to_dev(hw), recps[i].root_buf); } ice_rm_all_sw_replay_rule_info(hw); devm_kfree(ice_hw_to_dev(hw), sw->recp_list); @@ -1011,8 +1010,7 @@ static int ice_cfg_fw_log(struct ice_hw *hw, bool enable) } out: - if (data) - devm_kfree(ice_hw_to_dev(hw), data); + devm_kfree(ice_hw_to_dev(hw), data); return status; } diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 385fd88831db..e7d2474c431c 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -339,8 +339,7 @@ do { \ } \ } \ /* free the buffer info list */ \ - if ((qi)->ring.cmd_buf) \ - devm_kfree(ice_hw_to_dev(hw), (qi)->ring.cmd_buf); \ + devm_kfree(ice_hw_to_dev(hw), (qi)->ring.cmd_buf); \ /* free DMA head */ \ devm_kfree(ice_hw_to_dev(hw), (qi)->ring.dma_head); \ } while (0) diff --git a/drivers/net/ethernet/intel/ice/ice_flow.c b/drivers/net/ethernet/intel/ice/ice_flow.c index ef103e47a8dc..85cca572c22a 100644 --- a/drivers/net/ethernet/intel/ice/ice_flow.c +++ b/drivers/net/ethernet/intel/ice/ice_flow.c @@ -1303,23 +1303,6 @@ ice_flow_find_prof_id(struct ice_hw *hw, enum ice_block blk, u64 prof_id) return NULL; } -/** - * ice_dealloc_flow_entry - Deallocate flow entry memory - * @hw: pointer to the HW struct - * @entry: flow entry to be removed - */ -static void -ice_dealloc_flow_entry(struct ice_hw *hw, struct ice_flow_entry *entry) -{ - if (!entry) - return; - - if (entry->entry) - devm_kfree(ice_hw_to_dev(hw), entry->entry); - - devm_kfree(ice_hw_to_dev(hw), entry); -} - /** * ice_flow_rem_entry_sync - Remove a flow entry * @hw: pointer to the HW struct @@ -1335,7 +1318,8 @@ ice_flow_rem_entry_sync(struct ice_hw *hw, enum ice_block __always_unused blk, list_del(&entry->l_entry); - ice_dealloc_flow_entry(hw, entry); + devm_kfree(ice_hw_to_dev(hw), entry->entry); + devm_kfree(ice_hw_to_dev(hw), entry); return 0; } @@ -1662,8 +1646,7 @@ ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id, out: if (status && e) { - if (e->entry) - devm_kfree(ice_hw_to_dev(hw), e->entry); + devm_kfree(ice_hw_to_dev(hw), e->entry); devm_kfree(ice_hw_to_dev(hw), e); } diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 5ddb95d1073a..00e3afd507a4 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -321,31 +321,19 @@ static void ice_vsi_free_arrays(struct ice_vsi *vsi) dev = ice_pf_to_dev(pf); - if (vsi->af_xdp_zc_qps) { - bitmap_free(vsi->af_xdp_zc_qps); - vsi->af_xdp_zc_qps = NULL; - } + bitmap_free(vsi->af_xdp_zc_qps); + vsi->af_xdp_zc_qps = NULL; /* free the ring and vector containers */ - if (vsi->q_vectors) { - devm_kfree(dev, vsi->q_vectors); - vsi->q_vectors = NULL; - } - if (vsi->tx_rings) { - devm_kfree(dev, vsi->tx_rings); - vsi->tx_rings = NULL; - } - if (vsi->rx_rings) { - devm_kfree(dev, vsi->rx_rings); - vsi->rx_rings = NULL; - } - if (vsi->txq_map) { - devm_kfree(dev, vsi->txq_map); - vsi->txq_map = NULL; - } - if (vsi->rxq_map) { - devm_kfree(dev, vsi->rxq_map); - vsi->rxq_map = NULL; - } + devm_kfree(dev, vsi->q_vectors); + vsi->q_vectors = NULL; + devm_kfree(dev, vsi->tx_rings); + vsi->tx_rings = NULL; + devm_kfree(dev, vsi->rx_rings); + vsi->rx_rings = NULL; + devm_kfree(dev, vsi->txq_map); + vsi->txq_map = NULL; + devm_kfree(dev, vsi->rxq_map); + vsi->rxq_map = NULL; } /** @@ -902,10 +890,8 @@ static void ice_rss_clean(struct ice_vsi *vsi) dev = ice_pf_to_dev(pf); - if (vsi->rss_hkey_user) - devm_kfree(dev, vsi->rss_hkey_user); - if (vsi->rss_lut_user) - devm_kfree(dev, vsi->rss_lut_user); + devm_kfree(dev, vsi->rss_hkey_user); + devm_kfree(dev, vsi->rss_lut_user); ice_vsi_clean_rss_flow_fld(vsi); /* remove RSS replay list */ diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index b7682de0ae05..b664d60fd037 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -358,10 +358,7 @@ void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node) node->sibling; } - /* leaf nodes have no children */ - if (node->children) - devm_kfree(ice_hw_to_dev(hw), node->children); - + devm_kfree(ice_hw_to_dev(hw), node->children); kfree(node->name); xa_erase(&pi->sched_node_ids, node->id); devm_kfree(ice_hw_to_dev(hw), node); @@ -859,10 +856,8 @@ void ice_sched_cleanup_all(struct ice_hw *hw) if (!hw) return; - if (hw->layer_info) { - devm_kfree(ice_hw_to_dev(hw), hw->layer_info); - hw->layer_info = NULL; - } + devm_kfree(ice_hw_to_dev(hw), hw->layer_info); + hw->layer_info = NULL; ice_sched_clear_port(hw->port_info); diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 2ea9e1ae5517..6db4ca7978cb 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -1636,21 +1636,16 @@ ice_save_vsi_ctx(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi) */ static void ice_clear_vsi_q_ctx(struct ice_hw *hw, u16 vsi_handle) { - struct ice_vsi_ctx *vsi; + struct ice_vsi_ctx *vsi = ice_get_vsi_ctx(hw, vsi_handle); u8 i; - vsi = ice_get_vsi_ctx(hw, vsi_handle); if (!vsi) return; ice_for_each_traffic_class(i) { - if (vsi->lan_q_ctx[i]) { - devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]); - vsi->lan_q_ctx[i] = NULL; - } - if (vsi->rdma_q_ctx[i]) { - devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]); - vsi->rdma_q_ctx[i] = NULL; - } + devm_kfree(ice_hw_to_dev(hw), vsi->lan_q_ctx[i]); + vsi->lan_q_ctx[i] = NULL; + devm_kfree(ice_hw_to_dev(hw), vsi->rdma_q_ctx[i]); + vsi->rdma_q_ctx[i] = NULL; } } @@ -5468,9 +5463,7 @@ err_unroll: devm_kfree(ice_hw_to_dev(hw), fvit); } - if (rm->root_buf) - devm_kfree(ice_hw_to_dev(hw), rm->root_buf); - + devm_kfree(ice_hw_to_dev(hw), rm->root_buf); kfree(rm); err_free_lkup_exts: -- cgit v1.2.3 From 2404dd01b53430e4ab78fc9ca069e9e93fd22059 Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Thu, 22 Jun 2023 09:54:07 +0000 Subject: bpf, docs: BPF Iterator Document Fix the description of the seq_info field of the bpf_iter_reg structure which was wrong due to an accidental copy/paste of the previous field's description. Fixes: 8972e18a439d ("bpf, docs: BPF Iterator Document") Signed-off-by: Anton Protopopov Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230622095407.1024053-1-aspsk@isovalent.com --- Documentation/bpf/bpf_iterators.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Documentation/bpf/bpf_iterators.rst b/Documentation/bpf/bpf_iterators.rst index 6d7770793fab..07433915aa41 100644 --- a/Documentation/bpf/bpf_iterators.rst +++ b/Documentation/bpf/bpf_iterators.rst @@ -238,11 +238,8 @@ The following is the breakdown for each field in struct ``bpf_iter_reg``. that the kernel function cond_resched() is called to avoid other kernel subsystem (e.g., rcu) misbehaving. * - seq_info - - Specifies certain action requests in the kernel BPF iterator - infrastructure. Currently, only BPF_ITER_RESCHED is supported. This means - that the kernel function cond_resched() is called to avoid other kernel - subsystem (e.g., rcu) misbehaving. - + - Specifies the set of seq operations for the BPF iterator and helpers to + initialize/free the private data for the corresponding ``seq_file``. `Click here `_ -- cgit v1.2.3 From fbc5669de62a452fb3a26a4560668637d5c9e7b5 Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Thu, 22 Jun 2023 09:54:24 +0000 Subject: bpf, docs: Document existing macros instead of deprecated The BTF_TYPE_SAFE_NESTED macro was replaced by the BTF_TYPE_SAFE_TRUSTED, BTF_TYPE_SAFE_RCU, and BTF_TYPE_SAFE_RCU_OR_NULL macros. Fix the docs correspondingly. Fixes: 6fcd486b3a0a ("bpf: Refactor RCU enforcement in the verifier.") Signed-off-by: Anton Protopopov Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20230622095424.1024244-1-aspsk@isovalent.com --- Documentation/bpf/kfuncs.rst | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst index 7a3d9de5f315..0d2647fb358d 100644 --- a/Documentation/bpf/kfuncs.rst +++ b/Documentation/bpf/kfuncs.rst @@ -227,23 +227,49 @@ absolutely no ABI stability guarantees. As mentioned above, a nested pointer obtained from walking a trusted pointer is no longer trusted, with one exception. If a struct type has a field that is -guaranteed to be valid as long as its parent pointer is trusted, the -``BTF_TYPE_SAFE_NESTED`` macro can be used to express that to the verifier as -follows: +guaranteed to be valid (trusted or rcu, as in KF_RCU description below) as long +as its parent pointer is valid, the following macros can be used to express +that to the verifier: + +* ``BTF_TYPE_SAFE_TRUSTED`` +* ``BTF_TYPE_SAFE_RCU`` +* ``BTF_TYPE_SAFE_RCU_OR_NULL`` + +For example, + +.. code-block:: c + + BTF_TYPE_SAFE_TRUSTED(struct socket) { + struct sock *sk; + }; + +or .. code-block:: c - BTF_TYPE_SAFE_NESTED(struct task_struct) { + BTF_TYPE_SAFE_RCU(struct task_struct) { const cpumask_t *cpus_ptr; + struct css_set __rcu *cgroups; + struct task_struct __rcu *real_parent; + struct task_struct *group_leader; }; In other words, you must: -1. Wrap the trusted pointer type in the ``BTF_TYPE_SAFE_NESTED`` macro. +1. Wrap the valid pointer type in a ``BTF_TYPE_SAFE_*`` macro. -2. Specify the type and name of the trusted nested field. This field must match +2. Specify the type and name of the valid nested field. This field must match the field in the original type definition exactly. +A new type declared by a ``BTF_TYPE_SAFE_*`` macro also needs to be emitted so +that it appears in BTF. For example, ``BTF_TYPE_SAFE_TRUSTED(struct socket)`` +is emitted in the ``type_is_trusted()`` function as follows: + +.. code-block:: c + + BTF_TYPE_EMIT(BTF_TYPE_SAFE_TRUSTED(struct socket)); + + 2.4.5 KF_SLEEPABLE flag ----------------------- -- cgit v1.2.3 From 31b5a547622b3782388eb676081da1eefe5b98d2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Jun 2023 19:44:22 +0200 Subject: wifi: ieee80211: fix erroneous NSTR bitmap size checks The complete profile bit together with the NSTR link pair present bit indicate whether or not the NSTR bitmap is, the NSTR bitmap size just indicates how big it is. Fixes: 7b6f08771bf6 ("wifi: ieee80211: Support validating ML station profile length") Fixes: 5c1f97537bfb ("wifi: mac80211: store BSS param change count from assoc response") Reported-by: Dan Carpenter Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 6f1747a9c106..4b998090898e 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -4920,7 +4920,7 @@ static inline bool ieee80211_mle_basic_sta_prof_size_ok(const u8 *data, if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT) info_len += 2; if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE && - control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) { + control & IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT) { if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) info_len += 2; else @@ -4959,7 +4959,7 @@ ieee80211_mle_basic_sta_prof_bss_param_ch_cnt(const struct ieee80211_mle_per_sta if (control & IEEE80211_MLE_STA_CONTROL_DTIM_INFO_PRESENT) pos += 2; if (control & IEEE80211_MLE_STA_CONTROL_COMPLETE_PROFILE && - control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) { + control & IEEE80211_MLE_STA_CONTROL_NSTR_LINK_PAIR_PRESENT) { if (control & IEEE80211_MLE_STA_CONTROL_NSTR_BITMAP_SIZE) pos += 2; else -- cgit v1.2.3 From 1dacc49782e67d4316b46329e416c24473c0369c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 11 Jun 2023 22:44:13 +0200 Subject: ice: Remove managed memory usage in ice_get_fw_log_cfg() There is no need to use managed memory allocation here. The memory is released at the end of the function. Use kzalloc()/kfree() to simplify the code. Signed-off-by: Christophe JAILLET Reviewed-by: Pavan Chebbi Reviewed-by: Jacob Keller Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 6acb40f3c202..e16d4c83ed5f 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -833,7 +833,7 @@ static int ice_get_fw_log_cfg(struct ice_hw *hw) u16 size; size = sizeof(*config) * ICE_AQC_FW_LOG_ID_MAX; - config = devm_kzalloc(ice_hw_to_dev(hw), size, GFP_KERNEL); + config = kzalloc(size, GFP_KERNEL); if (!config) return -ENOMEM; @@ -856,7 +856,7 @@ static int ice_get_fw_log_cfg(struct ice_hw *hw) } } - devm_kfree(ice_hw_to_dev(hw), config); + kfree(config); return status; } -- cgit v1.2.3 From b7a0345723385c3cc0438cf4266ccc110dc7b583 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Tue, 13 Jun 2023 13:35:52 +0200 Subject: ice: use ice_down_up() where applicable ice_change_mtu() is currently using a separate ice_down() and ice_up() calls to reflect changed MTU. ice_down_up() serves this purpose, so do the refactoring here. Signed-off-by: Maciej Fijalkowski Reviewed-by: Przemek Kitszel Reviewed-by: Simon Horman Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 5dd88611141e..93979ab18bc1 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -7412,21 +7412,9 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu) } netdev->mtu = (unsigned int)new_mtu; - - /* if VSI is up, bring it down and then back up */ - if (!test_and_set_bit(ICE_VSI_DOWN, vsi->state)) { - err = ice_down(vsi); - if (err) { - netdev_err(netdev, "change MTU if_down err %d\n", err); - return err; - } - - err = ice_up(vsi); - if (err) { - netdev_err(netdev, "change MTU if_up err %d\n", err); - return err; - } - } + err = ice_down_up(vsi); + if (err) + return err; netdev_dbg(netdev, "changed MTU to %d\n", new_mtu); set_bit(ICE_FLAG_MTU_CHANGED, pf->flags); -- cgit v1.2.3 From 533bbc7ce562e476ac381e8ddcb27c46279a44f9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 21 Jun 2023 08:09:49 +0200 Subject: Bluetooth: MAINTAINERS: add Devicetree bindings to Bluetooth drivers The Devicetree bindings should be picked up by subsystem maintainers, but respective pattern for Bluetooth drivers was missing. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Simon Horman Signed-off-by: Jakub Kicinski --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 35e19594640d..4b53a958e3a7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3613,6 +3613,7 @@ S: Supported W: http://www.bluez.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git +F: Documentation/devicetree/bindings/net/bluetooth/ F: drivers/bluetooth/ BLUETOOTH SUBSYSTEM -- cgit v1.2.3 From b9ec61be2d91cc09b5e7302e65442e6d71f0ed93 Mon Sep 17 00:00:00 2001 From: Sathesh Edara Date: Wed, 21 Jun 2023 03:16:49 -0700 Subject: MAINTAINERS: update email addresses of octeon_ep driver maintainers Update email addresses of Marvell octeon_ep driver maintainers. Also remove a former maintainer. As a maintainer below are the responsibilities: - Pushing the bug fixes and new features to upstream. - Responsible for reviewing the external changes submitted for the octeon_ep driver. - Reply to maintainers questions in a timely manner. Signed-off-by: Sathesh Edara Signed-off-by: Jakub Kicinski --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 4b53a958e3a7..1ddfde285a06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12552,7 +12552,7 @@ F: drivers/mtd/nand/raw/marvell_nand.c MARVELL OCTEON ENDPOINT DRIVER M: Veerasenareddy Burru -M: Abhijit Ayarekar +M: Sathesh Edara L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/marvell/octeon_ep -- cgit v1.2.3 From c4fc88ad2a765224a648db8ab35f125e120fe41b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 21 Jun 2023 15:55:37 +0200 Subject: net: stmmac: fix double serdes powerdown Commit 49725ffc15fc ("net: stmmac: power up/down serdes in stmmac_open/release") correctly added a call to the serdes_powerdown() callback to stmmac_release() but did not remove the one from stmmac_remove() which leads to a doubled call to serdes_powerdown(). This can lead to all kinds of problems: in the case of the qcom ethqos driver, it caused an unbalanced regulator disable splat. Fixes: 49725ffc15fc ("net: stmmac: power up/down serdes in stmmac_open/release") Signed-off-by: Bartosz Golaszewski Reviewed-by: Jiri Pirko Acked-by: Junxiao Chang Reviewed-by: Andrew Halaney Tested-by: Andrew Halaney Link: https://lore.kernel.org/r/20230621135537.376649-1-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 87510951f4e8..b74946bbee3c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -7457,12 +7457,6 @@ void stmmac_dvr_remove(struct device *dev) netif_carrier_off(ndev); unregister_netdev(ndev); - /* Serdes power down needs to happen after VLAN filter - * is deleted that is triggered by unregister_netdev(). - */ - if (priv->plat->serdes_powerdown) - priv->plat->serdes_powerdown(ndev, priv->plat->bsp_priv); - #ifdef CONFIG_DEBUG_FS stmmac_exit_fs(ndev); #endif -- cgit v1.2.3 From 8d61f926d42045961e6b65191c09e3678d86a9cf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Jun 2023 15:43:37 +0000 Subject: netlink: fix potential deadlock in netlink_set_err() syzbot reported a possible deadlock in netlink_set_err() [1] A similar issue was fixed in commit 1d482e666b8e ("netlink: disable IRQs for netlink_lock_table()") in netlink_lock_table() This patch adds IRQ safety to netlink_set_err() and __netlink_diag_dump() which were not covered by cited commit. [1] WARNING: possible irq lock inversion dependency detected 6.4.0-rc6-syzkaller-00240-g4e9f0ec38852 #0 Not tainted syz-executor.2/23011 just changed the state of lock: ffffffff8e1a7a58 (nl_table_lock){.+.?}-{2:2}, at: netlink_set_err+0x2e/0x3a0 net/netlink/af_netlink.c:1612 but this lock was taken by another, SOFTIRQ-safe lock in the past: (&local->queue_stop_reason_lock){..-.}-{2:2} and interrupts could create inverse lock ordering between them. other info that might help us debug this: Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(nl_table_lock); local_irq_disable(); lock(&local->queue_stop_reason_lock); lock(nl_table_lock); lock(&local->queue_stop_reason_lock); *** DEADLOCK *** Fixes: 1d482e666b8e ("netlink: disable IRQs for netlink_lock_table()") Reported-by: syzbot+a7d200a347f912723e5c@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=a7d200a347f912723e5c Link: https://lore.kernel.org/netdev/000000000000e38d1605fea5747e@google.com/T/#u Signed-off-by: Eric Dumazet Cc: Johannes Berg Link: https://lore.kernel.org/r/20230621154337.1668594-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/netlink/af_netlink.c | 5 +++-- net/netlink/diag.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3a1e0fd5bf14..5968b6450d82 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1600,6 +1600,7 @@ out: int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code) { struct netlink_set_err_data info; + unsigned long flags; struct sock *sk; int ret = 0; @@ -1609,12 +1610,12 @@ int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code) /* sk->sk_err wants a positive error value */ info.code = -code; - read_lock(&nl_table_lock); + read_lock_irqsave(&nl_table_lock, flags); sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) ret += do_one_set_err(sk, &info); - read_unlock(&nl_table_lock); + read_unlock_irqrestore(&nl_table_lock, flags); return ret; } EXPORT_SYMBOL(netlink_set_err); diff --git a/net/netlink/diag.c b/net/netlink/diag.c index c6255eac305c..4143b2ea4195 100644 --- a/net/netlink/diag.c +++ b/net/netlink/diag.c @@ -94,6 +94,7 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net *net = sock_net(skb->sk); struct netlink_diag_req *req; struct netlink_sock *nlsk; + unsigned long flags; struct sock *sk; int num = 2; int ret = 0; @@ -152,7 +153,7 @@ static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, num++; mc_list: - read_lock(&nl_table_lock); + read_lock_irqsave(&nl_table_lock, flags); sk_for_each_bound(sk, &tbl->mc_list) { if (sk_hashed(sk)) continue; @@ -173,7 +174,7 @@ mc_list: } num++; } - read_unlock(&nl_table_lock); + read_unlock_irqrestore(&nl_table_lock, flags); done: cb->args[0] = num; -- cgit v1.2.3 From aa5406950726e336c5c9585b09799a734b6e77bf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Jun 2023 17:47:20 +0000 Subject: netlink: do not hard code device address lenth in fdb dumps syzbot reports that some netdev devices do not have a six bytes address [1] Replace ETH_ALEN by dev->addr_len. [1] (Case of a device where dev->addr_len = 4) BUG: KMSAN: kernel-infoleak in instrument_copy_to_user include/linux/instrumented.h:114 [inline] BUG: KMSAN: kernel-infoleak in copyout+0xb8/0x100 lib/iov_iter.c:169 instrument_copy_to_user include/linux/instrumented.h:114 [inline] copyout+0xb8/0x100 lib/iov_iter.c:169 _copy_to_iter+0x6d8/0x1d00 lib/iov_iter.c:536 copy_to_iter include/linux/uio.h:206 [inline] simple_copy_to_iter+0x68/0xa0 net/core/datagram.c:513 __skb_datagram_iter+0x123/0xdc0 net/core/datagram.c:419 skb_copy_datagram_iter+0x5c/0x200 net/core/datagram.c:527 skb_copy_datagram_msg include/linux/skbuff.h:3960 [inline] netlink_recvmsg+0x4ae/0x15a0 net/netlink/af_netlink.c:1970 sock_recvmsg_nosec net/socket.c:1019 [inline] sock_recvmsg net/socket.c:1040 [inline] ____sys_recvmsg+0x283/0x7f0 net/socket.c:2722 ___sys_recvmsg+0x223/0x840 net/socket.c:2764 do_recvmmsg+0x4f9/0xfd0 net/socket.c:2858 __sys_recvmmsg net/socket.c:2937 [inline] __do_sys_recvmmsg net/socket.c:2960 [inline] __se_sys_recvmmsg net/socket.c:2953 [inline] __x64_sys_recvmmsg+0x397/0x490 net/socket.c:2953 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd Uninit was stored to memory at: __nla_put lib/nlattr.c:1009 [inline] nla_put+0x1c6/0x230 lib/nlattr.c:1067 nlmsg_populate_fdb_fill+0x2b8/0x600 net/core/rtnetlink.c:4071 nlmsg_populate_fdb net/core/rtnetlink.c:4418 [inline] ndo_dflt_fdb_dump+0x616/0x840 net/core/rtnetlink.c:4456 rtnl_fdb_dump+0x14ff/0x1fc0 net/core/rtnetlink.c:4629 netlink_dump+0x9d1/0x1310 net/netlink/af_netlink.c:2268 netlink_recvmsg+0xc5c/0x15a0 net/netlink/af_netlink.c:1995 sock_recvmsg_nosec+0x7a/0x120 net/socket.c:1019 ____sys_recvmsg+0x664/0x7f0 net/socket.c:2720 ___sys_recvmsg+0x223/0x840 net/socket.c:2764 do_recvmmsg+0x4f9/0xfd0 net/socket.c:2858 __sys_recvmmsg net/socket.c:2937 [inline] __do_sys_recvmmsg net/socket.c:2960 [inline] __se_sys_recvmmsg net/socket.c:2953 [inline] __x64_sys_recvmmsg+0x397/0x490 net/socket.c:2953 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd Uninit was created at: slab_post_alloc_hook+0x12d/0xb60 mm/slab.h:716 slab_alloc_node mm/slub.c:3451 [inline] __kmem_cache_alloc_node+0x4ff/0x8b0 mm/slub.c:3490 kmalloc_trace+0x51/0x200 mm/slab_common.c:1057 kmalloc include/linux/slab.h:559 [inline] __hw_addr_create net/core/dev_addr_lists.c:60 [inline] __hw_addr_add_ex+0x2e5/0x9e0 net/core/dev_addr_lists.c:118 __dev_mc_add net/core/dev_addr_lists.c:867 [inline] dev_mc_add+0x9a/0x130 net/core/dev_addr_lists.c:885 igmp6_group_added+0x267/0xbc0 net/ipv6/mcast.c:680 ipv6_mc_up+0x296/0x3b0 net/ipv6/mcast.c:2754 ipv6_mc_remap+0x1e/0x30 net/ipv6/mcast.c:2708 addrconf_type_change net/ipv6/addrconf.c:3731 [inline] addrconf_notify+0x4d3/0x1d90 net/ipv6/addrconf.c:3699 notifier_call_chain kernel/notifier.c:93 [inline] raw_notifier_call_chain+0xe4/0x430 kernel/notifier.c:461 call_netdevice_notifiers_info net/core/dev.c:1935 [inline] call_netdevice_notifiers_extack net/core/dev.c:1973 [inline] call_netdevice_notifiers+0x1ee/0x2d0 net/core/dev.c:1987 bond_enslave+0xccd/0x53f0 drivers/net/bonding/bond_main.c:1906 do_set_master net/core/rtnetlink.c:2626 [inline] rtnl_newlink_create net/core/rtnetlink.c:3460 [inline] __rtnl_newlink net/core/rtnetlink.c:3660 [inline] rtnl_newlink+0x378c/0x40e0 net/core/rtnetlink.c:3673 rtnetlink_rcv_msg+0x16a6/0x1840 net/core/rtnetlink.c:6395 netlink_rcv_skb+0x371/0x650 net/netlink/af_netlink.c:2546 rtnetlink_rcv+0x34/0x40 net/core/rtnetlink.c:6413 netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline] netlink_unicast+0xf28/0x1230 net/netlink/af_netlink.c:1365 netlink_sendmsg+0x122f/0x13d0 net/netlink/af_netlink.c:1913 sock_sendmsg_nosec net/socket.c:724 [inline] sock_sendmsg net/socket.c:747 [inline] ____sys_sendmsg+0x999/0xd50 net/socket.c:2503 ___sys_sendmsg+0x28d/0x3c0 net/socket.c:2557 __sys_sendmsg net/socket.c:2586 [inline] __do_sys_sendmsg net/socket.c:2595 [inline] __se_sys_sendmsg net/socket.c:2593 [inline] __x64_sys_sendmsg+0x304/0x490 net/socket.c:2593 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd Bytes 2856-2857 of 3500 are uninitialized Memory access of size 3500 starts at ffff888018d99104 Data copied to user address 0000000020000480 Fixes: d83b06036048 ("net: add fdb generic dump routine") Reported-by: syzbot Signed-off-by: Eric Dumazet Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20230621174720.1845040-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/core/rtnetlink.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 41de3a2f29e1..7776611a14ae 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -4090,7 +4090,7 @@ static int nlmsg_populate_fdb_fill(struct sk_buff *skb, ndm->ndm_ifindex = dev->ifindex; ndm->ndm_state = ndm_state; - if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr)) + if (nla_put(skb, NDA_LLADDR, dev->addr_len, addr)) goto nla_put_failure; if (vid) if (nla_put(skb, NDA_VLAN, sizeof(u16), &vid)) @@ -4104,10 +4104,10 @@ nla_put_failure: return -EMSGSIZE; } -static inline size_t rtnl_fdb_nlmsg_size(void) +static inline size_t rtnl_fdb_nlmsg_size(const struct net_device *dev) { return NLMSG_ALIGN(sizeof(struct ndmsg)) + - nla_total_size(ETH_ALEN) + /* NDA_LLADDR */ + nla_total_size(dev->addr_len) + /* NDA_LLADDR */ nla_total_size(sizeof(u16)) + /* NDA_VLAN */ 0; } @@ -4119,7 +4119,7 @@ static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, u16 vid, int type, struct sk_buff *skb; int err = -ENOBUFS; - skb = nlmsg_new(rtnl_fdb_nlmsg_size(), GFP_ATOMIC); + skb = nlmsg_new(rtnl_fdb_nlmsg_size(dev), GFP_ATOMIC); if (!skb) goto errout; -- cgit v1.2.3 From b028813ac97370e61351b1190c1860a1bd24fe56 Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Thu, 22 Jun 2023 01:26:25 +0000 Subject: i40e, xsk: fix comment typo Spell "transmission" properly. Found by searching for keyword "tranm". Signed-off-by: Yueh-Shun Li Link: https://lore.kernel.org/r/20230622012627.15050-3-shamrocklee@posteo.net Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/i40e/i40e_xsk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c index cd7b52fb6b46..05ec1181471e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c +++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c @@ -582,7 +582,7 @@ static void i40e_clean_xdp_tx_buffer(struct i40e_ring *tx_ring, * @vsi: Current VSI * @tx_ring: XDP Tx ring * - * Returns true if cleanup/tranmission is done. + * Returns true if cleanup/transmission is done. **/ bool i40e_clean_xdp_tx_irq(struct i40e_vsi *vsi, struct i40e_ring *tx_ring) { -- cgit v1.2.3 From 304b1875ba02022f2504952a32e5e90482bbdb39 Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Thu, 22 Jun 2023 01:26:31 +0000 Subject: tcp: fix comment typo Spell "transmissions" properly. Found by searching for keyword "tranm". Signed-off-by: Yueh-Shun Li Link: https://lore.kernel.org/r/20230622012627.15050-6-shamrocklee@posteo.net Signed-off-by: Jakub Kicinski --- net/ipv4/tcp_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bf8b22218dd4..6f072095211e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2867,7 +2867,7 @@ static void tcp_process_loss(struct sock *sk, int flag, int num_dupack, } if (tcp_is_reno(tp)) { /* A Reno DUPACK means new data in F-RTO step 2.b above are - * delivered. Lower inflight to clock out (re)tranmissions. + * delivered. Lower inflight to clock out (re)transmissions. */ if (after(tp->snd_nxt, tp->high_seq) && num_dupack) tcp_add_reno_sack(sk, num_dupack, flag & FLAG_ECE); -- cgit v1.2.3 From a0e128ef88e4a033a52963ec4ad94d96a17f8179 Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Thu, 22 Jun 2023 01:26:33 +0000 Subject: net/tls: fix comment typo Spell "retransmit" properly. Found by searching for keyword "tranm". Signed-off-by: Yueh-Shun Li Link: https://lore.kernel.org/r/20230622012627.15050-7-shamrocklee@posteo.net Signed-off-by: Jakub Kicinski --- net/tls/tls_device_fallback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tls/tls_device_fallback.c b/net/tls/tls_device_fallback.c index 7fbb1d0b69b3..b28c5e296dfd 100644 --- a/net/tls/tls_device_fallback.c +++ b/net/tls/tls_device_fallback.c @@ -271,7 +271,7 @@ static int fill_sg_in(struct scatterlist *sg_in, * There is a corner case where the packet contains * both an acked and a non-acked record. * We currently don't handle that case and rely - * on TCP to retranmit a packet that doesn't contain + * on TCP to retransmit a packet that doesn't contain * already acked payload. */ if (!is_start_marker) -- cgit v1.2.3 From f99d471afa03f770149f1cc60a288b9a08285903 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:06:22 +0100 Subject: net: phylink: add PCS negotiation mode PCS have to work out whether they should enable PCS negotiation by looking at the "mode" and "interface" arguments, and the Autoneg bit in the advertising mask. This leads to some complex logic, so lets pull that out into phylink and instead pass a "neg_mode" argument to the PCS configuration and link up methods, instead of the "mode" argument. In order to transition drivers, add a "neg_mode" flag to the phylink PCS structure to PCS can indicate whether they want to be passed the neg_mode or the old mode argument. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8De-00EaFA-Ht@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 45 +++++++++++++++----- include/linux/phylink.h | 104 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 17 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 97c15e1f81de..5d8f8b84908c 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -71,6 +71,7 @@ struct phylink { struct mutex state_mutex; struct phylink_link_state phy_state; struct work_struct resolve; + unsigned int pcs_neg_mode; bool mac_link_dropped; bool using_mac_select_pcs; @@ -992,23 +993,23 @@ static void phylink_resolve_an_pause(struct phylink_link_state *state) } } -static int phylink_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, const struct phylink_link_state *state, bool permit_pause_to_mac) { if (!pcs) return 0; - return pcs->ops->pcs_config(pcs, mode, state->interface, + return pcs->ops->pcs_config(pcs, neg_mode, state->interface, state->advertising, permit_pause_to_mac); } -static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +static void phylink_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex) { if (pcs && pcs->ops->pcs_link_up) - pcs->ops->pcs_link_up(pcs, mode, interface, speed, duplex); + pcs->ops->pcs_link_up(pcs, neg_mode, interface, speed, duplex); } static void phylink_pcs_poll_stop(struct phylink *pl) @@ -1058,10 +1059,15 @@ static void phylink_major_config(struct phylink *pl, bool restart, struct phylink_pcs *pcs = NULL; bool pcs_changed = false; unsigned int rate_kbd; + unsigned int neg_mode; int err; phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); + pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode, + state->interface, + state->advertising); + if (pl->using_mac_select_pcs) { pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); if (IS_ERR(pcs)) { @@ -1094,9 +1100,12 @@ static void phylink_major_config(struct phylink *pl, bool restart, phylink_mac_config(pl, state); - err = phylink_pcs_config(pl->pcs, pl->cur_link_an_mode, state, - !!(pl->link_config.pause & - MLO_PAUSE_AN)); + neg_mode = pl->cur_link_an_mode; + if (pl->pcs && pl->pcs->neg_mode) + neg_mode = pl->pcs_neg_mode; + + err = phylink_pcs_config(pl->pcs, neg_mode, state, + !!(pl->link_config.pause & MLO_PAUSE_AN)); if (err < 0) phylink_err(pl, "pcs_config failed: %pe\n", ERR_PTR(err)); @@ -1131,6 +1140,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, */ static int phylink_change_inband_advert(struct phylink *pl) { + unsigned int neg_mode; int ret; if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) @@ -1149,12 +1159,20 @@ static int phylink_change_inband_advert(struct phylink *pl) __ETHTOOL_LINK_MODE_MASK_NBITS, pl->link_config.advertising, pl->link_config.pause); + /* Recompute the PCS neg mode */ + pl->pcs_neg_mode = phylink_pcs_neg_mode(pl->cur_link_an_mode, + pl->link_config.interface, + pl->link_config.advertising); + + neg_mode = pl->cur_link_an_mode; + if (pl->pcs->neg_mode) + neg_mode = pl->pcs_neg_mode; + /* Modern PCS-based method; update the advert at the PCS, and * restart negotiation if the pcs_config() helper indicates that * the programmed advertisement has changed. */ - ret = phylink_pcs_config(pl->pcs, pl->cur_link_an_mode, - &pl->link_config, + ret = phylink_pcs_config(pl->pcs, neg_mode, &pl->link_config, !!(pl->link_config.pause & MLO_PAUSE_AN)); if (ret < 0) return ret; @@ -1257,6 +1275,7 @@ static void phylink_link_up(struct phylink *pl, struct phylink_link_state link_state) { struct net_device *ndev = pl->netdev; + unsigned int neg_mode; int speed, duplex; bool rx_pause; @@ -1287,8 +1306,12 @@ static void phylink_link_up(struct phylink *pl, pl->cur_interface = link_state.interface; - phylink_pcs_link_up(pl->pcs, pl->cur_link_an_mode, pl->cur_interface, - speed, duplex); + neg_mode = pl->cur_link_an_mode; + if (pl->pcs && pl->pcs->neg_mode) + neg_mode = pl->pcs_neg_mode; + + phylink_pcs_link_up(pl->pcs, neg_mode, pl->cur_interface, speed, + duplex); pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode, pl->cur_interface, speed, duplex, diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 0cf07d7d11b8..2b322d7fa51a 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -21,6 +21,24 @@ enum { MLO_AN_FIXED, /* Fixed-link mode */ MLO_AN_INBAND, /* In-band protocol */ + /* PCS "negotiation" mode. + * PHYLINK_PCS_NEG_NONE - protocol has no inband capability + * PHYLINK_PCS_NEG_OUTBAND - some out of band or fixed link setting + * PHYLINK_PCS_NEG_INBAND_DISABLED - inband mode disabled, e.g. + * 1000base-X with autoneg off + * PHYLINK_PCS_NEG_INBAND_ENABLED - inband mode enabled + * Additionally, this can be tested using bitmasks: + * PHYLINK_PCS_NEG_INBAND - inband mode selected + * PHYLINK_PCS_NEG_ENABLED - negotiation mode enabled + */ + PHYLINK_PCS_NEG_NONE = 0, + PHYLINK_PCS_NEG_ENABLED = BIT(4), + PHYLINK_PCS_NEG_OUTBAND = BIT(5), + PHYLINK_PCS_NEG_INBAND = BIT(6), + PHYLINK_PCS_NEG_INBAND_DISABLED = PHYLINK_PCS_NEG_INBAND, + PHYLINK_PCS_NEG_INBAND_ENABLED = PHYLINK_PCS_NEG_INBAND | + PHYLINK_PCS_NEG_ENABLED, + /* MAC_SYM_PAUSE and MAC_ASYM_PAUSE are used when configuring our * autonegotiation advertisement. They correspond to the PAUSE and * ASM_DIR bits defined by 802.3, respectively. @@ -79,6 +97,70 @@ static inline bool phylink_autoneg_inband(unsigned int mode) return mode == MLO_AN_INBAND; } +/** + * phylink_pcs_neg_mode() - helper to determine PCS inband mode + * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND. + * @interface: interface mode to be used + * @advertising: adertisement ethtool link mode mask + * + * Determines the negotiation mode to be used by the PCS, and returns + * one of: + * %PHYLINK_PCS_NEG_NONE: interface mode does not support inband + * %PHYLINK_PCS_NEG_OUTBAND: an out of band mode (e.g. reading the PHY) + * will be used. + * %PHYLINK_PCS_NEG_INBAND_DISABLED: inband mode selected but autoneg disabled + * %PHYLINK_PCS_NEG_INBAND_ENABLED: inband mode selected and autoneg enabled + * + * Note: this is for cases where the PCS itself is involved in negotiation + * (e.g. Clause 37, SGMII and similar) not Clause 73. + */ +static inline unsigned int phylink_pcs_neg_mode(unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising) +{ + unsigned int neg_mode; + + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + case PHY_INTERFACE_MODE_QUSGMII: + case PHY_INTERFACE_MODE_USXGMII: + /* These protocols are designed for use with a PHY which + * communicates its negotiation result back to the MAC via + * inband communication. Note: there exist PHYs that run + * with SGMII but do not send the inband data. + */ + if (!phylink_autoneg_inband(mode)) + neg_mode = PHYLINK_PCS_NEG_OUTBAND; + else + neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + break; + + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + /* 1000base-X is designed for use media-side for Fibre + * connections, and thus the Autoneg bit needs to be + * taken into account. We also do this for 2500base-X + * as well, but drivers may not support this, so may + * need to override this. + */ + if (!phylink_autoneg_inband(mode)) + neg_mode = PHYLINK_PCS_NEG_OUTBAND; + else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + advertising)) + neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; + else + neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED; + break; + + default: + neg_mode = PHYLINK_PCS_NEG_NONE; + break; + } + + return neg_mode; +} + /** * struct phylink_link_state - link state structure * @advertising: ethtool bitmask containing advertised link modes @@ -436,6 +518,7 @@ struct phylink_pcs_ops; /** * struct phylink_pcs - PHYLINK PCS instance * @ops: a pointer to the &struct phylink_pcs_ops structure + * @neg_mode: provide PCS neg mode via "mode" argument * @poll: poll the PCS for link changes * * This structure is designed to be embedded within the PCS private data, @@ -443,6 +526,7 @@ struct phylink_pcs_ops; */ struct phylink_pcs { const struct phylink_pcs_ops *ops; + bool neg_mode; bool poll; }; @@ -460,12 +544,12 @@ struct phylink_pcs_ops { const struct phylink_link_state *state); void (*pcs_get_state)(struct phylink_pcs *pcs, struct phylink_link_state *state); - int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode, + int (*pcs_config)(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac); void (*pcs_an_restart)(struct phylink_pcs *pcs); - void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int mode, + void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex); }; @@ -508,7 +592,7 @@ void pcs_get_state(struct phylink_pcs *pcs, /** * pcs_config() - Configure the PCS mode and advertisement * @pcs: a pointer to a &struct phylink_pcs. - * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND. + * @neg_mode: link negotiation mode (see below) * @interface: interface mode to be used * @advertising: adertisement ethtool link mode mask * @permit_pause_to_mac: permit forwarding pause resolution to MAC @@ -526,8 +610,12 @@ void pcs_get_state(struct phylink_pcs *pcs, * For 1000BASE-X, the advertisement should be programmed into the PCS. * * For most 10GBASE-R, there is no advertisement. + * + * The %neg_mode argument should be tested via the phylink_mode_*() family of + * functions, or for PCS that set pcs->neg_mode true, should be tested + * against the %PHYLINK_PCS_NEG_* definitions. */ -int pcs_config(struct phylink_pcs *pcs, unsigned int mode, +int pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac); @@ -543,7 +631,7 @@ void pcs_an_restart(struct phylink_pcs *pcs); /** * pcs_link_up() - program the PCS for the resolved link configuration * @pcs: a pointer to a &struct phylink_pcs. - * @mode: link autonegotiation mode + * @neg_mode: link negotiation mode (see below) * @interface: link &typedef phy_interface_t mode * @speed: link speed * @duplex: link duplex @@ -552,8 +640,12 @@ void pcs_an_restart(struct phylink_pcs *pcs); * the resolved link parameters. For example, a PCS operating in SGMII * mode without in-band AN needs to be manually configured for the link * and duplex setting. Otherwise, this should be a no-op. + * + * The %mode argument should be tested via the phylink_mode_*() family of + * functions, or for PCS that set pcs->neg_mode true, should be tested + * against the %PHYLINK_PCS_NEG_* definitions. */ -void pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +void pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex); #endif -- cgit v1.2.3 From cdb08aa0473730315dbc088d5394e59622314034 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:06:27 +0100 Subject: net: phylink: convert phylink_mii_c22_pcs_config() to neg_mode Use phylink_pcs_neg_mode() for phylink_mii_c22_pcs_config(). This results in no functional change. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8Dj-00EaFG-Mt@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/phy/phylink.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 5d8f8b84908c..567fd22a8924 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -3558,6 +3558,7 @@ int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, phy_interface_t interface, const unsigned long *advertising) { + unsigned int neg_mode; bool changed = 0; u16 bmcr; int ret, adv; @@ -3571,15 +3572,13 @@ int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, changed = ret; } - /* Ensure ISOLATE bit is disabled */ - if (mode == MLO_AN_INBAND && - (interface == PHY_INTERFACE_MODE_SGMII || - interface == PHY_INTERFACE_MODE_QSGMII || - linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising))) + neg_mode = phylink_pcs_neg_mode(mode, interface, advertising); + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) bmcr = BMCR_ANENABLE; else bmcr = 0; + /* Configure the inband state. Ensure ISOLATE bit is disabled */ ret = mdiodev_modify(pcs, MII_BMCR, BMCR_ANENABLE | BMCR_ISOLATE, bmcr); if (ret < 0) return ret; -- cgit v1.2.3 From febf2aaf05641f3258cc30e072aff65cffc7c82c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:06:32 +0100 Subject: net: phylink: pass neg_mode into phylink_mii_c22_pcs_config() Convert fman_dtsec, xilinx_axienet and pcs-lynx to pass the neg_mode into phylink_mii_c22_pcs_config(). Where appropriate, drivers are updated to have neg_mode passed into their pcs_config() and pcs_link_up() functions. For other drivers, we just hoist the call to phylink_pcs_neg_mode() to their pcs_config() method out of phylink_mii_c22_pcs_config(). Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8Do-00EaFM-Ra@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/fman/fman_dtsec.c | 7 ++++--- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 6 ++++-- drivers/net/pcs/pcs-lynx.c | 18 ++++++++++++------ drivers/net/phy/phylink.c | 9 ++++----- include/linux/phylink.h | 5 +++-- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c index d528ca681b6f..3088da7adf0f 100644 --- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c +++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c @@ -763,15 +763,15 @@ static void dtsec_pcs_get_state(struct phylink_pcs *pcs, phylink_mii_c22_pcs_get_state(dtsec->tbidev, state); } -static int dtsec_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int dtsec_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) { struct fman_mac *dtsec = pcs_to_dtsec(pcs); - return phylink_mii_c22_pcs_config(dtsec->tbidev, mode, interface, - advertising); + return phylink_mii_c22_pcs_config(dtsec->tbidev, interface, + advertising, neg_mode); } static void dtsec_pcs_an_restart(struct phylink_pcs *pcs) @@ -1447,6 +1447,7 @@ int dtsec_initialization(struct mac_device *mac_dev, goto _return_fm_mac_free; } dtsec->pcs.ops = &dtsec_pcs_ops; + dtsec->pcs.neg_mode = true; dtsec->pcs.poll = true; supported = mac_dev->phylink_config.supported_interfaces; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 3e310b55bce2..ae7b9af7b7d7 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1631,7 +1631,7 @@ static void axienet_pcs_an_restart(struct phylink_pcs *pcs) phylink_mii_c22_pcs_an_restart(pcs_phy); } -static int axienet_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int axienet_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -1653,7 +1653,8 @@ static int axienet_pcs_config(struct phylink_pcs *pcs, unsigned int mode, } } - ret = phylink_mii_c22_pcs_config(pcs_phy, mode, interface, advertising); + ret = phylink_mii_c22_pcs_config(pcs_phy, interface, advertising, + neg_mode); if (ret < 0) netdev_warn(ndev, "Failed to configure PCS: %d\n", ret); @@ -2129,6 +2130,7 @@ static int axienet_probe(struct platform_device *pdev) } of_node_put(np); lp->pcs.ops = &axienet_pcs_ops; + lp->pcs.neg_mode = true; lp->pcs.poll = true; } diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index fca48ebf0b81..25bd4b45eb7b 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -112,9 +112,10 @@ static void lynx_pcs_get_state(struct phylink_pcs *pcs, state->link, state->an_complete); } -static int lynx_pcs_config_giga(struct mdio_device *pcs, unsigned int mode, +static int lynx_pcs_config_giga(struct mdio_device *pcs, phy_interface_t interface, - const unsigned long *advertising) + const unsigned long *advertising, + unsigned int neg_mode) { int link_timer_ns; u32 link_timer; @@ -132,8 +133,9 @@ static int lynx_pcs_config_giga(struct mdio_device *pcs, unsigned int mode, if (interface == PHY_INTERFACE_MODE_1000BASEX) { if_mode = 0; } else { + /* SGMII and QSGMII */ if_mode = IF_MODE_SGMII_EN; - if (mode == MLO_AN_INBAND) + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) if_mode |= IF_MODE_USE_SGMII_AN; } @@ -143,7 +145,8 @@ static int lynx_pcs_config_giga(struct mdio_device *pcs, unsigned int mode, if (err) return err; - return phylink_mii_c22_pcs_config(pcs, mode, interface, advertising); + return phylink_mii_c22_pcs_config(pcs, interface, advertising, + neg_mode); } static int lynx_pcs_config_usxgmii(struct mdio_device *pcs, unsigned int mode, @@ -170,13 +173,16 @@ static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int mode, bool permit) { struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); + unsigned int neg_mode; + + neg_mode = phylink_pcs_neg_mode(mode, ifmode, advertising); switch (ifmode) { case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_QSGMII: - return lynx_pcs_config_giga(lynx->mdio, mode, ifmode, - advertising); + return lynx_pcs_config_giga(lynx->mdio, ifmode, advertising, + neg_mode); case PHY_INTERFACE_MODE_2500BASEX: if (phylink_autoneg_inband(mode)) { dev_err(&lynx->mdio->dev, diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 567fd22a8924..d0aaa5cad853 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -3545,20 +3545,20 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement); /** * phylink_mii_c22_pcs_config() - configure clause 22 PCS * @pcs: a pointer to a &struct mdio_device. - * @mode: link autonegotiation mode * @interface: the PHY interface mode being configured * @advertising: the ethtool advertisement mask + * @neg_mode: PCS negotiation mode * * Configure a Clause 22 PCS PHY with the appropriate negotiation * parameters for the @mode, @interface and @advertising parameters. * Returns negative error number on failure, zero if the advertisement * has not changed, or positive if there is a change. */ -int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, +int phylink_mii_c22_pcs_config(struct mdio_device *pcs, phy_interface_t interface, - const unsigned long *advertising) + const unsigned long *advertising, + unsigned int neg_mode) { - unsigned int neg_mode; bool changed = 0; u16 bmcr; int ret, adv; @@ -3572,7 +3572,6 @@ int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, changed = ret; } - neg_mode = phylink_pcs_neg_mode(mode, interface, advertising); if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) bmcr = BMCR_ANENABLE; else diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 2b322d7fa51a..516240f1e950 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -743,9 +743,10 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, struct phylink_link_state *state); int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, const unsigned long *advertising); -int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, +int phylink_mii_c22_pcs_config(struct mdio_device *pcs, phy_interface_t interface, - const unsigned long *advertising); + const unsigned long *advertising, + unsigned int neg_mode); void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs); void phylink_resolve_c73(struct phylink_link_state *state); -- cgit v1.2.3 From a3a47cfb88fcdf862594eae417611ef533ed8bae Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:06:37 +0100 Subject: net: pcs: xpcs: update PCS driver to use neg_mode Update xpcs to use neg_mode to configure whether inband negotiation should be used. We need to update sja1105 as well as that directly calls into the XPCS driver's config function. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8Dt-00EaFS-W9@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/dsa/sja1105/sja1105_main.c | 14 +++++------ drivers/net/pcs/pcs-xpcs.c | 43 ++++++++++++++++++---------------- include/linux/pcs/pcs-xpcs.h | 4 ++-- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index b70dcf32a26d..a55a6436fc05 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2314,7 +2314,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv, for (i = 0; i < ds->num_ports; i++) { struct dw_xpcs *xpcs = priv->xpcs[i]; - unsigned int mode; + unsigned int neg_mode; rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]); if (rc < 0) @@ -2324,17 +2324,15 @@ int sja1105_static_config_reload(struct sja1105_private *priv, continue; if (bmcr[i] & BMCR_ANENABLE) - mode = MLO_AN_INBAND; - else if (priv->fixed_link[i]) - mode = MLO_AN_FIXED; + neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED; else - mode = MLO_AN_PHY; + neg_mode = PHYLINK_PCS_NEG_OUTBAND; - rc = xpcs_do_config(xpcs, priv->phy_mode[i], mode, NULL); + rc = xpcs_do_config(xpcs, priv->phy_mode[i], NULL, neg_mode); if (rc < 0) goto out; - if (!phylink_autoneg_inband(mode)) { + if (neg_mode == PHYLINK_PCS_NEG_OUTBAND) { int speed = SPEED_UNKNOWN; if (priv->phy_mode[i] == PHY_INTERFACE_MODE_2500BASEX) @@ -2346,7 +2344,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv, else speed = SPEED_10; - xpcs_link_up(&xpcs->pcs, mode, priv->phy_mode[i], + xpcs_link_up(&xpcs->pcs, neg_mode, priv->phy_mode[i], speed, DUPLEX_FULL); } } diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index e4e59aa9faf7..44b037646865 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -657,7 +657,8 @@ int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable) } EXPORT_SYMBOL_GPL(xpcs_config_eee); -static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode) +static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, + unsigned int neg_mode) { int ret, mdio_ctrl; @@ -707,7 +708,7 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode) if (ret < 0) return ret; - if (phylink_autoneg_inband(mode)) + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; else ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; @@ -716,14 +717,15 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode) if (ret < 0) return ret; - if (phylink_autoneg_inband(mode)) + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, mdio_ctrl | AN_CL37_EN); return ret; } -static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, unsigned int mode, +static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, + unsigned int neg_mode, const unsigned long *advertising) { phy_interface_t interface = PHY_INTERFACE_MODE_1000BASEX; @@ -774,8 +776,7 @@ static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, unsigned int mod if (ret < 0) return ret; - if (phylink_autoneg_inband(mode) && - linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) { + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, mdio_ctrl | AN_CL37_EN); if (ret < 0) @@ -808,7 +809,7 @@ static int xpcs_config_2500basex(struct dw_xpcs *xpcs) } int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, - unsigned int mode, const unsigned long *advertising) + const unsigned long *advertising, unsigned int neg_mode) { const struct xpcs_compat *compat; int ret; @@ -821,19 +822,19 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, case DW_10GBASER: break; case DW_AN_C73: - if (test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) { + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { ret = xpcs_config_aneg_c73(xpcs, compat); if (ret) return ret; } break; case DW_AN_C37_SGMII: - ret = xpcs_config_aneg_c37_sgmii(xpcs, mode); + ret = xpcs_config_aneg_c37_sgmii(xpcs, neg_mode); if (ret) return ret; break; case DW_AN_C37_1000BASEX: - ret = xpcs_config_aneg_c37_1000basex(xpcs, mode, + ret = xpcs_config_aneg_c37_1000basex(xpcs, neg_mode, advertising); if (ret) return ret; @@ -857,14 +858,14 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, } EXPORT_SYMBOL_GPL(xpcs_do_config); -static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int xpcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); - return xpcs_do_config(xpcs, interface, mode, advertising); + return xpcs_do_config(xpcs, interface, advertising, neg_mode); } static int xpcs_get_state_c73(struct dw_xpcs *xpcs, @@ -898,7 +899,8 @@ static int xpcs_get_state_c73(struct dw_xpcs *xpcs, state->link = 0; - return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND, NULL); + return xpcs_do_config(xpcs, state->interface, NULL, + PHYLINK_PCS_NEG_INBAND_ENABLED); } /* There is no point doing anything else if the link is down. */ @@ -1046,12 +1048,12 @@ static void xpcs_get_state(struct phylink_pcs *pcs, } } -static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode, +static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int neg_mode, int speed, int duplex) { int val, ret; - if (phylink_autoneg_inband(mode)) + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) return; val = mii_bmcr_encode_fixed(speed, duplex); @@ -1060,12 +1062,12 @@ static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode, pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret)); } -static void xpcs_link_up_1000basex(struct dw_xpcs *xpcs, unsigned int mode, +static void xpcs_link_up_1000basex(struct dw_xpcs *xpcs, unsigned int neg_mode, int speed, int duplex) { int val, ret; - if (phylink_autoneg_inband(mode)) + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) return; switch (speed) { @@ -1089,7 +1091,7 @@ static void xpcs_link_up_1000basex(struct dw_xpcs *xpcs, unsigned int mode, pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret)); } -void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex) { struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs); @@ -1097,9 +1099,9 @@ void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode, if (interface == PHY_INTERFACE_MODE_USXGMII) return xpcs_config_usxgmii(xpcs, speed); if (interface == PHY_INTERFACE_MODE_SGMII) - return xpcs_link_up_sgmii(xpcs, mode, speed, duplex); + return xpcs_link_up_sgmii(xpcs, neg_mode, speed, duplex); if (interface == PHY_INTERFACE_MODE_1000BASEX) - return xpcs_link_up_1000basex(xpcs, mode, speed, duplex); + return xpcs_link_up_1000basex(xpcs, neg_mode, speed, duplex); } EXPORT_SYMBOL_GPL(xpcs_link_up); @@ -1283,6 +1285,7 @@ static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, } xpcs->pcs.ops = &xpcs_phylink_ops; + xpcs->pcs.neg_mode = true; if (compat->an_mode == DW_10GBASER) return xpcs; diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index ec8175b847cc..ff99cf7a5d0d 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -29,10 +29,10 @@ struct dw_xpcs { }; int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface); -void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex); int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, - unsigned int mode, const unsigned long *advertising); + const unsigned long *advertising, unsigned int neg_mode); void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces); int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable); -- cgit v1.2.3 From 3b2de56a146f34e3f70a84cc3a1897064e445d16 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:06:43 +0100 Subject: net: pcs: lynxi: update PCS driver to use neg_mode Update the Lynxi PCS driver to use neg_mode rather than the mode argument. This ensures that the link_up() method will always program the speed and duplex when negotiation is disabled. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8Dz-00EaFY-5A@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-mtk-lynxi.c | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 888452325edc..b0f3ede945d9 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -102,13 +102,13 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, FIELD_GET(SGMII_LPA, adv)); } -static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode, +static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) { struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); - bool mode_changed = false, changed, use_an; + bool mode_changed = false, changed; unsigned int rgc3, sgm_mode, bmcr; int advertise, link_timer; @@ -121,30 +121,21 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode, * we assume that fixes it's speed at bitrate = line rate (in * other words, 1000Mbps or 2500Mbps). */ - if (interface == PHY_INTERFACE_MODE_SGMII) { + if (interface == PHY_INTERFACE_MODE_SGMII) sgm_mode = SGMII_IF_MODE_SGMII; - if (phylink_autoneg_inband(mode)) { - sgm_mode |= SGMII_REMOTE_FAULT_DIS | - SGMII_SPEED_DUPLEX_AN; - use_an = true; - } else { - use_an = false; - } - } else if (phylink_autoneg_inband(mode)) { - /* 1000base-X or 2500base-X autoneg */ - sgm_mode = SGMII_REMOTE_FAULT_DIS; - use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - advertising); - } else { - /* 1000base-X or 2500base-X without autoneg */ + else sgm_mode = 0; - use_an = false; - } - if (use_an) + if (neg_mode & PHYLINK_PCS_NEG_INBAND) + sgm_mode |= SGMII_REMOTE_FAULT_DIS; + + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { + if (interface == PHY_INTERFACE_MODE_SGMII) + sgm_mode |= SGMII_SPEED_DUPLEX_AN; bmcr = BMCR_ANENABLE; - else + } else { bmcr = 0; + } if (mpcs->interface != interface) { link_timer = phylink_get_link_timer_ns(interface); @@ -216,14 +207,15 @@ static void mtk_pcs_lynxi_restart_an(struct phylink_pcs *pcs) regmap_set_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, BMCR_ANRESTART); } -static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, unsigned int mode, +static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, + unsigned int neg_mode, phy_interface_t interface, int speed, int duplex) { struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); unsigned int sgm_mode; - if (!phylink_autoneg_inband(mode)) { + if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) { /* Force the speed and duplex setting */ if (speed == SPEED_10) sgm_mode = SGMII_SPEED_10; @@ -286,6 +278,7 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, mpcs->regmap = regmap; mpcs->flags = flags; mpcs->pcs.ops = &mtk_pcs_lynxi_ops; + mpcs->pcs.neg_mode = true; mpcs->pcs.poll = true; mpcs->interface = PHY_INTERFACE_MODE_NA; -- cgit v1.2.3 From c689a6528c22b20565bd14d5a7fb8e827d6faa7c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:06:48 +0100 Subject: net: pcs: lynx: update PCS driver to use neg_mode Update the Lynx PCS driver to use neg_mode rather than the mode argument. This ensures that the link_up() method will always program the speed and duplex when negotiation is disabled. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8E4-00EaFf-Bf@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-lynx.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index 25bd4b45eb7b..9021b96d4f9d 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -149,13 +149,14 @@ static int lynx_pcs_config_giga(struct mdio_device *pcs, neg_mode); } -static int lynx_pcs_config_usxgmii(struct mdio_device *pcs, unsigned int mode, - const unsigned long *advertising) +static int lynx_pcs_config_usxgmii(struct mdio_device *pcs, + const unsigned long *advertising, + unsigned int neg_mode) { struct mii_bus *bus = pcs->bus; int addr = pcs->addr; - if (!phylink_autoneg_inband(mode)) { + if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) { dev_err(&pcs->dev, "USXGMII only supports in-band AN for now\n"); return -EOPNOTSUPP; } @@ -167,15 +168,11 @@ static int lynx_pcs_config_usxgmii(struct mdio_device *pcs, unsigned int mode, ADVERTISE_SGMII | ADVERTISE_LPACK); } -static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t ifmode, - const unsigned long *advertising, - bool permit) + const unsigned long *advertising, bool permit) { struct lynx_pcs *lynx = phylink_pcs_to_lynx(pcs); - unsigned int neg_mode; - - neg_mode = phylink_pcs_neg_mode(mode, ifmode, advertising); switch (ifmode) { case PHY_INTERFACE_MODE_1000BASEX: @@ -184,14 +181,15 @@ static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int mode, return lynx_pcs_config_giga(lynx->mdio, ifmode, advertising, neg_mode); case PHY_INTERFACE_MODE_2500BASEX: - if (phylink_autoneg_inband(mode)) { + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { dev_err(&lynx->mdio->dev, "AN not supported on 3.125GHz SerDes lane\n"); return -EOPNOTSUPP; } break; case PHY_INTERFACE_MODE_USXGMII: - return lynx_pcs_config_usxgmii(lynx->mdio, mode, advertising); + return lynx_pcs_config_usxgmii(lynx->mdio, advertising, + neg_mode); case PHY_INTERFACE_MODE_10GBASER: /* Nothing to do here for 10GBASER */ break; @@ -209,7 +207,8 @@ static void lynx_pcs_an_restart(struct phylink_pcs *pcs) phylink_mii_c22_pcs_an_restart(lynx->mdio); } -static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, unsigned int mode, +static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, + unsigned int neg_mode, int speed, int duplex) { u16 if_mode = 0, sgmii_speed; @@ -217,7 +216,7 @@ static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, unsigned int mode, /* The PCS needs to be configured manually only * when not operating on in-band mode */ - if (mode == MLO_AN_INBAND) + if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED) return; if (duplex == DUPLEX_HALF) @@ -264,12 +263,12 @@ static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, unsigned int mode, * 2500 Mbps and we do rate adaptation through pause frames. */ static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs, - unsigned int mode, + unsigned int neg_mode, int speed, int duplex) { u16 if_mode = 0; - if (mode == MLO_AN_INBAND) { + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { dev_err(&pcs->dev, "AN not supported for 2500BaseX\n"); return; } @@ -283,7 +282,7 @@ static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs, if_mode); } -static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex) { @@ -292,10 +291,10 @@ static void lynx_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, switch (interface) { case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_QSGMII: - lynx_pcs_link_up_sgmii(lynx->mdio, mode, speed, duplex); + lynx_pcs_link_up_sgmii(lynx->mdio, neg_mode, speed, duplex); break; case PHY_INTERFACE_MODE_2500BASEX: - lynx_pcs_link_up_2500basex(lynx->mdio, mode, speed, duplex); + lynx_pcs_link_up_2500basex(lynx->mdio, neg_mode, speed, duplex); break; case PHY_INTERFACE_MODE_USXGMII: /* At the moment, only in-band AN is supported for USXGMII @@ -325,6 +324,7 @@ static struct phylink_pcs *lynx_pcs_create(struct mdio_device *mdio) mdio_device_get(mdio); lynx->mdio = mdio; lynx->pcs.ops = &lynx_pcs_phylink_ops; + lynx->pcs.neg_mode = true; lynx->pcs.poll = true; return lynx_to_phylink_pcs(lynx); -- cgit v1.2.3 From a0e93cfdac4c91b73f79a4bfbfcf74b0911c1ad3 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:06:53 +0100 Subject: net: lan966x: update PCS driver to use neg_mode Update lan966x's embedded PCS driver to use neg_mode rather than the mode argument. As there is no pcs_link_up() method, this only affects the pcs_config() method. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8E9-00EaFl-GN@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan966x/lan966x_main.c | 1 + drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c index f6931dfb3e68..fbb0bb4594cd 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_main.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_main.c @@ -818,6 +818,7 @@ static int lan966x_probe_port(struct lan966x *lan966x, u32 p, port->phylink_config.type = PHYLINK_NETDEV; port->phylink_pcs.poll = true; port->phylink_pcs.ops = &lan966x_phylink_pcs_ops; + port->phylink_pcs.neg_mode = true; port->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD; diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c b/drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c index c5f9803e6e63..1d63903f9006 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_phylink.c @@ -95,8 +95,7 @@ static void lan966x_pcs_get_state(struct phylink_pcs *pcs, lan966x_port_status_get(port, state); } -static int lan966x_pcs_config(struct phylink_pcs *pcs, - unsigned int mode, +static int lan966x_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -107,8 +106,8 @@ static int lan966x_pcs_config(struct phylink_pcs *pcs, config = port->config; config.portmode = interface; - config.inband = phylink_autoneg_inband(mode); - config.autoneg = phylink_test(advertising, Autoneg); + config.inband = neg_mode & PHYLINK_PCS_NEG_INBAND; + config.autoneg = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED; config.advertising = advertising; ret = lan966x_port_pcs_set(port, &config); -- cgit v1.2.3 From 140d1002e2a30db0df58d18c07df3f72dc0659fa Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:06:58 +0100 Subject: net: mvneta: update PCS driver to use neg_mode Update mvneta's embedded PCS driver to use neg_mode rather than the mode argument. As there is no pcs_link_up() method, this only affects the pcs_config() method. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8EE-00EaFr-Kx@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/mvneta.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index e2abc00d0472..ff5647bcdfca 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -4002,8 +4002,8 @@ static void mvneta_pcs_get_state(struct phylink_pcs *pcs, state->pause |= MLO_PAUSE_TX; } -static int mvneta_pcs_config(struct phylink_pcs *pcs, - unsigned int mode, phy_interface_t interface, +static int mvneta_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) { @@ -4016,7 +4016,7 @@ static int mvneta_pcs_config(struct phylink_pcs *pcs, MVNETA_GMAC_AN_FLOW_CTRL_EN | MVNETA_GMAC_AN_DUPLEX_EN; - if (phylink_autoneg_inband(mode)) { + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { mask |= MVNETA_GMAC_CONFIG_MII_SPEED | MVNETA_GMAC_CONFIG_GMII_SPEED | MVNETA_GMAC_CONFIG_FULL_DUPLEX; @@ -5518,6 +5518,7 @@ static int mvneta_probe(struct platform_device *pdev) clk_prepare_enable(pp->clk_bus); pp->phylink_pcs.ops = &mvneta_phylink_pcs_ops; + pp->phylink_pcs.neg_mode = true; pp->phylink_config.dev = &dev->dev; pp->phylink_config.type = PHYLINK_NETDEV; -- cgit v1.2.3 From d5b16264fffe1e6a9ccad7b1cf311ea2fd5e2e79 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:07:03 +0100 Subject: net: mvpp2: update PCS driver to use neg_mode Update mvpp2's embedded PCS drivers to use neg_mode rather than the mode argument, remembering to update the ACPI path as well. As there are no pcs_link_up() methods, this only affects the two pcs_config() methods. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8EJ-00EaFx-P6@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index adc953611913..1fec84b4c068 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -6168,8 +6168,7 @@ static void mvpp2_xlg_pcs_get_state(struct phylink_pcs *pcs, state->pause |= MLO_PAUSE_RX; } -static int mvpp2_xlg_pcs_config(struct phylink_pcs *pcs, - unsigned int mode, +static int mvpp2_xlg_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -6232,7 +6231,7 @@ static void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs, state->pause |= MLO_PAUSE_TX; } -static int mvpp2_gmac_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int mvpp2_gmac_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -6246,7 +6245,7 @@ static int mvpp2_gmac_pcs_config(struct phylink_pcs *pcs, unsigned int mode, MVPP2_GMAC_FLOW_CTRL_AUTONEG | MVPP2_GMAC_AN_DUPLEX_EN; - if (phylink_autoneg_inband(mode)) { + if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) { mask |= MVPP2_GMAC_CONFIG_MII_SPEED | MVPP2_GMAC_CONFIG_GMII_SPEED | MVPP2_GMAC_CONFIG_FULL_DUPLEX; @@ -6649,8 +6648,9 @@ static void mvpp2_acpi_start(struct mvpp2_port *port) mvpp2_mac_prepare(&port->phylink_config, MLO_AN_INBAND, port->phy_interface); mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state); - pcs->ops->pcs_config(pcs, MLO_AN_INBAND, port->phy_interface, - state.advertising, false); + pcs->ops->pcs_config(pcs, PHYLINK_PCS_NEG_INBAND_ENABLED, + port->phy_interface, state.advertising, + false); mvpp2_mac_finish(&port->phylink_config, MLO_AN_INBAND, port->phy_interface); mvpp2_mac_link_up(&port->phylink_config, NULL, @@ -6896,7 +6896,9 @@ static int mvpp2_port_probe(struct platform_device *pdev, dev->dev.of_node = port_node; port->pcs_gmac.ops = &mvpp2_phylink_gmac_pcs_ops; + port->pcs_gmac.neg_mode = true; port->pcs_xlg.ops = &mvpp2_phylink_xlg_pcs_ops; + port->pcs_xlg.neg_mode = true; if (!mvpp2_use_acpi_compat_mode(port_fwnode)) { port->phylink_config.dev = &dev->dev; -- cgit v1.2.3 From d5a05299306227d73b0febba9cecedf88931c507 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:07:08 +0100 Subject: net: prestera: update PCS driver to use neg_mode Update prestera's embedded PCS driver to use neg_mode rather than the mode argument. As there is no pcs_link_up() method, this only affects the pcs_config() method. Acked-by: Elad Nachman Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8EO-00EaG3-TR@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/prestera/prestera_main.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c index 9d504142e51a..4fb886c57cd7 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_main.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c @@ -300,8 +300,7 @@ static void prestera_pcs_get_state(struct phylink_pcs *pcs, } } -static int prestera_pcs_config(struct phylink_pcs *pcs, - unsigned int mode, +static int prestera_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -316,30 +315,25 @@ static int prestera_pcs_config(struct phylink_pcs *pcs, cfg_mac.admin = true; cfg_mac.fec = PRESTERA_PORT_FEC_OFF; + cfg_mac.inband = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED; switch (interface) { case PHY_INTERFACE_MODE_10GBASER: cfg_mac.speed = SPEED_10000; - cfg_mac.inband = 0; cfg_mac.mode = PRESTERA_MAC_MODE_SR_LR; break; case PHY_INTERFACE_MODE_2500BASEX: cfg_mac.speed = SPEED_2500; cfg_mac.duplex = DUPLEX_FULL; - cfg_mac.inband = test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - advertising); cfg_mac.mode = PRESTERA_MAC_MODE_SGMII; break; case PHY_INTERFACE_MODE_SGMII: - cfg_mac.inband = 1; cfg_mac.mode = PRESTERA_MAC_MODE_SGMII; break; case PHY_INTERFACE_MODE_1000BASEX: default: cfg_mac.speed = SPEED_1000; cfg_mac.duplex = DUPLEX_FULL; - cfg_mac.inband = test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - advertising); cfg_mac.mode = PRESTERA_MAC_MODE_1000BASE_X; break; } @@ -401,6 +395,7 @@ static int prestera_port_sfp_bind(struct prestera_port *port) continue; port->phylink_pcs.ops = &prestera_pcs_ops; + port->phylink_pcs.neg_mode = true; port->phy_config.dev = &port->dev->dev; port->phy_config.type = PHYLINK_NETDEV; -- cgit v1.2.3 From bfa0a3ac05b69842aaee7c60a8ceffd734f2e2b9 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:07:14 +0100 Subject: net: qca8k: update PCS driver to use neg_mode Update qca8k's embedded PCS driver to use neg_mode rather than the mode argument. As there is no pcs_link_up() method, this only affects the pcs_config() method. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8EU-00EaG9-1l@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/dsa/qca/qca8k-8xxx.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c index dee7b6579916..f7d7cfb2fd86 100644 --- a/drivers/net/dsa/qca/qca8k-8xxx.c +++ b/drivers/net/dsa/qca/qca8k-8xxx.c @@ -1493,7 +1493,7 @@ static void qca8k_pcs_get_state(struct phylink_pcs *pcs, state->pause |= MLO_PAUSE_TX; } -static int qca8k_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int qca8k_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -1520,14 +1520,12 @@ static int qca8k_pcs_config(struct phylink_pcs *pcs, unsigned int mode, } /* Enable/disable SerDes auto-negotiation as necessary */ - ret = qca8k_read(priv, QCA8K_REG_PWS, &val); + val = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED ? + 0 : QCA8K_PWS_SERDES_AEN_DIS; + + ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8K_PWS_SERDES_AEN_DIS, val); if (ret) return ret; - if (phylink_autoneg_inband(mode)) - val &= ~QCA8K_PWS_SERDES_AEN_DIS; - else - val |= QCA8K_PWS_SERDES_AEN_DIS; - qca8k_write(priv, QCA8K_REG_PWS, val); /* Configure the SGMII parameters */ ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); @@ -1598,6 +1596,7 @@ static void qca8k_setup_pcs(struct qca8k_priv *priv, struct qca8k_pcs *qpcs, int port) { qpcs->pcs.ops = &qca8k_pcs_ops; + qpcs->pcs.neg_mode = true; /* We don't have interrupts for link changes, so we need to poll */ qpcs->pcs.poll = true; -- cgit v1.2.3 From 6e5bb3da9842950a161625b4ab2743d1d5c64715 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:07:19 +0100 Subject: net: sparx5: update PCS driver to use neg_mode Update Sparx5's embedded PCS driver to use neg_mode rather than the mode argument. As there is no pcs_link_up() method, this only affects the pcs_config() method. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8EZ-00EaGF-6F@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/sparx5/sparx5_main.c | 1 + drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c index a7edf524eedb..dc9af480bfea 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c @@ -281,6 +281,7 @@ static int sparx5_create_port(struct sparx5 *sparx5, spx5_port->custom_etype = 0x8880; /* Vitesse */ spx5_port->phylink_pcs.poll = true; spx5_port->phylink_pcs.ops = &sparx5_phylink_pcs_ops; + spx5_port->phylink_pcs.neg_mode = true; spx5_port->is_mrouter = false; INIT_LIST_HEAD(&spx5_port->tc_templates); sparx5->ports[config->portno] = spx5_port; diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c b/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c index bb97d27a1da4..f8562c1a894d 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c @@ -91,8 +91,7 @@ static void sparx5_pcs_get_state(struct phylink_pcs *pcs, state->pause = status.pause; } -static int sparx5_pcs_config(struct phylink_pcs *pcs, - unsigned int mode, +static int sparx5_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -104,8 +103,9 @@ static int sparx5_pcs_config(struct phylink_pcs *pcs, conf = port->conf; conf.power_down = false; conf.portmode = interface; - conf.inband = phylink_autoneg_inband(mode); - conf.autoneg = phylink_test(advertising, Autoneg); + conf.inband = neg_mode == PHYLINK_PCS_NEG_INBAND_DISABLED || + neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED; + conf.autoneg = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED; conf.pause_adv = 0; if (phylink_test(advertising, Pause)) conf.pause_adv |= ADVERTISE_1000XPAUSE; -- cgit v1.2.3 From 772c476dd1d43546ac8123c9a7060557d06dfe7c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:07:24 +0100 Subject: net: dsa: b53: update PCS driver to use neg_mode Update B53's embedded PCS driver to use neg_mode, even though it makes no use of it or the "mode" argument. This makes the driver consistent with converted drivers. Signed-off-by: Russell King (Oracle) Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/E1qA8Ee-00EaGL-Az@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_serdes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/b53/b53_serdes.c b/drivers/net/dsa/b53/b53_serdes.c index 0690210770ff..b0ccebcd3ffa 100644 --- a/drivers/net/dsa/b53/b53_serdes.c +++ b/drivers/net/dsa/b53/b53_serdes.c @@ -65,7 +65,7 @@ static u16 b53_serdes_read(struct b53_device *dev, u8 lane, return b53_serdes_read_blk(dev, offset, block); } -static int b53_serdes_config(struct phylink_pcs *pcs, unsigned int mode, +static int b53_serdes_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -239,6 +239,7 @@ int b53_serdes_init(struct b53_device *dev, int port) pcs->dev = dev; pcs->lane = lane; pcs->pcs.ops = &b53_pcs_ops; + pcs->pcs.neg_mode = true; return 0; } -- cgit v1.2.3 From 6c1e4eca0b4e4ec6a67a10e69cc0d936d0d9c19c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:07:29 +0100 Subject: net: dsa: mt7530: update PCS driver to use neg_mode Update mt7530's embedded PCS driver to use neg_mode, even though it makes no use of it or the "mode" argument. This makes the driver consistent with converted drivers. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8Ej-00EaGR-Fk@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mt7530.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 7e773c4ba046..38b3c6dda386 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -3005,7 +3005,7 @@ static void mt7530_pcs_get_state(struct phylink_pcs *pcs, state->pause |= MLO_PAUSE_TX; } -static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -3033,6 +3033,7 @@ mt753x_setup(struct dsa_switch *ds) /* Initialise the PCS devices */ for (i = 0; i < priv->ds->num_ports; i++) { priv->pcs[i].pcs.ops = priv->info->pcs_ops; + priv->pcs[i].pcs.neg_mode = true; priv->pcs[i].priv = priv; priv->pcs[i].port = i; } -- cgit v1.2.3 From f40df95d375dc9c96da541a2c4ac0ce1e630309d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 16 Jun 2023 13:07:34 +0100 Subject: net: macb: update PCS driver to use neg_mode Update macb's embedded PCS drivers to use neg_mode, even though it makes no use of it or the "mode" argument. This makes the driver consistent with converted drivers. Signed-off-by: Russell King (Oracle) Link: https://lore.kernel.org/r/E1qA8Eo-00EaGX-KJ@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/cadence/macb_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 2e35e200fdcb..f6a0f12a6d52 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -563,7 +563,7 @@ static void macb_set_tx_clk(struct macb *bp, int speed) netdev_err(bp->dev, "adjusting tx_clk failed.\n"); } -static void macb_usx_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +static void macb_usx_pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, phy_interface_t interface, int speed, int duplex) { @@ -596,7 +596,7 @@ static void macb_usx_pcs_get_state(struct phylink_pcs *pcs, } static int macb_usx_pcs_config(struct phylink_pcs *pcs, - unsigned int mode, + unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -621,7 +621,7 @@ static void macb_pcs_an_restart(struct phylink_pcs *pcs) } static int macb_pcs_config(struct phylink_pcs *pcs, - unsigned int mode, + unsigned int neg_mode, phy_interface_t interface, const unsigned long *advertising, bool permit_pause_to_mac) @@ -862,7 +862,9 @@ static int macb_mii_probe(struct net_device *dev) struct macb *bp = netdev_priv(dev); bp->phylink_sgmii_pcs.ops = &macb_phylink_pcs_ops; + bp->phylink_sgmii_pcs.neg_mode = true; bp->phylink_usx_pcs.ops = &macb_phylink_usx_pcs_ops; + bp->phylink_usx_pcs.neg_mode = true; bp->phylink_config.dev = &dev->dev; bp->phylink_config.type = PHYLINK_NETDEV; -- cgit v1.2.3 From fc0649395dca81f2b3b02d9b248acb38cbcee55c Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 21 Jun 2023 06:38:48 +0200 Subject: net: phy: dp83td510: fix kernel stall during netboot in DP83TD510E PHY driver Fix an issue where the kernel would stall during netboot, showing the "sched: RT throttling activated" message. This stall was triggered by the behavior of the mii_interrupt bit (Bit 7 - DP83TD510E_STS_MII_INT) in the DP83TD510E's PHY_STS Register (Address = 0x10). The DP83TD510E datasheet (2020) states that the bit clears on write, however, in practice, the bit clears on read. This discrepancy had significant implications on the driver's interrupt handling. The PHY_STS Register was used by handle_interrupt() to check for pending interrupts and by read_status() to get the current link status. The call to read_status() was unintentionally clearing the mii_interrupt status bit without deasserting the IRQ pin, causing handle_interrupt() to miss other pending interrupts. This issue was most apparent during netboot. The fix refrains from using the PHY_STS Register for interrupt handling. Instead, we now solely rely on the INTERRUPT_REG_1 Register (Address = 0x12) and INTERRUPT_REG_2 Register (Address = 0x13) for this purpose. These registers directly influence the IRQ pin state and are latched high until read. Note: The INTERRUPT_REG_2 Register (Address = 0x13) exists and can also be used for interrupt handling, specifically for "Aneg page received interrupt" and "Polarity change interrupt". However, these features are currently not supported by this driver. Fixes: 165cd04fe253 ("net: phy: dp83td510: Add support for the DP83TD510 Ethernet PHY") Cc: Signed-off-by: Oleksij Rempel Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230621043848.3806124-1-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski --- drivers/net/phy/dp83td510.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/drivers/net/phy/dp83td510.c b/drivers/net/phy/dp83td510.c index 3cd9a77f9532..d7616b13c594 100644 --- a/drivers/net/phy/dp83td510.c +++ b/drivers/net/phy/dp83td510.c @@ -12,6 +12,11 @@ /* MDIO_MMD_VEND2 registers */ #define DP83TD510E_PHY_STS 0x10 +/* Bit 7 - mii_interrupt, active high. Clears on read. + * Note: Clearing does not necessarily deactivate IRQ pin if interrupts pending. + * This differs from the DP83TD510E datasheet (2020) which states this bit + * clears on write 0. + */ #define DP83TD510E_STS_MII_INT BIT(7) #define DP83TD510E_LINK_STATUS BIT(0) @@ -53,12 +58,6 @@ static int dp83td510_config_intr(struct phy_device *phydev) int ret; if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { - /* Clear any pending interrupts */ - ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS, - 0x0); - if (ret) - return ret; - ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_INTERRUPT_REG_1, DP83TD510E_INT1_LINK_EN); @@ -81,10 +80,6 @@ static int dp83td510_config_intr(struct phy_device *phydev) DP83TD510E_GENCFG_INT_EN); if (ret) return ret; - - /* Clear any pending interrupts */ - ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS, - 0x0); } return ret; @@ -94,14 +89,6 @@ static irqreturn_t dp83td510_handle_interrupt(struct phy_device *phydev) { int ret; - ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS); - if (ret < 0) { - phy_error(phydev); - return IRQ_NONE; - } else if (!(ret & DP83TD510E_STS_MII_INT)) { - return IRQ_NONE; - } - /* Read the current enabled interrupts */ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_INTERRUPT_REG_1); if (ret < 0) { -- cgit v1.2.3 From 2a441a3dbe84be61be502142a2fb8ea633fcc528 Mon Sep 17 00:00:00 2001 From: Zhengchao Shao Date: Tue, 20 Jun 2023 14:25:19 +0800 Subject: net: txgbe: remove unused buffer in txgbe_calc_eeprom_checksum Half a year passed since commit 049fe5365324c ("net: txgbe: Add operations to interact with firmware") was submitted, the buffer in txgbe_calc_eeprom_checksum was not used. So remove it and the related branch codes. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202306200242.FXsHokaJ-lkp@intel.com/ Reviewed-by: Jiawen Wu Signed-off-by: Zhengchao Shao Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230620062519.1575298-1-shaozhengchao@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c | 32 +++++++++------------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c index ebc46f3be056..12405d71c5ee 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c @@ -160,34 +160,24 @@ int txgbe_read_pba_string(struct wx *wx, u8 *pba_num, u32 pba_num_size) static int txgbe_calc_eeprom_checksum(struct wx *wx, u16 *checksum) { u16 *eeprom_ptrs = NULL; - u32 buffer_size = 0; - u16 *buffer = NULL; u16 *local_buffer; int status; u16 i; wx_init_eeprom_params(wx); - if (!buffer) { - eeprom_ptrs = kvmalloc_array(TXGBE_EEPROM_LAST_WORD, sizeof(u16), - GFP_KERNEL); - if (!eeprom_ptrs) - return -ENOMEM; - /* Read pointer area */ - status = wx_read_ee_hostif_buffer(wx, 0, - TXGBE_EEPROM_LAST_WORD, - eeprom_ptrs); - if (status != 0) { - wx_err(wx, "Failed to read EEPROM image\n"); - kvfree(eeprom_ptrs); - return status; - } - local_buffer = eeprom_ptrs; - } else { - if (buffer_size < TXGBE_EEPROM_LAST_WORD) - return -EFAULT; - local_buffer = buffer; + eeprom_ptrs = kvmalloc_array(TXGBE_EEPROM_LAST_WORD, sizeof(u16), + GFP_KERNEL); + if (!eeprom_ptrs) + return -ENOMEM; + /* Read pointer area */ + status = wx_read_ee_hostif_buffer(wx, 0, TXGBE_EEPROM_LAST_WORD, eeprom_ptrs); + if (status != 0) { + wx_err(wx, "Failed to read EEPROM image\n"); + kvfree(eeprom_ptrs); + return status; } + local_buffer = eeprom_ptrs; for (i = 0; i < TXGBE_EEPROM_LAST_WORD; i++) if (i != wx->eeprom.sw_region_offset + TXGBE_EEPROM_CHECKSUM) -- cgit v1.2.3 From 0c3d6fd4b89c1a6393283249cdd0bd484ad8f2e5 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2023 16:17:19 -0700 Subject: tools: ynl: improve the direct-include header guard logic Przemek suggests that I shouldn't accuse GCC of witchcraft, there is a simpler explanation for why we need manual define. scripts/headers_install.sh modifies the guard, removing _UAPI. That's why including a kernel header from the tree and from /usr leads to duplicate definitions. This also solves the mystery of why I needed to include the header conditionally. I had the wrong guards for most cases but ethtool. Suggested-by: Przemek Kitszel Reviewed-by: Przemek Kitszel Link: https://lore.kernel.org/r/20230621231719.2728928-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- tools/net/ynl/Makefile.deps | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps index 524fc4bb586b..f842bc66b967 100644 --- a/tools/net/ynl/Makefile.deps +++ b/tools/net/ynl/Makefile.deps @@ -9,20 +9,12 @@ UAPI_PATH:=../../../../include/uapi/ -# If the header does not exist at all in the system path - let the -# compiler fall back to the kernel header via -Idirafter. -# GCC seems to ignore header guard if the header is different, so we need -# to specify the -D$(hdr_guard). -# And we need to define HASH indirectly because GNU Make 4.2 wants it escaped -# and Gnu Make 4.4 wants it without escaping. +# scripts/headers_install.sh strips "_UAPI" from header guards so we +# need the explicit -D matching what's in /usr, to avoid multiple definitions. -HASH := \# +get_hdr_inc=-D$(1) -include $(UAPI_PATH)/linux/$(2) -get_hdr_inc=$(if $(shell echo "$(HASH)include " | \ - cpp >>/dev/null 2>/dev/null && echo yes),\ - -D$(1) -include $(UAPI_PATH)/linux/$(2)) - -CFLAGS_devlink:=$(call get_hdr_inc,_UAPI_LINUX_DEVLINK_H_,devlink.h) +CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h) CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) -CFLAGS_handshake:=$(call get_hdr_inc,_UAPI_LINUX_HANDSHAKE_H,handshake.h) -CFLAGS_netdev:=$(call get_hdr_inc,_UAPI_LINUX_NETDEV_H,netdev.h) +CFLAGS_handshake:=$(call get_hdr_inc,_LINUX_HANDSHAKE_H,handshake.h) +CFLAGS_netdev:=$(call get_hdr_inc,_LINUX_NETDEV_H,netdev.h) -- cgit v1.2.3 From 3b42fbd5951171bce5ecd22ad72d6a16fefaa704 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 20 Jun 2023 13:38:52 +0200 Subject: net: dsa: microchip: simplify ksz_prmw8() Implement ksz_prmw8() in terms of ksz_rmw8(), just as all the other ksz_pX are implemented in terms of ksz_X. No functional change. Signed-off-by: Rasmus Villemoes Reviewed-by: Simon Horman Acked-by: Arun Ramadoss Link: https://lore.kernel.org/r/20230620113855.733526-2-linux@rasmusvillemoes.dk Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.h | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index a66b56857ec6..2453c43c48a5 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -578,17 +578,8 @@ static inline int ksz_pwrite32(struct ksz_device *dev, int port, int offset, static inline int ksz_prmw8(struct ksz_device *dev, int port, int offset, u8 mask, u8 val) { - int ret; - - ret = regmap_update_bits(ksz_regmap_8(dev), - dev->dev_ops->get_port_addr(port, offset), - mask, val); - if (ret) - dev_err(dev->dev, "can't rmw 8bit reg 0x%x: %pe\n", - dev->dev_ops->get_port_addr(port, offset), - ERR_PTR(ret)); - - return ret; + return ksz_rmw8(dev, dev->dev_ops->get_port_addr(port, offset), + mask, val); } static inline void ksz_regmap_lock(void *__mtx) -- cgit v1.2.3 From ece28ecbec9f63e3f722d7c9a99fb965cbeafc1b Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 20 Jun 2023 13:38:53 +0200 Subject: net: dsa: microchip: add ksz_prmw32() helper This will be used in a subsequent patch fixing an errata for writes to certain PHY registers. Signed-off-by: Rasmus Villemoes Reviewed-by: Simon Horman Acked-by: Arun Ramadoss Link: https://lore.kernel.org/r/20230620113855.733526-3-linux@rasmusvillemoes.dk Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz_common.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 2453c43c48a5..28444e5924f9 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -582,6 +582,13 @@ static inline int ksz_prmw8(struct ksz_device *dev, int port, int offset, mask, val); } +static inline int ksz_prmw32(struct ksz_device *dev, int port, int offset, + u32 mask, u32 val) +{ + return ksz_rmw32(dev, dev->dev_ops->get_port_addr(port, offset), + mask, val); +} + static inline void ksz_regmap_lock(void *__mtx) { struct mutex *mtx = __mtx; -- cgit v1.2.3 From 5c844d57aa7894154e49cf2fc648bfe2f1aefc1c Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Tue, 20 Jun 2023 13:38:54 +0200 Subject: net: dsa: microchip: fix writes to phy registers >= 0x10 According to the errata sheets for ksz9477 and ksz9567, writes to the PHY registers 0x10-0x1f (i.e. those located at addresses 0xN120 to 0xN13f) must be done as a 32 bit write to the 4-byte aligned address containing the register, hence requires a RMW in order not to change the adjacent PHY register. Signed-off-by: Rasmus Villemoes Reviewed-by: Simon Horman Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230620113855.733526-4-linux@rasmusvillemoes.dk Signed-off-by: Jakub Kicinski --- drivers/net/dsa/microchip/ksz9477.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index fc5157a10af5..83b7f2d5c1ea 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -329,11 +329,27 @@ int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) { + u32 mask, val32; + /* No real PHY after this. */ if (!dev->info->internal_phy[addr]) return 0; - return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); + if (reg < 0x10) + return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); + + /* Errata: When using SPI, I2C, or in-band register access, + * writes to certain PHY registers should be performed as + * 32-bit writes instead of 16-bit writes. + */ + val32 = val; + mask = 0xffff; + if ((reg & 1) == 0) { + val32 <<= 16; + mask <<= 16; + } + reg &= ~1; + return ksz_prmw32(dev, addr, 0x100 + (reg << 1), mask, val32); } void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member) -- cgit v1.2.3 From 004d25060c78fc31f66da0fa439c544dda1ac9d5 Mon Sep 17 00:00:00 2001 From: Ying Hsu Date: Tue, 20 Jun 2023 10:47:32 -0700 Subject: igb: Fix igb_down hung on surprise removal In a setup where a Thunderbolt hub connects to Ethernet and a display through USB Type-C, users may experience a hung task timeout when they remove the cable between the PC and the Thunderbolt hub. This is because the igb_down function is called multiple times when the Thunderbolt hub is unplugged. For example, the igb_io_error_detected triggers the first call, and the igb_remove triggers the second call. The second call to igb_down will block at napi_synchronize. Here's the call trace: __schedule+0x3b0/0xddb ? __mod_timer+0x164/0x5d3 schedule+0x44/0xa8 schedule_timeout+0xb2/0x2a4 ? run_local_timers+0x4e/0x4e msleep+0x31/0x38 igb_down+0x12c/0x22a [igb 6615058754948bfde0bf01429257eb59f13030d4] __igb_close+0x6f/0x9c [igb 6615058754948bfde0bf01429257eb59f13030d4] igb_close+0x23/0x2b [igb 6615058754948bfde0bf01429257eb59f13030d4] __dev_close_many+0x95/0xec dev_close_many+0x6e/0x103 unregister_netdevice_many+0x105/0x5b1 unregister_netdevice_queue+0xc2/0x10d unregister_netdev+0x1c/0x23 igb_remove+0xa7/0x11c [igb 6615058754948bfde0bf01429257eb59f13030d4] pci_device_remove+0x3f/0x9c device_release_driver_internal+0xfe/0x1b4 pci_stop_bus_device+0x5b/0x7f pci_stop_bus_device+0x30/0x7f pci_stop_bus_device+0x30/0x7f pci_stop_and_remove_bus_device+0x12/0x19 pciehp_unconfigure_device+0x76/0xe9 pciehp_disable_slot+0x6e/0x131 pciehp_handle_presence_or_link_change+0x7a/0x3f7 pciehp_ist+0xbe/0x194 irq_thread_fn+0x22/0x4d ? irq_thread+0x1fd/0x1fd irq_thread+0x17b/0x1fd ? irq_forced_thread_fn+0x5f/0x5f kthread+0x142/0x153 ? __irq_get_irqchip_state+0x46/0x46 ? kthread_associate_blkcg+0x71/0x71 ret_from_fork+0x1f/0x30 In this case, igb_io_error_detected detaches the network interface and requests a PCIE slot reset, however, the PCIE reset callback is not being invoked and thus the Ethernet connection breaks down. As the PCIE error in this case is a non-fatal one, requesting a slot reset can be avoided. This patch fixes the task hung issue and preserves Ethernet connection by ignoring non-fatal PCIE errors. Signed-off-by: Ying Hsu Tested-by: Pucha Himasekhar Reddy (A Contingent worker at Intel) Signed-off-by: Tony Nguyen Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230620174732.4145155-1-anthony.l.nguyen@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/igb/igb_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 9fcac96022d7..9a2561409b06 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -9587,6 +9587,11 @@ static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev, struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); + if (state == pci_channel_io_normal) { + dev_warn(&pdev->dev, "Non-correctable non-fatal error reported.\n"); + return PCI_ERS_RESULT_CAN_RECOVER; + } + netif_device_detach(netdev); if (state == pci_channel_io_perm_failure) -- cgit v1.2.3 From 2ffb8d02a9b60d9190a871cb8466cd0721bc0a49 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 21 Jun 2023 11:26:53 +0200 Subject: docs: ABI: sysfs-class-led-trigger-netdev: add new modes and entry Document newly introduced modes and entry for the LED netdev trigger. Add documentation for new modes: - link_10 - link_100 - link_1000 - half_duplex - full_duplex Add documentation for new entry: - hw_control Also add additional info for the interval entry and the tx/rx modes with the special case of hw_control ON. Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230621092653.23172-1-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- .../ABI/testing/sysfs-class-led-trigger-netdev | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev index 646540950e38..78b62a23b14a 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev @@ -13,6 +13,11 @@ Description: Specifies the duration of the LED blink in milliseconds. Defaults to 50 ms. + With hw_control ON, the interval value MUST be set to the + default value and cannot be changed. + Trying to set any value in this specific mode will return + an EINVAL error. + What: /sys/class/leds//link Date: Dec 2017 KernelVersion: 4.16 @@ -39,6 +44,9 @@ Description: If set to 1, the LED will blink for the milliseconds specified in interval to signal transmission. + With hw_control ON, the blink interval is controlled by hardware + and won't reflect the value set in interval. + What: /sys/class/leds//rx Date: Dec 2017 KernelVersion: 4.16 @@ -50,3 +58,84 @@ Description: If set to 1, the LED will blink for the milliseconds specified in interval to signal reception. + + With hw_control ON, the blink interval is controlled by hardware + and won't reflect the value set in interval. + +What: /sys/class/leds//hw_control +Date: Jun 2023 +KernelVersion: 6.5 +Contact: linux-leds@vger.kernel.org +Description: + Communicate whether the LED trigger modes are driven by hardware + or software fallback is used. + + If 0, the LED is using software fallback to blink. + + If 1, the LED is using hardware control to blink and signal the + requested modes. + +What: /sys/class/leds//link_10 +Date: Jun 2023 +KernelVersion: 6.5 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 10Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 10MBps of the named network device. + Setting this value also immediately changes the LED state. + +What: /sys/class/leds//link_100 +Date: Jun 2023 +KernelVersion: 6.5 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 100Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 100Mbps of the named network device. + Setting this value also immediately changes the LED state. + +What: /sys/class/leds//link_1000 +Date: Jun 2023 +KernelVersion: 6.5 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 1000Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 1000Mbps of the named network device. + Setting this value also immediately changes the LED state. + +What: /sys/class/leds//half_duplex +Date: Jun 2023 +KernelVersion: 6.5 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link half duplex state of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link half + duplex state of the named network device. + Setting this value also immediately changes the LED state. + +What: /sys/class/leds//full_duplex +Date: Jun 2023 +KernelVersion: 6.5 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link full duplex state of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link full + duplex state of the named network device. + Setting this value also immediately changes the LED state. -- cgit v1.2.3 From 2555f35a4f428a9bfdf09aa0459dbfdf59a24a9a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 21 Jun 2023 11:54:09 +0200 Subject: net: dsa: qca8k: add support for additional modes for netdev trigger The QCA8K switch supports additional modes that can be handled in hardware for the LED netdev trigger. Add these additional modes to further support the Switch LEDs and offload more blink modes. Add additional modes: - link_10 - link_100 - link_1000 - half_duplex - full_duplex Signed-off-by: Christian Marangi Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20230621095409.25859-1-ansuelsmth@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/dsa/qca/qca8k-leds.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c index 6f02029b454b..1261e0bb21ef 100644 --- a/drivers/net/dsa/qca/qca8k-leds.c +++ b/drivers/net/dsa/qca/qca8k-leds.c @@ -68,6 +68,16 @@ qca8k_parse_netdev(unsigned long rules, u32 *offload_trigger) *offload_trigger |= QCA8K_LED_TX_BLINK_MASK; if (test_bit(TRIGGER_NETDEV_RX, &rules)) *offload_trigger |= QCA8K_LED_RX_BLINK_MASK; + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + *offload_trigger |= QCA8K_LED_LINK_10M_EN_MASK; + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + *offload_trigger |= QCA8K_LED_LINK_100M_EN_MASK; + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + *offload_trigger |= QCA8K_LED_LINK_1000M_EN_MASK; + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) + *offload_trigger |= QCA8K_LED_HALF_DUPLEX_MASK; + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) + *offload_trigger |= QCA8K_LED_FULL_DUPLEX_MASK; if (rules && !*offload_trigger) return -EOPNOTSUPP; @@ -322,6 +332,16 @@ qca8k_cled_hw_control_get(struct led_classdev *ldev, unsigned long *rules) set_bit(TRIGGER_NETDEV_TX, rules); if (val & QCA8K_LED_RX_BLINK_MASK) set_bit(TRIGGER_NETDEV_RX, rules); + if (val & QCA8K_LED_LINK_10M_EN_MASK) + set_bit(TRIGGER_NETDEV_LINK_10, rules); + if (val & QCA8K_LED_LINK_100M_EN_MASK) + set_bit(TRIGGER_NETDEV_LINK_100, rules); + if (val & QCA8K_LED_LINK_1000M_EN_MASK) + set_bit(TRIGGER_NETDEV_LINK_1000, rules); + if (val & QCA8K_LED_HALF_DUPLEX_MASK) + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); + if (val & QCA8K_LED_FULL_DUPLEX_MASK) + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); return 0; } -- cgit v1.2.3 From 9a14f2e3dab106df7f27d1730cc540247317d4b9 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Wed, 21 Jun 2023 13:15:04 +0100 Subject: sfc: keep alive neighbour entries while a TC encap action is using them When processing counter updates, if any action set using the newly incremented counter includes an encap action, prod the corresponding neighbouring entry to indicate to the neighbour cache that the entry is still in use and passing traffic. Signed-off-by: Edward Cree Link: https://lore.kernel.org/r/20230621121504.17004-1-edward.cree@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/tc.c | 20 +++++++++++- drivers/net/ethernet/sfc/tc.h | 1 + drivers/net/ethernet/sfc/tc_counters.c | 58 ++++++++++++++++++++++++++++++++++ drivers/net/ethernet/sfc/tc_counters.h | 3 ++ 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 77acdb60381e..15ebd3973922 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -110,8 +110,13 @@ static void efx_tc_free_action_set(struct efx_nic *efx, */ list_del(&act->list); } - if (act->count) + if (act->count) { + spin_lock_bh(&act->count->cnt->lock); + if (!list_empty(&act->count_user)) + list_del(&act->count_user); + spin_unlock_bh(&act->count->cnt->lock); efx_tc_flower_put_counter_index(efx, act->count); + } if (act->encap_md) { list_del(&act->encap_user); efx_tc_flower_release_encap_md(efx, act->encap_md); @@ -796,6 +801,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx, goto release; } act->count = ctr; + INIT_LIST_HEAD(&act->count_user); } if (!efx_tc_flower_action_order_ok(act, EFX_TC_AO_DELIVER)) { @@ -1083,6 +1089,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx, goto release; } act->count = ctr; + INIT_LIST_HEAD(&act->count_user); } switch (fa->id) { @@ -1120,6 +1127,17 @@ static int efx_tc_flower_replace(struct efx_nic *efx, list_add_tail(&act->encap_user, &encap->users); act->dest_mport = encap->dest_mport; act->deliver = 1; + if (act->count && !WARN_ON(!act->count->cnt)) { + /* This counter is used by an encap + * action, which needs a reference back + * so it can prod neighbouring whenever + * traffic is seen. + */ + spin_lock_bh(&act->count->cnt->lock); + list_add_tail(&act->count_user, + &act->count->cnt->users); + spin_unlock_bh(&act->count->cnt->lock); + } rc = efx_mae_alloc_action_set(efx, act); if (rc) { NL_SET_ERR_MSG_MOD(extack, "Failed to write action set to hw (encap)"); diff --git a/drivers/net/ethernet/sfc/tc.h b/drivers/net/ethernet/sfc/tc.h index 607429f8bb28..1549c3df43bb 100644 --- a/drivers/net/ethernet/sfc/tc.h +++ b/drivers/net/ethernet/sfc/tc.h @@ -38,6 +38,7 @@ struct efx_tc_action_set { struct efx_tc_encap_action *encap_md; /* entry in tc_encap_ht table */ struct list_head encap_user; /* entry on encap_md->users list */ struct efx_tc_action_set_list *user; /* Only populated if encap_md */ + struct list_head count_user; /* entry on counter->users list, if encap */ u32 dest_mport; u32 fw_id; /* index of this entry in firmware actions table */ struct list_head list; diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c index d1a91d54c6bb..979f49058a0c 100644 --- a/drivers/net/ethernet/sfc/tc_counters.c +++ b/drivers/net/ethernet/sfc/tc_counters.c @@ -9,6 +9,7 @@ */ #include "tc_counters.h" +#include "tc_encap_actions.h" #include "mae_counter_format.h" #include "mae.h" #include "rx_common.h" @@ -31,6 +32,15 @@ static void efx_tc_counter_free(void *ptr, void *__unused) { struct efx_tc_counter *cnt = ptr; + WARN_ON(!list_empty(&cnt->users)); + /* We'd like to synchronize_rcu() here, but unfortunately we aren't + * removing the element from the hashtable (it's not clear that's a + * safe thing to do in an rhashtable_free_and_destroy free_fn), so + * threads could still be obtaining new pointers to *cnt if they can + * race against this function at all. + */ + flush_work(&cnt->work); + EFX_WARN_ON_PARANOID(spin_is_locked(&cnt->lock)); kfree(cnt); } @@ -74,6 +84,49 @@ void efx_tc_fini_counters(struct efx_nic *efx) rhashtable_free_and_destroy(&efx->tc->counter_ht, efx_tc_counter_free, NULL); } +static void efx_tc_counter_work(struct work_struct *work) +{ + struct efx_tc_counter *cnt = container_of(work, struct efx_tc_counter, work); + struct efx_tc_encap_action *encap; + struct efx_tc_action_set *act; + unsigned long touched; + struct neighbour *n; + + spin_lock_bh(&cnt->lock); + touched = READ_ONCE(cnt->touched); + + list_for_each_entry(act, &cnt->users, count_user) { + encap = act->encap_md; + if (!encap) + continue; + if (!encap->neigh) /* can't happen */ + continue; + if (time_after_eq(encap->neigh->used, touched)) + continue; + encap->neigh->used = touched; + /* We have passed traffic using this ARP entry, so + * indicate to the ARP cache that it's still active + */ + if (encap->neigh->dst_ip) + n = neigh_lookup(&arp_tbl, &encap->neigh->dst_ip, + encap->neigh->egdev); + else +#if IS_ENABLED(CONFIG_IPV6) + n = neigh_lookup(ipv6_stub->nd_tbl, + &encap->neigh->dst_ip6, + encap->neigh->egdev); +#else + n = NULL; +#endif + if (!n) + continue; + + neigh_event_send(n, NULL); + neigh_release(n); + } + spin_unlock_bh(&cnt->lock); +} + /* Counter allocation */ static struct efx_tc_counter *efx_tc_flower_allocate_counter(struct efx_nic *efx, @@ -87,12 +140,14 @@ static struct efx_tc_counter *efx_tc_flower_allocate_counter(struct efx_nic *efx return ERR_PTR(-ENOMEM); spin_lock_init(&cnt->lock); + INIT_WORK(&cnt->work, efx_tc_counter_work); cnt->touched = jiffies; cnt->type = type; rc = efx_mae_allocate_counter(efx, cnt); if (rc) goto fail1; + INIT_LIST_HEAD(&cnt->users); rc = rhashtable_insert_fast(&efx->tc->counter_ht, &cnt->linkage, efx_tc_counter_ht_params); if (rc) @@ -126,6 +181,7 @@ static void efx_tc_flower_release_counter(struct efx_nic *efx, netif_warn(efx, hw, efx->net_dev, "Failed to free MAE counter %u, rc %d\n", cnt->fw_id, rc); + WARN_ON(!list_empty(&cnt->users)); /* This doesn't protect counter updates coming in arbitrarily long * after we deleted the counter. The RCU just ensures that we won't * free the counter while another thread has a pointer to it. @@ -133,6 +189,7 @@ static void efx_tc_flower_release_counter(struct efx_nic *efx, * is handled by the generation count. */ synchronize_rcu(); + flush_work(&cnt->work); EFX_WARN_ON_PARANOID(spin_is_locked(&cnt->lock)); kfree(cnt); } @@ -302,6 +359,7 @@ static void efx_tc_counter_update(struct efx_nic *efx, cnt->touched = jiffies; } spin_unlock_bh(&cnt->lock); + schedule_work(&cnt->work); out: rcu_read_unlock(); } diff --git a/drivers/net/ethernet/sfc/tc_counters.h b/drivers/net/ethernet/sfc/tc_counters.h index 8fc7c4bbb29c..41e57f34b763 100644 --- a/drivers/net/ethernet/sfc/tc_counters.h +++ b/drivers/net/ethernet/sfc/tc_counters.h @@ -32,6 +32,9 @@ struct efx_tc_counter { u64 old_packets, old_bytes; /* Values last time passed to userspace */ /* jiffies of the last time we saw packets increase */ unsigned long touched; + struct work_struct work; /* For notifying encap actions */ + /* owners of corresponding count actions */ + struct list_head users; }; struct efx_tc_counter_index { -- cgit v1.2.3 From 0ec92a8f56ff07237dbe8af7c7a72aba7f957baf Mon Sep 17 00:00:00 2001 From: Piotr Gardocki Date: Wed, 21 Jun 2023 15:21:06 +0200 Subject: net: fix net device address assign type Commit ad72c4a06acc introduced optimization to return from function quickly if the MAC address is not changing at all. It was reported that such change causes dev->addr_assign_type to not change to NET_ADDR_SET from _PERM or _RANDOM. Restore the old behavior and skip only call to ndo_set_mac_address. Fixes: ad72c4a06acc ("net: add check for current MAC address in dev_set_mac_address") Reported-by: Gal Pressman Signed-off-by: Piotr Gardocki Reviewed-by: Simon Horman Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/20230621132106.991342-1-piotrx.gardocki@intel.com Signed-off-by: Jakub Kicinski --- net/core/dev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index e4ff0adf5523..69a3e544676c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8781,14 +8781,14 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa, return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; - if (!memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) - return 0; err = dev_pre_changeaddr_notify(dev, sa->sa_data, extack); if (err) return err; - err = ops->ndo_set_mac_address(dev, sa); - if (err) - return err; + if (memcmp(dev->dev_addr, sa->sa_data, dev->addr_len)) { + err = ops->ndo_set_mac_address(dev, sa); + if (err) + return err; + } dev->addr_assign_type = NET_ADDR_SET; call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); add_device_randomness(dev->dev_addr, dev->addr_len); -- cgit v1.2.3 From 9b476494da1aad70f4f083e853eb817bcb292d08 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Wed, 21 Jun 2023 20:33:07 +0800 Subject: net: hns3: refine the tcam key convert handle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The result of expression '(k ^ ~v) & k' is exactly the same with 'k & v', so simplify it. (k ^ ~v) & k == k & v The truth table (in non table form): k == 0, v == 0: (k ^ ~v) & k == (0 ^ ~0) & 0 == (0 ^ 1) & 0 == 1 & 0 == 0 k & v == 0 & 0 == 0 k == 0, v == 1: (k ^ ~v) & k == (0 ^ ~1) & 0 == (0 ^ 0) & 0 == 1 & 0 == 0 k & v == 0 & 1 == 0 k == 1, v == 0: (k ^ ~v) & k == (1 ^ ~0) & 1 == (1 ^ 1) & 1 == 0 & 1 == 0 k & v == 1 & 0 == 0 k == 1, v == 1: (k ^ ~v) & k == (1 ^ ~1) & 1 == (1 ^ 0) & 1 == 1 & 1 == 1 k & v == 1 & 1 == 1 Signed-off-by: Jian Shen Signed-off-by: Hao Lan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 81aa6b0facf5..6a43d1515585 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -835,15 +835,10 @@ struct hclge_vf_vlan_cfg { * Then for input key(k) and mask(v), we can calculate the value by * the formulae: * x = (~k) & v - * y = (k ^ ~v) & k + * y = k & v */ -#define calc_x(x, k, v) (x = ~(k) & (v)) -#define calc_y(y, k, v) \ - do { \ - const typeof(k) _k_ = (k); \ - const typeof(v) _v_ = (v); \ - (y) = (_k_ ^ ~_v_) & (_k_); \ - } while (0) +#define calc_x(x, k, v) ((x) = ~(k) & (v)) +#define calc_y(y, k, v) ((y) = (k) & (v)) #define HCLGE_MAC_STATS_FIELD_OFF(f) (offsetof(struct hclge_mac_stats, f)) #define HCLGE_STATS_READ(p, offset) (*(u64 *)((u8 *)(p) + (offset))) -- cgit v1.2.3 From 1cf3d5567f273a8746d1bade00633a93204f80f0 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Wed, 21 Jun 2023 20:33:08 +0800 Subject: net: hns3: fix strncpy() not using dest-buf length as length issue Now, strncpy() in hns3_dbg_fill_content() use src-length as copy-length, it may result in dest-buf overflow. This patch is to fix intel compile warning for csky-linux-gcc (GCC) 12.1.0 compiler. The warning reports as below: hclge_debugfs.c:92:25: warning: 'strncpy' specified bound depends on the length of the source argument [-Wstringop-truncation] strncpy(pos, items[i].name, strlen(items[i].name)); hclge_debugfs.c:90:25: warning: 'strncpy' output truncated before terminating nul copying as many bytes from a string as its length [-Wstringop-truncation] strncpy(pos, result[i], strlen(result[i])); strncpy() use src-length as copy-length, it may result in dest-buf overflow. So,this patch add some values check to avoid this issue. Signed-off-by: Hao Chen Reported-by: kernel test robot Closes: https://lore.kernel.org/lkml/202207170606.7WtHs9yS-lkp@intel.com/T/ Signed-off-by: Hao Lan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c | 31 +++++++++++++++++----- .../ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c | 29 ++++++++++++++++---- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index d385ffc21876..32bb14303473 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -438,19 +438,36 @@ static void hns3_dbg_fill_content(char *content, u16 len, const struct hns3_dbg_item *items, const char **result, u16 size) { +#define HNS3_DBG_LINE_END_LEN 2 char *pos = content; + u16 item_len; u16 i; + if (!len) { + return; + } else if (len <= HNS3_DBG_LINE_END_LEN) { + *pos++ = '\0'; + return; + } + memset(content, ' ', len); - for (i = 0; i < size; i++) { - if (result) - strncpy(pos, result[i], strlen(result[i])); - else - strncpy(pos, items[i].name, strlen(items[i].name)); + len -= HNS3_DBG_LINE_END_LEN; - pos += strlen(items[i].name) + items[i].interval; + for (i = 0; i < size; i++) { + item_len = strlen(items[i].name) + items[i].interval; + if (len < item_len) + break; + + if (result) { + if (item_len < strlen(result[i])) + break; + strscpy(pos, result[i], strlen(result[i])); + } else { + strscpy(pos, items[i].name, strlen(items[i].name)); + } + pos += item_len; + len -= item_len; } - *pos++ = '\n'; *pos++ = '\0'; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index a0b46e7d863e..233c132dc513 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -88,16 +88,35 @@ static void hclge_dbg_fill_content(char *content, u16 len, const struct hclge_dbg_item *items, const char **result, u16 size) { +#define HCLGE_DBG_LINE_END_LEN 2 char *pos = content; + u16 item_len; u16 i; + if (!len) { + return; + } else if (len <= HCLGE_DBG_LINE_END_LEN) { + *pos++ = '\0'; + return; + } + memset(content, ' ', len); + len -= HCLGE_DBG_LINE_END_LEN; + for (i = 0; i < size; i++) { - if (result) - strncpy(pos, result[i], strlen(result[i])); - else - strncpy(pos, items[i].name, strlen(items[i].name)); - pos += strlen(items[i].name) + items[i].interval; + item_len = strlen(items[i].name) + items[i].interval; + if (len < item_len) + break; + + if (result) { + if (item_len < strlen(result[i])) + break; + strscpy(pos, result[i], strlen(result[i])); + } else { + strscpy(pos, items[i].name, strlen(items[i].name)); + } + pos += item_len; + len -= item_len; } *pos++ = '\n'; *pos++ = '\0'; -- cgit v1.2.3 From ed1c6f35b73ec9249c07ebbd300423155c7baac3 Mon Sep 17 00:00:00 2001 From: Peiyang Wang Date: Wed, 21 Jun 2023 20:33:09 +0800 Subject: net: hns3: clear hns unused parameter alarm Several functions in the hns3 driver have unused parameters. The compiler will warn about them when building with -Wunused-parameter option of hns3. Signed-off-by: Peiyang Wang Signed-off-by: Hao Lan Signed-off-by: Paolo Abeni --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 3 +- .../hisilicon/hns3/hns3_common/hclge_comm_rss.c | 3 +- .../hisilicon/hns3/hns3_common/hclge_comm_rss.h | 3 +- drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c | 5 +-- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 7 ++-- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 47 +++++++++------------- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 14 +++---- 8 files changed, 33 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 9c9c72dc57e0..b99d75260d59 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -647,8 +647,7 @@ struct hnae3_ae_ops { int (*rm_mc_addr)(struct hnae3_handle *handle, const unsigned char *addr); void (*set_tso_stats)(struct hnae3_handle *handle, int enable); - void (*update_stats)(struct hnae3_handle *handle, - struct net_device_stats *net_stats); + void (*update_stats)(struct hnae3_handle *handle); void (*get_stats)(struct hnae3_handle *handle, u64 *data); void (*get_mac_stats)(struct hnae3_handle *handle, struct hns3_mac_stats *mac_stats); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c index ae2736549526..b4ae2160aff4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.c @@ -305,8 +305,7 @@ int hclge_comm_set_rss_indir_table(struct hnae3_ae_dev *ae_dev, return 0; } -int hclge_comm_set_rss_input_tuple(struct hnae3_handle *nic, - struct hclge_comm_hw *hw, bool is_pf, +int hclge_comm_set_rss_input_tuple(struct hclge_comm_hw *hw, struct hclge_comm_rss_cfg *rss_cfg) { struct hclge_comm_rss_input_tuple_cmd *req; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h index 92af3d2980d3..cdafa63fe38b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_rss.h @@ -112,8 +112,7 @@ int hclge_comm_init_rss_tuple_cmd(struct hclge_comm_rss_cfg *rss_cfg, struct hnae3_ae_dev *ae_dev, struct hclge_comm_rss_input_tuple_cmd *req); u64 hclge_comm_convert_rss_tuple(u8 tuple_sets); -int hclge_comm_set_rss_input_tuple(struct hnae3_handle *nic, - struct hclge_comm_hw *hw, bool is_pf, +int hclge_comm_set_rss_input_tuple(struct hclge_comm_hw *hw, struct hclge_comm_rss_cfg *rss_cfg); int hclge_comm_set_rss_indir_table(struct hnae3_ae_dev *ae_dev, struct hclge_comm_hw *hw, const u16 *indir); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 32bb14303473..6546cfe7f7cc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -958,8 +958,7 @@ static const struct hns3_dbg_item tx_bd_info_items[] = { { "MSS_HW_CSUM", 0 }, }; -static void hns3_dump_tx_bd_info(struct hns3_nic_priv *priv, - struct hns3_desc *desc, char **result, int idx) +static void hns3_dump_tx_bd_info(struct hns3_desc *desc, char **result, int idx) { unsigned int j = 0; @@ -1008,7 +1007,7 @@ static int hns3_dbg_tx_bd_info(struct hns3_dbg_data *d, char *buf, int len) for (i = 0; i < ring->desc_num; i++) { desc = &ring->desc[i]; - hns3_dump_tx_bd_info(priv, desc, result, i); + hns3_dump_tx_bd_info(desc, result, i); hns3_dbg_fill_content(content, sizeof(content), tx_bd_info_items, (const char **)result, ARRAY_SIZE(tx_bd_info_items)); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index b676496ec6d7..9f6890059666 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2538,7 +2538,7 @@ static void hns3_nic_get_stats64(struct net_device *netdev, if (test_bit(HNS3_NIC_STATE_DOWN, &priv->state)) return; - handle->ae_algo->ops->update_stats(handle, &netdev->stats); + handle->ae_algo->ops->update_stats(handle); memset(&ring_total_stats, 0, sizeof(ring_total_stats)); for (idx = 0; idx < queue_num; idx++) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 51d1278b18f6..407d30ee55d2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -228,7 +228,7 @@ static u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv, u32 budget) } static void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv, u32 start_ringid, - u32 end_ringid, u32 budget) + u32 end_ringid) { u32 i; @@ -295,8 +295,7 @@ static int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode) out: hns3_lb_clear_tx_ring(priv, HNS3_NIC_LB_TEST_RING_ID, - HNS3_NIC_LB_TEST_RING_ID, - HNS3_NIC_LB_TEST_PKT_NUM); + HNS3_NIC_LB_TEST_RING_ID); kfree_skb(skb); return ret_val; @@ -618,7 +617,7 @@ static void hns3_get_stats(struct net_device *netdev, return; } - h->ae_algo->ops->update_stats(h, &netdev->stats); + h->ae_algo->ops->update_stats(h); /* get per-queue stats */ p = hns3_get_stats_tqps(h, p); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2689b108f7df..bf675c15fbb9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -689,8 +689,7 @@ static void hclge_update_stats_for_all(struct hclge_dev *hdev) "Update MAC stats fail, status = %d.\n", status); } -static void hclge_update_stats(struct hnae3_handle *handle, - struct net_device_stats *net_stats) +static void hclge_update_stats(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; @@ -824,7 +823,7 @@ static void hclge_get_mac_stat(struct hnae3_handle *handle, struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; - hclge_update_stats(handle, NULL); + hclge_update_stats(handle); mac_stats->tx_pause_cnt = hdev->mac_stats.mac_tx_mac_pause_num; mac_stats->rx_pause_cnt = hdev->mac_stats.mac_rx_mac_pause_num; @@ -4965,9 +4964,7 @@ int hclge_rss_init_hw(struct hclge_dev *hdev) if (ret) return ret; - ret = hclge_comm_set_rss_input_tuple(&hdev->vport[0].nic, - &hdev->hw.hw, true, - &hdev->rss_cfg); + ret = hclge_comm_set_rss_input_tuple(&hdev->hw.hw, &hdev->rss_cfg); if (ret) return ret; @@ -6243,8 +6240,7 @@ static int hclge_fd_check_spec(struct hclge_dev *hdev, return hclge_fd_check_ext_tuple(hdev, fs, unused_tuple); } -static void hclge_fd_get_tcpip4_tuple(struct hclge_dev *hdev, - struct ethtool_rx_flow_spec *fs, +static void hclge_fd_get_tcpip4_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule, u8 ip_proto) { rule->tuples.src_ip[IPV4_INDEX] = @@ -6273,8 +6269,7 @@ static void hclge_fd_get_tcpip4_tuple(struct hclge_dev *hdev, rule->tuples_mask.ip_proto = 0xFF; } -static void hclge_fd_get_ip4_tuple(struct hclge_dev *hdev, - struct ethtool_rx_flow_spec *fs, +static void hclge_fd_get_ip4_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { rule->tuples.src_ip[IPV4_INDEX] = @@ -6297,8 +6292,7 @@ static void hclge_fd_get_ip4_tuple(struct hclge_dev *hdev, rule->tuples_mask.ether_proto = 0xFFFF; } -static void hclge_fd_get_tcpip6_tuple(struct hclge_dev *hdev, - struct ethtool_rx_flow_spec *fs, +static void hclge_fd_get_tcpip6_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule, u8 ip_proto) { be32_to_cpu_array(rule->tuples.src_ip, fs->h_u.tcp_ip6_spec.ip6src, @@ -6327,8 +6321,7 @@ static void hclge_fd_get_tcpip6_tuple(struct hclge_dev *hdev, rule->tuples_mask.ip_proto = 0xFF; } -static void hclge_fd_get_ip6_tuple(struct hclge_dev *hdev, - struct ethtool_rx_flow_spec *fs, +static void hclge_fd_get_ip6_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { be32_to_cpu_array(rule->tuples.src_ip, fs->h_u.usr_ip6_spec.ip6src, @@ -6351,8 +6344,7 @@ static void hclge_fd_get_ip6_tuple(struct hclge_dev *hdev, rule->tuples_mask.ether_proto = 0xFFFF; } -static void hclge_fd_get_ether_tuple(struct hclge_dev *hdev, - struct ethtool_rx_flow_spec *fs, +static void hclge_fd_get_ether_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule) { ether_addr_copy(rule->tuples.src_mac, fs->h_u.ether_spec.h_source); @@ -6388,8 +6380,7 @@ static void hclge_fd_get_user_def_tuple(struct hclge_fd_user_def_info *info, rule->ep.user_def = *info; } -static int hclge_fd_get_tuple(struct hclge_dev *hdev, - struct ethtool_rx_flow_spec *fs, +static int hclge_fd_get_tuple(struct ethtool_rx_flow_spec *fs, struct hclge_fd_rule *rule, struct hclge_fd_user_def_info *info) { @@ -6397,31 +6388,31 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev, switch (flow_type) { case SCTP_V4_FLOW: - hclge_fd_get_tcpip4_tuple(hdev, fs, rule, IPPROTO_SCTP); + hclge_fd_get_tcpip4_tuple(fs, rule, IPPROTO_SCTP); break; case TCP_V4_FLOW: - hclge_fd_get_tcpip4_tuple(hdev, fs, rule, IPPROTO_TCP); + hclge_fd_get_tcpip4_tuple(fs, rule, IPPROTO_TCP); break; case UDP_V4_FLOW: - hclge_fd_get_tcpip4_tuple(hdev, fs, rule, IPPROTO_UDP); + hclge_fd_get_tcpip4_tuple(fs, rule, IPPROTO_UDP); break; case IP_USER_FLOW: - hclge_fd_get_ip4_tuple(hdev, fs, rule); + hclge_fd_get_ip4_tuple(fs, rule); break; case SCTP_V6_FLOW: - hclge_fd_get_tcpip6_tuple(hdev, fs, rule, IPPROTO_SCTP); + hclge_fd_get_tcpip6_tuple(fs, rule, IPPROTO_SCTP); break; case TCP_V6_FLOW: - hclge_fd_get_tcpip6_tuple(hdev, fs, rule, IPPROTO_TCP); + hclge_fd_get_tcpip6_tuple(fs, rule, IPPROTO_TCP); break; case UDP_V6_FLOW: - hclge_fd_get_tcpip6_tuple(hdev, fs, rule, IPPROTO_UDP); + hclge_fd_get_tcpip6_tuple(fs, rule, IPPROTO_UDP); break; case IPV6_USER_FLOW: - hclge_fd_get_ip6_tuple(hdev, fs, rule); + hclge_fd_get_ip6_tuple(fs, rule); break; case ETHER_FLOW: - hclge_fd_get_ether_tuple(hdev, fs, rule); + hclge_fd_get_ether_tuple(fs, rule); break; default: return -EOPNOTSUPP; @@ -6578,7 +6569,7 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, if (!rule) return -ENOMEM; - ret = hclge_fd_get_tuple(hdev, fs, rule, &info); + ret = hclge_fd_get_tuple(fs, rule, &info); if (ret) { kfree(rule); return ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index dd08989a4c7c..34f02ca8d1d2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -121,8 +121,7 @@ static struct hclgevf_dev *hclgevf_ae_get_hdev(struct hnae3_handle *handle) return container_of(handle, struct hclgevf_dev, nic); } -static void hclgevf_update_stats(struct hnae3_handle *handle, - struct net_device_stats *net_stats) +static void hclgevf_update_stats(struct hnae3_handle *handle) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); int status; @@ -1645,8 +1644,7 @@ err_reset: hclgevf_reset_err_handle(hdev); } -static enum hnae3_reset_type hclgevf_get_reset_level(struct hclgevf_dev *hdev, - unsigned long *addr) +static enum hnae3_reset_type hclgevf_get_reset_level(unsigned long *addr) { enum hnae3_reset_type rst_level = HNAE3_NONE_RESET; @@ -1685,8 +1683,7 @@ static void hclgevf_reset_event(struct pci_dev *pdev, if (hdev->default_reset_request) hdev->reset_level = - hclgevf_get_reset_level(hdev, - &hdev->default_reset_request); + hclgevf_get_reset_level(&hdev->default_reset_request); else hdev->reset_level = HNAE3_VF_FUNC_RESET; @@ -1828,7 +1825,7 @@ static void hclgevf_reset_service_task(struct hclgevf_dev *hdev) hdev->last_reset_time = jiffies; hdev->reset_type = - hclgevf_get_reset_level(hdev, &hdev->reset_pending); + hclgevf_get_reset_level(&hdev->reset_pending); if (hdev->reset_type != HNAE3_NONE_RESET) hclgevf_reset(hdev); } else if (test_and_clear_bit(HCLGEVF_RESET_REQUESTED, @@ -2160,8 +2157,7 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) if (ret) return ret; - ret = hclge_comm_set_rss_input_tuple(&hdev->nic, &hdev->hw.hw, - false, rss_cfg); + ret = hclge_comm_set_rss_input_tuple(&hdev->hw.hw, rss_cfg); if (ret) return ret; } -- cgit v1.2.3 From d3f0c7fa09932d34bbf5548a156316927a099f25 Mon Sep 17 00:00:00 2001 From: Thorsten Winkler Date: Wed, 21 Jun 2023 15:49:18 +0200 Subject: s390/lcs: Convert sysfs sprintf to sysfs_emit Following the advice of the Documentation/filesystems/sysfs.rst. All sysfs related show()-functions should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. While at it, follow Linux kernel coding style and unify indentation Reported-by: Jules Irenge Reported-by: Joe Perches Reviewed-by: Alexandra Winter Reviewed-by: Simon Horman Signed-off-by: Thorsten Winkler Signed-off-by: Alexandra Winter Signed-off-by: Paolo Abeni --- drivers/s390/net/lcs.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index bb1092775dcc..a473d46ad668 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1899,14 +1899,14 @@ lcs_open_device(struct net_device *dev) static ssize_t lcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct lcs_card *card; + struct lcs_card *card; card = dev_get_drvdata(dev); - if (!card) - return 0; + if (!card) + return 0; - return sprintf(buf, "%d\n", card->portno); + return sysfs_emit(buf, "%d\n", card->portno); } /* @@ -1956,7 +1956,8 @@ lcs_type_show(struct device *dev, struct device_attribute *attr, char *buf) if (!cgdev) return -ENODEV; - return sprintf(buf, "%s\n", lcs_type[cgdev->cdev[0]->id.driver_info]); + return sysfs_emit(buf, "%s\n", + lcs_type[cgdev->cdev[0]->id.driver_info]); } static DEVICE_ATTR(type, 0444, lcs_type_show, NULL); @@ -1968,7 +1969,7 @@ lcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf) card = dev_get_drvdata(dev); - return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0; + return card ? sysfs_emit(buf, "%u\n", card->lancmd_timeout) : 0; } static ssize_t -- cgit v1.2.3 From 1a079f3e95295c3534c89f008e5e961a386e25e9 Mon Sep 17 00:00:00 2001 From: Thorsten Winkler Date: Wed, 21 Jun 2023 15:49:19 +0200 Subject: s390/lcs: Convert sprintf to scnprintf This LWN article explains the why scnprintf is preferred over snprintf in general https://lwn.net/Articles/69419/ Ie. snprintf() returns what *would* be the resulting length, while scnprintf() returns the actual length. Reported-by: Jules Irenge Reviewed-by: Alexandra Winter Signed-off-by: Thorsten Winkler Signed-off-by: Alexandra Winter Signed-off-by: Paolo Abeni --- drivers/s390/net/lcs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index bd52caa3b11b..a2699b70b050 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -21,7 +21,7 @@ do { \ #define LCS_DBF_TEXT_(level,name,text...) \ do { \ if (debug_level_enabled(lcs_dbf_##name, level)) { \ - sprintf(debug_buffer, text); \ + scnprintf(debug_buffer, sizeof(debug_buffer), text); \ debug_text_event(lcs_dbf_##name, level, debug_buffer); \ } \ } while (0) -- cgit v1.2.3 From d585e4b7480615031f798ef25e4012bfe53ff135 Mon Sep 17 00:00:00 2001 From: Thorsten Winkler Date: Wed, 21 Jun 2023 15:49:20 +0200 Subject: s390/ctcm: Convert sysfs sprintf to sysfs_emit Following the advice of the Documentation/filesystems/sysfs.rst. All sysfs related show()-functions should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. Reviewed-by: Alexandra Winter Reviewed-by: Simon Horman Signed-off-by: Thorsten Winkler Signed-off-by: Alexandra Winter Signed-off-by: Paolo Abeni --- drivers/s390/net/ctcm_sysfs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index e3813a7aa5e6..98680c2cc4e4 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c @@ -28,7 +28,7 @@ static ssize_t ctcm_buffer_show(struct device *dev, if (!priv) return -ENODEV; - return sprintf(buf, "%d\n", priv->buffer_size); + return sysfs_emit(buf, "%d\n", priv->buffer_size); } static ssize_t ctcm_buffer_write(struct device *dev, @@ -120,7 +120,7 @@ static ssize_t stats_show(struct device *dev, if (!priv || gdev->state != CCWGROUP_ONLINE) return -ENODEV; ctcm_print_statistics(priv); - return sprintf(buf, "0\n"); + return sysfs_emit(buf, "0\n"); } static ssize_t stats_write(struct device *dev, struct device_attribute *attr, @@ -142,7 +142,7 @@ static ssize_t ctcm_proto_show(struct device *dev, if (!priv) return -ENODEV; - return sprintf(buf, "%d\n", priv->protocol); + return sysfs_emit(buf, "%d\n", priv->protocol); } static ssize_t ctcm_proto_store(struct device *dev, @@ -184,8 +184,8 @@ static ssize_t ctcm_type_show(struct device *dev, if (!cgdev) return -ENODEV; - return sprintf(buf, "%s\n", - ctcm_type[cgdev->cdev[0]->id.driver_info]); + return sysfs_emit(buf, "%s\n", + ctcm_type[cgdev->cdev[0]->id.driver_info]); } static DEVICE_ATTR(buffer, 0644, ctcm_buffer_show, ctcm_buffer_write); -- cgit v1.2.3 From 1471d85ffba7d17456670afa1b75e50234caa2c6 Mon Sep 17 00:00:00 2001 From: Thorsten Winkler Date: Wed, 21 Jun 2023 15:49:21 +0200 Subject: s390/ctcm: Convert sprintf/snprintf to scnprintf This LWN article explains the why scnprintf is preferred over snprintf in general https://lwn.net/Articles/69419/ Ie. snprintf() returns what *would* be the resulting length, while scnprintf() returns the actual length. Note that ctcm_print_statistics() writes the data into the kernel log and is therefore not suitable for sysfs_emit(). Observable behavior is not changed, as there may be dependencies. Reviewed-by: Alexandra Winter Signed-off-by: Thorsten Winkler Signed-off-by: Alexandra Winter Signed-off-by: Paolo Abeni --- drivers/s390/net/ctcm_dbug.c | 2 +- drivers/s390/net/ctcm_main.c | 6 +++--- drivers/s390/net/ctcm_main.h | 1 + drivers/s390/net/ctcm_mpc.c | 18 ++++++++++-------- drivers/s390/net/ctcm_sysfs.c | 36 ++++++++++++++++++------------------ 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/s390/net/ctcm_dbug.c b/drivers/s390/net/ctcm_dbug.c index f7ec51db3cd6..b6f0e2f114b4 100644 --- a/drivers/s390/net/ctcm_dbug.c +++ b/drivers/s390/net/ctcm_dbug.c @@ -70,7 +70,7 @@ void ctcm_dbf_longtext(enum ctcm_dbf_names dbf_nix, int level, char *fmt, ...) if (!debug_level_enabled(ctcm_dbf[dbf_nix].id, level)) return; va_start(args, fmt); - vsnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args); + vscnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args); va_end(args); debug_text_event(ctcm_dbf[dbf_nix].id, level, dbf_txt_buf); diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 28db69d91f17..6faf27136024 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1333,7 +1333,7 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type, goto nomem_return; ch->cdev = cdev; - snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev->dev)); + scnprintf(ch->id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev->dev)); ch->type = type; /* @@ -1498,8 +1498,8 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) type = get_channel_type(&cdev0->id); - snprintf(read_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev0->dev)); - snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); + scnprintf(read_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev0->dev)); + scnprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); ret = add_channel(cdev0, type, priv); if (ret) { diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h index 90bd7b3f80c3..25164e8bf13d 100644 --- a/drivers/s390/net/ctcm_main.h +++ b/drivers/s390/net/ctcm_main.h @@ -100,6 +100,7 @@ enum ctcm_channel_types { #define CTCM_PROTO_MPC 4 #define CTCM_PROTO_MAX 4 +#define CTCM_STATSIZE_LIMIT 64 #define CTCM_BUFSIZE_LIMIT 65535 #define CTCM_BUFSIZE_DEFAULT 32768 #define MPC_BUFSIZE_DEFAULT CTCM_BUFSIZE_LIMIT diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index b8a226c6e1a9..c44ba88f9f47 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -144,9 +144,9 @@ void ctcmpc_dumpit(char *buf, int len) for (ct = 0; ct < len; ct++, ptr++, rptr++) { if (sw == 0) { - sprintf(addr, "%16.16llx", (__u64)rptr); + scnprintf(addr, sizeof(addr), "%16.16llx", (__u64)rptr); - sprintf(boff, "%4.4X", (__u32)ct); + scnprintf(boff, sizeof(boff), "%4.4X", (__u32)ct); bhex[0] = '\0'; basc[0] = '\0'; } @@ -155,7 +155,7 @@ void ctcmpc_dumpit(char *buf, int len) if (sw == 8) strcat(bhex, " "); - sprintf(tbuf, "%2.2llX", (__u64)*ptr); + scnprintf(tbuf, sizeof(tbuf), "%2.2llX", (__u64)*ptr); tbuf[2] = '\0'; strcat(bhex, tbuf); @@ -171,8 +171,8 @@ void ctcmpc_dumpit(char *buf, int len) continue; if ((strcmp(duphex, bhex)) != 0) { if (dup != 0) { - sprintf(tdup, - "Duplicate as above to %s", addr); + scnprintf(tdup, sizeof(tdup), + "Duplicate as above to %s", addr); ctcm_pr_debug(" --- %s ---\n", tdup); } @@ -197,14 +197,16 @@ void ctcmpc_dumpit(char *buf, int len) strcat(basc, " "); } if (dup != 0) { - sprintf(tdup, "Duplicate as above to %s", addr); + scnprintf(tdup, sizeof(tdup), + "Duplicate as above to %s", addr); ctcm_pr_debug(" --- %s ---\n", tdup); } ctcm_pr_debug(" %s (+%s) : %s [%s]\n", addr, boff, bhex, basc); } else { if (dup >= 1) { - sprintf(tdup, "Duplicate as above to %s", addr); + scnprintf(tdup, sizeof(tdup), + "Duplicate as above to %s", addr); ctcm_pr_debug(" --- %s ---\n", tdup); } if (dup != 0) { @@ -291,7 +293,7 @@ static struct net_device *ctcmpc_get_dev(int port_num) struct net_device *dev; struct ctcm_priv *priv; - sprintf(device, "%s%i", MPC_DEVICE_NAME, port_num); + scnprintf(device, sizeof(device), "%s%i", MPC_DEVICE_NAME, port_num); dev = __dev_get_by_name(&init_net, device); diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index 98680c2cc4e4..0c5d8a3eaa2e 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c @@ -86,24 +86,24 @@ static void ctcm_print_statistics(struct ctcm_priv *priv) return; p = sbuf; - p += sprintf(p, " Device FSM state: %s\n", - fsm_getstate_str(priv->fsm)); - p += sprintf(p, " RX channel FSM state: %s\n", - fsm_getstate_str(priv->channel[CTCM_READ]->fsm)); - p += sprintf(p, " TX channel FSM state: %s\n", - fsm_getstate_str(priv->channel[CTCM_WRITE]->fsm)); - p += sprintf(p, " Max. TX buffer used: %ld\n", - priv->channel[WRITE]->prof.maxmulti); - p += sprintf(p, " Max. chained SKBs: %ld\n", - priv->channel[WRITE]->prof.maxcqueue); - p += sprintf(p, " TX single write ops: %ld\n", - priv->channel[WRITE]->prof.doios_single); - p += sprintf(p, " TX multi write ops: %ld\n", - priv->channel[WRITE]->prof.doios_multi); - p += sprintf(p, " Netto bytes written: %ld\n", - priv->channel[WRITE]->prof.txlen); - p += sprintf(p, " Max. TX IO-time: %u\n", - jiffies_to_usecs(priv->channel[WRITE]->prof.tx_time)); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Device FSM state: %s\n", + fsm_getstate_str(priv->fsm)); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " RX channel FSM state: %s\n", + fsm_getstate_str(priv->channel[CTCM_READ]->fsm)); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX channel FSM state: %s\n", + fsm_getstate_str(priv->channel[CTCM_WRITE]->fsm)); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. TX buffer used: %ld\n", + priv->channel[WRITE]->prof.maxmulti); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. chained SKBs: %ld\n", + priv->channel[WRITE]->prof.maxcqueue); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX single write ops: %ld\n", + priv->channel[WRITE]->prof.doios_single); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX multi write ops: %ld\n", + priv->channel[WRITE]->prof.doios_multi); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Netto bytes written: %ld\n", + priv->channel[WRITE]->prof.txlen); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. TX IO-time: %u\n", + jiffies_to_usecs(priv->channel[WRITE]->prof.tx_time)); printk(KERN_INFO "Statistics for %s:\n%s", priv->channel[CTCM_WRITE]->netdev->name, sbuf); -- cgit v1.2.3 From faaa5fd30344f9a7b3816ae7a6b58ccd5a34998f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 21 Jun 2023 17:10:12 -0600 Subject: dt-bindings: net: altr,tse: Fix error in "compatible" conditional schema The conditional if/then schema has an error as the "enum" values have "const" in them. Drop the "const". Signed-off-by: Rob Herring Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230621231012.3816139-1-robh@kernel.org Signed-off-by: Paolo Abeni --- Documentation/devicetree/bindings/net/altr,tse.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/altr,tse.yaml b/Documentation/devicetree/bindings/net/altr,tse.yaml index 9d02af468906..f5d3b70af07a 100644 --- a/Documentation/devicetree/bindings/net/altr,tse.yaml +++ b/Documentation/devicetree/bindings/net/altr,tse.yaml @@ -72,8 +72,8 @@ allOf: compatible: contains: enum: - - const: altr,tse-1.0 - - const: ALTR,tse-1.0 + - altr,tse-1.0 + - ALTR,tse-1.0 then: properties: reg: -- cgit v1.2.3 From da744fd1362cd8ccf71043c62825cb88cb946886 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Wed, 14 Jun 2023 16:26:07 +0300 Subject: net/mlx5: Fix UAF in mlx5_eswitch_cleanup() mlx5_eswitch_cleanup() is using esw right after freeing it for releasing devlink_param. Fix it by releasing the devlink_param before freeing the esw, and adjust the create function accordingly. Fixes: 3f90840305e2 ("net/mlx5: Move esw multiport devlink param to eswitch code") Reported-by: Dan Carpenter Signed-off-by: Shay Drory Reviewed-by: Automatic Verification Reviewed-by: Gal Pressman Reviewed-by: Moshe Shemesh Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 5aaedbf71783..b4e465856127 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1751,16 +1751,14 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev) if (!MLX5_VPORT_MANAGER(dev) && !MLX5_ESWITCH_MANAGER(dev)) return 0; + esw = kzalloc(sizeof(*esw), GFP_KERNEL); + if (!esw) + return -ENOMEM; + err = devl_params_register(priv_to_devlink(dev), mlx5_eswitch_params, ARRAY_SIZE(mlx5_eswitch_params)); if (err) - return err; - - esw = kzalloc(sizeof(*esw), GFP_KERNEL); - if (!esw) { - err = -ENOMEM; - goto unregister_param; - } + goto free_esw; esw->dev = dev; esw->manager_vport = mlx5_eswitch_manager_vport(dev); @@ -1821,10 +1819,10 @@ abort: if (esw->work_queue) destroy_workqueue(esw->work_queue); debugfs_remove_recursive(esw->debugfs_root); - kfree(esw); -unregister_param: devl_params_unregister(priv_to_devlink(dev), mlx5_eswitch_params, ARRAY_SIZE(mlx5_eswitch_params)); +free_esw: + kfree(esw); return err; } @@ -1848,9 +1846,9 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) esw_offloads_cleanup(esw); mlx5_esw_vports_cleanup(esw); debugfs_remove_recursive(esw->debugfs_root); - kfree(esw); devl_params_unregister(priv_to_devlink(esw->dev), mlx5_eswitch_params, ARRAY_SIZE(mlx5_eswitch_params)); + kfree(esw); } /* Vport Administration */ -- cgit v1.2.3 From 25c24801d7da8f9cb088bc0ad5947d2e84035411 Mon Sep 17 00:00:00 2001 From: Shay Drory Date: Mon, 19 Jun 2023 07:42:07 +0300 Subject: net/mlx5: Fix SFs kernel documentation error Indent SFs probe code example in order to fix the below error: Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst:57: ERROR: Unexpected indentation. Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst:61: ERROR: Unexpected indentation. Fixes: e71383fb9cd1 ("net/mlx5: Light probe local SFs") Signed-off-by: Shay Drory Reviewed-by: Rahul Rameshbabu Signed-off-by: Saeed Mahameed Reviewed-by: Moshe Shemesh Reviewed-by: Automatic Verification Reviewed-by: Gal Pressman --- .../ethernet/mellanox/mlx5/switchdev.rst | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst index db62187eebce..6e3f5ee8b0d0 100644 --- a/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst +++ b/Documentation/networking/device_drivers/ethernet/mellanox/mlx5/switchdev.rst @@ -51,19 +51,21 @@ This will allow user to configure the SF before the SF have been fully probed, which will save time. Usage example: -Create SF: -$ devlink port add pci/0000:08:00.0 flavour pcisf pfnum 0 sfnum 11 -$ devlink port function set pci/0000:08:00.0/32768 \ - hw_addr 00:00:00:00:00:11 state active -Enable ETH auxiliary device: -$ devlink dev param set auxiliary/mlx5_core.sf.1 \ - name enable_eth value true cmode driverinit +- Create SF:: -Now, in order to fully probe the SF, use devlink reload: -$ devlink dev reload auxiliary/mlx5_core.sf.1 + $ devlink port add pci/0000:08:00.0 flavour pcisf pfnum 0 sfnum 11 + $ devlink port function set pci/0000:08:00.0/32768 hw_addr 00:00:00:00:00:11 state active -mlx5 supports ETH,rdma and vdpa (vnet) auxiliary devices devlink params (see :ref:`Documentation/networking/devlink/devlink-params.rst`) +- Enable ETH auxiliary device:: + + $ devlink dev param set auxiliary/mlx5_core.sf.1 name enable_eth value true cmode driverinit + +- Now, in order to fully probe the SF, use devlink reload:: + + $ devlink dev reload auxiliary/mlx5_core.sf.1 + +mlx5 supports ETH,rdma and vdpa (vnet) auxiliary devices devlink params (see :ref:`Documentation/networking/devlink/devlink-params.rst `). mlx5 supports subfunction management using devlink port (see :ref:`Documentation/networking/devlink/devlink-port.rst `) interface. -- cgit v1.2.3 From 9ee473c259de393718ae1c6fdd51271d5d087c4b Mon Sep 17 00:00:00 2001 From: Lama Kayal Date: Mon, 12 Jun 2023 16:34:43 +0300 Subject: net/mlx5: Fix reserved at offset in hca_cap register A member of struct mlx5_ifc_cmd_hca_cap_bits has been mistakenly assigned the wrong reserved_at offset value. Correct it to align to the right value, thus avoid future miscalculation. Signed-off-by: Lama Kayal Reviewed-by: Tariq Toukan Reviewed-by: Rahul Rameshbabu Signed-off-by: Saeed Mahameed --- include/linux/mlx5/mlx5_ifc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 354c7e326eab..33344a71c3e3 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1710,9 +1710,9 @@ struct mlx5_ifc_cmd_hca_cap_bits { u8 regexp_params[0x1]; u8 uar_sz[0x6]; u8 port_selection_cap[0x1]; - u8 reserved_at_248[0x1]; + u8 reserved_at_251[0x1]; u8 umem_uid_0[0x1]; - u8 reserved_at_250[0x5]; + u8 reserved_at_253[0x5]; u8 log_pg_sz[0x8]; u8 bf[0x1]; -- cgit v1.2.3 From 690ad62fc6e445cc371e625fe2016e62c3793a0f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 20 Jun 2023 16:43:07 +0300 Subject: net/mlx5: Fix error code in mlx5_is_reset_now_capable() The mlx5_is_reset_now_capable() function returns bool, not negative error codes. So if fast teardown is not supported it should return false instead of -EOPNOTSUPP. Fixes: 92501fa6e421 ("net/mlx5: Ack on sync_reset_request only if PF can do reset_now") Signed-off-by: Dan Carpenter Reviewed-by: Kalesh AP Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c index 7af2b14ab5d8..fb7874da3caa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c @@ -327,7 +327,7 @@ static bool mlx5_is_reset_now_capable(struct mlx5_core_dev *dev) if (!MLX5_CAP_GEN(dev, fast_teardown)) { mlx5_core_warn(dev, "fast teardown is not supported by firmware\n"); - return -EOPNOTSUPP; + return false; } err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id); -- cgit v1.2.3 From 8ec91f5d077c09e72e4e11d701a83eb1f1504ea3 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Tue, 23 May 2023 12:02:06 +0300 Subject: net/mlx5: Lag, Remove duplicate code checking lag is supported Remove duplicate function for checking if device has lag support. Signed-off-by: Roi Dayan Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c | 15 +++++++++++---- drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h | 10 +--------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index fdf482f6fb34..9056b0b014f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2868,7 +2868,7 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw) if (!MLX5_CAP_ESW(esw->dev, merged_eswitch)) return; - if (!mlx5_is_lag_supported(esw->dev)) + if (!mlx5_lag_is_supported(esw->dev)) return; mlx5_devcom_register_component(devcom, @@ -2890,7 +2890,7 @@ void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) if (!MLX5_CAP_ESW(esw->dev, merged_eswitch)) return; - if (!mlx5_is_lag_supported(esw->dev)) + if (!mlx5_lag_is_supported(esw->dev)) return; mlx5_devcom_send_event(devcom, MLX5_DEVCOM_ESW_OFFLOADS, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index ffd7e17b8ebe..f0a074b2fcdf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -1268,14 +1268,21 @@ recheck: mlx5_ldev_put(ldev); } +bool mlx5_lag_is_supported(struct mlx5_core_dev *dev) +{ + if (!MLX5_CAP_GEN(dev, vport_group_manager) || + !MLX5_CAP_GEN(dev, lag_master) || + MLX5_CAP_GEN(dev, num_lag_ports) < 2 || + MLX5_CAP_GEN(dev, num_lag_ports) > MLX5_MAX_PORTS) + return false; + return true; +} + void mlx5_lag_add_mdev(struct mlx5_core_dev *dev) { int err; - if (!MLX5_CAP_GEN(dev, vport_group_manager) || - !MLX5_CAP_GEN(dev, lag_master) || - (MLX5_CAP_GEN(dev, num_lag_ports) > MLX5_MAX_PORTS || - MLX5_CAP_GEN(dev, num_lag_ports) <= 1)) + if (!mlx5_lag_is_supported(dev)) return; recheck: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h index d7e7fa2348a5..a061b1873e27 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h @@ -74,15 +74,7 @@ struct mlx5_lag { struct lag_mpesw lag_mpesw; }; -static inline bool mlx5_is_lag_supported(struct mlx5_core_dev *dev) -{ - if (!MLX5_CAP_GEN(dev, vport_group_manager) || - !MLX5_CAP_GEN(dev, lag_master) || - MLX5_CAP_GEN(dev, num_lag_ports) < 2 || - MLX5_CAP_GEN(dev, num_lag_ports) > MLX5_MAX_PORTS) - return false; - return true; -} +bool mlx5_lag_is_supported(struct mlx5_core_dev *dev); static inline struct mlx5_lag * mlx5_lag_dev(struct mlx5_core_dev *dev) -- cgit v1.2.3 From 1da9f36252d4852205a1990f003549d753320e8c Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 28 May 2023 10:58:03 +0300 Subject: net/mlx5e: Use vhca_id for device index in vport rx rules Device index is like PF index and limited to max physical ports. For example, SFs created under PF the device index is the PF device index. Use vhca_id which gets the FW index per vport, for vport rx rules and vport pair events. Signed-off-by: Roi Dayan Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index 965a8261c99b..152b62138450 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -408,7 +408,7 @@ static int mlx5e_sqs2vport_add_peers_rules(struct mlx5_eswitch *esw, struct mlx5 mlx5_devcom_for_each_peer_entry(devcom, MLX5_DEVCOM_ESW_OFFLOADS, peer_esw, tmp) { - int peer_rule_idx = mlx5_get_dev_index(peer_esw->dev); + u16 peer_rule_idx = MLX5_CAP_GEN(peer_esw->dev, vhca_id); struct mlx5e_rep_sq_peer *sq_peer; int err; @@ -1581,7 +1581,7 @@ static void *mlx5e_vport_rep_get_proto_dev(struct mlx5_eswitch_rep *rep) static void mlx5e_vport_rep_event_unpair(struct mlx5_eswitch_rep *rep, struct mlx5_eswitch *peer_esw) { - int i = mlx5_get_dev_index(peer_esw->dev); + u16 i = MLX5_CAP_GEN(peer_esw->dev, vhca_id); struct mlx5e_rep_priv *rpriv; struct mlx5e_rep_sq *rep_sq; @@ -1603,7 +1603,7 @@ static int mlx5e_vport_rep_event_pair(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep, struct mlx5_eswitch *peer_esw) { - int i = mlx5_get_dev_index(peer_esw->dev); + u16 i = MLX5_CAP_GEN(peer_esw->dev, vhca_id); struct mlx5_flow_handle *flow_rule; struct mlx5e_rep_sq_peer *sq_peer; struct mlx5e_rep_priv *rpriv; -- cgit v1.2.3 From 1552e9b51810761881f7438d26c9b2dad171e423 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 28 May 2023 12:10:26 +0300 Subject: net/mlx5e: E-Switch, Add peer fdb miss rules for vport manager or ecpf Add peer fdb rules for E-Switch that are vport managers or ecpf device. It is not needed for other devices. Signed-off-by: Roi Dayan Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 9056b0b014f6..ed986d1c9e90 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1069,6 +1069,9 @@ static int esw_add_fdb_peer_miss_rules(struct mlx5_eswitch *esw, void *misc; int err; + if (!MLX5_VPORT_MANAGER(esw->dev) && !mlx5_core_is_ecpf_esw_manager(esw->dev)) + return 0; + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; @@ -1177,11 +1180,14 @@ alloc_flows_err: static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw, struct mlx5_core_dev *peer_dev) { + u16 peer_index = mlx5_get_dev_index(peer_dev); struct mlx5_flow_handle **flows; struct mlx5_vport *vport; unsigned long i; - flows = esw->fdb_table.offloads.peer_miss_rules[mlx5_get_dev_index(peer_dev)]; + flows = esw->fdb_table.offloads.peer_miss_rules[peer_index]; + if (!flows) + return; if (mlx5_core_ec_sriov_enabled(esw->dev)) { mlx5_esw_for_each_ec_vf_vport(esw, i, vport, mlx5_core_max_ec_vfs(esw->dev)) { @@ -1206,7 +1212,9 @@ static void esw_del_fdb_peer_miss_rules(struct mlx5_eswitch *esw, vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF); mlx5_del_flow_rules(flows[vport->index]); } + kvfree(flows); + esw->fdb_table.offloads.peer_miss_rules[peer_index] = NULL; } static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw) -- cgit v1.2.3 From 70c36438393546be0bbfd001d043a08e8ff611e9 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 28 May 2023 12:11:47 +0300 Subject: net/mlx5e: E-Switch, Use xarray for devcom paired device index To allow devcom events on E-Switch that is not a vport group manager, use vhca id as an index instead of device index which might be shared between several E-Switches. for example SF and its PF. Signed-off-by: Roi Dayan Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 2 +- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 30 +++++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 7064609f4998..ae0dc8a3060d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -353,7 +353,7 @@ struct mlx5_eswitch { u32 large_group_num; } params; struct blocking_notifier_head n_head; - bool paired[MLX5_MAX_PORTS]; + struct xarray paired; }; void esw_offloads_disable(struct mlx5_eswitch *esw); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index ed986d1c9e90..6f3b7d5eb6a4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2807,15 +2807,21 @@ static int mlx5_esw_offloads_devcom_event(int event, struct mlx5_eswitch *esw = my_data; struct mlx5_devcom *devcom = esw->dev->priv.devcom; struct mlx5_eswitch *peer_esw = event_data; + u16 esw_i, peer_esw_i; + bool esw_paired; int err; + peer_esw_i = MLX5_CAP_GEN(peer_esw->dev, vhca_id); + esw_i = MLX5_CAP_GEN(esw->dev, vhca_id); + esw_paired = !!xa_load(&esw->paired, peer_esw_i); + switch (event) { case ESW_OFFLOADS_DEVCOM_PAIR: if (mlx5_eswitch_vport_match_metadata_enabled(esw) != mlx5_eswitch_vport_match_metadata_enabled(peer_esw)) break; - if (esw->paired[mlx5_get_dev_index(peer_esw->dev)]) + if (esw_paired) break; err = mlx5_esw_offloads_set_ns_peer(esw, peer_esw, true); @@ -2829,23 +2835,29 @@ static int mlx5_esw_offloads_devcom_event(int event, if (err) goto err_pair; - esw->paired[mlx5_get_dev_index(peer_esw->dev)] = true; - peer_esw->paired[mlx5_get_dev_index(esw->dev)] = true; + err = xa_insert(&esw->paired, peer_esw_i, peer_esw, GFP_KERNEL); + if (err) + goto err_xa; + + err = xa_insert(&peer_esw->paired, esw_i, esw, GFP_KERNEL); + if (err) + goto err_peer_xa; + esw->num_peers++; peer_esw->num_peers++; mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, true); break; case ESW_OFFLOADS_DEVCOM_UNPAIR: - if (!esw->paired[mlx5_get_dev_index(peer_esw->dev)]) + if (!esw_paired) break; peer_esw->num_peers--; esw->num_peers--; if (!esw->num_peers && !peer_esw->num_peers) mlx5_devcom_comp_set_ready(devcom, MLX5_DEVCOM_ESW_OFFLOADS, false); - esw->paired[mlx5_get_dev_index(peer_esw->dev)] = false; - peer_esw->paired[mlx5_get_dev_index(esw->dev)] = false; + xa_erase(&peer_esw->paired, esw_i); + xa_erase(&esw->paired, peer_esw_i); mlx5_esw_offloads_unpair(peer_esw, esw); mlx5_esw_offloads_unpair(esw, peer_esw); mlx5_esw_offloads_set_ns_peer(esw, peer_esw, false); @@ -2854,6 +2866,10 @@ static int mlx5_esw_offloads_devcom_event(int event, return 0; +err_peer_xa: + xa_erase(&esw->paired, peer_esw_i); +err_xa: + mlx5_esw_offloads_unpair(peer_esw, esw); err_pair: mlx5_esw_offloads_unpair(esw, peer_esw); err_peer: @@ -2879,6 +2895,7 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw) if (!mlx5_lag_is_supported(esw->dev)) return; + xa_init(&esw->paired); mlx5_devcom_register_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS, mlx5_esw_offloads_devcom_event, @@ -2906,6 +2923,7 @@ void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) ESW_OFFLOADS_DEVCOM_UNPAIR, esw); mlx5_devcom_unregister_component(devcom, MLX5_DEVCOM_ESW_OFFLOADS); + xa_destroy(&esw->paired); } bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw) -- cgit v1.2.3 From 4575ab3b7de04813400acf989ca7f26dd7e29c59 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Sun, 28 May 2023 17:10:43 +0300 Subject: net/mlx5e: E-Switch, Pass other_vport flag if vport is not 0 When creating flow table for shared fdb resources, there is only need to pass other_vport flag if vport is not 0 or if the port is ECPF in BlueField. Signed-off-by: Roi Dayan Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 6f3b7d5eb6a4..ee507b12e908 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2551,13 +2551,13 @@ static int __esw_set_master_egress_rule(struct mlx5_core_dev *master, return err; } -static int esw_master_egress_create_resources(struct mlx5_flow_namespace *egress_ns, +static int esw_master_egress_create_resources(struct mlx5_eswitch *esw, + struct mlx5_flow_namespace *egress_ns, struct mlx5_vport *vport, size_t count) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_flow_table_attr ft_attr = { .max_fte = count, .prio = 0, .level = 0, - .flags = MLX5_FLOW_TABLE_OTHER_VPORT, }; struct mlx5_flow_table *acl; struct mlx5_flow_group *g; @@ -2572,6 +2572,9 @@ static int esw_master_egress_create_resources(struct mlx5_flow_namespace *egress if (!flow_group_in) return -ENOMEM; + if (vport->vport || mlx5_core_is_ecpf(esw->dev)) + ft_attr.flags = MLX5_FLOW_TABLE_OTHER_VPORT; + acl = mlx5_create_vport_flow_table(egress_ns, &ft_attr, vport->vport); if (IS_ERR(acl)) { err = PTR_ERR(acl); @@ -2642,7 +2645,7 @@ static int esw_set_master_egress_rule(struct mlx5_core_dev *master, if (vport->egress.acl && vport->egress.type != VPORT_EGRESS_ACL_TYPE_SHARED_FDB) return 0; - err = esw_master_egress_create_resources(egress_ns, vport, count); + err = esw_master_egress_create_resources(esw, egress_ns, vport, count); if (err) return err; -- cgit v1.2.3 From ae4de894931d37ff12405db29ca3a2395d3a0449 Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Mon, 29 May 2023 09:24:54 +0300 Subject: net/mlx5e: Remove redundant comment The function comment says what it is and the comment is redundant. Signed-off-by: Roi Dayan Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index ee507b12e908..612be82a8ad5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1904,7 +1904,6 @@ static int esw_create_vport_rx_group(struct mlx5_eswitch *esw) if (!flow_group_in) return -ENOMEM; - /* create vport rx group */ mlx5_esw_set_flow_group_source_port(esw, flow_group_in, 0); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); -- cgit v1.2.3 From 15ddd72ee323cf4b7012dc8e002ebb812f92e11f Mon Sep 17 00:00:00 2001 From: Roi Dayan Date: Mon, 29 May 2023 09:32:57 +0300 Subject: net/mlx5e: E-Switch, Fix shared fdb error flow On error flow resources being freed in esw_master_egress_destroy_resources() but pointers not being set to null if error flow is from creating a bounce rule. Then in esw_acl_egress_ofld_cleanup() we try to access already freed pointers. Fix it by resetting the pointers to null. Also if error is from creating a second or later bounce rule then the flow group and table being used and cannot and should not be freed. Add a check to destroy the flow group and table if there are no bounce rules. mlx5_core.sf mlx5_core.sf.2: mlx5_destroy_flow_group:2306:(pid 2235): Flow group 4 wasn't destroyed, refcount > 1 mlx5_core.sf mlx5_core.sf.2: mlx5_destroy_flow_table:2295:(pid 2235): Flow table 3 wasn't destroyed, refcount > 1 Fixes: 5e0202eb49ed ("net/mlx5: E-switch, Handle multiple master egress rules") Signed-off-by: Roi Dayan Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 612be82a8ad5..cf58295ad7e2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2618,8 +2618,12 @@ out: static void esw_master_egress_destroy_resources(struct mlx5_vport *vport) { + if (!xa_empty(&vport->egress.offloads.bounce_rules)) + return; mlx5_destroy_flow_group(vport->egress.offloads.bounce_grp); + vport->egress.offloads.bounce_grp = NULL; mlx5_destroy_flow_table(vport->egress.acl); + vport->egress.acl = NULL; } static int esw_set_master_egress_rule(struct mlx5_core_dev *master, -- cgit v1.2.3 From 61955da523d93b4d89f45f84dc6ce9d44ced7bae Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Jun 2023 13:12:37 +0200 Subject: net/mlx5: Remove redundant MLX5_ESWITCH_MANAGER() check from is_ib_rep_supported() MLX5_ESWITCH_MANAGER() check is done in is_eth_rep_supported(). Function is_ib_rep_supported() calls is_eth_rep_supported(). Remove the redundant check from it. Signed-off-by: Jiri Pirko Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/dev.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index 617ac7e5d75c..3b1e925f16d2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -151,9 +151,6 @@ static bool is_ib_rep_supported(struct mlx5_core_dev *dev) if (!is_eth_rep_supported(dev)) return false; - if (!MLX5_ESWITCH_MANAGER(dev)) - return false; - if (!is_mdev_switchdev_mode(dev)) return false; -- cgit v1.2.3 From 0d0946d6488e785c30a0c4fce4cf21dc7da6dc1f Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Jun 2023 13:15:12 +0200 Subject: net/mlx5: Remove redundant is_mdev_switchdev_mode() check from is_ib_rep_supported() is_mdev_switchdev_mode() check is done in is_eth_rep_supported(). Function is_ib_rep_supported() calls is_eth_rep_supported(). Remove the redundant check from it. Signed-off-by: Jiri Pirko Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/dev.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index 3b1e925f16d2..edb06fb9bbc5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -151,9 +151,6 @@ static bool is_ib_rep_supported(struct mlx5_core_dev *dev) if (!is_eth_rep_supported(dev)) return false; - if (!is_mdev_switchdev_mode(dev)) - return false; - if (mlx5_core_mp_enabled(dev)) return false; -- cgit v1.2.3 From 899862b653d74ed5fc3a61cd5e14a88b824a71d7 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 31 May 2023 15:11:07 +0200 Subject: net/mlx5: Remove redundant check from mlx5_esw_query_vport_vhca_id() Since mlx5_esw_query_vport_vhca_id() could be called either from mlx5_esw_vport_enable() or mlx5_esw_vport_disable() where the the check is done, this is always false here. Remove the redundant check. Signed-off-by: Jiri Pirko Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index cf58295ad7e2..bdfe609cc9ec 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -3961,9 +3961,6 @@ static int mlx5_esw_query_vport_vhca_id(struct mlx5_eswitch *esw, u16 vport_num, int err; *vhca_id = 0; - if (mlx5_esw_is_manager_vport(esw, vport_num) || - !MLX5_CAP_GEN(esw->dev, vhca_resource_manager)) - return -EPERM; query_ctx = kzalloc(query_out_sz, GFP_KERNEL); if (!query_ctx) -- cgit v1.2.3 From 29e4c95faee52a9b7a4f1293cb92cd17a0b5fd91 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 1 Jun 2023 09:17:17 +0200 Subject: net/mlx5: Remove pointless vport lookup from mlx5_esw_check_port_type() As xa_get_mark() returns false in case the entry is not present, no need to redundantly check if vport is present. Remove the lookup. Signed-off-by: Jiri Pirko Reviewed-by: Shay Drory Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index b4e465856127..faec7d7a4400 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1908,12 +1908,6 @@ int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw, static bool mlx5_esw_check_port_type(struct mlx5_eswitch *esw, u16 vport_num, xa_mark_t mark) { - struct mlx5_vport *vport; - - vport = mlx5_eswitch_get_vport(esw, vport_num); - if (IS_ERR(vport)) - return false; - return xa_get_mark(&esw->vports, vport_num, mark); } -- cgit v1.2.3 From 1b5ea7ffb7a3bdfffb4b7f40ce0d20a3372ee405 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 22 Jun 2023 03:31:07 -0700 Subject: net: bcmgenet: Ensure MDIO unregistration has clocks enabled With support for Ethernet PHY LEDs having been added, while unregistering a MDIO bus and its child device liks PHYs there may be "late" accesses to the MDIO bus. One typical use case is setting the PHY LEDs brightness to OFF for instance. We need to ensure that the MDIO bus controller remains entirely functional since it runs off the main GENET adapter clock. Cc: stable@vger.kernel.org Link: https://lore.kernel.org/all/20230617155500.4005881-1-andrew@lunn.ch/ Fixes: 9a4e79697009 ("net: bcmgenet: utilize generic Broadcom UniMAC MDIO controller driver") Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230622103107.1760280-1-florian.fainelli@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index c15ed0acdb77..0092e46c46f8 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -673,5 +673,7 @@ void bcmgenet_mii_exit(struct net_device *dev) if (of_phy_is_fixed_link(dn)) of_phy_deregister_fixed_link(dn); of_node_put(priv->phy_dn); + clk_prepare_enable(priv->clk); platform_device_unregister(priv->mii_pdev); + clk_disable_unprepare(priv->clk); } -- cgit v1.2.3 From 6a940abdef3162e5723f1495b8a49859d1708f79 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Jun 2023 15:23:04 +0000 Subject: bonding: do not assume skb mac_header is set Drivers must not assume in their ndo_start_xmit() that skbs have their mac_header set. skb->data is all what is needed. bonding seems to be one of the last offender as caught by syzbot: WARNING: CPU: 1 PID: 12155 at include/linux/skbuff.h:2907 skb_mac_offset include/linux/skbuff.h:2913 [inline] WARNING: CPU: 1 PID: 12155 at include/linux/skbuff.h:2907 bond_xmit_hash drivers/net/bonding/bond_main.c:4170 [inline] WARNING: CPU: 1 PID: 12155 at include/linux/skbuff.h:2907 bond_xmit_3ad_xor_slave_get drivers/net/bonding/bond_main.c:5149 [inline] WARNING: CPU: 1 PID: 12155 at include/linux/skbuff.h:2907 bond_3ad_xor_xmit drivers/net/bonding/bond_main.c:5186 [inline] WARNING: CPU: 1 PID: 12155 at include/linux/skbuff.h:2907 __bond_start_xmit drivers/net/bonding/bond_main.c:5442 [inline] WARNING: CPU: 1 PID: 12155 at include/linux/skbuff.h:2907 bond_start_xmit+0x14ab/0x19d0 drivers/net/bonding/bond_main.c:5470 Modules linked in: CPU: 1 PID: 12155 Comm: syz-executor.3 Not tainted 6.1.30-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/25/2023 RIP: 0010:skb_mac_header include/linux/skbuff.h:2907 [inline] RIP: 0010:skb_mac_offset include/linux/skbuff.h:2913 [inline] RIP: 0010:bond_xmit_hash drivers/net/bonding/bond_main.c:4170 [inline] RIP: 0010:bond_xmit_3ad_xor_slave_get drivers/net/bonding/bond_main.c:5149 [inline] RIP: 0010:bond_3ad_xor_xmit drivers/net/bonding/bond_main.c:5186 [inline] RIP: 0010:__bond_start_xmit drivers/net/bonding/bond_main.c:5442 [inline] RIP: 0010:bond_start_xmit+0x14ab/0x19d0 drivers/net/bonding/bond_main.c:5470 Code: 8b 7c 24 30 e8 76 dd 1a 01 48 85 c0 74 0d 48 89 c3 e8 29 67 2e fe e9 15 ef ff ff e8 1f 67 2e fe e9 10 ef ff ff e8 15 67 2e fe <0f> 0b e9 45 f8 ff ff e8 09 67 2e fe e9 dc fa ff ff e8 ff 66 2e fe RSP: 0018:ffffc90002fff6e0 EFLAGS: 00010283 RAX: ffffffff835874db RBX: 000000000000ffff RCX: 0000000000040000 RDX: ffffc90004dcf000 RSI: 00000000000000b5 RDI: 00000000000000b6 RBP: ffffc90002fff8b8 R08: ffffffff83586d16 R09: ffffffff83586584 R10: 0000000000000007 R11: ffff8881599fc780 R12: ffff88811b6a7b7e R13: 1ffff110236d4f6f R14: ffff88811b6a7ac0 R15: 1ffff110236d4f76 FS: 00007f2e9eb47700(0000) GS:ffff8881f6b00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000001b2e421000 CR3: 000000010e6d4000 CR4: 00000000003526e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: [] netdev_start_xmit include/linux/netdevice.h:4925 [inline] [] __dev_direct_xmit+0x4ef/0x850 net/core/dev.c:4380 [] dev_direct_xmit include/linux/netdevice.h:3043 [inline] [] packet_direct_xmit+0x18b/0x300 net/packet/af_packet.c:284 [] packet_snd net/packet/af_packet.c:3112 [inline] [] packet_sendmsg+0x4a22/0x64d0 net/packet/af_packet.c:3143 [] sock_sendmsg_nosec net/socket.c:716 [inline] [] sock_sendmsg net/socket.c:736 [inline] [] __sys_sendto+0x472/0x5f0 net/socket.c:2139 [] __do_sys_sendto net/socket.c:2151 [inline] [] __se_sys_sendto net/socket.c:2147 [inline] [] __x64_sys_sendto+0xe5/0x100 net/socket.c:2147 [] do_syscall_x64 arch/x86/entry/common.c:50 [inline] [] do_syscall_64+0x2f/0x50 arch/x86/entry/common.c:80 [] entry_SYSCALL_64_after_hwframe+0x63/0xcd Fixes: 7b8fc0103bb5 ("bonding: add a vlan+srcmac tx hashing option") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Jarod Wilson Cc: Moshe Tal Cc: Jussi Maki Cc: Jay Vosburgh Cc: Andy Gospodarek Cc: Vladimir Oltean Link: https://lore.kernel.org/r/20230622152304.2137482-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index edbaa1444f8e..091e035c76a6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4197,7 +4197,7 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb) return skb->hash; return __bond_xmit_hash(bond, skb, skb->data, skb->protocol, - skb_mac_offset(skb), skb_network_offset(skb), + 0, skb_network_offset(skb), skb_headlen(skb)); } -- cgit v1.2.3 From ebbd17ce297a3f367ca20058272063eaeeced63a Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Jun 2023 15:33:02 +0200 Subject: mlxsw: spectrum_router: Add extack argument to mlxsw_sp_lb_rif_init() The extack will be handy in later patches. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Link: https://lore.kernel.org/r/e87ba300121010d580b80a281877573a7b1377ca.1687438411.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 43e8f19c7a0a..0b1c17819388 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -10561,7 +10561,8 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); } -static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp) +static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp, + struct netlink_ext_ack *extack) { u16 lb_rif_index; int err; @@ -10674,7 +10675,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, if (err) goto err_vrs_init; - err = mlxsw_sp_lb_rif_init(mlxsw_sp); + err = mlxsw_sp_lb_rif_init(mlxsw_sp, extack); if (err) goto err_lb_rif_init; -- cgit v1.2.3 From f3c85eed1ac364ae2cb2729959c6150813cc9c20 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Jun 2023 15:33:03 +0200 Subject: mlxsw: spectrum_router: Use mlxsw_sp_ul_rif_get() to get main VRF LB RIF The current function, mlxsw_sp_router_ul_rif_get(), is a wrapper around the function mentioned in the subject. As such it forms an external interface of the router code. In future patches we will want to maintain connection between RIFs and the CRIFs (introduced in the next patch) that back them. That will not hold for the VRF-based loopback netdevices, so the whole CRIF business can be kept hidden from the rest of mlxsw. But for the main VRF loopback RIF we do want to keep the RIF-CRIF connection, because that RIF is used for blackhole next hops, and the next hop code can be kept simpler for assuming rif->crif is valid. Hence, instead, call mlxsw_sp_ul_rif_get() to create the main VRF loopback RIF. This being an internal function will take the CRIF argument anyway. Furthermore, the function does not lock, which is not necessary at this point in code yet. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Link: https://lore.kernel.org/r/7a39a011a02a84164cd7f5da7985ec5b2ae01ba5.1687438411.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 0b1c17819388..15ce0d557f39 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -10564,19 +10564,20 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp, struct netlink_ext_ack *extack) { - u16 lb_rif_index; + struct mlxsw_sp_rif *lb_rif; int err; /* Create a generic loopback RIF associated with the main table * (default VRF). Any table can be used, but the main table exists * anyway, so we do not waste resources. */ - err = mlxsw_sp_router_ul_rif_get(mlxsw_sp, RT_TABLE_MAIN, - &lb_rif_index); - if (err) + lb_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, RT_TABLE_MAIN, extack); + if (IS_ERR(lb_rif)) { + err = PTR_ERR(lb_rif); return err; + } - mlxsw_sp->router->lb_rif_index = lb_rif_index; + mlxsw_sp->router->lb_rif_index = lb_rif->rif_index; return 0; } -- cgit v1.2.3 From 4796c287b70a0f60fbc6a5df2ab33d92e8971732 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Jun 2023 15:33:04 +0200 Subject: mlxsw: spectrum_router: Maintain a hash table of CRIFs CRIFs are objects that mlxsw maintains for netdevices that may not have an associated RIF (i.e. they may not have been instantiated in the ASIC), but if indeed they do not, it is quite possible they will in the future. These netdevices are candidate RIFs, hence CRIFs. Netdevices for which CRIFs are created include e.g. bridges, LAGs, or front panel ports. The idea is that next hops would be kept at CRIFs, not RIFs, and thus it would be easier to offload and unoffload the entities that have been added before the RIF was created. In this patch, add the code for low-level CRIF maintenance: create and destroy, and keep in a table keyed by the netdevice pointer for easy recall. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Link: https://lore.kernel.org/r/186d44e399c475159da20689f2c540719f2d1ed0.1687438411.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 175 +++++++++++++++++++++ .../net/ethernet/mellanox/mlxsw/spectrum_router.h | 1 + 2 files changed, 176 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 15ce0d557f39..d251a926d140 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -51,6 +51,21 @@ struct mlxsw_sp_vr; struct mlxsw_sp_lpm_tree; struct mlxsw_sp_rif_ops; +struct mlxsw_sp_crif_key { + struct net_device *dev; +}; + +struct mlxsw_sp_crif { + struct mlxsw_sp_crif_key key; + struct rhash_head ht_node; +}; + +static const struct rhashtable_params mlxsw_sp_crif_ht_params = { + .key_offset = offsetof(struct mlxsw_sp_crif, key), + .key_len = sizeof_field(struct mlxsw_sp_crif, key), + .head_offset = offsetof(struct mlxsw_sp_crif, ht_node), +}; + struct mlxsw_sp_rif { struct list_head nexthop_list; struct list_head neigh_list; @@ -1060,6 +1075,56 @@ u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev) return tb_id; } +static void +mlxsw_sp_crif_init(struct mlxsw_sp_crif *crif, struct net_device *dev) +{ + crif->key.dev = dev; +} + +static struct mlxsw_sp_crif * +mlxsw_sp_crif_alloc(struct net_device *dev) +{ + struct mlxsw_sp_crif *crif; + + crif = kzalloc(sizeof(*crif), GFP_KERNEL); + if (!crif) + return NULL; + + mlxsw_sp_crif_init(crif, dev); + return crif; +} + +static void mlxsw_sp_crif_free(struct mlxsw_sp_crif *crif) +{ + kfree(crif); +} + +static int mlxsw_sp_crif_insert(struct mlxsw_sp_router *router, + struct mlxsw_sp_crif *crif) +{ + return rhashtable_insert_fast(&router->crif_ht, &crif->ht_node, + mlxsw_sp_crif_ht_params); +} + +static void mlxsw_sp_crif_remove(struct mlxsw_sp_router *router, + struct mlxsw_sp_crif *crif) +{ + rhashtable_remove_fast(&router->crif_ht, &crif->ht_node, + mlxsw_sp_crif_ht_params); +} + +static struct mlxsw_sp_crif * +mlxsw_sp_crif_lookup(struct mlxsw_sp_router *router, + const struct net_device *dev) +{ + struct mlxsw_sp_crif_key key = { + .dev = (struct net_device *)dev, + }; + + return rhashtable_lookup_fast(&router->crif_ht, &key, + mlxsw_sp_crif_ht_params); +} + static struct mlxsw_sp_rif * mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_rif_params *params, @@ -9148,6 +9213,95 @@ static int mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif *rif, return -ENOBUFS; } +static bool mlxsw_sp_router_netdevice_interesting(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev) +{ + struct vlan_dev_priv *vlan; + + if (netif_is_lag_master(dev) || + netif_is_bridge_master(dev) || + mlxsw_sp_port_dev_check(dev) || + mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev) || + netif_is_l3_master(dev)) + return true; + + if (!is_vlan_dev(dev)) + return false; + + vlan = vlan_dev_priv(dev); + return netif_is_lag_master(vlan->real_dev) || + netif_is_bridge_master(vlan->real_dev) || + mlxsw_sp_port_dev_check(vlan->real_dev); +} + +static struct mlxsw_sp_crif * +mlxsw_sp_crif_register(struct mlxsw_sp_router *router, struct net_device *dev) +{ + struct mlxsw_sp_crif *crif; + int err; + + if (WARN_ON(mlxsw_sp_crif_lookup(router, dev))) + return NULL; + + crif = mlxsw_sp_crif_alloc(dev); + if (!crif) + return ERR_PTR(-ENOMEM); + + err = mlxsw_sp_crif_insert(router, crif); + if (err) + goto err_netdev_insert; + + return crif; + +err_netdev_insert: + mlxsw_sp_crif_free(crif); + return ERR_PTR(err); +} + +static void mlxsw_sp_crif_unregister(struct mlxsw_sp_router *router, + struct mlxsw_sp_crif *crif) +{ + mlxsw_sp_crif_remove(router, crif); + mlxsw_sp_crif_free(crif); +} + +static int mlxsw_sp_netdevice_register(struct mlxsw_sp_router *router, + struct net_device *dev) +{ + struct mlxsw_sp_crif *crif; + + if (!mlxsw_sp_router_netdevice_interesting(router->mlxsw_sp, dev)) + return 0; + + crif = mlxsw_sp_crif_register(router, dev); + return PTR_ERR_OR_ZERO(crif); +} + +static void mlxsw_sp_netdevice_unregister(struct mlxsw_sp_router *router, + struct net_device *dev) +{ + struct mlxsw_sp_crif *crif; + + if (!mlxsw_sp_router_netdevice_interesting(router->mlxsw_sp, dev)) + return; + + /* netdev_run_todo(), by way of netdev_wait_allrefs_any(), rebroadcasts + * the NETDEV_UNREGISTER message, so we can get here twice. If that's + * what happened, the netdevice state is NETREG_UNREGISTERED. In that + * case, we expect to have collected the CRIF already, and warn if it + * still exists. Otherwise we expect the CRIF to exist. + */ + crif = mlxsw_sp_crif_lookup(router, dev); + if (dev->reg_state == NETREG_UNREGISTERED) { + if (!WARN_ON(crif)) + return; + } + if (WARN_ON(!crif)) + return; + + mlxsw_sp_crif_unregister(router, crif); +} + static bool mlxsw_sp_is_offload_xstats_event(unsigned long event) { switch (event) { @@ -9367,6 +9521,15 @@ static int mlxsw_sp_router_netdevice_event(struct notifier_block *nb, mutex_lock(&mlxsw_sp->router->lock); + if (event == NETDEV_REGISTER) { + err = mlxsw_sp_netdevice_register(router, dev); + if (err) + /* No need to roll this back, UNREGISTER will collect it + * anyhow. + */ + goto out; + } + if (mlxsw_sp_is_offload_xstats_event(event)) err = mlxsw_sp_netdevice_offload_xstats_cmd(mlxsw_sp, dev, event, ptr); @@ -9381,6 +9544,10 @@ static int mlxsw_sp_router_netdevice_event(struct notifier_block *nb, else if (mlxsw_sp_is_vrf_event(event, ptr)) err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr); + if (event == NETDEV_UNREGISTER) + mlxsw_sp_netdevice_unregister(router, dev); + +out: mutex_unlock(&mlxsw_sp->router->lock); return notifier_from_errno(err); @@ -10649,6 +10816,11 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, if (err) goto err_ipips_init; + err = rhashtable_init(&mlxsw_sp->router->crif_ht, + &mlxsw_sp_crif_ht_params); + if (err) + goto err_crif_ht_init; + err = mlxsw_sp_rifs_init(mlxsw_sp); if (err) goto err_rifs_init; @@ -10780,6 +10952,8 @@ err_nexthop_group_ht_init: err_nexthop_ht_init: mlxsw_sp_rifs_fini(mlxsw_sp); err_rifs_init: + rhashtable_destroy(&mlxsw_sp->router->crif_ht); +err_crif_ht_init: mlxsw_sp_ipips_fini(mlxsw_sp); err_ipips_init: __mlxsw_sp_router_fini(mlxsw_sp); @@ -10815,6 +10989,7 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) rhashtable_destroy(&router->nexthop_group_ht); rhashtable_destroy(&router->nexthop_ht); mlxsw_sp_rifs_fini(mlxsw_sp); + rhashtable_destroy(&mlxsw_sp->router->crif_ht); mlxsw_sp_ipips_fini(mlxsw_sp); __mlxsw_sp_router_fini(mlxsw_sp); cancel_delayed_work_sync(&router->nh_grp_activity_dw); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index 5a0babc614b4..b223e80303f5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -20,6 +20,7 @@ struct mlxsw_sp_router_nve_decap { struct mlxsw_sp_router { struct mlxsw_sp *mlxsw_sp; + struct rhashtable crif_ht; struct gen_pool *rifs_table; struct mlxsw_sp_rif **rifs; struct idr rif_mac_profiles_idr; -- cgit v1.2.3 From 78126cfd5dc97da7baf66415374452e3f8805faf Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Jun 2023 15:33:05 +0200 Subject: mlxsw: spectrum_router: Maintain CRIF for fallback loopback RIF CRIFs are generally not maintained for loopback RIFs. However, the RIF for the default VRF is used for offloading of blackhole nexthops. Nexthops expect to have a valid CRIF. Therefore in this patch, add code to maintain CRIF for the loopback RIF as well. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Link: https://lore.kernel.org/r/7f2b2fcc98770167ed1254a904c3f7f585ba43f0.1687438411.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 12 +++++++++++- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index d251a926d140..c4d538e0169e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -10731,9 +10731,14 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp, struct netlink_ext_ack *extack) { + struct mlxsw_sp_router *router = mlxsw_sp->router; struct mlxsw_sp_rif *lb_rif; int err; + router->lb_crif = mlxsw_sp_crif_alloc(NULL); + if (IS_ERR(router->lb_crif)) + return PTR_ERR(router->lb_crif); + /* Create a generic loopback RIF associated with the main table * (default VRF). Any table can be used, but the main table exists * anyway, so we do not waste resources. @@ -10741,17 +10746,22 @@ static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp, lb_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, RT_TABLE_MAIN, extack); if (IS_ERR(lb_rif)) { err = PTR_ERR(lb_rif); - return err; + goto err_ul_rif_get; } mlxsw_sp->router->lb_rif_index = lb_rif->rif_index; return 0; + +err_ul_rif_get: + mlxsw_sp_crif_free(router->lb_crif); + return err; } static void mlxsw_sp_lb_rif_fini(struct mlxsw_sp *mlxsw_sp) { mlxsw_sp_router_ul_rif_put(mlxsw_sp, mlxsw_sp->router->lb_rif_index); + mlxsw_sp_crif_free(mlxsw_sp->router->lb_crif); } static int mlxsw_sp1_router_init(struct mlxsw_sp *mlxsw_sp) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index b223e80303f5..0909cf229c86 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -61,6 +61,7 @@ struct mlxsw_sp_router { struct mutex lock; /* Protects shared router resources */ struct mlxsw_sp_fib_entry_op_ctx *ll_op_ctx; u16 lb_rif_index; + struct mlxsw_sp_crif *lb_crif; const struct mlxsw_sp_adj_grp_size_range *adj_grp_size_ranges; size_t adj_grp_size_ranges_count; struct delayed_work nh_grp_activity_dw; -- cgit v1.2.3 From aa21242b07a8cde689bb6aedcbc224eda9646d9f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Jun 2023 15:33:06 +0200 Subject: mlxsw: spectrum_router: Link CRIFs to RIFs When a RIF is about to be created, the registration of the netdevice that it should be associated with must have been seen in the past, and a CRIF created. Therefore make this a hard requirement by looking up the CRIF during RIF creation, and complaining loudly when there isn't one. This then allows to keep a link between a RIF and its corresponding CRIF (and back, as the relationship is one-to-at-most-one), which do. The CRIF will later be useful as the objects tracked there will be offloaded lazily as a result of RIF creation. CRIFs are created when an "interesting" netdevice is registered, and destroyed after such device is unregistered. CRIFs are supposed to already exist when a RIF creation request arises, and exist at least as long as that RIF exists. This makes for a simple invariant: it is always safe to dereference CRIF pointer from "its" RIF. To guarantee this, CRIFs cannot be removed immediately when the UNREGISTER event is delivered. The reason is that if a RIF's netdevices has an IPv6 address, removal of this address is notified in an atomic block. To remove the RIF, the IPv6 removal handler schedules a work item. It must be safe for this work item to access the associated CRIF as well. Thus when a netdevice that backs the CRIF is removed, if it still has a RIF, do not actually free the CRIF, only toggle its can_destroy flag, which this patch adds. Later on, mlxsw_sp_rif_destroy() collects the CRIF. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Link: https://lore.kernel.org/r/68c8e33afa6b8c03c431b435e1685ffdff752e63.1687438411.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 59 +++++++++++++++++----- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index c4d538e0169e..daa59fc59d3b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -58,6 +58,8 @@ struct mlxsw_sp_crif_key { struct mlxsw_sp_crif { struct mlxsw_sp_crif_key key; struct rhash_head ht_node; + bool can_destroy; + struct mlxsw_sp_rif *rif; }; static const struct rhashtable_params mlxsw_sp_crif_ht_params = { @@ -67,9 +69,9 @@ static const struct rhashtable_params mlxsw_sp_crif_ht_params = { }; struct mlxsw_sp_rif { + struct mlxsw_sp_crif *crif; /* NULL for underlay RIF */ struct list_head nexthop_list; struct list_head neigh_list; - struct net_device *dev; /* NULL for underlay RIF */ struct mlxsw_sp_fid *fid; unsigned char addr[ETH_ALEN]; int mtu; @@ -88,7 +90,9 @@ struct mlxsw_sp_rif { static struct net_device *mlxsw_sp_rif_dev(const struct mlxsw_sp_rif *rif) { - return rif->dev; + if (!rif->crif) + return NULL; + return rif->crif->key.dev; } struct mlxsw_sp_rif_params { @@ -1096,6 +1100,9 @@ mlxsw_sp_crif_alloc(struct net_device *dev) static void mlxsw_sp_crif_free(struct mlxsw_sp_crif *crif) { + if (WARN_ON(crif->rif)) + return; + kfree(crif); } @@ -7970,8 +7977,9 @@ static void mlxsw_sp_rif_index_free(struct mlxsw_sp *mlxsw_sp, u16 rif_index, static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, u16 vr_id, - struct net_device *l3_dev) + struct mlxsw_sp_crif *crif) { + struct net_device *l3_dev = crif ? crif->key.dev : NULL; struct mlxsw_sp_rif *rif; rif = kzalloc(rif_size, GFP_KERNEL); @@ -7983,10 +7991,13 @@ static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, if (l3_dev) { ether_addr_copy(rif->addr, l3_dev->dev_addr); rif->mtu = l3_dev->mtu; - rif->dev = l3_dev; } rif->vr_id = vr_id; rif->rif_index = rif_index; + if (crif) { + rif->crif = crif; + crif->rif = rif; + } return rif; } @@ -7995,6 +8006,9 @@ static void mlxsw_sp_rif_free(struct mlxsw_sp_rif *rif) { WARN_ON(!list_empty(&rif->neigh_list)); WARN_ON(!list_empty(&rif->nexthop_list)); + + if (rif->crif) + rif->crif->rif = NULL; kfree(rif); } @@ -8228,6 +8242,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_rif_ops *ops; struct mlxsw_sp_fid *fid = NULL; enum mlxsw_sp_rif_type type; + struct mlxsw_sp_crif *crif; struct mlxsw_sp_rif *rif; struct mlxsw_sp_vr *vr; u16 rif_index; @@ -8247,7 +8262,13 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp, goto err_rif_index_alloc; } - rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, params->dev); + crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, params->dev); + if (WARN_ON(!crif)) { + err = -ENOENT; + goto err_crif_lookup; + } + + rif = mlxsw_sp_rif_alloc(ops->rif_size, rif_index, vr->id, crif); if (!rif) { err = -ENOMEM; goto err_rif_alloc; @@ -8306,6 +8327,7 @@ err_fid_get: dev_put(params->dev); mlxsw_sp_rif_free(rif); err_rif_alloc: +err_crif_lookup: mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries); err_rif_index_alloc: vr->rif_count--; @@ -8318,6 +8340,7 @@ static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) struct net_device *dev = mlxsw_sp_rif_dev(rif); const struct mlxsw_sp_rif_ops *ops = rif->ops; struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp; + struct mlxsw_sp_crif *crif = rif->crif; struct mlxsw_sp_fid *fid = rif->fid; u8 rif_entries = rif->rif_entries; u16 rif_index = rif->rif_index; @@ -8348,6 +8371,9 @@ static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) mlxsw_sp_rif_index_free(mlxsw_sp, rif_index, rif_entries); vr->rif_count--; mlxsw_sp_vr_put(mlxsw_sp, vr); + + if (crif->can_destroy) + mlxsw_sp_crif_free(crif); } void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, @@ -9262,7 +9288,10 @@ static void mlxsw_sp_crif_unregister(struct mlxsw_sp_router *router, struct mlxsw_sp_crif *crif) { mlxsw_sp_crif_remove(router, crif); - mlxsw_sp_crif_free(crif); + if (crif->rif) + crif->can_destroy = true; + else + mlxsw_sp_crif_free(crif); } static int mlxsw_sp_netdevice_register(struct mlxsw_sp_router *router, @@ -10068,6 +10097,7 @@ mlxsw_sp_rif_ipip_lb_ul_rif_op(struct mlxsw_sp_rif *ul_rif, bool enable) static struct mlxsw_sp_rif * mlxsw_sp_ul_rif_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr, + struct mlxsw_sp_crif *ul_crif, struct netlink_ext_ack *extack) { struct mlxsw_sp_rif *ul_rif; @@ -10081,7 +10111,8 @@ mlxsw_sp_ul_rif_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr, return ERR_PTR(err); } - ul_rif = mlxsw_sp_rif_alloc(sizeof(*ul_rif), rif_index, vr->id, NULL); + ul_rif = mlxsw_sp_rif_alloc(sizeof(*ul_rif), rif_index, vr->id, + ul_crif); if (!ul_rif) { err = -ENOMEM; goto err_rif_alloc; @@ -10120,6 +10151,7 @@ static void mlxsw_sp_ul_rif_destroy(struct mlxsw_sp_rif *ul_rif) static struct mlxsw_sp_rif * mlxsw_sp_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, + struct mlxsw_sp_crif *ul_crif, struct netlink_ext_ack *extack) { struct mlxsw_sp_vr *vr; @@ -10132,7 +10164,7 @@ mlxsw_sp_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 tb_id, if (refcount_inc_not_zero(&vr->ul_rif_refcnt)) return vr->ul_rif; - vr->ul_rif = mlxsw_sp_ul_rif_create(mlxsw_sp, vr, extack); + vr->ul_rif = mlxsw_sp_ul_rif_create(mlxsw_sp, vr, ul_crif, extack); if (IS_ERR(vr->ul_rif)) { err = PTR_ERR(vr->ul_rif); goto err_ul_rif_create; @@ -10170,7 +10202,7 @@ int mlxsw_sp_router_ul_rif_get(struct mlxsw_sp *mlxsw_sp, u32 ul_tb_id, int err = 0; mutex_lock(&mlxsw_sp->router->lock); - ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL); + ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL, NULL); if (IS_ERR(ul_rif)) { err = PTR_ERR(ul_rif); goto out; @@ -10206,7 +10238,7 @@ mlxsw_sp2_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif, struct mlxsw_sp_rif *ul_rif; int err; - ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, extack); + ul_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, ul_tb_id, NULL, extack); if (IS_ERR(ul_rif)) return PTR_ERR(ul_rif); @@ -10741,9 +10773,12 @@ static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp, /* Create a generic loopback RIF associated with the main table * (default VRF). Any table can be used, but the main table exists - * anyway, so we do not waste resources. + * anyway, so we do not waste resources. Loopback RIFs are usually + * created with a NULL CRIF, but this RIF is used as a fallback RIF + * for blackhole nexthops, and nexthops expect to have a valid CRIF. */ - lb_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, RT_TABLE_MAIN, extack); + lb_rif = mlxsw_sp_ul_rif_get(mlxsw_sp, RT_TABLE_MAIN, router->lb_crif, + extack); if (IS_ERR(lb_rif)) { err = PTR_ERR(lb_rif); goto err_ul_rif_get; -- cgit v1.2.3 From bdc0b78e79a641fbbb928a9e5da56dbdd42ff674 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Jun 2023 15:33:07 +0200 Subject: mlxsw: spectrum_router: Use router.lb_crif instead of .lb_rif_index A previous patch added a pointer to loopback CRIF to the router data structure. That makes the loopback RIF index redundant, as everything necessary can be derived from the CRIF. Drop the field and adjust the code accordingly. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Link: https://lore.kernel.org/r/8637bf959bc5b6c9d5184b9bd8a0cd53c5132835.1687438411.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 12 ++++-------- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index daa59fc59d3b..acd6f1b5eef9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3563,7 +3563,7 @@ static int __mlxsw_sp_nexthop_eth_update(struct mlxsw_sp *mlxsw_sp, u16 rif_index; rif_index = nh->rif ? nh->rif->rif_index : - mlxsw_sp->router->lb_rif_index; + mlxsw_sp->router->lb_crif->rif->rif_index; op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY : MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY; mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_ETHERNET, @@ -4530,7 +4530,7 @@ static int mlxsw_sp_adj_trap_entry_init(struct mlxsw_sp *mlxsw_sp) mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true, MLXSW_REG_RATR_TYPE_ETHERNET, mlxsw_sp->router->adj_trap_index, - mlxsw_sp->router->lb_rif_index); + mlxsw_sp->router->lb_crif->rif->rif_index); mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action); mlxsw_reg_ratr_trap_id_set(ratr_pl, MLXSW_TRAP_ID_RTR_EGRESS0); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); @@ -4846,15 +4846,13 @@ static bool mlxsw_sp_nexthop_obj_is_gateway(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_nexthop_obj_blackhole_init(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { - u16 lb_rif_index = mlxsw_sp->router->lb_rif_index; - nh->action = MLXSW_SP_NEXTHOP_ACTION_DISCARD; nh->should_offload = 1; /* While nexthops that discard packets do not forward packets * via an egress RIF, they still need to be programmed using a * valid RIF, so use the loopback RIF created during init. */ - nh->rif = mlxsw_sp->router->rifs[lb_rif_index]; + nh->rif = mlxsw_sp->router->lb_crif->rif; } static void mlxsw_sp_nexthop_obj_blackhole_fini(struct mlxsw_sp *mlxsw_sp, @@ -10784,8 +10782,6 @@ static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp, goto err_ul_rif_get; } - mlxsw_sp->router->lb_rif_index = lb_rif->rif_index; - return 0; err_ul_rif_get: @@ -10795,7 +10791,7 @@ err_ul_rif_get: static void mlxsw_sp_lb_rif_fini(struct mlxsw_sp *mlxsw_sp) { - mlxsw_sp_router_ul_rif_put(mlxsw_sp, mlxsw_sp->router->lb_rif_index); + mlxsw_sp_ul_rif_put(mlxsw_sp->router->lb_crif->rif); mlxsw_sp_crif_free(mlxsw_sp->router->lb_crif); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h index 0909cf229c86..9a2669a08480 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h @@ -60,7 +60,6 @@ struct mlxsw_sp_router { struct mlxsw_sp_router_nve_decap nve_decap_config; struct mutex lock; /* Protects shared router resources */ struct mlxsw_sp_fib_entry_op_ctx *ll_op_ctx; - u16 lb_rif_index; struct mlxsw_sp_crif *lb_crif; const struct mlxsw_sp_adj_grp_size_range *adj_grp_size_ranges; size_t adj_grp_size_ranges_count; -- cgit v1.2.3 From a285d664236eb0655eea0ceb97095ad4b07fcbae Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Jun 2023 15:33:08 +0200 Subject: mlxsw: spectrum_router: Split nexthop finalization to two stages Nexthop finalization consists of two steps: the part where the offload is removed, because the backing RIF is now gone; and the part where the association to the RIF is severed. Extract from mlxsw_sp_nexthop_type_fini() a helper that covers the unoffloading part, mlxsw_sp_nexthop_type_rif_gone(), so that it can later be called independently. Note that this swaps around the ordering of mlxsw_sp_nexthop_ipip_fini() vs. mlxsw_sp_nexthop_rif_fini(). The current ordering is more of a historical happenstance than a conscious decision. The two cleanups do not depend on each other, and this change should have no observable effects. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Link: https://lore.kernel.org/r/7134559534c5f5c4807c3a1569fae56f8887e763.1687438411.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index acd6f1b5eef9..6c9244c35192 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -4369,21 +4369,26 @@ err_neigh_init: return err; } -static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_nexthop *nh) +static void mlxsw_sp_nexthop_type_rif_gone(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nexthop *nh) { switch (nh->type) { case MLXSW_SP_NEXTHOP_TYPE_ETH: mlxsw_sp_nexthop_neigh_fini(mlxsw_sp, nh); - mlxsw_sp_nexthop_rif_fini(nh); break; case MLXSW_SP_NEXTHOP_TYPE_IPIP: - mlxsw_sp_nexthop_rif_fini(nh); mlxsw_sp_nexthop_ipip_fini(mlxsw_sp, nh); break; } } +static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_nexthop *nh) +{ + mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh); + mlxsw_sp_nexthop_rif_fini(nh); +} + static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop_group *nh_grp, struct mlxsw_sp_nexthop *nh, -- cgit v1.2.3 From 9464a3d68ea99ccac7e3518e1dfd366ac80bbc90 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 22 Jun 2023 15:33:09 +0200 Subject: mlxsw: spectrum_router: Track next hops at CRIFs Move the list of next hops from struct mlxsw_sp_rif to mlxsw_sp_crif. The reason is that eventually, next hops for mlxsw uppers should be offloaded and unoffloaded on demand as a netdevice becomes an upper, or stops being one. Currently, next hops are tracked at RIFs, but RIFs do not exist when a netdevice is not an mlxsw uppers. CRIFs are kept track of throughout the netdevice lifetime. Correspondingly, track at each next hop not its RIF, but its CRIF (from which a RIF can always be deduced). Note that now that next hops are tracked at a CRIF, it is not necessary to move each over to a new RIF when it is necessary to edit a RIF. Therefore drop mlxsw_sp_nexthop_rif_migrate() and have mlxsw_sp_rif_migrate_destroy() call mlxsw_sp_nexthop_rif_update() directly. Signed-off-by: Petr Machata Reviewed-by: Danielle Ratson Link: https://lore.kernel.org/r/e7c1c0a7dd13883b0f09aeda12c4fcf4d63a70e3.1687438411.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 127 ++++++++++++--------- 1 file changed, 75 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 6c9244c35192..445ba7fe3c40 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -59,6 +59,7 @@ struct mlxsw_sp_crif { struct mlxsw_sp_crif_key key; struct rhash_head ht_node; bool can_destroy; + struct list_head nexthop_list; struct mlxsw_sp_rif *rif; }; @@ -70,7 +71,6 @@ static const struct rhashtable_params mlxsw_sp_crif_ht_params = { struct mlxsw_sp_rif { struct mlxsw_sp_crif *crif; /* NULL for underlay RIF */ - struct list_head nexthop_list; struct list_head neigh_list; struct mlxsw_sp_fid *fid; unsigned char addr[ETH_ALEN]; @@ -1083,6 +1083,7 @@ static void mlxsw_sp_crif_init(struct mlxsw_sp_crif *crif, struct net_device *dev) { crif->key.dev = dev; + INIT_LIST_HEAD(&crif->nexthop_list); } static struct mlxsw_sp_crif * @@ -1103,6 +1104,7 @@ static void mlxsw_sp_crif_free(struct mlxsw_sp_crif *crif) if (WARN_ON(crif->rif)) return; + WARN_ON(!list_empty(&crif->nexthop_list)); kfree(crif); } @@ -1720,17 +1722,26 @@ static void mlxsw_sp_netdevice_ipip_ol_down_event(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_ipip_entry_ol_down_event(mlxsw_sp, ipip_entry); } -static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *old_rif, - struct mlxsw_sp_rif *new_rif); +static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_rif *rif); + static void mlxsw_sp_rif_migrate_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *old_rif, struct mlxsw_sp_rif *new_rif, bool migrate_nhs) { + struct mlxsw_sp_crif *crif = old_rif->crif; + struct mlxsw_sp_crif mock_crif = {}; + if (migrate_nhs) - mlxsw_sp_nexthop_rif_migrate(mlxsw_sp, old_rif, new_rif); + mlxsw_sp_nexthop_rif_update(mlxsw_sp, new_rif); + /* Plant a mock CRIF so that destroying the old RIF doesn't unoffload + * our nexthops and IPIP tunnels, and doesn't sever the crif->rif link. + */ + mlxsw_sp_crif_init(&mock_crif, crif->key.dev); + old_rif->crif = &mock_crif; + mock_crif.rif = old_rif; mlxsw_sp_rif_destroy(old_rif); } @@ -1756,9 +1767,6 @@ mlxsw_sp_ipip_entry_ol_lb_update(struct mlxsw_sp *mlxsw_sp, return 0; } -static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif); - /** * __mlxsw_sp_ipip_entry_update_tunnel - Update offload related to IPIP entry. * @mlxsw_sp: mlxsw_sp. @@ -2987,7 +2995,7 @@ struct mlxsw_sp_nexthop_key { struct mlxsw_sp_nexthop { struct list_head neigh_list_node; /* member of neigh entry list */ - struct list_head rif_list_node; + struct list_head crif_list_node; struct list_head router_list_node; struct mlxsw_sp_nexthop_group_info *nhgi; /* pointer back to the group * this nexthop belongs to @@ -3000,7 +3008,7 @@ struct mlxsw_sp_nexthop { int nh_weight; int norm_nh_weight; int num_adj_entries; - struct mlxsw_sp_rif *rif; + struct mlxsw_sp_crif *crif; u8 should_offload:1, /* set indicates this nexthop should be written * to the adjacency table. */ @@ -3023,9 +3031,9 @@ struct mlxsw_sp_nexthop { static struct net_device * mlxsw_sp_nexthop_dev(const struct mlxsw_sp_nexthop *nh) { - if (nh->rif) - return mlxsw_sp_rif_dev(nh->rif); - return NULL; + if (!nh->crif) + return NULL; + return nh->crif->key.dev; } enum mlxsw_sp_nexthop_group_type { @@ -3050,7 +3058,11 @@ struct mlxsw_sp_nexthop_group_info { static struct mlxsw_sp_rif * mlxsw_sp_nhgi_rif(const struct mlxsw_sp_nexthop_group_info *nhgi) { - return nhgi->nexthops[0].rif; + struct mlxsw_sp_crif *crif = nhgi->nexthops[0].crif; + + if (!crif) + return NULL; + return crif->rif; } struct mlxsw_sp_nexthop_group_vr_key { @@ -3174,7 +3186,9 @@ int mlxsw_sp_nexthop_indexes(struct mlxsw_sp_nexthop *nh, u32 *p_adj_index, struct mlxsw_sp_rif *mlxsw_sp_nexthop_rif(struct mlxsw_sp_nexthop *nh) { - return nh->rif; + if (WARN_ON(!nh->crif)) + return NULL; + return nh->crif->rif; } bool mlxsw_sp_nexthop_group_has_ipip(struct mlxsw_sp_nexthop *nh) @@ -3559,11 +3573,12 @@ static int __mlxsw_sp_nexthop_eth_update(struct mlxsw_sp *mlxsw_sp, bool force, char *ratr_pl) { struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry; + struct mlxsw_sp_rif *rif = mlxsw_sp_nexthop_rif(nh); enum mlxsw_reg_ratr_op op; u16 rif_index; - rif_index = nh->rif ? nh->rif->rif_index : - mlxsw_sp->router->lb_crif->rif->rif_index; + rif_index = rif ? rif->rif_index : + mlxsw_sp->router->lb_crif->rif->rif_index; op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY : MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY; mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_ETHERNET, @@ -4181,23 +4196,23 @@ mlxsw_sp_nexthop_neigh_update(struct mlxsw_sp *mlxsw_sp, } } -static void mlxsw_sp_nexthop_rif_init(struct mlxsw_sp_nexthop *nh, - struct mlxsw_sp_rif *rif) +static void mlxsw_sp_nexthop_crif_init(struct mlxsw_sp_nexthop *nh, + struct mlxsw_sp_crif *crif) { - if (nh->rif) + if (nh->crif) return; - nh->rif = rif; - list_add(&nh->rif_list_node, &rif->nexthop_list); + nh->crif = crif; + list_add(&nh->crif_list_node, &crif->nexthop_list); } -static void mlxsw_sp_nexthop_rif_fini(struct mlxsw_sp_nexthop *nh) +static void mlxsw_sp_nexthop_crif_fini(struct mlxsw_sp_nexthop *nh) { - if (!nh->rif) + if (!nh->crif) return; - list_del(&nh->rif_list_node); - nh->rif = NULL; + list_del(&nh->crif_list_node); + nh->crif = NULL; } static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp, @@ -4209,6 +4224,9 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp, u8 nud_state, dead; int err; + if (WARN_ON(!nh->crif->rif)) + return 0; + if (!nh->nhgi->gateway || nh->neigh_entry) return 0; dev = mlxsw_sp_nexthop_dev(nh); @@ -4299,15 +4317,20 @@ static void mlxsw_sp_nexthop_ipip_init(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh, struct mlxsw_sp_ipip_entry *ipip_entry) { + struct mlxsw_sp_crif *crif; bool removing; if (!nh->nhgi->gateway || nh->ipip_entry) return; + crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, ipip_entry->ol_dev); + if (WARN_ON(!crif)) + return; + nh->ipip_entry = ipip_entry; removing = !mlxsw_sp_ipip_netdev_ul_up(ipip_entry->ol_dev); __mlxsw_sp_nexthop_neigh_update(nh, removing); - mlxsw_sp_nexthop_rif_init(nh, &ipip_entry->ol_lb->common); + mlxsw_sp_nexthop_crif_init(nh, crif); } static void mlxsw_sp_nexthop_ipip_fini(struct mlxsw_sp *mlxsw_sp, @@ -4339,7 +4362,7 @@ static int mlxsw_sp_nexthop_type_init(struct mlxsw_sp *mlxsw_sp, { const struct mlxsw_sp_ipip_ops *ipip_ops; struct mlxsw_sp_ipip_entry *ipip_entry; - struct mlxsw_sp_rif *rif; + struct mlxsw_sp_crif *crif; int err; ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, dev); @@ -4353,11 +4376,15 @@ static int mlxsw_sp_nexthop_type_init(struct mlxsw_sp *mlxsw_sp, } nh->type = MLXSW_SP_NEXTHOP_TYPE_ETH; - rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); - if (!rif) + crif = mlxsw_sp_crif_lookup(mlxsw_sp->router, dev); + if (!crif) + return 0; + + mlxsw_sp_nexthop_crif_init(nh, crif); + + if (!crif->rif) return 0; - mlxsw_sp_nexthop_rif_init(nh, rif); err = mlxsw_sp_nexthop_neigh_init(mlxsw_sp, nh); if (err) goto err_neigh_init; @@ -4365,7 +4392,7 @@ static int mlxsw_sp_nexthop_type_init(struct mlxsw_sp *mlxsw_sp, return 0; err_neigh_init: - mlxsw_sp_nexthop_rif_fini(nh); + mlxsw_sp_nexthop_crif_fini(nh); return err; } @@ -4386,7 +4413,7 @@ static void mlxsw_sp_nexthop_type_fini(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh); - mlxsw_sp_nexthop_rif_fini(nh); + mlxsw_sp_nexthop_crif_fini(nh); } static int mlxsw_sp_nexthop4_init(struct mlxsw_sp *mlxsw_sp, @@ -4479,7 +4506,7 @@ static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh; bool removing; - list_for_each_entry(nh, &rif->nexthop_list, rif_list_node) { + list_for_each_entry(nh, &rif->crif->nexthop_list, crif_list_node) { switch (nh->type) { case MLXSW_SP_NEXTHOP_TYPE_ETH: removing = false; @@ -4497,25 +4524,14 @@ static void mlxsw_sp_nexthop_rif_update(struct mlxsw_sp *mlxsw_sp, } } -static void mlxsw_sp_nexthop_rif_migrate(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *old_rif, - struct mlxsw_sp_rif *new_rif) -{ - struct mlxsw_sp_nexthop *nh; - - list_splice_init(&old_rif->nexthop_list, &new_rif->nexthop_list); - list_for_each_entry(nh, &new_rif->nexthop_list, rif_list_node) - nh->rif = new_rif; - mlxsw_sp_nexthop_rif_update(mlxsw_sp, new_rif); -} - static void mlxsw_sp_nexthop_rif_gone_sync(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif) { struct mlxsw_sp_nexthop *nh, *tmp; - list_for_each_entry_safe(nh, tmp, &rif->nexthop_list, rif_list_node) { - mlxsw_sp_nexthop_type_fini(mlxsw_sp, nh); + list_for_each_entry_safe(nh, tmp, &rif->crif->nexthop_list, + crif_list_node) { + mlxsw_sp_nexthop_type_rif_gone(mlxsw_sp, nh); mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh->nhgi->nh_grp); } } @@ -4857,13 +4873,13 @@ static void mlxsw_sp_nexthop_obj_blackhole_init(struct mlxsw_sp *mlxsw_sp, * via an egress RIF, they still need to be programmed using a * valid RIF, so use the loopback RIF created during init. */ - nh->rif = mlxsw_sp->router->lb_crif->rif; + nh->crif = mlxsw_sp->router->lb_crif; } static void mlxsw_sp_nexthop_obj_blackhole_fini(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_nexthop *nh) { - nh->rif = NULL; + nh->crif = NULL; nh->should_offload = 0; } @@ -7871,6 +7887,9 @@ static int mlxsw_sp_router_rif_disable(struct mlxsw_sp *mlxsw_sp, u16 rif) static void mlxsw_sp_router_rif_gone_sync(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif) { + /* Signal to nexthop cleanup that the RIF is going away. */ + rif->crif->rif = NULL; + mlxsw_sp_router_rif_disable(mlxsw_sp, rif->rif_index); mlxsw_sp_nexthop_rif_gone_sync(mlxsw_sp, rif); mlxsw_sp_neigh_rif_gone_sync(mlxsw_sp, rif); @@ -7989,7 +8008,6 @@ static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, if (!rif) return NULL; - INIT_LIST_HEAD(&rif->nexthop_list); INIT_LIST_HEAD(&rif->neigh_list); if (l3_dev) { ether_addr_copy(rif->addr, l3_dev->dev_addr); @@ -8008,7 +8026,6 @@ static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index, static void mlxsw_sp_rif_free(struct mlxsw_sp_rif *rif) { WARN_ON(!list_empty(&rif->neigh_list)); - WARN_ON(!list_empty(&rif->nexthop_list)); if (rif->crif) rif->crif->rif = NULL; @@ -9290,7 +9307,13 @@ err_netdev_insert: static void mlxsw_sp_crif_unregister(struct mlxsw_sp_router *router, struct mlxsw_sp_crif *crif) { + struct mlxsw_sp_nexthop *nh, *tmp; + mlxsw_sp_crif_remove(router, crif); + + list_for_each_entry_safe(nh, tmp, &crif->nexthop_list, crif_list_node) + mlxsw_sp_nexthop_type_fini(router->mlxsw_sp, nh); + if (crif->rif) crif->can_destroy = true; else -- cgit v1.2.3 From 28e219aea0b9ec374de27179c3d45b2d86bfe562 Mon Sep 17 00:00:00 2001 From: Giulio Benetti Date: Thu, 22 Jun 2023 20:47:21 +0200 Subject: net: phy: broadcom: drop brcm_phy_setbits() and use phy_set_bits() instead Linux provides phy_set_bits() helper so let's drop brcm_phy_setbits() and use phy_set_bits() in its place. Signed-off-by: Giulio Benetti Reviewed-by: Simon Horman Reviewed-by: Florian Fainelli Link: https://lore.kernel.org/r/20230622184721.24368-1-giulio.benetti@benettiengineering.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/broadcom.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 9f0a9c575bd7..59cae0d808aa 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -664,17 +664,6 @@ static int bcm54616s_read_status(struct phy_device *phydev) return err; } -static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) -{ - int val; - - val = phy_read(phydev, reg); - if (val < 0) - return val; - - return phy_write(phydev, reg, val | set); -} - static int brcm_fet_config_init(struct phy_device *phydev) { int reg, err, err2, brcmtest; @@ -745,15 +734,15 @@ static int brcm_fet_config_init(struct phy_device *phydev) goto done; /* Enable auto MDIX */ - err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, - MII_BRCM_FET_SHDW_MC_FAME); + err = phy_set_bits(phydev, MII_BRCM_FET_SHDW_MISCCTRL, + MII_BRCM_FET_SHDW_MC_FAME); if (err < 0) goto done; if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) { /* Enable auto power down */ - err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, - MII_BRCM_FET_SHDW_AS2_APDE); + err = phy_set_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2, + MII_BRCM_FET_SHDW_AS2_APDE); } done: -- cgit v1.2.3 From 6a11af7c21da0fdbba101452ddeec2dbe289b174 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 22 Jun 2023 08:54:09 -0700 Subject: revert "s390/net: lcs: use IS_ENABLED() for kconfig detection" The referenced patch is causing build errors when ETHERNET=y and FDDI=m. While we work out the preferred patch(es), revert this patch to make the pain go away. Fixes: 128272336120 ("s390/net: lcs: use IS_ENABLED() for kconfig detection") Signed-off-by: Randy Dunlap Reported-by: kernel test robot Link: lore.kernel.org/r/202306202129.pl0AqK8G-lkp@intel.com Cc: Alexandra Winter Cc: Wenjia Zhang Cc: Heiko Carstens Cc: Vasily Gorbik Cc: Alexander Gordeev Cc: Christian Borntraeger Cc: Sven Schnelle Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230622155409.27311-1-rdunlap@infradead.org Signed-off-by: Jakub Kicinski --- drivers/s390/net/lcs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index a473d46ad668..9fd8e6f07a03 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -36,7 +36,7 @@ #include "lcs.h" -#if !IS_ENABLED(CONFIG_ETHERNET) && !IS_ENABLED(CONFIG_FDDI) +#if !defined(CONFIG_ETHERNET) && !defined(CONFIG_FDDI) #error Cannot compile lcs.c without some net devices switched on. #endif @@ -1601,14 +1601,14 @@ lcs_startlan_auto(struct lcs_card *card) int rc; LCS_DBF_TEXT(2, trace, "strtauto"); -#if IS_ENABLED(CONFIG_ETHERNET) +#ifdef CONFIG_ETHERNET card->lan_type = LCS_FRAME_TYPE_ENET; rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); if (rc == 0) return 0; #endif -#if IS_ENABLED(CONFIG_FDDI) +#ifdef CONFIG_FDDI card->lan_type = LCS_FRAME_TYPE_FDDI; rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); if (rc == 0) @@ -2140,13 +2140,13 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) goto netdev_out; } switch (card->lan_type) { -#if IS_ENABLED(CONFIG_ETHERNET) +#ifdef CONFIG_ETHERNET case LCS_FRAME_TYPE_ENET: card->lan_type_trans = eth_type_trans; dev = alloc_etherdev(0); break; #endif -#if IS_ENABLED(CONFIG_FDDI) +#ifdef CONFIG_FDDI case LCS_FRAME_TYPE_FDDI: card->lan_type_trans = fddi_type_trans; dev = alloc_fddidev(0); -- cgit v1.2.3 From 11b73313c12403f617b47752db0ab3deef201af7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 22 Jun 2023 18:15:03 +0000 Subject: sch_netem: fix issues in netem_change() vs get_dist_table() In blamed commit, I missed that get_dist_table() was allocating memory using GFP_KERNEL, and acquiring qdisc lock to perform the swap of newly allocated table with current one. In this patch, get_dist_table() is allocating memory and copy user data before we acquire the qdisc lock. Then we perform swap operations while being protected by the lock. Note that after this patch netem_change() no longer can do partial changes. If an error is returned, qdisc conf is left unchanged. Fixes: 2174a08db80d ("sch_netem: acquire qdisc lock in netem_change()") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Stephen Hemminger Acked-by: Jamal Hadi Salim Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230622181503.2327695-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/sched/sch_netem.c | 59 ++++++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index e79be1b3e74d..b93ec2a3454e 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -773,12 +773,10 @@ static void dist_free(struct disttable *d) * signed 16 bit values. */ -static int get_dist_table(struct Qdisc *sch, struct disttable **tbl, - const struct nlattr *attr) +static int get_dist_table(struct disttable **tbl, const struct nlattr *attr) { size_t n = nla_len(attr)/sizeof(__s16); const __s16 *data = nla_data(attr); - spinlock_t *root_lock; struct disttable *d; int i; @@ -793,13 +791,7 @@ static int get_dist_table(struct Qdisc *sch, struct disttable **tbl, for (i = 0; i < n; i++) d->table[i] = data[i]; - root_lock = qdisc_root_sleeping_lock(sch); - - spin_lock_bh(root_lock); - swap(*tbl, d); - spin_unlock_bh(root_lock); - - dist_free(d); + *tbl = d; return 0; } @@ -956,6 +948,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, { struct netem_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_NETEM_MAX + 1]; + struct disttable *delay_dist = NULL; + struct disttable *slot_dist = NULL; struct tc_netem_qopt *qopt; struct clgstate old_clg; int old_loss_model = CLG_RANDOM; @@ -966,6 +960,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, if (ret < 0) return ret; + if (tb[TCA_NETEM_DELAY_DIST]) { + ret = get_dist_table(&delay_dist, tb[TCA_NETEM_DELAY_DIST]); + if (ret) + goto table_free; + } + + if (tb[TCA_NETEM_SLOT_DIST]) { + ret = get_dist_table(&slot_dist, tb[TCA_NETEM_SLOT_DIST]); + if (ret) + goto table_free; + } + sch_tree_lock(sch); /* backup q->clg and q->loss_model */ old_clg = q->clg; @@ -975,26 +981,17 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]); if (ret) { q->loss_model = old_loss_model; + q->clg = old_clg; goto unlock; } } else { q->loss_model = CLG_RANDOM; } - if (tb[TCA_NETEM_DELAY_DIST]) { - ret = get_dist_table(sch, &q->delay_dist, - tb[TCA_NETEM_DELAY_DIST]); - if (ret) - goto get_table_failure; - } - - if (tb[TCA_NETEM_SLOT_DIST]) { - ret = get_dist_table(sch, &q->slot_dist, - tb[TCA_NETEM_SLOT_DIST]); - if (ret) - goto get_table_failure; - } - + if (delay_dist) + swap(q->delay_dist, delay_dist); + if (slot_dist) + swap(q->slot_dist, slot_dist); sch->limit = qopt->limit; q->latency = PSCHED_TICKS2NS(qopt->latency); @@ -1044,17 +1041,11 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, unlock: sch_tree_unlock(sch); - return ret; -get_table_failure: - /* recover clg and loss_model, in case of - * q->clg and q->loss_model were modified - * in get_loss_clg() - */ - q->clg = old_clg; - q->loss_model = old_loss_model; - - goto unlock; +table_free: + dist_free(delay_dist); + dist_free(slot_dist); + return ret; } static int netem_init(struct Qdisc *sch, struct nlattr *opt, -- cgit v1.2.3 From 3f5f118bb657f94641ea383c7c1b8c09a5d46ea2 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 22 Jun 2023 11:43:51 -0700 Subject: af_unix: Call scm_recv() only after scm_set_cred(). syzkaller hit a WARN_ON_ONCE(!scm->pid) in scm_pidfd_recv(). In unix_stream_read_generic(), if there is no skb in the queue, we could bail out the do-while loop without calling scm_set_cred(): 1. No skb in the queue 2. sk is non-blocking or shutdown(sk, RCV_SHUTDOWN) is called concurrently or peer calls close() If the socket is configured with SO_PASSCRED or SO_PASSPIDFD, scm_recv() would populate cmsg with garbage. Let's not call scm_recv() unless there is skb to receive. WARNING: CPU: 1 PID: 3245 at include/net/scm.h:138 scm_pidfd_recv include/net/scm.h:138 [inline] WARNING: CPU: 1 PID: 3245 at include/net/scm.h:138 scm_recv.constprop.0+0x754/0x850 include/net/scm.h:177 Modules linked in: CPU: 1 PID: 3245 Comm: syz-executor.1 Not tainted 6.4.0-rc5-01219-gfa0e21fa4443 #2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 RIP: 0010:scm_pidfd_recv include/net/scm.h:138 [inline] RIP: 0010:scm_recv.constprop.0+0x754/0x850 include/net/scm.h:177 Code: 67 fd e9 55 fd ff ff e8 4a 70 67 fd e9 7f fd ff ff e8 40 70 67 fd e9 3e fb ff ff e8 36 70 67 fd e9 02 fd ff ff e8 8c 3a 20 fd <0f> 0b e9 fe fb ff ff e8 50 70 67 fd e9 2e f9 ff ff e8 46 70 67 fd RSP: 0018:ffffc90009af7660 EFLAGS: 00010216 RAX: 00000000000000a1 RBX: ffff888041e58a80 RCX: ffffc90003852000 RDX: 0000000000040000 RSI: ffffffff842675b4 RDI: 0000000000000007 RBP: ffffc90009af7810 R08: 0000000000000007 R09: 0000000000000013 R10: 00000000000000f8 R11: 0000000000000001 R12: ffffc90009af7db0 R13: 0000000000000000 R14: ffff888041e58a88 R15: 1ffff9200135eecc FS: 00007f6b7113f640(0000) GS:ffff88806cf00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f6b7111de38 CR3: 0000000012a6e002 CR4: 0000000000770ee0 PKRU: 55555554 Call Trace: unix_stream_read_generic+0x5fe/0x1f50 net/unix/af_unix.c:2830 unix_stream_recvmsg+0x194/0x1c0 net/unix/af_unix.c:2880 sock_recvmsg_nosec net/socket.c:1019 [inline] sock_recvmsg+0x188/0x1d0 net/socket.c:1040 ____sys_recvmsg+0x210/0x610 net/socket.c:2712 ___sys_recvmsg+0xff/0x190 net/socket.c:2754 do_recvmmsg+0x25d/0x6c0 net/socket.c:2848 __sys_recvmmsg net/socket.c:2927 [inline] __do_sys_recvmmsg net/socket.c:2950 [inline] __se_sys_recvmmsg net/socket.c:2943 [inline] __x64_sys_recvmmsg+0x224/0x290 net/socket.c:2943 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x72/0xdc RIP: 0033:0x7f6b71da2e5d Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 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 8b 0d 73 9f 1b 00 f7 d8 64 89 01 48 RSP: 002b:00007f6b7113ecc8 EFLAGS: 00000246 ORIG_RAX: 000000000000012b RAX: ffffffffffffffda RBX: 00000000004bc050 RCX: 00007f6b71da2e5d RDX: 0000000000000007 RSI: 0000000020006600 RDI: 000000000000000b RBP: 00000000004bc050 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000120 R11: 0000000000000246 R12: 0000000000000000 R13: 000000000000006e R14: 00007f6b71e03530 R15: 0000000000000000 Fixes: 5e2ff6704a27 ("scm: add SO_PASSPIDFD and SCM_PIDFD") Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzkaller Signed-off-by: Kuniyuki Iwashima Reviewed-by: Alexander Mikhalitsyn Link: https://lore.kernel.org/r/20230622184351.91544-1-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/unix/af_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 73c61a010b01..f9d196439b49 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2826,7 +2826,7 @@ unlock: } while (size); mutex_unlock(&u->iolock); - if (state->msg) + if (state->msg && check_creds) scm_recv(sock, state->msg, &scm, flags); else scm_destroy(&scm); -- cgit v1.2.3 From 5f789f103671fec3733ebe756e56adf15c90c21d Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Thu, 22 Jun 2023 23:03:34 +0200 Subject: selftests: rtnetlink: remove netdevsim device after ipsec offload test On systems where netdevsim is built-in or loaded before the test starts, kci_test_ipsec_offload doesn't remove the netdevsim device it created during the test. Fixes: e05b2d141fef ("netdevsim: move netdev creation/destruction to dev probe") Signed-off-by: Sabrina Dubroca Reviewed-by: Simon Horman Reviewed-by: Jiri Pirko Link: https://lore.kernel.org/r/e1cb94f4f82f4eca4a444feec4488a1323396357.1687466906.git.sd@queasysnail.net Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/rtnetlink.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index 383ac6fc037d..ba286d680fd9 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -860,6 +860,7 @@ EOF fi # clean up any leftovers + echo 0 > /sys/bus/netdevsim/del_device $probed && rmmod netdevsim if [ $ret -ne 0 ]; then -- cgit v1.2.3 From ce3aee7114c575fab32a5e9e939d4bbb3dcca79f Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 22 Jun 2023 14:32:31 -0700 Subject: gtp: Fix use-after-free in __gtp_encap_destroy(). syzkaller reported use-after-free in __gtp_encap_destroy(). [0] It shows the same process freed sk and touched it illegally. Commit e198987e7dd7 ("gtp: fix suspicious RCU usage") added lock_sock() and release_sock() in __gtp_encap_destroy() to protect sk->sk_user_data, but release_sock() is called after sock_put() releases the last refcnt. [0]: BUG: KASAN: slab-use-after-free in instrument_atomic_read_write include/linux/instrumented.h:96 [inline] BUG: KASAN: slab-use-after-free in atomic_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:541 [inline] BUG: KASAN: slab-use-after-free in queued_spin_lock include/asm-generic/qspinlock.h:111 [inline] BUG: KASAN: slab-use-after-free in do_raw_spin_lock include/linux/spinlock.h:186 [inline] BUG: KASAN: slab-use-after-free in __raw_spin_lock_bh include/linux/spinlock_api_smp.h:127 [inline] BUG: KASAN: slab-use-after-free in _raw_spin_lock_bh+0x75/0xe0 kernel/locking/spinlock.c:178 Write of size 4 at addr ffff88800dbef398 by task syz-executor.2/2401 CPU: 1 PID: 2401 Comm: syz-executor.2 Not tainted 6.4.0-rc5-01219-gfa0e21fa4443 #2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106 print_address_description mm/kasan/report.c:351 [inline] print_report+0xcc/0x620 mm/kasan/report.c:462 kasan_report+0xb2/0xe0 mm/kasan/report.c:572 check_region_inline mm/kasan/generic.c:181 [inline] kasan_check_range+0x39/0x1c0 mm/kasan/generic.c:187 instrument_atomic_read_write include/linux/instrumented.h:96 [inline] atomic_try_cmpxchg_acquire include/linux/atomic/atomic-instrumented.h:541 [inline] queued_spin_lock include/asm-generic/qspinlock.h:111 [inline] do_raw_spin_lock include/linux/spinlock.h:186 [inline] __raw_spin_lock_bh include/linux/spinlock_api_smp.h:127 [inline] _raw_spin_lock_bh+0x75/0xe0 kernel/locking/spinlock.c:178 spin_lock_bh include/linux/spinlock.h:355 [inline] release_sock+0x1f/0x1a0 net/core/sock.c:3526 gtp_encap_disable_sock drivers/net/gtp.c:651 [inline] gtp_encap_disable+0xb9/0x220 drivers/net/gtp.c:664 gtp_dev_uninit+0x19/0x50 drivers/net/gtp.c:728 unregister_netdevice_many_notify+0x97e/0x1520 net/core/dev.c:10841 rtnl_delete_link net/core/rtnetlink.c:3216 [inline] rtnl_dellink+0x3c0/0xb30 net/core/rtnetlink.c:3268 rtnetlink_rcv_msg+0x450/0xb10 net/core/rtnetlink.c:6423 netlink_rcv_skb+0x15d/0x450 net/netlink/af_netlink.c:2548 netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline] netlink_unicast+0x700/0x930 net/netlink/af_netlink.c:1365 netlink_sendmsg+0x91c/0xe30 net/netlink/af_netlink.c:1913 sock_sendmsg_nosec net/socket.c:724 [inline] sock_sendmsg+0x1b7/0x200 net/socket.c:747 ____sys_sendmsg+0x75a/0x990 net/socket.c:2493 ___sys_sendmsg+0x11d/0x1c0 net/socket.c:2547 __sys_sendmsg+0xfe/0x1d0 net/socket.c:2576 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x72/0xdc RIP: 0033:0x7f1168b1fe5d Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 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 8b 0d 73 9f 1b 00 f7 d8 64 89 01 48 RSP: 002b:00007f1167edccc8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00000000004bbf80 RCX: 00007f1168b1fe5d RDX: 0000000000000000 RSI: 00000000200002c0 RDI: 0000000000000003 RBP: 00000000004bbf80 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 000000000000000b R14: 00007f1168b80530 R15: 0000000000000000 Allocated by task 1483: kasan_save_stack+0x22/0x50 mm/kasan/common.c:45 kasan_set_track+0x25/0x30 mm/kasan/common.c:52 __kasan_slab_alloc+0x59/0x70 mm/kasan/common.c:328 kasan_slab_alloc include/linux/kasan.h:186 [inline] slab_post_alloc_hook mm/slab.h:711 [inline] slab_alloc_node mm/slub.c:3451 [inline] slab_alloc mm/slub.c:3459 [inline] __kmem_cache_alloc_lru mm/slub.c:3466 [inline] kmem_cache_alloc+0x16d/0x340 mm/slub.c:3475 sk_prot_alloc+0x5f/0x280 net/core/sock.c:2073 sk_alloc+0x34/0x6c0 net/core/sock.c:2132 inet6_create net/ipv6/af_inet6.c:192 [inline] inet6_create+0x2c7/0xf20 net/ipv6/af_inet6.c:119 __sock_create+0x2a1/0x530 net/socket.c:1535 sock_create net/socket.c:1586 [inline] __sys_socket_create net/socket.c:1623 [inline] __sys_socket_create net/socket.c:1608 [inline] __sys_socket+0x137/0x250 net/socket.c:1651 __do_sys_socket net/socket.c:1664 [inline] __se_sys_socket net/socket.c:1662 [inline] __x64_sys_socket+0x72/0xb0 net/socket.c:1662 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x72/0xdc Freed by task 2401: kasan_save_stack+0x22/0x50 mm/kasan/common.c:45 kasan_set_track+0x25/0x30 mm/kasan/common.c:52 kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521 ____kasan_slab_free mm/kasan/common.c:236 [inline] ____kasan_slab_free mm/kasan/common.c:200 [inline] __kasan_slab_free+0x10c/0x1b0 mm/kasan/common.c:244 kasan_slab_free include/linux/kasan.h:162 [inline] slab_free_hook mm/slub.c:1781 [inline] slab_free_freelist_hook mm/slub.c:1807 [inline] slab_free mm/slub.c:3786 [inline] kmem_cache_free+0xb4/0x490 mm/slub.c:3808 sk_prot_free net/core/sock.c:2113 [inline] __sk_destruct+0x500/0x720 net/core/sock.c:2207 sk_destruct+0xc1/0xe0 net/core/sock.c:2222 __sk_free+0xed/0x3d0 net/core/sock.c:2233 sk_free+0x7c/0xa0 net/core/sock.c:2244 sock_put include/net/sock.h:1981 [inline] __gtp_encap_destroy+0x165/0x1b0 drivers/net/gtp.c:634 gtp_encap_disable_sock drivers/net/gtp.c:651 [inline] gtp_encap_disable+0xb9/0x220 drivers/net/gtp.c:664 gtp_dev_uninit+0x19/0x50 drivers/net/gtp.c:728 unregister_netdevice_many_notify+0x97e/0x1520 net/core/dev.c:10841 rtnl_delete_link net/core/rtnetlink.c:3216 [inline] rtnl_dellink+0x3c0/0xb30 net/core/rtnetlink.c:3268 rtnetlink_rcv_msg+0x450/0xb10 net/core/rtnetlink.c:6423 netlink_rcv_skb+0x15d/0x450 net/netlink/af_netlink.c:2548 netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline] netlink_unicast+0x700/0x930 net/netlink/af_netlink.c:1365 netlink_sendmsg+0x91c/0xe30 net/netlink/af_netlink.c:1913 sock_sendmsg_nosec net/socket.c:724 [inline] sock_sendmsg+0x1b7/0x200 net/socket.c:747 ____sys_sendmsg+0x75a/0x990 net/socket.c:2493 ___sys_sendmsg+0x11d/0x1c0 net/socket.c:2547 __sys_sendmsg+0xfe/0x1d0 net/socket.c:2576 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x72/0xdc The buggy address belongs to the object at ffff88800dbef300 which belongs to the cache UDPv6 of size 1344 The buggy address is located 152 bytes inside of freed 1344-byte region [ffff88800dbef300, ffff88800dbef840) The buggy address belongs to the physical page: page:00000000d31bfed5 refcount:1 mapcount:0 mapping:0000000000000000 index:0xffff88800dbeed40 pfn:0xdbe8 head:00000000d31bfed5 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0 memcg:ffff888008ee0801 flags: 0x100000000010200(slab|head|node=0|zone=1) page_type: 0xffffffff() raw: 0100000000010200 ffff88800c7a3000 dead000000000122 0000000000000000 raw: ffff88800dbeed40 0000000080160015 00000001ffffffff ffff888008ee0801 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88800dbef280: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff88800dbef300: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb >ffff88800dbef380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff88800dbef400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff88800dbef480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb Fixes: e198987e7dd7 ("gtp: fix suspicious RCU usage") Reported-by: syzkaller Signed-off-by: Kuniyuki Iwashima Reviewed-by: Pablo Neira Ayuso Link: https://lore.kernel.org/r/20230622213231.24651-1-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- drivers/net/gtp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 15c7dc82107f..acb20ad4e37e 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -631,7 +631,9 @@ static void __gtp_encap_destroy(struct sock *sk) gtp->sk1u = NULL; udp_sk(sk)->encap_type = 0; rcu_assign_sk_user_data(sk, NULL); + release_sock(sk); sock_put(sk); + return; } release_sock(sk); } -- cgit v1.2.3 From 2fe11c9d36ee2f3dc3c642588c5d9a22190674c9 Mon Sep 17 00:00:00 2001 From: Pavel Begunkov Date: Fri, 23 Jun 2023 13:38:55 +0100 Subject: net/tcp: optimise locking for blocking splice Even when tcp_splice_read() reads all it was asked for, for blocking sockets it'll release and immediately regrab the socket lock, loop around and break on the while check. Check tss.len right after we adjust it, and return if we're done. That saves us one release_sock(); lock_sock(); pair per successful blocking splice read. Signed-off-by: Pavel Begunkov Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/80736a2cc6d478c383ea565ba825eaf4d1abd876.1687523671.git.asml.silence@gmail.com Signed-off-by: Jakub Kicinski --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 71b42eef9dbf..d56edc2c885f 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -839,7 +839,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, tss.len -= ret; spliced += ret; - if (!timeo) + if (!tss.len || !timeo) break; release_sock(sk); lock_sock(sk); -- cgit v1.2.3 From 97117eb51ec8e9c397a0baa0b9d62acb51250a83 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:07 +0200 Subject: net: stmmac: platform: provide stmmac_pltfr_init() Provide a helper wrapper around calling the platform's init() callback. This allows users to skip checking if the callback exists. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-2-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 25 ++++++++++++++++++++-- .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 3 +++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 3c6b55b60461..41ca4fc9f863 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -701,6 +701,25 @@ int stmmac_get_platform_resources(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); +/** + * stmmac_pltfr_init + * @pdev: pointer to the platform device + * @plat: driver data platform structure + * Description: Call the platform's init callback (if any) and propagate + * the return value. + */ +int stmmac_pltfr_init(struct platform_device *pdev, + struct plat_stmmacenet_data *plat) +{ + int ret = 0; + + if (plat->init) + ret = plat->init(pdev, plat->bsp_priv); + + return ret; +} +EXPORT_SYMBOL_GPL(stmmac_pltfr_init); + /** * stmmac_pltfr_remove * @pdev: platform device pointer @@ -755,9 +774,11 @@ static int __maybe_unused stmmac_pltfr_resume(struct device *dev) struct net_device *ndev = dev_get_drvdata(dev); struct stmmac_priv *priv = netdev_priv(ndev); struct platform_device *pdev = to_platform_device(dev); + int ret; - if (priv->plat->init) - priv->plat->init(pdev, priv->plat->bsp_priv); + ret = stmmac_pltfr_init(pdev, priv->plat->bsp_priv); + if (ret) + return ret; return stmmac_resume(dev); } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index f7e457946681..6a2cd47fedcd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -19,6 +19,9 @@ void stmmac_remove_config_dt(struct platform_device *pdev, int stmmac_get_platform_resources(struct platform_device *pdev, struct stmmac_resources *stmmac_res); +int stmmac_pltfr_init(struct platform_device *pdev, + struct plat_stmmacenet_data *plat); + void stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -- cgit v1.2.3 From 4450e7d4231af63027009967b01c8e258966801c Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:08 +0200 Subject: net: stmmac: dwmac-generic: use stmmac_pltfr_init() Shrink the code in dwmac-generic by using the new stmmac_pltfr_init() helper. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-3-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index ef1023930fd0..b7fc79864e8c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -47,11 +47,9 @@ static int dwmac_generic_probe(struct platform_device *pdev) } /* Custom initialisation (if needed) */ - if (plat_dat->init) { - ret = plat_dat->init(pdev, plat_dat->bsp_priv); - if (ret) - goto err_remove_config_dt; - } + ret = stmmac_pltfr_init(pdev, plat_dat); + if (ret) + goto err_remove_config_dt; ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) -- cgit v1.2.3 From 5b0acf8dd2c1bf3349257daad36dc34a8b62571e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:09 +0200 Subject: net: stmmac: platform: provide stmmac_pltfr_exit() Provide a helper wrapper around calling the platform's exit() callback. This allows users to skip checking if the callback exists. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-4-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 22 ++++++++++++++++------ .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 2 ++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 41ca4fc9f863..5b2bc129cd85 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -720,6 +720,20 @@ int stmmac_pltfr_init(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(stmmac_pltfr_init); +/** + * stmmac_pltfr_exit + * @pdev: pointer to the platform device + * @plat: driver data platform structure + * Description: Call the platform's exit callback (if any). + */ +void stmmac_pltfr_exit(struct platform_device *pdev, + struct plat_stmmacenet_data *plat) +{ + if (plat->exit) + plat->exit(pdev, plat->bsp_priv); +} +EXPORT_SYMBOL_GPL(stmmac_pltfr_exit); + /** * stmmac_pltfr_remove * @pdev: platform device pointer @@ -733,10 +747,7 @@ void stmmac_pltfr_remove(struct platform_device *pdev) struct plat_stmmacenet_data *plat = priv->plat; stmmac_dvr_remove(&pdev->dev); - - if (plat->exit) - plat->exit(pdev, plat->bsp_priv); - + stmmac_pltfr_exit(pdev, plat); stmmac_remove_config_dt(pdev, plat); } EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); @@ -756,8 +767,7 @@ static int __maybe_unused stmmac_pltfr_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); ret = stmmac_suspend(dev); - if (priv->plat->exit) - priv->plat->exit(pdev, priv->plat->bsp_priv); + stmmac_pltfr_exit(pdev, priv->plat); return ret; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 6a2cd47fedcd..e79134cc1d3d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -21,6 +21,8 @@ int stmmac_get_platform_resources(struct platform_device *pdev, int stmmac_pltfr_init(struct platform_device *pdev, struct plat_stmmacenet_data *plat); +void stmmac_pltfr_exit(struct platform_device *pdev, + struct plat_stmmacenet_data *plat); void stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -- cgit v1.2.3 From 40db9f1ddfcc97425433a609e1f829dde74aa157 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:10 +0200 Subject: net: stmmac: dwmac-generic: use stmmac_pltfr_exit() Shrink the code in dwmac-generic by using the new stmmac_pltfr_exit() helper. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-5-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index b7fc79864e8c..dabf05601221 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -58,8 +58,7 @@ static int dwmac_generic_probe(struct platform_device *pdev) return 0; err_exit: - if (plat_dat->exit) - plat_dat->exit(pdev, plat_dat->bsp_priv); + stmmac_pltfr_exit(pdev, plat_dat); err_remove_config_dt: if (pdev->dev.of_node) stmmac_remove_config_dt(pdev, plat_dat); -- cgit v1.2.3 From 3d5bf75d76ea8c6bfcffd1b6aa76686d86f9ea34 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:11 +0200 Subject: net: stmmac: platform: provide stmmac_pltfr_probe() Implement stmmac_pltfr_probe() which is the logical API counterpart for stmmac_pltfr_remove(). It calls the platform's init() callback and then probes the stmmac device. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-6-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 28 ++++++++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 5b2bc129cd85..df417cdab8c1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -734,6 +734,34 @@ void stmmac_pltfr_exit(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(stmmac_pltfr_exit); +/** + * stmmac_pltfr_probe + * @pdev: platform device pointer + * @plat: driver data platform structure + * @res: stmmac resources structure + * Description: This calls the platform's init() callback and probes the + * stmmac driver. + */ +int stmmac_pltfr_probe(struct platform_device *pdev, + struct plat_stmmacenet_data *plat, + struct stmmac_resources *res) +{ + int ret; + + ret = stmmac_pltfr_init(pdev, plat); + if (ret) + return ret; + + ret = stmmac_dvr_probe(&pdev->dev, plat, res); + if (ret) { + stmmac_pltfr_exit(pdev, plat); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(stmmac_pltfr_probe); + /** * stmmac_pltfr_remove * @pdev: platform device pointer diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index e79134cc1d3d..f968e658c9d2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -24,6 +24,9 @@ int stmmac_pltfr_init(struct platform_device *pdev, void stmmac_pltfr_exit(struct platform_device *pdev, struct plat_stmmacenet_data *plat); +int stmmac_pltfr_probe(struct platform_device *pdev, + struct plat_stmmacenet_data *plat, + struct stmmac_resources *res); void stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -- cgit v1.2.3 From 0a68a59493e043170be1a064558bae6a30fea39d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:12 +0200 Subject: net: stmmac: dwmac-generic: use stmmac_pltfr_probe() Shrink the code and remove labels by using the new stmmac_pltfr_probe() function. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-7-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index dabf05601221..20fc455b3337 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -46,19 +46,12 @@ static int dwmac_generic_probe(struct platform_device *pdev) plat_dat->unicast_filter_entries = 1; } - /* Custom initialisation (if needed) */ - ret = stmmac_pltfr_init(pdev, plat_dat); + ret = stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); if (ret) goto err_remove_config_dt; - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - if (ret) - goto err_exit; - return 0; -err_exit: - stmmac_pltfr_exit(pdev, plat_dat); err_remove_config_dt: if (pdev->dev.of_node) stmmac_remove_config_dt(pdev, plat_dat); -- cgit v1.2.3 From 1be0c9d65e17684865d9ed039ac20eeb21019652 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:13 +0200 Subject: net: stmmac: platform: provide stmmac_pltfr_remove_no_dt() Add a variant of stmmac_pltfr_remove() that only frees resources allocated by stmmac_pltfr_probe() and - unlike stmmac_pltfr_remove() - does not call stmmac_remove_config_dt(). Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-8-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 20 ++++++++++++++++++-- .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index df417cdab8c1..58d5c5cc2269 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -762,6 +762,23 @@ int stmmac_pltfr_probe(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(stmmac_pltfr_probe); +/** + * stmmac_pltfr_remove_no_dt + * @pdev: pointer to the platform device + * Description: This undoes the effects of stmmac_pltfr_probe() by removing the + * driver and calling the platform's exit() callback. + */ +void stmmac_pltfr_remove_no_dt(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(ndev); + struct plat_stmmacenet_data *plat = priv->plat; + + stmmac_dvr_remove(&pdev->dev); + stmmac_pltfr_exit(pdev, plat); +} +EXPORT_SYMBOL_GPL(stmmac_pltfr_remove_no_dt); + /** * stmmac_pltfr_remove * @pdev: platform device pointer @@ -774,8 +791,7 @@ void stmmac_pltfr_remove(struct platform_device *pdev) struct stmmac_priv *priv = netdev_priv(ndev); struct plat_stmmacenet_data *plat = priv->plat; - stmmac_dvr_remove(&pdev->dev); - stmmac_pltfr_exit(pdev, plat); + stmmac_pltfr_remove_no_dt(pdev); stmmac_remove_config_dt(pdev, plat); } EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index f968e658c9d2..af52d5aa2b9a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -27,6 +27,7 @@ void stmmac_pltfr_exit(struct platform_device *pdev, int stmmac_pltfr_probe(struct platform_device *pdev, struct plat_stmmacenet_data *plat, struct stmmac_resources *res); +void stmmac_pltfr_remove_no_dt(struct platform_device *pdev); void stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -- cgit v1.2.3 From d74065427374da6659a2d7fad4ec55c8926d43c4 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:14 +0200 Subject: net: stmmac: platform: provide devm_stmmac_probe_config_dt() Provide a devres variant of stmmac_probe_config_dt() that allows users to skip calling stmmac_remove_config_dt() at driver detach. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-9-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 41 ++++++++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 2 ++ 2 files changed, 43 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 58d5c5cc2269..82d8a1c76476 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -8,6 +8,7 @@ Author: Giuseppe Cavallaro *******************************************************************************/ +#include #include #include #include @@ -629,6 +630,39 @@ error_pclk_get: return ret; } +static void devm_stmmac_remove_config_dt(void *data) +{ + struct plat_stmmacenet_data *plat = data; + + /* Platform data argument is unused */ + stmmac_remove_config_dt(NULL, plat); +} + +/** + * devm_stmmac_probe_config_dt + * @pdev: platform_device structure + * @mac: MAC address to use + * Description: Devres variant of stmmac_probe_config_dt(). Does not require + * the user to call stmmac_remove_config_dt() at driver detach. + */ +struct plat_stmmacenet_data * +devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) +{ + struct plat_stmmacenet_data *plat; + int ret; + + plat = stmmac_probe_config_dt(pdev, mac); + if (IS_ERR(plat)) + return plat; + + ret = devm_add_action_or_reset(&pdev->dev, + devm_stmmac_remove_config_dt, plat); + if (ret) + return ERR_PTR(ret); + + return plat; +} + /** * stmmac_remove_config_dt - undo the effects of stmmac_probe_config_dt() * @pdev: platform_device structure @@ -651,12 +685,19 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) return ERR_PTR(-EINVAL); } +struct plat_stmmacenet_data * +devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) +{ + return ERR_PTR(-EINVAL); +} + void stmmac_remove_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat) { } #endif /* CONFIG_OF */ EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); +EXPORT_SYMBOL_GPL(devm_stmmac_probe_config_dt); EXPORT_SYMBOL_GPL(stmmac_remove_config_dt); int stmmac_get_platform_resources(struct platform_device *pdev, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index af52d5aa2b9a..8c1e5b2e9dae 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -13,6 +13,8 @@ struct plat_stmmacenet_data * stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac); +struct plat_stmmacenet_data * +devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac); void stmmac_remove_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat); -- cgit v1.2.3 From 061425d933ef9259dbe3789a3a3c63063f53202d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:15 +0200 Subject: net: stmmac: dwmac-qco-ethqos: use devm_stmmac_probe_config_dt() Significantly simplify the driver's probe() function by using the devres variant of stmmac_probe_config_dt(). This allows to drop the goto jumps entirely. The remove_new() callback now needs to be switched to stmmac_pltfr_remove_no_dt(). Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-10-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 49 +++++++--------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index fa0fc53c56a3..7b9fbcb8d84d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -708,7 +708,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (ret) return ret; - plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); + plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); if (IS_ERR(plat_dat)) { dev_err(dev, "dt configuration failed\n"); return PTR_ERR(plat_dat); @@ -717,10 +717,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->clks_config = ethqos_clks_config; ethqos = devm_kzalloc(dev, sizeof(*ethqos), GFP_KERNEL); - if (!ethqos) { - ret = -ENOMEM; - goto out_config_dt; - } + if (!ethqos) + return -ENOMEM; ethqos->phy_mode = device_get_phy_mode(dev); switch (ethqos->phy_mode) { @@ -734,19 +732,15 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->configure_func = ethqos_configure_sgmii; break; case -ENODEV: - ret = -ENODEV; - goto out_config_dt; + return -ENODEV; default: - ret = -EINVAL; - goto out_config_dt; + return -EINVAL; } ethqos->pdev = pdev; ethqos->rgmii_base = devm_platform_ioremap_resource_byname(pdev, "rgmii"); - if (IS_ERR(ethqos->rgmii_base)) { - ret = PTR_ERR(ethqos->rgmii_base); - goto out_config_dt; - } + if (IS_ERR(ethqos->rgmii_base)) + return PTR_ERR(ethqos->rgmii_base); ethqos->mac_base = stmmac_res.addr; @@ -757,24 +751,20 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->has_emac_ge_3 = data->has_emac_ge_3; ethqos->link_clk = devm_clk_get(dev, data->link_clk_name ?: "rgmii"); - if (IS_ERR(ethqos->link_clk)) { - ret = PTR_ERR(ethqos->link_clk); - goto out_config_dt; - } + if (IS_ERR(ethqos->link_clk)) + return PTR_ERR(ethqos->link_clk); ret = ethqos_clks_config(ethqos, true); if (ret) - goto out_config_dt; + return ret; ret = devm_add_action_or_reset(dev, ethqos_clks_disable, ethqos); if (ret) - goto out_config_dt; + return ret; ethqos->serdes_phy = devm_phy_optional_get(dev, "serdes"); - if (IS_ERR(ethqos->serdes_phy)) { - ret = PTR_ERR(ethqos->serdes_phy); - goto out_config_dt; - } + if (IS_ERR(ethqos->serdes_phy)) + return PTR_ERR(ethqos->serdes_phy); ethqos->speed = SPEED_1000; ethqos_update_link_clk(ethqos, SPEED_1000); @@ -797,16 +787,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->serdes_powerdown = qcom_ethqos_serdes_powerdown; } - ret = stmmac_dvr_probe(dev, plat_dat, &stmmac_res); - if (ret) - goto out_config_dt; - - return ret; - -out_config_dt: - stmmac_remove_config_dt(pdev, plat_dat); - - return ret; + return stmmac_dvr_probe(dev, plat_dat, &stmmac_res); } static const struct of_device_id qcom_ethqos_match[] = { @@ -820,7 +801,7 @@ MODULE_DEVICE_TABLE(of, qcom_ethqos_match); static struct platform_driver qcom_ethqos_driver = { .probe = qcom_ethqos_probe, - .remove_new = stmmac_pltfr_remove, + .remove_new = stmmac_pltfr_remove_no_dt, .driver = { .name = "qcom-ethqos", .pm = &stmmac_pltfr_pm_ops, -- cgit v1.2.3 From fc9ee2ac4f9c366d92e6bb4c89f316c47d3a8de6 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:16 +0200 Subject: net: stmmac: platform: provide devm_stmmac_pltfr_probe() Provide a devres variant of stmmac_pltfr_probe() which allows users to skip calling stmmac_pltfr_remove() at driver detach. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-11-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 30 ++++++++++++++++++++++ .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 3 +++ 2 files changed, 33 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 82d8a1c76476..231152ee5a32 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -803,6 +803,36 @@ int stmmac_pltfr_probe(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(stmmac_pltfr_probe); +static void devm_stmmac_pltfr_remove(void *data) +{ + struct platform_device *pdev = data; + + stmmac_pltfr_remove_no_dt(pdev); +} + +/** + * devm_stmmac_pltfr_probe + * @pdev: pointer to the platform device + * @plat: driver data platform structure + * @res: stmmac resources + * Description: Devres variant of stmmac_pltfr_probe(). Allows users to skip + * calling stmmac_pltfr_remove() on driver detach. + */ +int devm_stmmac_pltfr_probe(struct platform_device *pdev, + struct plat_stmmacenet_data *plat, + struct stmmac_resources *res) +{ + int ret; + + ret = stmmac_pltfr_probe(pdev, plat, res); + if (ret) + return ret; + + return devm_add_action_or_reset(&pdev->dev, devm_stmmac_pltfr_remove, + pdev); +} +EXPORT_SYMBOL_GPL(devm_stmmac_pltfr_probe); + /** * stmmac_pltfr_remove_no_dt * @pdev: pointer to the platform device diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 8c1e5b2e9dae..c5565b2a70ac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -29,6 +29,9 @@ void stmmac_pltfr_exit(struct platform_device *pdev, int stmmac_pltfr_probe(struct platform_device *pdev, struct plat_stmmacenet_data *plat, struct stmmac_resources *res); +int devm_stmmac_pltfr_probe(struct platform_device *pdev, + struct plat_stmmacenet_data *plat, + struct stmmac_resources *res); void stmmac_pltfr_remove_no_dt(struct platform_device *pdev); void stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -- cgit v1.2.3 From 4194f32a4b2b1e41c00fac7a1f5f63375a94ba11 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 23 Jun 2023 12:04:17 +0200 Subject: net: stmmac: dwmac-qcom-ethqos: use devm_stmmac_pltfr_probe() Use the devres variant of stmmac_pltfr_probe() and finally drop the remove() callback entirely. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230623100417.93592-12-brgl@bgdev.pl Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 7b9fbcb8d84d..e62940414e54 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -787,7 +787,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->serdes_powerdown = qcom_ethqos_serdes_powerdown; } - return stmmac_dvr_probe(dev, plat_dat, &stmmac_res); + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } static const struct of_device_id qcom_ethqos_match[] = { @@ -801,7 +801,6 @@ MODULE_DEVICE_TABLE(of, qcom_ethqos_match); static struct platform_driver qcom_ethqos_driver = { .probe = qcom_ethqos_probe, - .remove_new = stmmac_pltfr_remove_no_dt, .driver = { .name = "qcom-ethqos", .pm = &stmmac_pltfr_pm_ops, -- cgit v1.2.3 From 4369c198e5990ee077b97c979d678b5abd8a91ba Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:07 -0700 Subject: selftests: mptcp: test userspace pm out of transfer This patch moves userspace pm tests out of do_transfer(). Move add address test into a new function userspace_pm_add_addr(), and remove address test into userspace_pm_rm_sf_addr_ns1(). Move add subflow test into userspace_pm_add_sf() and remove subflow into userspace_pm_rm_sf_addr_ns2(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-1-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 145 ++++++++++++++++-------- 1 file changed, 99 insertions(+), 46 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index a7973d6a40a0..3baa6ac3b03e 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -589,6 +589,26 @@ wait_rm_addr() done } +rm_sf_count() +{ + get_counter "${1}" "MPTcpExtRmSubflow" +} + +# $1: ns, $2: old rm_sf counter in $ns +wait_rm_sf() +{ + local ns="${1}" + local old_cnt="${2}" + local cnt + + local i + for i in $(seq 10); do + cnt=$(rm_sf_count ${ns}) + [ "$cnt" = "${old_cnt}" ] || break + sleep 0.1 + done +} + wait_mpj() { local ns="${1}" @@ -813,7 +833,6 @@ do_transfer() local port=$((10000 + TEST_COUNT - 1)) local cappid - local userspace_pm=0 :> "$cout" :> "$sout" @@ -850,11 +869,6 @@ do_transfer() extra_args="-r ${speed:6}" fi - if [[ "${addr_nr_ns1}" = "userspace_"* ]]; then - userspace_pm=1 - addr_nr_ns1=${addr_nr_ns1:10} - fi - local flags="subflow" local extra_cl_args="" local extra_srv_args="" @@ -882,9 +896,6 @@ do_transfer() return 1 fi addr_nr_ns2=0 - elif [[ "${addr_nr_ns2}" = "userspace_"* ]]; then - userspace_pm=1 - addr_nr_ns2=${addr_nr_ns2:10} elif [[ "${addr_nr_ns2}" = "fullmesh_"* ]]; then flags="${flags},fullmesh" addr_nr_ns2=${addr_nr_ns2:9} @@ -938,7 +949,6 @@ do_transfer() local counter=2 local add_nr_ns1=${addr_nr_ns1} local id=10 - local tk while [ $add_nr_ns1 -gt 0 ]; do local addr if is_v6 "${connect_addr}"; then @@ -946,24 +956,7 @@ do_transfer() else addr="10.0.$counter.1" fi - if [ $userspace_pm -eq 0 ]; then - pm_nl_add_endpoint $ns1 $addr flags signal - else - tk=$(grep "type:1," "$evts_ns1" | - sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') - ip netns exec ${listener_ns} ./pm_nl_ctl ann $addr token $tk id $id - sleep 1 - sp=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') - da=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q') - dp=$(grep "type:10" "$evts_ns1" | - sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q') - ip netns exec ${listener_ns} ./pm_nl_ctl rem token $tk id $id - ip netns exec ${listener_ns} ./pm_nl_ctl dsf lip "::ffff:$addr" \ - lport $sp rip $da rport $dp token $tk - fi - + pm_nl_add_endpoint $ns1 $addr flags signal counter=$((counter + 1)) add_nr_ns1=$((add_nr_ns1 - 1)) id=$((id + 1)) @@ -1008,7 +1001,6 @@ do_transfer() local add_nr_ns2=${addr_nr_ns2} local counter=3 local id=20 - local tk da dp sp while [ $add_nr_ns2 -gt 0 ]; do local addr if is_v6 "${connect_addr}"; then @@ -1016,21 +1008,7 @@ do_transfer() else addr="10.0.$counter.2" fi - if [ $userspace_pm -eq 0 ]; then - pm_nl_add_endpoint $ns2 $addr flags $flags - else - tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") - da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") - dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") - ip netns exec ${connector_ns} ./pm_nl_ctl csf lip $addr lid $id \ - rip $da rport $dp token $tk - sleep 1 - sp=$(grep "type:10" "$evts_ns2" | - sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') - ip netns exec ${connector_ns} ./pm_nl_ctl rem token $tk id $id - ip netns exec ${connector_ns} ./pm_nl_ctl dsf lip $addr lport $sp \ - rip $da rport $dp token $tk - fi + pm_nl_add_endpoint $ns2 $addr flags $flags counter=$((counter + 1)) add_nr_ns2=$((add_nr_ns2 - 1)) id=$((id + 1)) @@ -3205,6 +3183,71 @@ fail_tests() fi } +userspace_pm_add_addr() +{ + local addr=$1 + local id=$2 + local tk + + tk=$(grep "type:1," "$evts_ns1" | + sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') + ip netns exec $ns1 ./pm_nl_ctl ann $addr token $tk id $id + sleep 1 +} + +userspace_pm_rm_sf_addr_ns1() +{ + local addr=$1 + local id=$2 + local tk sp da dp + + tk=$(grep "type:1," "$evts_ns1" | + sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q') + sp=$(grep "type:10" "$evts_ns1" | + sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') + da=$(grep "type:10" "$evts_ns1" | + sed -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q') + dp=$(grep "type:10" "$evts_ns1" | + sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q') + ip netns exec $ns1 ./pm_nl_ctl rem token $tk id $id + ip netns exec $ns1 ./pm_nl_ctl dsf lip "::ffff:$addr" \ + lport $sp rip $da rport $dp token $tk + wait_rm_addr $ns1 1 + wait_rm_sf $ns1 1 +} + +userspace_pm_add_sf() +{ + local addr=$1 + local id=$2 + local tk da dp + + tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") + dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + ip netns exec $ns2 ./pm_nl_ctl csf lip $addr lid $id \ + rip $da rport $dp token $tk + sleep 1 +} + +userspace_pm_rm_sf_addr_ns2() +{ + local addr=$1 + local id=$2 + local tk da dp sp + + tk=$(sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + da=$(sed -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evts_ns2") + dp=$(sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evts_ns2") + sp=$(grep "type:10" "$evts_ns2" | + sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q') + ip netns exec $ns2 ./pm_nl_ctl rem token $tk id $id + ip netns exec $ns2 ./pm_nl_ctl dsf lip $addr lport $sp \ + rip $da rport $dp token $tk + wait_rm_addr $ns2 1 + wait_rm_sf $ns2 1 +} + userspace_tests() { # userspace pm type prevents add_addr @@ -3283,11 +3326,16 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 userspace_1 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 & + local tests_pid=$! + wait_mpj $ns1 + userspace_pm_add_addr 10.0.2.1 10 chk_join_nr 1 1 1 chk_add_nr 1 1 + userspace_pm_rm_sf_addr_ns1 10.0.2.1 10 chk_rm_nr 1 1 invert kill_events_pids + wait $tests_pid fi # userspace pm create destroy subflow @@ -3295,10 +3343,15 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns2 pm_nl_set_limits $ns1 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 userspace_1 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 & + local tests_pid=$! + wait_mpj $ns2 + userspace_pm_add_sf 10.0.3.2 20 chk_join_nr 1 1 1 + userspace_pm_rm_sf_addr_ns2 10.0.3.2 20 chk_rm_nr 1 1 kill_events_pids + wait $tests_pid fi } -- cgit v1.2.3 From d7ced753aa851f54735d20ca49ddf4710e43f1d1 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:08 -0700 Subject: selftests: mptcp: check subflow and addr infos New MPTCP info are being checked in multiple places to improve the code coverage when using the userspace PM. This patch makes chk_mptcp_info() more generic to be able to check subflows, add_addr_signal and add_addr_accepted info (and even more later). New arguments are now required to get different infos from the two namespaces because some counters are specific to the client or the server. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-2-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 44 +++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 3baa6ac3b03e..95a56384294f 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -1832,31 +1832,26 @@ chk_subflow_nr() chk_mptcp_info() { - local nr_info=$1 - local info + local info1=$1 + local exp1=$2 + local info2=$3 + local exp2=$4 local cnt1 local cnt2 local dump_stats - if [[ $nr_info = "subflows_"* ]]; then - info="subflows" - nr_info=${nr_info:9} - else - echo "[fail] unsupported argument: $nr_info" - fail_test - return 1 - fi - - printf "%-${nr_blank}s %-30s" " " "mptcp_info $info=$nr_info" + printf "%-${nr_blank}s %-30s" " " "mptcp_info $info1:$info2=$exp1:$exp2" - cnt1=$(ss -N $ns1 -inmHM | grep "$info:" | - sed -n 's/.*\('"$info"':\)\([[:digit:]]*\).*$/\2/p;q') + cnt1=$(ss -N $ns1 -inmHM | grep "$info1:" | + sed -n 's/.*\('"$info1"':\)\([[:digit:]]*\).*$/\2/p;q') + cnt2=$(ss -N $ns2 -inmHM | grep "$info2:" | + sed -n 's/.*\('"$info2"':\)\([[:digit:]]*\).*$/\2/p;q') + # 'ss' only display active connections and counters that are not 0. [ -z "$cnt1" ] && cnt1=0 - cnt2=$(ss -N $ns2 -inmHM | grep "$info:" | - sed -n 's/.*\('"$info"':\)\([[:digit:]]*\).*$/\2/p;q') [ -z "$cnt2" ] && cnt2=0 - if [ "$cnt1" != "$nr_info" ] || [ "$cnt2" != "$nr_info" ]; then - echo "[fail] got $cnt1:$cnt2 $info expected $nr_info" + + if [ "$cnt1" != "$exp1" ] || [ "$cnt2" != "$exp2" ]; then + echo "[fail] got $cnt1:$cnt2 $info1:$info2 expected $exp1:$exp2" fail_test dump_stats=1 else @@ -3332,8 +3327,11 @@ userspace_tests() userspace_pm_add_addr 10.0.2.1 10 chk_join_nr 1 1 1 chk_add_nr 1 1 + chk_mptcp_info subflows 1 subflows 1 + chk_mptcp_info add_addr_signal 1 add_addr_accepted 1 userspace_pm_rm_sf_addr_ns1 10.0.2.1 10 chk_rm_nr 1 1 invert + chk_mptcp_info subflows 0 subflows 0 kill_events_pids wait $tests_pid fi @@ -3348,8 +3346,10 @@ userspace_tests() wait_mpj $ns2 userspace_pm_add_sf 10.0.3.2 20 chk_join_nr 1 1 1 + chk_mptcp_info subflows 1 subflows 1 userspace_pm_rm_sf_addr_ns2 10.0.3.2 20 chk_rm_nr 1 1 + chk_mptcp_info subflows 0 subflows 0 kill_events_pids wait $tests_pid fi @@ -3369,6 +3369,8 @@ endpoint_tests() wait_mpj $ns1 pm_nl_check_endpoint 1 "creation" \ $ns2 10.0.2.2 id 1 flags implicit + chk_mptcp_info subflows 1 subflows 1 + chk_mptcp_info add_addr_signal 1 add_addr_accepted 1 pm_nl_add_endpoint $ns2 10.0.2.2 id 33 pm_nl_check_endpoint 0 "ID change is prevented" \ @@ -3389,17 +3391,17 @@ endpoint_tests() wait_mpj $ns2 chk_subflow_nr needtitle "before delete" 2 - chk_mptcp_info subflows_1 + chk_mptcp_info subflows 1 subflows 1 pm_nl_del_endpoint $ns2 2 10.0.2.2 sleep 0.5 chk_subflow_nr "" "after delete" 1 - chk_mptcp_info subflows_0 + chk_mptcp_info subflows 0 subflows 0 pm_nl_add_endpoint $ns2 10.0.2.2 dev ns2eth2 flags subflow wait_mpj $ns2 chk_subflow_nr "" "after re-add" 2 - chk_mptcp_info subflows_1 + chk_mptcp_info subflows 1 subflows 1 kill_tests_wait fi } -- cgit v1.2.3 From be7e9786c9155c2942cd53b813e4723be67e07c4 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:09 -0700 Subject: selftests: mptcp: set FAILING_LINKS in run_tests Set FAILING_LINKS as an env var with a limited scope only when calling run_tests(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-3-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 95a56384294f..000c561bf622 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -2177,9 +2177,9 @@ link_failure_tests() pm_nl_set_limits $ns1 0 2 pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 2 - FAILING_LINKS="1" pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 1 + FAILING_LINKS="1" \ + run_tests $ns1 $ns2 10.0.1.1 1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_link_usage $ns2 ns2eth3 $cinsent 0 @@ -2193,8 +2193,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1 2" - run_tests $ns1 $ns2 10.0.1.1 1 + FAILING_LINKS="1 2" \ + run_tests $ns1 $ns2 10.0.1.1 1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_stale_nr $ns2 2 4 2 @@ -2209,8 +2209,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1 2" - run_tests $ns1 $ns2 10.0.1.1 2 + FAILING_LINKS="1 2" \ + run_tests $ns1 $ns2 10.0.1.1 2 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_stale_nr $ns2 1 -1 2 -- cgit v1.2.3 From 0c93af1f8907902692014fd7072d54e275034800 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:10 -0700 Subject: selftests: mptcp: drop test_linkfail parameter run_tests() accepts too many optional parameters. Before this modification, it was required to set all of then when only the last one had to be changed. That's not clear to see all these 0 and it makes the maintenance harder: run_tests $ns1 $ns2 10.0.1.1 1 2 3 slow Instead, the parameter can be set as an env var with a limited scope: foo=1 bar=2 next=3 \ run_tests $ns1 $ns2 10.0.1.1 slow This patch switches to key/value "test_linkfail=*" instead of positional parameter test_linkfail of do_transfer() and run_tests(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-4-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 192 ++++++++++++------------ 1 file changed, 99 insertions(+), 93 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 000c561bf622..bc6a26d357bb 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -50,6 +50,7 @@ TEST_NAME="" nr_blank=40 export FAILING_LINKS="" +export test_linkfail=0 # generated using "nfbpf_compile '(ip && (ip[54] & 0xf0) == 0x30) || # (ip6 && (ip6[74] & 0xf0) == 0x30)'" @@ -825,11 +826,10 @@ do_transfer() local cl_proto="$3" local srv_proto="$4" local connect_addr="$5" - local test_link_fail="$6" - local addr_nr_ns1="$7" - local addr_nr_ns2="$8" - local speed="$9" - local sflags="${10}" + local addr_nr_ns1="$6" + local addr_nr_ns2="$7" + local speed="$8" + local sflags="${9}" local port=$((10000 + TEST_COUNT - 1)) local cappid @@ -874,21 +874,21 @@ do_transfer() local extra_srv_args="" local trunc_size="" if [[ "${addr_nr_ns2}" = "fastclose_"* ]]; then - if [ ${test_link_fail} -le 1 ]; then - echo "fastclose tests need test_link_fail argument" + if [ ${test_linkfail} -le 1 ]; then + echo "fastclose tests need test_linkfail argument" fail_test return 1 fi # disconnect - trunc_size=${test_link_fail} + trunc_size=${test_linkfail} local side=${addr_nr_ns2:10} if [ ${side} = "client" ]; then - extra_cl_args="-f ${test_link_fail}" + extra_cl_args="-f ${test_linkfail}" extra_srv_args="-f -1" elif [ ${side} = "server" ]; then - extra_srv_args="-f ${test_link_fail}" + extra_srv_args="-f ${test_linkfail}" extra_cl_args="-f -1" else echo "wrong/unknown fastclose spec ${side}" @@ -902,7 +902,7 @@ do_transfer() fi extra_srv_args="$extra_args $extra_srv_args" - if [ "$test_link_fail" -gt 1 ];then + if [ "$test_linkfail" -gt 1 ];then timeout ${timeout_test} \ ip netns exec ${listener_ns} \ ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ @@ -918,12 +918,12 @@ do_transfer() wait_local_port_listen "${listener_ns}" "${port}" extra_cl_args="$extra_args $extra_cl_args" - if [ "$test_link_fail" -eq 0 ];then + if [ "$test_linkfail" -eq 0 ];then timeout ${timeout_test} \ ip netns exec ${connector_ns} \ ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ $extra_cl_args $connect_addr < "$cin" > "$cout" & - elif [ "$test_link_fail" -eq 1 ] || [ "$test_link_fail" -eq 2 ];then + elif [ "$test_linkfail" -eq 1 ] || [ "$test_linkfail" -eq 2 ];then ( cat "$cinfail" ; sleep 2; link_failure $listener_ns ; cat "$cinfail" ) | \ tee "$cinsent" | \ timeout ${timeout_test} \ @@ -1107,13 +1107,13 @@ do_transfer() return 1 fi - if [ "$test_link_fail" -gt 1 ];then + if [ "$test_linkfail" -gt 1 ];then check_transfer $sinfail $cout "file received by client" $trunc_size else check_transfer $sin $cout "file received by client" $trunc_size fi retc=$? - if [ "$test_link_fail" -eq 0 ];then + if [ "$test_linkfail" -eq 0 ];then check_transfer $cin $sout "file received by server" $trunc_size else check_transfer $cinsent $sout "file received by server" $trunc_size @@ -1146,11 +1146,10 @@ run_tests() local listener_ns="$1" local connector_ns="$2" local connect_addr="$3" - local test_linkfail="${4:-0}" - local addr_nr_ns1="${5:-0}" - local addr_nr_ns2="${6:-0}" - local speed="${7:-fast}" - local sflags="${8:-""}" + local addr_nr_ns1="${4:-0}" + local addr_nr_ns2="${5:-0}" + local speed="${6:-fast}" + local sflags="${7:-""}" local size @@ -1195,7 +1194,7 @@ run_tests() fi do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} \ - ${test_linkfail} ${addr_nr_ns1} ${addr_nr_ns2} ${speed} ${sflags} + ${addr_nr_ns1} ${addr_nr_ns2} ${speed} ${sflags} } dump_stats() @@ -1984,7 +1983,7 @@ subflows_error_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 0 0 0 fi @@ -1995,7 +1994,7 @@ subflows_error_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 1 1 1 fi @@ -2006,7 +2005,7 @@ subflows_error_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 1 1 1 fi @@ -2018,7 +2017,7 @@ subflows_error_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow & + run_tests $ns1 $ns2 10.0.1.1 0 0 slow & # mpj subflow will be in TW after the reset wait_attempt_fail $ns2 @@ -2117,7 +2116,7 @@ signal_address_tests() # the peer could possibly miss some addr notification, allow retransmission ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow # It is not directly linked to the commit introducing this # symbol but for the parent one which is linked anyway. @@ -2149,7 +2148,8 @@ link_failure_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 dev ns2eth4 flags subflow - run_tests $ns1 $ns2 10.0.1.1 1 + test_linkfail=1 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 3 3 3 chk_add_nr 1 1 chk_stale_nr $ns2 1 5 1 @@ -2164,7 +2164,8 @@ link_failure_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 dev ns2eth4 flags subflow - run_tests $ns1 $ns2 10.0.1.1 2 + test_linkfail=2 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 3 3 3 chk_add_nr 1 1 chk_stale_nr $ns2 1 -1 1 @@ -2178,8 +2179,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1" \ - run_tests $ns1 $ns2 10.0.1.1 1 + FAILING_LINKS="1" test_linkfail=1 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_link_usage $ns2 ns2eth3 $cinsent 0 @@ -2193,8 +2194,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1 2" \ - run_tests $ns1 $ns2 10.0.1.1 1 + FAILING_LINKS="1 2" test_linkfail=1 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_stale_nr $ns2 2 4 2 @@ -2209,8 +2210,8 @@ link_failure_tests() pm_nl_add_endpoint $ns1 10.0.2.1 dev ns1eth2 flags signal pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow,backup - FAILING_LINKS="1 2" \ - run_tests $ns1 $ns2 10.0.1.1 2 + FAILING_LINKS="1 2" test_linkfail=2 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 2 2 2 chk_add_nr 1 1 chk_stale_nr $ns2 1 -1 2 @@ -2225,7 +2226,7 @@ add_addr_timeout_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 1 1 1 chk_add_tx_nr 4 4 chk_add_nr 4 0 @@ -2236,7 +2237,7 @@ add_addr_timeout_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow chk_join_nr 1 1 1 chk_add_nr 4 0 fi @@ -2247,7 +2248,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 chk_join_nr 2 2 2 chk_add_nr 8 0 fi @@ -2258,7 +2259,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.12.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 chk_join_nr 1 1 1 chk_add_nr 8 0 fi @@ -2271,7 +2272,7 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 -1 slow + run_tests $ns1 $ns2 10.0.1.1 0 -1 slow chk_join_nr 1 1 1 chk_rm_tx_nr 1 chk_rm_nr 1 1 @@ -2283,7 +2284,7 @@ remove_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 -2 slow + run_tests $ns1 $ns2 10.0.1.1 0 -2 slow chk_join_nr 2 2 2 chk_rm_nr 2 2 fi @@ -2293,7 +2294,7 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 -1 0 slow + run_tests $ns1 $ns2 10.0.1.1 -1 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2305,7 +2306,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 -1 slow + run_tests $ns1 $ns2 10.0.1.1 -1 -1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 chk_rm_nr 1 1 @@ -2318,7 +2319,7 @@ remove_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 -2 speed_10 + run_tests $ns1 $ns2 10.0.1.1 -1 -2 speed_10 chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 2 2 @@ -2331,7 +2332,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 0 -3 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 -3 0 speed_10 chk_join_nr 3 3 3 chk_add_nr 3 3 chk_rm_nr 3 3 invert @@ -2344,7 +2345,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 0 -3 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 -3 0 speed_10 chk_join_nr 1 1 1 chk_add_nr 3 3 chk_rm_nr 3 1 invert @@ -2357,7 +2358,7 @@ remove_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow + run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 1 3 invert simult @@ -2370,7 +2371,7 @@ remove_tests() pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow id 150 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow + run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow chk_join_nr 3 3 3 if mptcp_lib_kversion_ge 5.18; then @@ -2388,7 +2389,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow + run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow chk_join_nr 3 3 3 chk_add_nr 3 3 chk_rm_nr 3 3 invert simult @@ -2401,7 +2402,7 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 0 -8 0 slow + run_tests $ns1 $ns2 10.0.1.1 -8 0 slow chk_join_nr 1 1 1 chk_add_nr 3 3 chk_rm_nr 3 1 invert @@ -2412,7 +2413,7 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 -9 slow + run_tests $ns1 $ns2 10.0.1.1 0 -9 slow chk_join_nr 1 1 1 chk_rm_nr 1 1 fi @@ -2422,7 +2423,7 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 -9 0 slow + run_tests $ns1 $ns2 10.0.1.1 -9 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2435,7 +2436,7 @@ add_tests() if reset "add single subflow"; then pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 1 slow + run_tests $ns1 $ns2 10.0.1.1 0 1 slow chk_join_nr 1 1 1 fi @@ -2443,7 +2444,7 @@ add_tests() if reset "add signal address"; then pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 1 0 slow + run_tests $ns1 $ns2 10.0.1.1 1 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 fi @@ -2452,7 +2453,7 @@ add_tests() if reset "add multiple subflows"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 0 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 2 slow + run_tests $ns1 $ns2 10.0.1.1 0 2 slow chk_join_nr 2 2 2 fi @@ -2460,7 +2461,7 @@ add_tests() if reset "add multiple subflows IPv6"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 0 2 - run_tests $ns1 $ns2 dead:beef:1::1 0 0 2 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 2 slow chk_join_nr 2 2 2 fi @@ -2468,7 +2469,7 @@ add_tests() if reset "add multiple addresses IPv6"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 dead:beef:1::1 0 2 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 2 0 slow chk_join_nr 2 2 2 chk_add_nr 2 2 fi @@ -2481,14 +2482,14 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 dead:beef:3::2 dev ns2eth3 flags subflow - run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow chk_join_nr 1 1 1 fi # add_address, unused IPv6 if reset "unused signal address IPv6"; then pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow chk_join_nr 0 0 0 chk_add_nr 1 1 fi @@ -2498,7 +2499,7 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 dead:beef:1::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 fi @@ -2508,7 +2509,7 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 dead:beef:1::1 0 -1 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 -1 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2520,7 +2521,7 @@ ipv6_tests() pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 dead:beef:3::2 dev ns2eth3 flags subflow - run_tests $ns1 $ns2 dead:beef:1::1 0 -1 -1 slow + run_tests $ns1 $ns2 dead:beef:1::1 -1 -1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 chk_rm_nr 1 1 @@ -2621,7 +2622,7 @@ mixed_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 0 0 0 fi @@ -2631,7 +2632,7 @@ mixed_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 10.0.1.1 flags signal - run_tests $ns1 $ns2 dead:beef:2::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:2::1 0 0 slow chk_join_nr 1 1 1 fi @@ -2642,7 +2643,7 @@ mixed_tests() pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns2 dead:beef:2::2 flags subflow,fullmesh pm_nl_add_endpoint $ns1 10.0.1.1 flags signal - run_tests $ns1 $ns2 dead:beef:2::1 0 0 0 slow + run_tests $ns1 $ns2 dead:beef:2::1 0 0 slow chk_join_nr 1 1 1 fi @@ -2654,7 +2655,7 @@ mixed_tests() pm_nl_set_limits $ns2 2 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 fullmesh_1 slow + run_tests $ns1 $ns2 dead:beef:1::1 0 fullmesh_1 slow chk_join_nr 4 4 4 fi } @@ -2667,7 +2668,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow nobackup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow nobackup chk_join_nr 1 1 1 chk_prio_nr 0 1 fi @@ -2678,7 +2679,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2690,7 +2691,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2699,7 +2700,7 @@ backup_tests() if reset "mpc backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2708,7 +2709,7 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow,backup pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 0 0 slow chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -2716,7 +2717,7 @@ backup_tests() if reset "mpc switch to backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2725,7 +2726,7 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -2814,7 +2815,7 @@ add_addr_ports_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 -1 0 slow + run_tests $ns1 $ns2 10.0.1.1 -1 0 slow chk_join_nr 1 1 1 chk_add_nr 1 1 1 chk_rm_nr 1 1 invert @@ -2830,7 +2831,7 @@ add_addr_ports_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 -1 slow + run_tests $ns1 $ns2 10.0.1.1 -1 -1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 1 chk_rm_nr 1 1 @@ -2843,7 +2844,7 @@ add_addr_ports_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -8 -2 slow + run_tests $ns1 $ns2 10.0.1.1 -8 -2 slow chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 1 3 invert simult @@ -3045,7 +3046,7 @@ fullmesh_tests() pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,fullmesh pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,fullmesh - run_tests $ns1 $ns2 10.0.1.1 0 1 0 slow + run_tests $ns1 $ns2 10.0.1.1 1 0 slow chk_join_nr 4 4 4 chk_add_nr 1 1 fi @@ -3057,7 +3058,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 1 3 pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 fullmesh_1 slow + run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_1 slow chk_join_nr 3 3 3 chk_add_nr 1 1 fi @@ -3069,7 +3070,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 2 5 pm_nl_set_limits $ns2 1 5 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 fullmesh_2 slow + run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_2 slow chk_join_nr 5 5 5 chk_add_nr 1 1 fi @@ -3082,7 +3083,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 2 4 pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 fullmesh_2 slow + run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_2 slow chk_join_nr 4 4 4 chk_add_nr 1 1 fi @@ -3093,7 +3094,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 0 1 slow fullmesh + run_tests $ns1 $ns2 10.0.1.1 0 1 slow fullmesh chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3104,7 +3105,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow,fullmesh pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 0 fullmesh_1 slow nofullmesh + run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_1 slow nofullmesh chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3115,7 +3116,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 0 1 slow backup,fullmesh + run_tests $ns1 $ns2 10.0.1.1 0 1 slow backup,fullmesh chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3127,7 +3128,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_set_limits $ns2 4 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup,fullmesh - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow nobackup,nofullmesh + run_tests $ns1 $ns2 10.0.1.1 0 0 slow nobackup,nofullmesh chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3137,14 +3138,16 @@ fullmesh_tests() fastclose_tests() { if reset_check_counter "fastclose test" "MPTcpExtMPFastcloseTx"; then - run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_client + test_linkfail=1024 \ + run_tests $ns1 $ns2 10.0.1.1 0 fastclose_client chk_join_nr 0 0 0 chk_fclose_nr 1 1 chk_rst_nr 1 1 invert fi if reset_check_counter "fastclose server test" "MPTcpExtMPFastcloseRx"; then - run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_server + test_linkfail=1024 \ + run_tests $ns1 $ns2 10.0.1.1 0 fastclose_server chk_join_nr 0 0 0 chk_fclose_nr 1 1 invert chk_rst_nr 1 1 @@ -3162,7 +3165,8 @@ fail_tests() { # single subflow if reset_with_fail "Infinite map" 1; then - run_tests $ns1 $ns2 10.0.1.1 128 + test_linkfail=128 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 +1 +0 1 0 1 "$(pedit_action_pkts)" chk_fail_nr 1 -1 invert fi @@ -3173,7 +3177,8 @@ fail_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.2.2 dev ns2eth2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 1024 + test_linkfail=1024 \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 1 1 1 1 0 1 1 0 "$(pedit_action_pkts)" fi } @@ -3298,7 +3303,7 @@ userspace_tests() pm_nl_set_limits $ns1 1 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup chk_join_nr 1 1 0 chk_prio_nr 0 0 fi @@ -3311,7 +3316,7 @@ userspace_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 -1 slow + run_tests $ns1 $ns2 10.0.1.1 0 -1 slow chk_join_nr 0 0 0 chk_rm_nr 0 0 fi @@ -3321,7 +3326,7 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 & + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 & local tests_pid=$! wait_mpj $ns1 userspace_pm_add_addr 10.0.2.1 10 @@ -3341,7 +3346,7 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns2 pm_nl_set_limits $ns1 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 0 speed_10 & + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 & local tests_pid=$! wait_mpj $ns2 userspace_pm_add_sf 10.0.3.2 20 @@ -3364,7 +3369,7 @@ endpoint_tests() pm_nl_set_limits $ns1 2 2 pm_nl_set_limits $ns2 2 2 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow 2>/dev/null & + run_tests $ns1 $ns2 10.0.1.1 0 0 slow 2>/dev/null & wait_mpj $ns1 pm_nl_check_endpoint 1 "creation" \ @@ -3387,7 +3392,8 @@ endpoint_tests() pm_nl_set_limits $ns1 1 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 4 0 0 speed_20 2>/dev/null & + test_linkfail=4 \ + run_tests $ns1 $ns2 10.0.1.1 0 0 speed_20 2>/dev/null & wait_mpj $ns2 chk_subflow_nr needtitle "before delete" 2 -- cgit v1.2.3 From 595ef566a2ef9af9e799491580e57c09c64c4e6d Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:11 -0700 Subject: selftests: mptcp: drop addr_nr_ns1/2 parameters run_tests() accepts too many optional parameters. Before this modification, it was required to set all of then when only the last one had to be changed. That's not clear to see all these 0 and it makes the maintenance harder: run_tests $ns1 $ns2 10.0.1.1 1 2 3 slow Instead, the parameter can be set as an env var with a limited scope: foo=1 bar=2 next=3 \ run_tests $ns1 $ns2 10.0.1.1 slow This patch switches to key/value "addr_nr_ns1=*, addr_nr_ns2=*" instead of positional parameters addr_nr_ns1 and addr_nr_ns2 of do_transfer() and run_tests(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-5-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 176 ++++++++++++++---------- 1 file changed, 103 insertions(+), 73 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index bc6a26d357bb..93f941fd51f2 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -51,6 +51,8 @@ nr_blank=40 export FAILING_LINKS="" export test_linkfail=0 +export addr_nr_ns1=0 +export addr_nr_ns2=0 # generated using "nfbpf_compile '(ip && (ip[54] & 0xf0) == 0x30) || # (ip6 && (ip6[74] & 0xf0) == 0x30)'" @@ -826,10 +828,8 @@ do_transfer() local cl_proto="$3" local srv_proto="$4" local connect_addr="$5" - local addr_nr_ns1="$6" - local addr_nr_ns2="$7" - local speed="$8" - local sflags="${9}" + local speed="$6" + local sflags="${7}" local port=$((10000 + TEST_COUNT - 1)) local cappid @@ -1146,10 +1146,8 @@ run_tests() local listener_ns="$1" local connector_ns="$2" local connect_addr="$3" - local addr_nr_ns1="${4:-0}" - local addr_nr_ns2="${5:-0}" - local speed="${6:-fast}" - local sflags="${7:-""}" + local speed="${4:-fast}" + local sflags="${5:-""}" local size @@ -1194,7 +1192,7 @@ run_tests() fi do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} \ - ${addr_nr_ns1} ${addr_nr_ns2} ${speed} ${sflags} + ${speed} ${sflags} } dump_stats() @@ -1983,7 +1981,7 @@ subflows_error_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 fi @@ -1994,7 +1992,7 @@ subflows_error_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 fi @@ -2005,7 +2003,7 @@ subflows_error_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 fi @@ -2017,7 +2015,7 @@ subflows_error_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow & + run_tests $ns1 $ns2 10.0.1.1 slow & # mpj subflow will be in TW after the reset wait_attempt_fail $ns2 @@ -2116,7 +2114,7 @@ signal_address_tests() # the peer could possibly miss some addr notification, allow retransmission ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1 - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow # It is not directly linked to the commit introducing this # symbol but for the parent one which is linked anyway. @@ -2226,7 +2224,7 @@ add_addr_timeout_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_tx_nr 4 4 chk_add_nr 4 0 @@ -2237,7 +2235,7 @@ add_addr_timeout_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 1 1 1 chk_add_nr 4 0 fi @@ -2248,7 +2246,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 2 2 2 chk_add_nr 8 0 fi @@ -2259,7 +2257,7 @@ add_addr_timeout_tests() pm_nl_add_endpoint $ns1 10.0.12.1 flags signal pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 1 1 1 chk_add_nr 8 0 fi @@ -2272,7 +2270,8 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 slow + addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_rm_tx_nr 1 chk_rm_nr 1 1 @@ -2284,7 +2283,8 @@ remove_tests() pm_nl_set_limits $ns2 0 2 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -2 slow + addr_nr_ns2=-2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_rm_nr 2 2 fi @@ -2294,7 +2294,8 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 -1 0 slow + addr_nr_ns1=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2306,7 +2307,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -1 -1 slow + addr_nr_ns1=-1 addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 chk_rm_nr 1 1 @@ -2319,7 +2321,8 @@ remove_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -1 -2 speed_10 + addr_nr_ns1=-1 addr_nr_ns2=-2 \ + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 2 2 @@ -2332,7 +2335,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 -3 0 speed_10 + addr_nr_ns1=-3 \ + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 3 3 3 chk_add_nr 3 3 chk_rm_nr 3 3 invert @@ -2345,7 +2349,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 -3 0 speed_10 + addr_nr_ns1=-3 \ + run_tests $ns1 $ns2 10.0.1.1 speed_10 chk_join_nr 1 1 1 chk_add_nr 3 3 chk_rm_nr 3 1 invert @@ -2358,7 +2363,8 @@ remove_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow + addr_nr_ns1=-8 addr_nr_ns2=-8 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 1 3 invert simult @@ -2371,7 +2377,8 @@ remove_tests() pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow id 150 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow + addr_nr_ns1=-8 addr_nr_ns2=-8 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 if mptcp_lib_kversion_ge 5.18; then @@ -2389,7 +2396,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.4.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 -8 -8 slow + addr_nr_ns1=-8 addr_nr_ns2=-8 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 chk_add_nr 3 3 chk_rm_nr 3 3 invert simult @@ -2402,7 +2410,8 @@ remove_tests() pm_nl_add_endpoint $ns1 10.0.3.1 flags signal pm_nl_add_endpoint $ns1 10.0.14.1 flags signal pm_nl_set_limits $ns2 3 3 - run_tests $ns1 $ns2 10.0.1.1 -8 0 slow + addr_nr_ns1=-8 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 3 3 chk_rm_nr 3 1 invert @@ -2413,7 +2422,8 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -9 slow + addr_nr_ns2=-9 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_rm_nr 1 1 fi @@ -2423,7 +2433,8 @@ remove_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 -9 0 slow + addr_nr_ns1=-9 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2436,7 +2447,8 @@ add_tests() if reset "add single subflow"; then pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 1 slow + addr_nr_ns2=1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 fi @@ -2444,7 +2456,8 @@ add_tests() if reset "add signal address"; then pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 1 0 slow + addr_nr_ns1=1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 fi @@ -2453,7 +2466,8 @@ add_tests() if reset "add multiple subflows"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 0 2 - run_tests $ns1 $ns2 10.0.1.1 0 2 slow + addr_nr_ns2=2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 fi @@ -2461,7 +2475,8 @@ add_tests() if reset "add multiple subflows IPv6"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 0 2 - run_tests $ns1 $ns2 dead:beef:1::1 0 2 slow + addr_nr_ns2=2 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 2 2 2 fi @@ -2469,7 +2484,8 @@ add_tests() if reset "add multiple addresses IPv6"; then pm_nl_set_limits $ns1 0 2 pm_nl_set_limits $ns2 2 2 - run_tests $ns1 $ns2 dead:beef:1::1 2 0 slow + addr_nr_ns1=2 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 2 2 2 chk_add_nr 2 2 fi @@ -2482,14 +2498,14 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 dead:beef:3::2 dev ns2eth3 flags subflow - run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 1 1 1 fi # add_address, unused IPv6 if reset "unused signal address IPv6"; then pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 0 0 0 chk_add_nr 1 1 fi @@ -2499,7 +2515,7 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 dead:beef:1::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 fi @@ -2509,7 +2525,8 @@ ipv6_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 dead:beef:1::1 -1 0 slow + addr_nr_ns1=-1 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_rm_nr 1 1 invert @@ -2521,7 +2538,8 @@ ipv6_tests() pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 dead:beef:3::2 dev ns2eth3 flags subflow - run_tests $ns1 $ns2 dead:beef:1::1 -1 -1 slow + addr_nr_ns1=-1 addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 chk_rm_nr 1 1 @@ -2622,7 +2640,7 @@ mixed_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 fi @@ -2632,7 +2650,7 @@ mixed_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns1 10.0.1.1 flags signal - run_tests $ns1 $ns2 dead:beef:2::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:2::1 slow chk_join_nr 1 1 1 fi @@ -2643,7 +2661,7 @@ mixed_tests() pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns2 dead:beef:2::2 flags subflow,fullmesh pm_nl_add_endpoint $ns1 10.0.1.1 flags signal - run_tests $ns1 $ns2 dead:beef:2::1 0 0 slow + run_tests $ns1 $ns2 dead:beef:2::1 slow chk_join_nr 1 1 1 fi @@ -2655,7 +2673,8 @@ mixed_tests() pm_nl_set_limits $ns2 2 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal - run_tests $ns1 $ns2 dead:beef:1::1 0 fullmesh_1 slow + addr_nr_ns2=fullmesh_1 \ + run_tests $ns1 $ns2 dead:beef:1::1 slow chk_join_nr 4 4 4 fi } @@ -2668,7 +2687,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 slow nobackup + run_tests $ns1 $ns2 10.0.1.1 slow nobackup chk_join_nr 1 1 1 chk_prio_nr 0 1 fi @@ -2679,7 +2698,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2691,7 +2710,7 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2700,7 +2719,7 @@ backup_tests() if reset "mpc backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2709,7 +2728,7 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow,backup pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 0 0 slow + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -2717,7 +2736,7 @@ backup_tests() if reset "mpc switch to backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2726,7 +2745,7 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -2815,7 +2834,8 @@ add_addr_ports_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 -1 0 slow + addr_nr_ns1=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 1 chk_rm_nr 1 1 invert @@ -2831,7 +2851,8 @@ add_addr_ports_tests() pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 2 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -1 -1 slow + addr_nr_ns1=-1 addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_add_nr 1 1 1 chk_rm_nr 1 1 @@ -2844,7 +2865,8 @@ add_addr_ports_tests() pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 -8 -2 slow + addr_nr_ns1=-8 addr_nr_ns2=-2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 chk_add_nr 1 1 chk_rm_nr 1 3 invert simult @@ -3046,7 +3068,8 @@ fullmesh_tests() pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,fullmesh pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,fullmesh - run_tests $ns1 $ns2 10.0.1.1 1 0 slow + addr_nr_ns1=1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 4 4 4 chk_add_nr 1 1 fi @@ -3058,7 +3081,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 1 3 pm_nl_set_limits $ns2 1 3 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_1 slow + addr_nr_ns2=fullmesh_1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 3 3 3 chk_add_nr 1 1 fi @@ -3070,7 +3094,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 2 5 pm_nl_set_limits $ns2 1 5 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_2 slow + addr_nr_ns2=fullmesh_2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 5 5 5 chk_add_nr 1 1 fi @@ -3083,7 +3108,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 2 4 pm_nl_set_limits $ns2 1 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_2 slow + addr_nr_ns2=fullmesh_2 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 4 4 4 chk_add_nr 1 1 fi @@ -3094,7 +3120,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 1 slow fullmesh + addr_nr_ns2=1 \ + run_tests $ns1 $ns2 10.0.1.1 slow fullmesh chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3105,7 +3132,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow,fullmesh pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 fullmesh_1 slow nofullmesh + addr_nr_ns2=fullmesh_1 \ + run_tests $ns1 $ns2 10.0.1.1 slow nofullmesh chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3116,7 +3144,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - run_tests $ns1 $ns2 10.0.1.1 0 1 slow backup,fullmesh + addr_nr_ns2=1 run_tests \ + $ns1 $ns2 10.0.1.1 slow backup,fullmesh chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3128,7 +3157,7 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_set_limits $ns2 4 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup,fullmesh - run_tests $ns1 $ns2 10.0.1.1 0 0 slow nobackup,nofullmesh + run_tests $ns1 $ns2 10.0.1.1 slow nobackup,nofullmesh chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3138,16 +3167,16 @@ fullmesh_tests() fastclose_tests() { if reset_check_counter "fastclose test" "MPTcpExtMPFastcloseTx"; then - test_linkfail=1024 \ - run_tests $ns1 $ns2 10.0.1.1 0 fastclose_client + test_linkfail=1024 addr_nr_ns2=fastclose_client \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 chk_fclose_nr 1 1 chk_rst_nr 1 1 invert fi if reset_check_counter "fastclose server test" "MPTcpExtMPFastcloseRx"; then - test_linkfail=1024 \ - run_tests $ns1 $ns2 10.0.1.1 0 fastclose_server + test_linkfail=1024 addr_nr_ns2=fastclose_server \ + run_tests $ns1 $ns2 10.0.1.1 chk_join_nr 0 0 0 chk_fclose_nr 1 1 invert chk_rst_nr 1 1 @@ -3303,7 +3332,7 @@ userspace_tests() pm_nl_set_limits $ns1 1 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 0 slow backup + run_tests $ns1 $ns2 10.0.1.1 slow backup chk_join_nr 1 1 0 chk_prio_nr 0 0 fi @@ -3316,7 +3345,8 @@ userspace_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 0 -1 slow + addr_nr_ns2=-1 \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_rm_nr 0 0 fi @@ -3326,7 +3356,7 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns1 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 & + run_tests $ns1 $ns2 10.0.1.1 speed_10 & local tests_pid=$! wait_mpj $ns1 userspace_pm_add_addr 10.0.2.1 10 @@ -3346,7 +3376,7 @@ userspace_tests() continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then set_userspace_pm $ns2 pm_nl_set_limits $ns1 0 1 - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_10 & + run_tests $ns1 $ns2 10.0.1.1 speed_10 & local tests_pid=$! wait_mpj $ns2 userspace_pm_add_sf 10.0.3.2 20 @@ -3369,7 +3399,7 @@ endpoint_tests() pm_nl_set_limits $ns1 2 2 pm_nl_set_limits $ns2 2 2 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal - run_tests $ns1 $ns2 10.0.1.1 0 0 slow 2>/dev/null & + run_tests $ns1 $ns2 10.0.1.1 slow 2>/dev/null & wait_mpj $ns1 pm_nl_check_endpoint 1 "creation" \ @@ -3393,7 +3423,7 @@ endpoint_tests() pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow test_linkfail=4 \ - run_tests $ns1 $ns2 10.0.1.1 0 0 speed_20 2>/dev/null & + run_tests $ns1 $ns2 10.0.1.1 speed_20 2>/dev/null & wait_mpj $ns2 chk_subflow_nr needtitle "before delete" 2 -- cgit v1.2.3 From 1534f87ee0dc1328043f7d0872fbf34937185682 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:12 -0700 Subject: selftests: mptcp: drop sflags parameter run_tests() accepts too many optional parameters. Before this modification, it was required to set all of then when only the last one had to be changed. That's not clear to see all these 0 and it makes the maintenance harder: run_tests $ns1 $ns2 10.0.1.1 1 2 3 slow Instead, the parameter can be set as an env var with a limited scope: foo=1 bar=2 next=3 \ run_tests $ns1 $ns2 10.0.1.1 slow This patch switches to key/value "sflags=*" instead of positional parameter sflags of do_transfer() and run_tests(). Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-6-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 39 ++++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 93f941fd51f2..5cb66f85c88f 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -53,6 +53,7 @@ export FAILING_LINKS="" export test_linkfail=0 export addr_nr_ns1=0 export addr_nr_ns2=0 +export sflags="" # generated using "nfbpf_compile '(ip && (ip[54] & 0xf0) == 0x30) || # (ip6 && (ip6[74] & 0xf0) == 0x30)'" @@ -829,7 +830,6 @@ do_transfer() local srv_proto="$4" local connect_addr="$5" local speed="$6" - local sflags="${7}" local port=$((10000 + TEST_COUNT - 1)) local cappid @@ -1147,7 +1147,6 @@ run_tests() local connector_ns="$2" local connect_addr="$3" local speed="${4:-fast}" - local sflags="${5:-""}" local size @@ -1191,8 +1190,7 @@ run_tests() make_file "$sinfail" "server" $size fi - do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} \ - ${speed} ${sflags} + do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} ${speed} } dump_stats() @@ -2687,7 +2685,8 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_set_limits $ns2 0 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup - run_tests $ns1 $ns2 10.0.1.1 slow nobackup + sflags=nobackup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_prio_nr 0 1 fi @@ -2698,7 +2697,8 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2710,7 +2710,8 @@ backup_tests() pm_nl_set_limits $ns1 0 1 pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100 pm_nl_set_limits $ns2 1 1 - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 1 chk_add_nr 1 1 chk_prio_nr 1 1 @@ -2736,7 +2737,8 @@ backup_tests() if reset "mpc switch to backup" && continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_prio_nr 0 1 fi @@ -2745,7 +2747,8 @@ backup_tests() continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 0 0 0 chk_prio_nr 1 1 fi @@ -3120,8 +3123,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - addr_nr_ns2=1 \ - run_tests $ns1 $ns2 10.0.1.1 slow fullmesh + addr_nr_ns2=1 sflags=fullmesh \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3132,8 +3135,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow,fullmesh pm_nl_set_limits $ns2 4 4 - addr_nr_ns2=fullmesh_1 \ - run_tests $ns1 $ns2 10.0.1.1 slow nofullmesh + addr_nr_ns2=fullmesh_1 sflags=nofullmesh \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_rm_nr 0 1 fi @@ -3144,8 +3147,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow pm_nl_set_limits $ns2 4 4 - addr_nr_ns2=1 run_tests \ - $ns1 $ns2 10.0.1.1 slow backup,fullmesh + addr_nr_ns2=1 sflags=backup,fullmesh \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3157,7 +3160,8 @@ fullmesh_tests() pm_nl_set_limits $ns1 4 4 pm_nl_set_limits $ns2 4 4 pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup,fullmesh - run_tests $ns1 $ns2 10.0.1.1 slow nobackup,nofullmesh + sflags=nobackup,nofullmesh \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 2 2 2 chk_prio_nr 0 1 chk_rm_nr 0 1 @@ -3332,7 +3336,8 @@ userspace_tests() pm_nl_set_limits $ns1 1 1 pm_nl_set_limits $ns2 1 1 pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow - run_tests $ns1 $ns2 10.0.1.1 slow backup + sflags=backup \ + run_tests $ns1 $ns2 10.0.1.1 slow chk_join_nr 1 1 0 chk_prio_nr 0 0 fi -- cgit v1.2.3 From 9e9d176df8e9aa74c9efc09ac1b4d348261cb630 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 23 Jun 2023 10:34:13 -0700 Subject: selftests: mptcp: add pm_nl_set_endpoint helper This patch moves endpoint settings out of do_transfer() into a new helper pm_nl_set_endpoint(). And invoke this helper in do_transfer(). This makes the code much more clearer. Reviewed-by: Matthieu Baerts Signed-off-by: Geliang Tang Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-7-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_join.sh | 235 ++++++++++++------------ 1 file changed, 122 insertions(+), 113 deletions(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index 5cb66f85c88f..e6c9d5451c5b 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -822,122 +822,11 @@ pm_nl_check_endpoint() fi } -do_transfer() +pm_nl_set_endpoint() { local listener_ns="$1" local connector_ns="$2" - local cl_proto="$3" - local srv_proto="$4" - local connect_addr="$5" - local speed="$6" - - local port=$((10000 + TEST_COUNT - 1)) - local cappid - - :> "$cout" - :> "$sout" - :> "$capout" - - if [ $capture -eq 1 ]; then - local capuser - if [ -z $SUDO_USER ] ; then - capuser="" - else - capuser="-Z $SUDO_USER" - fi - - capfile=$(printf "mp_join-%02u-%s.pcap" "$TEST_COUNT" "${listener_ns}") - - echo "Capturing traffic for test $TEST_COUNT into $capfile" - ip netns exec ${listener_ns} tcpdump -i any -s 65535 -B 32768 $capuser -w $capfile > "$capout" 2>&1 & - cappid=$! - - sleep 1 - fi - - NSTAT_HISTORY=/tmp/${listener_ns}.nstat ip netns exec ${listener_ns} \ - nstat -n - NSTAT_HISTORY=/tmp/${connector_ns}.nstat ip netns exec ${connector_ns} \ - nstat -n - - local extra_args - if [ $speed = "fast" ]; then - extra_args="-j" - elif [ $speed = "slow" ]; then - extra_args="-r 50" - elif [[ $speed = "speed_"* ]]; then - extra_args="-r ${speed:6}" - fi - - local flags="subflow" - local extra_cl_args="" - local extra_srv_args="" - local trunc_size="" - if [[ "${addr_nr_ns2}" = "fastclose_"* ]]; then - if [ ${test_linkfail} -le 1 ]; then - echo "fastclose tests need test_linkfail argument" - fail_test - return 1 - fi - - # disconnect - trunc_size=${test_linkfail} - local side=${addr_nr_ns2:10} - - if [ ${side} = "client" ]; then - extra_cl_args="-f ${test_linkfail}" - extra_srv_args="-f -1" - elif [ ${side} = "server" ]; then - extra_srv_args="-f ${test_linkfail}" - extra_cl_args="-f -1" - else - echo "wrong/unknown fastclose spec ${side}" - fail_test - return 1 - fi - addr_nr_ns2=0 - elif [[ "${addr_nr_ns2}" = "fullmesh_"* ]]; then - flags="${flags},fullmesh" - addr_nr_ns2=${addr_nr_ns2:9} - fi - - extra_srv_args="$extra_args $extra_srv_args" - if [ "$test_linkfail" -gt 1 ];then - timeout ${timeout_test} \ - ip netns exec ${listener_ns} \ - ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ - $extra_srv_args "::" < "$sinfail" > "$sout" & - else - timeout ${timeout_test} \ - ip netns exec ${listener_ns} \ - ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ - $extra_srv_args "::" < "$sin" > "$sout" & - fi - local spid=$! - - wait_local_port_listen "${listener_ns}" "${port}" - - extra_cl_args="$extra_args $extra_cl_args" - if [ "$test_linkfail" -eq 0 ];then - timeout ${timeout_test} \ - ip netns exec ${connector_ns} \ - ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_cl_args $connect_addr < "$cin" > "$cout" & - elif [ "$test_linkfail" -eq 1 ] || [ "$test_linkfail" -eq 2 ];then - ( cat "$cinfail" ; sleep 2; link_failure $listener_ns ; cat "$cinfail" ) | \ - tee "$cinsent" | \ - timeout ${timeout_test} \ - ip netns exec ${connector_ns} \ - ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_cl_args $connect_addr > "$cout" & - else - tee "$cinsent" < "$cinfail" | \ - timeout ${timeout_test} \ - ip netns exec ${connector_ns} \ - ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ - $extra_cl_args $connect_addr > "$cout" & - fi - local cpid=$! + local connect_addr="$3" # let the mptcp subflow be established in background before # do endpoint manipulation @@ -1077,6 +966,126 @@ do_transfer() done done fi +} + +do_transfer() +{ + local listener_ns="$1" + local connector_ns="$2" + local cl_proto="$3" + local srv_proto="$4" + local connect_addr="$5" + local speed="$6" + + local port=$((10000 + TEST_COUNT - 1)) + local cappid + + :> "$cout" + :> "$sout" + :> "$capout" + + if [ $capture -eq 1 ]; then + local capuser + if [ -z $SUDO_USER ] ; then + capuser="" + else + capuser="-Z $SUDO_USER" + fi + + capfile=$(printf "mp_join-%02u-%s.pcap" "$TEST_COUNT" "${listener_ns}") + + echo "Capturing traffic for test $TEST_COUNT into $capfile" + ip netns exec ${listener_ns} tcpdump -i any -s 65535 -B 32768 $capuser -w $capfile > "$capout" 2>&1 & + cappid=$! + + sleep 1 + fi + + NSTAT_HISTORY=/tmp/${listener_ns}.nstat ip netns exec ${listener_ns} \ + nstat -n + NSTAT_HISTORY=/tmp/${connector_ns}.nstat ip netns exec ${connector_ns} \ + nstat -n + + local extra_args + if [ $speed = "fast" ]; then + extra_args="-j" + elif [ $speed = "slow" ]; then + extra_args="-r 50" + elif [[ $speed = "speed_"* ]]; then + extra_args="-r ${speed:6}" + fi + + local flags="subflow" + local extra_cl_args="" + local extra_srv_args="" + local trunc_size="" + if [[ "${addr_nr_ns2}" = "fastclose_"* ]]; then + if [ ${test_linkfail} -le 1 ]; then + echo "fastclose tests need test_linkfail argument" + fail_test + return 1 + fi + + # disconnect + trunc_size=${test_linkfail} + local side=${addr_nr_ns2:10} + + if [ ${side} = "client" ]; then + extra_cl_args="-f ${test_linkfail}" + extra_srv_args="-f -1" + elif [ ${side} = "server" ]; then + extra_srv_args="-f ${test_linkfail}" + extra_cl_args="-f -1" + else + echo "wrong/unknown fastclose spec ${side}" + fail_test + return 1 + fi + addr_nr_ns2=0 + elif [[ "${addr_nr_ns2}" = "fullmesh_"* ]]; then + flags="${flags},fullmesh" + addr_nr_ns2=${addr_nr_ns2:9} + fi + + extra_srv_args="$extra_args $extra_srv_args" + if [ "$test_linkfail" -gt 1 ];then + timeout ${timeout_test} \ + ip netns exec ${listener_ns} \ + ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ + $extra_srv_args "::" < "$sinfail" > "$sout" & + else + timeout ${timeout_test} \ + ip netns exec ${listener_ns} \ + ./mptcp_connect -t ${timeout_poll} -l -p $port -s ${srv_proto} \ + $extra_srv_args "::" < "$sin" > "$sout" & + fi + local spid=$! + + wait_local_port_listen "${listener_ns}" "${port}" + + extra_cl_args="$extra_args $extra_cl_args" + if [ "$test_linkfail" -eq 0 ];then + timeout ${timeout_test} \ + ip netns exec ${connector_ns} \ + ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ + $extra_cl_args $connect_addr < "$cin" > "$cout" & + elif [ "$test_linkfail" -eq 1 ] || [ "$test_linkfail" -eq 2 ];then + ( cat "$cinfail" ; sleep 2; link_failure $listener_ns ; cat "$cinfail" ) | \ + tee "$cinsent" | \ + timeout ${timeout_test} \ + ip netns exec ${connector_ns} \ + ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ + $extra_cl_args $connect_addr > "$cout" & + else + tee "$cinsent" < "$cinfail" | \ + timeout ${timeout_test} \ + ip netns exec ${connector_ns} \ + ./mptcp_connect -t ${timeout_poll} -p $port -s ${cl_proto} \ + $extra_cl_args $connect_addr > "$cout" & + fi + local cpid=$! + + pm_nl_set_endpoint $listener_ns $connector_ns $connect_addr wait $cpid local retc=$? -- cgit v1.2.3 From e6b8a78ea266a2feeb3ac8cc6ed45bf667f6e405 Mon Sep 17 00:00:00 2001 From: Yueh-Shun Li Date: Fri, 23 Jun 2023 10:34:14 -0700 Subject: selftests: mptcp: connect: fix comment typo Spell "transmissions" properly. Found by searching for keyword "tranm". Reviewed-by: Matthieu Baerts Signed-off-by: Yueh-Shun Li Signed-off-by: Mat Martineau Link: https://lore.kernel.org/r/20230623-send-net-next-20230623-v1-8-a883213c8ba9@kernel.org Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/mptcp/mptcp_connect.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.sh b/tools/testing/selftests/net/mptcp/mptcp_connect.sh index 773dd770a567..13561e5bc0cd 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.sh @@ -809,7 +809,7 @@ run_tests_disconnect() cat $cin $cin $cin > "$cin".disconnect - # force do_transfer to cope with the multiple tranmissions + # force do_transfer to cope with the multiple transmissions sin="$cin.disconnect" cin="$cin.disconnect" cin_disconnect="$old_cin" -- cgit v1.2.3 From f1bc9fc4a06de0108e0dca2a9a7e99ba1fc632f9 Mon Sep 17 00:00:00 2001 From: Maxim Kochetkov Date: Thu, 22 Jun 2023 22:22:45 +0300 Subject: net: axienet: Move reset before 64-bit DMA detection 64-bit DMA detection will fail if axienet was started before (by boot loader, boot ROM, etc). In this state axienet will not start properly. XAXIDMA_TX_CDESC_OFFSET + 4 register (MM2S_CURDESC_MSB) is used to detect 64-bit DMA capability here. But datasheet says: When DMACR.RS is 1 (axienet is in enabled state), CURDESC_PTR becomes Read Only (RO) and is used to fetch the first descriptor. So iowrite32()/ioread32() trick to this register to detect 64-bit DMA will not work. So move axienet reset before 64-bit DMA detection. Fixes: f735c40ed93c ("net: axienet: Autodetect 64-bit DMA capability") Signed-off-by: Maxim Kochetkov Reviewed-by: Robert Hancock Reviewed-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/20230622192245.116864-1-fido_max@inbox.ru Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 3e310b55bce2..734822321e0a 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -2042,6 +2042,11 @@ static int axienet_probe(struct platform_device *pdev) goto cleanup_clk; } + /* Reset core now that clocks are enabled, prior to accessing MDIO */ + ret = __axienet_device_reset(lp); + if (ret) + goto cleanup_clk; + /* Autodetect the need for 64-bit DMA pointers. * When the IP is configured for a bus width bigger than 32 bits, * writing the MSB registers is mandatory, even if they are all 0. @@ -2096,11 +2101,6 @@ static int axienet_probe(struct platform_device *pdev) lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD; lp->coalesce_usec_tx = XAXIDMA_DFT_TX_USEC; - /* Reset core now that clocks are enabled, prior to accessing MDIO */ - ret = __axienet_device_reset(lp); - if (ret) - goto cleanup_clk; - ret = axienet_mdio_setup(lp); if (ret) dev_warn(&pdev->dev, -- cgit v1.2.3 From 737eab775d367b0ba6575d8aa2073c607a9bcf9e Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Fri, 23 Jun 2023 21:19:26 +0100 Subject: netlink: specs: add display-hint to schema definitions Add a display-hint property to the netlink schema that is for providing optional hints to generic netlink clients about how to display attribute values. A display-hint on an attribute definition is intended for letting a client such as ynl know that, for example, a u32 should be rendered as an ipv4 address. The display-hint enumeration includes a small number of networking domain-specific value types. Signed-off-by: Donald Hunter Link: https://lore.kernel.org/r/20230623201928.14275-2-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/genetlink-c.yaml | 6 ++++++ Documentation/netlink/genetlink-legacy.yaml | 11 ++++++++++- Documentation/netlink/genetlink.yaml | 6 ++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/netlink/genetlink-c.yaml b/Documentation/netlink/genetlink-c.yaml index 0519c257ecf4..57d1c1c4918f 100644 --- a/Documentation/netlink/genetlink-c.yaml +++ b/Documentation/netlink/genetlink-c.yaml @@ -195,6 +195,12 @@ properties: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' sub-type: *attr-type + display-hint: &display-hint + description: | + Optional format indicator that is intended only for choosing + the right formatting mechanism when displaying values of this + type. + enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] # Start genetlink-c name-prefix: type: string diff --git a/Documentation/netlink/genetlink-legacy.yaml b/Documentation/netlink/genetlink-legacy.yaml index b474889b49ff..43b769c98fb2 100644 --- a/Documentation/netlink/genetlink-legacy.yaml +++ b/Documentation/netlink/genetlink-legacy.yaml @@ -119,7 +119,8 @@ properties: name: type: string type: - enum: [ u8, u16, u32, u64, s8, s16, s32, s64, string ] + description: The netlink attribute type + enum: [ u8, u16, u32, u64, s8, s16, s32, s64, string, binary ] len: $ref: '#/$defs/len-or-define' byte-order: @@ -130,6 +131,12 @@ properties: enum: description: Name of the enum type used for the attribute. type: string + display-hint: &display-hint + description: | + Optional format indicator that is intended only for choosing + the right formatting mechanism when displaying values of this + type. + enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] # End genetlink-legacy attribute-sets: @@ -179,6 +186,7 @@ properties: name: type: string type: &attr-type + description: The netlink attribute type enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64, string, nest, array-nest, nest-type-value ] doc: @@ -226,6 +234,7 @@ properties: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' sub-type: *attr-type + display-hint: *display-hint # Start genetlink-c name-prefix: type: string diff --git a/Documentation/netlink/genetlink.yaml b/Documentation/netlink/genetlink.yaml index d8b2cdeba058..1cbb448d2f1c 100644 --- a/Documentation/netlink/genetlink.yaml +++ b/Documentation/netlink/genetlink.yaml @@ -168,6 +168,12 @@ properties: description: Max length for a string or a binary attribute. $ref: '#/$defs/len-or-define' sub-type: *attr-type + display-hint: &display-hint + description: | + Optional format indicator that is intended only for choosing + the right formatting mechanism when displaying values of this + type. + enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] # Make sure name-prefix does not appear in subsets (subsets inherit naming) dependencies: -- cgit v1.2.3 From d8eea68d913c20aabb3a97bc1e9ba61407a9e872 Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Fri, 23 Jun 2023 21:19:27 +0100 Subject: tools: ynl: add display-hint support to ynl Add support to the ynl tool for rendering output based on display-hint properties. Signed-off-by: Donald Hunter Link: https://lore.kernel.org/r/20230623201928.14275-3-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/lib/nlspec.py | 10 ++++++++++ tools/net/ynl/lib/ynl.py | 34 +++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/tools/net/ynl/lib/nlspec.py b/tools/net/ynl/lib/nlspec.py index 1ba572cae27b..0ff0d18666b2 100644 --- a/tools/net/ynl/lib/nlspec.py +++ b/tools/net/ynl/lib/nlspec.py @@ -154,6 +154,9 @@ class SpecAttr(SpecElement): is_multi bool, attr may repeat multiple times struct_name string, name of struct definition sub_type string, name of sub type + len integer, optional byte length of binary types + display_hint string, hint to help choose format specifier + when displaying the value """ def __init__(self, family, attr_set, yaml, value): super().__init__(family, yaml) @@ -164,6 +167,8 @@ class SpecAttr(SpecElement): self.struct_name = yaml.get('struct') self.sub_type = yaml.get('sub-type') self.byte_order = yaml.get('byte-order') + self.len = yaml.get('len') + self.display_hint = yaml.get('display-hint') class SpecAttrSet(SpecElement): @@ -229,12 +234,17 @@ class SpecStructMember(SpecElement): type string, type of the member attribute byte_order string or None for native byte order enum string, name of the enum definition + len integer, optional byte length of binary types + display_hint string, hint to help choose format specifier + when displaying the value """ def __init__(self, family, yaml): super().__init__(family, yaml) self.type = yaml['type'] self.byte_order = yaml.get('byte-order') self.enum = yaml.get('enum') + self.len = yaml.get('len') + self.display_hint = yaml.get('display-hint') class SpecStruct(SpecElement): diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py index 3b343d6cbbc0..1b3a36fbb1c3 100644 --- a/tools/net/ynl/lib/ynl.py +++ b/tools/net/ynl/lib/ynl.py @@ -8,6 +8,8 @@ import socket import struct from struct import Struct import yaml +import ipaddress +import uuid from .nlspec import SpecFamily @@ -105,6 +107,20 @@ class NlAttr: else format.little return format.native + @classmethod + def formatted_string(cls, raw, display_hint): + if display_hint == 'mac': + formatted = ':'.join('%02x' % b for b in raw) + elif display_hint == 'hex': + formatted = bytes.hex(raw, ' ') + elif display_hint in [ 'ipv4', 'ipv6' ]: + formatted = format(ipaddress.ip_address(raw)) + elif display_hint == 'uuid': + formatted = str(uuid.UUID(bytes=raw)) + else: + formatted = raw + return formatted + def as_scalar(self, attr_type, byte_order=None): format = self.get_format(attr_type, byte_order) return format.unpack(self.raw)[0] @@ -124,10 +140,16 @@ class NlAttr: offset = 0 for m in members: # TODO: handle non-scalar members - format = self.get_format(m.type, m.byte_order) - decoded = format.unpack_from(self.raw, offset) - offset += format.size - value[m.name] = decoded[0] + if m.type == 'binary': + decoded = self.raw[offset:offset+m['len']] + offset += m['len'] + elif m.type in NlAttr.type_formats: + format = self.get_format(m.type, m.byte_order) + [ decoded ] = format.unpack_from(self.raw, offset) + offset += format.size + if m.display_hint: + decoded = self.formatted_string(decoded, m.display_hint) + value[m.name] = decoded return value def __repr__(self): @@ -385,7 +407,7 @@ class YnlFamily(SpecFamily): elif attr["type"] == 'string': attr_payload = str(value).encode('ascii') + b'\x00' elif attr["type"] == 'binary': - attr_payload = value + attr_payload = bytes.fromhex(value) elif attr['type'] in NlAttr.type_formats: format = NlAttr.get_format(attr['type'], attr.byte_order) attr_payload = format.pack(int(value)) @@ -421,6 +443,8 @@ class YnlFamily(SpecFamily): decoded = attr.as_c_array(attr_spec.sub_type) else: decoded = attr.as_bin() + if attr_spec.display_hint: + decoded = NlAttr.formatted_string(decoded, attr_spec.display_hint) return decoded def _decode(self, attrs, space): -- cgit v1.2.3 From 334f39ce17eff255f243ab5998af27ae40f9f04c Mon Sep 17 00:00:00 2001 From: Donald Hunter Date: Fri, 23 Jun 2023 21:19:28 +0100 Subject: netlink: specs: add display hints to ovs_flow Add display hints for mac, ipv4, ipv6, hex and uuid to the ovs_flow schema. Signed-off-by: Donald Hunter Link: https://lore.kernel.org/r/20230623201928.14275-4-donald.hunter@gmail.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/ovs_flow.yaml | 107 ++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/Documentation/netlink/specs/ovs_flow.yaml b/Documentation/netlink/specs/ovs_flow.yaml index 1ecbcd117385..109ca1f57b6c 100644 --- a/Documentation/netlink/specs/ovs_flow.yaml +++ b/Documentation/netlink/specs/ovs_flow.yaml @@ -33,6 +33,20 @@ definitions: name: n-bytes type: u64 doc: Number of matched bytes. + - + name: ovs-key-ethernet + type: struct + members: + - + name: eth-src + type: binary + len: 6 + display-hint: mac + - + name: eth-dst + type: binary + len: 6 + display-hint: mac - name: ovs-key-mpls type: struct @@ -49,10 +63,12 @@ definitions: name: ipv4-src type: u32 byte-order: big-endian + display-hint: ipv4 - name: ipv4-dst type: u32 byte-order: big-endian + display-hint: ipv4 - name: ipv4-proto type: u8 @@ -66,6 +82,45 @@ definitions: name: ipv4-frag type: u8 enum: ovs-frag-type + - + name: ovs-key-ipv6 + type: struct + members: + - + name: ipv6-src + type: binary + len: 16 + byte-order: big-endian + display-hint: ipv6 + - + name: ipv6-dst + type: binary + len: 16 + byte-order: big-endian + display-hint: ipv6 + - + name: ipv6-label + type: u32 + byte-order: big-endian + - + name: ipv6-proto + type: u8 + - + name: ipv6-tclass + type: u8 + - + name: ipv6-hlimit + type: u8 + - + name: ipv6-frag + type: u8 + - + name: ovs-key-ipv6-exthdrs + type: struct + members: + - + name: hdrs + type: u16 - name: ovs-frag-type name-prefix: ovs-frag-type- @@ -129,6 +184,51 @@ definitions: - name: icmp-code type: u8 + - + name: ovs-key-arp + type: struct + members: + - + name: arp-sip + type: u32 + byte-order: big-endian + - + name: arp-tip + type: u32 + byte-order: big-endian + - + name: arp-op + type: u16 + byte-order: big-endian + - + name: arp-sha + type: binary + len: 6 + display-hint: mac + - + name: arp-tha + type: binary + len: 6 + display-hint: mac + - + name: ovs-key-nd + type: struct + members: + - + name: nd_target + type: binary + len: 16 + byte-order: big-endian + - + name: nd-sll + type: binary + len: 6 + display-hint: mac + - + name: nd-tll + type: binary + len: 6 + display-hint: mac - name: ovs-key-ct-tuple-ipv4 type: struct @@ -345,6 +445,7 @@ attribute-sets: value of the OVS_FLOW_ATTR_KEY attribute. Optional for all requests. Present in notifications if the flow was created with this attribute. + display-hint: uuid - name: ufid-flags type: u32 @@ -374,6 +475,7 @@ attribute-sets: - name: ethernet type: binary + struct: ovs-key-ethernet doc: struct ovs_key_ethernet - name: vlan @@ -390,6 +492,7 @@ attribute-sets: - name: ipv6 type: binary + struct: ovs-key-ipv6 doc: struct ovs_key_ipv6 - name: tcp @@ -410,10 +513,12 @@ attribute-sets: - name: arp type: binary + struct: ovs-key-arp doc: struct ovs_key_arp - name: nd type: binary + struct: ovs-key-nd doc: struct ovs_key_nd - name: skb-mark @@ -457,6 +562,7 @@ attribute-sets: - name: ct-labels type: binary + display-hint: hex doc: 16-octet connection tracking label - name: ct-orig-tuple-ipv4 @@ -486,6 +592,7 @@ attribute-sets: - name: ipv6-exthdrs type: binary + struct: ovs-key-ipv6-exthdrs doc: struct ovs_key_ipv6_exthdr - name: action-attrs -- cgit v1.2.3 From f8dd95b29d7ef08c19ec9720564acf72243ddcf6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:54:58 +0100 Subject: tcp_bpf, smc, tls, espintcp, siw: Reduce MSG_SENDPAGE_NOTLAST usage As MSG_SENDPAGE_NOTLAST is being phased out along with sendpage(), don't use it further in than the sendpage methods, but rather translate it to MSG_MORE and use that instead. Signed-off-by: David Howells cc: Willem de Bruijn cc: Bernard Metzler cc: Jason Gunthorpe cc: Leon Romanovsky cc: John Fastabend cc: Jakub Sitnicki cc: David Ahern cc: Karsten Graul cc: Wenjia Zhang cc: Jan Karcher cc: "D. Wythe" cc: Tony Lu cc: Wen Gu cc: Boris Pismenny cc: Steffen Klassert cc: Herbert Xu Link: https://lore.kernel.org/r/20230623225513.2732256-2-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- drivers/infiniband/sw/siw/siw_qp_tx.c | 5 ++--- net/ipv4/tcp_bpf.c | 5 +++-- net/smc/smc_tx.c | 6 ++++-- net/tls/tls_device.c | 4 ++-- net/xfrm/espintcp.c | 10 ++++++---- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c index ffb16beb6c30..7c7a51d36d0c 100644 --- a/drivers/infiniband/sw/siw/siw_qp_tx.c +++ b/drivers/infiniband/sw/siw/siw_qp_tx.c @@ -325,8 +325,7 @@ static int siw_tcp_sendpages(struct socket *s, struct page **page, int offset, { struct bio_vec bvec; struct msghdr msg = { - .msg_flags = (MSG_MORE | MSG_DONTWAIT | MSG_SENDPAGE_NOTLAST | - MSG_SPLICE_PAGES), + .msg_flags = (MSG_MORE | MSG_DONTWAIT | MSG_SPLICE_PAGES), }; struct sock *sk = s->sk; int i = 0, rv = 0, sent = 0; @@ -335,7 +334,7 @@ static int siw_tcp_sendpages(struct socket *s, struct page **page, int offset, size_t bytes = min_t(size_t, PAGE_SIZE - offset, size); if (size + offset <= PAGE_SIZE) - msg.msg_flags &= ~MSG_SENDPAGE_NOTLAST; + msg.msg_flags &= ~MSG_MORE; tcp_rate_check_app_limited(sk); bvec_set_page(&bvec, page[i], bytes, offset); diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index 5a84053ac62b..31d6005cea9b 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -88,9 +88,9 @@ static int bpf_tcp_ingress(struct sock *sk, struct sk_psock *psock, static int tcp_bpf_push(struct sock *sk, struct sk_msg *msg, u32 apply_bytes, int flags, bool uncharge) { + struct msghdr msghdr = {}; bool apply = apply_bytes; struct scatterlist *sge; - struct msghdr msghdr = { .msg_flags = flags | MSG_SPLICE_PAGES, }; struct page *page; int size, ret = 0; u32 off; @@ -107,11 +107,12 @@ static int tcp_bpf_push(struct sock *sk, struct sk_msg *msg, u32 apply_bytes, tcp_rate_check_app_limited(sk); retry: + msghdr.msg_flags = flags | MSG_SPLICE_PAGES; has_tx_ulp = tls_sw_has_ctx_tx(sk); if (has_tx_ulp) msghdr.msg_flags |= MSG_SENDPAGE_NOPOLICY; - if (flags & MSG_SENDPAGE_NOTLAST) + if (size < sge->length && msg->sg.start != msg->sg.end) msghdr.msg_flags |= MSG_MORE; bvec_set_page(&bvec, page, size, off); diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index 45128443f1f1..9b9e0a190734 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c @@ -168,8 +168,7 @@ static bool smc_tx_should_cork(struct smc_sock *smc, struct msghdr *msg) * should known how/when to uncork it. */ if ((msg->msg_flags & MSG_MORE || - smc_tx_is_corked(smc) || - msg->msg_flags & MSG_SENDPAGE_NOTLAST) && + smc_tx_is_corked(smc)) && atomic_read(&conn->sndbuf_space)) return true; @@ -306,6 +305,9 @@ int smc_tx_sendpage(struct smc_sock *smc, struct page *page, int offset, struct kvec iov; int rc; + if (flags & MSG_SENDPAGE_NOTLAST) + msg.msg_flags |= MSG_MORE; + iov.iov_base = kaddr + offset; iov.iov_len = size; iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, size); diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index b82770f68807..975299d7213b 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -449,7 +449,7 @@ static int tls_push_data(struct sock *sk, return -sk->sk_err; flags |= MSG_SENDPAGE_DECRYPTED; - tls_push_record_flags = flags | MSG_SENDPAGE_NOTLAST; + tls_push_record_flags = flags | MSG_MORE; timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); if (tls_is_partially_sent_record(tls_ctx)) { @@ -532,7 +532,7 @@ handle_error: if (!size) { last_record: tls_push_record_flags = flags; - if (flags & (MSG_SENDPAGE_NOTLAST | MSG_MORE)) { + if (flags & MSG_MORE) { more = true; break; } diff --git a/net/xfrm/espintcp.c b/net/xfrm/espintcp.c index 3504925babdb..d3b3f9e720b3 100644 --- a/net/xfrm/espintcp.c +++ b/net/xfrm/espintcp.c @@ -205,13 +205,15 @@ static int espintcp_sendskb_locked(struct sock *sk, struct espintcp_msg *emsg, static int espintcp_sendskmsg_locked(struct sock *sk, struct espintcp_msg *emsg, int flags) { - struct msghdr msghdr = { .msg_flags = flags | MSG_SPLICE_PAGES, }; + struct msghdr msghdr = { + .msg_flags = flags | MSG_SPLICE_PAGES | MSG_MORE, + }; struct sk_msg *skmsg = &emsg->skmsg; + bool more = flags & MSG_MORE; struct scatterlist *sg; int done = 0; int ret; - msghdr.msg_flags |= MSG_SENDPAGE_NOTLAST; sg = &skmsg->sg.data[skmsg->sg.start]; do { struct bio_vec bvec; @@ -221,8 +223,8 @@ static int espintcp_sendskmsg_locked(struct sock *sk, emsg->offset = 0; - if (sg_is_last(sg)) - msghdr.msg_flags &= ~MSG_SENDPAGE_NOTLAST; + if (sg_is_last(sg) && !more) + msghdr.msg_flags &= ~MSG_MORE; p = sg_page(sg); retry: -- cgit v1.2.3 From c729ed6f5be57b4d164dbbc415554c066e29306b Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:54:59 +0100 Subject: net: Use sendmsg(MSG_SPLICE_PAGES) not sendpage in skb_send_sock() Use sendmsg() with MSG_SPLICE_PAGES rather than sendpage in skb_send_sock(). This causes pages to be spliced from the source iterator if possible. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Note that this could perhaps be improved to fill out a bvec array with all the frags and then make a single sendmsg call, possibly sticking the header on the front also. Signed-off-by: David Howells cc: Jens Axboe cc: Matthew Wilcox Link: https://lore.kernel.org/r/20230623225513.2732256-3-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- net/core/skbuff.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index fee2b1c105fe..6c5915efbc17 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2989,32 +2989,32 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, } EXPORT_SYMBOL_GPL(skb_splice_bits); -static int sendmsg_unlocked(struct sock *sk, struct msghdr *msg, - struct kvec *vec, size_t num, size_t size) +static int sendmsg_locked(struct sock *sk, struct msghdr *msg) { struct socket *sock = sk->sk_socket; + size_t size = msg_data_left(msg); if (!sock) return -EINVAL; - return kernel_sendmsg(sock, msg, vec, num, size); + + if (!sock->ops->sendmsg_locked) + return sock_no_sendmsg_locked(sk, msg, size); + + return sock->ops->sendmsg_locked(sk, msg, size); } -static int sendpage_unlocked(struct sock *sk, struct page *page, int offset, - size_t size, int flags) +static int sendmsg_unlocked(struct sock *sk, struct msghdr *msg) { struct socket *sock = sk->sk_socket; if (!sock) return -EINVAL; - return kernel_sendpage(sock, page, offset, size, flags); + return sock_sendmsg(sock, msg); } -typedef int (*sendmsg_func)(struct sock *sk, struct msghdr *msg, - struct kvec *vec, size_t num, size_t size); -typedef int (*sendpage_func)(struct sock *sk, struct page *page, int offset, - size_t size, int flags); +typedef int (*sendmsg_func)(struct sock *sk, struct msghdr *msg); static int __skb_send_sock(struct sock *sk, struct sk_buff *skb, int offset, - int len, sendmsg_func sendmsg, sendpage_func sendpage) + int len, sendmsg_func sendmsg) { unsigned int orig_len = len; struct sk_buff *head = skb; @@ -3034,8 +3034,9 @@ do_frag_list: memset(&msg, 0, sizeof(msg)); msg.msg_flags = MSG_DONTWAIT; - ret = INDIRECT_CALL_2(sendmsg, kernel_sendmsg_locked, - sendmsg_unlocked, sk, &msg, &kv, 1, slen); + iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &kv, 1, slen); + ret = INDIRECT_CALL_2(sendmsg, sendmsg_locked, + sendmsg_unlocked, sk, &msg); if (ret <= 0) goto error; @@ -3066,11 +3067,18 @@ do_frag_list: slen = min_t(size_t, len, skb_frag_size(frag) - offset); while (slen) { - ret = INDIRECT_CALL_2(sendpage, kernel_sendpage_locked, - sendpage_unlocked, sk, - skb_frag_page(frag), - skb_frag_off(frag) + offset, - slen, MSG_DONTWAIT); + struct bio_vec bvec; + struct msghdr msg = { + .msg_flags = MSG_SPLICE_PAGES | MSG_DONTWAIT, + }; + + bvec_set_page(&bvec, skb_frag_page(frag), slen, + skb_frag_off(frag) + offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, + slen); + + ret = INDIRECT_CALL_2(sendmsg, sendmsg_locked, + sendmsg_unlocked, sk, &msg); if (ret <= 0) goto error; @@ -3107,16 +3115,14 @@ error: int skb_send_sock_locked(struct sock *sk, struct sk_buff *skb, int offset, int len) { - return __skb_send_sock(sk, skb, offset, len, kernel_sendmsg_locked, - kernel_sendpage_locked); + return __skb_send_sock(sk, skb, offset, len, sendmsg_locked); } EXPORT_SYMBOL_GPL(skb_send_sock_locked); /* Send skb data on a socket. Socket must be unlocked. */ int skb_send_sock(struct sock *sk, struct sk_buff *skb, int offset, int len) { - return __skb_send_sock(sk, skb, offset, len, sendmsg_unlocked, - sendpage_unlocked); + return __skb_send_sock(sk, skb, offset, len, sendmsg_unlocked); } /** -- cgit v1.2.3 From 40a8c17aa7709caaeb9c6945297a98fe8699ca1b Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:00 +0100 Subject: ceph: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage Use sendmsg() and MSG_SPLICE_PAGES rather than sendpage in ceph when transmitting data. For the moment, this can only transmit one page at a time because of the architecture of net/ceph/, but if write_partial_message_data() can be given a bvec[] at a time by the iteration code, this would allow pages to be sent in a batch. Signed-off-by: David Howells cc: Ilya Dryomov cc: Xiubo Li cc: Jeff Layton cc: Jens Axboe cc: Matthew Wilcox Link: https://lore.kernel.org/r/20230623225513.2732256-4-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- net/ceph/messenger_v1.c | 60 +++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/net/ceph/messenger_v1.c b/net/ceph/messenger_v1.c index d664cb1593a7..814579f27f04 100644 --- a/net/ceph/messenger_v1.c +++ b/net/ceph/messenger_v1.c @@ -74,37 +74,6 @@ static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov, return r; } -/* - * @more: either or both of MSG_MORE and MSG_SENDPAGE_NOTLAST - */ -static int ceph_tcp_sendpage(struct socket *sock, struct page *page, - int offset, size_t size, int more) -{ - ssize_t (*sendpage)(struct socket *sock, struct page *page, - int offset, size_t size, int flags); - int flags = MSG_DONTWAIT | MSG_NOSIGNAL | more; - int ret; - - /* - * sendpage cannot properly handle pages with page_count == 0, - * we need to fall back to sendmsg if that's the case. - * - * Same goes for slab pages: skb_can_coalesce() allows - * coalescing neighboring slab objects into a single frag which - * triggers one of hardened usercopy checks. - */ - if (sendpage_ok(page)) - sendpage = sock->ops->sendpage; - else - sendpage = sock_no_sendpage; - - ret = sendpage(sock, page, offset, size, flags); - if (ret == -EAGAIN) - ret = 0; - - return ret; -} - static void con_out_kvec_reset(struct ceph_connection *con) { BUG_ON(con->v1.out_skip); @@ -464,7 +433,6 @@ static int write_partial_message_data(struct ceph_connection *con) struct ceph_msg *msg = con->out_msg; struct ceph_msg_data_cursor *cursor = &msg->cursor; bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC); - int more = MSG_MORE | MSG_SENDPAGE_NOTLAST; u32 crc; dout("%s %p msg %p\n", __func__, con, msg); @@ -482,6 +450,10 @@ static int write_partial_message_data(struct ceph_connection *con) */ crc = do_datacrc ? le32_to_cpu(msg->footer.data_crc) : 0; while (cursor->total_resid) { + struct bio_vec bvec; + struct msghdr msghdr = { + .msg_flags = MSG_SPLICE_PAGES, + }; struct page *page; size_t page_offset; size_t length; @@ -493,10 +465,13 @@ static int write_partial_message_data(struct ceph_connection *con) } page = ceph_msg_data_next(cursor, &page_offset, &length); - if (length == cursor->total_resid) - more = MSG_MORE; - ret = ceph_tcp_sendpage(con->sock, page, page_offset, length, - more); + if (length != cursor->total_resid) + msghdr.msg_flags |= MSG_MORE; + + bvec_set_page(&bvec, page, length, page_offset); + iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, length); + + ret = sock_sendmsg(con->sock, &msghdr); if (ret <= 0) { if (do_datacrc) msg->footer.data_crc = cpu_to_le32(crc); @@ -526,7 +501,10 @@ static int write_partial_message_data(struct ceph_connection *con) */ static int write_partial_skip(struct ceph_connection *con) { - int more = MSG_MORE | MSG_SENDPAGE_NOTLAST; + struct bio_vec bvec; + struct msghdr msghdr = { + .msg_flags = MSG_SPLICE_PAGES | MSG_MORE, + }; int ret; dout("%s %p %d left\n", __func__, con, con->v1.out_skip); @@ -534,9 +512,11 @@ static int write_partial_skip(struct ceph_connection *con) size_t size = min(con->v1.out_skip, (int)PAGE_SIZE); if (size == con->v1.out_skip) - more = MSG_MORE; - ret = ceph_tcp_sendpage(con->sock, ceph_zero_page, 0, size, - more); + msghdr.msg_flags &= ~MSG_MORE; + bvec_set_page(&bvec, ZERO_PAGE(0), size, 0); + iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, size); + + ret = sock_sendmsg(con->sock, &msghdr); if (ret <= 0) goto out; con->v1.out_skip -= ret; -- cgit v1.2.3 From fa094ccae1e7904d9fa7bb1bc44c9873eec7baf4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:01 +0100 Subject: ceph: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage() Use sendmsg() and MSG_SPLICE_PAGES rather than sendpage in ceph when transmitting data. For the moment, this can only transmit one page at a time because of the architecture of net/ceph/, but if write_partial_message_data() can be given a bvec[] at a time by the iteration code, this would allow pages to be sent in a batch. Signed-off-by: David Howells cc: Ilya Dryomov cc: Xiubo Li cc: Jeff Layton cc: Jens Axboe cc: Matthew Wilcox Link: https://lore.kernel.org/r/20230623225513.2732256-5-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- net/ceph/messenger_v2.c | 91 +++++++++++-------------------------------------- 1 file changed, 19 insertions(+), 72 deletions(-) diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c index 301a991dc6a6..87ac97073e75 100644 --- a/net/ceph/messenger_v2.c +++ b/net/ceph/messenger_v2.c @@ -117,91 +117,38 @@ static int ceph_tcp_recv(struct ceph_connection *con) return ret; } -static int do_sendmsg(struct socket *sock, struct iov_iter *it) -{ - struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS }; - int ret; - - msg.msg_iter = *it; - while (iov_iter_count(it)) { - ret = sock_sendmsg(sock, &msg); - if (ret <= 0) { - if (ret == -EAGAIN) - ret = 0; - return ret; - } - - iov_iter_advance(it, ret); - } - - WARN_ON(msg_data_left(&msg)); - return 1; -} - -static int do_try_sendpage(struct socket *sock, struct iov_iter *it) -{ - struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS }; - struct bio_vec bv; - int ret; - - if (WARN_ON(!iov_iter_is_bvec(it))) - return -EINVAL; - - while (iov_iter_count(it)) { - /* iov_iter_iovec() for ITER_BVEC */ - bvec_set_page(&bv, it->bvec->bv_page, - min(iov_iter_count(it), - it->bvec->bv_len - it->iov_offset), - it->bvec->bv_offset + it->iov_offset); - - /* - * sendpage cannot properly handle pages with - * page_count == 0, we need to fall back to sendmsg if - * that's the case. - * - * Same goes for slab pages: skb_can_coalesce() allows - * coalescing neighboring slab objects into a single frag - * which triggers one of hardened usercopy checks. - */ - if (sendpage_ok(bv.bv_page)) { - ret = sock->ops->sendpage(sock, bv.bv_page, - bv.bv_offset, bv.bv_len, - CEPH_MSG_FLAGS); - } else { - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bv, 1, bv.bv_len); - ret = sock_sendmsg(sock, &msg); - } - if (ret <= 0) { - if (ret == -EAGAIN) - ret = 0; - return ret; - } - - iov_iter_advance(it, ret); - } - - return 1; -} - /* * Write as much as possible. The socket is expected to be corked, - * so we don't bother with MSG_MORE/MSG_SENDPAGE_NOTLAST here. + * so we don't bother with MSG_MORE here. * * Return: - * 1 - done, nothing (else) to write + * >0 - done, nothing (else) to write * 0 - socket is full, need to wait * <0 - error */ static int ceph_tcp_send(struct ceph_connection *con) { + struct msghdr msg = { + .msg_iter = con->v2.out_iter, + .msg_flags = CEPH_MSG_FLAGS, + }; int ret; + if (WARN_ON(!iov_iter_is_bvec(&con->v2.out_iter))) + return -EINVAL; + + if (con->v2.out_iter_sendpage) + msg.msg_flags |= MSG_SPLICE_PAGES; + dout("%s con %p have %zu try_sendpage %d\n", __func__, con, iov_iter_count(&con->v2.out_iter), con->v2.out_iter_sendpage); - if (con->v2.out_iter_sendpage) - ret = do_try_sendpage(con->sock, &con->v2.out_iter); - else - ret = do_sendmsg(con->sock, &con->v2.out_iter); + + ret = sock_sendmsg(con->sock, &msg); + if (ret > 0) + iov_iter_advance(&con->v2.out_iter, ret); + else if (ret == -EAGAIN) + ret = 0; + dout("%s con %p ret %d left %zu\n", __func__, con, ret, iov_iter_count(&con->v2.out_iter)); return ret; -- cgit v1.2.3 From 572efade27c55f11436ed10bbb59ef10c6d83d93 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:02 +0100 Subject: rds: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage When transmitting data, call down into TCP using a single sendmsg with MSG_SPLICE_PAGES to indicate that content should be spliced. To make this work, the data is assembled in a bio_vec array and attached to a BVEC-type iterator. Signed-off-by: David Howells cc: Santosh Shilimkar cc: Jens Axboe cc: Matthew Wilcox cc: rds-devel@oss.oracle.com Link: https://lore.kernel.org/r/20230623225513.2732256-6-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- net/rds/tcp_send.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c index 8c4d1d6e9249..7d284ac7e81a 100644 --- a/net/rds/tcp_send.c +++ b/net/rds/tcp_send.c @@ -72,9 +72,10 @@ int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm, { struct rds_conn_path *cp = rm->m_inc.i_conn_path; struct rds_tcp_connection *tc = cp->cp_transport_data; + struct msghdr msg = {}; + struct bio_vec bvec; int done = 0; int ret = 0; - int more; if (hdr_off == 0) { /* @@ -111,15 +112,17 @@ int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm, goto out; } - more = rm->data.op_nents > 1 ? (MSG_MORE | MSG_SENDPAGE_NOTLAST) : 0; while (sg < rm->data.op_nents) { - int flags = MSG_DONTWAIT | MSG_NOSIGNAL | more; - - ret = tc->t_sock->ops->sendpage(tc->t_sock, - sg_page(&rm->data.op_sg[sg]), - rm->data.op_sg[sg].offset + off, - rm->data.op_sg[sg].length - off, - flags); + msg.msg_flags = MSG_SPLICE_PAGES | MSG_DONTWAIT | MSG_NOSIGNAL; + if (sg + 1 < rm->data.op_nents) + msg.msg_flags |= MSG_MORE; + + bvec_set_page(&bvec, sg_page(&rm->data.op_sg[sg]), + rm->data.op_sg[sg].length - off, + rm->data.op_sg[sg].offset + off); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, + rm->data.op_sg[sg].length - off); + ret = sock_sendmsg(tc->t_sock, &msg); rdsdebug("tcp sendpage %p:%u:%u ret %d\n", (void *)sg_page(&rm->data.op_sg[sg]), rm->data.op_sg[sg].offset + off, rm->data.op_sg[sg].length - off, ret); @@ -132,8 +135,6 @@ int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm, off = 0; sg++; } - if (sg == rm->data.op_nents - 1) - more = 0; } out: -- cgit v1.2.3 From a1a5e8752786b2f7c5699fb99e3a641936297d69 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:03 +0100 Subject: dlm: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage When transmitting data, call down a layer using a single sendmsg with MSG_SPLICE_PAGES to indicate that content should be spliced rather using sendpage. This allows ->sendpage() to be replaced by something that can handle multiple multipage folios in a single transaction. Signed-off-by: David Howells cc: Christine Caulfield cc: David Teigland cc: Jens Axboe cc: Matthew Wilcox cc: cluster-devel@redhat.com Link: https://lore.kernel.org/r/20230623225513.2732256-7-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- fs/dlm/lowcomms.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 3d3802c47b8b..5c12d8cdfc16 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -1395,8 +1395,11 @@ int dlm_lowcomms_resend_msg(struct dlm_msg *msg) /* Send a message */ static int send_to_sock(struct connection *con) { - const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; struct writequeue_entry *e; + struct bio_vec bvec; + struct msghdr msg = { + .msg_flags = MSG_SPLICE_PAGES | MSG_DONTWAIT | MSG_NOSIGNAL, + }; int len, offset, ret; spin_lock_bh(&con->writequeue_lock); @@ -1412,8 +1415,9 @@ static int send_to_sock(struct connection *con) WARN_ON_ONCE(len == 0 && e->users == 0); spin_unlock_bh(&con->writequeue_lock); - ret = kernel_sendpage(con->sock, e->page, offset, len, - msg_flags); + bvec_set_page(&bvec, e->page, len, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, len); + ret = sock_sendmsg(con->sock, &msg); trace_dlm_send(con->nodeid, ret); if (ret == -EAGAIN || ret == 0) { lock_sock(con->sock->sk); -- cgit v1.2.3 From 7769887817c3dc49b55957badcbd515cf925728b Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:04 +0100 Subject: nvme-tcp: Use sendmsg(MSG_SPLICE_PAGES) rather then sendpage When transmitting data, call down into TCP using a sendmsg with MSG_SPLICE_PAGES instead of sendpage. Signed-off-by: David Howells Tested-by: Sagi Grimberg Acked-by: Willem de Bruijn cc: Keith Busch cc: Jens Axboe cc: Christoph Hellwig cc: Chaitanya Kulkarni cc: Jens Axboe cc: Matthew Wilcox cc: linux-nvme@lists.infradead.org Link: https://lore.kernel.org/r/20230623225513.2732256-8-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- drivers/nvme/host/tcp.c | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index bf0230442d57..47ae17f16c05 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -997,25 +997,28 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req) u32 h2cdata_left = req->h2cdata_left; while (true) { + struct bio_vec bvec; + struct msghdr msg = { + .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, + }; struct page *page = nvme_tcp_req_cur_page(req); size_t offset = nvme_tcp_req_cur_offset(req); size_t len = nvme_tcp_req_cur_length(req); bool last = nvme_tcp_pdu_last_send(req, len); int req_data_sent = req->data_sent; - int ret, flags = MSG_DONTWAIT; + int ret; if (last && !queue->data_digest && !nvme_tcp_queue_more(queue)) - flags |= MSG_EOR; + msg.msg_flags |= MSG_EOR; else - flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; + msg.msg_flags |= MSG_MORE; - if (sendpage_ok(page)) { - ret = kernel_sendpage(queue->sock, page, offset, len, - flags); - } else { - ret = sock_no_sendpage(queue->sock, page, offset, len, - flags); - } + if (!sendpage_ok(page)) + msg.msg_flags &= ~MSG_SPLICE_PAGES, + + bvec_set_page(&bvec, page, len, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, len); + ret = sock_sendmsg(queue->sock, &msg); if (ret <= 0) return ret; @@ -1054,22 +1057,24 @@ static int nvme_tcp_try_send_cmd_pdu(struct nvme_tcp_request *req) { struct nvme_tcp_queue *queue = req->queue; struct nvme_tcp_cmd_pdu *pdu = nvme_tcp_req_cmd_pdu(req); + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, }; bool inline_data = nvme_tcp_has_inline_data(req); u8 hdgst = nvme_tcp_hdgst_len(queue); int len = sizeof(*pdu) + hdgst - req->offset; - int flags = MSG_DONTWAIT; int ret; if (inline_data || nvme_tcp_queue_more(queue)) - flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; + msg.msg_flags |= MSG_MORE; else - flags |= MSG_EOR; + msg.msg_flags |= MSG_EOR; if (queue->hdr_digest && !req->offset) nvme_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu)); - ret = kernel_sendpage(queue->sock, virt_to_page(pdu), - offset_in_page(pdu) + req->offset, len, flags); + bvec_set_virt(&bvec, (void *)pdu + req->offset, len); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, len); + ret = sock_sendmsg(queue->sock, &msg); if (unlikely(ret <= 0)) return ret; @@ -1093,6 +1098,8 @@ static int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req) { struct nvme_tcp_queue *queue = req->queue; struct nvme_tcp_data_pdu *pdu = nvme_tcp_req_data_pdu(req); + struct bio_vec bvec; + struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_MORE, }; u8 hdgst = nvme_tcp_hdgst_len(queue); int len = sizeof(*pdu) - req->offset + hdgst; int ret; @@ -1101,13 +1108,11 @@ static int nvme_tcp_try_send_data_pdu(struct nvme_tcp_request *req) nvme_tcp_hdgst(queue->snd_hash, pdu, sizeof(*pdu)); if (!req->h2cdata_left) - ret = kernel_sendpage(queue->sock, virt_to_page(pdu), - offset_in_page(pdu) + req->offset, len, - MSG_DONTWAIT | MSG_MORE | MSG_SENDPAGE_NOTLAST); - else - ret = sock_no_sendpage(queue->sock, virt_to_page(pdu), - offset_in_page(pdu) + req->offset, len, - MSG_DONTWAIT | MSG_MORE); + msg.msg_flags |= MSG_SPLICE_PAGES; + + bvec_set_virt(&bvec, (void *)pdu + req->offset, len); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, len); + ret = sock_sendmsg(queue->sock, &msg); if (unlikely(ret <= 0)) return ret; -- cgit v1.2.3 From c336a79983c7e67a0a163ab4feafa3c273d915be Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:05 +0100 Subject: nvmet-tcp: Use sendmsg(MSG_SPLICE_PAGES) rather then sendpage When transmitting data, call down into TCP using a single sendmsg with MSG_SPLICE_PAGES to indicate that content should be spliced rather than copied instead of calling sendpage. Signed-off-by: David Howells Tested-by: Sagi Grimberg Acked-by: Willem de Bruijn cc: Keith Busch cc: Jens Axboe cc: Christoph Hellwig cc: Chaitanya Kulkarni cc: Jens Axboe cc: Matthew Wilcox cc: linux-nvme@lists.infradead.org Link: https://lore.kernel.org/r/20230623225513.2732256-9-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- drivers/nvme/target/tcp.c | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index ed98df72c76b..868aa4de2e4c 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -576,13 +576,17 @@ static void nvmet_tcp_execute_request(struct nvmet_tcp_cmd *cmd) static int nvmet_try_send_data_pdu(struct nvmet_tcp_cmd *cmd) { + struct msghdr msg = { + .msg_flags = MSG_DONTWAIT | MSG_MORE | MSG_SPLICE_PAGES, + }; + struct bio_vec bvec; u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); int left = sizeof(*cmd->data_pdu) - cmd->offset + hdgst; int ret; - ret = kernel_sendpage(cmd->queue->sock, virt_to_page(cmd->data_pdu), - offset_in_page(cmd->data_pdu) + cmd->offset, - left, MSG_DONTWAIT | MSG_MORE | MSG_SENDPAGE_NOTLAST); + bvec_set_virt(&bvec, (void *)cmd->data_pdu + cmd->offset, left); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, left); + ret = sock_sendmsg(cmd->queue->sock, &msg); if (ret <= 0) return ret; @@ -603,17 +607,21 @@ static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd, bool last_in_batch) int ret; while (cmd->cur_sg) { + struct msghdr msg = { + .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, + }; struct page *page = sg_page(cmd->cur_sg); + struct bio_vec bvec; u32 left = cmd->cur_sg->length - cmd->offset; - int flags = MSG_DONTWAIT; if ((!last_in_batch && cmd->queue->send_list_len) || cmd->wbytes_done + left < cmd->req.transfer_len || queue->data_digest || !queue->nvme_sq.sqhd_disabled) - flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; + msg.msg_flags |= MSG_MORE; - ret = kernel_sendpage(cmd->queue->sock, page, cmd->offset, - left, flags); + bvec_set_page(&bvec, page, left, cmd->offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, left); + ret = sock_sendmsg(cmd->queue->sock, &msg); if (ret <= 0) return ret; @@ -649,18 +657,20 @@ static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd, bool last_in_batch) static int nvmet_try_send_response(struct nvmet_tcp_cmd *cmd, bool last_in_batch) { + struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, }; + struct bio_vec bvec; u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); int left = sizeof(*cmd->rsp_pdu) - cmd->offset + hdgst; - int flags = MSG_DONTWAIT; int ret; if (!last_in_batch && cmd->queue->send_list_len) - flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; + msg.msg_flags |= MSG_MORE; else - flags |= MSG_EOR; + msg.msg_flags |= MSG_EOR; - ret = kernel_sendpage(cmd->queue->sock, virt_to_page(cmd->rsp_pdu), - offset_in_page(cmd->rsp_pdu) + cmd->offset, left, flags); + bvec_set_virt(&bvec, (void *)cmd->rsp_pdu + cmd->offset, left); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, left); + ret = sock_sendmsg(cmd->queue->sock, &msg); if (ret <= 0) return ret; cmd->offset += ret; @@ -677,18 +687,20 @@ static int nvmet_try_send_response(struct nvmet_tcp_cmd *cmd, static int nvmet_try_send_r2t(struct nvmet_tcp_cmd *cmd, bool last_in_batch) { + struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES, }; + struct bio_vec bvec; u8 hdgst = nvmet_tcp_hdgst_len(cmd->queue); int left = sizeof(*cmd->r2t_pdu) - cmd->offset + hdgst; - int flags = MSG_DONTWAIT; int ret; if (!last_in_batch && cmd->queue->send_list_len) - flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; + msg.msg_flags |= MSG_MORE; else - flags |= MSG_EOR; + msg.msg_flags |= MSG_EOR; - ret = kernel_sendpage(cmd->queue->sock, virt_to_page(cmd->r2t_pdu), - offset_in_page(cmd->r2t_pdu) + cmd->offset, left, flags); + bvec_set_virt(&bvec, (void *)cmd->r2t_pdu + cmd->offset, left); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, left); + ret = sock_sendmsg(cmd->queue->sock, &msg); if (ret <= 0) return ret; cmd->offset += ret; -- cgit v1.2.3 From 2f8bc2bbb0fa87bcf7fb9eeb65eb6d79c5a08895 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:06 +0100 Subject: smc: Drop smc_sendpage() in favour of smc_sendmsg() + MSG_SPLICE_PAGES Drop the smc_sendpage() code as smc_sendmsg() just passes the call down to the underlying TCP socket and smc_tx_sendpage() is just a wrapper around its sendmsg implementation. Signed-off-by: David Howells cc: Karsten Graul cc: Wenjia Zhang cc: Jan Karcher cc: "D. Wythe" cc: Tony Lu cc: Wen Gu cc: Jens Axboe cc: Matthew Wilcox Link: https://lore.kernel.org/r/20230623225513.2732256-10-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- net/smc/af_smc.c | 29 ----------------------------- net/smc/smc_stats.c | 2 +- net/smc/smc_stats.h | 1 - net/smc/smc_tx.c | 19 ------------------- net/smc/smc_tx.h | 2 -- 5 files changed, 1 insertion(+), 52 deletions(-) diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 538e9c6ec8c9..a7f887d91d89 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -3133,34 +3133,6 @@ static int smc_ioctl(struct socket *sock, unsigned int cmd, return put_user(answ, (int __user *)arg); } -static ssize_t smc_sendpage(struct socket *sock, struct page *page, - int offset, size_t size, int flags) -{ - struct sock *sk = sock->sk; - struct smc_sock *smc; - int rc = -EPIPE; - - smc = smc_sk(sk); - lock_sock(sk); - if (sk->sk_state != SMC_ACTIVE) { - release_sock(sk); - goto out; - } - release_sock(sk); - if (smc->use_fallback) { - rc = kernel_sendpage(smc->clcsock, page, offset, - size, flags); - } else { - lock_sock(sk); - rc = smc_tx_sendpage(smc, page, offset, size, flags); - release_sock(sk); - SMC_STAT_INC(smc, sendpage_cnt); - } - -out: - return rc; -} - /* Map the affected portions of the rmbe into an spd, note the number of bytes * to splice in conn->splice_pending, and press 'go'. Delays consumer cursor * updates till whenever a respective page has been fully processed. @@ -3232,7 +3204,6 @@ static const struct proto_ops smc_sock_ops = { .sendmsg = smc_sendmsg, .recvmsg = smc_recvmsg, .mmap = sock_no_mmap, - .sendpage = smc_sendpage, .splice_read = smc_splice_read, }; diff --git a/net/smc/smc_stats.c b/net/smc/smc_stats.c index e80e34f7ac15..ca14c0f3a07d 100644 --- a/net/smc/smc_stats.c +++ b/net/smc/smc_stats.c @@ -227,7 +227,7 @@ static int smc_nl_fill_stats_tech_data(struct sk_buff *skb, SMC_NLA_STATS_PAD)) goto errattr; if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_SENDPAGE_CNT, - smc_tech->sendpage_cnt, + 0, SMC_NLA_STATS_PAD)) goto errattr; if (nla_put_u64_64bit(skb, SMC_NLA_STATS_T_CORK_CNT, diff --git a/net/smc/smc_stats.h b/net/smc/smc_stats.h index 84b7ecd8c05c..b60fe1eb37ab 100644 --- a/net/smc/smc_stats.h +++ b/net/smc/smc_stats.h @@ -71,7 +71,6 @@ struct smc_stats_tech { u64 clnt_v2_succ_cnt; u64 srv_v1_succ_cnt; u64 srv_v2_succ_cnt; - u64 sendpage_cnt; u64 urg_data_cnt; u64 splice_cnt; u64 cork_cnt; diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c index 9b9e0a190734..3b0ff3b589c7 100644 --- a/net/smc/smc_tx.c +++ b/net/smc/smc_tx.c @@ -297,25 +297,6 @@ out_err: return rc; } -int smc_tx_sendpage(struct smc_sock *smc, struct page *page, int offset, - size_t size, int flags) -{ - struct msghdr msg = {.msg_flags = flags}; - char *kaddr = kmap(page); - struct kvec iov; - int rc; - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - iov.iov_base = kaddr + offset; - iov.iov_len = size; - iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, size); - rc = smc_tx_sendmsg(smc, &msg, size); - kunmap(page); - return rc; -} - /***************************** sndbuf consumer *******************************/ /* sndbuf consumer: actual data transfer of one target chunk with ISM write */ diff --git a/net/smc/smc_tx.h b/net/smc/smc_tx.h index 34b578498b1f..a59f370b8b43 100644 --- a/net/smc/smc_tx.h +++ b/net/smc/smc_tx.h @@ -31,8 +31,6 @@ void smc_tx_pending(struct smc_connection *conn); void smc_tx_work(struct work_struct *work); void smc_tx_init(struct smc_sock *smc); int smc_tx_sendmsg(struct smc_sock *smc, struct msghdr *msg, size_t len); -int smc_tx_sendpage(struct smc_sock *smc, struct page *page, int offset, - size_t size, int flags); int smc_tx_sndbuf_nonempty(struct smc_connection *conn); void smc_tx_sndbuf_nonfull(struct smc_sock *smc); void smc_tx_consumer_update(struct smc_connection *conn, bool force); -- cgit v1.2.3 From eeac7405c735acde8ec78869489a5aa25a141c13 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:07 +0100 Subject: drbd: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use sendmsg() conditionally with MSG_SPLICE_PAGES in _drbd_send_page() rather than calling sendpage() or _drbd_no_send_page(). Signed-off-by: David Howells cc: Philipp Reisner cc: Lars Ellenberg cc: "Christoph Böhmwalder" cc: Jens Axboe cc: drbd-dev@lists.linbit.com Link: https://lore.kernel.org/r/20230623225513.2732256-11-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- drivers/block/drbd/drbd_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 83987e7a5ef2..ea82d6733313 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1540,6 +1540,8 @@ static int _drbd_send_page(struct drbd_peer_device *peer_device, struct page *pa int offset, size_t size, unsigned msg_flags) { struct socket *socket = peer_device->connection->data.socket; + struct msghdr msg = { .msg_flags = msg_flags, }; + struct bio_vec bvec; int len = size; int err = -EIO; @@ -1549,15 +1551,17 @@ static int _drbd_send_page(struct drbd_peer_device *peer_device, struct page *pa * put_page(); and would cause either a VM_BUG directly, or * __page_cache_release a page that would actually still be referenced * by someone, leading to some obscure delayed Oops somewhere else. */ - if (drbd_disable_sendpage || !sendpage_ok(page)) - return _drbd_no_send_page(peer_device, page, offset, size, msg_flags); + if (!drbd_disable_sendpage && sendpage_ok(page)) + msg.msg_flags |= MSG_NOSIGNAL | MSG_SPLICE_PAGES; - msg_flags |= MSG_NOSIGNAL; drbd_update_congested(peer_device->connection); do { int sent; - sent = socket->ops->sendpage(socket, page, offset, len, msg_flags); + bvec_set_page(&bvec, page, offset, len); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, len); + + sent = sock_sendmsg(socket, &msg); if (sent <= 0) { if (sent == -EAGAIN) { if (we_should_drop_the_connection(peer_device->connection, socket)) -- cgit v1.2.3 From fa8df3435727a7b398760ef5e2ac95457a62ae1b Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:08 +0100 Subject: scsi: iscsi_tcp: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage Use sendmsg() with MSG_SPLICE_PAGES rather than sendpage. This allows multiple pages and multipage folios to be passed through. Signed-off-by: David Howells Reviewed-by: Mike Christie cc: Lee Duncan cc: Chris Leech cc: "James E.J. Bottomley" cc: "Martin K. Petersen" cc: Jens Axboe cc: Matthew Wilcox cc: Al Viro cc: open-iscsi@googlegroups.com Link: https://lore.kernel.org/r/20230623225513.2732256-12-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- drivers/scsi/iscsi_tcp.c | 26 ++++++++++---------------- drivers/scsi/iscsi_tcp.h | 2 -- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 9637d4bc2bc9..9ab8555180a3 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -301,35 +301,32 @@ static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn, while (!iscsi_tcp_segment_done(tcp_conn, segment, 0, r)) { struct scatterlist *sg; + struct msghdr msg = {}; + struct bio_vec bv; unsigned int offset, copy; - int flags = 0; r = 0; offset = segment->copied; copy = segment->size - offset; if (segment->total_copied + segment->size < segment->total_size) - flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST; + msg.msg_flags |= MSG_MORE; if (tcp_sw_conn->queue_recv) - flags |= MSG_DONTWAIT; + msg.msg_flags |= MSG_DONTWAIT; - /* Use sendpage if we can; else fall back to sendmsg */ if (!segment->data) { + if (!tcp_conn->iscsi_conn->datadgst_en) + msg.msg_flags |= MSG_SPLICE_PAGES; sg = segment->sg; offset += segment->sg_offset + sg->offset; - r = tcp_sw_conn->sendpage(sk, sg_page(sg), offset, - copy, flags); + bvec_set_page(&bv, sg_page(sg), copy, offset); } else { - struct msghdr msg = { .msg_flags = flags }; - struct kvec iov = { - .iov_base = segment->data + offset, - .iov_len = copy - }; - - r = kernel_sendmsg(sk, &msg, &iov, 1, copy); + bvec_set_virt(&bv, segment->data + offset, copy); } + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bv, 1, copy); + r = sock_sendmsg(sk, &msg); if (r < 0) { iscsi_tcp_segment_unmap(segment); return r; @@ -746,7 +743,6 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session, sock_no_linger(sk); iscsi_sw_tcp_conn_set_callbacks(conn); - tcp_sw_conn->sendpage = tcp_sw_conn->sock->ops->sendpage; /* * set receive state machine into initial state */ @@ -777,8 +773,6 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn, return -ENOTCONN; } iscsi_set_param(cls_conn, param, buf, buflen); - tcp_sw_conn->sendpage = conn->datadgst_en ? - sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage; mutex_unlock(&tcp_sw_conn->sock_lock); break; case ISCSI_PARAM_MAX_R2T: diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 68e14a344904..89a6fc552f0b 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -47,8 +47,6 @@ struct iscsi_sw_tcp_conn { /* MIB custom statistics */ uint32_t sendpage_failures_cnt; uint32_t discontiguous_hdr_cnt; - - ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); }; struct iscsi_sw_tcp_host { -- cgit v1.2.3 From d2fe21077d6d4687ecab642ffe97c2e4acf3a547 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:09 +0100 Subject: scsi: target: iscsi: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage Use sendmsg() with MSG_SPLICE_PAGES rather than sendpage. This allows multiple pages and multipage folios to be passed through. TODO: iscsit_fe_sendpage_sg() should perhaps set up a bio_vec array for the entire set of pages it's going to transfer plus two for the header and trailer and page fragments to hold the header and trailer - and then call sendmsg once for the entire message. Signed-off-by: David Howells cc: Mike Christie cc: Maurizio Lombardi cc: "James E.J. Bottomley" cc: "Martin K. Petersen" cc: Jens Axboe cc: Matthew Wilcox cc: Al Viro cc: open-iscsi@googlegroups.com Link: https://lore.kernel.org/r/20230623225513.2732256-13-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- drivers/target/iscsi/iscsi_target_util.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index b14835fcb033..6231fa4ef5c6 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -1129,6 +1129,8 @@ int iscsit_fe_sendpage_sg( struct iscsit_conn *conn) { struct scatterlist *sg = cmd->first_data_sg; + struct bio_vec bvec; + struct msghdr msghdr = { .msg_flags = MSG_SPLICE_PAGES, }; struct kvec iov; u32 tx_hdr_size, data_len; u32 offset = cmd->first_data_sg_off; @@ -1172,17 +1174,18 @@ send_hdr: u32 space = (sg->length - offset); u32 sub_len = min_t(u32, data_len, space); send_pg: - tx_sent = conn->sock->ops->sendpage(conn->sock, - sg_page(sg), sg->offset + offset, sub_len, 0); + bvec_set_page(&bvec, sg_page(sg), sub_len, sg->offset + offset); + iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, sub_len); + + tx_sent = conn->sock->ops->sendmsg(conn->sock, &msghdr, + sub_len); if (tx_sent != sub_len) { if (tx_sent == -EAGAIN) { - pr_err("tcp_sendpage() returned" - " -EAGAIN\n"); + pr_err("sendmsg/splice returned -EAGAIN\n"); goto send_pg; } - pr_err("tcp_sendpage() failure: %d\n", - tx_sent); + pr_err("sendmsg/splice failure: %d\n", tx_sent); return -1; } -- cgit v1.2.3 From 86d7bd6e66e9925f0f04a7bcf3c92c05fdfefb5a Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:10 +0100 Subject: ocfs2: Fix use of slab data with sendpage ocfs2 uses kzalloc() to allocate buffers for o2net_hand, o2net_keep_req and o2net_keep_resp and then passes these to sendpage. This isn't really allowed as the lifetime of slab objects is not controlled by page ref - though in this case it will probably work. sendmsg() with MSG_SPLICE_PAGES will, however, print a warning and give an error. Fix it to use folio_alloc() instead to allocate a buffer for the handshake message, keepalive request and reply messages. Fixes: 98211489d414 ("[PATCH] OCFS2: The Second Oracle Cluster Filesystem") Signed-off-by: David Howells cc: Mark Fasheh cc: Kurt Hackel cc: Joel Becker cc: Joseph Qi cc: ocfs2-devel@oss.oracle.com Link: https://lore.kernel.org/r/20230623225513.2732256-14-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- fs/ocfs2/cluster/tcp.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index aecbd712a00c..929a1133bc18 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -2087,18 +2087,24 @@ void o2net_stop_listening(struct o2nm_node *node) int o2net_init(void) { + struct folio *folio; + void *p; unsigned long i; o2quo_init(); - o2net_debugfs_init(); - o2net_hand = kzalloc(sizeof(struct o2net_handshake), GFP_KERNEL); - o2net_keep_req = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL); - o2net_keep_resp = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL); - if (!o2net_hand || !o2net_keep_req || !o2net_keep_resp) + folio = folio_alloc(GFP_KERNEL | __GFP_ZERO, 0); + if (!folio) goto out; + p = folio_address(folio); + o2net_hand = p; + p += sizeof(struct o2net_handshake); + o2net_keep_req = p; + p += sizeof(struct o2net_msg); + o2net_keep_resp = p; + o2net_hand->protocol_version = cpu_to_be64(O2NET_PROTOCOL_VERSION); o2net_hand->connector_id = cpu_to_be64(1); @@ -2124,9 +2130,6 @@ int o2net_init(void) return 0; out: - kfree(o2net_hand); - kfree(o2net_keep_req); - kfree(o2net_keep_resp); o2net_debugfs_exit(); o2quo_exit(); return -ENOMEM; @@ -2135,8 +2138,6 @@ out: void o2net_exit(void) { o2quo_exit(); - kfree(o2net_hand); - kfree(o2net_keep_req); - kfree(o2net_keep_resp); o2net_debugfs_exit(); + folio_put(virt_to_folio(o2net_hand)); } -- cgit v1.2.3 From e52828cc0109f511bba1dfb41292833c2fd3b6e6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:11 +0100 Subject: ocfs2: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage() Switch ocfs2 from using sendpage() to using sendmsg() + MSG_SPLICE_PAGES so that sendpage can be phased out. Signed-off-by: David Howells cc: Mark Fasheh cc: Joel Becker cc: Joseph Qi cc: ocfs2-devel@oss.oracle.com Link: https://lore.kernel.org/r/20230623225513.2732256-15-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- fs/ocfs2/cluster/tcp.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 929a1133bc18..960080753d3b 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -930,19 +930,22 @@ out: } static void o2net_sendpage(struct o2net_sock_container *sc, - void *kmalloced_virt, - size_t size) + void *virt, size_t size) { struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num); + struct msghdr msg = {}; + struct bio_vec bv; ssize_t ret; + bvec_set_virt(&bv, virt, size); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bv, 1, size); + while (1) { + msg.msg_flags = MSG_DONTWAIT | MSG_SPLICE_PAGES; mutex_lock(&sc->sc_send_lock); - ret = sc->sc_sock->ops->sendpage(sc->sc_sock, - virt_to_page(kmalloced_virt), - offset_in_page(kmalloced_virt), - size, MSG_DONTWAIT); + ret = sock_sendmsg(sc->sc_sock, &msg); mutex_unlock(&sc->sc_send_lock); + if (ret == size) break; if (ret == (ssize_t)-EAGAIN) { -- cgit v1.2.3 From dc97391e661009eab46783030d2404c9b6e6f2e7 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:12 +0100 Subject: sock: Remove ->sendpage*() in favour of sendmsg(MSG_SPLICE_PAGES) Remove ->sendpage() and ->sendpage_locked(). sendmsg() with MSG_SPLICE_PAGES should be used instead. This allows multiple pages and multipage folios to be passed through. Signed-off-by: David Howells Acked-by: Marc Kleine-Budde # for net/can cc: Jens Axboe cc: Matthew Wilcox cc: linux-afs@lists.infradead.org cc: mptcp@lists.linux.dev cc: rds-devel@oss.oracle.com cc: tipc-discussion@lists.sourceforge.net cc: virtualization@lists.linux-foundation.org Link: https://lore.kernel.org/r/20230623225513.2732256-16-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- Documentation/bpf/map_sockmap.rst | 10 ++--- Documentation/filesystems/locking.rst | 2 - Documentation/filesystems/vfs.rst | 1 - Documentation/networking/scaling.rst | 4 +- crypto/af_alg.c | 28 ------------- crypto/algif_aead.c | 22 ++-------- crypto/algif_rng.c | 2 - crypto/algif_skcipher.c | 14 ------- .../ethernet/chelsio/inline_crypto/chtls/chtls.h | 2 - .../chelsio/inline_crypto/chtls/chtls_io.c | 14 ------- .../chelsio/inline_crypto/chtls/chtls_main.c | 1 - fs/nfsd/vfs.c | 2 +- include/crypto/if_alg.h | 2 - include/linux/net.h | 8 ---- include/net/inet_common.h | 2 - include/net/sock.h | 6 --- include/net/tcp.h | 4 -- net/appletalk/ddp.c | 1 - net/atm/pvc.c | 1 - net/atm/svc.c | 1 - net/ax25/af_ax25.c | 1 - net/caif/caif_socket.c | 2 - net/can/bcm.c | 1 - net/can/isotp.c | 1 - net/can/j1939/socket.c | 1 - net/can/raw.c | 1 - net/core/sock.c | 35 +--------------- net/dccp/ipv4.c | 1 - net/dccp/ipv6.c | 1 - net/ieee802154/socket.c | 2 - net/ipv4/af_inet.c | 21 ---------- net/ipv4/tcp.c | 43 ++----------------- net/ipv4/tcp_bpf.c | 23 +---------- net/ipv4/tcp_ipv4.c | 1 - net/ipv4/udp.c | 15 ------- net/ipv4/udp_impl.h | 2 - net/ipv4/udplite.c | 1 - net/ipv6/af_inet6.c | 3 -- net/ipv6/raw.c | 1 - net/ipv6/tcp_ipv6.c | 1 - net/kcm/kcmsock.c | 20 --------- net/key/af_key.c | 1 - net/l2tp/l2tp_ip.c | 1 - net/l2tp/l2tp_ip6.c | 1 - net/llc/af_llc.c | 1 - net/mctp/af_mctp.c | 1 - net/mptcp/protocol.c | 2 - net/netlink/af_netlink.c | 1 - net/netrom/af_netrom.c | 1 - net/packet/af_packet.c | 2 - net/phonet/socket.c | 2 - net/qrtr/af_qrtr.c | 1 - net/rds/af_rds.c | 1 - net/rose/af_rose.c | 1 - net/rxrpc/af_rxrpc.c | 1 - net/sctp/protocol.c | 1 - net/socket.c | 48 ---------------------- net/tipc/socket.c | 3 -- net/tls/tls.h | 6 --- net/tls/tls_device.c | 17 -------- net/tls/tls_main.c | 7 ---- net/tls/tls_sw.c | 35 ---------------- net/unix/af_unix.c | 19 --------- net/vmw_vsock/af_vsock.c | 3 -- net/x25/af_x25.c | 1 - net/xdp/xsk.c | 1 - 66 files changed, 20 insertions(+), 442 deletions(-) diff --git a/Documentation/bpf/map_sockmap.rst b/Documentation/bpf/map_sockmap.rst index cc92047c6630..2d630686a00b 100644 --- a/Documentation/bpf/map_sockmap.rst +++ b/Documentation/bpf/map_sockmap.rst @@ -240,11 +240,11 @@ offsets into ``msg``, respectively. If a program of type ``BPF_PROG_TYPE_SK_MSG`` is run on a ``msg`` it can only parse data that the (``data``, ``data_end``) pointers have already consumed. For ``sendmsg()`` hooks this is likely the first scatterlist element. But for -calls relying on the ``sendpage`` handler (e.g., ``sendfile()``) this will be -the range (**0**, **0**) because the data is shared with user space and by -default the objective is to avoid allowing user space to modify data while (or -after) BPF verdict is being decided. This helper can be used to pull in data -and to set the start and end pointers to given values. Data will be copied if +calls relying on MSG_SPLICE_PAGES (e.g., ``sendfile()``) this will be the +range (**0**, **0**) because the data is shared with user space and by default +the objective is to avoid allowing user space to modify data while (or after) +BPF verdict is being decided. This helper can be used to pull in data and to +set the start and end pointers to given values. Data will be copied if necessary (i.e., if data was not linear and if start and end pointers do not point to the same chunk). diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index aa1a233b0fa8..ed148919e11a 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -521,8 +521,6 @@ prototypes:: int (*fsync) (struct file *, loff_t start, loff_t end, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); - ssize_t (*sendpage) (struct file *, struct page *, int, size_t, - loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 769be5230210..cb2a97e49872 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -1086,7 +1086,6 @@ This describes how the VFS can manipulate an open file. As of kernel int (*fsync) (struct file *, loff_t, loff_t, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); - ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*flock) (struct file *, int, struct file_lock *); diff --git a/Documentation/networking/scaling.rst b/Documentation/networking/scaling.rst index 3d435caa3ef2..92c9fb46d6a2 100644 --- a/Documentation/networking/scaling.rst +++ b/Documentation/networking/scaling.rst @@ -269,8 +269,8 @@ a single application thread handles flows with many different flow hashes. rps_sock_flow_table is a global flow table that contains the *desired* CPU for flows: the CPU that is currently processing the flow in userspace. Each table value is a CPU index that is updated during calls to recvmsg -and sendmsg (specifically, inet_recvmsg(), inet_sendmsg(), inet_sendpage() -and tcp_splice_read()). +and sendmsg (specifically, inet_recvmsg(), inet_sendmsg() and +tcp_splice_read()). When the scheduler moves a thread to a new CPU while it has outstanding receive packets on the old CPU, packets may arrive out of order. To diff --git a/crypto/af_alg.c b/crypto/af_alg.c index cdb1dcc5dd1a..6218c773d71c 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -482,7 +482,6 @@ static const struct proto_ops alg_proto_ops = { .listen = sock_no_listen, .shutdown = sock_no_shutdown, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, .sendmsg = sock_no_sendmsg, .recvmsg = sock_no_recvmsg, @@ -1106,33 +1105,6 @@ unlock: } EXPORT_SYMBOL_GPL(af_alg_sendmsg); -/** - * af_alg_sendpage - sendpage system call handler - * @sock: socket of connection to user space to write to - * @page: data to send - * @offset: offset into page to begin sending - * @size: length of data - * @flags: message send/receive flags - * - * This is a generic implementation of sendpage to fill ctx->tsgl_list. - */ -ssize_t af_alg_sendpage(struct socket *sock, struct page *page, - int offset, size_t size, int flags) -{ - struct bio_vec bvec; - struct msghdr msg = { - .msg_flags = flags | MSG_SPLICE_PAGES, - }; - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - return sock_sendmsg(sock, &msg); -} -EXPORT_SYMBOL_GPL(af_alg_sendpage); - /** * af_alg_free_resources - release resources required for crypto request * @areq: Request holding the TX and RX SGL diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 35bfa283748d..7d58cbbce4af 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -9,10 +9,10 @@ * The following concept of the memory management is used: * * The kernel maintains two SGLs, the TX SGL and the RX SGL. The TX SGL is - * filled by user space with the data submitted via sendpage. Filling up - * the TX SGL does not cause a crypto operation -- the data will only be - * tracked by the kernel. Upon receipt of one recvmsg call, the caller must - * provide a buffer which is tracked with the RX SGL. + * filled by user space with the data submitted via sendmsg (maybe with + * MSG_SPLICE_PAGES). Filling up the TX SGL does not cause a crypto operation + * -- the data will only be tracked by the kernel. Upon receipt of one recvmsg + * call, the caller must provide a buffer which is tracked with the RX SGL. * * During the processing of the recvmsg operation, the cipher request is * allocated and prepared. As part of the recvmsg operation, the processed @@ -370,7 +370,6 @@ static struct proto_ops algif_aead_ops = { .release = af_alg_release, .sendmsg = aead_sendmsg, - .sendpage = af_alg_sendpage, .recvmsg = aead_recvmsg, .poll = af_alg_poll, }; @@ -422,18 +421,6 @@ static int aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg, return aead_sendmsg(sock, msg, size); } -static ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page, - int offset, size_t size, int flags) -{ - int err; - - err = aead_check_key(sock); - if (err) - return err; - - return af_alg_sendpage(sock, page, offset, size, flags); -} - static int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { @@ -461,7 +448,6 @@ static struct proto_ops algif_aead_ops_nokey = { .release = af_alg_release, .sendmsg = aead_sendmsg_nokey, - .sendpage = aead_sendpage_nokey, .recvmsg = aead_recvmsg_nokey, .poll = af_alg_poll, }; diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c index 407408c43730..10c41adac3b1 100644 --- a/crypto/algif_rng.c +++ b/crypto/algif_rng.c @@ -174,7 +174,6 @@ static struct proto_ops algif_rng_ops = { .bind = sock_no_bind, .accept = sock_no_accept, .sendmsg = sock_no_sendmsg, - .sendpage = sock_no_sendpage, .release = af_alg_release, .recvmsg = rng_recvmsg, @@ -192,7 +191,6 @@ static struct proto_ops __maybe_unused algif_rng_test_ops = { .mmap = sock_no_mmap, .bind = sock_no_bind, .accept = sock_no_accept, - .sendpage = sock_no_sendpage, .release = af_alg_release, .recvmsg = rng_test_recvmsg, diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index b1f321b9f846..9ada9b741af8 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -194,7 +194,6 @@ static struct proto_ops algif_skcipher_ops = { .release = af_alg_release, .sendmsg = skcipher_sendmsg, - .sendpage = af_alg_sendpage, .recvmsg = skcipher_recvmsg, .poll = af_alg_poll, }; @@ -246,18 +245,6 @@ static int skcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg, return skcipher_sendmsg(sock, msg, size); } -static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page, - int offset, size_t size, int flags) -{ - int err; - - err = skcipher_check_key(sock); - if (err) - return err; - - return af_alg_sendpage(sock, page, offset, size, flags); -} - static int skcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { @@ -285,7 +272,6 @@ static struct proto_ops algif_skcipher_ops_nokey = { .release = af_alg_release, .sendmsg = skcipher_sendmsg_nokey, - .sendpage = skcipher_sendpage_nokey, .recvmsg = skcipher_recvmsg_nokey, .poll = af_alg_poll, }; diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h index da4818d2c856..68562a82d036 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls.h @@ -569,8 +569,6 @@ int chtls_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); int chtls_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len); void chtls_splice_eof(struct socket *sock); -int chtls_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags); int send_tx_flowc_wr(struct sock *sk, int compl, u32 snd_nxt, u32 rcv_nxt); void chtls_tcp_push(struct sock *sk, int flags); diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c index e08ac960c967..5fc64e47568a 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_io.c @@ -1246,20 +1246,6 @@ void chtls_splice_eof(struct socket *sock) release_sock(sk); } -int chtls_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags) -{ - struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; - struct bio_vec bvec; - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - return chtls_sendmsg(sk, &msg, size); -} - static void chtls_select_window(struct sock *sk) { struct chtls_sock *csk = rcu_dereference_sk_user_data(sk); diff --git a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c index 6b6787eafd2f..455a54708be4 100644 --- a/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c +++ b/drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_main.c @@ -607,7 +607,6 @@ static void __init chtls_init_ulp_ops(void) chtls_cpl_prot.shutdown = chtls_shutdown; chtls_cpl_prot.sendmsg = chtls_sendmsg; chtls_cpl_prot.splice_eof = chtls_splice_eof; - chtls_cpl_prot.sendpage = chtls_sendpage; chtls_cpl_prot.recvmsg = chtls_recvmsg; chtls_cpl_prot.setsockopt = chtls_setsockopt; chtls_cpl_prot.getsockopt = chtls_getsockopt; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index db67f8e19344..8879e207ff5a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -936,7 +936,7 @@ nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, int may_flags, /* * Grab and keep cached pages associated with a file in the svc_rqst - * so that they can be passed to the network sendmsg/sendpage routines + * so that they can be passed to the network sendmsg routines * directly. They will be released after the sending has completed. * * Return values: Number of bytes consumed, or -EIO if there are no diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h index 34224e77f5a2..ef8ce86b1f78 100644 --- a/include/crypto/if_alg.h +++ b/include/crypto/if_alg.h @@ -229,8 +229,6 @@ void af_alg_wmem_wakeup(struct sock *sk); int af_alg_wait_for_data(struct sock *sk, unsigned flags, unsigned min); int af_alg_sendmsg(struct socket *sock, struct msghdr *msg, size_t size, unsigned int ivsize); -ssize_t af_alg_sendpage(struct socket *sock, struct page *page, - int offset, size_t size, int flags); void af_alg_free_resources(struct af_alg_async_req *areq); void af_alg_async_cb(void *data, int err); __poll_t af_alg_poll(struct file *file, struct socket *sock, diff --git a/include/linux/net.h b/include/linux/net.h index 23324e9a2b3d..41c608c1b02c 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -207,8 +207,6 @@ struct proto_ops { size_t total_len, int flags); int (*mmap) (struct file *file, struct socket *sock, struct vm_area_struct * vma); - ssize_t (*sendpage) (struct socket *sock, struct page *page, - int offset, size_t size, int flags); ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); void (*splice_eof)(struct socket *sock); @@ -222,8 +220,6 @@ struct proto_ops { sk_read_actor_t recv_actor); /* This is different from read_sock(), it reads an entire skb at a time. */ int (*read_skb)(struct sock *sk, skb_read_actor_t recv_actor); - int (*sendpage_locked)(struct sock *sk, struct page *page, - int offset, size_t size, int flags); int (*sendmsg_locked)(struct sock *sk, struct msghdr *msg, size_t size); int (*set_rcvlowat)(struct sock *sk, int val); @@ -341,10 +337,6 @@ int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, int flags); int kernel_getsockname(struct socket *sock, struct sockaddr *addr); int kernel_getpeername(struct socket *sock, struct sockaddr *addr); -int kernel_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags); -int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset, - size_t size, int flags); int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how); /* Routine returns the IP overhead imposed by a (caller-protected) socket. */ diff --git a/include/net/inet_common.h b/include/net/inet_common.h index a75333342c4e..b86b8e21de7f 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -36,8 +36,6 @@ void __inet_accept(struct socket *sock, struct socket *newsock, int inet_send_prepare(struct sock *sk); int inet_sendmsg(struct socket *sock, struct msghdr *msg, size_t size); void inet_splice_eof(struct socket *sock); -ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags); int inet_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags); int inet_shutdown(struct socket *sock, int how); diff --git a/include/net/sock.h b/include/net/sock.h index 62a1b99da349..121284f455a8 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1277,8 +1277,6 @@ struct proto { size_t len); int (*recvmsg)(struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len); - int (*sendpage)(struct sock *sk, struct page *page, - int offset, size_t size, int flags); void (*splice_eof)(struct socket *sock); int (*bind)(struct sock *sk, struct sockaddr *addr, int addr_len); @@ -1919,10 +1917,6 @@ int sock_no_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len); int sock_no_recvmsg(struct socket *, struct msghdr *, size_t, int); int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma); -ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags); -ssize_t sock_no_sendpage_locked(struct sock *sk, struct page *page, - int offset, size_t size, int flags); /* * Functions to fill in entries in struct proto_ops when a protocol diff --git a/include/net/tcp.h b/include/net/tcp.h index 31b534370787..226bce6d1e8c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -329,10 +329,6 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size); int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied, size_t size, struct ubuf_info *uarg); void tcp_splice_eof(struct socket *sock); -int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, - int flags); -int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, - size_t size, int flags); int tcp_send_mss(struct sock *sk, int *size_goal, int flags); int tcp_wmem_schedule(struct sock *sk, int copy); void tcp_push(struct sock *sk, int flags, int mss_now, int nonagle, diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index a06f4d4a6f47..8978fb6212ff 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1929,7 +1929,6 @@ static const struct proto_ops atalk_dgram_ops = { .sendmsg = atalk_sendmsg, .recvmsg = atalk_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct notifier_block ddp_notifier = { diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 53e7d3f39e26..66d9a9bd5896 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -126,7 +126,6 @@ static const struct proto_ops pvc_proto_ops = { .sendmsg = vcc_sendmsg, .recvmsg = vcc_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; diff --git a/net/atm/svc.c b/net/atm/svc.c index d83556d8beb9..36a814f1fbd1 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -654,7 +654,6 @@ static const struct proto_ops svc_proto_ops = { .sendmsg = vcc_sendmsg, .recvmsg = vcc_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index d8da400cb4de..5db805d5f74d 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -2022,7 +2022,6 @@ static const struct proto_ops ax25_proto_ops = { .sendmsg = ax25_sendmsg, .recvmsg = ax25_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; /* diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c index 4eebcc66c19a..9c82698da4f5 100644 --- a/net/caif/caif_socket.c +++ b/net/caif/caif_socket.c @@ -976,7 +976,6 @@ static const struct proto_ops caif_seqpacket_ops = { .sendmsg = caif_seqpkt_sendmsg, .recvmsg = caif_seqpkt_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static const struct proto_ops caif_stream_ops = { @@ -996,7 +995,6 @@ static const struct proto_ops caif_stream_ops = { .sendmsg = caif_stream_sendmsg, .recvmsg = caif_stream_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; /* This function is called when a socket is finally destroyed. */ diff --git a/net/can/bcm.c b/net/can/bcm.c index a962ec2b8ba5..9ba35685b043 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1703,7 +1703,6 @@ static const struct proto_ops bcm_ops = { .sendmsg = bcm_sendmsg, .recvmsg = bcm_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct proto bcm_proto __read_mostly = { diff --git a/net/can/isotp.c b/net/can/isotp.c index 84f9aba02901..1f25b45868cf 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -1699,7 +1699,6 @@ static const struct proto_ops isotp_ops = { .sendmsg = isotp_sendmsg, .recvmsg = isotp_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct proto isotp_proto __read_mostly = { diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index 35970c25496a..feaec4ad6d16 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -1306,7 +1306,6 @@ static const struct proto_ops j1939_ops = { .sendmsg = j1939_sk_sendmsg, .recvmsg = j1939_sk_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct proto j1939_proto __read_mostly = { diff --git a/net/can/raw.c b/net/can/raw.c index f64469b98260..15c79b079184 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -962,7 +962,6 @@ static const struct proto_ops raw_ops = { .sendmsg = raw_sendmsg, .recvmsg = raw_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct proto raw_proto __read_mostly = { diff --git a/net/core/sock.c b/net/core/sock.c index 5f1747c12004..de719094b804 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -3261,36 +3261,6 @@ void __receive_sock(struct file *file) } } -ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) -{ - ssize_t res; - struct msghdr msg = {.msg_flags = flags}; - struct kvec iov; - char *kaddr = kmap(page); - iov.iov_base = kaddr + offset; - iov.iov_len = size; - res = kernel_sendmsg(sock, &msg, &iov, 1, size); - kunmap(page); - return res; -} -EXPORT_SYMBOL(sock_no_sendpage); - -ssize_t sock_no_sendpage_locked(struct sock *sk, struct page *page, - int offset, size_t size, int flags) -{ - ssize_t res; - struct msghdr msg = {.msg_flags = flags}; - struct kvec iov; - char *kaddr = kmap(page); - - iov.iov_base = kaddr + offset; - iov.iov_len = size; - res = kernel_sendmsg_locked(sk, &msg, &iov, 1, size); - kunmap(page); - return res; -} -EXPORT_SYMBOL(sock_no_sendpage_locked); - /* * Default Socket Callbacks */ @@ -4046,7 +4016,7 @@ static void proto_seq_printf(struct seq_file *seq, struct proto *proto) { seq_printf(seq, "%-9s %4u %6d %6ld %-3s %6u %-3s %-10s " - "%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n", + "%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n", proto->name, proto->obj_size, sock_prot_inuse_get(seq_file_net(seq), proto), @@ -4067,7 +4037,6 @@ static void proto_seq_printf(struct seq_file *seq, struct proto *proto) proto_method_implemented(proto->getsockopt), proto_method_implemented(proto->sendmsg), proto_method_implemented(proto->recvmsg), - proto_method_implemented(proto->sendpage), proto_method_implemented(proto->bind), proto_method_implemented(proto->backlog_rcv), proto_method_implemented(proto->hash), @@ -4088,7 +4057,7 @@ static int proto_seq_show(struct seq_file *seq, void *v) "maxhdr", "slab", "module", - "cl co di ac io in de sh ss gs se re sp bi br ha uh gp em\n"); + "cl co di ac io in de sh ss gs se re bi br ha uh gp em\n"); else proto_seq_printf(seq, list_entry(v, struct proto, node)); return 0; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 3ab68415d121..fa8079303cb0 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1010,7 +1010,6 @@ static const struct proto_ops inet_dccp_ops = { .sendmsg = inet_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct inet_protosw dccp_v4_protosw = { diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 93c98990d726..7249ef218178 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1087,7 +1087,6 @@ static const struct proto_ops inet6_dccp_ops = { .sendmsg = inet_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, #ifdef CONFIG_COMPAT .compat_ioctl = inet6_compat_ioctl, #endif diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index 9c124705120d..00302e8b9615 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c @@ -426,7 +426,6 @@ static const struct proto_ops ieee802154_raw_ops = { .sendmsg = ieee802154_sock_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; /* DGRAM Sockets (802.15.4 dataframes) */ @@ -989,7 +988,6 @@ static const struct proto_ops ieee802154_dgram_ops = { .sendmsg = ieee802154_sock_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static void ieee802154_sock_destruct(struct sock *sk) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 38e649fb4474..9b2ca2fcc5a1 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -847,23 +847,6 @@ void inet_splice_eof(struct socket *sock) } EXPORT_SYMBOL_GPL(inet_splice_eof); -ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags) -{ - struct sock *sk = sock->sk; - const struct proto *prot; - - if (unlikely(inet_send_prepare(sk))) - return -EAGAIN; - - /* IPV6_ADDRFORM can change sk->sk_prot under us. */ - prot = READ_ONCE(sk->sk_prot); - if (prot->sendpage) - return prot->sendpage(sk, page, offset, size, flags); - return sock_no_sendpage(sock, page, offset, size, flags); -} -EXPORT_SYMBOL(inet_sendpage); - INDIRECT_CALLABLE_DECLARE(int udp_recvmsg(struct sock *, struct msghdr *, size_t, int, int *)); int inet_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, @@ -1067,12 +1050,10 @@ const struct proto_ops inet_stream_ops = { .mmap = tcp_mmap, #endif .splice_eof = inet_splice_eof, - .sendpage = inet_sendpage, .splice_read = tcp_splice_read, .read_sock = tcp_read_sock, .read_skb = tcp_read_skb, .sendmsg_locked = tcp_sendmsg_locked, - .sendpage_locked = tcp_sendpage_locked, .peek_len = tcp_peek_len, #ifdef CONFIG_COMPAT .compat_ioctl = inet_compat_ioctl, @@ -1102,7 +1083,6 @@ const struct proto_ops inet_dgram_ops = { .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, .splice_eof = inet_splice_eof, - .sendpage = inet_sendpage, .set_peek_off = sk_set_peek_off, #ifdef CONFIG_COMPAT .compat_ioctl = inet_compat_ioctl, @@ -1134,7 +1114,6 @@ static const struct proto_ops inet_sockraw_ops = { .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, .splice_eof = inet_splice_eof, - .sendpage = inet_sendpage, #ifdef CONFIG_COMPAT .compat_ioctl = inet_compat_ioctl, #endif diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index d56edc2c885f..e03e08745308 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -923,11 +923,10 @@ int tcp_send_mss(struct sock *sk, int *size_goal, int flags) return mss_now; } -/* In some cases, both sendpage() and sendmsg() could have added - * an skb to the write queue, but failed adding payload on it. - * We need to remove it to consume less memory, but more - * importantly be able to generate EPOLLOUT for Edge Trigger epoll() - * users. +/* In some cases, both sendmsg() could have added an skb to the write queue, + * but failed adding payload on it. We need to remove it to consume less + * memory, but more importantly be able to generate EPOLLOUT for Edge Trigger + * epoll() users. */ void tcp_remove_empty_skb(struct sock *sk) { @@ -975,40 +974,6 @@ int tcp_wmem_schedule(struct sock *sk, int copy) return min(copy, sk->sk_forward_alloc); } -int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct bio_vec bvec; - struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; - - if (!(sk->sk_route_caps & NETIF_F_SG)) - return sock_no_sendpage_locked(sk, page, offset, size, flags); - - tcp_rate_check_app_limited(sk); /* is sending application-limited? */ - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - return tcp_sendmsg_locked(sk, &msg, size); -} -EXPORT_SYMBOL_GPL(tcp_sendpage_locked); - -int tcp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - int ret; - - lock_sock(sk); - ret = tcp_sendpage_locked(sk, page, offset, size, flags); - release_sock(sk); - - return ret; -} -EXPORT_SYMBOL(tcp_sendpage); - void tcp_free_fastopen_req(struct tcp_sock *tp) { if (tp->fastopen_req) { diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c index 31d6005cea9b..81f0dff69e0b 100644 --- a/net/ipv4/tcp_bpf.c +++ b/net/ipv4/tcp_bpf.c @@ -486,7 +486,7 @@ static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) long timeo; int flags; - /* Don't let internal sendpage flags through */ + /* Don't let internal flags through */ flags = (msg->msg_flags & ~MSG_SENDPAGE_DECRYPTED); flags |= MSG_NO_SHARED_FRAGS; @@ -566,23 +566,6 @@ out_err: return copied ? copied : err; } -static int tcp_bpf_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct bio_vec bvec; - struct msghdr msg = { - .msg_flags = flags | MSG_SPLICE_PAGES, - }; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - return tcp_bpf_sendmsg(sk, &msg, size); -} - enum { TCP_BPF_IPV4, TCP_BPF_IPV6, @@ -612,7 +595,6 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS], prot[TCP_BPF_TX] = prot[TCP_BPF_BASE]; prot[TCP_BPF_TX].sendmsg = tcp_bpf_sendmsg; - prot[TCP_BPF_TX].sendpage = tcp_bpf_sendpage; prot[TCP_BPF_RX] = prot[TCP_BPF_BASE]; prot[TCP_BPF_RX].recvmsg = tcp_bpf_recvmsg_parser; @@ -647,8 +629,7 @@ static int tcp_bpf_assert_proto_ops(struct proto *ops) * indeed valid assumptions. */ return ops->recvmsg == tcp_recvmsg && - ops->sendmsg == tcp_sendmsg && - ops->sendpage == tcp_sendpage ? 0 : -ENOTSUPP; + ops->sendmsg == tcp_sendmsg ? 0 : -ENOTSUPP; } int tcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 9213804b034f..fd365de4d5ff 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -3117,7 +3117,6 @@ struct proto tcp_prot = { .recvmsg = tcp_recvmsg, .sendmsg = tcp_sendmsg, .splice_eof = tcp_splice_eof, - .sendpage = tcp_sendpage, .backlog_rcv = tcp_v4_do_rcv, .release_cb = tcp_release_cb, .hash = inet_hash, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 48fdcd3cad9c..42a96b3547c9 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1340,20 +1340,6 @@ void udp_splice_eof(struct socket *sock) } EXPORT_SYMBOL_GPL(udp_splice_eof); -int udp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct bio_vec bvec; - struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES }; - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - return udp_sendmsg(sk, &msg, size); -} - #define UDP_SKB_IS_STATELESS 0x80000000 /* all head states (dst, sk, nf conntrack) except skb extensions are @@ -2933,7 +2919,6 @@ struct proto udp_prot = { .sendmsg = udp_sendmsg, .recvmsg = udp_recvmsg, .splice_eof = udp_splice_eof, - .sendpage = udp_sendpage, .release_cb = ip4_datagram_release_cb, .hash = udp_lib_hash, .unhash = udp_lib_unhash, diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 4ba7a88a1b1d..e1ff3a375996 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -19,8 +19,6 @@ int udp_getsockopt(struct sock *sk, int level, int optname, int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags, int *addr_len); -int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, - int flags); void udp_destroy_sock(struct sock *sk); #ifdef CONFIG_PROC_FS diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 143f93a12f25..39ecdad1b50c 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -56,7 +56,6 @@ struct proto udplite_prot = { .getsockopt = udp_getsockopt, .sendmsg = udp_sendmsg, .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, .hash = udp_lib_hash, .unhash = udp_lib_unhash, .rehash = udp_v4_rehash, diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index b3451cf47d29..5d593ddc0347 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -696,9 +696,7 @@ const struct proto_ops inet6_stream_ops = { .mmap = tcp_mmap, #endif .splice_eof = inet_splice_eof, - .sendpage = inet_sendpage, .sendmsg_locked = tcp_sendmsg_locked, - .sendpage_locked = tcp_sendpage_locked, .splice_read = tcp_splice_read, .read_sock = tcp_read_sock, .read_skb = tcp_read_skb, @@ -729,7 +727,6 @@ const struct proto_ops inet6_dgram_ops = { .recvmsg = inet6_recvmsg, /* retpoline's sake */ .read_skb = udp_read_skb, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, .set_peek_off = sk_set_peek_off, #ifdef CONFIG_COMPAT .compat_ioctl = inet6_compat_ioctl, diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index c9caeb5a43ed..ac1cef094c5f 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1296,7 +1296,6 @@ const struct proto_ops inet6_sockraw_ops = { .sendmsg = inet_sendmsg, /* ok */ .recvmsg = sock_common_recvmsg, /* ok */ .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, #ifdef CONFIG_COMPAT .compat_ioctl = inet6_compat_ioctl, #endif diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c17c8ff94b79..40dd92a2f480 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2151,7 +2151,6 @@ struct proto tcpv6_prot = { .recvmsg = tcp_recvmsg, .sendmsg = tcp_sendmsg, .splice_eof = tcp_splice_eof, - .sendpage = tcp_sendpage, .backlog_rcv = tcp_v6_do_rcv, .release_cb = tcp_release_cb, .hash = inet6_hash, diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index d0537c1c8cd7..393f01b2a7e6 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -963,24 +963,6 @@ static void kcm_splice_eof(struct socket *sock) release_sock(sk); } -static ssize_t kcm_sendpage(struct socket *sock, struct page *page, - int offset, size_t size, int flags) - -{ - struct bio_vec bvec; - struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - if (flags & MSG_OOB) - return -EOPNOTSUPP; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - return kcm_sendmsg(sock, &msg, size); -} - static int kcm_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) { @@ -1769,7 +1751,6 @@ static const struct proto_ops kcm_dgram_ops = { .recvmsg = kcm_recvmsg, .mmap = sock_no_mmap, .splice_eof = kcm_splice_eof, - .sendpage = kcm_sendpage, }; static const struct proto_ops kcm_seqpacket_ops = { @@ -1791,7 +1772,6 @@ static const struct proto_ops kcm_seqpacket_ops = { .recvmsg = kcm_recvmsg, .mmap = sock_no_mmap, .splice_eof = kcm_splice_eof, - .sendpage = kcm_sendpage, .splice_read = kcm_splice_read, }; diff --git a/net/key/af_key.c b/net/key/af_key.c index 31ab12fd720a..ede3c6a60353 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3761,7 +3761,6 @@ static const struct proto_ops pfkey_ops = { .listen = sock_no_listen, .shutdown = sock_no_shutdown, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, /* Now the operations that really occur. */ .release = pfkey_release, diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index 2b795c1064f5..f9073bc7281f 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -624,7 +624,6 @@ static const struct proto_ops l2tp_ip_ops = { .sendmsg = inet_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct inet_protosw l2tp_ip_protosw = { diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index 5137ea1861ce..b1623f9c4f92 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c @@ -751,7 +751,6 @@ static const struct proto_ops l2tp_ip6_ops = { .sendmsg = inet_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, #ifdef CONFIG_COMPAT .compat_ioctl = inet6_compat_ioctl, #endif diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 9ffbc667be6c..57c35c960b2c 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -1232,7 +1232,6 @@ static const struct proto_ops llc_ui_ops = { .sendmsg = llc_ui_sendmsg, .recvmsg = llc_ui_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static const char llc_proc_err_msg[] __initconst = diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c index bb4bd0b6a4f7..f6be58b68c6f 100644 --- a/net/mctp/af_mctp.c +++ b/net/mctp/af_mctp.c @@ -485,7 +485,6 @@ static const struct proto_ops mctp_dgram_ops = { .sendmsg = mctp_sendmsg, .recvmsg = mctp_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, #ifdef CONFIG_COMPAT .compat_ioctl = mctp_compat_ioctl, #endif diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index bd023debedc8..e892673deb73 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3866,7 +3866,6 @@ static const struct proto_ops mptcp_stream_ops = { .sendmsg = inet_sendmsg, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, - .sendpage = inet_sendpage, }; static struct inet_protosw mptcp_protosw = { @@ -3961,7 +3960,6 @@ static const struct proto_ops mptcp_v6_stream_ops = { .sendmsg = inet6_sendmsg, .recvmsg = inet6_recvmsg, .mmap = sock_no_mmap, - .sendpage = inet_sendpage, #ifdef CONFIG_COMPAT .compat_ioctl = inet6_compat_ioctl, #endif diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index cbd9aa7ee24a..39cfb778ebc5 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2815,7 +2815,6 @@ static const struct proto_ops netlink_ops = { .sendmsg = netlink_sendmsg, .recvmsg = netlink_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static const struct net_proto_family netlink_family_ops = { diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 5a4cb796150f..eb8ccbd58df7 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -1364,7 +1364,6 @@ static const struct proto_ops nr_proto_ops = { .sendmsg = nr_sendmsg, .recvmsg = nr_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct notifier_block nr_dev_notifier = { diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a2dbeb264f26..85ff90a03b0c 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -4621,7 +4621,6 @@ static const struct proto_ops packet_ops_spkt = { .sendmsg = packet_sendmsg_spkt, .recvmsg = packet_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static const struct proto_ops packet_ops = { @@ -4643,7 +4642,6 @@ static const struct proto_ops packet_ops = { .sendmsg = packet_sendmsg, .recvmsg = packet_recvmsg, .mmap = packet_mmap, - .sendpage = sock_no_sendpage, }; static const struct net_proto_family packet_family_ops = { diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 967f9b4dc026..1018340d89a7 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -441,7 +441,6 @@ const struct proto_ops phonet_dgram_ops = { .sendmsg = pn_socket_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; const struct proto_ops phonet_stream_ops = { @@ -462,7 +461,6 @@ const struct proto_ops phonet_stream_ops = { .sendmsg = pn_socket_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; EXPORT_SYMBOL(phonet_stream_ops); diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c index 76f0434d3d06..78beb74146e7 100644 --- a/net/qrtr/af_qrtr.c +++ b/net/qrtr/af_qrtr.c @@ -1244,7 +1244,6 @@ static const struct proto_ops qrtr_proto_ops = { .shutdown = sock_no_shutdown, .release = qrtr_release, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct proto qrtr_proto = { diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 3ff6995244e5..01c4cdfef45d 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -653,7 +653,6 @@ static const struct proto_ops rds_proto_ops = { .sendmsg = rds_sendmsg, .recvmsg = rds_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static void rds_sock_destruct(struct sock *sk) diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index ca2b17f32670..49dafe9ac72f 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -1496,7 +1496,6 @@ static const struct proto_ops rose_proto_ops = { .sendmsg = rose_sendmsg, .recvmsg = rose_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct notifier_block rose_dev_notifier = { diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index da0b3b5157d5..f2cf4aa99db2 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -954,7 +954,6 @@ static const struct proto_ops rxrpc_rpc_ops = { .sendmsg = rxrpc_sendmsg, .recvmsg = rxrpc_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct proto rxrpc_proto = { diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 664d1f2e9121..274d07bd774f 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1133,7 +1133,6 @@ static const struct proto_ops inet_seqpacket_ops = { .sendmsg = inet_sendmsg, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; /* Registration with AF_INET family. */ diff --git a/net/socket.c b/net/socket.c index b778fc03c6e0..8c3c8b29995a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3552,54 +3552,6 @@ int kernel_getpeername(struct socket *sock, struct sockaddr *addr) } EXPORT_SYMBOL(kernel_getpeername); -/** - * kernel_sendpage - send a &page through a socket (kernel space) - * @sock: socket - * @page: page - * @offset: page offset - * @size: total size in bytes - * @flags: flags (MSG_DONTWAIT, ...) - * - * Returns the total amount sent in bytes or an error. - */ - -int kernel_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags) -{ - if (sock->ops->sendpage) { - /* Warn in case the improper page to zero-copy send */ - WARN_ONCE(!sendpage_ok(page), "improper page for zero-copy send"); - return sock->ops->sendpage(sock, page, offset, size, flags); - } - return sock_no_sendpage(sock, page, offset, size, flags); -} -EXPORT_SYMBOL(kernel_sendpage); - -/** - * kernel_sendpage_locked - send a &page through the locked sock (kernel space) - * @sk: sock - * @page: page - * @offset: page offset - * @size: total size in bytes - * @flags: flags (MSG_DONTWAIT, ...) - * - * Returns the total amount sent in bytes or an error. - * Caller must hold @sk. - */ - -int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct socket *sock = sk->sk_socket; - - if (sock->ops->sendpage_locked) - return sock->ops->sendpage_locked(sk, page, offset, size, - flags); - - return sock_no_sendpage_locked(sk, page, offset, size, flags); -} -EXPORT_SYMBOL(kernel_sendpage_locked); - /** * kernel_sock_shutdown - shut down part of a full-duplex connection (kernel space) * @sock: socket diff --git a/net/tipc/socket.c b/net/tipc/socket.c index dd73d71c02a9..ef8e5139a873 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -3375,7 +3375,6 @@ static const struct proto_ops msg_ops = { .sendmsg = tipc_sendmsg, .recvmsg = tipc_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage }; static const struct proto_ops packet_ops = { @@ -3396,7 +3395,6 @@ static const struct proto_ops packet_ops = { .sendmsg = tipc_send_packet, .recvmsg = tipc_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage }; static const struct proto_ops stream_ops = { @@ -3417,7 +3415,6 @@ static const struct proto_ops stream_ops = { .sendmsg = tipc_sendstream, .recvmsg = tipc_recvstream, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage }; static const struct net_proto_family tipc_family_ops = { diff --git a/net/tls/tls.h b/net/tls/tls.h index d002c3af1966..86cef1c68e03 100644 --- a/net/tls/tls.h +++ b/net/tls/tls.h @@ -98,10 +98,6 @@ void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx); void tls_sw_strparser_done(struct tls_context *tls_ctx); int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); void tls_sw_splice_eof(struct socket *sock); -int tls_sw_sendpage_locked(struct sock *sk, struct page *page, - int offset, size_t size, int flags); -int tls_sw_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags); void tls_sw_cancel_work_tx(struct tls_context *tls_ctx); void tls_sw_release_resources_tx(struct sock *sk); void tls_sw_free_ctx_tx(struct tls_context *tls_ctx); @@ -117,8 +113,6 @@ ssize_t tls_sw_splice_read(struct socket *sock, loff_t *ppos, int tls_device_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); void tls_device_splice_eof(struct socket *sock); -int tls_device_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags); int tls_tx_records(struct sock *sk, int flags); void tls_sw_write_space(struct sock *sk, struct tls_context *ctx); diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 975299d7213b..840ee06f1708 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -621,23 +621,6 @@ void tls_device_splice_eof(struct socket *sock) mutex_unlock(&tls_ctx->tx_lock); } -int tls_device_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags) -{ - struct bio_vec bvec; - struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - if (flags & MSG_OOB) - return -EOPNOTSUPP; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - return tls_device_sendmsg(sk, &msg, size); -} - struct tls_record_info *tls_get_record(struct tls_offload_context_tx *context, u32 seq, u64 *p_record_sn) { diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index 7b9c83dd7de2..d5ed4d47b16e 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -958,7 +958,6 @@ static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG] ops[TLS_SW ][TLS_BASE] = ops[TLS_BASE][TLS_BASE]; ops[TLS_SW ][TLS_BASE].splice_eof = tls_sw_splice_eof; - ops[TLS_SW ][TLS_BASE].sendpage_locked = tls_sw_sendpage_locked; ops[TLS_BASE][TLS_SW ] = ops[TLS_BASE][TLS_BASE]; ops[TLS_BASE][TLS_SW ].splice_read = tls_sw_splice_read; @@ -970,17 +969,14 @@ static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG] #ifdef CONFIG_TLS_DEVICE ops[TLS_HW ][TLS_BASE] = ops[TLS_BASE][TLS_BASE]; - ops[TLS_HW ][TLS_BASE].sendpage_locked = NULL; ops[TLS_HW ][TLS_SW ] = ops[TLS_BASE][TLS_SW ]; - ops[TLS_HW ][TLS_SW ].sendpage_locked = NULL; ops[TLS_BASE][TLS_HW ] = ops[TLS_BASE][TLS_SW ]; ops[TLS_SW ][TLS_HW ] = ops[TLS_SW ][TLS_SW ]; ops[TLS_HW ][TLS_HW ] = ops[TLS_HW ][TLS_SW ]; - ops[TLS_HW ][TLS_HW ].sendpage_locked = NULL; #endif #ifdef CONFIG_TLS_TOE ops[TLS_HW_RECORD][TLS_HW_RECORD] = *base; @@ -1029,7 +1025,6 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], prot[TLS_SW][TLS_BASE] = prot[TLS_BASE][TLS_BASE]; prot[TLS_SW][TLS_BASE].sendmsg = tls_sw_sendmsg; prot[TLS_SW][TLS_BASE].splice_eof = tls_sw_splice_eof; - prot[TLS_SW][TLS_BASE].sendpage = tls_sw_sendpage; prot[TLS_BASE][TLS_SW] = prot[TLS_BASE][TLS_BASE]; prot[TLS_BASE][TLS_SW].recvmsg = tls_sw_recvmsg; @@ -1045,12 +1040,10 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG], prot[TLS_HW][TLS_BASE] = prot[TLS_BASE][TLS_BASE]; prot[TLS_HW][TLS_BASE].sendmsg = tls_device_sendmsg; prot[TLS_HW][TLS_BASE].splice_eof = tls_device_splice_eof; - prot[TLS_HW][TLS_BASE].sendpage = tls_device_sendpage; prot[TLS_HW][TLS_SW] = prot[TLS_BASE][TLS_SW]; prot[TLS_HW][TLS_SW].sendmsg = tls_device_sendmsg; prot[TLS_HW][TLS_SW].splice_eof = tls_device_splice_eof; - prot[TLS_HW][TLS_SW].sendpage = tls_device_sendpage; prot[TLS_BASE][TLS_HW] = prot[TLS_BASE][TLS_SW]; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 319f61590d2c..9b3aa89a4292 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1281,41 +1281,6 @@ unlock: mutex_unlock(&tls_ctx->tx_lock); } -int tls_sw_sendpage_locked(struct sock *sk, struct page *page, - int offset, size_t size, int flags) -{ - struct bio_vec bvec; - struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; - - if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | - MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY | - MSG_NO_SHARED_FRAGS)) - return -EOPNOTSUPP; - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - return tls_sw_sendmsg_locked(sk, &msg, size); -} - -int tls_sw_sendpage(struct sock *sk, struct page *page, - int offset, size_t size, int flags) -{ - struct bio_vec bvec; - struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES, }; - - if (flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | - MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY)) - return -EOPNOTSUPP; - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - return tls_sw_sendmsg(sk, &msg, size); -} - static int tls_rx_rec_wait(struct sock *sk, struct sk_psock *psock, bool nonblock, bool released) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f9d196439b49..f2f234f0b92c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -758,8 +758,6 @@ static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon static int unix_shutdown(struct socket *, int); static int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int); -static ssize_t unix_stream_sendpage(struct socket *, struct page *, int offset, - size_t size, int flags); static ssize_t unix_stream_splice_read(struct socket *, loff_t *ppos, struct pipe_inode_info *, size_t size, unsigned int flags); @@ -852,7 +850,6 @@ static const struct proto_ops unix_stream_ops = { .recvmsg = unix_stream_recvmsg, .read_skb = unix_stream_read_skb, .mmap = sock_no_mmap, - .sendpage = unix_stream_sendpage, .splice_read = unix_stream_splice_read, .set_peek_off = unix_set_peek_off, .show_fdinfo = unix_show_fdinfo, @@ -878,7 +875,6 @@ static const struct proto_ops unix_dgram_ops = { .read_skb = unix_read_skb, .recvmsg = unix_dgram_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, .set_peek_off = unix_set_peek_off, .show_fdinfo = unix_show_fdinfo, }; @@ -902,7 +898,6 @@ static const struct proto_ops unix_seqpacket_ops = { .sendmsg = unix_seqpacket_sendmsg, .recvmsg = unix_seqpacket_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, .set_peek_off = unix_set_peek_off, .show_fdinfo = unix_show_fdinfo, }; @@ -2294,20 +2289,6 @@ out_err: return sent ? : err; } -static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page, - int offset, size_t size, int flags) -{ - struct bio_vec bvec; - struct msghdr msg = { .msg_flags = flags | MSG_SPLICE_PAGES }; - - if (flags & MSG_SENDPAGE_NOTLAST) - msg.msg_flags |= MSG_MORE; - - bvec_set_page(&bvec, page, size, offset); - iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); - return unix_stream_sendmsg(socket, &msg, size); -} - static int unix_seqpacket_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index efb8a0937a13..020cf17ab7e4 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1306,7 +1306,6 @@ static const struct proto_ops vsock_dgram_ops = { .sendmsg = vsock_dgram_sendmsg, .recvmsg = vsock_dgram_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, .read_skb = vsock_read_skb, }; @@ -2234,7 +2233,6 @@ static const struct proto_ops vsock_stream_ops = { .sendmsg = vsock_connectible_sendmsg, .recvmsg = vsock_connectible_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, .set_rcvlowat = vsock_set_rcvlowat, .read_skb = vsock_read_skb, }; @@ -2257,7 +2255,6 @@ static const struct proto_ops vsock_seqpacket_ops = { .sendmsg = vsock_connectible_sendmsg, .recvmsg = vsock_connectible_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, .read_skb = vsock_read_skb, }; diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 5c7ad301d742..0fb5143bec7a 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1757,7 +1757,6 @@ static const struct proto_ops x25_proto_ops = { .sendmsg = x25_sendmsg, .recvmsg = x25_recvmsg, .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, }; static struct packet_type x25_packet_type __read_mostly = { diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c index cc1e7f15fa73..5a8c0dd250af 100644 --- a/net/xdp/xsk.c +++ b/net/xdp/xsk.c @@ -1389,7 +1389,6 @@ static const struct proto_ops xsk_proto_ops = { .sendmsg = xsk_sendmsg, .recvmsg = xsk_recvmsg, .mmap = xsk_mmap, - .sendpage = sock_no_sendpage, }; static void xsk_destruct(struct sock *sk) -- cgit v1.2.3 From b848b26c6672c9b977890ba85f5a155e5eb221f0 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2023 23:55:13 +0100 Subject: net: Kill MSG_SENDPAGE_NOTLAST Now that ->sendpage() has been removed, MSG_SENDPAGE_NOTLAST can be cleaned up. Things were converted to use MSG_MORE instead, but the protocol sendpage stubs still convert MSG_SENDPAGE_NOTLAST to MSG_MORE, which is now unnecessary. Signed-off-by: David Howells cc: Jens Axboe cc: Matthew Wilcox cc: linux-afs@lists.infradead.org cc: mptcp@lists.linux.dev cc: rds-devel@oss.oracle.com cc: tipc-discussion@lists.sourceforge.net cc: virtualization@lists.linux-foundation.org Link: https://lore.kernel.org/r/20230623225513.2732256-17-dhowells@redhat.com Signed-off-by: Jakub Kicinski --- include/linux/socket.h | 4 +--- net/tls/tls_device.c | 3 +-- net/tls/tls_main.c | 2 +- net/tls/tls_sw.c | 2 +- tools/perf/trace/beauty/include/linux/socket.h | 1 - tools/perf/trace/beauty/msg_flags.c | 5 +---- 6 files changed, 5 insertions(+), 12 deletions(-) diff --git a/include/linux/socket.h b/include/linux/socket.h index 58204700018a..39b74d83c7c4 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -319,7 +319,6 @@ struct ucred { #define MSG_MORE 0x8000 /* Sender will send more */ #define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */ #define MSG_SENDPAGE_NOPOLICY 0x10000 /* sendpage() internal : do no apply policy */ -#define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */ #define MSG_BATCH 0x40000 /* sendmmsg(): more messages coming */ #define MSG_EOF MSG_FIN #define MSG_NO_SHARED_FRAGS 0x80000 /* sendpage() internal : page frags are not shared */ @@ -341,8 +340,7 @@ struct ucred { /* Flags to be cleared on entry by sendmsg and sendmmsg syscalls */ #define MSG_INTERNAL_SENDMSG_FLAGS \ - (MSG_SPLICE_PAGES | MSG_SENDPAGE_NOPOLICY | MSG_SENDPAGE_NOTLAST | \ - MSG_SENDPAGE_DECRYPTED) + (MSG_SPLICE_PAGES | MSG_SENDPAGE_NOPOLICY | MSG_SENDPAGE_DECRYPTED) /* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ #define SOL_IP 0 diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 840ee06f1708..2021fe557e50 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -441,8 +441,7 @@ static int tls_push_data(struct sock *sk, long timeo; if (flags & - ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SENDPAGE_NOTLAST | - MSG_SPLICE_PAGES)) + ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_SPLICE_PAGES)) return -EOPNOTSUPP; if (unlikely(sk->sk_err)) diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c index d5ed4d47b16e..b6896126bb92 100644 --- a/net/tls/tls_main.c +++ b/net/tls/tls_main.c @@ -127,7 +127,7 @@ int tls_push_sg(struct sock *sk, { struct bio_vec bvec; struct msghdr msg = { - .msg_flags = MSG_SENDPAGE_NOTLAST | MSG_SPLICE_PAGES | flags, + .msg_flags = MSG_SPLICE_PAGES | flags, }; int ret = 0; struct page *p; diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c index 9b3aa89a4292..53f944e6d8ef 100644 --- a/net/tls/tls_sw.c +++ b/net/tls/tls_sw.c @@ -1194,7 +1194,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_CMSG_COMPAT | MSG_SPLICE_PAGES | - MSG_SENDPAGE_NOTLAST | MSG_SENDPAGE_NOPOLICY)) + MSG_SENDPAGE_NOPOLICY)) return -EOPNOTSUPP; ret = mutex_lock_interruptible(&tls_ctx->tx_lock); diff --git a/tools/perf/trace/beauty/include/linux/socket.h b/tools/perf/trace/beauty/include/linux/socket.h index 13c3a237b9c9..3bef212a24d7 100644 --- a/tools/perf/trace/beauty/include/linux/socket.h +++ b/tools/perf/trace/beauty/include/linux/socket.h @@ -318,7 +318,6 @@ struct ucred { #define MSG_MORE 0x8000 /* Sender will send more */ #define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */ #define MSG_SENDPAGE_NOPOLICY 0x10000 /* sendpage() internal : do no apply policy */ -#define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */ #define MSG_BATCH 0x40000 /* sendmmsg(): more messages coming */ #define MSG_EOF MSG_FIN #define MSG_NO_SHARED_FRAGS 0x80000 /* sendpage() internal : page frags are not shared */ diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c index ea68db08b8e7..5cdebd7ece7e 100644 --- a/tools/perf/trace/beauty/msg_flags.c +++ b/tools/perf/trace/beauty/msg_flags.c @@ -8,9 +8,6 @@ #ifndef MSG_WAITFORONE #define MSG_WAITFORONE 0x10000 #endif -#ifndef MSG_SENDPAGE_NOTLAST -#define MSG_SENDPAGE_NOTLAST 0x20000 -#endif #ifndef MSG_FASTOPEN #define MSG_FASTOPEN 0x20000000 #endif @@ -50,7 +47,7 @@ static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size, P_MSG_FLAG(NOSIGNAL); P_MSG_FLAG(MORE); P_MSG_FLAG(WAITFORONE); - P_MSG_FLAG(SENDPAGE_NOTLAST); + P_MSG_FLAG(SPLICE_PAGES); P_MSG_FLAG(FASTOPEN); P_MSG_FLAG(CMSG_CLOEXEC); #undef P_MSG_FLAG -- cgit v1.2.3 From de6843be3082d416eaf2a00b72dad95c784ca980 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 6 Jun 2023 09:38:42 +0200 Subject: netfilter: nft_payload: rebuild vlan header when needed Skip rebuilding the vlan header when accessing destination and source mac address. Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_payload.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c index 3a3c7746e88f..8cb800989947 100644 --- a/net/netfilter/nft_payload.c +++ b/net/netfilter/nft_payload.c @@ -171,7 +171,8 @@ void nft_payload_eval(const struct nft_expr *expr, if (!skb_mac_header_was_set(skb)) goto err; - if (skb_vlan_tag_present(skb)) { + if (skb_vlan_tag_present(skb) && + priv->offset >= offsetof(struct ethhdr, h_proto)) { if (!nft_payload_copy_vlan(dest, skb, priv->offset, priv->len)) goto err; -- cgit v1.2.3 From 78aa23d0081b2029a5763c4f7d396bf2666c0c87 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 6 Jun 2023 13:58:27 +0200 Subject: netfilter: ipset: remove rcu_read_lock_bh pair from ip_set_test Callers already hold rcu_read_lock. Prior to RCU conversion this used to be a read_lock_bh(), but now the bh-disable isn't needed anymore. Cc: Jozsef Kadlecsik Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipset/ip_set_core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 46ebee9400da..a77c75f6dfb9 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -739,9 +739,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, !(opt->family == set->family || set->family == NFPROTO_UNSPEC)) return 0; - rcu_read_lock_bh(); ret = set->variant->kadt(set, skb, par, IPSET_TEST, opt); - rcu_read_unlock_bh(); if (ret == -EAGAIN) { /* Type requests element to be completed */ -- cgit v1.2.3 From 96b2ef9b16cb302d0b47c5670d30a05963e0e1e3 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 6 Jun 2023 14:08:49 +0200 Subject: netfilter: nf_tables: permit update of set size Now that set->nelems is always updated permit update of the sets max size. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_tables.h | 3 +++ net/netfilter/nf_tables_api.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 2e24ea1d744c..89b1ac4e6d4a 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -1589,6 +1589,7 @@ struct nft_trans_set { u64 timeout; bool update; bool bound; + u32 size; }; #define nft_trans_set(trans) \ @@ -1603,6 +1604,8 @@ struct nft_trans_set { (((struct nft_trans_set *)trans->data)->timeout) #define nft_trans_set_gc_int(trans) \ (((struct nft_trans_set *)trans->data)->gc_int) +#define nft_trans_set_size(trans) \ + (((struct nft_trans_set *)trans->data)->size) struct nft_trans_chain { bool update; diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 0396fd8f4e71..dfd441ff1e3e 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -483,6 +483,7 @@ static int __nft_trans_set_add(const struct nft_ctx *ctx, int msg_type, nft_trans_set_update(trans) = true; nft_trans_set_gc_int(trans) = desc->gc_int; nft_trans_set_timeout(trans) = desc->timeout; + nft_trans_set_size(trans) = desc->size; } nft_trans_commit_list_add_tail(ctx->net, trans); @@ -9428,6 +9429,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) WRITE_ONCE(set->timeout, nft_trans_set_timeout(trans)); WRITE_ONCE(set->gc_int, nft_trans_set_gc_int(trans)); + + if (nft_trans_set_size(trans)) + WRITE_ONCE(set->size, nft_trans_set_size(trans)); } else { nft_clear(net, nft_trans_set(trans)); /* This avoids hitting -EBUSY when deleting the table -- cgit v1.2.3 From 4589725502871e77d06464f731f92fd9173e2be6 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 6 Jun 2023 22:59:30 +0200 Subject: netfilter: snat: evict closing tcp entries on reply tuple collision When all tried source tuples are in use, the connection request (skb) and the new conntrack will be dropped in nf_confirm() due to the non-recoverable clash. Make it so that the last 32 attempts are allowed to evict a colliding entry if this connection is already closing and the new sequence number has advanced past the old one. Such "all tuples taken" secenario can happen with tcp-rpc workloads where same dst:dport gets queried repeatedly. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_nat_core.c | 92 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index ce829d434f13..fadbd4ed3dc0 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -27,6 +27,9 @@ #include "nf_internals.h" +#define NF_NAT_MAX_ATTEMPTS 128 +#define NF_NAT_HARDER_THRESH (NF_NAT_MAX_ATTEMPTS / 4) + static spinlock_t nf_nat_locks[CONNTRACK_LOCKS]; static DEFINE_MUTEX(nf_nat_proto_mutex); @@ -197,6 +200,88 @@ nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, return nf_conntrack_tuple_taken(&reply, ignored_conntrack); } +static bool nf_nat_may_kill(struct nf_conn *ct, unsigned long flags) +{ + static const unsigned long flags_refuse = IPS_FIXED_TIMEOUT | + IPS_DYING; + static const unsigned long flags_needed = IPS_SRC_NAT; + enum tcp_conntrack old_state; + + old_state = READ_ONCE(ct->proto.tcp.state); + if (old_state < TCP_CONNTRACK_TIME_WAIT) + return false; + + if (flags & flags_refuse) + return false; + + return (flags & flags_needed) == flags_needed; +} + +/* reverse direction will send packets to new source, so + * make sure such packets are invalid. + */ +static bool nf_seq_has_advanced(const struct nf_conn *old, const struct nf_conn *new) +{ + return (__s32)(new->proto.tcp.seen[0].td_end - + old->proto.tcp.seen[0].td_end) > 0; +} + +static int +nf_nat_used_tuple_harder(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack, + unsigned int attempts_left) +{ + static const unsigned long flags_offload = IPS_OFFLOAD | IPS_HW_OFFLOAD; + struct nf_conntrack_tuple_hash *thash; + const struct nf_conntrack_zone *zone; + struct nf_conntrack_tuple reply; + unsigned long flags; + struct nf_conn *ct; + bool taken = true; + struct net *net; + + nf_ct_invert_tuple(&reply, tuple); + + if (attempts_left > NF_NAT_HARDER_THRESH || + tuple->dst.protonum != IPPROTO_TCP || + ignored_conntrack->proto.tcp.state != TCP_CONNTRACK_SYN_SENT) + return nf_conntrack_tuple_taken(&reply, ignored_conntrack); + + /* :ast few attempts to find a free tcp port. Destructive + * action: evict colliding if its in timewait state and the + * tcp sequence number has advanced past the one used by the + * old entry. + */ + net = nf_ct_net(ignored_conntrack); + zone = nf_ct_zone(ignored_conntrack); + + thash = nf_conntrack_find_get(net, zone, &reply); + if (!thash) + return false; + + ct = nf_ct_tuplehash_to_ctrack(thash); + + if (thash->tuple.dst.dir == IP_CT_DIR_ORIGINAL) + goto out; + + if (WARN_ON_ONCE(ct == ignored_conntrack)) + goto out; + + flags = READ_ONCE(ct->status); + if (!nf_nat_may_kill(ct, flags)) + goto out; + + if (!nf_seq_has_advanced(ct, ignored_conntrack)) + goto out; + + /* Even if we can evict do not reuse if entry is offloaded. */ + if (nf_ct_kill(ct)) + taken = flags & flags_offload; +out: + nf_ct_put(ct); + return taken; +} + static bool nf_nat_inet_in_range(const struct nf_conntrack_tuple *t, const struct nf_nat_range2 *range) { @@ -385,7 +470,6 @@ static void nf_nat_l4proto_unique_tuple(struct nf_conntrack_tuple *tuple, unsigned int range_size, min, max, i, attempts; __be16 *keyptr; u16 off; - static const unsigned int max_attempts = 128; switch (tuple->dst.protonum) { case IPPROTO_ICMP: @@ -471,8 +555,8 @@ find_free_id: off = get_random_u16(); attempts = range_size; - if (attempts > max_attempts) - attempts = max_attempts; + if (attempts > NF_NAT_MAX_ATTEMPTS) + attempts = NF_NAT_MAX_ATTEMPTS; /* We are in softirq; doing a search of the entire range risks * soft lockup when all tuples are already used. @@ -483,7 +567,7 @@ find_free_id: another_round: for (i = 0; i < attempts; i++, off++) { *keyptr = htons(min + off % range_size); - if (!nf_nat_used_tuple(tuple, ct)) + if (!nf_nat_used_tuple_harder(tuple, ct, attempts - i)) return; } -- cgit v1.2.3 From 079cd633219d7298d087cd115c17682264244c18 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 15 Jun 2023 16:31:40 +0200 Subject: netfilter: nf_tables: Introduce NFT_MSG_GETSETELEM_RESET Analogous to NFT_MSG_GETOBJ_RESET, but for set elements with a timeout or attached stateful expressions like counters or quotas - reset them all at once. Respect a per element timeout value if present to reset the 'expires' value to. Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter/nf_tables.h | 2 + net/netfilter/nf_tables_api.c | 68 ++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index e059dc2644df..8466c2a9938f 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -105,6 +105,7 @@ enum nft_verdicts { * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes) * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes) * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes) + * @NFT_MSG_GETSETELEM_RESET: get set elements and reset attached stateful expressions (enum nft_set_elem_attributes) */ enum nf_tables_msg_types { NFT_MSG_NEWTABLE, @@ -140,6 +141,7 @@ enum nf_tables_msg_types { NFT_MSG_DESTROYSETELEM, NFT_MSG_DESTROYOBJ, NFT_MSG_DESTROYFLOWTABLE, + NFT_MSG_GETSETELEM_RESET, NFT_MSG_MAX, }; diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index dfd441ff1e3e..30fd62224df9 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -5229,7 +5229,8 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + static int nft_set_elem_expr_dump(struct sk_buff *skb, const struct nft_set *set, - const struct nft_set_ext *ext) + const struct nft_set_ext *ext, + bool reset) { struct nft_set_elem_expr *elem_expr; u32 size, num_exprs = 0; @@ -5242,7 +5243,7 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb, if (num_exprs == 1) { expr = nft_setelem_expr_at(elem_expr, 0); - if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, expr, false) < 0) + if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, expr, reset) < 0) return -1; return 0; @@ -5253,7 +5254,7 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb, nft_setelem_expr_foreach(expr, elem_expr, size) { expr = nft_setelem_expr_at(elem_expr, size); - if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr, false) < 0) + if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr, reset) < 0) goto nla_put_failure; } nla_nest_end(skb, nest); @@ -5266,11 +5267,13 @@ nla_put_failure: static int nf_tables_fill_setelem(struct sk_buff *skb, const struct nft_set *set, - const struct nft_set_elem *elem) + const struct nft_set_elem *elem, + bool reset) { const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); unsigned char *b = skb_tail_pointer(skb); struct nlattr *nest; + u64 timeout = 0; nest = nla_nest_start_noflag(skb, NFTA_LIST_ELEM); if (nest == NULL) @@ -5293,7 +5296,7 @@ static int nf_tables_fill_setelem(struct sk_buff *skb, goto nla_put_failure; if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS) && - nft_set_elem_expr_dump(skb, set, ext)) + nft_set_elem_expr_dump(skb, set, ext, reset)) goto nla_put_failure; if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) && @@ -5306,11 +5309,15 @@ static int nf_tables_fill_setelem(struct sk_buff *skb, htonl(*nft_set_ext_flags(ext)))) goto nla_put_failure; - if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) && - nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT, - nf_jiffies64_to_msecs(*nft_set_ext_timeout(ext)), - NFTA_SET_ELEM_PAD)) - goto nla_put_failure; + if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) { + timeout = *nft_set_ext_timeout(ext); + if (nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT, + nf_jiffies64_to_msecs(timeout), + NFTA_SET_ELEM_PAD)) + goto nla_put_failure; + } else if (set->flags & NFT_SET_TIMEOUT) { + timeout = READ_ONCE(set->timeout); + } if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { u64 expires, now = get_jiffies_64(); @@ -5325,6 +5332,9 @@ static int nf_tables_fill_setelem(struct sk_buff *skb, nf_jiffies64_to_msecs(expires), NFTA_SET_ELEM_PAD)) goto nla_put_failure; + + if (reset) + *nft_set_ext_expiration(ext) = now + timeout; } if (nft_set_ext_exists(ext, NFT_SET_EXT_USERDATA)) { @@ -5348,6 +5358,7 @@ struct nft_set_dump_args { const struct netlink_callback *cb; struct nft_set_iter iter; struct sk_buff *skb; + bool reset; }; static int nf_tables_dump_setelem(const struct nft_ctx *ctx, @@ -5358,7 +5369,7 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx, struct nft_set_dump_args *args; args = container_of(iter, struct nft_set_dump_args, iter); - return nf_tables_fill_setelem(args->skb, set, elem); + return nf_tables_fill_setelem(args->skb, set, elem, args->reset); } struct nft_set_dump_ctx { @@ -5367,7 +5378,7 @@ struct nft_set_dump_ctx { }; static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb, - const struct nft_set *set) + const struct nft_set *set, bool reset) { struct nft_set_elem_catchall *catchall; u8 genmask = nft_genmask_cur(net); @@ -5382,7 +5393,7 @@ static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb, continue; elem.priv = catchall->elem; - ret = nf_tables_fill_setelem(skb, set, &elem); + ret = nf_tables_fill_setelem(skb, set, &elem, reset); break; } @@ -5400,6 +5411,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) bool set_found = false; struct nlmsghdr *nlh; struct nlattr *nest; + bool reset = false; u32 portid, seq; int event; @@ -5447,8 +5459,12 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) if (nest == NULL) goto nla_put_failure; + if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET) + reset = true; + args.cb = cb; args.skb = skb; + args.reset = reset; args.iter.genmask = nft_genmask_cur(net); args.iter.skip = cb->args[0]; args.iter.count = 0; @@ -5457,7 +5473,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) set->ops->walk(&dump_ctx->ctx, set, &args.iter); if (!args.iter.err && args.iter.count == cb->args[0]) - args.iter.err = nft_set_catchall_dump(net, skb, set); + args.iter.err = nft_set_catchall_dump(net, skb, set, reset); rcu_read_unlock(); nla_nest_end(skb, nest); @@ -5495,7 +5511,8 @@ static int nf_tables_fill_setelem_info(struct sk_buff *skb, const struct nft_ctx *ctx, u32 seq, u32 portid, int event, u16 flags, const struct nft_set *set, - const struct nft_set_elem *elem) + const struct nft_set_elem *elem, + bool reset) { struct nlmsghdr *nlh; struct nlattr *nest; @@ -5516,7 +5533,7 @@ static int nf_tables_fill_setelem_info(struct sk_buff *skb, if (nest == NULL) goto nla_put_failure; - err = nf_tables_fill_setelem(skb, set, elem); + err = nf_tables_fill_setelem(skb, set, elem, reset); if (err < 0) goto nla_put_failure; @@ -5622,7 +5639,7 @@ static int nft_setelem_get(struct nft_ctx *ctx, struct nft_set *set, } static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, - const struct nlattr *attr) + const struct nlattr *attr, bool reset) { struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; struct nft_set_elem elem; @@ -5666,7 +5683,8 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, return err; err = nf_tables_fill_setelem_info(skb, ctx, ctx->seq, ctx->portid, - NFT_MSG_NEWSETELEM, 0, set, &elem); + NFT_MSG_NEWSETELEM, 0, set, &elem, + reset); if (err < 0) goto err_fill_setelem; @@ -5690,6 +5708,7 @@ static int nf_tables_getsetelem(struct sk_buff *skb, struct nft_set *set; struct nlattr *attr; struct nft_ctx ctx; + bool reset = false; int rem, err = 0; table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family, @@ -5724,8 +5743,11 @@ static int nf_tables_getsetelem(struct sk_buff *skb, if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS]) return -EINVAL; + if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET) + reset = true; + nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) { - err = nft_get_set_elem(&ctx, set, attr); + err = nft_get_set_elem(&ctx, set, attr, reset); if (err < 0) { NL_SET_BAD_ATTR(extack, attr); break; @@ -5758,7 +5780,7 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx, flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags, - set, elem); + set, elem, false); if (err < 0) { kfree_skb(skb); goto err; @@ -8715,6 +8737,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { .attr_count = NFTA_SET_ELEM_LIST_MAX, .policy = nft_set_elem_list_policy, }, + [NFT_MSG_GETSETELEM_RESET] = { + .call = nf_tables_getsetelem, + .type = NFNL_CB_RCU, + .attr_count = NFTA_SET_ELEM_LIST_MAX, + .policy = nft_set_elem_list_policy, + }, [NFT_MSG_DELSETELEM] = { .call = nf_tables_delsetelem, .type = NFNL_CB_BATCH, -- cgit v1.2.3 From a412dbf40ff37515acca4bba666f5386aa37246e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 21 Jun 2023 21:11:03 +0200 Subject: netfilter: nf_tables: limit allowed range via nla_policy These NLA_U32 types get stored in u8 fields, reject invalid values instead of silently casting to u8. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_bitwise.c | 2 +- net/netfilter/nft_byteorder.c | 6 +++--- net/netfilter/nft_ct.c | 2 +- net/netfilter/nft_dynset.c | 2 +- net/netfilter/nft_exthdr.c | 4 ++-- net/netfilter/nft_fwd_netdev.c | 2 +- net/netfilter/nft_hash.c | 2 +- net/netfilter/nft_meta.c | 2 +- net/netfilter/nft_range.c | 2 +- net/netfilter/nft_reject.c | 2 +- net/netfilter/nft_rt.c | 2 +- net/netfilter/nft_socket.c | 4 ++-- net/netfilter/nft_tproxy.c | 2 +- net/netfilter/nft_tunnel.c | 4 ++-- net/netfilter/nft_xfrm.c | 4 ++-- 15 files changed, 21 insertions(+), 21 deletions(-) diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c index 84eae7cabc67..14e3c44ef959 100644 --- a/net/netfilter/nft_bitwise.c +++ b/net/netfilter/nft_bitwise.c @@ -86,7 +86,7 @@ static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = { [NFTA_BITWISE_LEN] = { .type = NLA_U32 }, [NFTA_BITWISE_MASK] = { .type = NLA_NESTED }, [NFTA_BITWISE_XOR] = { .type = NLA_NESTED }, - [NFTA_BITWISE_OP] = { .type = NLA_U32 }, + [NFTA_BITWISE_OP] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_BITWISE_DATA] = { .type = NLA_NESTED }, }; diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c index b66647a5a171..9a85e797ed58 100644 --- a/net/netfilter/nft_byteorder.c +++ b/net/netfilter/nft_byteorder.c @@ -88,9 +88,9 @@ void nft_byteorder_eval(const struct nft_expr *expr, static const struct nla_policy nft_byteorder_policy[NFTA_BYTEORDER_MAX + 1] = { [NFTA_BYTEORDER_SREG] = { .type = NLA_U32 }, [NFTA_BYTEORDER_DREG] = { .type = NLA_U32 }, - [NFTA_BYTEORDER_OP] = { .type = NLA_U32 }, - [NFTA_BYTEORDER_LEN] = { .type = NLA_U32 }, - [NFTA_BYTEORDER_SIZE] = { .type = NLA_U32 }, + [NFTA_BYTEORDER_OP] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_BYTEORDER_LEN] = NLA_POLICY_MAX(NLA_BE32, 255), + [NFTA_BYTEORDER_SIZE] = NLA_POLICY_MAX(NLA_BE32, 255), }; static int nft_byteorder_init(const struct nft_ctx *ctx, diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c index b9c84499438b..38958e067aa8 100644 --- a/net/netfilter/nft_ct.c +++ b/net/netfilter/nft_ct.c @@ -332,7 +332,7 @@ static void nft_ct_set_eval(const struct nft_expr *expr, static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = { [NFTA_CT_DREG] = { .type = NLA_U32 }, - [NFTA_CT_KEY] = { .type = NLA_U32 }, + [NFTA_CT_KEY] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_CT_DIRECTION] = { .type = NLA_U8 }, [NFTA_CT_SREG] = { .type = NLA_U32 }, }; diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c index bd19c7aec92e..4fb34d76dbea 100644 --- a/net/netfilter/nft_dynset.c +++ b/net/netfilter/nft_dynset.c @@ -148,7 +148,7 @@ static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = { [NFTA_DYNSET_SET_NAME] = { .type = NLA_STRING, .len = NFT_SET_MAXNAMELEN - 1 }, [NFTA_DYNSET_SET_ID] = { .type = NLA_U32 }, - [NFTA_DYNSET_OP] = { .type = NLA_U32 }, + [NFTA_DYNSET_OP] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_DYNSET_SREG_KEY] = { .type = NLA_U32 }, [NFTA_DYNSET_SREG_DATA] = { .type = NLA_U32 }, [NFTA_DYNSET_TIMEOUT] = { .type = NLA_U64 }, diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c index 671474e59817..7f856ceb3a66 100644 --- a/net/netfilter/nft_exthdr.c +++ b/net/netfilter/nft_exthdr.c @@ -487,9 +487,9 @@ static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = { [NFTA_EXTHDR_DREG] = { .type = NLA_U32 }, [NFTA_EXTHDR_TYPE] = { .type = NLA_U8 }, [NFTA_EXTHDR_OFFSET] = { .type = NLA_U32 }, - [NFTA_EXTHDR_LEN] = { .type = NLA_U32 }, + [NFTA_EXTHDR_LEN] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_EXTHDR_FLAGS] = { .type = NLA_U32 }, - [NFTA_EXTHDR_OP] = { .type = NLA_U32 }, + [NFTA_EXTHDR_OP] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_EXTHDR_SREG] = { .type = NLA_U32 }, }; diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c index 7b9d4d1bd17c..a5268e6dd32f 100644 --- a/net/netfilter/nft_fwd_netdev.c +++ b/net/netfilter/nft_fwd_netdev.c @@ -40,7 +40,7 @@ static void nft_fwd_netdev_eval(const struct nft_expr *expr, static const struct nla_policy nft_fwd_netdev_policy[NFTA_FWD_MAX + 1] = { [NFTA_FWD_SREG_DEV] = { .type = NLA_U32 }, [NFTA_FWD_SREG_ADDR] = { .type = NLA_U32 }, - [NFTA_FWD_NFPROTO] = { .type = NLA_U32 }, + [NFTA_FWD_NFPROTO] = NLA_POLICY_MAX(NLA_BE32, 255), }; static int nft_fwd_netdev_init(const struct nft_ctx *ctx, diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index ee8d487b69c0..92d47e469204 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c @@ -59,7 +59,7 @@ static void nft_symhash_eval(const struct nft_expr *expr, static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = { [NFTA_HASH_SREG] = { .type = NLA_U32 }, [NFTA_HASH_DREG] = { .type = NLA_U32 }, - [NFTA_HASH_LEN] = { .type = NLA_U32 }, + [NFTA_HASH_LEN] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_HASH_MODULUS] = { .type = NLA_U32 }, [NFTA_HASH_SEED] = { .type = NLA_U32 }, [NFTA_HASH_OFFSET] = { .type = NLA_U32 }, diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index e384e0de7a54..8fdc7318c03c 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c @@ -458,7 +458,7 @@ EXPORT_SYMBOL_GPL(nft_meta_set_eval); const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { [NFTA_META_DREG] = { .type = NLA_U32 }, - [NFTA_META_KEY] = { .type = NLA_U32 }, + [NFTA_META_KEY] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_META_SREG] = { .type = NLA_U32 }, }; EXPORT_SYMBOL_GPL(nft_meta_policy); diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c index 0566d6aaf1e5..51ae64cd268f 100644 --- a/net/netfilter/nft_range.c +++ b/net/netfilter/nft_range.c @@ -42,7 +42,7 @@ void nft_range_eval(const struct nft_expr *expr, static const struct nla_policy nft_range_policy[NFTA_RANGE_MAX + 1] = { [NFTA_RANGE_SREG] = { .type = NLA_U32 }, - [NFTA_RANGE_OP] = { .type = NLA_U32 }, + [NFTA_RANGE_OP] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_RANGE_FROM_DATA] = { .type = NLA_NESTED }, [NFTA_RANGE_TO_DATA] = { .type = NLA_NESTED }, }; diff --git a/net/netfilter/nft_reject.c b/net/netfilter/nft_reject.c index f2addc844dd2..ed2e668474d6 100644 --- a/net/netfilter/nft_reject.c +++ b/net/netfilter/nft_reject.c @@ -18,7 +18,7 @@ #include const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = { - [NFTA_REJECT_TYPE] = { .type = NLA_U32 }, + [NFTA_REJECT_TYPE] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_REJECT_ICMP_CODE] = { .type = NLA_U8 }, }; EXPORT_SYMBOL_GPL(nft_reject_policy); diff --git a/net/netfilter/nft_rt.c b/net/netfilter/nft_rt.c index 5990fdd7b3cc..35a2c28caa60 100644 --- a/net/netfilter/nft_rt.c +++ b/net/netfilter/nft_rt.c @@ -104,7 +104,7 @@ err: static const struct nla_policy nft_rt_policy[NFTA_RT_MAX + 1] = { [NFTA_RT_DREG] = { .type = NLA_U32 }, - [NFTA_RT_KEY] = { .type = NLA_U32 }, + [NFTA_RT_KEY] = NLA_POLICY_MAX(NLA_BE32, 255), }; static int nft_rt_get_init(const struct nft_ctx *ctx, diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c index 85f8df87efda..84def74698b7 100644 --- a/net/netfilter/nft_socket.c +++ b/net/netfilter/nft_socket.c @@ -138,9 +138,9 @@ static void nft_socket_eval(const struct nft_expr *expr, } static const struct nla_policy nft_socket_policy[NFTA_SOCKET_MAX + 1] = { - [NFTA_SOCKET_KEY] = { .type = NLA_U32 }, + [NFTA_SOCKET_KEY] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_SOCKET_DREG] = { .type = NLA_U32 }, - [NFTA_SOCKET_LEVEL] = { .type = NLA_U32 }, + [NFTA_SOCKET_LEVEL] = NLA_POLICY_MAX(NLA_BE32, 255), }; static int nft_socket_init(const struct nft_ctx *ctx, diff --git a/net/netfilter/nft_tproxy.c b/net/netfilter/nft_tproxy.c index ea83f661417e..ae15cd693f0e 100644 --- a/net/netfilter/nft_tproxy.c +++ b/net/netfilter/nft_tproxy.c @@ -183,7 +183,7 @@ static void nft_tproxy_eval(const struct nft_expr *expr, } static const struct nla_policy nft_tproxy_policy[NFTA_TPROXY_MAX + 1] = { - [NFTA_TPROXY_FAMILY] = { .type = NLA_U32 }, + [NFTA_TPROXY_FAMILY] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_TPROXY_REG_ADDR] = { .type = NLA_U32 }, [NFTA_TPROXY_REG_PORT] = { .type = NLA_U32 }, }; diff --git a/net/netfilter/nft_tunnel.c b/net/netfilter/nft_tunnel.c index b059aa541798..9f21953c7433 100644 --- a/net/netfilter/nft_tunnel.c +++ b/net/netfilter/nft_tunnel.c @@ -66,9 +66,9 @@ static void nft_tunnel_get_eval(const struct nft_expr *expr, } static const struct nla_policy nft_tunnel_policy[NFTA_TUNNEL_MAX + 1] = { - [NFTA_TUNNEL_KEY] = { .type = NLA_U32 }, + [NFTA_TUNNEL_KEY] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_TUNNEL_DREG] = { .type = NLA_U32 }, - [NFTA_TUNNEL_MODE] = { .type = NLA_U32 }, + [NFTA_TUNNEL_MODE] = NLA_POLICY_MAX(NLA_BE32, 255), }; static int nft_tunnel_get_init(const struct nft_ctx *ctx, diff --git a/net/netfilter/nft_xfrm.c b/net/netfilter/nft_xfrm.c index c88fd078a9ae..452f8587adda 100644 --- a/net/netfilter/nft_xfrm.c +++ b/net/netfilter/nft_xfrm.c @@ -16,9 +16,9 @@ #include static const struct nla_policy nft_xfrm_policy[NFTA_XFRM_MAX + 1] = { - [NFTA_XFRM_KEY] = { .type = NLA_U32 }, + [NFTA_XFRM_KEY] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_XFRM_DIR] = { .type = NLA_U8 }, - [NFTA_XFRM_SPNUM] = { .type = NLA_U32 }, + [NFTA_XFRM_SPNUM] = NLA_POLICY_MAX(NLA_BE32, 255), [NFTA_XFRM_DREG] = { .type = NLA_U32 }, }; -- cgit v1.2.3 From d1b355438b8325a486f087e506d412c4e852f37b Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 23 Jun 2023 15:34:48 +0100 Subject: sfc: fix crash when reading stats while NIC is resetting efx_net_stats() (.ndo_get_stats64) can be called during an ethtool selftest, during which time nic_data->mc_stats is NULL as the NIC has been fini'd. In this case do not attempt to fetch the latest stats from the hardware, else we will crash on a NULL dereference: BUG: kernel NULL pointer dereference, address: 0000000000000038 RIP efx_nic_update_stats abridged calltrace: efx_ef10_update_stats_pf efx_net_stats dev_get_stats dev_seq_printf_stats Skipping the read is safe, we will simply give out stale stats. To ensure that the free in efx_ef10_fini_nic() does not race against efx_ef10_update_stats_pf(), which could cause a TOCTTOU bug, take the efx->stats_lock in fini_nic (it is already held across update_stats). Fixes: d3142c193dca ("sfc: refactor EF10 stats handling") Reviewed-by: Pieter Jansen van Vuuren Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index b63e47af6365..8c019f382a7f 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -1297,8 +1297,10 @@ static void efx_ef10_fini_nic(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; + spin_lock_bh(&efx->stats_lock); kfree(nic_data->mc_stats); nic_data->mc_stats = NULL; + spin_unlock_bh(&efx->stats_lock); } static int efx_ef10_init_nic(struct efx_nic *efx) @@ -1852,9 +1854,14 @@ static size_t efx_ef10_update_stats_pf(struct efx_nic *efx, u64 *full_stats, efx_ef10_get_stat_mask(efx, mask); - efx_nic_copy_stats(efx, nic_data->mc_stats); - efx_nic_update_stats(efx_ef10_stat_desc, EF10_STAT_COUNT, - mask, stats, nic_data->mc_stats, false); + /* If NIC was fini'd (probably resetting), then we can't read + * updated stats right now. + */ + if (nic_data->mc_stats) { + efx_nic_copy_stats(efx, nic_data->mc_stats); + efx_nic_update_stats(efx_ef10_stat_desc, EF10_STAT_COUNT, + mask, stats, nic_data->mc_stats, false); + } /* Update derived statistics */ efx_nic_fix_nodesc_drop_stat(efx, -- cgit v1.2.3 From cf60ed469629927fe43c2f4b4ef28a563d991935 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 23 Jun 2023 19:38:04 +0100 Subject: sfc: use padding to fix alignment in loopback test Add two bytes of padding to the start of struct efx_loopback_payload, which are not sent on the wire. This ensures the 'ip' member is 4-byte aligned, preventing the following W=1 warning: net/ethernet/sfc/selftest.c:46:15: error: field ip within 'struct efx_loopback_payload' is less aligned than 'struct iphdr' and is usually due to 'struct efx_loopback_payload' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] struct iphdr ip; Reported-by: Arnd Bergmann Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/selftest.c | 47 ++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 3c5227afd497..96d856b9043c 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -42,12 +42,16 @@ * Falcon only performs RSS on TCP/UDP packets. */ struct efx_loopback_payload { + char pad[2]; /* Ensures ip is 4-byte aligned */ struct ethhdr header; struct iphdr ip; struct udphdr udp; __be16 iteration; char msg[64]; -} __packed; +} __packed __aligned(4); +#define EFX_LOOPBACK_PAYLOAD_LEN (sizeof(struct efx_loopback_payload) - \ + offsetof(struct efx_loopback_payload, \ + header)) /* Loopback test source MAC address */ static const u8 payload_source[ETH_ALEN] __aligned(2) = { @@ -282,7 +286,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, const char *buf_ptr, int pkt_len) { struct efx_loopback_state *state = efx->loopback_selftest; - struct efx_loopback_payload *received; + struct efx_loopback_payload received; struct efx_loopback_payload *payload; BUG_ON(!buf_ptr); @@ -293,13 +297,14 @@ void efx_loopback_rx_packet(struct efx_nic *efx, payload = &state->payload; - received = (struct efx_loopback_payload *) buf_ptr; - received->ip.saddr = payload->ip.saddr; + memcpy(&received.header, buf_ptr, + min_t(int, pkt_len, EFX_LOOPBACK_PAYLOAD_LEN)); + received.ip.saddr = payload->ip.saddr; if (state->offload_csum) - received->ip.check = payload->ip.check; + received.ip.check = payload->ip.check; /* Check that header exists */ - if (pkt_len < sizeof(received->header)) { + if (pkt_len < sizeof(received.header)) { netif_err(efx, drv, efx->net_dev, "saw runt RX packet (length %d) in %s loopback " "test\n", pkt_len, LOOPBACK_MODE(efx)); @@ -307,7 +312,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, } /* Check that the ethernet header exists */ - if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) { + if (memcmp(&received.header, &payload->header, ETH_HLEN) != 0) { netif_err(efx, drv, efx->net_dev, "saw non-loopback RX packet in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -315,16 +320,16 @@ void efx_loopback_rx_packet(struct efx_nic *efx, } /* Check packet length */ - if (pkt_len != sizeof(*payload)) { + if (pkt_len != EFX_LOOPBACK_PAYLOAD_LEN) { netif_err(efx, drv, efx->net_dev, "saw incorrect RX packet length %d (wanted %d) in " - "%s loopback test\n", pkt_len, (int)sizeof(*payload), - LOOPBACK_MODE(efx)); + "%s loopback test\n", pkt_len, + (int)EFX_LOOPBACK_PAYLOAD_LEN, LOOPBACK_MODE(efx)); goto err; } /* Check that IP header matches */ - if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) { + if (memcmp(&received.ip, &payload->ip, sizeof(payload->ip)) != 0) { netif_err(efx, drv, efx->net_dev, "saw corrupted IP header in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -332,7 +337,7 @@ void efx_loopback_rx_packet(struct efx_nic *efx, } /* Check that msg and padding matches */ - if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) { + if (memcmp(&received.msg, &payload->msg, sizeof(received.msg)) != 0) { netif_err(efx, drv, efx->net_dev, "saw corrupted RX packet in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -340,10 +345,10 @@ void efx_loopback_rx_packet(struct efx_nic *efx, } /* Check that iteration matches */ - if (received->iteration != payload->iteration) { + if (received.iteration != payload->iteration) { netif_err(efx, drv, efx->net_dev, "saw RX packet from iteration %d (wanted %d) in " - "%s loopback test\n", ntohs(received->iteration), + "%s loopback test\n", ntohs(received.iteration), ntohs(payload->iteration), LOOPBACK_MODE(efx)); goto err; } @@ -363,7 +368,8 @@ void efx_loopback_rx_packet(struct efx_nic *efx, buf_ptr, pkt_len, 0); netif_err(efx, drv, efx->net_dev, "expected packet:\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, - &state->payload, sizeof(state->payload), 0); + &state->payload.header, EFX_LOOPBACK_PAYLOAD_LEN, + 0); } #endif atomic_inc(&state->rx_bad); @@ -385,14 +391,15 @@ static void efx_iterate_state(struct efx_nic *efx) payload->ip.daddr = htonl(INADDR_LOOPBACK); payload->ip.ihl = 5; payload->ip.check = (__force __sum16) htons(0xdead); - payload->ip.tot_len = htons(sizeof(*payload) - sizeof(struct ethhdr)); + payload->ip.tot_len = htons(sizeof(*payload) - + offsetof(struct efx_loopback_payload, ip)); payload->ip.version = IPVERSION; payload->ip.protocol = IPPROTO_UDP; /* Initialise udp header */ payload->udp.source = 0; - payload->udp.len = htons(sizeof(*payload) - sizeof(struct ethhdr) - - sizeof(struct iphdr)); + payload->udp.len = htons(sizeof(*payload) - + offsetof(struct efx_loopback_payload, udp)); payload->udp.check = 0; /* checksum ignored */ /* Fill out payload */ @@ -418,7 +425,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) for (i = 0; i < state->packet_count; i++) { /* Allocate an skb, holding an extra reference for * transmit completion counting */ - skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); + skb = alloc_skb(EFX_LOOPBACK_PAYLOAD_LEN, GFP_KERNEL); if (!skb) return -ENOMEM; state->skbs[i] = skb; @@ -429,6 +436,8 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) payload = skb_put(skb, sizeof(state->payload)); memcpy(payload, &state->payload, sizeof(state->payload)); payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); + /* Strip off the leading padding */ + skb_pull(skb, offsetof(struct efx_loopback_payload, header)); /* Ensure everything we've written is visible to the * interrupt handler. */ -- cgit v1.2.3 From 30c24dd87f3f4640ee3dc693230f343023227c1c Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 23 Jun 2023 19:38:05 +0100 Subject: sfc: siena: use padding to fix alignment in loopback test Add two bytes of padding to the start of struct efx_loopback_payload, which are not sent on the wire. This ensures the 'ip' member is 4-byte aligned, preventing the following W=1 warning: net/ethernet/sfc/siena/selftest.c:46:15: error: field ip within 'struct efx_loopback_payload' is less aligned than 'struct iphdr' and is usually due to 'struct efx_loopback_payload' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] struct iphdr ip; Reported-by: Arnd Bergmann Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/siena/selftest.c | 47 ++++++++++++++++++------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/sfc/siena/selftest.c b/drivers/net/ethernet/sfc/siena/selftest.c index 07715a3d6bea..111ac17194a5 100644 --- a/drivers/net/ethernet/sfc/siena/selftest.c +++ b/drivers/net/ethernet/sfc/siena/selftest.c @@ -42,12 +42,16 @@ * Falcon only performs RSS on TCP/UDP packets. */ struct efx_loopback_payload { + char pad[2]; /* Ensures ip is 4-byte aligned */ struct ethhdr header; struct iphdr ip; struct udphdr udp; __be16 iteration; char msg[64]; -} __packed; +} __packed __aligned(4); +#define EFX_LOOPBACK_PAYLOAD_LEN (sizeof(struct efx_loopback_payload) - \ + offsetof(struct efx_loopback_payload, \ + header)) /* Loopback test source MAC address */ static const u8 payload_source[ETH_ALEN] __aligned(2) = { @@ -282,7 +286,7 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, const char *buf_ptr, int pkt_len) { struct efx_loopback_state *state = efx->loopback_selftest; - struct efx_loopback_payload *received; + struct efx_loopback_payload received; struct efx_loopback_payload *payload; BUG_ON(!buf_ptr); @@ -293,13 +297,14 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, payload = &state->payload; - received = (struct efx_loopback_payload *) buf_ptr; - received->ip.saddr = payload->ip.saddr; + memcpy(&received.header, buf_ptr, + min_t(int, pkt_len, EFX_LOOPBACK_PAYLOAD_LEN)); + received.ip.saddr = payload->ip.saddr; if (state->offload_csum) - received->ip.check = payload->ip.check; + received.ip.check = payload->ip.check; /* Check that header exists */ - if (pkt_len < sizeof(received->header)) { + if (pkt_len < sizeof(received.header)) { netif_err(efx, drv, efx->net_dev, "saw runt RX packet (length %d) in %s loopback " "test\n", pkt_len, LOOPBACK_MODE(efx)); @@ -307,7 +312,7 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, } /* Check that the ethernet header exists */ - if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) { + if (memcmp(&received.header, &payload->header, ETH_HLEN) != 0) { netif_err(efx, drv, efx->net_dev, "saw non-loopback RX packet in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -315,16 +320,16 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, } /* Check packet length */ - if (pkt_len != sizeof(*payload)) { + if (pkt_len != EFX_LOOPBACK_PAYLOAD_LEN) { netif_err(efx, drv, efx->net_dev, "saw incorrect RX packet length %d (wanted %d) in " - "%s loopback test\n", pkt_len, (int)sizeof(*payload), - LOOPBACK_MODE(efx)); + "%s loopback test\n", pkt_len, + (int)EFX_LOOPBACK_PAYLOAD_LEN, LOOPBACK_MODE(efx)); goto err; } /* Check that IP header matches */ - if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) { + if (memcmp(&received.ip, &payload->ip, sizeof(payload->ip)) != 0) { netif_err(efx, drv, efx->net_dev, "saw corrupted IP header in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -332,7 +337,7 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, } /* Check that msg and padding matches */ - if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) { + if (memcmp(&received.msg, &payload->msg, sizeof(received.msg)) != 0) { netif_err(efx, drv, efx->net_dev, "saw corrupted RX packet in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -340,10 +345,10 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, } /* Check that iteration matches */ - if (received->iteration != payload->iteration) { + if (received.iteration != payload->iteration) { netif_err(efx, drv, efx->net_dev, "saw RX packet from iteration %d (wanted %d) in " - "%s loopback test\n", ntohs(received->iteration), + "%s loopback test\n", ntohs(received.iteration), ntohs(payload->iteration), LOOPBACK_MODE(efx)); goto err; } @@ -363,7 +368,8 @@ void efx_siena_loopback_rx_packet(struct efx_nic *efx, buf_ptr, pkt_len, 0); netif_err(efx, drv, efx->net_dev, "expected packet:\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, - &state->payload, sizeof(state->payload), 0); + &state->payload.header, EFX_LOOPBACK_PAYLOAD_LEN, + 0); } #endif atomic_inc(&state->rx_bad); @@ -385,14 +391,15 @@ static void efx_iterate_state(struct efx_nic *efx) payload->ip.daddr = htonl(INADDR_LOOPBACK); payload->ip.ihl = 5; payload->ip.check = (__force __sum16) htons(0xdead); - payload->ip.tot_len = htons(sizeof(*payload) - sizeof(struct ethhdr)); + payload->ip.tot_len = htons(sizeof(*payload) - + offsetof(struct efx_loopback_payload, ip)); payload->ip.version = IPVERSION; payload->ip.protocol = IPPROTO_UDP; /* Initialise udp header */ payload->udp.source = 0; - payload->udp.len = htons(sizeof(*payload) - sizeof(struct ethhdr) - - sizeof(struct iphdr)); + payload->udp.len = htons(sizeof(*payload) - + offsetof(struct efx_loopback_payload, udp)); payload->udp.check = 0; /* checksum ignored */ /* Fill out payload */ @@ -418,7 +425,7 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) for (i = 0; i < state->packet_count; i++) { /* Allocate an skb, holding an extra reference for * transmit completion counting */ - skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); + skb = alloc_skb(EFX_LOOPBACK_PAYLOAD_LEN, GFP_KERNEL); if (!skb) return -ENOMEM; state->skbs[i] = skb; @@ -429,6 +436,8 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) payload = skb_put(skb, sizeof(state->payload)); memcpy(payload, &state->payload, sizeof(state->payload)); payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); + /* Strip off the leading padding */ + skb_pull(skb, offsetof(struct efx_loopback_payload, header)); /* Ensure everything we've written is visible to the * interrupt handler. */ -- cgit v1.2.3 From 1186c6b31ee14fa1e83f5a94be0daa9bc99f9b30 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 23 Jun 2023 19:38:06 +0100 Subject: sfc: falcon: use padding to fix alignment in loopback test Add two bytes of padding to the start of struct ef4_loopback_payload, which are not sent on the wire. This ensures the 'ip' member is 4-byte aligned, preventing the following W=1 warning: net/ethernet/sfc/falcon/selftest.c:43:15: error: field ip within 'struct ef4_loopback_payload' is less aligned than 'struct iphdr' and is usually due to 'struct ef4_loopback_payload' being packed, which can lead to unaligned accesses [-Werror,-Wunaligned-access] struct iphdr ip; Reported-by: Arnd Bergmann Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/falcon/selftest.c | 47 ++++++++++++++++++------------ 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/sfc/falcon/selftest.c b/drivers/net/ethernet/sfc/falcon/selftest.c index 6a454ac6f876..9e5ce2a13787 100644 --- a/drivers/net/ethernet/sfc/falcon/selftest.c +++ b/drivers/net/ethernet/sfc/falcon/selftest.c @@ -39,12 +39,16 @@ * Falcon only performs RSS on TCP/UDP packets. */ struct ef4_loopback_payload { + char pad[2]; /* Ensures ip is 4-byte aligned */ struct ethhdr header; struct iphdr ip; struct udphdr udp; __be16 iteration; char msg[64]; -} __packed; +} __packed __aligned(4); +#define EF4_LOOPBACK_PAYLOAD_LEN (sizeof(struct ef4_loopback_payload) - \ + offsetof(struct ef4_loopback_payload, \ + header)) /* Loopback test source MAC address */ static const u8 payload_source[ETH_ALEN] __aligned(2) = { @@ -284,7 +288,7 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, const char *buf_ptr, int pkt_len) { struct ef4_loopback_state *state = efx->loopback_selftest; - struct ef4_loopback_payload *received; + struct ef4_loopback_payload received; struct ef4_loopback_payload *payload; BUG_ON(!buf_ptr); @@ -295,13 +299,14 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, payload = &state->payload; - received = (struct ef4_loopback_payload *) buf_ptr; - received->ip.saddr = payload->ip.saddr; + memcpy(&received.header, buf_ptr, + min_t(int, pkt_len, EF4_LOOPBACK_PAYLOAD_LEN)); + received.ip.saddr = payload->ip.saddr; if (state->offload_csum) - received->ip.check = payload->ip.check; + received.ip.check = payload->ip.check; /* Check that header exists */ - if (pkt_len < sizeof(received->header)) { + if (pkt_len < sizeof(received.header)) { netif_err(efx, drv, efx->net_dev, "saw runt RX packet (length %d) in %s loopback " "test\n", pkt_len, LOOPBACK_MODE(efx)); @@ -309,7 +314,7 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, } /* Check that the ethernet header exists */ - if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) { + if (memcmp(&received.header, &payload->header, ETH_HLEN) != 0) { netif_err(efx, drv, efx->net_dev, "saw non-loopback RX packet in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -317,16 +322,16 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, } /* Check packet length */ - if (pkt_len != sizeof(*payload)) { + if (pkt_len != EF4_LOOPBACK_PAYLOAD_LEN) { netif_err(efx, drv, efx->net_dev, "saw incorrect RX packet length %d (wanted %d) in " - "%s loopback test\n", pkt_len, (int)sizeof(*payload), - LOOPBACK_MODE(efx)); + "%s loopback test\n", pkt_len, + (int)EF4_LOOPBACK_PAYLOAD_LEN, LOOPBACK_MODE(efx)); goto err; } /* Check that IP header matches */ - if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) { + if (memcmp(&received.ip, &payload->ip, sizeof(payload->ip)) != 0) { netif_err(efx, drv, efx->net_dev, "saw corrupted IP header in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -334,7 +339,7 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, } /* Check that msg and padding matches */ - if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) { + if (memcmp(&received.msg, &payload->msg, sizeof(received.msg)) != 0) { netif_err(efx, drv, efx->net_dev, "saw corrupted RX packet in %s loopback test\n", LOOPBACK_MODE(efx)); @@ -342,10 +347,10 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, } /* Check that iteration matches */ - if (received->iteration != payload->iteration) { + if (received.iteration != payload->iteration) { netif_err(efx, drv, efx->net_dev, "saw RX packet from iteration %d (wanted %d) in " - "%s loopback test\n", ntohs(received->iteration), + "%s loopback test\n", ntohs(received.iteration), ntohs(payload->iteration), LOOPBACK_MODE(efx)); goto err; } @@ -365,7 +370,8 @@ void ef4_loopback_rx_packet(struct ef4_nic *efx, buf_ptr, pkt_len, 0); netif_err(efx, drv, efx->net_dev, "expected packet:\n"); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, - &state->payload, sizeof(state->payload), 0); + &state->payload.header, EF4_LOOPBACK_PAYLOAD_LEN, + 0); } #endif atomic_inc(&state->rx_bad); @@ -387,14 +393,15 @@ static void ef4_iterate_state(struct ef4_nic *efx) payload->ip.daddr = htonl(INADDR_LOOPBACK); payload->ip.ihl = 5; payload->ip.check = (__force __sum16) htons(0xdead); - payload->ip.tot_len = htons(sizeof(*payload) - sizeof(struct ethhdr)); + payload->ip.tot_len = htons(sizeof(*payload) - + offsetof(struct ef4_loopback_payload, ip)); payload->ip.version = IPVERSION; payload->ip.protocol = IPPROTO_UDP; /* Initialise udp header */ payload->udp.source = 0; - payload->udp.len = htons(sizeof(*payload) - sizeof(struct ethhdr) - - sizeof(struct iphdr)); + payload->udp.len = htons(sizeof(*payload) - + offsetof(struct ef4_loopback_payload, udp)); payload->udp.check = 0; /* checksum ignored */ /* Fill out payload */ @@ -420,7 +427,7 @@ static int ef4_begin_loopback(struct ef4_tx_queue *tx_queue) for (i = 0; i < state->packet_count; i++) { /* Allocate an skb, holding an extra reference for * transmit completion counting */ - skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); + skb = alloc_skb(EF4_LOOPBACK_PAYLOAD_LEN, GFP_KERNEL); if (!skb) return -ENOMEM; state->skbs[i] = skb; @@ -431,6 +438,8 @@ static int ef4_begin_loopback(struct ef4_tx_queue *tx_queue) payload = skb_put(skb, sizeof(state->payload)); memcpy(payload, &state->payload, sizeof(state->payload)); payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); + /* Strip off the leading padding */ + skb_pull(skb, offsetof(struct ef4_loopback_payload, header)); /* Ensure everything we've written is visible to the * interrupt handler. */ -- cgit v1.2.3 From 6709d4b7bc2e079241fdef15d1160581c5261c10 Mon Sep 17 00:00:00 2001 From: Lin Ma Date: Sun, 25 Jun 2023 17:10:07 +0800 Subject: net: nfc: Fix use-after-free caused by nfc_llcp_find_local This commit fixes several use-after-free that caused by function nfc_llcp_find_local(). For example, one UAF can happen when below buggy time window occurs. // nfc_genl_llc_get_params | // nfc_unregister_device | dev = nfc_get_device(idx); | device_lock(...) if (!dev) | dev->shutting_down = true; return -ENODEV; | device_unlock(...); | device_lock(...); | // nfc_llcp_unregister_device | nfc_llcp_find_local() nfc_llcp_find_local(...); | | local_cleanup() if (!local) { | rc = -ENODEV; | // nfc_llcp_local_put goto exit; | kref_put(.., local_release) } | | // local_release | list_del(&local->list) // nfc_genl_send_params | kfree() local->dev->idx !!!UAF!!! | | and the crash trace for the one of the discussed UAF like: BUG: KASAN: slab-use-after-free in nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045 Read of size 8 at addr ffff888105b0e410 by task 20114 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x72/0xa0 lib/dump_stack.c:106 print_address_description mm/kasan/report.c:319 [inline] print_report+0xcc/0x620 mm/kasan/report.c:430 kasan_report+0xb2/0xe0 mm/kasan/report.c:536 nfc_genl_send_params net/nfc/netlink.c:999 [inline] nfc_genl_llc_get_params+0x72f/0x780 net/nfc/netlink.c:1045 genl_family_rcv_msg_doit.isra.0+0x1ee/0x2e0 net/netlink/genetlink.c:968 genl_family_rcv_msg net/netlink/genetlink.c:1048 [inline] genl_rcv_msg+0x503/0x7d0 net/netlink/genetlink.c:1065 netlink_rcv_skb+0x161/0x430 net/netlink/af_netlink.c:2548 genl_rcv+0x28/0x40 net/netlink/genetlink.c:1076 netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline] netlink_unicast+0x644/0x900 net/netlink/af_netlink.c:1365 netlink_sendmsg+0x934/0xe70 net/netlink/af_netlink.c:1913 sock_sendmsg_nosec net/socket.c:724 [inline] sock_sendmsg+0x1b6/0x200 net/socket.c:747 ____sys_sendmsg+0x6e9/0x890 net/socket.c:2501 ___sys_sendmsg+0x110/0x1b0 net/socket.c:2555 __sys_sendmsg+0xf7/0x1d0 net/socket.c:2584 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x72/0xdc RIP: 0033:0x7f34640a2389 RSP: 002b:00007f3463415168 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007f34641c1f80 RCX: 00007f34640a2389 RDX: 0000000000000000 RSI: 0000000020000240 RDI: 0000000000000006 RBP: 00007f34640ed493 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffe38449ecf R14: 00007f3463415300 R15: 0000000000022000 Allocated by task 20116: kasan_save_stack+0x22/0x50 mm/kasan/common.c:45 kasan_set_track+0x25/0x30 mm/kasan/common.c:52 ____kasan_kmalloc mm/kasan/common.c:374 [inline] __kasan_kmalloc+0x7f/0x90 mm/kasan/common.c:383 kmalloc include/linux/slab.h:580 [inline] kzalloc include/linux/slab.h:720 [inline] nfc_llcp_register_device+0x49/0xa40 net/nfc/llcp_core.c:1567 nfc_register_device+0x61/0x260 net/nfc/core.c:1124 nci_register_device+0x776/0xb20 net/nfc/nci/core.c:1257 virtual_ncidev_open+0x147/0x230 drivers/nfc/virtual_ncidev.c:148 misc_open+0x379/0x4a0 drivers/char/misc.c:165 chrdev_open+0x26c/0x780 fs/char_dev.c:414 do_dentry_open+0x6c4/0x12a0 fs/open.c:920 do_open fs/namei.c:3560 [inline] path_openat+0x24fe/0x37e0 fs/namei.c:3715 do_filp_open+0x1ba/0x410 fs/namei.c:3742 do_sys_openat2+0x171/0x4c0 fs/open.c:1356 do_sys_open fs/open.c:1372 [inline] __do_sys_openat fs/open.c:1388 [inline] __se_sys_openat fs/open.c:1383 [inline] __x64_sys_openat+0x143/0x200 fs/open.c:1383 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x72/0xdc Freed by task 20115: kasan_save_stack+0x22/0x50 mm/kasan/common.c:45 kasan_set_track+0x25/0x30 mm/kasan/common.c:52 kasan_save_free_info+0x2e/0x50 mm/kasan/generic.c:521 ____kasan_slab_free mm/kasan/common.c:236 [inline] ____kasan_slab_free mm/kasan/common.c:200 [inline] __kasan_slab_free+0x10a/0x190 mm/kasan/common.c:244 kasan_slab_free include/linux/kasan.h:162 [inline] slab_free_hook mm/slub.c:1781 [inline] slab_free_freelist_hook mm/slub.c:1807 [inline] slab_free mm/slub.c:3787 [inline] __kmem_cache_free+0x7a/0x190 mm/slub.c:3800 local_release net/nfc/llcp_core.c:174 [inline] kref_put include/linux/kref.h:65 [inline] nfc_llcp_local_put net/nfc/llcp_core.c:182 [inline] nfc_llcp_local_put net/nfc/llcp_core.c:177 [inline] nfc_llcp_unregister_device+0x206/0x290 net/nfc/llcp_core.c:1620 nfc_unregister_device+0x160/0x1d0 net/nfc/core.c:1179 virtual_ncidev_close+0x52/0xa0 drivers/nfc/virtual_ncidev.c:163 __fput+0x252/0xa20 fs/file_table.c:321 task_work_run+0x174/0x270 kernel/task_work.c:179 resume_user_mode_work include/linux/resume_user_mode.h:49 [inline] exit_to_user_mode_loop kernel/entry/common.c:171 [inline] exit_to_user_mode_prepare+0x108/0x110 kernel/entry/common.c:204 __syscall_exit_to_user_mode_work kernel/entry/common.c:286 [inline] syscall_exit_to_user_mode+0x21/0x50 kernel/entry/common.c:297 do_syscall_64+0x4c/0x90 arch/x86/entry/common.c:86 entry_SYSCALL_64_after_hwframe+0x72/0xdc Last potentially related work creation: kasan_save_stack+0x22/0x50 mm/kasan/common.c:45 __kasan_record_aux_stack+0x95/0xb0 mm/kasan/generic.c:491 kvfree_call_rcu+0x29/0xa80 kernel/rcu/tree.c:3328 drop_sysctl_table+0x3be/0x4e0 fs/proc/proc_sysctl.c:1735 unregister_sysctl_table.part.0+0x9c/0x190 fs/proc/proc_sysctl.c:1773 unregister_sysctl_table+0x24/0x30 fs/proc/proc_sysctl.c:1753 neigh_sysctl_unregister+0x5f/0x80 net/core/neighbour.c:3895 addrconf_notify+0x140/0x17b0 net/ipv6/addrconf.c:3684 notifier_call_chain+0xbe/0x210 kernel/notifier.c:87 call_netdevice_notifiers_info+0xb5/0x150 net/core/dev.c:1937 call_netdevice_notifiers_extack net/core/dev.c:1975 [inline] call_netdevice_notifiers net/core/dev.c:1989 [inline] dev_change_name+0x3c3/0x870 net/core/dev.c:1211 dev_ifsioc+0x800/0xf70 net/core/dev_ioctl.c:376 dev_ioctl+0x3d9/0xf80 net/core/dev_ioctl.c:542 sock_do_ioctl+0x160/0x260 net/socket.c:1213 sock_ioctl+0x3f9/0x670 net/socket.c:1316 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x19e/0x210 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x72/0xdc The buggy address belongs to the object at ffff888105b0e400 which belongs to the cache kmalloc-1k of size 1024 The buggy address is located 16 bytes inside of freed 1024-byte region [ffff888105b0e400, ffff888105b0e800) The buggy address belongs to the physical page: head:ffffea000416c200 order:3 entire_mapcount:0 nr_pages_mapped:0 pincount:0 flags: 0x200000000010200(slab|head|node=0|zone=2) raw: 0200000000010200 ffff8881000430c0 ffffea00044c7010 ffffea0004510e10 raw: 0000000000000000 00000000000a000a 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff888105b0e300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff888105b0e380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc >ffff888105b0e400: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff888105b0e480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff888105b0e500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb In summary, this patch solves those use-after-free by 1. Re-implement the nfc_llcp_find_local(). The current version does not grab the reference when getting the local from the linked list. For example, the llcp_sock_bind() gets the reference like below: // llcp_sock_bind() local = nfc_llcp_find_local(dev); // A ..... \ | raceable ..... / llcp_sock->local = nfc_llcp_local_get(local); // B There is an apparent race window that one can drop the reference and free the local object fetched in (A) before (B) gets the reference. 2. Some callers of the nfc_llcp_find_local() do not grab the reference at all. For example, the nfc_genl_llc_{{get/set}_params/sdreq} functions. We add the nfc_llcp_local_put() for them. Moreover, we add the necessary error handling function to put the reference. 3. Add the nfc_llcp_remove_local() helper. The local object is removed from the linked list in local_release() when all reference is gone. This patch removes it when nfc_llcp_unregister_device() is called. Therefore, every caller of nfc_llcp_find_local() will get a reference even when the nfc_llcp_unregister_device() is called. This promises no use-after-free for the local object is ever possible. Fixes: 52feb444a903 ("NFC: Extend netlink interface for LTO, RW, and MIUX parameters support") Fixes: c7aa12252f51 ("NFC: Take a reference on the LLCP local pointer when creating a socket") Signed-off-by: Lin Ma Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- net/nfc/llcp.h | 1 - net/nfc/llcp_commands.c | 12 +++++++++--- net/nfc/llcp_core.c | 49 ++++++++++++++++++++++++++++++++++++++++++------- net/nfc/llcp_sock.c | 18 ++++++++++-------- net/nfc/netlink.c | 20 +++++++++++++++----- net/nfc/nfc.h | 1 + 6 files changed, 77 insertions(+), 24 deletions(-) diff --git a/net/nfc/llcp.h b/net/nfc/llcp.h index c1d9be636933..d8345ed57c95 100644 --- a/net/nfc/llcp.h +++ b/net/nfc/llcp.h @@ -201,7 +201,6 @@ void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s); void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s); void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock); struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); -struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local); int nfc_llcp_local_put(struct nfc_llcp_local *local); u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, struct nfc_llcp_sock *sock); diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 41e3a20c8935..5d2d4bc26ef9 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -359,6 +359,7 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) struct sk_buff *skb; struct nfc_llcp_local *local; u16 size = 0; + int err; local = nfc_llcp_find_local(dev); if (local == NULL) @@ -368,8 +369,10 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE; skb = alloc_skb(size, GFP_KERNEL); - if (skb == NULL) - return -ENOMEM; + if (skb == NULL) { + err = -ENOMEM; + goto out; + } skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE); @@ -379,8 +382,11 @@ int nfc_llcp_send_symm(struct nfc_dev *dev) nfc_llcp_send_to_raw_sock(local, skb, NFC_DIRECTION_TX); - return nfc_data_exchange(dev, local->target_idx, skb, + err = nfc_data_exchange(dev, local->target_idx, skb, nfc_llcp_recv, local); +out: + nfc_llcp_local_put(local); + return err; } int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index a27e1842b2a0..f60e424e0607 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -17,6 +17,8 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d}; static LIST_HEAD(llcp_devices); +/* Protects llcp_devices list */ +static DEFINE_SPINLOCK(llcp_devices_lock); static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb); @@ -141,7 +143,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device, write_unlock(&local->raw_sockets.lock); } -struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) +static struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) { kref_get(&local->ref); @@ -169,7 +171,6 @@ static void local_release(struct kref *ref) local = container_of(ref, struct nfc_llcp_local, ref); - list_del(&local->list); local_cleanup(local); kfree(local); } @@ -282,12 +283,33 @@ static void nfc_llcp_sdreq_timer(struct timer_list *t) struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) { struct nfc_llcp_local *local; + struct nfc_llcp_local *res = NULL; + spin_lock(&llcp_devices_lock); list_for_each_entry(local, &llcp_devices, list) - if (local->dev == dev) + if (local->dev == dev) { + res = nfc_llcp_local_get(local); + break; + } + spin_unlock(&llcp_devices_lock); + + return res; +} + +static struct nfc_llcp_local *nfc_llcp_remove_local(struct nfc_dev *dev) +{ + struct nfc_llcp_local *local, *tmp; + + spin_lock(&llcp_devices_lock); + list_for_each_entry_safe(local, tmp, &llcp_devices, list) + if (local->dev == dev) { + list_del(&local->list); + spin_unlock(&llcp_devices_lock); return local; + } + spin_unlock(&llcp_devices_lock); - pr_debug("No device found\n"); + pr_warn("Shutting down device not found\n"); return NULL; } @@ -608,12 +630,15 @@ u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) *general_bytes_len = local->gb_len; + nfc_llcp_local_put(local); + return local->gb; } int nfc_llcp_set_remote_gb(struct nfc_dev *dev, const u8 *gb, u8 gb_len) { struct nfc_llcp_local *local; + int err; if (gb_len < 3 || gb_len > NFC_MAX_GT_LEN) return -EINVAL; @@ -630,12 +655,16 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, const u8 *gb, u8 gb_len) if (memcmp(local->remote_gb, llcp_magic, 3)) { pr_err("MAC does not support LLCP\n"); - return -EINVAL; + err = -EINVAL; + goto out; } - return nfc_llcp_parse_gb_tlv(local, + err = nfc_llcp_parse_gb_tlv(local, &local->remote_gb[3], local->remote_gb_len - 3); +out: + nfc_llcp_local_put(local); + return err; } static u8 nfc_llcp_dsap(const struct sk_buff *pdu) @@ -1517,6 +1546,8 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb) __nfc_llcp_recv(local, skb); + nfc_llcp_local_put(local); + return 0; } @@ -1533,6 +1564,8 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) /* Close and purge all existing sockets */ nfc_llcp_socket_release(local, true, 0); + + nfc_llcp_local_put(local); } void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, @@ -1558,6 +1591,8 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, mod_timer(&local->link_timer, jiffies + msecs_to_jiffies(local->remote_lto)); } + + nfc_llcp_local_put(local); } int nfc_llcp_register_device(struct nfc_dev *ndev) @@ -1608,7 +1643,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) void nfc_llcp_unregister_device(struct nfc_dev *dev) { - struct nfc_llcp_local *local = nfc_llcp_find_local(dev); + struct nfc_llcp_local *local = nfc_llcp_remove_local(dev); if (local == NULL) { pr_debug("No such device\n"); diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index 77642d18a3b4..645677f84dba 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c @@ -99,7 +99,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } llcp_sock->dev = dev; - llcp_sock->local = nfc_llcp_local_get(local); + llcp_sock->local = local; llcp_sock->nfc_protocol = llcp_addr.nfc_protocol; llcp_sock->service_name_len = min_t(unsigned int, llcp_addr.service_name_len, @@ -186,7 +186,7 @@ static int llcp_raw_sock_bind(struct socket *sock, struct sockaddr *addr, } llcp_sock->dev = dev; - llcp_sock->local = nfc_llcp_local_get(local); + llcp_sock->local = local; llcp_sock->nfc_protocol = llcp_addr.nfc_protocol; nfc_llcp_sock_link(&local->raw_sockets, sk); @@ -696,22 +696,22 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, if (dev->dep_link_up == false) { ret = -ENOLINK; device_unlock(&dev->dev); - goto put_dev; + goto sock_llcp_put_local; } device_unlock(&dev->dev); if (local->rf_mode == NFC_RF_INITIATOR && addr->target_idx != local->target_idx) { ret = -ENOLINK; - goto put_dev; + goto sock_llcp_put_local; } llcp_sock->dev = dev; - llcp_sock->local = nfc_llcp_local_get(local); + llcp_sock->local = local; llcp_sock->ssap = nfc_llcp_get_local_ssap(local); if (llcp_sock->ssap == LLCP_SAP_MAX) { ret = -ENOMEM; - goto sock_llcp_put_local; + goto sock_llcp_nullify; } llcp_sock->reserved_ssap = llcp_sock->ssap; @@ -757,11 +757,13 @@ sock_unlink: sock_llcp_release: nfc_llcp_put_ssap(local, llcp_sock->ssap); -sock_llcp_put_local: - nfc_llcp_local_put(llcp_sock->local); +sock_llcp_nullify: llcp_sock->local = NULL; llcp_sock->dev = NULL; +sock_llcp_put_local: + nfc_llcp_local_put(local); + put_dev: nfc_put_device(dev); diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index b9264e730fd9..e9ac6a6f934e 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -1039,11 +1039,14 @@ static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info) msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) { rc = -ENOMEM; - goto exit; + goto put_local; } rc = nfc_genl_send_params(msg, local, info->snd_portid, info->snd_seq); +put_local: + nfc_llcp_local_put(local); + exit: device_unlock(&dev->dev); @@ -1105,7 +1108,7 @@ static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NFC_ATTR_LLC_PARAM_LTO]) { if (dev->dep_link_up) { rc = -EINPROGRESS; - goto exit; + goto put_local; } local->lto = nla_get_u8(info->attrs[NFC_ATTR_LLC_PARAM_LTO]); @@ -1117,6 +1120,9 @@ static int nfc_genl_llc_set_params(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NFC_ATTR_LLC_PARAM_MIUX]) local->miux = cpu_to_be16(miux); +put_local: + nfc_llcp_local_put(local); + exit: device_unlock(&dev->dev); @@ -1172,7 +1178,7 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info) if (rc != 0) { rc = -EINVAL; - goto exit; + goto put_local; } if (!sdp_attrs[NFC_SDP_ATTR_URI]) @@ -1191,7 +1197,7 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info) sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len); if (sdreq == NULL) { rc = -ENOMEM; - goto exit; + goto put_local; } tlvs_len += sdreq->tlv_len; @@ -1201,10 +1207,14 @@ static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info) if (hlist_empty(&sdreq_list)) { rc = -EINVAL; - goto exit; + goto put_local; } rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len); + +put_local: + nfc_llcp_local_put(local); + exit: device_unlock(&dev->dev); diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index de2ec66d7e83..0b1e6466f4fb 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -52,6 +52,7 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, const u8 *gb, u8 gb_len); u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len); int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb); struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); +int nfc_llcp_local_put(struct nfc_llcp_local *local); int __init nfc_llcp_init(void); void nfc_llcp_exit(void); void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp); -- cgit v1.2.3 From 6f67fbf8192da80c4db01a1800c7fceaca9cf1f9 Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Mon, 19 Jun 2023 20:06:57 +0100 Subject: lib/ts_bm: reset initial match offset for every block of text The `shift` variable which indicates the offset in the string at which to start matching the pattern is initialized to `bm->patlen - 1`, but it is not reset when a new block is retrieved. This means the implemen- tation may start looking at later and later positions in each successive block and miss occurrences of the pattern at the beginning. E.g., consider a HTTP packet held in a non-linear skb, where the HTTP request line occurs in the second block: [... 52 bytes of packet headers ...] GET /bmtest HTTP/1.1\r\nHost: www.example.com\r\n\r\n and the pattern is "GET /bmtest". Once the first block comprising the packet headers has been examined, `shift` will be pointing to somewhere near the end of the block, and so when the second block is examined the request line at the beginning will be missed. Reinitialize the variable for each new block. Fixes: 8082e4ed0a61 ("[LIB]: Boyer-Moore extension for textsearch infrastructure strike #2") Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1390 Signed-off-by: Jeremy Sowden Signed-off-by: Pablo Neira Ayuso --- lib/ts_bm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ts_bm.c b/lib/ts_bm.c index 1f2234221dd1..c8ecbf74ef29 100644 --- a/lib/ts_bm.c +++ b/lib/ts_bm.c @@ -60,10 +60,12 @@ static unsigned int bm_find(struct ts_config *conf, struct ts_state *state) struct ts_bm *bm = ts_config_priv(conf); unsigned int i, text_len, consumed = state->offset; const u8 *text; - int shift = bm->patlen - 1, bs; + int bs; const u8 icase = conf->flags & TS_IGNORECASE; for (;;) { + int shift = bm->patlen - 1; + text_len = conf->get_next_block(consumed, &text, conf, state); if (unlikely(text_len == 0)) -- cgit v1.2.3 From ff0a3a7d52ff7282dbd183e7fc29a1fe386b0c30 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 21 Jun 2023 17:56:53 +0200 Subject: netfilter: conntrack: dccp: copy entire header to stack buffer, not just basic one Eric Dumazet says: nf_conntrack_dccp_packet() has an unique: dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); And nothing more is 'pulled' from the packet, depending on the content. dh->dccph_doff, and/or dh->dccph_x ...) So dccp_ack_seq() is happily reading stuff past the _dh buffer. BUG: KASAN: stack-out-of-bounds in nf_conntrack_dccp_packet+0x1134/0x11c0 Read of size 4 at addr ffff000128f66e0c by task syz-executor.2/29371 [..] Fix this by increasing the stack buffer to also include room for the extra sequence numbers and all the known dccp packet type headers, then pull again after the initial validation of the basic header. While at it, mark packets invalid that lack 48bit sequence bit but where RFC says the type MUST use them. Compile tested only. v2: first skb_header_pointer() now needs to adjust the size to only pull the generic header. (Eric) Heads-up: I intend to remove dccp conntrack support later this year. Fixes: 2bc780499aa3 ("[NETFILTER]: nf_conntrack: add DCCP protocol support") Reported-by: Eric Dumazet Signed-off-by: Florian Westphal Reviewed-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_proto_dccp.c | 52 +++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index c1557d47ccd1..d4fd626d2b8c 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -432,9 +432,19 @@ static bool dccp_error(const struct dccp_hdr *dh, struct sk_buff *skb, unsigned int dataoff, const struct nf_hook_state *state) { + static const unsigned long require_seq48 = 1 << DCCP_PKT_REQUEST | + 1 << DCCP_PKT_RESPONSE | + 1 << DCCP_PKT_CLOSEREQ | + 1 << DCCP_PKT_CLOSE | + 1 << DCCP_PKT_RESET | + 1 << DCCP_PKT_SYNC | + 1 << DCCP_PKT_SYNCACK; unsigned int dccp_len = skb->len - dataoff; unsigned int cscov; const char *msg; + u8 type; + + BUILD_BUG_ON(DCCP_PKT_INVALID >= BITS_PER_LONG); if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || dh->dccph_doff * 4 > dccp_len) { @@ -459,34 +469,70 @@ static bool dccp_error(const struct dccp_hdr *dh, goto out_invalid; } - if (dh->dccph_type >= DCCP_PKT_INVALID) { + type = dh->dccph_type; + if (type >= DCCP_PKT_INVALID) { msg = "nf_ct_dccp: reserved packet type "; goto out_invalid; } + + if (test_bit(type, &require_seq48) && !dh->dccph_x) { + msg = "nf_ct_dccp: type lacks 48bit sequence numbers"; + goto out_invalid; + } + return false; out_invalid: nf_l4proto_log_invalid(skb, state, IPPROTO_DCCP, "%s", msg); return true; } +struct nf_conntrack_dccp_buf { + struct dccp_hdr dh; /* generic header part */ + struct dccp_hdr_ext ext; /* optional depending dh->dccph_x */ + union { /* depends on header type */ + struct dccp_hdr_ack_bits ack; + struct dccp_hdr_request req; + struct dccp_hdr_response response; + struct dccp_hdr_reset rst; + } u; +}; + +static struct dccp_hdr * +dccp_header_pointer(const struct sk_buff *skb, int offset, const struct dccp_hdr *dh, + struct nf_conntrack_dccp_buf *buf) +{ + unsigned int hdrlen = __dccp_hdr_len(dh); + + if (hdrlen > sizeof(*buf)) + return NULL; + + return skb_header_pointer(skb, offset, hdrlen, buf); +} + int nf_conntrack_dccp_packet(struct nf_conn *ct, struct sk_buff *skb, unsigned int dataoff, enum ip_conntrack_info ctinfo, const struct nf_hook_state *state) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - struct dccp_hdr _dh, *dh; + struct nf_conntrack_dccp_buf _dh; u_int8_t type, old_state, new_state; enum ct_dccp_roles role; unsigned int *timeouts; + struct dccp_hdr *dh; - dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh); + dh = skb_header_pointer(skb, dataoff, sizeof(*dh), &_dh.dh); if (!dh) return NF_DROP; if (dccp_error(dh, skb, dataoff, state)) return -NF_ACCEPT; + /* pull again, including possible 48 bit sequences and subtype header */ + dh = dccp_header_pointer(skb, dataoff, dh, &_dh); + if (!dh) + return NF_DROP; + type = dh->dccph_type; if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh, state)) return -NF_ACCEPT; -- cgit v1.2.3 From f18e7122cc73d9218930156fa38f050a2e37de57 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 22 Jun 2023 23:11:01 -0700 Subject: linux/netfilter.h: fix kernel-doc warnings kernel-doc does not support DECLARE_PER_CPU(), so don't mark it with kernel-doc notation. One comment block is not kernel-doc notation, so just use "/*" to begin the comment. Quietens these warnings: netfilter.h:493: warning: Function parameter or member 'bool' not described in 'DECLARE_PER_CPU' netfilter.h:493: warning: Function parameter or member 'nf_skb_duplicated' not described in 'DECLARE_PER_CPU' netfilter.h:493: warning: expecting prototype for nf_skb_duplicated(). Prototype was for DECLARE_PER_CPU() instead netfilter.h:496: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Contains bitmask of ctnetlink event subscribers, if any. Fixes: e7c8899f3e6f ("netfilter: move tee_active to core") Fixes: fdf6491193e4 ("netfilter: ctnetlink: make event listener tracking global") Signed-off-by: Randy Dunlap Reviewed-by: Simon Horman Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 0762444e3767..d4fed4c508ca 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -481,7 +481,7 @@ struct nfnl_ct_hook { }; extern const struct nfnl_ct_hook __rcu *nfnl_ct_hook; -/** +/* * nf_skb_duplicated - TEE target has sent a packet * * When a xtables target sends a packet, the OUTPUT and POSTROUTING @@ -492,7 +492,7 @@ extern const struct nfnl_ct_hook __rcu *nfnl_ct_hook; */ DECLARE_PER_CPU(bool, nf_skb_duplicated); -/** +/* * Contains bitmask of ctnetlink event subscribers, if any. * Can't be pernet due to NETLINK_LISTEN_ALL_NSID setsockopt flag. */ -- cgit v1.2.3 From f188d30087480eab421cd8ca552fb15f55d57f4d Mon Sep 17 00:00:00 2001 From: "Ilia.Gavrilov" Date: Fri, 23 Jun 2023 11:23:46 +0000 Subject: netfilter: nf_conntrack_sip: fix the ct_sip_parse_numerical_param() return value. ct_sip_parse_numerical_param() returns only 0 or 1 now. But process_register_request() and process_register_response() imply checking for a negative value if parsing of a numerical header parameter failed. The invocation in nf_nat_sip() looks correct: if (ct_sip_parse_numerical_param(...) > 0 && ...) { ... } Make the return value of the function ct_sip_parse_numerical_param() a tristate to fix all the cases a) return 1 if value is found; *val is set b) return 0 if value is not found; *val is unchanged c) return -1 on error; *val is undefined Found by InfoTeCS on behalf of Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 0f32a40fc91a ("[NETFILTER]: nf_conntrack_sip: create signalling expectations") Signed-off-by: Ilia.Gavrilov Reviewed-by: Simon Horman Reviewed-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_conntrack_sip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 77f5e82d8e3f..d0eac27f6ba0 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -611,7 +611,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, start += strlen(name); *val = simple_strtoul(start, &end, 0); if (start == end) - return 0; + return -1; if (matchoff && matchlen) { *matchoff = start - dptr; *matchlen = end - start; -- cgit v1.2.3 From 3e70489721b6c870252c9082c496703677240f53 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 26 Jun 2023 00:42:18 +0200 Subject: netfilter: nf_tables: unbind non-anonymous set if rule construction fails Otherwise a dangling reference to a rule object that is gone remains in the set binding list. Fixes: 26b5a5712eb8 ("netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain") Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 4c7937fd803f..1d64c163076a 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -5343,6 +5343,8 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set, nft_set_trans_unbind(ctx, set); if (nft_set_is_anonymous(set)) nft_deactivate_next(ctx->net, set); + else + list_del_rcu(&binding->list); set->use--; break; -- cgit v1.2.3 From b389139f12f287b8ed2e2628b72df89a081f0b59 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 26 Jun 2023 00:42:19 +0200 Subject: netfilter: nf_tables: fix underflow in chain reference counter Set element addition error path decrements reference counter on chains twice: once on element release and again via nft_data_release(). Then, d6b478666ffa ("netfilter: nf_tables: fix underflow in object reference counter") incorrectly fixed this by removing the stateful object reference count decrement. Restore the stateful object decrement as in b91d90368837 ("netfilter: nf_tables: fix leaking object reference count") and let nft_data_release() decrement the chain reference counter, so this is done only once. Fixes: d6b478666ffa ("netfilter: nf_tables: fix underflow in object reference counter") Fixes: 628bd3e49cba ("netfilter: nf_tables: drop map element references from preparation phase") Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 1d64c163076a..c742918f22a4 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6771,7 +6771,9 @@ err_set_full: err_element_clash: kfree(trans); err_elem_free: - nft_set_elem_destroy(set, elem.priv, true); + nf_tables_set_elem_destroy(ctx, set, elem.priv); + if (obj) + obj->use--; err_parse_data: if (nla[NFTA_SET_ELEM_DATA] != NULL) nft_data_release(&elem.data.val, desc.type); -- cgit v1.2.3 From 8a9922e7be6d042fa00f894c376473b17a162b66 Mon Sep 17 00:00:00 2001 From: Cambda Zhu Date: Mon, 26 Jun 2023 17:33:47 +0800 Subject: ipvlan: Fix return value of ipvlan_queue_xmit() ipvlan_queue_xmit() should return NET_XMIT_XXX, but ipvlan_xmit_mode_l2/l3() returns rx_handler_result_t or NET_RX_XXX in some cases. ipvlan_rcv_frame() will only return RX_HANDLER_CONSUMED in ipvlan_xmit_mode_l2/l3() because 'local' is true. It's equal to NET_XMIT_SUCCESS. But dev_forward_skb() can return NET_RX_SUCCESS or NET_RX_DROP, and returning NET_RX_DROP(NET_XMIT_DROP) will increase both ipvlan and ipvlan->phy_dev drops counter. The skb to forward can be treated as xmitted successfully. This patch makes ipvlan_queue_xmit() return NET_XMIT_SUCCESS for forward skb. Fixes: 2ad7bf363841 ("ipvlan: Initial check-in of the IPVLAN driver.") Signed-off-by: Cambda Zhu Link: https://lore.kernel.org/r/20230626093347.7492-1-cambda@linux.alibaba.com Signed-off-by: Paolo Abeni --- drivers/net/ipvlan/ipvlan_core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index ab5133eb1d51..e45817caaee8 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -585,7 +585,8 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev) consume_skb(skb); return NET_XMIT_DROP; } - return ipvlan_rcv_frame(addr, &skb, true); + ipvlan_rcv_frame(addr, &skb, true); + return NET_XMIT_SUCCESS; } } out: @@ -611,7 +612,8 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) consume_skb(skb); return NET_XMIT_DROP; } - return ipvlan_rcv_frame(addr, &skb, true); + ipvlan_rcv_frame(addr, &skb, true); + return NET_XMIT_SUCCESS; } } skb = skb_share_check(skb, GFP_ATOMIC); @@ -623,7 +625,8 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) * the skb for the main-dev. At the RX side we just return * RX_PASS for it to be processed further on the stack. */ - return dev_forward_skb(ipvlan->phy_dev, skb); + dev_forward_skb(ipvlan->phy_dev, skb); + return NET_XMIT_SUCCESS; } else if (is_multicast_ether_addr(eth->h_dest)) { skb_reset_mac_header(skb); -- cgit v1.2.3 From 2553a5270d6c281b8fc43bd34611197bff67d715 Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Mon, 26 Jun 2023 11:02:39 +0200 Subject: perf trace: fix MSG_SPLICE_PAGES build error Our MPTCP CI and Stephen got this error: In file included from builtin-trace.c:907: trace/beauty/msg_flags.c: In function 'syscall_arg__scnprintf_msg_flags': trace/beauty/msg_flags.c:28:21: error: 'MSG_SPLICE_PAGES' undeclared (first use in this function) 28 | if (flags & MSG_##n) { | ^~~~ trace/beauty/msg_flags.c:50:9: note: in expansion of macro 'P_MSG_FLAG' 50 | P_MSG_FLAG(SPLICE_PAGES); | ^~~~~~~~~~ trace/beauty/msg_flags.c:28:21: note: each undeclared identifier is reported only once for each function it appears in 28 | if (flags & MSG_##n) { | ^~~~ trace/beauty/msg_flags.c:50:9: note: in expansion of macro 'P_MSG_FLAG' 50 | P_MSG_FLAG(SPLICE_PAGES); | ^~~~~~~~~~ The fix is similar to what was done with MSG_FASTOPEN: the new macro is defined if it is not defined in the system headers. Fixes: b848b26c6672 ("net: Kill MSG_SENDPAGE_NOTLAST") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/r/20230626112847.2ef3d422@canb.auug.org.au/ Signed-off-by: Matthieu Baerts Link: https://lore.kernel.org/r/20230626090239.899672-1-matthieu.baerts@tessares.net Signed-off-by: Paolo Abeni --- tools/perf/trace/beauty/msg_flags.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c index 5cdebd7ece7e..aa9934020232 100644 --- a/tools/perf/trace/beauty/msg_flags.c +++ b/tools/perf/trace/beauty/msg_flags.c @@ -8,6 +8,9 @@ #ifndef MSG_WAITFORONE #define MSG_WAITFORONE 0x10000 #endif +#ifndef MSG_SPLICE_PAGES +#define MSG_SPLICE_PAGES 0x8000000 +#endif #ifndef MSG_FASTOPEN #define MSG_FASTOPEN 0x20000000 #endif -- cgit v1.2.3 From eaaacb085144e7e950061bfd6d097eb87f7513d7 Mon Sep 17 00:00:00 2001 From: Davide Tronchin Date: Mon, 26 Jun 2023 14:53:36 +0200 Subject: net: usb: qmi_wwan: add u-blox 0x1312 composition Add RmNet support for LARA-R6 01B. The new LARA-R6 product variant identified by the "01B" string can be configured (by AT interface) in three different USB modes: * Default mode (Vendor ID: 0x1546 Product ID: 0x1311) with 4 serial interfaces * RmNet mode (Vendor ID: 0x1546 Product ID: 0x1312) with 4 serial interfaces and 1 RmNet virtual network interface * CDC-ECM mode (Vendor ID: 0x1546 Product ID: 0x1313) with 4 serial interface and 1 CDC-ECM virtual network interface The first 4 interfaces of all the 3 configurations (default, RmNet, ECM) are the same. In RmNet mode LARA-R6 01B exposes the following interfaces: If 0: Diagnostic If 1: AT parser If 2: AT parser If 3: AT parset/alternative functions If 4: RMNET interface Signed-off-by: Davide Tronchin Link: https://lore.kernel.org/r/20230626125336.3127-1-davide.tronchin.94@gmail.com Signed-off-by: Paolo Abeni --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 2e7c7b0cdc54..417f7ea1fffa 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1427,6 +1427,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */ {QMI_FIXED_INTF(0x0489, 0xe0b5, 0)}, /* Foxconn T77W968 LTE with eSIM support*/ {QMI_FIXED_INTF(0x2692, 0x9025, 4)}, /* Cellient MPL200 (rebranded Qualcomm 05c6:9025) */ + {QMI_QUIRK_SET_DTR(0x1546, 0x1312, 4)}, /* u-blox LARA-R6 01B */ {QMI_QUIRK_SET_DTR(0x1546, 0x1342, 4)}, /* u-blox LARA-L6 */ /* 4. Gobi 1000 devices */ -- cgit v1.2.3 From 32d462a5c3e5b312e7dcd886e20e71b0c33abf10 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:17 +0200 Subject: octeon_ep: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20230627144339.144478-3-Julia.Lawall@inria.fr Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeon_ep/octep_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c index 392d9b0da0d7..3c43f8078528 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c @@ -158,7 +158,7 @@ static int octep_setup_oq(struct octep_device *oct, int q_no) goto desc_dma_alloc_err; } - oq->buff_info = vzalloc(oq->max_count * OCTEP_OQ_RECVBUF_SIZE); + oq->buff_info = vcalloc(oq->max_count, OCTEP_OQ_RECVBUF_SIZE); if (unlikely(!oq->buff_info)) { dev_err(&oct->pdev->dev, "Failed to allocate buffer info for OQ-%d\n", q_no); -- cgit v1.2.3 From a13de901e8d590a7d26a6d4a1c4c7e9eebbb6ca6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:19 +0200 Subject: gve: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20230627144339.144478-5-Julia.Lawall@inria.fr Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/google/gve/gve_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c index 813da572abca..6957a865cff3 100644 --- a/drivers/net/ethernet/google/gve/gve_tx.c +++ b/drivers/net/ethernet/google/gve/gve_tx.c @@ -248,7 +248,7 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx) tx->mask = slots - 1; /* alloc metadata */ - tx->info = vzalloc(sizeof(*tx->info) * slots); + tx->info = vcalloc(slots, sizeof(*tx->info)); if (!tx->info) return -ENOMEM; -- cgit v1.2.3 From 906a76cc764541bdb7f602a01e3b4cdd93dea96a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:24 +0200 Subject: pds_core: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20230627144339.144478-10-Julia.Lawall@inria.fr Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/amd/pds_core/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c index 483a070d96fa..f2c79456d745 100644 --- a/drivers/net/ethernet/amd/pds_core/core.c +++ b/drivers/net/ethernet/amd/pds_core/core.c @@ -196,7 +196,7 @@ int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index, dma_addr_t q_base_pa; int err; - qcq->q.info = vzalloc(num_descs * sizeof(*qcq->q.info)); + qcq->q.info = vcalloc(num_descs, sizeof(*qcq->q.info)); if (!qcq->q.info) { err = -ENOMEM; goto err_out; @@ -219,7 +219,7 @@ int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index, if (err) goto err_out_free_q_info; - qcq->cq.info = vzalloc(num_descs * sizeof(*qcq->cq.info)); + qcq->cq.info = vcalloc(num_descs, sizeof(*qcq->cq.info)); if (!qcq->cq.info) { err = -ENOMEM; goto err_out_free_irq; -- cgit v1.2.3 From f712c8297e0a4dadc14ba2094c92e3e99a0ff871 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:26 +0200 Subject: ionic: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20230627144339.144478-12-Julia.Lawall@inria.fr Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 6ccc1ea91992..7c20a44e549b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -561,7 +561,7 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, new->q.dev = dev; new->flags = flags; - new->q.info = vzalloc(num_descs * sizeof(*new->q.info)); + new->q.info = vcalloc(num_descs, sizeof(*new->q.info)); if (!new->q.info) { netdev_err(lif->netdev, "Cannot allocate queue info\n"); err = -ENOMEM; @@ -582,7 +582,7 @@ static int ionic_qcq_alloc(struct ionic_lif *lif, unsigned int type, if (err) goto err_out; - new->cq.info = vzalloc(num_descs * sizeof(*new->cq.info)); + new->cq.info = vcalloc(num_descs, sizeof(*new->cq.info)); if (!new->cq.info) { netdev_err(lif->netdev, "Cannot allocate completion queue info\n"); err = -ENOMEM; -- cgit v1.2.3 From fa87c54693ae248db9ff867baa28b792db671b24 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:33 +0200 Subject: net: enetc: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20230627144339.144478-19-Julia.Lawall@inria.fr Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/enetc/enetc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 164b73df9f6b..35461165de0d 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1789,7 +1789,7 @@ static int enetc_alloc_tx_resource(struct enetc_bdr_resource *res, res->bd_count = bd_count; res->bd_size = sizeof(union enetc_tx_bd); - res->tx_swbd = vzalloc(bd_count * sizeof(*res->tx_swbd)); + res->tx_swbd = vcalloc(bd_count, sizeof(*res->tx_swbd)); if (!res->tx_swbd) return -ENOMEM; @@ -1877,7 +1877,7 @@ static int enetc_alloc_rx_resource(struct enetc_bdr_resource *res, if (extended) res->bd_size *= 2; - res->rx_swbd = vzalloc(bd_count * sizeof(struct enetc_rx_swbd)); + res->rx_swbd = vcalloc(bd_count, sizeof(struct enetc_rx_swbd)); if (!res->rx_swbd) return -ENOMEM; -- cgit v1.2.3 From e9c74f8b8a31f77f8e9d7bbed5fc9f2eacbf32a5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 27 Jun 2023 16:43:37 +0200 Subject: net: mana: use vmalloc_array and vcalloc Use vmalloc_array and vcalloc to protect against multiplication overflows. The changes were done using the following Coccinelle semantic patch: // @initialize:ocaml@ @@ let rename alloc = match alloc with "vmalloc" -> "vmalloc_array" | "vzalloc" -> "vcalloc" | _ -> failwith "unknown" @@ size_t e1,e2; constant C1, C2; expression E1, E2, COUNT, x1, x2, x3; typedef u8; typedef __u8; type t = {u8,__u8,char,unsigned char}; identifier alloc = {vmalloc,vzalloc}; fresh identifier realloc = script:ocaml(alloc) { rename alloc }; @@ ( alloc(x1*x2*x3) | alloc(C1 * C2) | alloc((sizeof(t)) * (COUNT), ...) | - alloc((e1) * (e2)) + realloc(e1, e2) | - alloc((e1) * (COUNT)) + realloc(COUNT, e1) | - alloc((E1) * (E2)) + realloc(E1, E2) ) // Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20230627144339.144478-23-Julia.Lawall@inria.fr Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microsoft/mana/hw_channel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c index 9d1507eba5b9..2bd1d74021f7 100644 --- a/drivers/net/ethernet/microsoft/mana/hw_channel.c +++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c @@ -627,7 +627,7 @@ static int mana_hwc_establish_channel(struct gdma_context *gc, u16 *q_depth, if (WARN_ON(cq->id >= gc->max_num_cqs)) return -EPROTO; - gc->cq_table = vzalloc(gc->max_num_cqs * sizeof(struct gdma_queue *)); + gc->cq_table = vcalloc(gc->max_num_cqs, sizeof(struct gdma_queue *)); if (!gc->cq_table) return -ENOMEM; -- cgit v1.2.3 From 528a08bcd820d07887edeae706df88ceb06db109 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 27 Jun 2023 16:42:35 +0300 Subject: net: phy: mscc: fix packet loss due to RGMII delays Two deadly typos break RX and TX traffic on the VSC8502 PHY using RGMII if phy-mode = "rgmii-id" or "rgmii-txid", and no "tx-internal-delay-ps" override exists. The negative error code from phy_get_internal_delay() does not get overridden with the delay deduced from the phy-mode, and later gets committed to hardware. Also, the rx_delay gets overridden by what should have been the tx_delay. Fixes: dbb050d2bfc8 ("phy: mscc: Add support for RGMII delay configuration") Signed-off-by: Vladimir Oltean Reviewed-by: Harini Katakam Reviewed-by: Simon Horman Link: https://lore.kernel.org/r/20230627134235.3453358-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/mscc/mscc_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c index 669a4a7a28ce..4171f01d34e5 100644 --- a/drivers/net/phy/mscc/mscc_main.c +++ b/drivers/net/phy/mscc/mscc_main.c @@ -563,9 +563,9 @@ static int vsc85xx_update_rgmii_cntl(struct phy_device *phydev, u32 rgmii_cntl, if (tx_delay < 0) { if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - rx_delay = RGMII_CLK_DELAY_2_0_NS; + tx_delay = RGMII_CLK_DELAY_2_0_NS; else - rx_delay = RGMII_CLK_DELAY_0_2_NS; + tx_delay = RGMII_CLK_DELAY_0_2_NS; } reg_val |= rx_delay << rgmii_rx_delay_pos; -- cgit v1.2.3 From 5da4d7b8e6dfd5bd7d61f7fe1338b1e5d5b4f76c Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 27 Jun 2023 14:49:48 +0100 Subject: libceph: Partially revert changes to support MSG_SPLICE_PAGES Fix the mishandling of MSG_DONTWAIT and also reinstates the per-page checking of the source pages (which might have come from a DIO write by userspace) by partially reverting the changes to support MSG_SPLICE_PAGES and doing things a little differently. In messenger_v1: (1) The ceph_tcp_sendpage() is resurrected and the callers reverted to use that. (2) The callers now pass MSG_MORE unconditionally. Previously, they were passing in MSG_MORE|MSG_SENDPAGE_NOTLAST and then degrading that to just MSG_MORE on the last call to ->sendpage(). (3) Make ceph_tcp_sendpage() a wrapper around sendmsg() rather than sendpage(), setting MSG_SPLICE_PAGES if sendpage_ok() returns true on the page. In messenger_v2: (4) Bring back do_try_sendpage() and make the callers use that. (5) Make do_try_sendpage() use sendmsg() for both cases and set MSG_SPLICE_PAGES if sendpage_ok() is set. Fixes: 40a8c17aa770 ("ceph: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage") Fixes: fa094ccae1e7 ("ceph: Use sendmsg(MSG_SPLICE_PAGES) rather than sendpage()") Reported-by: Ilya Dryomov Link: https://lore.kernel.org/r/CAOi1vP9vjLfk3W+AJFeexC93jqPaPUn2dD_4NrzxwoZTbYfOnw@mail.gmail.com/ Link: https://lore.kernel.org/r/CAOi1vP_Bn918j24S94MuGyn+Gxk212btw7yWeDrRcW1U8pc_BA@mail.gmail.com/ Signed-off-by: David Howells cc: Xiubo Li cc: Jeff Layton cc: Jens Axboe cc: Matthew Wilcox Link: https://lore.kernel.org/r/3101881.1687801973@warthog.procyon.org.uk/ # v1 Link: https://lore.kernel.org/r/3111635.1687813501@warthog.procyon.org.uk/ # v2 Reviewed-by: Ilya Dryomov Link: https://lore.kernel.org/r/3199652.1687873788@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- net/ceph/messenger_v1.c | 58 ++++++++++++++++++++------------ net/ceph/messenger_v2.c | 88 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 107 insertions(+), 39 deletions(-) diff --git a/net/ceph/messenger_v1.c b/net/ceph/messenger_v1.c index 814579f27f04..3d57bb48a2b4 100644 --- a/net/ceph/messenger_v1.c +++ b/net/ceph/messenger_v1.c @@ -74,6 +74,39 @@ static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov, return r; } +/* + * @more: MSG_MORE or 0. + */ +static int ceph_tcp_sendpage(struct socket *sock, struct page *page, + int offset, size_t size, int more) +{ + struct msghdr msg = { + .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL | more, + }; + struct bio_vec bvec; + int ret; + + /* + * MSG_SPLICE_PAGES cannot properly handle pages with page_count == 0, + * we need to fall back to sendmsg if that's the case. + * + * Same goes for slab pages: skb_can_coalesce() allows + * coalescing neighboring slab objects into a single frag which + * triggers one of hardened usercopy checks. + */ + if (sendpage_ok(page)) + msg.msg_flags |= MSG_SPLICE_PAGES; + + bvec_set_page(&bvec, page, size, offset); + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size); + + ret = sock_sendmsg(sock, &msg); + if (ret == -EAGAIN) + ret = 0; + + return ret; +} + static void con_out_kvec_reset(struct ceph_connection *con) { BUG_ON(con->v1.out_skip); @@ -450,10 +483,6 @@ static int write_partial_message_data(struct ceph_connection *con) */ crc = do_datacrc ? le32_to_cpu(msg->footer.data_crc) : 0; while (cursor->total_resid) { - struct bio_vec bvec; - struct msghdr msghdr = { - .msg_flags = MSG_SPLICE_PAGES, - }; struct page *page; size_t page_offset; size_t length; @@ -465,13 +494,8 @@ static int write_partial_message_data(struct ceph_connection *con) } page = ceph_msg_data_next(cursor, &page_offset, &length); - if (length != cursor->total_resid) - msghdr.msg_flags |= MSG_MORE; - - bvec_set_page(&bvec, page, length, page_offset); - iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, length); - - ret = sock_sendmsg(con->sock, &msghdr); + ret = ceph_tcp_sendpage(con->sock, page, page_offset, length, + MSG_MORE); if (ret <= 0) { if (do_datacrc) msg->footer.data_crc = cpu_to_le32(crc); @@ -501,22 +525,14 @@ static int write_partial_message_data(struct ceph_connection *con) */ static int write_partial_skip(struct ceph_connection *con) { - struct bio_vec bvec; - struct msghdr msghdr = { - .msg_flags = MSG_SPLICE_PAGES | MSG_MORE, - }; int ret; dout("%s %p %d left\n", __func__, con, con->v1.out_skip); while (con->v1.out_skip > 0) { size_t size = min(con->v1.out_skip, (int)PAGE_SIZE); - if (size == con->v1.out_skip) - msghdr.msg_flags &= ~MSG_MORE; - bvec_set_page(&bvec, ZERO_PAGE(0), size, 0); - iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, size); - - ret = sock_sendmsg(con->sock, &msghdr); + ret = ceph_tcp_sendpage(con->sock, ceph_zero_page, 0, size, + MSG_MORE); if (ret <= 0) goto out; con->v1.out_skip -= ret; diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c index 87ac97073e75..1a888b86a494 100644 --- a/net/ceph/messenger_v2.c +++ b/net/ceph/messenger_v2.c @@ -117,38 +117,90 @@ static int ceph_tcp_recv(struct ceph_connection *con) return ret; } +static int do_sendmsg(struct socket *sock, struct iov_iter *it) +{ + struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS }; + int ret; + + msg.msg_iter = *it; + while (iov_iter_count(it)) { + ret = sock_sendmsg(sock, &msg); + if (ret <= 0) { + if (ret == -EAGAIN) + ret = 0; + return ret; + } + + iov_iter_advance(it, ret); + } + + WARN_ON(msg_data_left(&msg)); + return 1; +} + +static int do_try_sendpage(struct socket *sock, struct iov_iter *it) +{ + struct msghdr msg = { .msg_flags = CEPH_MSG_FLAGS }; + struct bio_vec bv; + int ret; + + if (WARN_ON(!iov_iter_is_bvec(it))) + return -EINVAL; + + while (iov_iter_count(it)) { + /* iov_iter_iovec() for ITER_BVEC */ + bvec_set_page(&bv, it->bvec->bv_page, + min(iov_iter_count(it), + it->bvec->bv_len - it->iov_offset), + it->bvec->bv_offset + it->iov_offset); + + /* + * MSG_SPLICE_PAGES cannot properly handle pages with + * page_count == 0, we need to fall back to sendmsg if + * that's the case. + * + * Same goes for slab pages: skb_can_coalesce() allows + * coalescing neighboring slab objects into a single frag + * which triggers one of hardened usercopy checks. + */ + if (sendpage_ok(bv.bv_page)) + msg.msg_flags |= MSG_SPLICE_PAGES; + else + msg.msg_flags &= ~MSG_SPLICE_PAGES; + + iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bv, 1, bv.bv_len); + ret = sock_sendmsg(sock, &msg); + if (ret <= 0) { + if (ret == -EAGAIN) + ret = 0; + return ret; + } + + iov_iter_advance(it, ret); + } + + return 1; +} + /* * Write as much as possible. The socket is expected to be corked, * so we don't bother with MSG_MORE here. * * Return: - * >0 - done, nothing (else) to write + * 1 - done, nothing (else) to write * 0 - socket is full, need to wait * <0 - error */ static int ceph_tcp_send(struct ceph_connection *con) { - struct msghdr msg = { - .msg_iter = con->v2.out_iter, - .msg_flags = CEPH_MSG_FLAGS, - }; int ret; - if (WARN_ON(!iov_iter_is_bvec(&con->v2.out_iter))) - return -EINVAL; - - if (con->v2.out_iter_sendpage) - msg.msg_flags |= MSG_SPLICE_PAGES; - dout("%s con %p have %zu try_sendpage %d\n", __func__, con, iov_iter_count(&con->v2.out_iter), con->v2.out_iter_sendpage); - - ret = sock_sendmsg(con->sock, &msg); - if (ret > 0) - iov_iter_advance(&con->v2.out_iter, ret); - else if (ret == -EAGAIN) - ret = 0; - + if (con->v2.out_iter_sendpage) + ret = do_try_sendpage(con->sock, &con->v2.out_iter); + else + ret = do_sendmsg(con->sock, &con->v2.out_iter); dout("%s con %p ret %d left %zu\n", __func__, con, ret, iov_iter_count(&con->v2.out_iter)); return ret; -- cgit v1.2.3 From 1a3f6fc430ed220889c7fb1a63bc2a30267ebc2a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 26 Jun 2023 14:46:40 -0700 Subject: phylink: ReST-ify the phylink_pcs_neg_mode() kdoc Stephen reports warnings when rendering phylink kdocs as HTML: include/linux/phylink.h:110: ERROR: Unexpected indentation. include/linux/phylink.h:111: WARNING: Block quote ends without a blank line; unexpected unindent. include/linux/phylink.h:614: WARNING: Inline literal start-string without end-string. include/linux/phylink.h:644: WARNING: Inline literal start-string without end-string. Make phylink_pcs_neg_mode() use a proper list format to fix the first two warnings. The last two warnings, AFAICT, come from the use of shorthand like phylink_mode_*(). Perhaps those should be special-cased at the Sphinx level. Reported-by: Stephen Rothwell Link: https://lore.kernel.org/all/20230626162908.2f149f98@canb.auug.org.au/ Link: https://lore.kernel.org/r/20230626214640.3142252-1-kuba@kernel.org Signed-off-by: Jakub Kicinski --- include/linux/phylink.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 516240f1e950..1817940a3418 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -105,11 +105,13 @@ static inline bool phylink_autoneg_inband(unsigned int mode) * * Determines the negotiation mode to be used by the PCS, and returns * one of: - * %PHYLINK_PCS_NEG_NONE: interface mode does not support inband - * %PHYLINK_PCS_NEG_OUTBAND: an out of band mode (e.g. reading the PHY) + * + * - %PHYLINK_PCS_NEG_NONE: interface mode does not support inband + * - %PHYLINK_PCS_NEG_OUTBAND: an out of band mode (e.g. reading the PHY) * will be used. - * %PHYLINK_PCS_NEG_INBAND_DISABLED: inband mode selected but autoneg disabled - * %PHYLINK_PCS_NEG_INBAND_ENABLED: inband mode selected and autoneg enabled + * - %PHYLINK_PCS_NEG_INBAND_DISABLED: inband mode selected but autoneg + * disabled + * - %PHYLINK_PCS_NEG_INBAND_ENABLED: inband mode selected and autoneg enabled * * Note: this is for cases where the PCS itself is involved in negotiation * (e.g. Clause 37, SGMII and similar) not Clause 73. -- cgit v1.2.3 From 9d797ee2dce1e3e243bcc18dad7728df72fd11a4 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 26 Jun 2023 13:58:37 -0700 Subject: Revert "af_unix: Call scm_recv() only after scm_set_cred()." This reverts commit 3f5f118bb657f94641ea383c7c1b8c09a5d46ea2. Konrad reported that desktop environment below cannot be reached after commit 3f5f118bb657 ("af_unix: Call scm_recv() only after scm_set_cred().") - postmarketOS (Alpine Linux w/ musl 1.2.4) - busybox 1.36.1 - GNOME 44.1 - networkmanager 1.42.6 - openrc 0.47 Regarding to the warning of SO_PASSPIDFD, I'll post another patch to suppress it by skipping SCM_PIDFD if scm->pid == NULL in scm_pidfd_recv(). Reported-by: Konrad Dybcio Link: https://lore.kernel.org/netdev/8c7f9abd-4f84-7296-2788-1e130d6304a0@kernel.org/ Signed-off-by: Kuniyuki Iwashima Tested-by: Ido Schimmel Tested-by: Gal Pressman Link: https://lore.kernel.org/r/20230626205837.82086-1-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- net/unix/af_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index f2f234f0b92c..3953daa2e1d0 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2807,7 +2807,7 @@ unlock: } while (size); mutex_unlock(&u->iolock); - if (state->msg && check_creds) + if (state->msg) scm_recv(sock, state->msg, &scm, flags); else scm_destroy(&scm); -- cgit v1.2.3 From d06f925f13976ab82167c93467c70a337a0a3cda Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 26 Jun 2023 18:44:02 +0300 Subject: net: dsa: avoid suspicious RCU usage for synced VLAN-aware MAC addresses When using the felix driver (the only one which supports UC filtering and MC filtering) as a DSA master for a random other DSA switch, one can see the following stack trace when the downstream switch ports join a VLAN-aware bridge: ============================= WARNING: suspicious RCU usage ----------------------------- net/8021q/vlan_core.c:238 suspicious rcu_dereference_protected() usage! stack backtrace: Workqueue: dsa_ordered dsa_slave_switchdev_event_work Call trace: lockdep_rcu_suspicious+0x170/0x210 vlan_for_each+0x8c/0x188 dsa_slave_sync_uc+0x128/0x178 __hw_addr_sync_dev+0x138/0x158 dsa_slave_set_rx_mode+0x58/0x70 __dev_set_rx_mode+0x88/0xa8 dev_uc_add+0x74/0xa0 dsa_port_bridge_host_fdb_add+0xec/0x180 dsa_slave_switchdev_event_work+0x7c/0x1c8 process_one_work+0x290/0x568 What it's saying is that vlan_for_each() expects rtnl_lock() context and it's not getting it, when it's called from the DSA master's ndo_set_rx_mode(). The caller of that - dsa_slave_set_rx_mode() - is the slave DSA interface's dsa_port_bridge_host_fdb_add() which comes from the deferred dsa_slave_switchdev_event_work(). We went to great lengths to avoid the rtnl_lock() context in that call path in commit 0faf890fc519 ("net: dsa: drop rtnl_lock from dsa_slave_switchdev_event_work"), and calling rtnl_lock() is simply not an option due to the possibility of deadlocking when calling dsa_flush_workqueue() from the call paths that do hold rtnl_lock() - basically all of them. So, when the DSA master calls vlan_for_each() from its ndo_set_rx_mode(), the state of the 8021q driver on this device is really not protected from concurrent access by anything. Looking at net/8021q/, I don't think that vlan_info->vid_list was particularly designed with RCU traversal in mind, so introducing an RCU read-side form of vlan_for_each() - vlan_for_each_rcu() - won't be so easy, and it also wouldn't be exactly what we need anyway. In general I believe that the solution isn't in net/8021q/ anyway; vlan_for_each() is not cut out for this task. DSA doesn't need rtnl_lock() to be held per se - since it's not a netdev state change that we're blocking, but rather, just concurrent additions/removals to a VLAN list. We don't even need sleepable context - the callback of vlan_for_each() just schedules deferred work. The proposed escape is to remove the dependency on vlan_for_each() and to open-code a non-sleepable, rtnl-free alternative to that, based on copies of the VLAN list modified from .ndo_vlan_rx_add_vid() and .ndo_vlan_rx_kill_vid(). Fixes: 64fdc5f341db ("net: dsa: sync unicast and multicast addresses for VLAN filters too") Signed-off-by: Vladimir Oltean Link: https://lore.kernel.org/r/20230626154402.3154454-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- include/net/dsa.h | 12 ++++++-- net/dsa/dsa.c | 2 +- net/dsa/slave.c | 84 ++++++++++++++++++++++++++++++++++++++----------------- net/dsa/switch.c | 4 +-- net/dsa/switch.h | 3 ++ 5 files changed, 74 insertions(+), 31 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index ab0f0a5b0860..197c5a6ca8f7 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -314,9 +314,17 @@ struct dsa_port { struct list_head fdbs; struct list_head mdbs; - /* List of VLANs that CPU and DSA ports are members of. */ struct mutex vlans_lock; - struct list_head vlans; + union { + /* List of VLANs that CPU and DSA ports are members of. + * Access to this is serialized by the sleepable @vlans_lock. + */ + struct list_head vlans; + /* List of VLANs that user ports are members of. + * Access to this is serialized by netif_addr_lock_bh(). + */ + struct list_head user_vlans; + }; }; /* TODO: ideally DSA ports would have a single dp->link_dp member, diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 1afed89e03c0..ccbdb98109f8 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -1106,7 +1106,7 @@ static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) mutex_init(&dp->vlans_lock); INIT_LIST_HEAD(&dp->fdbs); INIT_LIST_HEAD(&dp->mdbs); - INIT_LIST_HEAD(&dp->vlans); + INIT_LIST_HEAD(&dp->vlans); /* also initializes &dp->user_vlans */ INIT_LIST_HEAD(&dp->list); list_add_tail(&dp->list, &dst->ports); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 165bb2cb8431..527b1d576460 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -27,6 +27,7 @@ #include "master.h" #include "netlink.h" #include "slave.h" +#include "switch.h" #include "tag.h" struct dsa_switchdev_event_work { @@ -161,8 +162,7 @@ static int dsa_slave_schedule_standalone_work(struct net_device *dev, return 0; } -static int dsa_slave_host_vlan_rx_filtering(struct net_device *vdev, int vid, - void *arg) +static int dsa_slave_host_vlan_rx_filtering(void *arg, int vid) { struct dsa_host_vlan_rx_filtering_ctx *ctx = arg; @@ -170,6 +170,28 @@ static int dsa_slave_host_vlan_rx_filtering(struct net_device *vdev, int vid, ctx->addr, vid); } +static int dsa_slave_vlan_for_each(struct net_device *dev, + int (*cb)(void *arg, int vid), void *arg) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_vlan *v; + int err; + + lockdep_assert_held(&dev->addr_list_lock); + + err = cb(arg, 0); + if (err) + return err; + + list_for_each_entry(v, &dp->user_vlans, list) { + err = cb(arg, v->vid); + if (err) + return err; + } + + return 0; +} + static int dsa_slave_sync_uc(struct net_device *dev, const unsigned char *addr) { @@ -180,18 +202,14 @@ static int dsa_slave_sync_uc(struct net_device *dev, .addr = addr, .event = DSA_UC_ADD, }; - int err; dev_uc_add(master, addr); if (!dsa_switch_supports_uc_filtering(dp->ds)) return 0; - err = dsa_slave_schedule_standalone_work(dev, DSA_UC_ADD, addr, 0); - if (err) - return err; - - return vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, &ctx); + return dsa_slave_vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, + &ctx); } static int dsa_slave_unsync_uc(struct net_device *dev, @@ -204,18 +222,14 @@ static int dsa_slave_unsync_uc(struct net_device *dev, .addr = addr, .event = DSA_UC_DEL, }; - int err; dev_uc_del(master, addr); if (!dsa_switch_supports_uc_filtering(dp->ds)) return 0; - err = dsa_slave_schedule_standalone_work(dev, DSA_UC_DEL, addr, 0); - if (err) - return err; - - return vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, &ctx); + return dsa_slave_vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, + &ctx); } static int dsa_slave_sync_mc(struct net_device *dev, @@ -228,18 +242,14 @@ static int dsa_slave_sync_mc(struct net_device *dev, .addr = addr, .event = DSA_MC_ADD, }; - int err; dev_mc_add(master, addr); if (!dsa_switch_supports_mc_filtering(dp->ds)) return 0; - err = dsa_slave_schedule_standalone_work(dev, DSA_MC_ADD, addr, 0); - if (err) - return err; - - return vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, &ctx); + return dsa_slave_vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, + &ctx); } static int dsa_slave_unsync_mc(struct net_device *dev, @@ -252,18 +262,14 @@ static int dsa_slave_unsync_mc(struct net_device *dev, .addr = addr, .event = DSA_MC_DEL, }; - int err; dev_mc_del(master, addr); if (!dsa_switch_supports_mc_filtering(dp->ds)) return 0; - err = dsa_slave_schedule_standalone_work(dev, DSA_MC_DEL, addr, 0); - if (err) - return err; - - return vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, &ctx); + return dsa_slave_vlan_for_each(dev, dsa_slave_host_vlan_rx_filtering, + &ctx); } void dsa_slave_sync_ha(struct net_device *dev) @@ -1759,6 +1765,7 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, struct netlink_ext_ack extack = {0}; struct dsa_switch *ds = dp->ds; struct netdev_hw_addr *ha; + struct dsa_vlan *v; int ret; /* User port... */ @@ -1782,8 +1789,17 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, !dsa_switch_supports_mc_filtering(ds)) return 0; + v = kzalloc(sizeof(*v), GFP_KERNEL); + if (!v) { + ret = -ENOMEM; + goto rollback; + } + netif_addr_lock_bh(dev); + v->vid = vid; + list_add_tail(&v->list, &dp->user_vlans); + if (dsa_switch_supports_mc_filtering(ds)) { netdev_for_each_synced_mc_addr(ha, dev) { dsa_slave_schedule_standalone_work(dev, DSA_MC_ADD, @@ -1803,6 +1819,12 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, dsa_flush_workqueue(); return 0; + +rollback: + dsa_port_host_vlan_del(dp, &vlan); + dsa_port_vlan_del(dp, &vlan); + + return ret; } static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, @@ -1816,6 +1838,7 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, }; struct dsa_switch *ds = dp->ds; struct netdev_hw_addr *ha; + struct dsa_vlan *v; int err; err = dsa_port_vlan_del(dp, &vlan); @@ -1832,6 +1855,15 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, netif_addr_lock_bh(dev); + v = dsa_vlan_find(&dp->user_vlans, &vlan); + if (!v) { + netif_addr_unlock_bh(dev); + return -ENOENT; + } + + list_del(&v->list); + kfree(v); + if (dsa_switch_supports_mc_filtering(ds)) { netdev_for_each_synced_mc_addr(ha, dev) { dsa_slave_schedule_standalone_work(dev, DSA_MC_DEL, diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 8c9a9f94b756..1a42f9317334 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -673,8 +673,8 @@ static bool dsa_port_host_vlan_match(struct dsa_port *dp, return false; } -static struct dsa_vlan *dsa_vlan_find(struct list_head *vlan_list, - const struct switchdev_obj_port_vlan *vlan) +struct dsa_vlan *dsa_vlan_find(struct list_head *vlan_list, + const struct switchdev_obj_port_vlan *vlan) { struct dsa_vlan *v; diff --git a/net/dsa/switch.h b/net/dsa/switch.h index 15e67b95eb6e..ea034677da15 100644 --- a/net/dsa/switch.h +++ b/net/dsa/switch.h @@ -111,6 +111,9 @@ struct dsa_notifier_master_state_info { bool operational; }; +struct dsa_vlan *dsa_vlan_find(struct list_head *vlan_list, + const struct switchdev_obj_port_vlan *vlan); + int dsa_tree_notify(struct dsa_switch_tree *dst, unsigned long e, void *v); int dsa_broadcast(unsigned long e, void *v); -- cgit v1.2.3 From 25a9c8a4431c364f97f75558cb346d2ad3f53fbb Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Mon, 26 Jun 2023 09:43:13 -0700 Subject: netlink: Add __sock_i_ino() for __netlink_diag_dump(). syzbot reported a warning in __local_bh_enable_ip(). [0] Commit 8d61f926d420 ("netlink: fix potential deadlock in netlink_set_err()") converted read_lock(&nl_table_lock) to read_lock_irqsave() in __netlink_diag_dump() to prevent a deadlock. However, __netlink_diag_dump() calls sock_i_ino() that uses read_lock_bh() and read_unlock_bh(). If CONFIG_TRACE_IRQFLAGS=y, read_unlock_bh() finally enables IRQ even though it should stay disabled until the following read_unlock_irqrestore(). Using read_lock() in sock_i_ino() would trigger a lockdep splat in another place that was fixed in commit f064af1e500a ("net: fix a lockdep splat"), so let's add __sock_i_ino() that would be safe to use under BH disabled. [0]: WARNING: CPU: 0 PID: 5012 at kernel/softirq.c:376 __local_bh_enable_ip+0xbe/0x130 kernel/softirq.c:376 Modules linked in: CPU: 0 PID: 5012 Comm: syz-executor487 Not tainted 6.4.0-rc7-syzkaller-00202-g6f68fc395f49 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/27/2023 RIP: 0010:__local_bh_enable_ip+0xbe/0x130 kernel/softirq.c:376 Code: 45 bf 01 00 00 00 e8 91 5b 0a 00 e8 3c 15 3d 00 fb 65 8b 05 ec e9 b5 7e 85 c0 74 58 5b 5d c3 65 8b 05 b2 b6 b4 7e 85 c0 75 a2 <0f> 0b eb 9e e8 89 15 3d 00 eb 9f 48 89 ef e8 6f 49 18 00 eb a8 0f RSP: 0018:ffffc90003a1f3d0 EFLAGS: 00010046 RAX: 0000000000000000 RBX: 0000000000000201 RCX: 1ffffffff1cf5996 RDX: 0000000000000000 RSI: 0000000000000201 RDI: ffffffff8805c6f3 RBP: ffffffff8805c6f3 R08: 0000000000000001 R09: ffff8880152b03a3 R10: ffffed1002a56074 R11: 0000000000000005 R12: 00000000000073e4 R13: dffffc0000000000 R14: 0000000000000002 R15: 0000000000000000 FS: 0000555556726300(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000045ad50 CR3: 000000007c646000 CR4: 00000000003506f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: sock_i_ino+0x83/0xa0 net/core/sock.c:2559 __netlink_diag_dump+0x45c/0x790 net/netlink/diag.c:171 netlink_diag_dump+0xd6/0x230 net/netlink/diag.c:207 netlink_dump+0x570/0xc50 net/netlink/af_netlink.c:2269 __netlink_dump_start+0x64b/0x910 net/netlink/af_netlink.c:2374 netlink_dump_start include/linux/netlink.h:329 [inline] netlink_diag_handler_dump+0x1ae/0x250 net/netlink/diag.c:238 __sock_diag_cmd net/core/sock_diag.c:238 [inline] sock_diag_rcv_msg+0x31e/0x440 net/core/sock_diag.c:269 netlink_rcv_skb+0x165/0x440 net/netlink/af_netlink.c:2547 sock_diag_rcv+0x2a/0x40 net/core/sock_diag.c:280 netlink_unicast_kernel net/netlink/af_netlink.c:1339 [inline] netlink_unicast+0x547/0x7f0 net/netlink/af_netlink.c:1365 netlink_sendmsg+0x925/0xe30 net/netlink/af_netlink.c:1914 sock_sendmsg_nosec net/socket.c:724 [inline] sock_sendmsg+0xde/0x190 net/socket.c:747 ____sys_sendmsg+0x71c/0x900 net/socket.c:2503 ___sys_sendmsg+0x110/0x1b0 net/socket.c:2557 __sys_sendmsg+0xf7/0x1c0 net/socket.c:2586 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd RIP: 0033:0x7f5303aaabb9 Code: 28 c3 e8 2a 14 00 00 66 2e 0f 1f 84 00 00 00 00 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 c0 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007ffc7506e548 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f5303aaabb9 RDX: 0000000000000000 RSI: 0000000020000180 RDI: 0000000000000003 RBP: 00007f5303a6ed60 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f5303a6edf0 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 Fixes: 8d61f926d420 ("netlink: fix potential deadlock in netlink_set_err()") Reported-by: syzbot+5da61cf6a9bc1902d422@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=5da61cf6a9bc1902d422 Suggested-by: Eric Dumazet Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Link: https://lore.kernel.org/r/20230626164313.52528-1-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/sock.h | 1 + net/core/sock.c | 17 ++++++++++++++--- net/netlink/diag.c | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index 6f428a7f3567..ad468fe71413 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2100,6 +2100,7 @@ static inline void sock_graft(struct sock *sk, struct socket *parent) } kuid_t sock_i_uid(struct sock *sk); +unsigned long __sock_i_ino(struct sock *sk); unsigned long sock_i_ino(struct sock *sk); static inline kuid_t sock_net_uid(const struct net *net, const struct sock *sk) diff --git a/net/core/sock.c b/net/core/sock.c index 6e5662ca00fe..4a0edccf8606 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2550,13 +2550,24 @@ kuid_t sock_i_uid(struct sock *sk) } EXPORT_SYMBOL(sock_i_uid); -unsigned long sock_i_ino(struct sock *sk) +unsigned long __sock_i_ino(struct sock *sk) { unsigned long ino; - read_lock_bh(&sk->sk_callback_lock); + read_lock(&sk->sk_callback_lock); ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0; - read_unlock_bh(&sk->sk_callback_lock); + read_unlock(&sk->sk_callback_lock); + return ino; +} +EXPORT_SYMBOL(__sock_i_ino); + +unsigned long sock_i_ino(struct sock *sk) +{ + unsigned long ino; + + local_bh_disable(); + ino = __sock_i_ino(sk); + local_bh_enable(); return ino; } EXPORT_SYMBOL(sock_i_ino); diff --git a/net/netlink/diag.c b/net/netlink/diag.c index 4143b2ea4195..e4f21b1067bc 100644 --- a/net/netlink/diag.c +++ b/net/netlink/diag.c @@ -168,7 +168,7 @@ mc_list: NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - sock_i_ino(sk)) < 0) { + __sock_i_ino(sk)) < 0) { ret = 1; break; } -- cgit v1.2.3 From 30ac666a2fccaa8c164199ea8844dc28aa714453 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Tue, 27 Jun 2023 03:54:32 +0000 Subject: net: lan743x: Simplify comparison Simplify comparison, no functional changes. Cc: Bryan Whitehead Cc: UNGLinuxDriver@microchip.com Suggested-by: Jakub Kicinski Signed-off-by: Moritz Fischer Link: https://lore.kernel.org/r/20230627035432.1296760-1-moritzf@google.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/microchip/lan743x_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index f1bded993edc..5b0e8b0e0c89 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -152,7 +152,7 @@ static int lan743x_csr_wait_for_bit(struct lan743x_adapter *adapter, u32 data; return readx_poll_timeout(LAN743X_CSR_READ_OP, offset, data, - target_value == ((data & bit_mask) ? 1 : 0), + target_value == !!(data & bit_mask), usleep_max, usleep_min * count); } -- cgit v1.2.3 From 603fc57ab70c306fa483ca66152223e861455e09 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 27 Jun 2023 10:43:13 -0700 Subject: af_unix: Skip SCM_PIDFD if scm->pid is NULL. syzkaller hit a WARN_ON_ONCE(!scm->pid) in scm_pidfd_recv(). In unix_stream_read_generic(), if there is no skb in the queue, we could bail out the do-while loop without calling scm_set_cred(): 1. No skb in the queue 2. sk is non-blocking or shutdown(sk, RCV_SHUTDOWN) is called concurrently or peer calls close() If the socket is configured with SO_PASSPIDFD, scm_pidfd_recv() would populate cmsg with garbage emitting the warning. Let's skip SCM_PIDFD if scm->pid is NULL in scm_pidfd_recv(). Note another way would be skip calling scm_recv() in such cases, but this caused a regression resulting in commit 9d797ee2dce1 ("Revert "af_unix: Call scm_recv() only after scm_set_cred().""). WARNING: CPU: 1 PID: 3245 at include/net/scm.h:138 scm_pidfd_recv include/net/scm.h:138 [inline] WARNING: CPU: 1 PID: 3245 at include/net/scm.h:138 scm_recv.constprop.0+0x754/0x850 include/net/scm.h:177 Modules linked in: CPU: 1 PID: 3245 Comm: syz-executor.1 Not tainted 6.4.0-rc5-01219-gfa0e21fa4443 #2 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014 RIP: 0010:scm_pidfd_recv include/net/scm.h:138 [inline] RIP: 0010:scm_recv.constprop.0+0x754/0x850 include/net/scm.h:177 Code: 67 fd e9 55 fd ff ff e8 4a 70 67 fd e9 7f fd ff ff e8 40 70 67 fd e9 3e fb ff ff e8 36 70 67 fd e9 02 fd ff ff e8 8c 3a 20 fd <0f> 0b e9 fe fb ff ff e8 50 70 67 fd e9 2e f9 ff ff e8 46 70 67 fd RSP: 0018:ffffc90009af7660 EFLAGS: 00010216 RAX: 00000000000000a1 RBX: ffff888041e58a80 RCX: ffffc90003852000 RDX: 0000000000040000 RSI: ffffffff842675b4 RDI: 0000000000000007 RBP: ffffc90009af7810 R08: 0000000000000007 R09: 0000000000000013 R10: 00000000000000f8 R11: 0000000000000001 R12: ffffc90009af7db0 R13: 0000000000000000 R14: ffff888041e58a88 R15: 1ffff9200135eecc FS: 00007f6b7113f640(0000) GS:ffff88806cf00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f6b7111de38 CR3: 0000000012a6e002 CR4: 0000000000770ee0 PKRU: 55555554 Call Trace: unix_stream_read_generic+0x5fe/0x1f50 net/unix/af_unix.c:2830 unix_stream_recvmsg+0x194/0x1c0 net/unix/af_unix.c:2880 sock_recvmsg_nosec net/socket.c:1019 [inline] sock_recvmsg+0x188/0x1d0 net/socket.c:1040 ____sys_recvmsg+0x210/0x610 net/socket.c:2712 ___sys_recvmsg+0xff/0x190 net/socket.c:2754 do_recvmmsg+0x25d/0x6c0 net/socket.c:2848 __sys_recvmmsg net/socket.c:2927 [inline] __do_sys_recvmmsg net/socket.c:2950 [inline] __se_sys_recvmmsg net/socket.c:2943 [inline] __x64_sys_recvmmsg+0x224/0x290 net/socket.c:2943 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3f/0x90 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x72/0xdc RIP: 0033:0x7f6b71da2e5d Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 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 8b 0d 73 9f 1b 00 f7 d8 64 89 01 48 RSP: 002b:00007f6b7113ecc8 EFLAGS: 00000246 ORIG_RAX: 000000000000012b RAX: ffffffffffffffda RBX: 00000000004bc050 RCX: 00007f6b71da2e5d RDX: 0000000000000007 RSI: 0000000020006600 RDI: 000000000000000b RBP: 00000000004bc050 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000120 R11: 0000000000000246 R12: 0000000000000000 R13: 000000000000006e R14: 00007f6b71e03530 R15: 0000000000000000 Fixes: 5e2ff6704a27 ("scm: add SO_PASSPIDFD and SCM_PIDFD") Reported-by: syzkaller Signed-off-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230627174314.67688-2-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/scm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/net/scm.h b/include/net/scm.h index c67f765a165b..d456fc41b8bf 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -135,7 +135,9 @@ static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm return; } - WARN_ON_ONCE(!scm->pid); + if (!scm->pid) + return; + pidfd = pidfd_prepare(scm->pid, 0, &pidfd_file); if (put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd)) { -- cgit v1.2.3 From a9c49cc2f5b578c4ffa0ee135aa552d06dec0e82 Mon Sep 17 00:00:00 2001 From: Alexander Mikhalitsyn Date: Tue, 27 Jun 2023 10:43:14 -0700 Subject: net: scm: introduce and use scm_recv_unix helper Recently, our friends from bluetooth subsystem reported [1] that after commit 5e2ff6704a27 ("scm: add SO_PASSPIDFD and SCM_PIDFD") scm_recv() helper become unusable in kernel modules (because it uses unexported pidfd_prepare() API). We were aware of this issue and workarounded it in a hard way by commit 97154bcf4d1b ("af_unix: Kconfig: make CONFIG_UNIX bool"). But recently a new functionality was added in the scope of commit 817efd3cad74 ("Bluetooth: hci_sock: Forward credentials to monitor") and after that bluetooth can't be compiled as a kernel module. After some discussion in [1] we decided to split scm_recv() into two helpers, one won't support SCM_PIDFD (used for unix sockets), and another one will be completely the same as it was before commit 5e2ff6704a27 ("scm: add SO_PASSPIDFD and SCM_PIDFD"). Link: https://lore.kernel.org/lkml/CAJqdLrpFcga4n7wxBhsFqPQiN8PKFVr6U10fKcJ9W7AcZn+o6Q@mail.gmail.com/ [1] Fixes: 5e2ff6704a27 ("scm: add SO_PASSPIDFD and SCM_PIDFD") Signed-off-by: Alexander Mikhalitsyn Reviewed-by: Kuniyuki Iwashima Link: https://lore.kernel.org/r/20230627174314.67688-3-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- include/net/scm.h | 35 +++++++++++++++++++++++++---------- net/unix/af_unix.c | 4 ++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/include/net/scm.h b/include/net/scm.h index d456fc41b8bf..c5bcdf65f55c 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -153,8 +153,8 @@ static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm fd_install(pidfd, pidfd_file); } -static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, - struct scm_cookie *scm, int flags) +static inline bool __scm_recv_common(struct socket *sock, struct msghdr *msg, + struct scm_cookie *scm, int flags) { if (!msg->msg_control) { if (test_bit(SOCK_PASSCRED, &sock->flags) || @@ -162,7 +162,7 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, scm->fp || scm_has_secdata(sock)) msg->msg_flags |= MSG_CTRUNC; scm_destroy(scm); - return; + return false; } if (test_bit(SOCK_PASSCRED, &sock->flags)) { @@ -175,19 +175,34 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); } - if (test_bit(SOCK_PASSPIDFD, &sock->flags)) - scm_pidfd_recv(msg, scm); + scm_passec(sock, msg, scm); - scm_destroy_cred(scm); + if (scm->fp) + scm_detach_fds(msg, scm); - scm_passec(sock, msg, scm); + return true; +} - if (!scm->fp) +static inline void scm_recv(struct socket *sock, struct msghdr *msg, + struct scm_cookie *scm, int flags) +{ + if (!__scm_recv_common(sock, msg, scm, flags)) return; - - scm_detach_fds(msg, scm); + + scm_destroy_cred(scm); } +static inline void scm_recv_unix(struct socket *sock, struct msghdr *msg, + struct scm_cookie *scm, int flags) +{ + if (!__scm_recv_common(sock, msg, scm, flags)) + return; + + if (test_bit(SOCK_PASSPIDFD, &sock->flags)) + scm_pidfd_recv(msg, scm); + + scm_destroy_cred(scm); +} #endif /* __LINUX_NET_SCM_H */ diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3953daa2e1d0..123b35ddfd71 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2427,7 +2427,7 @@ int __unix_dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t size, } err = (flags & MSG_TRUNC) ? skb->len - skip : size; - scm_recv(sock, msg, &scm, flags); + scm_recv_unix(sock, msg, &scm, flags); out_free: skb_free_datagram(sk, skb); @@ -2808,7 +2808,7 @@ unlock: mutex_unlock(&u->iolock); if (state->msg) - scm_recv(sock, state->msg, &scm, flags); + scm_recv_unix(sock, state->msg, &scm, flags); else scm_destroy(&scm); out: -- cgit v1.2.3